/** * @file SettingsHub.tsx * @description Tabbed shell for /settings that hosts the dashboard's own settings plus one configuration panel per AI tool (Claude Code and Codex), with the active tab kept in the `?tool=` query param. * @author Nguyễn Ngọc Trí Vĩ */ import type { ComponentType } from "react"; import { useSearchParams } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Boxes, Settings as SettingsIcon, SquareTerminal } from "lucide-react"; import { PageTabs } from "../components/PageTabs"; import { Settings } from "./Settings"; import { CcConfig } from "./CcConfig"; import { CodexConfig } from "./CodexConfig"; interface ToolTab { id: string; labelKey: string; Icon: ComponentType<{ className?: string }>; Panel: ComponentType; } const DASHBOARD_TAB: ToolTab = { id: "dashboard", labelKey: "tools.dashboard", Icon: SettingsIcon, Panel: Settings, }; /** Add a tool here to give it a tab; that is the whole extension point. */ const TOOL_TABS: ToolTab[] = [ DASHBOARD_TAB, { id: "claude-code", labelKey: "tools.claudeCode", Icon: Boxes, Panel: CcConfig }, { id: "codex", labelKey: "tools.codex", Icon: SquareTerminal, Panel: CodexConfig }, ]; /** * Settings page shell with one tab per configuration surface. * @returns The tab bar plus the active tab's panel. */ export function SettingsHub() { const { t } = useTranslation("settings"); const [params, setParams] = useSearchParams(); const requested = params.get("tool"); const active = TOOL_TABS.find((tab) => tab.id === requested) ?? DASHBOARD_TAB; return (
setParams(id === DASHBOARD_TAB.id ? {} : { tool: id }, { replace: true })} tabs={TOOL_TABS.map(({ id, labelKey, Icon }) => ({ id, Icon, label: t(labelKey), }))} />
); }