108 lines
4.0 KiB
TypeScript
108 lines
4.0 KiB
TypeScript
'use client';
|
|
|
|
import { AutoRefresh } from '@/components/dashboard/auto-refresh.js';
|
|
import { PriceAlertMonitor } from '@/components/dashboard/price-alert.js';
|
|
import { TickerTape } from '@/components/dashboard/ticker-tape.js';
|
|
import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet.js';
|
|
import { cn } from '@/lib/utils.js';
|
|
import { Activity, BarChart3, Flame, LayoutDashboard, Map, Menu, TrendingUp } from 'lucide-react';
|
|
import Link from 'next/link';
|
|
import { usePathname } from 'next/navigation.js';
|
|
import { useState } from 'react';
|
|
|
|
const NAV_LINKS = [
|
|
{ href: '/', label: 'Dashboard', icon: LayoutDashboard },
|
|
{ href: '/map', label: 'Map', icon: Map },
|
|
{ href: '/trends', label: 'Trends', icon: TrendingUp },
|
|
{ href: '/demand', label: 'Demand', icon: Activity },
|
|
{ href: '/generation', label: 'Generation', icon: Flame },
|
|
] as const;
|
|
|
|
export function Nav() {
|
|
const pathname = usePathname();
|
|
const [mobileOpen, setMobileOpen] = useState(false);
|
|
|
|
return (
|
|
<header className="sticky top-0 z-50 border-b border-border/40 bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60">
|
|
<TickerTape />
|
|
|
|
<div className="flex h-14 items-center px-4 sm:px-6">
|
|
<Link href="/" className="mr-4 flex items-center gap-2 sm:mr-8">
|
|
<BarChart3 className="h-5 w-5 text-chart-1" />
|
|
<span className="text-lg font-semibold tracking-tight">Energy & AI Dashboard</span>
|
|
</Link>
|
|
|
|
{/* Desktop navigation */}
|
|
<nav className="hidden items-center gap-1 md:flex">
|
|
{NAV_LINKS.map(({ href, label, icon: Icon }) => {
|
|
const isActive = href === '/' ? pathname === '/' : pathname.startsWith(href);
|
|
|
|
return (
|
|
<Link
|
|
key={href}
|
|
href={href}
|
|
className={cn(
|
|
'flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
|
|
isActive
|
|
? 'bg-accent text-accent-foreground'
|
|
: 'text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground',
|
|
)}>
|
|
<Icon className="h-4 w-4" />
|
|
{label}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
|
|
<div className="ml-auto">
|
|
<AutoRefresh />
|
|
</div>
|
|
|
|
{/* Mobile hamburger */}
|
|
<button
|
|
type="button"
|
|
className="ml-2 inline-flex h-9 w-9 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground md:hidden"
|
|
onClick={() => setMobileOpen(true)}
|
|
aria-label="Open navigation menu">
|
|
<Menu className="h-5 w-5" />
|
|
</button>
|
|
|
|
{/* Mobile sheet */}
|
|
<Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
|
|
<SheetContent side="right" className="w-64">
|
|
<SheetHeader>
|
|
<SheetTitle className="flex items-center gap-2">
|
|
<BarChart3 className="h-5 w-5 text-chart-1" />
|
|
Navigation
|
|
</SheetTitle>
|
|
</SheetHeader>
|
|
<nav className="flex flex-col gap-1 px-4">
|
|
{NAV_LINKS.map(({ href, label, icon: Icon }) => {
|
|
const isActive = href === '/' ? pathname === '/' : pathname.startsWith(href);
|
|
|
|
return (
|
|
<Link
|
|
key={href}
|
|
href={href}
|
|
onClick={() => setMobileOpen(false)}
|
|
className={cn(
|
|
'flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
|
isActive
|
|
? 'bg-accent text-accent-foreground'
|
|
: 'text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground',
|
|
)}>
|
|
<Icon className="h-4 w-4" />
|
|
{label}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
</SheetContent>
|
|
</Sheet>
|
|
</div>
|
|
|
|
<PriceAlertMonitor />
|
|
</header>
|
|
);
|
|
}
|