Spaces:
Sleeping
Sleeping
File size: 4,174 Bytes
6cdce85 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
'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>
);
}
|