Files
hedena_gold/apps/user-app-v2/src/components/home/ProductPanel.vue
T
s.esmaeili 53a304b5d5 SearchView: Removed the dynamic collection-tile grid (e.g. "پرفروش‌های این هفته") and the "نتایج / N محصول" section header from the UI. Underlying data/filtering logic untouched.
DashboardView ("میز کار"): Rebuilt from scratch with a new structure, distinct from the old card+grid layout but visually aligned with HomeView (same blurred bar, @ink/@wine palette, staged reveal animation on mount):

Single hero card (ink→wine gradient) showing balance, gold/fiat debt, and identity — no quick-action icons inside it anymore.

Live gold rate folded into a slim inline row at the bottom instead of a titled section.
Iterated shadow/spacing on the hero card per feedback (softer, less clipped).
DialogVant / DialogVantOneButton (shared modal components, used in 7+ call sites: Dashboard, Cart, SingleProduct, Register, App): Replaced Vant's default dialog chrome with the app's own rounded-card language — circular icon badge for the illustration, pill-shaped primary/secondary buttons. No call-site markup changed.

LoginView: Rebuilt from scratch — full-bleed dark hero (brand + step copy) overlapped by a floating white form sheet, animated crossfade transition between the mobile-number and OTP steps, same staged entrance animation as Home/Dashboard. All auth logic (API check, OTP stub, session login) unchanged.
2026-09-18 12:54:45 +03:30

118 lines
2.8 KiB
Vue

<!--
Product card from the design: a soft grey rounded panel with the piece
centred on it, the title beneath, then a meta line of weight + making charge.
On honesty of the meta line — the design mocks up a struck-through "اجرت ۱۵٪"
next to a red "اجرت ۱۰٪", i.e. a discounted wage. The API exposes no
promotion or discount data today (useProduct's `hasDiscountWage` is always
null, see its header), so the struck-through half only renders when a real
`wageBefore` is passed in. Until the backend returns one, the card shows the
variant's genuine wage alone — the layout is identical, minus an invented
number.
-->
<template>
<article class="panel" @click="emit('open', value)">
<div class="panel__art">
<img v-lazy="image" :alt="title" />
</div>
<h3 class="panel__title">{{ title }}</h3>
<div class="panel__meta">
<span class="panel__weight">{{ min_gram }} گرم</span>
<template v-if="wage != null">
<span class="panel__sep" aria-hidden="true"></span>
<span v-if="wageBefore != null" class="panel__wageOld">اجرت {{ format(wageBefore) }}٪</span>
<span class="panel__wage">{{ format(wage) }}٪ اجرت</span>
</template>
</div>
</article>
</template>
<script setup lang="ts">
import { useProduct } from '../../composables/useProduct'
import type { ProductSummary } from '../../api/client'
const props = defineProps<{ value: ProductSummary; wageBefore?: number | null }>()
const emit = defineEmits<{ (e: 'open', value: ProductSummary): void }>()
const { image, title, min_gram, wage } = useProduct(props.value)
// Whole percents print bare (۱۰٪), fractional ones keep two places (۱۰.۵٪).
function format(v: number) {
return v % 1 === 0 ? String(v) : v.toFixed(2)
}
</script>
<style scoped lang="less">
.panel {
cursor: pointer;
border-radius: 32px;
background: @hairlineSoft;
padding: 18px 16px 16px;
text-align: center;
transition: transform 0.2s ease, background 0.2s ease;
}
.panel:active {
transform: scale(0.985);
}
.panel__art {
height: 148px;
display: flex;
align-items: center;
justify-content: center;
}
.panel__art img {
max-width: 78%;
max-height: 100%;
object-fit: contain;
display: block;
}
.panel__title {
margin: 14px 0 0;
font-size: 14px;
font-weight: 600;
color: @ink;
line-height: 1.6;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.panel__meta {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding-top: 9px;
font-size: 12px;
}
.panel__weight {
color: @inkSoft;
font-weight: 500;
font-size: 14px;
}
.panel__sep {
width: 1px;
height: 12px;
background: @hairline;
}
.panel__wageOld {
color: @inkFaint;
text-decoration: line-through;
}
.panel__wage {
color: @danger;
font-weight: 600;
font-size: 12px !important;
}
</style>