diff --git a/tenant-dashboard/src/components/layout/Header.tsx b/tenant-dashboard/src/components/layout/Header.tsx index 37347f5..587fa2d 100644 --- a/tenant-dashboard/src/components/layout/Header.tsx +++ b/tenant-dashboard/src/components/layout/Header.tsx @@ -26,6 +26,7 @@ import { } from "lucide-react"; import { cn, getInitials } from "@/lib/utils"; import { CommandPalette, useCommandPalette } from "@/components/design-system"; +import { useResponsive, responsive } from "@/hooks/useResponsive"; interface HeaderProps { onMenuToggle?: () => void; @@ -35,6 +36,7 @@ interface HeaderProps { export function Header({ onMenuToggle, className }: HeaderProps) { const [theme, setTheme] = React.useState<"light" | "dark">("light"); const { open, setOpen, CommandPalette: CommandPaletteComponent } = useCommandPalette(); + const { isMobile, isTablet } = useResponsive(); const [notifications] = React.useState([ { id: "1", @@ -82,18 +84,38 @@ export function Header({ onMenuToggle, className }: HeaderProps) { }; return ( -
+
-
+
+ {/* Mobile tenant info - condensed */} +
+
+ {tenant.avatar ? ( + {tenant.name} + ) : ( + getInitials(tenant.name) + )} +
+
+

{tenant.name}

+
+
+ + {/* Desktop tenant info - full */}
@@ -115,19 +137,33 @@ export function Header({ onMenuToggle, className }: HeaderProps) {
-
- {/* Command Palette Trigger */} +
+ {/* Command Palette Trigger - responsive sizing */} {/* Theme Toggle */} @@ -135,7 +171,8 @@ export function Header({ onMenuToggle, className }: HeaderProps) { variant="ghost" size="icon" onClick={toggleTheme} - className="h-9 w-9" + className={cn("h-9 w-9", responsive.touchTarget)} + aria-label={`Switch to ${theme === "light" ? "dark" : "light"} mode`} > {theme === "light" ? ( @@ -147,7 +184,12 @@ export function Header({ onMenuToggle, className }: HeaderProps) { {/* Notifications */} - @@ -211,11 +267,16 @@ export function Header({ onMenuToggle, className }: HeaderProps) { - +
{user.name} - {user.email} + {user.email}
- + Profile Settings - + Account Settings - + Sign Out diff --git a/tenant-dashboard/src/components/layout/MainLayout.tsx b/tenant-dashboard/src/components/layout/MainLayout.tsx index e9ad44e..eddc59d 100644 --- a/tenant-dashboard/src/components/layout/MainLayout.tsx +++ b/tenant-dashboard/src/components/layout/MainLayout.tsx @@ -3,7 +3,9 @@ import React from "react"; import { Header } from "./Header"; import { Sidebar } from "./Sidebar"; +import { MobileNav } from "./MobileNav"; import { cn } from "@/lib/utils"; +import { useResponsive, responsive } from "@/hooks/useResponsive"; interface MainLayoutProps { children: React.ReactNode; @@ -12,22 +14,21 @@ interface MainLayoutProps { export function MainLayout({ children, className }: MainLayoutProps) { const [sidebarOpen, setSidebarOpen] = React.useState(false); + const { isMobile, isDesktop } = useResponsive(); return (
- {/* Mobile sidebar overlay */} - {sidebarOpen && ( -
setSidebarOpen(false)} - /> - )} + {/* Mobile Navigation */} + setSidebarOpen(false)} + /> - {/* Sidebar */} + {/* Desktop Sidebar */}
@@ -36,7 +37,11 @@ export function MainLayout({ children, className }: MainLayoutProps) { {/* Main content */}
setSidebarOpen(!sidebarOpen)} /> -
+
{children}
diff --git a/tenant-dashboard/src/components/layout/MobileNav.tsx b/tenant-dashboard/src/components/layout/MobileNav.tsx new file mode 100644 index 0000000..ad51804 --- /dev/null +++ b/tenant-dashboard/src/components/layout/MobileNav.tsx @@ -0,0 +1,225 @@ +"use client"; + +import React from "react"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { cn } from "@/lib/utils"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { responsive } from "@/hooks/useResponsive"; +import { + LayoutDashboard, + Users, + FolderOpen, + CreditCard, + Settings, + Shield, + Building2, + Home, + X, + ChevronRight, +} from "lucide-react"; + +const navigationItems = [ + { + id: "overview", + label: "Overview", + href: "/", + icon: Home, + badge: null, + }, + { + id: "dashboard", + label: "Dashboard", + href: "/dashboard", + icon: LayoutDashboard, + badge: null, + }, + { + id: "team", + label: "Team", + href: "/team", + icon: Users, + badge: "2", + }, + { + id: "workspaces", + label: "Workspaces", + href: "/workspaces", + icon: FolderOpen, + badge: null, + }, + { + id: "billing", + label: "Billing", + href: "/billing", + icon: CreditCard, + badge: null, + }, + { + id: "settings", + label: "Settings", + href: "/settings", + icon: Settings, + badge: null, + }, + { + id: "security", + label: "Security", + href: "/security", + icon: Shield, + badge: null, + }, +]; + +interface MobileNavProps { + isOpen: boolean; + onClose: () => void; + className?: string; +} + +/** + * Mobile-optimized navigation component with touch-friendly interactions + * Features: + * - Touch-friendly 44px minimum target sizes + * - Slide-in animation + * - Simplified navigation structure for mobile + * - Large text and icons for better accessibility + */ +export function MobileNav({ isOpen, onClose, className }: MobileNavProps) { + const pathname = usePathname(); + + const isActiveItem = (href: string) => { + if (href === "/") { + return pathname === "/"; + } + return pathname.startsWith(href); + }; + + // Close menu when clicking outside + React.useEffect(() => { + if (isOpen) { + document.body.style.overflow = "hidden"; + } else { + document.body.style.overflow = "unset"; + } + + return () => { + document.body.style.overflow = "unset"; + }; + }, [isOpen]); + + return ( + <> + {/* Backdrop */} + {isOpen && ( +