import { Activity, useRef, useState } from "react"; import type { ReactElement } from "react"; import AiTextDetector from "./components/AiTextDetector"; import AnalyzeForm from "./components/AnalyzeForm"; import BatchUpload from "./components/BatchUpload"; import CompareModels from "./components/CompareModels"; import HowItWorks from "./components/HowItWorks"; const TABS = ["Analyze", "Batch", "Compare Sentiment", "AI Detector", "How it works"] as const; type Tab = (typeof TABS)[number]; // Panels are static JSX, hoisted so the elements are created once. const PANELS: Record = { Analyze: , Batch: , "Compare Sentiment": , "AI Detector": , "How it works": , }; const slug = (t: Tab) => t.toLowerCase().replace(/\W+/g, "-"); export default function App() { const [tab, setTab] = useState("Analyze"); const tabRefs = useRef(new Map()); // Roving tabindex per the WAI-ARIA tabs pattern: arrows move selection and // focus together; only the active tab is in the page tab order. const move = (dir: 1 | -1) => { const next = TABS[(TABS.indexOf(tab) + dir + TABS.length) % TABS.length]; setTab(next); tabRefs.current.get(next)?.focus(); }; return (
{/* Wordmark device: the three sentiment classes as a tiny bar readout. This is the only place chroma appears outside data. */}
{TABS.map((t) => ( ))}
{/* Activity keeps every panel mounted: a half-typed sentence on Analyze or an uploaded batch survives a trip to How it works. */} {TABS.map((t) => (
{PANELS[t]}
))}
); }