diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 5535a72c..808189f8 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -1837,7 +1837,9 @@ }, "sidebar": { "expand": "展開側欄", - "collapse": "收合側欄" + "collapse": "收合側欄", + "openNavigation": "開啟導航選單", + "closeNavigation": "關閉導航選單" }, "settings": { "title": "系統設定", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 5535a72c..808189f8 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -1837,7 +1837,9 @@ }, "sidebar": { "expand": "展開側欄", - "collapse": "收合側欄" + "collapse": "收合側欄", + "openNavigation": "開啟導航選單", + "closeNavigation": "關閉導航選單" }, "settings": { "title": "系統設定", diff --git a/apps/web/src/components/layout/app-layout.tsx b/apps/web/src/components/layout/app-layout.tsx index 4d89f2c0..102db462 100644 --- a/apps/web/src/components/layout/app-layout.tsx +++ b/apps/web/src/components/layout/app-layout.tsx @@ -15,9 +15,11 @@ */ import { useState, useEffect } from 'react' +import { useTranslations } from 'next-intl' import { Sidebar } from './sidebar' import { Header } from './header' import { DotMatrixBg } from '@/components/ui/dot-matrix-bg' +import { Z_INDEX } from '@/lib/constants/z-index' import { cn } from '@/lib/utils' import { useDashboardStore } from '@/stores/dashboard.store' @@ -50,8 +52,10 @@ export function AppLayout({ showBackground = true, fullBleed = false, }: AppLayoutProps) { + const tSidebar = useTranslations('sidebar') const [collapsed, setCollapsed] = useState(false) const [mobileShell, setMobileShell] = useState(false) + const [mobileNavigationOpen, setMobileNavigationOpen] = useState(false) const [mounted, setMounted] = useState(false) // Phase 19 修復: 全局 SSE 連接 @@ -73,6 +77,8 @@ export function AppLayout({ setMobileShell(isMobile) if (isMobile) { setCollapsed(false) + } else { + setMobileNavigationOpen(false) } } @@ -100,6 +106,11 @@ export function AppLayout({ // Save collapsed state to localStorage const handleToggle = () => { + if (mobileShell) { + setMobileNavigationOpen(value => !value) + return + } + const newState = !collapsed setCollapsed(newState) localStorage.setItem(SIDEBAR_STATE_KEY, String(newState)) @@ -110,8 +121,25 @@ export function AppLayout({ const effectiveCollapsed = mounted ? collapsed : false const shellCollapsed = effectiveCollapsed const contentOffsetClass = shellCollapsed - ? mobileShell ? 'ml-[48px]' : 'ml-[64px]' - : 'ml-[224px]' + ? 'ml-0 md:ml-[64px]' + : 'ml-0 md:ml-[224px]' + + useEffect(() => { + if (!mobileNavigationOpen) { + return + } + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + setMobileNavigationOpen(false) + } + } + + window.addEventListener('keydown', handleKeyDown) + return () => { + window.removeEventListener('keydown', handleKeyDown) + } + }, [mobileNavigationOpen]) return (