Spaces:
Sleeping
Sleeping
| 'use client'; | |
| import { Github, Database, Boxes, ExternalLink, MessageSquare, Code } from 'lucide-react'; | |
| import { clsx } from 'clsx'; | |
| import { PROJECT_CONFIG, LINKS } from '@/config/constants'; | |
| import { WarmupIndicator } from '@/components/Chat/WarmupIndicator'; | |
| import type { AppMode } from '@/types'; | |
| interface HeaderProps { | |
| mode?: AppMode; | |
| onModeChange?: (mode: AppMode) => void; | |
| } | |
| interface BadgeProps { | |
| href: string; | |
| icon: React.ReactNode; | |
| label: string; | |
| variant: 'default' | 'accent' | 'highlight'; | |
| } | |
| function Badge({ href, icon, label, variant }: BadgeProps) { | |
| const variantStyles = { | |
| default: 'bg-zinc-800/80 hover:bg-zinc-700/80 text-zinc-300 border-zinc-700/50', | |
| accent: 'bg-teal-900/30 hover:bg-teal-800/40 text-teal-400 border-teal-700/40', | |
| highlight: 'bg-amber-900/30 hover:bg-amber-800/40 text-amber-400 border-amber-700/40', | |
| }; | |
| return ( | |
| <a | |
| href={href} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className={`inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium | |
| transition-all duration-200 hover:scale-[1.02] border ${variantStyles[variant]}`} | |
| > | |
| {icon} | |
| <span>{label}</span> | |
| <ExternalLink className="w-3 h-3 opacity-50" /> | |
| </a> | |
| ); | |
| } | |
| interface ModeToggleProps { | |
| mode: AppMode; | |
| onModeChange: (mode: AppMode) => void; | |
| } | |
| function ModeToggle({ mode, onModeChange }: ModeToggleProps) { | |
| return ( | |
| <div className="flex items-center bg-zinc-800/60 rounded-lg p-1 border border-zinc-700/50"> | |
| <button | |
| onClick={() => onModeChange('chat')} | |
| className={clsx( | |
| 'flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium transition-all', | |
| mode === 'chat' | |
| ? 'bg-teal-600 text-white shadow-sm' | |
| : 'text-zinc-400 hover:text-zinc-200 hover:bg-zinc-700/50' | |
| )} | |
| > | |
| <MessageSquare className="w-3.5 h-3.5" /> | |
| <span>Chat</span> | |
| </button> | |
| <button | |
| onClick={() => onModeChange('practice')} | |
| className={clsx( | |
| 'flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium transition-all', | |
| mode === 'practice' | |
| ? 'bg-teal-600 text-white shadow-sm' | |
| : 'text-zinc-400 hover:text-zinc-200 hover:bg-zinc-700/50' | |
| )} | |
| > | |
| <Code className="w-3.5 h-3.5" /> | |
| <span>Practice</span> | |
| </button> | |
| </div> | |
| ); | |
| } | |
| export function Header({ mode = 'chat', onModeChange }: HeaderProps) { | |
| return ( | |
| <header className="bg-zinc-900/95 backdrop-blur-sm border-b border-zinc-800/80 sticky top-0 z-50"> | |
| <div className="max-w-7xl mx-auto px-4 py-3"> | |
| <div className="flex flex-col sm:flex-row sm:items-center gap-3"> | |
| {/* Title - far left */} | |
| <div className="flex-shrink-0"> | |
| <div className="flex items-center gap-2"> | |
| <h1 className="text-lg font-semibold text-zinc-100 tracking-tight"> | |
| {PROJECT_CONFIG.name} | |
| </h1> | |
| <WarmupIndicator /> | |
| </div> | |
| <p className="text-xs text-zinc-500"> | |
| {PROJECT_CONFIG.description} | |
| </p> | |
| </div> | |
| {/* Mode Toggle - center */} | |
| {onModeChange && ( | |
| <div className="flex-1 flex justify-center"> | |
| <ModeToggle mode={mode} onModeChange={onModeChange} /> | |
| </div> | |
| )} | |
| {/* Badges - far right */} | |
| <div className="flex flex-wrap items-center gap-2 flex-shrink-0 sm:ml-auto"> | |
| <Badge | |
| href={LINKS.github} | |
| icon={<Github className="w-3.5 h-3.5" />} | |
| label="GitHub" | |
| variant="default" | |
| /> | |
| <Badge | |
| href={LINKS.dataset} | |
| icon={<Database className="w-3.5 h-3.5" />} | |
| label="Dataset" | |
| variant="highlight" | |
| /> | |
| <Badge | |
| href={LINKS.models} | |
| icon={<Boxes className="w-3.5 h-3.5" />} | |
| label="Models" | |
| variant="accent" | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| ); | |
| } | |