@tailor-platform/app-shell 1.15.0 → 1.17.0

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 (109) hide show
  1. package/dist/app-shell-core.css +1 -1
  2. package/dist/app-shell.d.ts +811 -131
  3. package/dist/app-shell.js +7155 -5797
  4. package/dist/{appshell-DLVBFo5J.js → appshell-CahhZy7v.js} +656 -524
  5. package/dist/semantic-contrast.test.ts +154 -0
  6. package/dist/style-entry.d.ts +147 -92
  7. package/dist/testing.d.ts +152 -95
  8. package/dist/testing.js +1 -1
  9. package/dist/theme-bridge.test.ts +101 -1
  10. package/dist/theme.bridge.css +91 -0
  11. package/dist/theme.css +6 -1
  12. package/dist/themes/_template.css +7 -1
  13. package/dist/themes/bloom.css +0 -6
  14. package/dist/themes/cream.css +0 -6
  15. package/dist/themes/default.css +389 -69
  16. package/dist/vite-plugin.d.ts +147 -92
  17. package/package.json +8 -8
  18. package/skills/app-shell-patterns/SKILL.md +108 -19
  19. package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +115 -0
  20. package/skills/app-shell-patterns/references/api/create-typed-paths.md +117 -0
  21. package/skills/app-shell-patterns/references/api/define-i18n-labels.md +143 -0
  22. package/skills/app-shell-patterns/references/api/define-module.md +247 -0
  23. package/skills/app-shell-patterns/references/api/define-resource.md +307 -0
  24. package/skills/app-shell-patterns/references/api/guards/hidden.md +202 -0
  25. package/skills/app-shell-patterns/references/api/guards/overview.md +354 -0
  26. package/skills/app-shell-patterns/references/api/guards/pass.md +129 -0
  27. package/skills/app-shell-patterns/references/api/guards/redirect-to.md +307 -0
  28. package/skills/app-shell-patterns/references/api/router/use-location.md +240 -0
  29. package/skills/app-shell-patterns/references/api/router/use-navigate.md +138 -0
  30. package/skills/app-shell-patterns/references/api/router/use-params.md +218 -0
  31. package/skills/app-shell-patterns/references/api/use-ai-chat.md +110 -0
  32. package/skills/app-shell-patterns/references/api/use-app-shell-config.md +132 -0
  33. package/skills/app-shell-patterns/references/api/use-app-shell-data.md +150 -0
  34. package/skills/app-shell-patterns/references/api/use-app-shell.md +150 -0
  35. package/skills/app-shell-patterns/references/api/use-auth.md +145 -0
  36. package/skills/app-shell-patterns/references/api/use-override-breadcrumb.md +74 -0
  37. package/skills/app-shell-patterns/references/api/use-page-meta.md +96 -0
  38. package/skills/app-shell-patterns/references/api/use-register-command-palette-actions.md +90 -0
  39. package/skills/app-shell-patterns/references/api/use-resolved-locale.md +67 -0
  40. package/skills/app-shell-patterns/references/api/use-route-error.md +214 -0
  41. package/skills/app-shell-patterns/references/api/use-theme.md +108 -0
  42. package/skills/app-shell-patterns/references/api/use-time-zone.md +80 -0
  43. package/skills/app-shell-patterns/references/api/use-toast.md +104 -0
  44. package/skills/app-shell-patterns/references/components/action-panel.md +168 -0
  45. package/skills/app-shell-patterns/references/components/activity-card.md +142 -0
  46. package/skills/app-shell-patterns/references/components/ai-chat.md +315 -0
  47. package/skills/app-shell-patterns/references/components/alert.md +202 -0
  48. package/skills/app-shell-patterns/references/components/app-shell.md +530 -0
  49. package/skills/app-shell-patterns/references/components/appearance-switcher.md +87 -0
  50. package/skills/app-shell-patterns/references/components/attachment.md +138 -0
  51. package/skills/app-shell-patterns/references/components/autocomplete.md +278 -0
  52. package/skills/app-shell-patterns/references/components/avatar.md +80 -0
  53. package/skills/app-shell-patterns/references/components/badge.md +309 -0
  54. package/skills/app-shell-patterns/references/components/button.md +164 -0
  55. package/skills/app-shell-patterns/references/components/card.md +181 -0
  56. package/skills/app-shell-patterns/references/components/checkbox.md +169 -0
  57. package/skills/app-shell-patterns/references/components/combobox.md +318 -0
  58. package/skills/app-shell-patterns/references/components/command-palette.md +413 -0
  59. package/skills/app-shell-patterns/references/components/csv-importer.md +214 -0
  60. package/skills/app-shell-patterns/references/components/data-table.md +1168 -0
  61. package/skills/app-shell-patterns/references/components/date-picker.md +259 -0
  62. package/skills/app-shell-patterns/references/components/default-header.md +75 -0
  63. package/skills/app-shell-patterns/references/components/default-sidebar.md +136 -0
  64. package/skills/app-shell-patterns/references/components/description-card.md +569 -0
  65. package/skills/app-shell-patterns/references/components/dialog.md +164 -0
  66. package/skills/app-shell-patterns/references/components/document-progress-card.md +154 -0
  67. package/skills/app-shell-patterns/references/components/filter-rail.md +165 -0
  68. package/skills/app-shell-patterns/references/components/form.md +378 -0
  69. package/skills/app-shell-patterns/references/components/global-header-layout.md +132 -0
  70. package/skills/app-shell-patterns/references/components/grid.md +184 -0
  71. package/skills/app-shell-patterns/references/components/input.md +83 -0
  72. package/skills/app-shell-patterns/references/components/layout.md +539 -0
  73. package/skills/app-shell-patterns/references/components/menu.md +218 -0
  74. package/skills/app-shell-patterns/references/components/metric-card.md +94 -0
  75. package/skills/app-shell-patterns/references/components/select.md +283 -0
  76. package/skills/app-shell-patterns/references/components/sheet.md +237 -0
  77. package/skills/app-shell-patterns/references/components/sidebar-group.md +472 -0
  78. package/skills/app-shell-patterns/references/components/sidebar-item.md +458 -0
  79. package/skills/app-shell-patterns/references/components/sidebar-layout.md +258 -0
  80. package/skills/app-shell-patterns/references/components/sidebar-section.md +114 -0
  81. package/skills/app-shell-patterns/references/components/spinner.md +81 -0
  82. package/skills/app-shell-patterns/references/components/table.md +188 -0
  83. package/skills/app-shell-patterns/references/components/tabs.md +158 -0
  84. package/skills/app-shell-patterns/references/components/textarea.md +122 -0
  85. package/skills/app-shell-patterns/references/components/timeline.md +317 -0
  86. package/skills/app-shell-patterns/references/components/toolbar.md +138 -0
  87. package/skills/app-shell-patterns/references/components/tooltip.md +144 -0
  88. package/skills/app-shell-patterns/references/components/with-guard.md +445 -0
  89. package/skills/app-shell-patterns/references/concepts/authentication.md +301 -0
  90. package/skills/app-shell-patterns/references/concepts/custom-components.md +59 -0
  91. package/skills/app-shell-patterns/references/concepts/file-based-routing.md +356 -0
  92. package/skills/app-shell-patterns/references/{fundamental → concepts}/graphql.md +31 -18
  93. package/skills/app-shell-patterns/references/concepts/modules-and-resources.md +229 -0
  94. package/skills/app-shell-patterns/references/concepts/routing-navigation.md +425 -0
  95. package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +420 -0
  96. package/skills/app-shell-patterns/references/concepts/styling-theming.md +785 -0
  97. package/skills/app-shell-patterns/references/migrations.md +55 -0
  98. package/skills/app-shell-patterns/references/pages/{detail.md → document-detail.md} +10 -33
  99. package/skills/app-shell-patterns/references/patterns/form-composer.md +43 -45
  100. package/skills/app-shell-patterns/references/patterns/form-modal.md +37 -92
  101. package/skills/app-shell-patterns/references/patterns/form-sectioned.md +12 -38
  102. package/skills/app-shell-patterns/references/patterns/form-single-page.md +11 -32
  103. package/skills/app-shell-patterns/references/patterns/form-wizard.md +12 -53
  104. package/skills/app-shell-patterns/references/patterns/interaction-confirm.md +11 -27
  105. package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +136 -139
  106. package/skills/app-shell-patterns/references/patterns/interaction-toast.md +10 -34
  107. package/skills/app-shell-patterns/references/patterns/list-dense-scan.md +13 -88
  108. package/skills/app-shell-patterns/references/fundamental/components.md +0 -1009
  109. package/skills/app-shell-patterns/references/fundamental/design-system.md +0 -440
