Spaces:
Sleeping
Sleeping
| "use client"; | |
| import { useEffect, useState } from "react"; | |
| import { | |
| AlertTriangle, | |
| Download, | |
| FileSearch, | |
| LayoutGrid, | |
| ScrollText, | |
| Table2, | |
| } from "lucide-react"; | |
| import type { Citation, DocumentDetail } from "@/lib/types"; | |
| import DocumentViewer from "@/components/DocumentViewer"; | |
| import FieldsPanel from "@/components/FieldsPanel"; | |
| import ClassifyPanel from "@/components/ClassifyPanel"; | |
| import SummaryPanel from "@/components/SummaryPanel"; | |
| import ExportPanel from "@/components/ExportPanel"; | |
| import ProcessingBar from "@/components/ProcessingBar"; | |
| type Tab = "viewer" | "fields" | "classify" | "summary" | "export"; | |
| const TABS: { id: Tab; label: string; icon: any }[] = [ | |
| { id: "viewer", label: "Viewer", icon: FileSearch }, | |
| { id: "fields", label: "Fields & Tables", icon: Table2 }, | |
| { id: "classify", label: "Classification", icon: LayoutGrid }, | |
| { id: "summary", label: "Summary", icon: ScrollText }, | |
| { id: "export", label: "Export", icon: Download }, | |
| ]; | |
| export default function Workspace({ | |
| detail, | |
| provider, | |
| focusCitation, | |
| onRefresh, | |
| }: { | |
| detail: DocumentDetail | null; | |
| provider: string | null; | |
| focusCitation: Citation | null; | |
| onRefresh: () => void; | |
| }) { | |
| const [tab, setTab] = useState<Tab>("viewer"); | |
| useEffect(() => { | |
| if (focusCitation) setTab("viewer"); | |
| }, [focusCitation]); | |
| const anomalyCount = detail?.anomalies?.length ?? 0; | |
| if (!detail) { | |
| return ( | |
| <div className="flex h-full flex-col items-center justify-center px-6 text-center"> | |
| <div className="relative mb-5"> | |
| <div className="absolute inset-0 rounded-2xl bg-brand-500/10 blur-2xl" /> | |
| <div className="relative flex h-16 w-16 items-center justify-center rounded-2xl border border-white/[0.06] bg-surface-900"> | |
| <FileSearch className="text-white/30" size={28} /> | |
| </div> | |
| </div> | |
| <h2 className="text-base font-semibold text-white/70">Your workspace</h2> | |
| <p className="mt-1.5 max-w-sm text-sm leading-relaxed text-white/40"> | |
| Upload a document to view it here alongside extracted fields, | |
| classification, summary, and export controls. | |
| </p> | |
| <div className="mt-6 grid grid-cols-2 gap-2 text-left"> | |
| {[ | |
| ["Viewer", "See pages with source highlights"], | |
| ["Fields", "Structured data + confidence"], | |
| ["Classify", "Auto document-type detection"], | |
| ["Export", "JSON · CSV · Excel"], | |
| ].map(([t, d]) => ( | |
| <div | |
| key={t} | |
| className="rounded-xl border border-white/[0.05] bg-surface-900/50 px-3 py-2.5" | |
| > | |
| <p className="text-xs font-medium text-white/70">{t}</p> | |
| <p className="mt-0.5 text-[11px] text-white/35">{d}</p> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div className="flex h-full flex-col"> | |
| <ProcessingBar detail={detail} /> | |
| {/* tabs */} | |
| <div className="flex items-center gap-1 px-3 py-2"> | |
| {TABS.map((t) => { | |
| const Icon = t.icon; | |
| const active = tab === t.id; | |
| return ( | |
| <button | |
| key={t.id} | |
| onClick={() => setTab(t.id)} | |
| className={`relative flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium transition ${ | |
| active | |
| ? "bg-white/[0.07] text-white shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)]" | |
| : "text-white/45 hover:bg-white/[0.03] hover:text-white/75" | |
| }`} | |
| > | |
| <Icon size={13} className={active ? "text-brand-300" : ""} /> | |
| {t.label} | |
| {t.id === "fields" && anomalyCount > 0 && ( | |
| <span className="ml-0.5 flex items-center gap-0.5 rounded-full bg-amber-500/20 px-1.5 text-[10px] font-semibold text-amber-300"> | |
| <AlertTriangle size={9} /> | |
| {anomalyCount} | |
| </span> | |
| )} | |
| </button> | |
| ); | |
| })} | |
| </div> | |
| <div className="hairline opacity-60" /> | |
| {/* body */} | |
| <div className="min-h-0 flex-1 overflow-hidden"> | |
| {tab === "viewer" && ( | |
| <DocumentViewer detail={detail} focusCitation={focusCitation} /> | |
| )} | |
| {tab === "fields" && ( | |
| <FieldsPanel detail={detail} provider={provider} onRefresh={onRefresh} /> | |
| )} | |
| {tab === "classify" && ( | |
| <ClassifyPanel detail={detail} provider={provider} onRefresh={onRefresh} /> | |
| )} | |
| {tab === "summary" && ( | |
| <SummaryPanel detail={detail} provider={provider} onRefresh={onRefresh} /> | |
| )} | |
| {tab === "export" && <ExportPanel detail={detail} />} | |
| </div> | |
| </div> | |
| ); | |
| } | |