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.
118 lines
2.8 KiB
Vue
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>
|