{
  "aliases": [
    "settings-tabs",
    "settings-page",
    "settings-layout"
  ],
  "code": "// Research basis: GitHub, Google Account, Microsoft Account, Atlassian Account settings +\n// the IBM Carbon form grid. Every destination is a URL, so deep links and browser back/forward\n// work for free and the active item is derived from the route — never from local tab state.\n//\n// Desktop (>= lg): persistent vertical local nav on the left + bounded content on the right.\n// Mobile (< lg):   the SAME routes become a horizontal, scrollable tab strip above the content.\n// Styling uses ONLY real semantic token classes (bg-muted / text-foreground / text-muted-foreground)\n// and responsive/visibility utilities — the library ships NO bespoke settings shell/nav CSS classes.\nimport { NavLink, Outlet, Navigate } from \"react-router-dom\";\nimport { Flex } from \"@godxjp/ui/layout\";\nimport { Form, FormField, Input } from \"@godxjp/ui/data-entry\";\nimport { Button } from \"@godxjp/ui/general\";\n\nconst SECTIONS = [\n  { to: \"general\", label: \"基本情報\" },\n  { to: \"security\", label: \"セキュリティ\" },\n  { to: \"notifications\", label: \"通知\" },\n] as const;\n\n// One link renderer for BOTH breakpoints. NavLink gives us the active state (and sets\n// aria-current=\"page\") straight from the URL; semantic tokens only, no invented classes.\nconst link = ({ isActive }: { isActive: boolean }) =>\n  [\n    \"rounded-md px-3 py-2 text-sm no-underline transition-colors whitespace-nowrap\",\n    isActive\n      ? \"bg-muted text-foreground font-medium\"\n      : \"text-muted-foreground hover:text-foreground\",\n  ].join(\" \");\n\nexport function SettingsLayout() {\n  return (\n    <Flex direction=\"col\" gap=\"lg\" className=\"lg:flex-row lg:items-start\">\n      {/* < lg: horizontal, scrollable route tabs. Flex owns the row and the gap — hideFrom /\n          hideBelow own the breakpoint, so neither nav needs a hand-rolled flex or gap utility. */}\n      <Flex as=\"nav\" aria-label=\"設定\" gap={1} hideFrom=\"lg\" className=\"overflow-x-auto\">\n        {SECTIONS.map((s) => (\n          <NavLink key={s.to} to={s.to} className={link} end>{s.label}</NavLink>\n        ))}\n      </Flex>\n      {/* >= lg: persistent vertical local nav (bounded width, does not shrink). */}\n      <Flex as=\"nav\" aria-label=\"設定\" direction=\"col\" gap={1} hideBelow=\"lg\" width={224} shrink={false}>\n        {SECTIONS.map((s) => (\n          <NavLink key={s.to} to={s.to} className={link} end>{s.label}</NavLink>\n        ))}\n      </Flex>\n      {/* Bounded content region (~42rem) — the routed section renders here. min-w-0 lets it shrink. */}\n      <main className=\"min-w-0 max-w-2xl flex-1\"><Outlet /></main>\n    </Flex>\n  );\n}\n\n// A settings section. Horizontal label/control rows on desktop (collapse to stacked on mobile),\n// controls bounded to a semantic width — set ONCE on the <Form>, which every FormField reads\n// (gh#998). FormField OWNS the label↔control relationship — do NOT hand-roll <Label> + <input>. Save feedback = Button loading prop + a toast in onSuccess.\nexport function GeneralSettingsSection({\n  defaults, onSave, saving, error,\n}: { defaults: { name: string; email: string }; onSave: (v: FormData) => void; saving: boolean; error?: string }) {\n  return (\n    <Form layout=\"horizontal\" controlWidth=\"24rem\"\n      onSubmit={(e) => { e.preventDefault(); onSave(new FormData(e.currentTarget)); }}>\n      <FormField id=\"ws-name\" label=\"ワークスペース名\"\n        helper=\"請求書や共有リンクに表示されます。\" error={error}>\n        <Input id=\"ws-name\" name=\"name\" defaultValue={defaults.name} />\n      </FormField>\n      <FormField id=\"ws-email\" label=\"連絡先メール\">\n        <Input id=\"ws-email\" name=\"email\" type=\"email\" defaultValue={defaults.email} />\n      </FormField>\n      <Flex gap=\"sm\"><Button type=\"submit\" loading={saving}>変更を保存</Button></Flex>\n    </Form>\n  );\n}\n\n// Router wiring — each destination is addressable, so deep links + back/forward just work:\n//   <Route path=\"settings\" element={<SettingsLayout/>}>\n//     <Route index element={<Navigate to=\"general\" replace/>} />\n//     <Route path=\"general\" element={<GeneralSettingsSection .../>} />\n//     <Route path=\"security\" element={<SecuritySection/>} />\n//     <Route path=\"notifications\" element={<NotificationsSection/>} />\n//   </Route>\n\n// ── DO / DON'T ────────────────────────────────────────────────────────────────────────────\n// ✅ Tabs (navigation) are fine for a SMALL number (2–4) of PEER views inside ONE task/section\n//    — e.g. \"プロフィール\" ⇄ \"環境設定\" within a single account page — where losing the URL is OK.\n// ⛔ Tabs as the PRIMARY IA for broad settings (Account / Security / Billing / Members / …):\n//    use route-backed local navigation so every area is deep-linkable and back/forward works.\n// ⛔ Do NOT wrap the whole settings page in a Card, and do NOT make desktop a horizontal tab bar\n//    — persistent local nav scales to many sections; a tab strip does not.\n// ⛔ Do NOT invent CSS class names for the shell/nav/content — compose Flex + semantic tokens.",
  "name": "settings-page-responsive",
  "tagline": "Route-backed settings: persistent desktop local navigation, compact mobile tab strip, deep links + browser history, and bounded form content — NO Card wrapper, NO undefined CSS.",
  "tags": [
    "settings",
    "form",
    "tabs",
    "admin",
    "responsive",
    "navigation"
  ]
}
