Split desktop and mobile layouts with shared page data so APIs fetch once per context.
Add layout shells, desktop views, module-level page caches, and UI fixes for auth, home, wallet, transactions, address, and related pages. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="daddr">
|
||||
<div class="daddr__container">
|
||||
<header class="daddr-topbar">
|
||||
<p class="daddr-topbar__eyebrow">حساب کاربری</p>
|
||||
<h1 class="daddr-topbar__title">آدرسها</h1>
|
||||
<p class="daddr-topbar__subtitle">آدرسهای تحویل سفارش خود را مدیریت کنید</p>
|
||||
</header>
|
||||
|
||||
<div
|
||||
v-if="isBazretalaProject()"
|
||||
class="daddr-notice"
|
||||
>
|
||||
جهت تحویل فیزیکی محصول در تهران و قم ازطریق معرف اقدام فرمائید یا با شماره امورمالی و حسابداری 09925202099 درارتباط باشید.
|
||||
</div>
|
||||
|
||||
<div class="daddr-grid">
|
||||
<section class="daddr-surface daddr-form">
|
||||
<div class="daddr-form__header">
|
||||
<h2 class="daddr-form__title">{{ editId ? 'ویرایش آدرس' : 'ثبت آدرس جدید' }}</h2>
|
||||
<button
|
||||
v-if="editId"
|
||||
type="button"
|
||||
class="daddr-form__reset"
|
||||
@click="openAdd()"
|
||||
>
|
||||
آدرس جدید
|
||||
</button>
|
||||
</div>
|
||||
<AddressForm variant="desktop" />
|
||||
</section>
|
||||
|
||||
<section class="daddr-surface daddr-list">
|
||||
<div class="daddr-list__header">
|
||||
<h3 class="daddr-list__title">آدرسهای ثبتشده</h3>
|
||||
<span class="daddr-list__count">{{ items.length }} مورد</span>
|
||||
</div>
|
||||
|
||||
<div v-if="loading" class="daddr-list__skeletons">
|
||||
<TransactionSkeleton v-for="i in 6" :key="i" class="mt-1" />
|
||||
</div>
|
||||
|
||||
<div v-else-if="items.length" class="daddr-list__items">
|
||||
<list-anim>
|
||||
<Item
|
||||
v-for="item in items"
|
||||
:key="`desktop-${item.id}`"
|
||||
:item="item"
|
||||
variant="desktop"
|
||||
@edit="openEdit"
|
||||
@refresh="initItems"
|
||||
/>
|
||||
</list-anim>
|
||||
</div>
|
||||
|
||||
<div v-else class="daddr-empty">
|
||||
<BasicIcon icon="vuesax-linear:location" size="36" />
|
||||
<p>هنوز آدرسی ثبت نشده است.</p>
|
||||
<button type="button" class="daddr-empty__btn" @click="openAdd()">
|
||||
افزودن اولین آدرس
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import ListAnim from '@/components/ListAnim.vue'
|
||||
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
|
||||
import AddressForm from '../components/AddressForm.vue'
|
||||
import Item from '../components/Item.vue'
|
||||
import { useAddressPageContext } from '../composables/useAddressPage'
|
||||
|
||||
const {
|
||||
items,
|
||||
loading,
|
||||
editId,
|
||||
isBazretalaProject,
|
||||
openAdd,
|
||||
openEdit,
|
||||
initItems,
|
||||
} = useAddressPageContext()
|
||||
</script>
|
||||
@@ -0,0 +1,307 @@
|
||||
/* Premium desktop address page — scoped to desktop shell only */
|
||||
|
||||
html.app-layout--desktop {
|
||||
.daddr {
|
||||
min-height: 100%;
|
||||
background: #f6f7f9;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.daddr__container {
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 28px 36px 40px;
|
||||
}
|
||||
|
||||
.daddr-topbar {
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 24px;
|
||||
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
|
||||
|
||||
&__eyebrow {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #9ca3af;
|
||||
margin: 0 0 4px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.03em;
|
||||
color: #111827;
|
||||
margin: 0 0 6px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
margin: 0;
|
||||
max-width: 520px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.daddr-notice {
|
||||
margin-bottom: 20px;
|
||||
padding: 14px 16px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(59, 130, 246, 0.15);
|
||||
background: rgba(59, 130, 246, 0.06);
|
||||
color: @App-primary-color;
|
||||
font-size: 13px;
|
||||
line-height: 1.8;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.daddr-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 380px) minmax(0, 1fr);
|
||||
gap: 20px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.daddr-surface {
|
||||
background: #fff;
|
||||
border: 1px solid rgba(15, 23, 42, 0.06);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
||||
}
|
||||
|
||||
.daddr-form {
|
||||
padding: 24px;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__reset {
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
color: #6b7280;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
padding: 6px 10px;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s ease, color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: @App-primary-color;
|
||||
color: @App-primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__fields {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
&__address-item {
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
|
||||
&__submit {
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.daddr-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 420px;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 20px 24px 0;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__count {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #6b7280;
|
||||
background: #f3f4f6;
|
||||
border-radius: 999px;
|
||||
padding: 4px 10px;
|
||||
}
|
||||
|
||||
&__items {
|
||||
padding: 16px 24px 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
&__skeletons {
|
||||
padding: 16px 24px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.daddr-card {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 12px 16px;
|
||||
padding: 16px 18px;
|
||||
border: 1px solid #eef0f3;
|
||||
border-radius: 12px;
|
||||
background: #fafbfc;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #dbe0e6;
|
||||
box-shadow: 0 2px 8px rgba(15, 23, 42, 0.04);
|
||||
}
|
||||
|
||||
&__address {
|
||||
grid-column: 1 / -1;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
&__meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
&__label {
|
||||
color: #9ca3af;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__value {
|
||||
color: #374151;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
&__icon-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s ease, background 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
&--danger:hover {
|
||||
border-color: #fecaca;
|
||||
background: #fef2f2;
|
||||
}
|
||||
|
||||
&--edit:hover {
|
||||
border-color: #bbf7d0;
|
||||
background: #f0fdf4;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #eef0f3;
|
||||
}
|
||||
|
||||
&__date {
|
||||
font-size: 12px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
.daddr-empty {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
padding: 48px 24px;
|
||||
color: #6b7280;
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&__btn {
|
||||
margin-top: 4px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
background: @App-primary-color;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
padding: 10px 16px;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.92;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1023.98px) {
|
||||
.daddr-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user