From 8ab0da604110e5eda779dcc44a467f5288a8aacd Mon Sep 17 00:00:00 2001 From: senke Date: Mon, 23 Mar 2026 15:44:37 +0100 Subject: [PATCH] feat: design system, theme, and layout improvements Update color tokens, motion, spacing, typography. Enhance ThemeProvider and ThemeSwitcher. Refine layout components (Header, Sidebar, Navbar, MobileBottomNav, DashboardLayout). CSS overhaul in index.css. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/components/layout/DashboardLayout.tsx | 25 +- apps/web/src/components/layout/Header.tsx | 37 +- .../src/components/layout/MobileBottomNav.tsx | 26 +- apps/web/src/components/layout/Navbar.tsx | 2 +- apps/web/src/components/layout/Sidebar.tsx | 63 +- .../src/components/theme/ThemeProvider.tsx | 211 ++++- .../src/components/theme/ThemeSwitcher.tsx | 58 +- apps/web/src/index.css | 755 +++++++++++++----- packages/design-system/src/tokens/colors.ts | 190 +++-- packages/design-system/src/tokens/motion.ts | 2 +- packages/design-system/src/tokens/spacing.ts | 2 +- .../design-system/src/tokens/typography.ts | 5 +- 12 files changed, 1008 insertions(+), 368 deletions(-) diff --git a/apps/web/src/components/layout/DashboardLayout.tsx b/apps/web/src/components/layout/DashboardLayout.tsx index 31207dbab..58cda4070 100644 --- a/apps/web/src/components/layout/DashboardLayout.tsx +++ b/apps/web/src/components/layout/DashboardLayout.tsx @@ -1,6 +1,7 @@ import type { ReactNode } from 'react'; import { Header } from './Header'; import { Sidebar } from './Sidebar'; +import { MobileBottomNav } from './MobileBottomNav'; import { AnnouncementBanner } from '../feedback/AnnouncementBanner'; import { GlobalPlayer } from '@/features/player/components/GlobalPlayer'; import { useQueueSync } from '@/features/player/hooks/useQueueSync'; @@ -14,12 +15,21 @@ interface DashboardLayoutProps { /** * Layout principal "App Shell" - Veza Professional V2 - * + * * Architecture: * - Body: Fixed viewport (overflow-hidden) - * - Sidebar: Fixed left, z-index high + * - Sidebar: Fixed left, z-index high (desktop only) + * - MobileBottomNav: Fixed bottom (mobile only, lg:hidden) * - Main: Scrollable container independent of window * - Header: Sticky top within Main + * - Player: Fixed above bottom nav (mobile) / above content (desktop) + * + * Z-index hierarchy (bottom to top): + * z-raised (10) — main content + * z-40 — MobileBottomNav + * z-player — GlobalPlayer (z-sticky = 200) + * z-sidebar — Sidebar (95) + * z-sticky — Header (200) */ export function DashboardLayout({ children }: DashboardLayoutProps) { const { sidebarOpen } = useUIStore(); @@ -30,7 +40,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) { {/* 1. Global Background (Fixed z-0) */} - {/* 2. Fixed Sidebar (z-90) */} + {/* 2. Fixed Sidebar — desktop only (z-90) */} {/* 3. Main Content Area (The only thing that scrolls) */} @@ -44,7 +54,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) { {/* Header is part of the flow but stays at top */}
- {/* Scrollable Content Container */} + {/* Scrollable Content Container — bottom padding accounts for player + mobile nav */}
- {/* Floating Player: wrapper constrains width to main area; GlobalPlayer is fixed inside */} -
+ {/* Floating Player — sits above MobileBottomNav on mobile */} +
+ + {/* 4. Mobile Bottom Navigation — fixed, below player, above content */} + ); } \ No newline at end of file diff --git a/apps/web/src/components/layout/Header.tsx b/apps/web/src/components/layout/Header.tsx index c6a2aa860..81217597b 100644 --- a/apps/web/src/components/layout/Header.tsx +++ b/apps/web/src/components/layout/Header.tsx @@ -59,7 +59,7 @@ export function Header(_props: HeaderProps) { return (
@@ -67,12 +67,23 @@ export function Header(_props: HeaderProps) { {/* Mobile Sidebar Toggle */} - {/* Search — Spotify-style: pill shape, smooth focus expansion */} + {/* Mobile Search Button — navigates to search page */} + + + {/* Search — Spotify-style: pill shape, smooth focus expansion (desktop) */}
{ if (e.key === 'Enter') { @@ -109,9 +120,9 @@ export function Header(_props: HeaderProps) { {/* Right Actions */}
-
- - {t('header.online')} +
+ + {t('header.online')}
@@ -151,7 +162,7 @@ export function Header(_props: HeaderProps) { {isUserMenuOpen && ( setIsUserMenuOpen(false)}> -
+

{user?.username}

{user?.email}

diff --git a/apps/web/src/components/layout/MobileBottomNav.tsx b/apps/web/src/components/layout/MobileBottomNav.tsx index 4171c2d8a..a22d9be1f 100644 --- a/apps/web/src/components/layout/MobileBottomNav.tsx +++ b/apps/web/src/components/layout/MobileBottomNav.tsx @@ -1,21 +1,26 @@ import { useLocation, Link } from 'react-router-dom'; import { Home, Search, Layers, MessageSquare, User } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { cn } from '@/lib/utils'; const navItems = [ - { id: 'home', label: 'Home', icon: Home, path: '/dashboard' }, - { id: 'search', label: 'Search', icon: Search, path: '/search' }, - { id: 'library', label: 'Library', icon: Layers, path: '/library' }, - { id: 'chat', label: 'Chat', icon: MessageSquare, path: '/chat' }, - { id: 'profile', label: 'Profile', icon: User, path: '/settings' }, + { id: 'home', labelKey: 'nav.items.dashboard', icon: Home, path: '/dashboard' }, + { id: 'search', labelKey: 'nav.items.discover', icon: Search, path: '/discover' }, + { id: 'library', labelKey: 'nav.items.tracks', icon: Layers, path: '/library' }, + { id: 'chat', labelKey: 'nav.items.chat', icon: MessageSquare, path: '/chat' }, + { id: 'profile', labelKey: 'nav.settings', icon: User, path: '/settings' }, ]; export function MobileBottomNav() { const location = useLocation(); + const { t } = useTranslation(); return ( -