| 'use client'; |
|
|
| import Link from 'next/link'; |
| import { usePathname } from 'next/navigation'; |
| import { cn } from '@/lib/utils'; |
| import { |
| LayoutDashboard, |
| UtensilsCrossed, |
| QrCode, |
| ShoppingBag, |
| BarChart3, |
| CreditCard, |
| Settings, |
| Store, |
| ChevronLeft, |
| Menu, |
| LogOut, |
| Sparkles, |
| } from 'lucide-react'; |
| import { useState } from 'react'; |
|
|
| const navigation = [ |
| { name: 'Overview', href: '/dashboard/overview', icon: LayoutDashboard }, |
| { name: 'Menu Builder', href: '/dashboard/menu-builder', icon: UtensilsCrossed }, |
| { name: 'QR Codes', href: '/dashboard/qr-manager', icon: QrCode }, |
| { name: 'Orders', href: '/dashboard/orders', icon: ShoppingBag }, |
| { name: 'Analytics', href: '/dashboard/analytics', icon: BarChart3 }, |
| { name: 'Billing', href: '/dashboard/billing', icon: CreditCard }, |
| { name: 'Restaurant', href: '/dashboard/restaurant-setup', icon: Store }, |
| { name: 'Settings', href: '/dashboard/settings', icon: Settings }, |
| ]; |
|
|
| export function DashboardSidebar() { |
| const pathname = usePathname(); |
| const [collapsed, setCollapsed] = useState(false); |
| const [mobileOpen, setMobileOpen] = useState(false); |
|
|
| return ( |
| <> |
| {/* Mobile menu button */} |
| <button |
| onClick={() => setMobileOpen(true)} |
| className="fixed left-4 top-4 z-50 rounded-xl border border-zinc-200 bg-white p-2.5 shadow-sm lg:hidden dark:border-zinc-700 dark:bg-zinc-900" |
| > |
| <Menu className="h-5 w-5 text-zinc-600" /> |
| </button> |
| |
| {/* Mobile overlay */} |
| {mobileOpen && ( |
| <div |
| className="fixed inset-0 z-40 bg-black/30 backdrop-blur-sm lg:hidden" |
| onClick={() => setMobileOpen(false)} |
| /> |
| )} |
| |
| {/* Sidebar */} |
| <aside |
| className={cn( |
| 'fixed inset-y-0 left-0 z-50 flex flex-col border-r border-zinc-200/60 bg-white transition-all duration-300 dark:border-zinc-800 dark:bg-zinc-950', |
| collapsed ? 'w-[72px]' : 'w-[260px]', |
| mobileOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0' |
| )} |
| > |
| {/* Logo */} |
| <div className={cn('flex h-16 items-center border-b border-zinc-200/60 px-4 dark:border-zinc-800', collapsed && 'justify-center')}> |
| <Link href="/dashboard/overview" className="flex items-center gap-2.5"> |
| <div className="flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-emerald-500 to-cyan-500 shadow-sm"> |
| <Sparkles className="h-4 w-4 text-white" /> |
| </div> |
| {!collapsed && ( |
| <span className="text-lg font-bold tracking-tight text-zinc-900 dark:text-white"> |
| Scan<span className="text-emerald-600">Menu</span> |
| </span> |
| )} |
| </Link> |
| </div> |
| |
| {/* Navigation */} |
| <nav className="flex-1 space-y-1 overflow-y-auto px-3 py-4"> |
| {navigation.map((item) => { |
| const isActive = pathname === item.href || pathname?.startsWith(item.href + '/'); |
| return ( |
| <Link |
| key={item.name} |
| href={item.href} |
| onClick={() => setMobileOpen(false)} |
| className={cn( |
| 'group flex items-center gap-3 rounded-xl px-3 py-2.5 text-sm font-medium transition-all duration-150', |
| isActive |
| ? 'bg-zinc-900 text-white shadow-sm dark:bg-white dark:text-zinc-900' |
| : 'text-zinc-600 hover:bg-zinc-100 hover:text-zinc-900 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-white', |
| collapsed && 'justify-center px-2' |
| )} |
| > |
| <item.icon className={cn('h-[18px] w-[18px] shrink-0', isActive ? 'text-current' : 'text-zinc-400 group-hover:text-zinc-600 dark:group-hover:text-zinc-300')} /> |
| {!collapsed && <span>{item.name}</span>} |
| </Link> |
| ); |
| })} |
| </nav> |
| |
| {/* Footer */} |
| <div className="border-t border-zinc-200/60 p-3 dark:border-zinc-800"> |
| {!collapsed && ( |
| <div className="mb-3 rounded-xl bg-gradient-to-br from-emerald-50 to-cyan-50 p-3 dark:from-emerald-950/30 dark:to-cyan-950/30"> |
| <p className="text-xs font-semibold text-emerald-700 dark:text-emerald-400">Pro Plan</p> |
| <p className="mt-0.5 text-[11px] text-emerald-600/70 dark:text-emerald-500/70">Unlimited menus & orders</p> |
| </div> |
| )} |
| <button |
| className={cn( |
| 'flex w-full items-center gap-3 rounded-xl px-3 py-2.5 text-sm font-medium text-zinc-500 transition-all hover:bg-zinc-100 hover:text-zinc-700 dark:hover:bg-zinc-800', |
| collapsed && 'justify-center px-2' |
| )} |
| > |
| <LogOut className="h-[18px] w-[18px]" /> |
| {!collapsed && <span>Sign Out</span>} |
| </button> |
| |
| {/* Collapse toggle β desktop only */} |
| <button |
| onClick={() => setCollapsed(!collapsed)} |
| className="mt-2 hidden w-full items-center justify-center rounded-xl p-2 text-zinc-400 transition-all hover:bg-zinc-100 hover:text-zinc-600 lg:flex dark:hover:bg-zinc-800" |
| > |
| <ChevronLeft className={cn('h-4 w-4 transition-transform', collapsed && 'rotate-180')} /> |
| </button> |
| </div> |
| </aside> |
| </> |
| ); |
| } |
|
|