From 284ced1c89e2e8f272724ef0bfcb9c68ad37f4c1 Mon Sep 17 00:00:00 2001 From: "s.esmaeili" Date: Fri, 16 Oct 2026 10:24:59 +0330 Subject: [PATCH] Replace the home hero with a spring carousel and default theme to light. Adds Carousel under keep-alive-safe autoplay, peeks side cards past the container, and stops following the OS dark preference on first run. Co-authored-by: Cursor --- apps/user-app/index.html | 3 +- .../user-app/src/components/home/Carousel.vue | 507 ++++++++++++++++++ apps/user-app/src/stores/appearanceStore.ts | 7 +- apps/user-app/src/views/HomeView.vue | 7 +- docs/plans/2026-10-16-home-carousel-design.md | 37 ++ 5 files changed, 553 insertions(+), 8 deletions(-) create mode 100644 apps/user-app/src/components/home/Carousel.vue create mode 100644 docs/plans/2026-10-16-home-carousel-design.md diff --git a/apps/user-app/index.html b/apps/user-app/index.html index f162154..623aa0d 100644 --- a/apps/user-app/index.html +++ b/apps/user-app/index.html @@ -19,7 +19,8 @@ try { var s = JSON.parse(localStorage.getItem('hedena-gold:appearance') || '{}'); var mq = function (q) { return window.matchMedia && matchMedia(q).matches; }; - var dark = s.theme === 'dark' || ((s.theme || 'system') === 'system' && mq('(prefers-color-scheme: dark)')); + // Default is light when nothing is saved (matches appearanceStore). + var dark = s.theme === 'dark' || (s.theme === 'system' && mq('(prefers-color-scheme: dark)')); var motion = typeof s.reduceMotion === 'boolean' ? s.reduceMotion : mq('(prefers-reduced-motion: reduce)'); var c = document.documentElement.classList; if (dark) { c.add('theme-dark', 'van-theme-dark'); document.querySelector('meta[name=theme-color]').setAttribute('content', '#15171A'); } diff --git a/apps/user-app/src/components/home/Carousel.vue b/apps/user-app/src/components/home/Carousel.vue new file mode 100644 index 0000000..8ba42e2 --- /dev/null +++ b/apps/user-app/src/components/home/Carousel.vue @@ -0,0 +1,507 @@ + + + + + + diff --git a/apps/user-app/src/stores/appearanceStore.ts b/apps/user-app/src/stores/appearanceStore.ts index f33b016..4dc7f32 100644 --- a/apps/user-app/src/stores/appearanceStore.ts +++ b/apps/user-app/src/stores/appearanceStore.ts @@ -30,9 +30,10 @@ const darkQuery = () => (typeof matchMedia !== 'undefined' ? matchMedia('(prefer const motionQuery = () => (typeof matchMedia !== 'undefined' ? matchMedia('(prefers-reduced-motion: reduce)') : null) function load(): Stored { - // First run: theme follows the system; motion follows the OS's own - // "reduce motion" accessibility setting. - const fallback: Stored = { theme: 'system', reduceMotion: !!motionQuery()?.matches } + // First run: light theme by default; motion follows the OS's own + // "reduce motion" accessibility setting. Users can still pick system/dark + // in Appearance settings. + const fallback: Stored = { theme: 'light', reduceMotion: !!motionQuery()?.matches } try { const raw = localStorage.getItem(APPEARANCE_STORAGE_KEY) if (!raw) return fallback diff --git a/apps/user-app/src/views/HomeView.vue b/apps/user-app/src/views/HomeView.vue index cf8898d..0740926 100644 --- a/apps/user-app/src/views/HomeView.vue +++ b/apps/user-app/src/views/HomeView.vue @@ -4,11 +4,10 @@ Layout intent — shop first, account second: 1. a slim brand bar with search + cart 2. the live 18k rate strip (real: GET /pricing/latest) - 3. an editorial showcase hero built from real categories + 3. spring card carousel hero (admin slider images) 4. the category rail (real: derived from GET /catalog/products) 5. "برگزیده" — staggered 2-col masonry (wireframe: unequal card heights, flush bottoms) 6. "تازه‌ها" — full-width horizontal ProductRow list - 7. the account block (real: GET /customers/:id when signed in) Data honesty, carried over from the previous version deliberately: - the API exposes no curated home payload, no promotions and no per-product @@ -43,7 +42,7 @@ -