Redesign orders/cart/search flows and fix RTL/auth edge cases in user-app

- Fix silent redirect-to-home for unauthenticated users on protected routes;
  now redirects to login with a return path
- Restyle OrderCard, SearchInput, Filters, DropDown, and product card image
  sizing/centering to match the app's LESS-token design language
- Fix ant-design Slider handle placement/drag under RTL and seed a valid
  default range so handles actually render
- Fix chip-row edge padding and top spacing across Orders/Cart/Search lists
- Add pull-to-refresh to the dashboard and fix its header/padding to match
  the fixed PageBar pattern
- Remove the floating WhatsApp button from index.html
This commit is contained in:
s.esmaeili
2026-09-16 01:15:16 +03:30
parent 0e5f9ccd7b
commit e756fbaf85
30 changed files with 890 additions and 365 deletions
+32 -7
View File
@@ -62,7 +62,12 @@
@change="hideFilters"
/>
<container v-show="!showFilter" class="search__body">
<PullRefresh v-show="!showFilter" v-model="refreshing" @refresh="onRefresh">
<template #pulling><Loading size="18" /></template>
<template #loosing><Loading size="18" /></template>
<template #loading><Loading size="18" /></template>
<template #success><span /></template>
<container class="search__body">
<div v-if="availableCollections.length" class="search__collections">
<button
v-for="item in availableCollections"
@@ -92,7 +97,7 @@
reaches the end — the same incremental behaviour the previous
ScrollFetchSearch-based list had. -->
<div v-if="hasMore" ref="sentinel" class="search__more">
<Spinner :spinning="true" :indicator="true" tip="" cls="my-[10px]" />
<Spinner :spinning="true" :indicator="true" :fixed="false" tip="" cls="my-[10px]" />
</div>
<section v-else-if="!loadingPage" class="search__empty">
@@ -100,12 +105,14 @@
<p>محصولی با این مشخصات پیدا نشد.</p>
</section>
</container>
</PullRefresh>
</Spinner>
</div>
</template>
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { PullRefresh } from 'vant'
import Icon from '../../components/icon/Icon.vue'
import PageBar from '../../components/ui/PageBar.vue'
import Spinner from '../../components/Spinner.vue'
@@ -121,6 +128,7 @@ const filters = useFiltersStore()
const nav = useNavStore()
const loadingPage = ref(false)
const refreshing = ref(false)
const allProducts = ref<ProductSummary[]>([])
const showFilter = ref(false)
const filterKeys = ref<string[]>([])
@@ -203,6 +211,11 @@ async function loadProducts() {
}
}
async function onRefresh() {
await loadProducts()
refreshing.value = false
}
function search(value: string | undefined) {
filters.query.text = value
}
@@ -245,18 +258,26 @@ onMounted(loadProducts)
.search__barExtra {
max-width: 768px;
margin: 0 auto;
padding: 0 16px 11px;
padding: 0 16px 0;
}
.search__chips {
display: flex;
gap: 8px;
gap: 4px;
overflow-x: auto;
margin: 11px -16px 0;
padding: 0 16px;
margin: 8px 0px 8px -16px;
// `padding` alone on an RTL flex scroller can get its edge padding
// collapsed by the browser once content overflows — explicit spacer
// elements hold the same 16px gap reliably at both scroll extremes.
scroll-snap-type: x proximity;
}
.search__chips::before,
.search__chips::after {
content: '';
flex: 0 0 16px;
}
.search__chip {
scroll-snap-align: start;
flex: 0 0 auto;
@@ -292,10 +313,14 @@ onMounted(loadProducts)
}
.search__body {
padding-top: 16px;
padding-top: 160px;
padding-bottom: 90px;
}
.search__body > *:first-child {
margin-top: 16px;
}
.search__collections {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));