@@ -0,0 +1,530 @@
1
+ ---
2
+ title: AppShell
3
+ description: The root component that provides routing, navigation, and theming for your application
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/app-shell.docs.outline.md — do not edit by hand. -->
7
+
8
+ # AppShell
9
+
10
+ `AppShell` is the root component that wires together routing, navigation, authentication, and theming for your AppShell application. It should wrap your entire application layout.
11
+
12
+ ## Import
13
+
14
+ ```tsx
15
+ import { AppShell } from "@tailor-platform/app-shell";
16
+ ```
17
+
18
+ ## Basic Usage
19
+
20
+ ```tsx
21
+ import { AppShell, SidebarLayout, defineModule } from "@tailor-platform/app-shell";
22
+
23
+ const modules = [
24
+ defineModule({
25
+ path: "dashboard",
26
+ component: DashboardPage,
27
+ meta: { title: "Dashboard" },
28
+ }),
29
+ ];
30
+
31
+ function App() {
32
+ return (
33
+ <AppShell title="My ERP App" basePath="/app" modules={modules}>
34
+ <SidebarLayout />
35
+ </AppShell>
36
+ );
37
+ }
38
+ ```
39
+
40
+ ## Props
41
+
42
+ ### title
43
+
44
+ - **Type:** `string` (optional)
45
+ - **Description:** Application title displayed in the sidebar header. Also used as the browser tab title suffix — AppShell keeps `document.title` in sync with the active route as `"<page> · <title>"`, where `<page>` is the current breadcrumb leaf (including any [`useOverrideBreadcrumb`](../api/use-override-breadcrumb.md) override). When omitted, the tab shows just the page name.
46
+
47
+ ```tsx
48
+ <AppShell title="My ERP App" modules={modules}>
49
+ {/* ... */}
50
+ </AppShell>
51
+ ```
52
+
53
+ ### icon
54
+
55
+ - **Type:** `React.ReactNode` (optional)
56
+ - **Description:** Application icon displayed in the sidebar header
57
+
58
+ ```tsx
59
+ import { Building } from "lucide-react";
60
+
61
+ <AppShell title="My App" icon={<Building />} modules={modules}>
62
+ {/* ... */}
63
+ </AppShell>;
64
+ ```
65
+
66
+ ### favicon
67
+
68
+ - **Type:** `string` (optional)
69
+ - **Default:** Bundled default favicon set
70
+ - **Description:** Browser-tab favicon href. Accepts any value valid for `<link rel="icon">` — a public-path URL (e.g. `/favicon.ico`) or a data URI. When provided, AppShell renders a single `<link rel="icon">` with this href, replacing the default favicon set.
71
+
72
+ When `favicon` is omitted and the host page declares no `<link rel="icon">`, AppShell automatically injects a small default favicon set as embedded data URIs (no asset-copy step required):
73
+
74
+ - 16×16 PNG tab icon
75
+ - 32×32 PNG tab icon
76
+ - 180×180 Apple touch icon (covers "Add to Home Screen" on iOS and Android)
77
+
78
+ If the host page already declares a `<link rel="icon">`, AppShell leaves it untouched.
79
+
80
+ ```tsx
81
+ <AppShell favicon="/favicon.ico" modules={modules}>
82
+ {/* ... */}
83
+ </AppShell>
84
+ ```
85
+
86
+ ### basePath
87
+
88
+ - **Type:** `string` (optional)
89
+ - **Default:** `""`
90
+ - **Description:** Base path prefix for all routes
91
+
92
+ ```tsx
93
+ // Routes will be /app/dashboard, /app/products, etc.
94
+ <AppShell basePath="/app" modules={modules}>
95
+ {/* ... */}
96
+ </AppShell>
97
+
98
+ // Routes will be /dashboard, /products, etc.
99
+ <AppShell basePath="" modules={modules}>
100
+ {/* ... */}
101
+ </AppShell>
102
+ ```
103
+
104
+ ### modules
105
+
106
+ - **Type:** `Module[]` (required when not using file-based routing)
107
+ - **Description:** Array of module definitions that define your application structure
108
+
109
+ ```tsx
110
+ import { defineModule, defineResource } from "@tailor-platform/app-shell";
111
+
112
+ const modules = [
113
+ defineModule({
114
+ path: "products",
115
+ component: ProductsListPage,
116
+ meta: { title: "Products" },
117
+ resources: [
118
+ defineResource({
119
+ path: ":id",
120
+ component: ProductDetailPage,
121
+ meta: { title: "Product Details" },
122
+ }),
123
+ ],
124
+ }),
125
+ ];
126
+
127
+ <AppShell modules={modules}>{/* ... */}</AppShell>;
128
+ ```
129
+
130
+ [Learn more about Modules and Resources →](../concepts/modules-and-resources.md)
131
+
132
+ ### rootComponent
133
+
134
+ - **Type:** `() => React.ReactNode` (optional)
135
+ - **Description:** Component to render at the root path (e.g., `/app/`)
136
+
137
+ ```tsx
138
+ <AppShell basePath="/app" modules={modules} rootComponent={() => <HomePage />}>
139
+ {/* ... */}
140
+ </AppShell>
141
+ ```
142
+
143
+ When `rootComponent` is set, the root page is treated as a first-class navigation item: it appears in `DefaultSidebar` and `CommandPalette` just like any other module. The title defaults to the localized `"Home"` / `"ホーム"` if no explicit title is provided.
144
+
145
+ > **Tip:** For redirects from the root, use a guard with `redirectTo()` instead
146
+
147
+ ```tsx
148
+ import { redirectTo } from "@tailor-platform/app-shell";
149
+
150
+ <AppShell basePath="/app" modules={modules} rootComponent={() => redirectTo("/app/dashboard")}>
151
+ {/* ... */}
152
+ </AppShell>;
153
+ ```
154
+
155
+ > **Note:** If a module with `path: ""` is present in `modules`, it takes precedence over `rootComponent`.
156
+
157
+ ### settingsResources
158
+
159
+ - **Type:** `Resource[]` (optional)
160
+ - **Description:** Resources to include in the settings menu dropdown
161
+
162
+ ```tsx
163
+ import { defineResource } from "@tailor-platform/app-shell";
164
+
165
+ const settingsResources = [
166
+ defineResource({
167
+ path: "profile",
168
+ component: ProfileSettingsPage,
169
+ meta: { title: "Profile" },
170
+ }),
171
+ defineResource({
172
+ path: "billing",
173
+ component: BillingSettingsPage,
174
+ meta: { title: "Billing" },
175
+ }),
176
+ ];
177
+
178
+ <AppShell modules={modules} settingsResources={settingsResources}>
179
+ {/* ... */}
180
+ </AppShell>;
181
+ ```
182
+
183
+ Settings appear in a dropdown menu in the sidebar header, accessible via the settings icon.
184
+
185
+ ### defaultColorTheme
186
+
187
+ - **Type:** `"light" | "dark" | "system"` (optional)
188
+ - **Default:** `"system"`
189
+ - **Description:** Initial color mode applied before any value is loaded from `localStorage`. Does not override a stored user preference. `"system"` follows the OS light/dark setting.
190
+
191
+ ```tsx
192
+ <AppShell defaultColorTheme="light" modules={modules}>
193
+ {/* ... */}
194
+ </AppShell>
195
+ ```
196
+
197
+ The end user's selection (via [`AppearanceSwitcher`](./appearance-switcher.md) or a custom toggle using [`useTheme`](../api/use-theme.md)) is persisted automatically and takes precedence over this prop on subsequent visits.
198
+
199
+ ### locale
200
+
201
+ - **Type:** `string` (optional)
202
+ - **Default:** Auto-detected from browser, falls back to `"en"`
203
+ - **Description:** Locale code for built-in UI strings
204
+
205
+ ```tsx
206
+ <AppShell locale="ja" modules={modules}>
207
+ {/* ... */}
208
+ </AppShell>
209
+ ```
210
+
211
+ Supported locales: `en`, `ja`
212
+
213
+ [Learn more about Internationalization →](../api/define-i18n-labels.md)
214
+
215
+ ### timeZone
216
+
217
+ - **Type:** `string` (optional)
218
+ - **Default:** User's local timezone
219
+ - **Description:** IANA timezone (e.g. `"America/Los_Angeles"`) used by date/time components as the default for resolving "today" and for `ZonedDateTime` values. When omitted, date/time components fall back to the user's local timezone.
220
+
221
+ ```tsx
222
+ <AppShell timeZone="America/Los_Angeles" modules={modules}>
223
+ {/* ... */}
224
+ </AppShell>
225
+ ```
226
+
227
+ Access the configured timezone in components using [`useTimeZone`](../api/use-time-zone.md).
228
+
229
+ ### errorBoundary
230
+
231
+ - **Type:** `ErrorBoundaryComponent` (optional)
232
+ - **Description:** Global error boundary component applied to all routes
233
+
234
+ ```tsx
235
+ import { useRouteError } from "@tailor-platform/app-shell";
236
+
237
+ const GlobalErrorBoundary = () => {
238
+ const error = useRouteError() as Error;
239
+ return (
240
+ <div className="p-8">
241
+ <h1 className="text-xl font-bold mb-4">Something went wrong</h1>
242
+ <p className="text-red-600">{error.message}</p>
243
+ </div>
244
+ );
245
+ };
246
+
247
+ <AppShell modules={modules} errorBoundary={GlobalErrorBoundary}>
248
+ {/* ... */}
249
+ </AppShell>;
250
+ ```
251
+
252
+ > **Note:** Module and resource-level error boundaries take precedence over the global error boundary.
253
+
254
+ ### contextData
255
+
256
+ - **Type:** `ContextData` (optional)
257
+ - **Description:** Custom context data accessible from guards and components via `useAppShell()`
258
+
259
+ First, define your context data type using module augmentation:
260
+
261
+ ```typescript
262
+ // types.d.ts — `User` and `ApiClient` are your application's own types
263
+ declare module "@tailor-platform/app-shell" {
264
+ interface AppShellRegister {
265
+ contextData: {
266
+ apiClient: ApiClient;
267
+ currentUser: User | null;
268
+ tenantId: string;
269
+ };
270
+ }
271
+ }
272
+ ```
273
+
274
+ Then pass the data to AppShell:
275
+
276
+ ```tsx
277
+ // App.tsx
278
+ <AppShell
279
+ modules={modules}
280
+ contextData={{
281
+ apiClient,
282
+ currentUser,
283
+ tenantId: "tenant-123",
284
+ }}
285
+ >
286
+ {/* ... */}
287
+ </AppShell>
288
+ ```
289
+
290
+ Access the context data in your components:
291
+
292
+ ```tsx
293
+ import { useAppShell } from "@tailor-platform/app-shell";
294
+
295
+ function MyComponent() {
296
+ const { contextData } = useAppShell();
297
+
298
+ // Fully typed!
299
+ const user = contextData.currentUser;
300
+ const client = contextData.apiClient;
301
+
302
+ return <div>Welcome, {user?.name}</div>;
303
+ }
304
+ ```
305
+
306
+ Or in guards:
307
+
308
+ ```tsx
309
+ import { pass, hidden } from "@tailor-platform/app-shell";
310
+
311
+ const requireAuth: Guard = ({ context }) => {
312
+ if (!context.currentUser) {
313
+ return redirectTo("/login");
314
+ }
315
+ return pass();
316
+ };
317
+ ```
318
+
319
+ ### searchSources
320
+
321
+ - **Type:** `readonly SearchSource[]` (optional)
322
+ - **Description:** Async search sources wired into the built-in CommandPalette. Each source is activated by typing its `prefix` followed by `:` in the palette. When active, the Actions and Pages sections are hidden and only results from that source are shown. The empty-input state of the palette lists all registered sources in a **Search Modes** section so users can discover them with a single click.
323
+
324
+ ```tsx
325
+ import { AppShell, type SearchSource } from "@tailor-platform/app-shell";
326
+
327
+ const searchSources: readonly SearchSource[] = [
328
+ {
329
+ prefix: "ORD",
330
+ title: "Orders",
331
+ search: async (query, { signal }) => {
332
+ const results = await api.searchOrders(query, { signal });
333
+ return results.map((o) => ({
334
+ key: o.id,
335
+ label: o.number,
336
+ path: `/orders/${o.id}`,
337
+ }));
338
+ },
339
+ },
340
+ ];
341
+
342
+ <AppShell modules={modules} searchSources={searchSources}>
343
+ <SidebarLayout sidebar={<DefaultSidebar />} />
344
+ </AppShell>;
345
+ ```
346
+
347
+ See [`SearchSource`](./command-palette.md#searchsource) for the full type reference.
348
+
349
+ > **Note:** `DefaultSidebar` always renders a **Search** entry that opens the palette regardless of whether `searchSources` is configured. The `Cmd+K` / `Ctrl+K` shortcut also works globally.
350
+
351
+ ### appInfo
352
+
353
+ - **Type:** `AppInfo` (optional)
354
+ - **Description:** Configuration for the built-in `/__appinfo` page, which exposes app metadata and the current AppShell version. The page is excluded from sidebar navigation but appears in the Command Palette as a page entry and includes a copy button for the rendered information.
355
+
356
+ `AppInfo` has the following shape:
357
+
358
+ | Property | Type | Description |
359
+ | ---------- | ------------------------- | ---------------------------------------------- |
360
+ | `metadata` | `readonly AppInfoEntry[]` | Additional rows shown on the `/__appinfo` page |
361
+
362
+ Each `AppInfoEntry` has:
363
+
364
+ | Property | Type | Description |
365
+ | -------- | -------------------------------------------------- | ------------------------------- |
366
+ | `label` | `string` | Display label shown on the page |
367
+ | `value` | `string \| number \| boolean \| null \| undefined` | Value rendered as text |
368
+
369
+ ```tsx
370
+ <AppShell
371
+ title="My App"
372
+ appInfo={{
373
+ metadata: [
374
+ { label: "Environment", value: "staging" },
375
+ { label: "Release", value: "2026.07.16" },
376
+ ],
377
+ }}
378
+ modules={modules}
379
+ >
380
+ {/* ... */}
381
+ </AppShell>
382
+ ```
383
+
384
+ ### children
385
+
386
+ - **Type:** `React.ReactNode` (required)
387
+ - **Description:** Layout component that renders your application content
388
+
389
+ Typically, you'll use `SidebarLayout`:
390
+
391
+ ```tsx
392
+ import { SidebarLayout } from "@tailor-platform/app-shell";
393
+
394
+ <AppShell modules={modules}>
395
+ <SidebarLayout />
396
+ </AppShell>;
397
+ ```
398
+
399
+ Or create a custom layout:
400
+
401
+ ```tsx
402
+ <AppShell modules={modules}>
403
+ <CustomLayout />
404
+ </AppShell>
405
+ ```
406
+
407
+ ## File-Based Routing Mode
408
+
409
+ When using the Vite plugin for file-based routing, use `AppShell` exactly as you would without the plugin — no `modules` prop required. The plugin intercepts the `@tailor-platform/app-shell` import and wraps `AppShell` with pages pre-configured via `AppShell.WithPages()` internally.
410
+
411
+ ```tsx
412
+ // App.tsx
413
+ import { AppShell, SidebarLayout, DefaultSidebar } from "@tailor-platform/app-shell";
414
+
415
+ // No modules prop needed — the plugin injects pages automatically
416
+ <AppShell title="My App">
417
+ <SidebarLayout sidebar={<DefaultSidebar />} />
418
+ </AppShell>;
419
+ ```
420
+
421
+ > **Note:** `AppShell.WithPages` is an internal method used by the Vite plugin. Do not call it directly in application code.
422
+
423
+ [Learn more about File-Based Routing →](../concepts/file-based-routing.md)
424
+
425
+ ## Complete Example
426
+
427
+ Here's a complete example with all common features:
428
+
429
+ ```tsx
430
+ import {
431
+ AppShell,
432
+ SidebarLayout,
433
+ defineModule,
434
+ defineResource,
435
+ useRouteError,
436
+ } from "@tailor-platform/app-shell";
437
+ import { Building } from "lucide-react";
438
+
439
+ // Define context data type
440
+ declare module "@tailor-platform/app-shell" {
441
+ interface AppShellRegister {
442
+ contextData: {
443
+ currentUser: User | null;
444
+ };
445
+ }
446
+ }
447
+
448
+ // Error boundary
449
+ const ErrorBoundary = () => {
450
+ const error = useRouteError() as Error;
451
+ return (
452
+ <div className="p-8">
453
+ <h1 className="text-xl font-bold">Error</h1>
454
+ <p>{error.message}</p>
455
+ </div>
456
+ );
457
+ };
458
+
459
+ // Modules
460
+ const modules = [
461
+ defineModule({
462
+ path: "dashboard",
463
+ component: DashboardPage,
464
+ meta: { title: "Dashboard" },
465
+ }),
466
+ defineModule({
467
+ path: "products",
468
+ component: ProductsPage,
469
+ meta: { title: "Products" },
470
+ resources: [
471
+ defineResource({
472
+ path: ":id",
473
+ component: ProductDetailPage,
474
+ }),
475
+ ],
476
+ }),
477
+ ];
478
+
479
+ // Settings
480
+ const settingsResources = [
481
+ defineResource({
482
+ path: "profile",
483
+ component: ProfilePage,
484
+ meta: { title: "Profile" },
485
+ }),
486
+ ];
487
+
488
+ // App
489
+ function App() {
490
+ const currentUser = useCurrentUser();
491
+
492
+ return (
493
+ <AppShell
494
+ title="My ERP App"
495
+ icon={<Building />}
496
+ favicon="/favicon.ico"
497
+ basePath="/app"
498
+ modules={modules}
499
+ settingsResources={settingsResources}
500
+ locale="en"
501
+ defaultColorTheme="system"
502
+ errorBoundary={ErrorBoundary}
503
+ contextData={{ currentUser }}
504
+ >
505
+ <SidebarLayout />
506
+ </AppShell>
507
+ );
508
+ }
509
+
510
+ export default App;
511
+ ```
512
+
513
+ ## Related Components
514
+
515
+ - [SidebarLayout](./sidebar-layout.md) - Default layout with sidebar navigation
516
+ - [CommandPalette](./command-palette.md) - Keyboard-driven navigation
517
+
518
+ ## Related Concepts
519
+
520
+ - [Modules and Resources](../concepts/modules-and-resources.md) - Application structure
521
+ - [Authentication](../concepts/authentication.md) - User authentication setup
522
+ - [Routing and Navigation](../concepts/routing-navigation.md) - Navigation between pages
523
+
524
+ ## API Reference
525
+
526
+ - [defineModule](../api/define-module.md) - Define a top-level module
527
+ - [defineResource](../api/define-resource.md) - Define a nested resource
528
+ - [useAppShell](../api/use-app-shell.md) - Access AppShell context
529
+ - [useResolvedLocale](../api/use-resolved-locale.md) - Access the full BCP-47 locale and language code
530
+ - [useTimeZone](../api/use-time-zone.md) - Access the configured IANA timezone
@@ -0,0 +1,87 @@
1
+ ---
2
+ title: AppearanceSwitcher
3
+ description: Pre-built dropdown for toggling the application color theme
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/appearance-switcher.docs.outline.md — do not edit by hand. -->
7
+
8
+ # AppearanceSwitcher
9
+
10
+ `AppearanceSwitcher` is a ready-made button and dropdown menu that lets end users switch between **Light**, **Dark**, and **System** color modes. It reads and writes the theme through [`useTheme`](../api/use-theme.md) and requires no configuration.
11
+
12
+ ## Import
13
+
14
+ ```tsx
15
+ import { AppearanceSwitcher } from "@tailor-platform/app-shell";
16
+ ```
17
+
18
+ ## Basic Usage
19
+
20
+ <example-preview name="basic-usage"></example-preview>
21
+
22
+ ```tsx
23
+ function BasicUsage() {
24
+ return <AppearanceSwitcher />;
25
+ }
26
+ ```
27
+
28
+ Drop it anywhere inside an `<AppShell>` tree — for example in a sidebar footer or a settings toolbar.
29
+
30
+ It is also the default action in [`SidebarLayout.DefaultHeader`](./default-header.md). Because `DefaultHeader`'s `actions` prop **replaces** the entire right-hand cluster, you must include `<AppearanceSwitcher />` in your `actions` array if you customize the header and still want the switcher:
31
+
32
+ ```tsx
33
+ <SidebarLayout
34
+ header={
35
+ <SidebarLayout.DefaultHeader
36
+ actions={[<NotificationBell key="bell" />, <AppearanceSwitcher key="appearance" />]}
37
+ />
38
+ }
39
+ />
40
+ ```
41
+
42
+ ## Props
43
+
44
+ `AppearanceSwitcher` accepts no props. Color theme state is managed internally via `useTheme`.
45
+
46
+ ## Behavior
47
+
48
+ - Renders a palette icon button. Clicking it opens a popover menu with three radio options: **Light**, **Dark**, and **System**.
49
+ - The active option is highlighted.
50
+ - When **System** is selected, the button tooltip shows the currently resolved mode (e.g. _"Following system — currently dark"_).
51
+ - The selected preference is persisted to `localStorage` (key `appshell-ui-theme`) and restored on subsequent visits.
52
+
53
+ ## Example: Sidebar Footer
54
+
55
+ ```tsx
56
+ import {
57
+ AppShell,
58
+ SidebarLayout,
59
+ DefaultSidebar,
60
+ AppearanceSwitcher,
61
+ } from "@tailor-platform/app-shell";
62
+
63
+ function CustomSidebar() {
64
+ return (
65
+ <DefaultSidebar
66
+ footer={
67
+ <div className="flex items-center justify-end p-2">
68
+ <AppearanceSwitcher />
69
+ </div>
70
+ }
71
+ />
72
+ );
73
+ }
74
+
75
+ function App() {
76
+ return (
77
+ <AppShell title="My App" modules={modules}>
78
+ <SidebarLayout sidebar={<CustomSidebar />} />
79
+ </AppShell>
80
+ );
81
+ }
82
+ ```
83
+
84
+ ## Related
85
+
86
+ - [useTheme](../api/use-theme.md) — hook to read and set the color theme programmatically
87
+ - [Styling & Theming](../concepts/styling-theming.md) — color themes and palette overview