refactor(channels): adopt shared Tabs + usePersistedTab for the manager tab row (R13 S2b)
Retire the hand-rolled channel-manager view pills for the shared <Tabs> component (given an optional className so it embeds in the justify-between header without the default mb-4), and back view + layout on usePersistedTab instead of manual getAccountRaw/setAccountRaw useState. That subsumes the account-pin re-hydrate (usePersistedTab now re-reads on the pin), so ChannelsProvider's bespoke markManagerDirty/useAccountRehydrate is gone; setView keeps the history-tab logic (_chTab pushState + popstate) layered on the stable raw setter, and useAccountPersistedState's setter is now memoized so that stable action holds. Per the user's call, unify every channel-manager pill on the rounded-lg idiom: the view tabs via <Tabs>, the sync chips and tag chips + the "manage tags" affordance from rounded-full to rounded-lg — no more odd-one-out rounded-full. gate-green: tsc + vitest 120 + eslint-0 + knip + prettier. Self-E2E'd: tab switch, browser Back across tabs (Blocked->Hidden->Subscriptions with localStorage in sync), and a fresh tab restoring view=hidden on the FIRST load; zero console errors.
This commit is contained in:
@@ -18,13 +18,17 @@ export default function Tabs({
|
||||
tabs,
|
||||
active,
|
||||
onChange,
|
||||
className = "flex flex-wrap gap-1 mb-4",
|
||||
}: {
|
||||
tabs: TabDef[];
|
||||
active: string;
|
||||
onChange: (id: string) => void;
|
||||
// Override the row wrapper — e.g. the channel manager embeds the rail in a justify-between header
|
||||
// and drops the default bottom margin. Omit for the standalone-row default.
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-1 mb-4">
|
||||
<div className={className}>
|
||||
{tabs.map((tb) => {
|
||||
const on = tb.id === active;
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user