feat(settings): one page per section with a grouped nav and search
Settings moves from a tab bar to /settings/<section>: a left nav grouped General / Agents / Routing / Git / Projects (a select on narrow screens), a search box over every section (Ctrl/Cmd+F, Enter opens the first match), and row primitives. Each AI tool has its page under agents/<id>, the AI Tools modal becomes the Agents page, Pricing shows every vendor, Git → Worktrees sets which untracked worktrees the sidebar lists, and each project gets a page with its own worktree override and Forget all. ?tool= and #ai-tools links redirect to the path form.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @file WorktreeVisibilitySettings — Settings → Git → Worktrees: whether the
|
||||
* sidebar's project tree lists a repo's untracked worktrees, and which sources
|
||||
* of them (`.claude/worktrees/*`, AgentHub-managed) it hides. Writes the tree's
|
||||
* own localStorage prefs (`lib/projectTreePrefs.ts`), so the sidebar follows at
|
||||
* once; a project's own override lives on its Settings → Projects page.
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useProjectTreePrefs, writeProjectTreePrefs } from "../../lib/projectTreePrefs";
|
||||
import { SettingsSection, SettingsSwitchRow } from "./SettingsRow";
|
||||
|
||||
export const WORKTREE_SOURCES = ["claude", "agenthub"] as const;
|
||||
|
||||
/** Show/hide switches for each source over a `hideSources` list. */
|
||||
export function SourceSwitches({
|
||||
hidden,
|
||||
onChange,
|
||||
disabled = false,
|
||||
}: {
|
||||
hidden: string[];
|
||||
onChange: (hidden: string[]) => void;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation("settings");
|
||||
return (
|
||||
<>
|
||||
{WORKTREE_SOURCES.map((src) => (
|
||||
<SettingsSwitchRow
|
||||
key={src}
|
||||
label={t(`worktrees.${src}`)}
|
||||
description={t(`worktrees.${src}Desc`)}
|
||||
checked={!hidden.includes(src)}
|
||||
disabled={disabled}
|
||||
onChange={(show) => onChange(show ? hidden.filter((s) => s !== src) : [...hidden, src])}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function WorktreeVisibilitySettings() {
|
||||
const { t } = useTranslation("settings");
|
||||
const prefs = useProjectTreePrefs();
|
||||
return (
|
||||
<SettingsSection title={t("worktrees.title")} description={t("worktrees.description")}>
|
||||
<SettingsSwitchRow
|
||||
label={t("worktrees.showUntracked")}
|
||||
description={t("worktrees.showUntrackedDesc")}
|
||||
checked={prefs.showUntracked}
|
||||
onChange={(showUntracked) => writeProjectTreePrefs({ showUntracked })}
|
||||
/>
|
||||
<SourceSwitches
|
||||
hidden={prefs.hideSources}
|
||||
disabled={!prefs.showUntracked}
|
||||
onChange={(hideSources) => writeProjectTreePrefs({ hideSources })}
|
||||
/>
|
||||
</SettingsSection>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user