Breadcrumbs: - Added Breadcrumbs to main Layout (appears on ALL pages) - Dynamic route support (/batches/:id, /rooms/:id) - Proper navigation hierarchy Daily Walkthrough: - Enhanced layout with progress bar - Photo capture from camera or file upload - Notes fields for each check - Improved touch targets and mobile UX Removed inline breadcrumbs from individual pages since they now come from the global Layout.
166 lines
7.1 KiB
TypeScript
166 lines
7.1 KiB
TypeScript
import { useState } from 'react';
|
|
import { Outlet, Link } from 'react-router-dom';
|
|
import { Menu, X, Command } from 'lucide-react';
|
|
import { useAuth } from '../context/AuthContext';
|
|
import { Sidebar } from './layout/Sidebar';
|
|
import { MobileNav } from './layout/MobileNav';
|
|
import { MobileNavSheet } from './layout/MobileNavSheet';
|
|
import { UserMenu } from './layout/UserMenu';
|
|
import ThemeToggle from './ThemeToggle';
|
|
import { CommandPalette } from './ui/CommandPalette';
|
|
import { SessionTimeoutWarning } from './ui/SessionTimeoutWarning';
|
|
import { PageTitleUpdater } from '../hooks/usePageTitle';
|
|
import AnnouncementBanner from './AnnouncementBanner';
|
|
import { DevTools } from './dev/DevTools';
|
|
import { Breadcrumbs } from './ui/Breadcrumbs';
|
|
|
|
export default function Layout() {
|
|
const { user } = useAuth();
|
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
const [mobileSheetOpen, setMobileSheetOpen] = useState(false);
|
|
|
|
return (
|
|
<div className="flex flex-col h-screen bg-primary">
|
|
{/* Skip to main content link (accessibility) */}
|
|
<a
|
|
href="#main-content"
|
|
className="absolute left-0 top-0 -translate-y-full bg-accent text-white px-4 py-2 rounded-br-lg font-medium focus:translate-y-0 z-50 transition-transform duration-fast"
|
|
>
|
|
Skip to main content
|
|
</a>
|
|
|
|
{/* Mobile Top Header */}
|
|
<header className="md:hidden bg-elevated border-b border-default px-4 py-3 flex items-center justify-between sticky top-0 z-40">
|
|
<Link to="/" className="flex items-center gap-3">
|
|
<img
|
|
src="/assets/logo-777-wolfpack.jpg"
|
|
alt="777 Wolfpack"
|
|
className="w-8 h-8 rounded-lg"
|
|
/>
|
|
<div>
|
|
<h1 className="text-sm font-semibold text-primary leading-tight tracking-tight">
|
|
777 Wolfpack
|
|
</h1>
|
|
<p className="text-[10px] text-tertiary">
|
|
Operations
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
|
|
<button
|
|
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
|
className="p-2 rounded-md hover:bg-tertiary transition-colors duration-fast"
|
|
aria-label={mobileMenuOpen ? 'Close menu' : 'Open menu'}
|
|
>
|
|
{mobileMenuOpen ? (
|
|
<X size={20} className="text-primary" />
|
|
) : (
|
|
<Menu size={20} className="text-primary" />
|
|
)}
|
|
</button>
|
|
</header>
|
|
|
|
{/* Mobile Dropdown Menu */}
|
|
{mobileMenuOpen && (
|
|
<div
|
|
className="md:hidden fixed inset-0 top-[53px] z-30 bg-black/40 animate-fade-in"
|
|
onClick={() => setMobileMenuOpen(false)}
|
|
>
|
|
<div
|
|
className="bg-elevated border-b border-default shadow-xl max-h-[60vh] overflow-y-auto animate-slide-up"
|
|
onClick={e => e.stopPropagation()}
|
|
>
|
|
<div className="p-4">
|
|
<Sidebar onItemClick={() => setMobileMenuOpen(false)} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex flex-1 overflow-hidden">
|
|
{/* Desktop Sidebar */}
|
|
<aside
|
|
className="hidden md:flex w-60 lg:w-64 bg-secondary border-r border-default flex-col"
|
|
role="navigation"
|
|
aria-label="Main navigation"
|
|
>
|
|
{/* Logo */}
|
|
<div className="p-4 border-b border-default">
|
|
<Link to="/" className="flex items-center gap-3 group">
|
|
<div className="relative">
|
|
<img
|
|
src="/assets/logo-777-wolfpack.jpg"
|
|
alt="777 Wolfpack"
|
|
className="w-9 h-9 rounded-lg transition-transform duration-fast group-hover:scale-105"
|
|
/>
|
|
{/* Status indicator */}
|
|
<div className="absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 bg-success rounded-full border-2 border-secondary" />
|
|
</div>
|
|
<div>
|
|
<h1 className="text-sm font-semibold text-primary leading-tight tracking-tight">
|
|
777 Wolfpack
|
|
</h1>
|
|
<p className="text-xs text-tertiary">
|
|
Operations
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Search hint */}
|
|
<div className="px-4 py-3 border-b border-subtle">
|
|
<button
|
|
onClick={() => dispatchEvent(new KeyboardEvent('keydown', { key: 'k', metaKey: true }))}
|
|
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-tertiary bg-tertiary/50 hover:bg-tertiary rounded-md transition-colors duration-fast"
|
|
>
|
|
<Command size={14} />
|
|
<span>Search...</span>
|
|
<kbd className="ml-auto text-[10px] font-mono bg-primary px-1.5 py-0.5 rounded">⌘K</kbd>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Navigation */}
|
|
<Sidebar />
|
|
|
|
{/* Footer */}
|
|
<div className="mt-auto p-3 border-t border-default">
|
|
<UserMenu />
|
|
</div>
|
|
</aside>
|
|
|
|
{/* Main Content */}
|
|
<main
|
|
id="main-content"
|
|
className="flex-1 overflow-auto pb-20 md:pb-6 custom-scrollbar bg-primary"
|
|
role="main"
|
|
>
|
|
<PageTitleUpdater />
|
|
<AnnouncementBanner />
|
|
<div className="p-4 md:p-6 lg:p-8">
|
|
{/* Global Breadcrumbs - appears on all pages */}
|
|
<Breadcrumbs />
|
|
<Outlet />
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
{/* Mobile Bottom Navigation */}
|
|
<MobileNav onMoreClick={() => setMobileSheetOpen(true)} />
|
|
|
|
{/* Mobile Navigation Sheet */}
|
|
<MobileNavSheet
|
|
isOpen={mobileSheetOpen}
|
|
onClose={() => setMobileSheetOpen(false)}
|
|
/>
|
|
|
|
{/* Command Palette */}
|
|
<CommandPalette />
|
|
|
|
{/* Session Timeout Warning */}
|
|
<SessionTimeoutWarning />
|
|
|
|
{/* Dev Tools */}
|
|
<DevTools />
|
|
</div>
|
|
);
|
|
}
|