import { useCallback } from 'react'; import { Menu, Sparkles, LogOut, Volume2, VolumeOff, Cpu, Bot, Download } from 'lucide-react'; import type { ConnectionStatus, Session, ChatMessage } from '../types'; import { useT } from '../hooks/useLocale'; import { LanguageSelector } from './LanguageSelector'; import { ThemeSwitcher } from './ThemeSwitcher'; import { sessionDisplayName } from '../lib/sessionName'; import { messagesToMarkdown, downloadFile } from '../lib/exportChat'; interface Props { status: ConnectionStatus; sessionKey: string; onToggleSidebar: () => void; activeSessionData?: Session; onLogout?: () => void; soundEnabled?: boolean; onToggleSound?: () => void; messages?: ChatMessage[]; agentAvatarUrl?: string; } export function Header({ status, sessionKey, onToggleSidebar, activeSessionData, onLogout, soundEnabled, onToggleSound, messages, agentAvatarUrl }: Props) { const t = useT(); const sessionLabel = activeSessionData ? sessionDisplayName(activeSessionData) : (sessionKey.split(':').pop() || sessionKey); const handleExport = useCallback(() => { if (!messages || messages.length === 0) return; const md = messagesToMarkdown(messages, sessionLabel); const safeLabel = sessionLabel.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 50); const date = new Date().toISOString().slice(0, 10); downloadFile(md, `${safeLabel}_${date}.md`); }, [messages, sessionLabel]); return ( <>
PinchChat
{t('header.title')}
{activeSessionData?.agentId && ( {activeSessionData.agentId} · )} {sessionLabel}
{onToggleSound && ( )} {messages && messages.length > 0 && ( )} {status === 'connected' ? (
{t('header.connected')}
) : status === 'connecting' ? (
{t('login.connecting')}
) : (
{t('header.disconnected')}
)} {onLogout && ( )}
{(() => { const ctx = activeSessionData?.contextTokens; const total = activeSessionData?.totalTokens || 0; if (!ctx) return null; const pct = Math.min(100, (total / ctx) * 100); const opacity = Math.max(0.35, Math.min(1, pct / 100)); const barStyle = { width: `${pct}%`, backgroundColor: `rgba(var(--pc-accent-rgb), ${opacity})` }; return (
{activeSessionData?.model && ( {activeSessionData.model.replace(/^.*\//, '')} )}
{(total / 1000).toFixed(1)}k / {(ctx / 1000).toFixed(0)}k tokens
); })()} ); }