feat(ui-polish): sidebar icons + topbar + dashboard redesign
- Sidebar: lucide-react icons, lock on gated items, upgrade badge on "Mon plan", user footer with avatar initials + plan label, "EX|PRIA" logo header
- Topbar: sticky with backdrop-blur, breadcrumb via centralized route-titles.ts, search placeholder, keyboard shortcuts + notifications icons
- Dashboard: split into Free/Standard/Premium views (ARCHITECTURE.md §3 aligned)
- NclcHero: NCLC display + gauge 5→10 + SVG score ring
- StatCards: simulations remaining + NCLC estimé + dernier score with delta
- RecentSimulations: 3 latest with NCLC badge + chevron nav
- NextStepCard: static recommendation per plan
- PaywallBanner: full-width redesign + fixed dead Boréal tokens
- Removed orphan MobileHeader.tsx (0 consumers)
Typecheck: OK · Tests: 122/122 ✅
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b68f160bce
commit
4005673ae8
16 changed files with 1188 additions and 171 deletions
|
|
@ -1,20 +1,20 @@
|
|||
/**
|
||||
* Layout applicatif — enveloppe toutes les routes privées.
|
||||
*
|
||||
* Desktop (≥ 1024px) : Sidebar fixe 240px + zone contenu principale.
|
||||
* Mobile (< 1024px) : MobileHeader sticky + drawer slide-in + BottomNav fixe.
|
||||
* Desktop (≥ 1024px) : Sidebar fixe 230px + Topbar sticky + zone contenu.
|
||||
* Mobile (< 1024px) : Topbar avec hamburger + drawer slide-in + BottomNav fixe.
|
||||
*
|
||||
* Le drawer mobile se ferme automatiquement à chaque changement de route
|
||||
* (useEffect sur location.pathname).
|
||||
*
|
||||
* Règle L : tokens Direction H exclusivement.
|
||||
* Règle L : tokens du design system exclusivement.
|
||||
* Règle H : aucune logique métier — plan lu depuis le cache TanStack Query.
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { Sidebar } from './Sidebar'
|
||||
import { MobileHeader } from './MobileHeader'
|
||||
import { Topbar } from './Topbar'
|
||||
import { BottomNav } from './BottomNav'
|
||||
import { usePlan } from '@/features/dashboard/hooks/usePlan'
|
||||
import { cn } from '@/shared/lib/utils'
|
||||
|
|
@ -31,8 +31,6 @@ export function AppLayout({ children }: AppLayoutProps) {
|
|||
const plan: Plan = data?.plan ?? 'free'
|
||||
|
||||
// Ferme le drawer à chaque changement de route.
|
||||
// Synchronisation UI → router state : pattern légitime (source externe = React
|
||||
// Router). Bail-out React si déjà fermé = zéro cascading render en pratique.
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
setIsMobileMenuOpen(false)
|
||||
|
|
@ -51,9 +49,6 @@ export function AppLayout({ children }: AppLayoutProps) {
|
|||
<Sidebar plan={plan} />
|
||||
</aside>
|
||||
|
||||
{/* ── MOBILE — Header sticky ─────────────────────────────────── */}
|
||||
<MobileHeader onMenuOpen={() => setIsMobileMenuOpen(true)} />
|
||||
|
||||
{/* ── MOBILE — Drawer overlay ────────────────────────────────── */}
|
||||
<div
|
||||
aria-hidden="true"
|
||||
|
|
@ -81,6 +76,7 @@ export function AppLayout({ children }: AppLayoutProps) {
|
|||
className="min-h-screen pb-16 lg:pb-0 lg:pl-[230px]"
|
||||
style={{ background: mainBackground }}
|
||||
>
|
||||
<Topbar onMobileMenuOpen={() => setIsMobileMenuOpen(true)} />
|
||||
<div className="mx-auto max-w-[1100px] px-5 py-6 lg:px-9 lg:py-9">{children}</div>
|
||||
</main>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue