@urbicon-ui/design-content 6.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +54 -0
  2. package/content/auth/components/account-settings/llm.txt +33 -0
  3. package/content/auth/components/forgot-password-page/llm.txt +25 -0
  4. package/content/auth/components/invitation-manager/llm.txt +28 -0
  5. package/content/auth/components/login-page/llm.txt +34 -0
  6. package/content/auth/components/notification-badge/llm.txt +21 -0
  7. package/content/auth/components/notification-center/llm.txt +33 -0
  8. package/content/auth/components/notification-listener/llm.txt +24 -0
  9. package/content/auth/components/passkey-manager/llm.txt +27 -0
  10. package/content/auth/components/push-permission-prompt/llm.txt +32 -0
  11. package/content/auth/components/register-page/llm.txt +35 -0
  12. package/content/auth/components/reset-password-page/llm.txt +26 -0
  13. package/content/auth/components/session-manager/llm.txt +32 -0
  14. package/content/auth/components/two-factor-manager/llm.txt +40 -0
  15. package/content/auth/components/verify-email-page/llm.txt +25 -0
  16. package/content/blocks/components/area-chart/llm.txt +46 -0
  17. package/content/blocks/components/bar-chart/llm.txt +44 -0
  18. package/content/blocks/components/calendar/llm.txt +105 -0
  19. package/content/blocks/components/chart-frame/llm.txt +38 -0
  20. package/content/blocks/components/command-palette/llm.txt +60 -0
  21. package/content/blocks/components/composition-bar/llm.txt +69 -0
  22. package/content/blocks/components/currency-input/llm.txt +65 -0
  23. package/content/blocks/components/date-picker/llm.txt +90 -0
  24. package/content/blocks/components/donut-chart/llm.txt +45 -0
  25. package/content/blocks/components/empty-state/llm.txt +43 -0
  26. package/content/blocks/components/file-upload/llm.txt +76 -0
  27. package/content/blocks/components/guide/llm.txt +49 -0
  28. package/content/blocks/components/guide-article/llm.txt +30 -0
  29. package/content/blocks/components/guide-beacon/llm.txt +38 -0
  30. package/content/blocks/components/guide-hint/llm.txt +41 -0
  31. package/content/blocks/components/guide-marker/llm.txt +36 -0
  32. package/content/blocks/components/guide-mention/llm.txt +31 -0
  33. package/content/blocks/components/guide-panel/llm.txt +42 -0
  34. package/content/blocks/components/guide-provider/llm.txt +31 -0
  35. package/content/blocks/components/line-chart/llm.txt +45 -0
  36. package/content/blocks/components/locale-switcher/llm.txt +44 -0
  37. package/content/blocks/components/planner/llm.txt +68 -0
  38. package/content/blocks/components/sankey/llm.txt +72 -0
  39. package/content/blocks/components/sidebar-layout/llm.txt +87 -0
  40. package/content/blocks/components/sparkline/llm.txt +33 -0
  41. package/content/blocks/components/theme-switcher/llm.txt +40 -0
  42. package/content/blocks/primitives/accordion/llm.txt +57 -0
  43. package/content/blocks/primitives/alert/llm.txt +54 -0
  44. package/content/blocks/primitives/avatar/llm.txt +61 -0
  45. package/content/blocks/primitives/badge/llm.txt +60 -0
  46. package/content/blocks/primitives/breadcrumb/llm.txt +47 -0
  47. package/content/blocks/primitives/button/llm.txt +80 -0
  48. package/content/blocks/primitives/button-group/llm.txt +65 -0
  49. package/content/blocks/primitives/card/llm.txt +68 -0
  50. package/content/blocks/primitives/checkbox/llm.txt +61 -0
  51. package/content/blocks/primitives/collapsible/llm.txt +66 -0
  52. package/content/blocks/primitives/combobox/llm.txt +86 -0
  53. package/content/blocks/primitives/confirm-dialog/llm.txt +47 -0
  54. package/content/blocks/primitives/dialog/llm.txt +59 -0
  55. package/content/blocks/primitives/drawer/llm.txt +54 -0
  56. package/content/blocks/primitives/form-field/llm.txt +43 -0
  57. package/content/blocks/primitives/input/llm.txt +73 -0
  58. package/content/blocks/primitives/menu/llm.txt +81 -0
  59. package/content/blocks/primitives/pagination/llm.txt +68 -0
  60. package/content/blocks/primitives/popover/llm.txt +72 -0
  61. package/content/blocks/primitives/progress/llm.txt +55 -0
  62. package/content/blocks/primitives/radio-group/llm.txt +53 -0
  63. package/content/blocks/primitives/segment-group/llm.txt +51 -0
  64. package/content/blocks/primitives/select/llm.txt +130 -0
  65. package/content/blocks/primitives/separator/llm.txt +45 -0
  66. package/content/blocks/primitives/sidebar/llm.txt +79 -0
  67. package/content/blocks/primitives/skeleton/llm.txt +54 -0
  68. package/content/blocks/primitives/slider/llm.txt +82 -0
  69. package/content/blocks/primitives/spinner/llm.txt +46 -0
  70. package/content/blocks/primitives/stepper/llm.txt +60 -0
  71. package/content/blocks/primitives/tab/llm.txt +72 -0
  72. package/content/blocks/primitives/textarea/llm.txt +61 -0
  73. package/content/blocks/primitives/toast/llm.txt +45 -0
  74. package/content/blocks/primitives/toggle/llm.txt +62 -0
  75. package/content/blocks/primitives/toolbar/llm.txt +60 -0
  76. package/content/blocks/primitives/tooltip/llm.txt +54 -0
  77. package/content/component-catalog.json +5010 -0
  78. package/content/design-system/patterns/dashboard.md +55 -0
  79. package/content/design-system/patterns/form-page.md +69 -0
  80. package/content/design-system/patterns/onboarding-guide.md +50 -0
  81. package/content/design-system/patterns/planning-board.md +46 -0
  82. package/content/design-system/patterns/settings-page.md +48 -0
  83. package/content/design-system/patterns/tab-navigation.md +136 -0
  84. package/content/design-system/principles.md +260 -0
  85. package/content/docs/components/api-reference/llm.txt +32 -0
  86. package/content/docs/components/code-example/llm.txt +44 -0
  87. package/content/docs/components/code-panel/llm.txt +26 -0
  88. package/content/docs/components/docs-layout/llm.txt +61 -0
  89. package/content/docs/components/info-card/llm.txt +31 -0
  90. package/content/docs/components/playground-configurator/llm.txt +49 -0
  91. package/content/docs/components/section/llm.txt +46 -0
  92. package/content/docs/components/table-of-contents/llm.txt +48 -0
  93. package/content/docs/components/types-reference/llm.txt +38 -0
  94. package/content/guides/llms-full-template.md +1019 -0
  95. package/content/icons.json +4834 -0
  96. package/content/meta.json +5 -0
  97. package/content/table/table/llm.txt +110 -0
  98. package/content/verbs/adopt.md +33 -0
  99. package/content/verbs/audit.md +29 -0
  100. package/content/verbs/compose.md +38 -0
  101. package/content/verbs/critique.md +27 -0
  102. package/content/verbs/fix.md +29 -0
  103. package/content/verbs/migrate.md +30 -0
  104. package/content/verbs/onboard.md +33 -0
  105. package/content/verbs/polish.md +25 -0
  106. package/content/verbs/redesign.md +29 -0
  107. package/content/verbs/retheme.md +29 -0
  108. package/package.json +45 -0
  109. package/src/content-loader.test.ts +78 -0
  110. package/src/content-loader.ts +97 -0
  111. package/src/index.ts +23 -0
