import { useState, useRef, useEffect } from 'react' import { useStore } from '../stores' import { ConfirmDialog } from './ConfirmDialog' import { api } from '../api' import { Settings, ChevronDown, Plus, Trash2, Download, Upload, } from 'lucide-react' export function Navbar() { const { t, locale, setSettingsOpen, currentProject, currentProjectId, projects, createProject, switchProject, deleteProject, fetchBugs, } = useStore() const zh = locale === 'zh' // Project switching const [projDropdown, setProjDropdown] = useState(false) const [projCreating, setProjCreating] = useState(false) const [projNewName, setProjNewName] = useState('') const [projCreateLoading, setProjCreateLoading] = useState(false) const [projImportLoading, setProjImportLoading] = useState(false) const [projDeleteTarget, setProjDeleteTarget] = useState<{ id: string; name: string } | null>(null) const projDropdownRef = useRef(null) const projImportRef = useRef(null) useEffect(() => { const handler = (e: MouseEvent) => { if (projDropdownRef.current && !projDropdownRef.current.contains(e.target as Node)) { setProjDropdown(false) setProjCreating(false) } } document.addEventListener('mousedown', handler) return () => document.removeEventListener('mousedown', handler) }, []) const handleProjCreate = async () => { const name = projNewName.trim() if (!name || projCreateLoading) return setProjCreateLoading(true) try { await createProject(name) setProjNewName('') setProjCreating(false) setProjDropdown(false) } finally { setProjCreateLoading(false) } } const handleProjImport = async (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (!file || projImportLoading) return setProjImportLoading(true) try { const res = await api.importProject(currentProjectId, file) if (res.ok) { await fetchBugs() setProjDropdown(false) } else { console.error('Import failed:',res.error) } } catch (err) { console.error('Import failed:',err) } finally { setProjImportLoading(false) } e.target.value = '' } return (
{/* Left Logo */}
BugPack {t.app.name}
{/* Right side */}
{/* Project switcher */}
{projDropdown && (
{/* Project list */}
{projects.map((p) => (
{ switchProject(p.id); setProjDropdown(false) }} > {p.name}
))}
{/* New project input (shown when expanded) */} {projCreating && (
setProjNewName(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') handleProjCreate(); if (e.key === 'Escape') setProjCreating(false) }} placeholder={zh ? '项目名称' : 'Project name'} className="flex-1 px-2 py-1.5 bg-bg-input border border-border rounded text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:border-accent" />
)} {/* New / Export / Import in one row */}
{!projCreating && ( )} setProjDropdown(false)} className="flex-1 flex items-center justify-center gap-1 px-2 py-1.5 text-xs text-text-secondary hover:bg-bg-hover rounded transition-colors" > {zh ? '导出' : 'Export'}
)}
{/* Settings */}
{/* Delete project confirmation */} { if (projDeleteTarget) deleteProject(projDeleteTarget.id); setProjDeleteTarget(null) }} onCancel={() => setProjDeleteTarget(null)} />
) }