refactor(ui): fold Settings + Stats tabs into shared Tabs (R13 S2c step 6)
Tabs gains an `orientation` prop (+ optional per-tab `icon`/`testId`) so the two hand-rolled NAV tab-sets that duplicated its active treatment now use it: - SettingsPanel vertical rail (appearance/notifications/account) -> vertical Tabs with icons; settings-tab-* testIds preserved - Stats overview/system tabs -> Tabs (rounded-full+border -> the rounded-lg tab canonical, per the agreed tab shape) The underline ChannelPage tabs and the icon NavSidebar rail are intentionally left as distinct idioms. Self-E2E'd: settings rail switches + persists with icons, stats tabs toggle. gate green (tsc/eslint-0/vitest 136/knip/prettier). Branch not merged.
This commit is contained in:
@@ -14,6 +14,7 @@ import { type SaveState } from "./ui/DraftSaveBar";
|
||||
import { useConfirm } from "./ConfirmProvider";
|
||||
import { useWizard } from "./WizardProvider";
|
||||
import { usePrefs } from "./PrefsProvider";
|
||||
import Tabs from "./Tabs";
|
||||
import { useMe } from "../lib/useMe";
|
||||
|
||||
// The Settings page edits server-persisted preferences. Each change applies locally for instant
|
||||
@@ -61,25 +62,18 @@ export default function SettingsPanel() {
|
||||
<div className="glass rounded-2xl overflow-hidden">
|
||||
<div className="flex">
|
||||
{/* Vertical tab rail — never wraps; active is a clear accent pill. */}
|
||||
<nav className="w-32 sm:w-36 shrink-0 border-r border-border/60 p-2 flex flex-col gap-1">
|
||||
{TABS.map((tabItem) => {
|
||||
const active = tab === tabItem.id;
|
||||
return (
|
||||
<button
|
||||
key={tabItem.id}
|
||||
data-testid={`settings-tab-${tabItem.id}`}
|
||||
onClick={() => setTab(tabItem.id)}
|
||||
aria-pressed={active}
|
||||
className={`pill flex items-center gap-2 px-3 py-2 rounded-lg text-sm text-left ${
|
||||
active ? "font-medium shadow-md shadow-accent/20" : "hover:bg-card/60"
|
||||
}`}
|
||||
>
|
||||
<tabItem.icon className="w-4 h-4 shrink-0" />
|
||||
{t(`settings.tabs.${tabItem.id}`)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
<Tabs
|
||||
orientation="vertical"
|
||||
className="w-32 sm:w-36 shrink-0 border-r border-border/60 p-2 flex flex-col gap-1"
|
||||
active={tab}
|
||||
onChange={setTab}
|
||||
tabs={TABS.map((tabItem) => ({
|
||||
id: tabItem.id,
|
||||
label: t(`settings.tabs.${tabItem.id}`),
|
||||
icon: tabItem.icon,
|
||||
testId: `settings-tab-${tabItem.id}`,
|
||||
}))}
|
||||
/>
|
||||
|
||||
{/* Render only the active tab so the panel sizes to its actual content. (Stacking
|
||||
every tab in one grid cell made the whole panel as tall as the tallest tab —
|
||||
|
||||
Reference in New Issue
Block a user