From 4df06babd0884b5366410fb8c817803b9b1ae346 Mon Sep 17 00:00:00 2001 From: kkfluous Date: Wed, 29 Apr 2026 18:28:39 +0800 Subject: [PATCH] fix(mobile): replace top tab strip with hamburger drawer The previous top tab strip ate vertical space and didn't match the desktop sidebar UX. Add a Menu button next to the title (mobile only) that slides the existing Sidebar in from the left as a drawer, with a backdrop, scroll lock, and auto-close on selection. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/App.tsx | 38 ++++------- src/components/Header.tsx | 17 +++-- src/components/Sidebar.tsx | 130 ++++++++++++++++++++++++++----------- 3 files changed, 117 insertions(+), 68 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index b4b6295..9a03dbd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,11 +1,11 @@ import { useState } from 'react'; import { Dashboard } from './components/Dashboard'; -import { Sidebar, sidebarMenuItems } from './components/Sidebar'; +import { Sidebar } from './components/Sidebar'; import { Header } from './components/Header'; -import { cn } from './lib/utils'; export default function App() { const [currentView, setCurrentView] = useState('overall'); + const [mobileNavOpen, setMobileNavOpen] = useState(false); const viewTitles: Record = { 'overall': '全网精细化运营大盘', @@ -15,31 +15,17 @@ export default function App() { return (
- + setMobileNavOpen(false)} + />
-
- +
setMobileNavOpen(true)} + />
diff --git a/src/components/Header.tsx b/src/components/Header.tsx index ddd2a99..960ab00 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,11 +1,20 @@ import React from 'react'; -import { Bell, Search, UserCircle, ChevronDown } from 'lucide-react'; +import { Bell, Search, UserCircle, ChevronDown, Menu } from 'lucide-react'; -export function Header({ title }: { title: string }) { +export function Header({ title, onMenuClick }: { title: string; onMenuClick?: () => void }) { return (
-
-

{title}

+
+ {onMenuClick && ( + + )} +

{title}

void }) { +type SidebarProps = { + currentView: string; + setCurrentView: (v: string) => void; + mobileOpen?: boolean; + onMobileClose?: () => void; +}; + +export function Sidebar({ currentView, setCurrentView, mobileOpen = false, onMobileClose }: SidebarProps) { + useEffect(() => { + if (!mobileOpen) return; + const prev = document.body.style.overflow; + document.body.style.overflow = 'hidden'; + return () => { + document.body.style.overflow = prev; + }; + }, [mobileOpen]); + + const handleSelect = (id: string) => { + setCurrentView(id); + onMobileClose?.(); + }; + return ( - + ); }