@@ -0,0 +1,55 @@
1
+ # Dashboard
2
+
3
+ Data-rich overview page with metrics, charts, and action shortcuts.
4
+
5
+ ## Layout
6
+
7
+ - **Structure:** full-width content area, optionally within `SidebarLayout` for app navigation
8
+ - **Grid:** CSS grid with responsive columns. Desktop: 3-4 columns for stat tiles, 2 columns for charts/tables. Mobile: single column stack.
9
+ - **Content:** no max-width constraint (data-dense view). Cards fill available space.
10
+ - **Spacing:** `gap-4` between grid items, `gap-6` between sections (stats row, charts row, table row)
11
+
12
+ ## Component Selection
13
+
14
+ | UI Need | Component | Configuration |
15
+ |---|---|---|
16
+ | Stat/KPI tile | `Card` | Compact padding, prominent number + label + trend indicator |
17
+ | Trend direction | `Badge` | `intent="success"` for up, `intent="danger"` for down |
18
+ | Proportional data | `CompositionBar` | Horizontal bar with legend |
19
+ | Flow visualization | `Sankey` | Multi-level relationship flows |
20
+ | Data table | `Table` | With sorting, filtering; limit visible rows (5-10), link to full view |
21
+ | Quick actions | `ButtonGroup` or `Toolbar` | Top-right of page or section |
22
+ | Date range filter | `DatePicker` or `Select` | Top of page, controls all widgets below |
23
+ | Empty widget | `EmptyState` | In Card, with action to configure/populate |
24
+ | Loading state | `Skeleton` | Match widget dimensions, not generic spinners |
25
+ | Notifications | `Alert` | Persistent, at page top, for system status |
26
+
27
+ ## Section Ordering
28
+
29
+ 1. **Page header:** title + date range filter + quick actions
30
+ 2. **Stat tiles:** 3-4 KPI cards in a single row
31
+ 3. **Charts / visualizations:** 2 cards side-by-side (e.g., CompositionBar + trend chart)
32
+ 4. **Activity table:** recent activity or transactions, with link to full view
33
+ 5. **Secondary widgets:** lower-priority info, may be collapsed or tabbed
34
+
35
+ ## Behavioral Rules
36
+
37
+ - All widgets should show `Skeleton` during data loading, matching the widget's final dimensions.
38
+ - Date range filter at the top controls all widgets — changing the range refreshes everything.
39
+ - Stat tiles: show current value, trend (% change), and a subtle trend indicator (Badge with intent).
40
+ - Tables: show only 5-10 rows on the dashboard. Provide a "View all" link to the full table view.
41
+ - Auto-refresh: if data is live, use `Table` live-update capabilities (`pushInsert`, `pushUpdate`). Show a subtle timestamp ("Last updated: 2 min ago").
42
+ - Error states: per-widget errors, not a page-level error. Show `Alert` within the `Card` that failed.
43
+
44
+ ## Anti-Patterns
45
+
46
+ - Do not use full-featured `Table` with all controls (grouping, column reorder, etc.) on the dashboard. Keep it compact.
47
+ - Do not mix different Card styles within the same section. Stat tiles should look uniform.
48
+ - Do not stack more than 3 vertical sections without scroll anchoring or navigation.
49
+ - Do not use `Dialog` for drill-down. Use `Drawer` or navigate to a detail page.
50
+ - Do not show raw numbers without context. Always pair a number with a label and, where applicable, a trend.
51
+
52
+ ## Related
53
+
54
+ - Recipe: `dashboard` — complete production-ready code example
55
+ - Pattern: `settings-page` — for admin dashboards with settings navigation
@@ -0,0 +1,69 @@
1
+ # Form Page
2
+
3
+ Standalone form for data entry — registration, creation, multi-step wizards.
4
+
5
+ ## Layout
6
+
7
+ - **Structure:** centered content area with constrained width
8
+ - **Content:** max-width 560px for simple forms, 720px for complex forms with side context
9
+ - **Spacing:** `gap-6` between form groups, `gap-4` between fields within a group
10
+ - **Responsive:** single-column stack. On desktop, short related fields (first/last name, city/zip) can sit side-by-side in a 2-column grid.
11
+ - **Actions:** bottom of form, right-aligned. Primary action first (right), secondary (Cancel/Back) second (left).
12
+
13
+ ## Component Selection
14
+
15
+ | UI Need | Component | Configuration |
16
+ |---|---|---|
17
+ | Text input | `Input` | Wrapped in `FormField` |
18
+ | Multi-line text | `Textarea` | Wrapped in `FormField`, with character count if limited |
19
+ | Email/password | `Input` | `type="email"` / `type="password"`, wrapped in `FormField` |
20
+ | Enum selection | `Select` or `RadioGroup` | Select for 4+, RadioGroup for 2-3 visible options |
21
+ | Searchable selection | `Combobox` | 7+ options, wrapped in `FormField` |
22
+ | Boolean consent | `Checkbox` | For agreements ("I accept the terms") |
23
+ | Boolean toggle | `Toggle` | For preference settings within a form |
24
+ | Date input | `DatePicker` | Wrapped in `FormField` |
25
+ | Currency | `CurrencyInput` | Locale-aware, wrapped in `FormField` |
26
+ | File | `FileUpload` | Drag-and-drop zone, clear accepted formats |
27
+ | Form group | `Card` or visual separator | Card for distinct sections, `Separator` for light division |
28
+ | Submit action | `Button intent="primary"` | Loading state during submission |
29
+ | Multi-step | `Stepper` | Shows progress, validates per step |
30
+ | Validation feedback | `FormField` error prop | Inline, under the field |
31
+ | Submit feedback | `Toast` | Success/error after submission |
32
+
33
+ ## Validation Rules
34
+
35
+ - Validate on blur for individual fields (immediate feedback).
36
+ - Validate on submit for cross-field rules (password confirmation, date ranges).
37
+ - Show error text below the field via `FormField` error prop, not in a `Toast` or `Alert`.
38
+ - Required fields: mark optional fields with "(optional)" label suffix instead of marking required with asterisks.
39
+ - Disable submit button only while submission is in-flight (spinner), not while fields are invalid — let users click and see validation errors.
40
+
41
+ ## Multi-Step Forms
42
+
43
+ - Use `Stepper` to show progress.
44
+ - Validate the current step before allowing navigation to the next.
45
+ - Allow backward navigation without losing data.
46
+ - Show a summary/review step before final submission for important forms.
47
+ - Keep step count visible (e.g., "Step 2 of 4"), not just a progress bar.
48
+
49
+ ## Behavioral Rules
50
+
51
+ - Pre-fill known data (from user profile, previous entries, URL params).
52
+ - Persist draft state for long forms (localStorage or server-side draft).
53
+ - Show unsaved-changes warning on navigation away (`ConfirmDialog`).
54
+ - Group related fields together. Use `Card` with a heading for distinct sections (Personal Info, Payment, Shipping).
55
+ - Place help text in `FormField` description, not in `Tooltip`. Tooltips are hidden by default.
56
+
57
+ ## Anti-Patterns
58
+
59
+ - Do not use `Dialog` for forms with more than 3 fields. Use a dedicated page or `Drawer`.
60
+ - Do not use horizontal multi-column layouts for unrelated fields. Side-by-side only for naturally paired fields (first + last name, city + zip).
61
+ - Do not put the submit button above the form. Actions go at the bottom, where the user ends.
62
+ - Do not use `placeholder` as the only label. Always use `FormField` with a visible label.
63
+ - Do not auto-submit on field change without explicit user instruction.
64
+
65
+ ## Related
66
+
67
+ - Recipe: `login` — login/registration form example
68
+ - Recipe: `wizard` — multi-step form wizard example
69
+ - Pattern: `settings-page` — for forms embedded in settings sections
@@ -0,0 +1,50 @@
1
+ # Onboarding & In-App Help
2
+
3
+ Guide a first-run user and keep help available in context, using the Guide system over one
4
+ headless controller — without a modal wizard that blocks the app. Guide is the library's
5
+ sequential, system-driven overlay pattern (it decides *when*, *in what order*, and *in what
6
+ mode* help appears), unlike the spatial, event-driven overlays (`Dialog`, `Popover`, `Tooltip`).
7
+
8
+ ## Layout
9
+
10
+ - **Provider:** one `GuideProvider` near the app root, holding one `GuideController` you create yourself for programmatic control.
11
+ - **Tour renderer:** one `<Guide />` inside the provider — invisible until a tour starts; it owns the top-layer spotlight + bubble.
12
+ - **Help panel:** one `GuidePanel` — non-modal, docks to a screen edge at `--z-sidebar`; the app stays interactive behind it.
13
+ - **Entry point:** a `GuideBeacon` placed inline or absolutely over a "new" feature — the gentle, opt-in tour entry. Never auto-start.
14
+ - **Targets:** mark each referenced element once with `data-guide="<id>"`; tours, hints, markers, and mentions all resolve through that one namespace.
15
+
16
+ ## Component Selection
17
+
18
+ | UI Need | Component | Configuration |
19
+ |---|---|---|
20
+ | First-run walkthrough | `Guide` + a `GuideTour` | Opt-in, 3–5 steps; spotlight each step `target` |
21
+ | Gentle tour entry | `GuideBeacon` | `tour={...}`; hides itself once the tour is seen |
22
+ | Always-available help | `GuidePanel` + `GuideArticle` | Non-modal; controller-driven `openPanel(article?)` |
23
+ | "What does this do?" affordance | `GuideMarker` | `for="<id>"` → opens the panel at the article (UI → guide) |
24
+ | Point an article at the UI | `GuideMention` | `for="<id>"` inside an article; highlights on hover **and** focus (guide → UI) |
25
+ | One-off contextual nudge | `GuideHint` | `trigger="mount"`, or `"manual"` + `open`; `once` persists "seen" |
26
+ | Onboarding analytics | `onStep` / `onComplete` / `onSkip` | On the `GuideTour` — the funnel + drop-off signal |
27
+
28
+ ## Behavioral Rules
29
+
30
+ - **Helpful, not intrusive.** Default to the callable panel and the waiting hint. The scrim tour is the most aggressive mode and stays opt-in (beacon or explicit button) — never auto-started.
31
+ - **One controller, many surfaces.** Create the `GuideController`, pass it to `GuideProvider`, and drive everything (`startTour`, `openPanel`, `hasSeen`) from it.
32
+ - **Persist "seen."** Tours and `once` hints mark themselves seen on end, so a returning user is not nagged. `stopTour()` (route change / unmount) deliberately does NOT mark seen and is analytics-silent.
33
+ - **Track the funnel.** Wire `onStep` / `onComplete` / `onSkip` — `onStep.via` distinguishes `start` vs `next`/`prev`, and `onSkip.index` is the drop-off step. This is the real business value of onboarding.
34
+ - **Cross-route tours are app-driven.** The controller survives client navigation and the renderer re-anchors once the new route's `data-guide` target appears; the app navigates in `tour.onStep` (e.g. `goto(stepRoutes[index])`). Mount `Guide` in the layout — a route-local renderer unmounts mid-tour. Full recipe: `docs/GUIDE.md` §9.
35
+ - **Learning-by-doing steps:** `GuideStep.advance: 'action'` (paired with `interactive: true`) disables Next; the user performs the real action and the app advances via `controller.next()`.
36
+ - **Content lives in the app**, not the library: steps, article text, and `data-guide` selectors are app-owned (and i18n'd by the app).
37
+ - **Reduced motion** is honored automatically (panel slide, beacon pulse, step fade) — no extra work.
38
+
39
+ ## Anti-Patterns
40
+
41
+ - Do not auto-start a tour on page load. Onboarding that hijacks the screen before the user acts is exactly why product tours earned a bad reputation.
42
+ - Do not use a modal `Dialog` / `Drawer` as the help panel. The panel must be non-modal so a `GuideMention` can highlight a UI element while the panel is open (the bidirectional link breaks otherwise).
43
+ - Do not build a multi-step **form wizard** with `Guide`. That is a `Stepper` + form pattern; `Guide` overlays *existing* UI, it does not collect input.
44
+ - Do not invent `data-guide` ids with `Math.random()` — they are author-chosen, stable strings shared across surfaces.
45
+ - Do not duplicate help copy across a tour step and an article; point both at the same `data-guide` topic instead.
46
+
47
+ ## Related
48
+
49
+ - Recipe: `onboarding-flow` — complete production-ready Guide-system example
50
+ - Guide: `docs/GUIDE.md` — full architecture and the cross-route tour recipe (§9)
@@ -0,0 +1,46 @@
1
+ # Planning Board
2
+
3
+ Date-indexed board that lays domain items — meals, shifts, bookings, content slots — onto calendar days across a week, month or custom range.
4
+
5
+ ## Layout
6
+
7
+ - **Structure:** `Planner` is the whole board. It buckets `items` by day and renders each cell via your `cell` snippet — no manual date math, no per-day grid.
8
+ - **View:** `view="week"` for a column-per-day plan (the default), `view="month"` for a compact 6×7 overview, `view="range"` for an arbitrary span. Week stacks to one column per day on mobile automatically.
9
+ - **Cells:** put a small stack of cards or rows inside `cell`. Keep each item to one or two lines (icon + label); the cell is narrow.
10
+ - **Spacing:** week cells get `gap-1`–`gap-2` between items; month cells stay terse — show counts or 1–2 items, not the full list.
11
+ - **Server alignment:** load the week on the server with `@urbicon-ui/blocks/date` (`startOfWeek` / `toIso`) so the SSR range and the client grid agree — no UTC drift.
12
+
13
+ ## Component Selection
14
+
15
+ | UI Need | Component | Configuration |
16
+ |---|---|---|
17
+ | The board itself | `Planner` | `view`, `items`, `getDate`; `sort` for intra-day order |
18
+ | Per-day content | `cell` snippet | Receives typed `items: T[]`, `isoDate`, `isToday`, `selectDate()` |
19
+ | An item card | `Card` or a plain `div` | One per item, kept to a line or two |
20
+ | Item category / status | `Badge` | `intent` per category (`success`/`warning`/`primary`…) |
21
+ | Add-on-a-day affordance | `Button variant="ghost" size="sm"` | Inside `cell` — rendered for empty days too |
22
+ | Empty-day placeholder | `empty` snippet | Optional; omit it to let `cell` handle empty days |
23
+ | Custom toolbar | `header` snippet | Replaces prev/next/today/title |
24
+ | Timed appointments instead | `Calendar` | Use Calendar, not Planner, when items have a clock time |
25
+
26
+ ## Behavioral Rules
27
+
28
+ - `getDate` returns a `Date` or a local ISO date string (`'2026-06-16'`); strings are taken verbatim, so a day never shifts across timezones. Pass a `Date` for UTC instants.
29
+ - The `cell` snippet runs for **every** day, empty ones included — keep the "add" button there so it is reachable on blank days.
30
+ - Drive data loading from `onNavigate(date, range)`: fetch `range.start … range.end`, not the whole month.
31
+ - `bind:value` is the reference date; `bind:selectedDate` is the active day. Clicking a cell's body selects its day; clicks on interactive cell content keep their own behaviour.
32
+ - Sort within a day via `sort` (e.g. breakfast → lunch → dinner), not by reordering `items`.
33
+
34
+ ## Anti-Patterns
35
+
36
+ - Do not reach for `Calendar` for uhrzeit-lose day content — its model is timed `CalendarEvent`s with bars and recurrence. Planner is single-date bucketing of your own type.
37
+ - Do not rebuild the week/month grid by hand with `getWeekDates` + a `{#each}`. That is exactly what Planner removes.
38
+ - Do not stuff a full item list into a month cell. Summarise (count or top item) and switch to `view="week"` for detail.
39
+ - Do not parse a plain date string through `new Date()` before handing it to `getDate` — you reintroduce the UTC off-by-one Planner avoids.
40
+ - Do not gate the add affordance behind "has items". Empty days are where you add most.
41
+
42
+ ## Related
43
+
44
+ - Component: `Planner` — the board; see also `Calendar` for timed events
45
+ - Recipe: `meal-planner` — complete production-ready weekly plan
46
+ - Pattern: `dashboard` — when the board is one panel among analytics
@@ -0,0 +1,48 @@
1
+ # Settings Page
2
+
3
+ Multi-section user preferences with sidebar navigation and grouped content areas.
4
+
5
+ ## Layout
6
+
7
+ - **Structure:** `SidebarLayout` with sidebar navigation + scrollable content area
8
+ - **Sidebar:** 240-280px width, grouped navigation links via `Sidebar` with `Accordion` for groups
9
+ - **Content:** max-width 720px, vertically stacked sections
10
+ - **Responsive:** below 768px, sidebar collapses; use a `Select` or horizontal scrollable navigation to switch sections
11
+ - **Spacing:** `gap-8` between sections, `gap-4` within sections
12
+
13
+ ## Component Selection
14
+
15
+ | UI Need | Component | Configuration |
16
+ |---|---|---|
17
+ | Section navigation | `Sidebar` + `Accordion` | Grouped links, highlight active section |
18
+ | Section container | `Card` | `variant="outlined"` |
19
+ | Section heading | Native `h2` | `text-text-primary font-semibold text-lg` |
20
+ | Subsection heading | Native `h3` | `text-text-secondary font-medium text-base` |
21
+ | Boolean setting | `Toggle` | With label, not `Checkbox` |
22
+ | Enum setting (3-6) | `Select` | Labeled via `FormField` |
23
+ | Enum setting (7+) | `Combobox` | Searchable, labeled via `FormField` |
24
+ | Free text | `Input` or `Textarea` | Labeled via `FormField` |
25
+ | Save/cancel | `Button` pair | Sticky bottom bar when form exceeds viewport |
26
+ | Destructive action | `Button intent="danger"` | Separated at bottom, requires `ConfirmDialog` |
27
+ | Status feedback | `Toast` | On save success/failure |
28
+
29
+ ## Behavioral Rules
30
+
31
+ - Group related settings in Cards. One Card per conceptual group (Account, Notifications, Privacy).
32
+ - Save button shows loading state (spinner) during save.
33
+ - Warn on unsaved changes: intercept navigation, show `ConfirmDialog`.
34
+ - Reset/Cancel returns to last saved state, not initial page load state.
35
+ - Destructive settings (delete account, revoke access) separated at the bottom of the page, visually distinct from other settings.
36
+ - Default values: show the active value, not "unchanged". Users should see what is currently configured.
37
+
38
+ ## Anti-Patterns
39
+
40
+ - Do not use `Tab` for settings groups. Tabs imply peer sections at the same hierarchy; settings are hierarchical.
41
+ - Do not put all settings in a single scrollable list without navigation.
42
+ - Do not use modals for inline editing. Edit in place, save with the section's save action.
43
+ - Do not auto-save without explicit user signal. Settings changes should be intentional.
44
+
45
+ ## Related
46
+
47
+ - Recipe: `settings` — complete production-ready code example
48
+ - Pattern: `form-page` — for standalone forms within settings sections
@@ -0,0 +1,136 @@
1
+ # Tab Navigation
2
+
3
+ URL-based tab navigation for SvelteKit routes — each tab maps to a route segment.
4
+
5
+ ## When to Use
6
+
7
+ Use this pattern when:
8
+ - Peer sections of a detail view need their own URL (bookmarkable, shareable)
9
+ - Each section has distinct content that justifies a separate route
10
+ - The user navigates between sections without losing page context (e.g., project detail with Overview, Settings, Logs)
11
+
12
+ Do NOT use when:
13
+ - Sections share state that would be lost on navigation — use client-side `Tab` with `bind:value` instead
14
+ - There are only 2 sections — consider a simple toggle or inline layout
15
+ - Sections are hierarchical — use `Sidebar` navigation instead (see `settings-page` pattern)
16
+
17
+ ## Layout
18
+
19
+ - **Structure:** shared layout (`+layout.svelte`) with `Tab` or `SegmentGroup` + nested `+page.svelte` per section
20
+ - **Placement:** tabs directly below the page header / breadcrumb, above the content area
21
+ - **Content:** each `+page.svelte` renders its own section content below the shared tab bar
22
+ - **Responsive:** on mobile, consider horizontal scroll for the tab bar, or collapse to a `Select` dropdown for 5+ tabs
23
+
24
+ ## SvelteKit Route Structure
25
+
26
+ ```
27
+ routes/
28
+ project/[id]/
29
+ +layout.svelte ← shared tab bar
30
+ +page.svelte ← "Overview" (default tab)
31
+ settings/
32
+ +page.svelte ← "Settings" tab
33
+ logs/
34
+ +page.svelte ← "Logs" tab
35
+ hooks/
36
+ +page.svelte ← "Hooks" tab
37
+ ```
38
+
39
+ ## Implementation
40
+
41
+ ### Shared Layout with Tab Navigation
42
+
43
+ ```svelte
44
+ <script lang="ts">
45
+ import { page } from '$app/state';
46
+ import { Tab } from '@urbicon-ui/blocks';
47
+
48
+ const { children } = $props();
49
+
50
+ const tabs = [
51
+ { label: 'Overview', href: `/project/${page.params.id}` },
52
+ { label: 'Settings', href: `/project/${page.params.id}/settings` },
53
+ { label: 'Logs', href: `/project/${page.params.id}/logs` },
54
+ { label: 'Hooks', href: `/project/${page.params.id}/hooks` },
55
+ ];
56
+
57
+ const activeTab = $derived(
58
+ tabs.findIndex((t) => page.url.pathname === t.href) ?? 0
59
+ );
60
+ </script>
61
+
62
+ <div class="flex flex-col gap-6">
63
+ <Tab.Root value={tabs[activeTab]?.label}>
64
+ {#each tabs as tab}
65
+ <Tab.Trigger value={tab.label}>
66
+ <a href={tab.href}>{tab.label}</a>
67
+ </Tab.Trigger>
68
+ {/each}
69
+ </Tab.Root>
70
+
71
+ {@render children()}
72
+ </div>
73
+ ```
74
+
75
+ ### Alternative: SegmentGroup (Compact)
76
+
77
+ For fewer tabs (2-4) where a more compact visual is preferred:
78
+
79
+ ```svelte
80
+ <script lang="ts">
81
+ import { page } from '$app/state';
82
+ import { goto } from '$app/navigation';
83
+ import { SegmentGroup } from '@urbicon-ui/blocks';
84
+
85
+ const segments = [
86
+ { value: 'overview', label: 'Overview', href: `/project/${page.params.id}` },
87
+ { value: 'settings', label: 'Settings', href: `/project/${page.params.id}/settings` },
88
+ ];
89
+
90
+ const current = $derived(
91
+ segments.find((s) => page.url.pathname === s.href)?.value ?? 'overview'
92
+ );
93
+ </script>
94
+
95
+ <SegmentGroup
96
+ value={current}
97
+ onValueChange={(v) => {
98
+ const seg = segments.find((s) => s.value === v);
99
+ if (seg) goto(seg.href);
100
+ }}
101
+ >
102
+ {#each segments as seg}
103
+ <SegmentGroup.Item value={seg.value}>{seg.label}</SegmentGroup.Item>
104
+ {/each}
105
+ </SegmentGroup>
106
+ ```
107
+
108
+ ## Component Selection
109
+
110
+ | UI Need | Component | When |
111
+ |---|---|---|
112
+ | 3+ peer sections | `Tab` | Standard horizontal tabs |
113
+ | 2-4 compact options | `SegmentGroup` | Tighter visual, pill-style |
114
+ | 5+ sections on mobile | `Select` | Dropdown fallback for narrow screens |
115
+ | Hierarchical subsections | `Sidebar` | Use `settings-page` pattern instead |
116
+
117
+ ## Behavioral Rules
118
+
119
+ - The default route (`+page.svelte` at the layout level) is the first/primary tab.
120
+ - Active tab is derived from `page.url.pathname`, not from component state — the URL is the source of truth.
121
+ - Use `<a href>` for navigation, not `goto()`, to preserve browser history and link behavior.
122
+ - Breadcrumbs above the tab bar should show the entity context (e.g., "Projects / My Project"), not the tab name.
123
+ - Each tab page should be independently loadable via URL (deep linking).
124
+
125
+ ## Anti-Patterns
126
+
127
+ - Do not store active tab in `$state` — derive it from the URL. Client-side state and URL will drift.
128
+ - Do not use `Tab` with `bind:value` for route-based navigation — use `<a href>` inside tab triggers.
129
+ - Do not duplicate the tab bar in every `+page.svelte` — put it in the shared `+layout.svelte`.
130
+ - Do not use this pattern for settings with save/cancel — use the `settings-page` pattern with `Sidebar` instead.
131
+
132
+ ## Related
133
+
134
+ - Pattern: `settings-page` — for hierarchical settings navigation
135
+ - Component: `Tab` — the underlying tab component API
136
+ - Component: `SegmentGroup` — compact alternative for few sections