113 lines
3.9 KiB
TypeScript
113 lines
3.9 KiB
TypeScript
'use client';
|
|
|
|
import { Text } from '@/ui/Text';
|
|
import { Bell, Command } from 'lucide-react';
|
|
import { usePathname } from 'next/navigation';
|
|
import { useCurrentSession } from '@/hooks/auth/useCurrentSession';
|
|
import { useState, useEffect } from 'react';
|
|
import { ShellHeader } from '@/ui/shell/Shell';
|
|
import { CommandModal } from './CommandModal';
|
|
import { UserPill } from '@/components/profile/UserPill';
|
|
import { Input } from '@/ui/Input';
|
|
import { Box } from '@/ui/Box';
|
|
import { IconButton } from '@/ui/IconButton';
|
|
import { useSidebar } from '@/components/layout/SidebarContext';
|
|
import { PublicTopNav } from '@/ui/PublicTopNav';
|
|
import { PublicNavLogin } from '@/ui/PublicNavLogin';
|
|
import { PublicNavSignup } from '@/ui/PublicNavSignup';
|
|
|
|
export function AppHeader() {
|
|
const pathname = usePathname();
|
|
const { data: session } = useCurrentSession();
|
|
const isAuthenticated = !!session;
|
|
const [isCommandOpen, setIsCommandOpen] = useState(false);
|
|
const { isCollapsed } = useSidebar();
|
|
|
|
// Simple breadcrumb logic
|
|
const pathSegments = pathname.split('/').filter(Boolean);
|
|
const breadcrumbs = pathSegments.length > 0
|
|
? pathSegments.map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(' / ')
|
|
: 'Home';
|
|
|
|
// Cmd+K Listener
|
|
useEffect(() => {
|
|
const down = (e: KeyboardEvent) => {
|
|
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
|
|
e.preventDefault();
|
|
setIsCommandOpen((open) => !open);
|
|
}
|
|
};
|
|
document.addEventListener('keydown', down);
|
|
return () => document.removeEventListener('keydown', down);
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<ShellHeader collapsed={isCollapsed}>
|
|
{/* Left: Public Navigation & Context */}
|
|
<Box display="flex" alignItems="center" gap={6} flex={1}>
|
|
{/* Public Top Navigation - Only when not authenticated */}
|
|
{!isAuthenticated && (
|
|
<PublicTopNav pathname={pathname} />
|
|
)}
|
|
|
|
{/* Context & Search - Only when authenticated */}
|
|
{isAuthenticated && (
|
|
<>
|
|
<Text size="sm" variant="med" weight="medium" style={{ minWidth: '100px' }}>
|
|
{breadcrumbs}
|
|
</Text>
|
|
|
|
{/* Command Search Trigger */}
|
|
<Box display={{ base: 'none', md: 'block' }}>
|
|
<Input
|
|
readOnly
|
|
onClick={() => setIsCommandOpen(true)}
|
|
placeholder="Search or type a command..."
|
|
variant="search"
|
|
width="24rem"
|
|
rightElement={
|
|
<Box display="flex" alignItems="center" gap={1} paddingX={1.5} paddingY={0.5} rounded bg="white/5" border>
|
|
<Command size={10} />
|
|
<Text size="xs" font="mono" variant="low" style={{ fontSize: '10px' }}>K</Text>
|
|
</Box>
|
|
}
|
|
className="cursor-pointer"
|
|
/>
|
|
</Box>
|
|
</>
|
|
)}
|
|
</Box>
|
|
|
|
{/* Right: User & Notifications */}
|
|
<Box display="flex" alignItems="center" gap={4}>
|
|
{/* Notifications - Only when authed */}
|
|
{isAuthenticated && (
|
|
<Box position="relative">
|
|
<IconButton
|
|
icon={Bell}
|
|
variant="ghost"
|
|
title="Notifications"
|
|
/>
|
|
<Box position="absolute" top={2} right={2} width={1.5} height={1.5} bg="var(--ui-color-intent-primary)" rounded="full" ring="2px" />
|
|
</Box>
|
|
)}
|
|
|
|
{/* Public Login/Signup Buttons - Only when not authenticated */}
|
|
{!isAuthenticated && (
|
|
<>
|
|
<PublicNavLogin />
|
|
<PublicNavSignup />
|
|
</>
|
|
)}
|
|
|
|
{/* User Pill (Handles Auth & Menu) - Only when authenticated */}
|
|
{isAuthenticated && <UserPill />}
|
|
</Box>
|
|
</ShellHeader>
|
|
|
|
<CommandModal isOpen={isCommandOpen} onClose={() => setIsCommandOpen(false)} />
|
|
</>
|
|
);
|
|
}
|