@exxatdesignux/ui 0.2.17 → 0.2.19

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 (162) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/consumer-extras/AGENTS.md +76 -0
  3. package/consumer-extras/README.md +5 -1
  4. package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +14 -3
  5. package/consumer-extras/cursor-skills/exxat-consumer-app/SKILL.md +37 -0
  6. package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +22 -7
  7. package/consumer-extras/cursor-skills/exxat-focused-workflow-page/SKILL.md +57 -0
  8. package/consumer-extras/cursor-skills/exxat-kpi-flat-band/SKILL.md +38 -0
  9. package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +10 -3
  10. package/consumer-extras/patterns/consumer-app-pattern.md +39 -0
  11. package/consumer-extras/patterns/consumer-upgrade-checklist.md +20 -0
  12. package/consumer-extras/patterns/data-views-pattern.md +42 -3
  13. package/consumer-extras/patterns/focused-workflow-page-pattern.md +84 -0
  14. package/consumer-extras/patterns/kpi-flat-band-pattern.md +57 -0
  15. package/consumer-extras/patterns/shell-surface-elevation-pattern.md +54 -0
  16. package/package.json +2 -1
  17. package/src/components/ui/button-group.tsx +81 -0
  18. package/src/components/ui/button.tsx +4 -4
  19. package/src/components/ui/sidebar.tsx +2 -2
  20. package/src/globals.css +7 -1807
  21. package/src/theme.css +10 -1126
  22. package/src/tokens/README.md +15 -0
  23. package/src/tokens/base.css +337 -0
  24. package/src/tokens/high-contrast.css +1195 -0
  25. package/src/tokens/layers.css +224 -0
  26. package/src/tokens/tailwind-bridge.css +118 -0
  27. package/src/tokens/themes.css +201 -0
  28. package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +1 -1
  29. package/template/AGENTS.md +66 -21
  30. package/template/app/(app)/dashboard/loading.tsx +3 -15
  31. package/template/app/(app)/dashboard/page.tsx +2 -14
  32. package/template/app/(app)/data-list/layout.tsx +43 -0
  33. package/template/app/(app)/data-list/page.tsx +2 -2
  34. package/template/app/(app)/error.tsx +22 -6
  35. package/template/app/(app)/examples/focused-workflow/page.tsx +5 -0
  36. package/template/app/(app)/examples/page.tsx +1 -0
  37. package/template/app/(app)/layout.tsx +13 -6
  38. package/template/app/(app)/loading.tsx +1 -18
  39. package/template/app/(app)/question-bank/find/page.tsx +2 -1
  40. package/template/app/(app)/question-bank/library/page.tsx +2 -1
  41. package/template/app/(app)/question-bank/list/page.tsx +2 -1
  42. package/template/app/(app)/question-bank/new/page.tsx +15 -23
  43. package/template/app/(app)/question-bank/page.tsx +2 -1
  44. package/template/app/(app)/settings/page.tsx +4 -5
  45. package/template/app/global-error.tsx +63 -0
  46. package/template/app/globals.css +7 -1934
  47. package/template/app/layout.tsx +2 -0
  48. package/template/components/app-route-loading.tsx +14 -0
  49. package/template/components/app-sidebar.tsx +71 -55
  50. package/template/components/data-table/index.tsx +31 -67
  51. package/template/components/data-table/use-table-state.ts +33 -6
  52. package/template/components/data-views/index.ts +37 -9
  53. package/template/components/data-views/list-page-calendar-view.tsx +593 -0
  54. package/template/components/data-views/list-page-connected-view-body.tsx +66 -0
  55. package/template/components/data-views/list-page-folder-columns-panel.tsx +345 -0
  56. package/template/components/data-views/list-page-split-hub-chrome.tsx +8 -0
  57. package/template/components/dev-chunk-load-recovery.tsx +41 -0
  58. package/template/components/examples/focused-workflow-showcase.tsx +183 -0
  59. package/template/components/exxat-product-logo.tsx +2 -6
  60. package/template/components/key-metrics.tsx +54 -22
  61. package/template/components/list-hub-board-view.tsx +68 -0
  62. package/template/components/list-hub-client.tsx +186 -0
  63. package/template/components/list-hub-list-view.tsx +36 -0
  64. package/template/components/list-hub-panel-activator.tsx +8 -0
  65. package/template/components/list-hub-secondary-nav.tsx +121 -0
  66. package/template/components/list-hub-table.tsx +336 -0
  67. package/template/components/new-question-composer.tsx +6 -24
  68. package/template/components/product-switcher.tsx +5 -5
  69. package/template/components/product-wordmark.tsx +4 -7
  70. package/template/components/question-bank-client.tsx +4 -1
  71. package/template/components/question-bank-folder-columns-panel.tsx +104 -0
  72. package/template/components/question-bank-hub-client.tsx +2 -5
  73. package/template/components/question-bank-table.tsx +155 -509
  74. package/template/components/secondary-panel/nav-link-rows.tsx +83 -0
  75. package/template/components/secondary-panel.tsx +4 -44
  76. package/template/components/secondary-panels/list-hub-panel.tsx +39 -0
  77. package/template/components/secondary-panels/question-bank-panel.tsx +39 -0
  78. package/template/components/secondary-panels/registry.tsx +15 -0
  79. package/template/components/settings-appearance-card.tsx +3 -2
  80. package/template/components/settings-client.tsx +59 -15
  81. package/template/components/settings-form-row.tsx +9 -4
  82. package/template/components/sidebar-shell.tsx +2 -1
  83. package/template/components/table-properties/drawer-button.tsx +51 -20
  84. package/template/components/table-properties/drawer.tsx +81 -17
  85. package/template/components/templates/focused-workflow-layouts.tsx +448 -0
  86. package/template/components/templates/focused-workflow-page-template.tsx +69 -0
  87. package/template/components/templates/list-page.tsx +40 -13
  88. package/template/components/templates/nested-secondary-panel-shell.tsx +3 -2
  89. package/template/components/templates/page-loading-shell.tsx +262 -0
  90. package/template/components/ui/button-group.tsx +1 -0
  91. package/template/contexts/product-context.tsx +21 -2
  92. package/template/docs/consumer-app-pattern.md +39 -0
  93. package/template/docs/data-views-pattern.md +42 -3
  94. package/template/docs/drawer-vs-dialog-pattern.md +3 -1
  95. package/template/docs/focused-workflow-page-pattern.md +84 -0
  96. package/template/docs/kpi-flat-band-pattern.md +57 -0
  97. package/template/docs/kpi-strip-max-four-pattern.md +1 -0
  98. package/template/docs/shell-surface-elevation-pattern.md +54 -0
  99. package/template/lib/chunk-load-error.ts +13 -0
  100. package/template/lib/command-menu-search-data.ts +11 -27
  101. package/template/lib/conditional-rule-match.ts +87 -22
  102. package/template/lib/data-list-display-options.ts +16 -2
  103. package/template/lib/data-list-view-registry.ts +104 -0
  104. package/template/lib/data-list-view-surface.ts +15 -1
  105. package/template/lib/data-list-view.ts +16 -1
  106. package/template/lib/data-view-dashboard-storage.ts +38 -35
  107. package/template/lib/hub-connected-view-renderers.ts +58 -0
  108. package/template/lib/list-hub-nav.ts +121 -0
  109. package/template/lib/list-hub-supported-views.ts +10 -0
  110. package/template/lib/list-page-table-properties.ts +3 -7
  111. package/template/lib/list-status-badges.ts +4 -97
  112. package/template/lib/mock/list-hub-directory.ts +27 -0
  113. package/template/lib/mock/list-hub-kpi.ts +27 -0
  114. package/template/lib/mock/navigation.tsx +1 -0
  115. package/template/lib/page-loading-variant.ts +40 -0
  116. package/template/lib/question-bank-supported-views.ts +13 -0
  117. package/template/lib/sidebar-state-cookie.ts +9 -0
  118. package/template/lib/table-state-lifecycle.ts +60 -13
  119. package/template/app/(app)/data-list/[id]/page.tsx +0 -44
  120. package/template/app/(app)/data-list/new/page.tsx +0 -34
  121. package/template/components/compliance-board-view.tsx +0 -142
  122. package/template/components/compliance-client.tsx +0 -92
  123. package/template/components/compliance-list-view.tsx +0 -54
  124. package/template/components/compliance-page-header.tsx +0 -89
  125. package/template/components/compliance-table.tsx +0 -632
  126. package/template/components/data-view-dashboard-charts-compliance.tsx +0 -963
  127. package/template/components/data-view-dashboard-charts-team.tsx +0 -971
  128. package/template/components/data-view-dashboard-charts.tsx +0 -1503
  129. package/template/components/new-placement-back-btn.tsx +0 -28
  130. package/template/components/new-placement-form.tsx +0 -1068
  131. package/template/components/placement-board-card.tsx +0 -262
  132. package/template/components/placement-detail.tsx +0 -438
  133. package/template/components/placements-board-view.tsx +0 -404
  134. package/template/components/placements-client.tsx +0 -252
  135. package/template/components/placements-list-view.tsx +0 -171
  136. package/template/components/placements-page-header.tsx +0 -166
  137. package/template/components/placements-table-cells.test.tsx +0 -22
  138. package/template/components/placements-table-cells.tsx +0 -173
  139. package/template/components/placements-table-columns.tsx +0 -640
  140. package/template/components/placements-table.tsx +0 -1675
  141. package/template/components/rotations-empty-state.tsx +0 -50
  142. package/template/components/rotations-panel-activator.tsx +0 -8
  143. package/template/components/sites-all-client.tsx +0 -154
  144. package/template/components/sites-board-view.tsx +0 -67
  145. package/template/components/sites-list-view.tsx +0 -42
  146. package/template/components/sites-table.tsx +0 -402
  147. package/template/components/team-board-view.tsx +0 -122
  148. package/template/components/team-client.tsx +0 -100
  149. package/template/components/team-list-view.tsx +0 -59
  150. package/template/components/team-page-header.tsx +0 -92
  151. package/template/components/team-table.tsx +0 -714
  152. package/template/lib/data-view-dashboard-placements-layout.ts +0 -215
  153. package/template/lib/mock/compliance-kpi.ts +0 -61
  154. package/template/lib/mock/compliance.ts +0 -146
  155. package/template/lib/mock/placements-kpi.ts +0 -134
  156. package/template/lib/mock/placements.ts +0 -183
  157. package/template/lib/mock/sites-directory.ts +0 -16
  158. package/template/lib/mock/sites-kpi.ts +0 -25
  159. package/template/lib/mock/team-kpi.ts +0 -60
  160. package/template/lib/mock/team.ts +0 -118
  161. package/template/lib/placement-board-card-layout.ts +0 -79
  162. package/template/lib/placement-lifecycle.ts +0 -5
package/CHANGELOG.md CHANGED
@@ -15,6 +15,36 @@ After the user bumps `@exxatdesignux/ui`, do this in order:
15
15
 
16
16
  ---
17
17
 
18
+ ## [0.2.19] - 2026-05-19
19
+
20
+ ### Added
21
+
22
+ - **Design tokens (CSS modules):** Split theme surface into `src/tokens/` (`base.css`, `themes.css`, `high-contrast.css`, `layers.css`, `tailwind-bridge.css`). Entry points `globals.css` / `theme.css` re-export only — **no token value changes**.
23
+ - **Package export:** `@exxatdesignux/ui/tokens/*` for consumers that import token partials alongside Tailwind v4.
24
+
25
+ ### Changed
26
+
27
+ - **Starter `template/`** and **consumer extras:** List hub shell, secondary panel registry, route-aware loading skeletons, focused-workflow settings layout, KPI flat band + shell elevation docs/skills — synced from `apps/web`.
28
+
29
+ ### Chore (monorepo)
30
+
31
+ - Package **`version`** **0.2.19** — publish with tag **`ui-v0.2.19`**.
32
+
33
+ ## [0.2.18] - 2026-05-19
34
+
35
+ ### Fixed
36
+
37
+ - **`Sidebar`**: Read `sidebar_state` on the server for `defaultOpen` so the documents **Resources** heading and rail chrome match the first client paint (fixes hydration warnings). Skip redundant cookie restore when state already matches.
38
+ - **`TablePropertiesDrawer`**: Portaled **Add filter / sort / rule** menus use `z-[90]` above the properties sheet (`z-[80]`); `Sheet` and dropdowns use `modal={false}`; filter updates apply synchronously (no `startTransition` deferral). Drawer button routes column/display handlers through refs for the portaled sheet.
39
+
40
+ ### Changed
41
+
42
+ - **Starter `template/`** and **consumer extras**: KPI flat band + shell surface elevation patterns/skills; table-properties and hub parity with `apps/web`.
43
+
44
+ ### Chore (monorepo)
45
+
46
+ - Package **`version`** set to **0.2.18** for npm publish (tag **`ui-v0.2.18`**).
47
+
18
48
  ## [0.2.17] - 2026-05-18
19
49
 
20
50
  ### Changed
@@ -0,0 +1,76 @@
1
+ # Exxat DS — consumer app handbook
2
+
3
+ **Purpose:** Guide for **product repositories** that depend on **`@exxatdesignux/ui`** from npm. The monorepo **`apps/web`** app is the full reference implementation; this file is what ships in the package for consumers.
4
+
5
+ **Path after sync:** `docs/exxat-ds/AGENTS-consumer.md` or merge sections into your app handbook via **`exxat-ui sync-extras`**.
6
+
7
+ ---
8
+
9
+ ## 1. How to use this file (for AI agents)
10
+
11
+ 1. **Before** upgrading **`@exxatdesignux/ui`**, read **`consumer-upgrade-checklist.md`** and **`CHANGELOG.md`** in the installed package.
12
+ 2. **Before** adding a **list / table / board hub**, read **`data-views-pattern.md`** (view registry + connected bodies), **`consumer-app-pattern.md`**, and skill **`exxat-centralized-list-dataset`**.
13
+ 3. **Before** a **dedicated form / wizard / settings route**, read **`focused-workflow-page-pattern.md`** and **`exxat-focused-workflow-page`** skill.
14
+ 4. **Before** nested **Library / scope** nav, read **`exxat-primary-nav-secondary-panel`** skill and **`shell-surface-elevation-pattern.md`**.
15
+ 5. Run **`exxat-ui sync-extras`** after every DS version bump so **`.cursor/skills/exxat-*`** match the tarball.
16
+
17
+ ---
18
+
19
+ ## 2. What ships in the package
20
+
21
+ | Artifact | Location in npm | Use |
22
+ |----------|-----------------|-----|
23
+ | Components + tokens | `@exxatdesignux/ui` | Import UI, hooks, CSS |
24
+ | Reference app | `node_modules/@exxatdesignux/ui/template/` | Diff / port routes and hub clients |
25
+ | Cursor skills | `consumer-extras/cursor-skills/` → sync to `.cursor/skills/` | AI checklists |
26
+ | Pattern docs | `consumer-extras/patterns/` → sync to `docs/exxat-ds/` | Human + AI narrative |
27
+
28
+ **`sync-extras` does not** modify your product routes — you port intentionally from **`template/`**.
29
+
30
+ ---
31
+
32
+ ## 3. List hub stack (centralized)
33
+
34
+ **MUST:**
35
+
36
+ - **`lib/mock/<entity>.ts`** — one row type + seed data.
37
+ - **`lib/<hub>-supported-views.ts`** — allowlist shared by **`ListPageTemplate`** and **`TablePropertiesDrawer`**.
38
+ - **`useTableState`** — **`tableState.rows`** feeds table, list, board, dashboard, folder, panel, tree.
39
+ - **`ListPageConnectedViewBody`** + **`defineHubViewRenderers`** — no silent dashboard fallback.
40
+ - **`ListPageViewFrame`** / **`components/data-views/`** for non-table bodies.
41
+
42
+ **MUST NOT:** Second mock array per view; **`ListPageTemplate`** on a dedicated create/edit URL.
43
+
44
+ **Rule/skill (sync from package):** `exxat-centralized-list-dataset`, `exxat-list-page-connected-views`, `exxat-list-page-view-shells`.
45
+
46
+ ---
47
+
48
+ ## 4. Shell elevation
49
+
50
+ | Level | Token |
51
+ |-------|--------|
52
+ | Primary sidebar | `--sidebar` |
53
+ | Secondary panel (Library) | `--secondary-panel-bg` |
54
+ | Page | `--background` |
55
+
56
+ Dark mode secondary panel **MUST** use **`color-mix(… var(--sidebar-accent) …)`**, not light **`--brand-tint`**. See **`shell-surface-elevation-pattern.md`**.
57
+
58
+ ---
59
+
60
+ ## 5. Consumer app checklist (copy for PRs)
61
+
62
+ - [ ] **`@exxatdesignux/ui`** version recorded; **`exxat-ui sync-extras`** run if skills/docs changed.
63
+ - [ ] Template diff reviewed for new **`template/`** files relevant to this feature.
64
+ - [ ] List hub: **`supportedViewTypes`** aligned; **`ListPageConnectedViewBody`**; **`tableState.rows`** everywhere.
65
+ - [ ] Form/wizard route: **`FocusedWorkflowPageTemplate`** (not list hub shell).
66
+ - [ ] Secondary panel: **`--secondary-panel-bg`** on **`NestedSecondaryPanelShell`**; dark mode spot-checked.
67
+ - [ ] Product switcher: collapsed sidebar opens menu (**`SidebarMenuButton` `tooltip`**, not nested Tooltip + DropdownMenu).
68
+ - [ ] No toast — banners / inline / dialog.
69
+
70
+ ---
71
+
72
+ ## 6. See also
73
+
74
+ - **`consumer-app-pattern.md`**
75
+ - **`consumer-upgrade-checklist.md`**
76
+ - Monorepo **`apps/web/AGENTS.md`** (full product handbook when you have the design-system repo)
@@ -8,7 +8,9 @@ touching product routes or pages.
8
8
  |----------------------|-------------------------------------------|
9
9
  | `CHANGELOG.md` (package root) | Stay in `node_modules/…` — read for release notes; **`exxat-ui changelog`** prints it |
10
10
  | `cursor-skills/exxat-*` | `.cursor/skills/exxat-*` (replaced) |
11
- | `patterns/*.md` | `docs/exxat-ds/*.md` (replaced) — includes **`consumer-upgrade-checklist.md`** for upgrades + AI handoff |
11
+ | `patterns/*.md` | `docs/exxat-ds/*.md` (replaced) — includes **`consumer-upgrade-checklist.md`**, **`consumer-app-pattern.md`**, view-registry + shell docs |
12
+ | `AGENTS.md` (this folder) | Copy or merge into your app handbook as **`AGENTS-consumer.md`** |
13
+ | `cursor-skills/exxat-consumer-app` | Consumer-repo checklist (npm install, template diff) |
12
14
 
13
15
  **Components and hooks** still come only from `node_modules/@exxatdesignux/ui`
14
16
  via normal semver installs — `sync-extras` does not copy TS source into your app.
@@ -20,3 +22,5 @@ pnpm --filter @exxatdesignux/ui vendor:consumer-extras
20
22
  ```
21
23
 
22
24
  …then bump `packages/ui` version and publish so consumers get the new bundle.
25
+
26
+ **List-page stack** (registry, `ListPageConnectedViewBody`, `supportedViewTypes`) lives in **`template/`** inside the tarball — not in `@exxatdesignux/ui` component exports. After changing **`apps/web`** or **`packages/ui/template`**, diff both trees and re-publish so consumer apps that copy from **`node_modules/@exxatdesignux/ui/template/`** stay aligned.
@@ -60,7 +60,18 @@ Goal: **one row model**, **one filtered bag** (`tableState.rows`), **one place f
60
60
 
61
61
  ---
62
62
 
63
- ## 6. Implementation checklist (new hub or new view)
63
+ ## 6. View registry + connected body (required)
64
+
65
+ - [ ] **`lib/<hub>-supported-views.ts`** — same array on **`ListPageTemplate`** (`supportedViewTypes`) and **`TablePropertiesDrawerButton`**.
66
+ - [ ] **`ListPageConnectedViewBody`** + **`defineHubViewRenderers(supported, { … })`** — one renderer per **`DataListViewRenderKind`**; missing → **`ListPageViewNotConfigured`** (never silent dashboard).
67
+ - [ ] Branch on **`getDataListViewRenderKind(view)`** via the connected body — not long **`if (view === "table")`** chains in the table file.
68
+ - [ ] **`lib/data-list-view-registry.ts`** — labels/icons/render kinds stay centralized.
69
+
70
+ **Canon:** `docs/data-views-pattern.md` § “View registry and connected bodies”, **`AGENTS.md` §4.1.1**.
71
+
72
+ ---
73
+
74
+ ## 7. Implementation checklist (new hub or new view)
64
75
 
65
76
  - [ ] Exactly **one** primary row array shape in **`lib/mock/<entity>.ts`** (or API).
66
77
  - [ ] **`useTableState`** seeded from that array; **child views** receive **`tableState.rows`** (or equivalent), **not** a fresh import of the mock list.
@@ -72,7 +83,7 @@ Goal: **one row model**, **one filtered bag** (`tableState.rows`), **one place f
72
83
 
73
84
  ---
74
85
 
75
- ## 7. Reference implementations
86
+ ## 8. Reference implementations
76
87
 
77
88
  - **`components/data-list-client.tsx`** + **`data-list-table.tsx`** — Placements pattern.
78
89
  - **`components/team-client.tsx`** + **`team-table.tsx`**.
@@ -80,7 +91,7 @@ Goal: **one row model**, **one filtered bag** (`tableState.rows`), **one place f
80
91
 
81
92
  ---
82
93
 
83
- ## 8. Centralized presentation (with the same dataset)
94
+ ## 9. Centralized presentation (with the same dataset)
84
95
 
85
96
  **Layout:** Non-table view branches wrap in **`ListPageViewFrame`** (constants in **`list-page-view-frame.tsx`**) — see **`.cursor/rules/exxat-list-page-view-shells.mdc`**.
86
97
 
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: exxat-consumer-app
3
+ description: Build or upgrade product apps that install @exxatdesignux/ui from npm — sync-extras, diff template/, centralized list hubs, focused workflow routes, shell elevation. Use when working outside the design-system monorepo or after pnpm add @exxatdesignux/ui.
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Exxat DS — consumer app
8
+
9
+ **Pattern:** `consumer-app-pattern.md` (in `docs/exxat-ds/` after sync)
10
+ **Handbook:** `AGENTS-consumer.md` or `consumer-app-pattern.md` parent **`AGENTS.md`** in package extras
11
+ **Upgrade:** `consumer-upgrade-checklist.md`
12
+
13
+ ## When this applies
14
+
15
+ - Repo has **`@exxatdesignux/ui`** in **`package.json`**, not the design-system monorepo **`apps/web`**.
16
+ - Task is **porting** a hub, shell, or route from **`node_modules/@exxatdesignux/ui/template/`**.
17
+
18
+ ## Checklist
19
+
20
+ - [ ] Read installed **`CHANGELOG.md`**; run **`exxat-ui sync-extras`** after bump.
21
+ - [ ] Diff **`template/`** vs your app for the feature (client, table, mocks, layout).
22
+ - [ ] **List hub:** `lib/<hub>-supported-views.ts` + **`ListPageConnectedViewBody`** + **`defineHubViewRenderers`** + one **`useTableState`** row bag.
23
+ - [ ] **Same** `supportedViewTypes` on **`ListPageTemplate`** and **`TablePropertiesDrawer`**.
24
+ - [ ] **Form/wizard/settings URL:** **`FocusedWorkflowPageTemplate`** — not **`ListPageTemplate`**.
25
+ - [ ] **Secondary panel:** `NestedSecondaryPanelShell` + **`--secondary-panel-bg`**; verify **dark mode** (no light rose panel).
26
+ - [ ] **Product switcher (collapsed):** `DropdownMenuTrigger` → **`SidebarMenuButton`** with **`tooltip=`** — do not nest **`Tooltip`** outside **`DropdownMenuTrigger`**.
27
+ - [ ] CSS: import DS globals; product theme classes on **`<html>`** via **`ProductProvider`** pattern from template.
28
+
29
+ ## MUST NOT
30
+
31
+ - Fork **`DataTable`** / view-tab stack when template already has the hub pattern.
32
+ - Import raw **`ENTITY_ROWS`** into folder/board views while the table filters **`useTableState`**.
33
+ - Skip **`exxat-ui sync-extras`** and rely on stale **`.cursor/skills`**.
34
+
35
+ ## Pair with
36
+
37
+ - **`exxat-centralized-list-dataset`**, **`exxat-list-page-view-shells`**, **`exxat-focused-workflow-page`**, **`exxat-primary-nav-secondary-panel`**
@@ -21,7 +21,7 @@ description: >
21
21
  - **Stack:** Next.js 16 (App Router), React, TypeScript, Tailwind CSS, shadcn/ui primitives, Font Awesome icons
22
22
  - **App root:** `exxat-ds/app/(app)/` — route group that wraps all authenticated pages
23
23
  - **Single source of truth:** `exxat-ds/AGENTS.md` for full prose explanations; this skill is the actionable summary
24
- - **Companion skills (narrow topics):** `exxat-fontawesome-icons`, `exxat-mono-ids`, `exxat-primary-nav-secondary-panel`, `exxat-centralized-list-dataset`, `exxat-list-page-view-shells`, `exxat-dedicated-search-surfaces`, `exxat-accessibility`, `exxat-board-cards`, `exxat-collaboration-access` — live under `.cursor/skills/`; vetted copies ship with **`@exxatdesignux/ui`** in `consumer-extras/cursor-skills/` after **`pnpm --filter @exxatdesignux/ui vendor:consumer-extras`**.
24
+ - **Companion skills (narrow topics):** `exxat-fontawesome-icons`, `exxat-mono-ids`, `exxat-primary-nav-secondary-panel`, `exxat-centralized-list-dataset`, `exxat-list-page-view-shells`, `exxat-dedicated-search-surfaces`, `exxat-focused-workflow-page`, `exxat-accessibility`, `exxat-board-cards`, `exxat-collaboration-access` — live under `.cursor/skills/`; vetted copies ship with **`@exxatdesignux/ui`** in `consumer-extras/cursor-skills/` after **`pnpm --filter @exxatdesignux/ui vendor:consumer-extras`**.
25
25
  - **Question bank folder-scoped header (rule + doc):** **`.cursor/rules/exxat-question-bank-hub-header.mdc`** and **`docs/question-bank-hub-header-pattern.md`** — pair with **`exxat-primary-nav-secondary-panel`** when URL **`scope=folder`** drives the hub title.
26
26
  - **Consumer repos (npm install of `@exxatdesignux/ui`):** After a version bump, read **`node_modules/@exxatdesignux/ui/CHANGELOG.md`**, run **`npx --package=@exxatdesignux/ui@latest exxat-ui sync-extras`** so **`docs/exxat-ds/consumer-upgrade-checklist.md`** and Cursor skills match the tarball, and diff the host app against **`node_modules/@exxatdesignux/ui/template/`** for anything new to port (routes, re-exports, AGENTS). Use **`exxat-ui changelog`**, **`exxat-ui update`**, and **`exxat-ui doctor`** for CLI guidance.
27
27
 
@@ -259,8 +259,21 @@ ListPageTemplate
259
259
  ```
260
260
 
261
261
  **Reference implementations:**
262
- - `components/team-client.tsx` + `components/team-table.tsx` canonical pattern
263
- - `components/data-list-client.tsx` + `components/data-list-table.tsx` — Placements (most complete)
262
+ - **`apps/web`:** `components/list-hub-client.tsx` + `list-hub-table.tsx`, `question-bank-client.tsx` + `question-bank-table.tsx`
263
+ - **`packages/ui/template/`** (ships with npm): `placements-client.tsx` + `placements-table.tsx`, `team-client.tsx` + `team-table.tsx` — diff template on upgrade
264
+
265
+ ### 4.1 View registry (do not fork `if (view === …)`)
266
+
267
+ 1. **`lib/data-list-view.ts`** — `DATA_LIST_VIEW_TILES` (labels/icons).
268
+ 2. **`lib/data-list-view-registry.ts`** — `renderKind`, `showsListPageHubMetricsStrip`, `dataListViewTilesForHub`.
269
+ 3. **`lib/foo-supported-views.ts`** — `export const FOO_SUPPORTED_VIEWS = ["table", "list", …] as const`.
270
+ 4. **`ListPageTemplate`** — `supportedViewTypes={FOO_SUPPORTED_VIEWS}`.
271
+ 5. **`foo-table.tsx`** — `ListPageConnectedViewBody` with renderers per kind; **`TablePropertiesDrawerButton`** gets the same **`supportedViewTypes`**.
272
+ 6. Generic bodies under **`components/data-views/`** — calendar, board template, folder grid, etc.
273
+
274
+ **MUST NOT** default unknown views to dashboard KPIs — missing renderers use **`ListPageViewNotConfigured`**.
275
+
276
+ **Narrative:** `docs/data-views-pattern.md` § “View registry and connected bodies”.
264
277
 
265
278
  **Files to create for a new hub page `Foo`:**
266
279
  | File | Purpose |
@@ -268,8 +281,9 @@ ListPageTemplate
268
281
  | `lib/mock/foo.ts` | Mock data + TypeScript interface (12+ rows) |
269
282
  | `lib/mock/foo-kpi.ts` | `fooKpiMetrics()` + `fooKpiInsight()` |
270
283
  | `components/foo-page-header.tsx` | `PageHeader` + primary CTA + ⋯ menu |
271
- | `components/foo-table.tsx` | `DataTable` + `useTableState` + `TablePropertiesDrawer` |
272
- | `components/foo-client.tsx` | `ListPageTemplate` orchestrator |
284
+ | `lib/foo-supported-views.ts` | Views this hub implements (registry allowlist) |
285
+ | `components/foo-table.tsx` | `ListPageConnectedViewBody` + `DataTable` + `useTableState` + Properties |
286
+ | `components/foo-client.tsx` | `ListPageTemplate` + `supportedViewTypes` |
273
287
  | `app/(app)/foo/page.tsx` | Thin server component |
274
288
 
275
289
  **Do not** ship a **nav-linked hub** as an **empty page** or a single “replace this later” paragraph. If the route appears in **`lib/mock/navigation.tsx`**, implement the full hub (mock rows, **`ListPageTemplate`**, connected views per **`exxat-ds/AGENTS.md` §4.1**) unless the product explicitly defines a non-data shell.
@@ -279,8 +293,9 @@ ListPageTemplate
279
293
  - **Drawer / sheet** — Use when the user needs **the current page behind them** *and* a **quick view**, **quick actions**, or a **short step** (e.g. properties, export, glance at a row).
280
294
  - **Dialog** — **Blocking** confirm/alert/short choice — **`docs/drawer-vs-dialog-pattern.md`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**.
281
295
  - **New page** — Use **otherwise**: **primary**, **long-form**, **multi-step**, or flows that need their **own URL** without the hub visible.
296
+ - **Focused workflow route** — **`FocusedWorkflowPageTemplate`** + **`FocusedWorkflowSingleColumn`** | **`FocusedWorkflowStepForm`** | **`FocusedWorkflowSidebarSections`** | **`FocusedWorkflowEmptyState`** — **`docs/focused-workflow-page-pattern.md`**, **`AGENTS.md` §14**, **`exxat-focused-workflow-page`** skill. **Not** list hubs; **not** Miller columns.
282
297
 
283
- Align with **`exxat-ds/AGENTS.md` §6.4**, **`docs/data-views-pattern.md`**, **`docs/drawer-vs-dialog-pattern.md`**, **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**.
298
+ Align with **`exxat-ds/AGENTS.md` §6.4**, **§14**, **`docs/data-views-pattern.md`**, **`docs/drawer-vs-dialog-pattern.md`**, **`docs/focused-workflow-page-pattern.md`**, **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**, **`.cursor/rules/exxat-focused-workflow-page.mdc`**.
284
299
 
285
300
  ---
286
301
 
@@ -551,7 +566,7 @@ import { DropdownMenuItem, Shortcut } from "@/components/ui/dropdown-menu"
551
566
  | Duplicate | ⌘/Ctrl + D |
552
567
  | Review / Info | ⌘/Ctrl + I |
553
568
  | Remove / Delete item | ⌘/Ctrl + ⌫ |
554
- | Add view (1..n) | ⌘/Ctrl + ⇧/Shift + 1..9 |
569
+ | Add view (1..n) | **1..9** (plain digit; `dataListViewAddShortcut`) |
555
570
  | **Submit a workflow** (Create, Save, Export, Apply) | **Enter** ⏎ — scoped to the open form/drawer/dialog |
556
571
  | **Cancel / dismiss** a workflow | **Esc** (Radix Dialog/Sheet/AlertDialog already bind this) |
557
572
  | **Advance a multi-step wizard** | ⌘/Ctrl + Enter (plain Enter must not submit mid-flow) |
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: exxat-focused-workflow-page
3
+ description: FocusedWorkflowPageTemplate — dedicated routes for large forms, multi-step wizards, and sectioned settings (single column, steps, sidebar nav). Not list hubs or Miller-column explorers. Use when adding create/edit routes, settings pages, or empty workflow placeholders.
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Exxat DS — focused workflow page
8
+
9
+ **Rule:** `.cursor/rules/exxat-focused-workflow-page.mdc`
10
+ **Doc:** `docs/focused-workflow-page-pattern.md` (app / consumer-extras `patterns/`)
11
+ **Handbook:** `AGENTS.md` §6.4, **§14** checklist
12
+
13
+ ## When to use
14
+
15
+ | Use **focused workflow** | Use something else |
16
+ | --- | --- |
17
+ | Own URL; primary create/edit; multi-step wizard; sectioned settings | **List hub** → `ListPageTemplate` + `DataTable` |
18
+ | Large form that should not sit in a drawer | **Quick hub adjunct** → drawer (`ExportDrawer`, `TablePropertiesDrawer`) |
19
+ | | **Blocking confirm** → dialog |
20
+ | | **Finder / folder columns** → `ListPageSplitHubChrome`, `ListPageFolderColumnsPanel` |
21
+
22
+ ## Checklist
23
+
24
+ - [ ] Route uses **`FocusedWorkflowPageTemplate`** — not raw `SidebarInset` copy-paste; not **`PrimaryPageTemplate`** / **`ListPageTemplate`**.
25
+ - [ ] **`siteHeader`**: `back` or `breadcrumbs` + `title`; parent trail stays in header, not duplicated in body.
26
+ - [ ] **`maxWidth`**: `md` simple forms · `lg` settings / wide fields · `xl` only when justified.
27
+ - [ ] **One body layout** from `focused-workflow-layouts.tsx`:
28
+ - **`FocusedWorkflowSingleColumn`** — default stack
29
+ - **`FocusedWorkflowStepForm`** + **`FocusedWorkflowWizardFooter`** — wizard
30
+ - **`FocusedWorkflowSidebarSections`** — left section nav (`id` on `<section>` matches `sections[].id`)
31
+ - **`FocusedWorkflowEmptyState`** — not configured / coming soon
32
+ - [ ] **Footers:** **`FocusedWorkflowActionFooter`** or **`FocusedWorkflowWizardFooter`** with **`Shortcut`** + **`<Kbd variant="bare">`** in buttons (**`exxat-kbd-shortcuts.mdc`**).
33
+ - [ ] Domain UI in **`*-composer.tsx`** / **`*-client.tsx`**; keep **`FocusedWorkflow*`** names generic (not product-specific).
34
+ - [ ] Long forms: optional **`beforeSiteHeader={<SidebarAutoCollapse />}`** (see `/question-bank/new`).
35
+ - [ ] **No** **`ListPageTemplate`** view tabs, **no** Miller columns, **no** **`ListPageFolderColumnsPanel`** inside this shell.
36
+ - [ ] **No toast** for outcomes — banners, inline, or dialog (**`exxat-no-toast.mdc`**).
37
+
38
+ ## MUST NOT
39
+
40
+ - Ship a **full create/edit wizard** only in a drawer when it needs bookmarkable URL / long focus.
41
+ - Use **`ListPageTemplate`** for a dedicated “new record” route.
42
+ - Name shared templates after one feature (`NewQuestionPageTemplate`, etc.).
43
+
44
+ ## Code pointers
45
+
46
+ | Piece | Path |
47
+ | --- | --- |
48
+ | Shell | `components/templates/focused-workflow-page-template.tsx` |
49
+ | Layouts + footers | `components/templates/focused-workflow-layouts.tsx` |
50
+ | Showcase | `components/examples/focused-workflow-showcase.tsx`, `/examples/focused-workflow` |
51
+ | Single column | `app/(app)/question-bank/new/page.tsx` + `new-question-composer.tsx` |
52
+ | Sidebar sections | `app/(app)/settings/page.tsx` + `settings-client.tsx` |
53
+
54
+ ## Pair with
55
+
56
+ - **`exxat-page-vs-drawer`**, **`exxat-drawer-vs-dialog`**, **`exxat-kbd-shortcuts`**
57
+ - **`exxat-reuse-before-custom`** — extend layouts before forking shell markup
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: exxat-kpi-flat-band
3
+ description: KeyMetrics variant flat — transparent KPI strip, OKLCH brand glow only, cell-border hairlines (no grid surface). Use when wiring ListPageTemplate metrics, dashboard mix KPIs, or fixing flat band looking like a grey box.
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Exxat DS — KPI flat band
8
+
9
+ **Rule:** `.cursor/rules/exxat-kpi-flat-band.mdc`
10
+ **Doc:** `apps/web/docs/kpi-flat-band-pattern.md`
11
+
12
+ ## Checklist
13
+
14
+ - [ ] `variant="flat"` on hub / mix view — not `card` for list-page strip.
15
+ - [ ] `flatBandStyle` = **only** `var(--key-metrics-flat-band-radial)`; shadow **`none`**.
16
+ - [ ] No `--key-metrics-flat-band-linear` in component or hub inline `style`.
17
+ - [ ] Cells **`bg-transparent`**; grid uses **`flatMetricsHairlineClass(count, halfLayout)`** — borders only, **no** `gap-px` fill.
18
+ - [ ] **4 KPIs:** verticals between 1|2|3|4 when wide; 2×2 dividers only below `@[max-width:29.99rem]` container.
19
+ - [ ] Divider + glow tokens stay **OKLCH** (`--key-metrics-flat-divider`, `color-mix(in oklch, var(--brand-color) …)`).
20
+ - [ ] **≤ 4** `MetricItem` — `docs/kpi-strip-max-four-pattern.md`.
21
+ - [ ] KPI helpers use **`tableState.rows`** on connected hubs.
22
+
23
+ ## MUST NOT
24
+
25
+ - Grey/lavender **panel** behind metrics (removed linear wash + gap fill).
26
+ - Duplicate KPI **`Card`** wall for same numbers.
27
+ - Mute product suffix to grey in dark (`mutedSuffix` does **not** change `wordmarkColor`).
28
+
29
+ ## Code pointers
30
+
31
+ - `apps/web/components/key-metrics.tsx` — `flatMetricsHairlineClass`, `flatBandStyle`
32
+ - `apps/web/app/globals.css` — `--key-metrics-flat-*`
33
+ - `question-bank-client.tsx`, `dashboard-tabs.tsx` — reference usage
34
+
35
+ ## Pair with
36
+
37
+ - `exxat-kpi-max-four`, `exxat-kpi-trends`, `exxat-list-page-connected-views`
38
+ - `docs/shell-surface-elevation-pattern.md` — sidebar vs page (not the KPI band)
@@ -12,17 +12,19 @@ user-invocable: true
12
12
  ## Wiring checklist
13
13
 
14
14
  1. **`lib/mock/navigation.tsx`** — set **`secondaryPanel: "<id>"`** on the primary **`NavLinkItem`**; **`url`** = hub route.
15
- 2. **`components/secondary-panel.tsx`** — add **`PANELS["<id>"]`** → panel shell (title, optional search) + secondary nav component.
15
+ 2. **`components/secondary-panels/registry.tsx`** — add **`SECONDARY_PANELS["<id>"]`** → panel shell (title) + hub-specific nav component (e.g. **`list-hub-panel.tsx`**, **`question-bank-panel.tsx`**). Do not add new hubs inside **`question-bank-*.tsx`**.
16
16
  3. **Hub client** — mount **`*PanelActivator`** with **`useAutoPanel("<id>")`** (same id) for the lifetime of the route (e.g. `QuestionBankPanelActivator`).
17
17
  4. **Data** — keep **one** **`useTableState`** / **`tableState.rows`**; drive scope from **URL** + small helpers (see **`lib/question-bank-nav.ts`**).
18
18
  5. **Folder-scoped hub header (Question bank library)** — When **`scope === "folder"`** in the URL, **`QuestionBankPageHeader`** **⋯ More** includes **Customize folder**; mount **`QuestionBankNewFolderSheet`** on **`QuestionBankClient`** so it works on **all** **`ListPageTemplate`** view tabs — **`.cursor/rules/exxat-question-bank-hub-header.mdc`**, **`docs/question-bank-hub-header-pattern.md`**.
19
19
  6. **Collapse control** — the nested rail header uses **`collapseActiveSecondaryPanel()`** (angles-left icon), not “close”, so the panel stays dismissed until **`openPanel`** runs again (nav, scope hook, or hub re-entry). Layout effects that auto-call **`openPanel`** must respect **`secondaryPanelAutoReopenSuppressed`** (see **`app/(app)/question-bank/layout.tsx`** + **`SecondaryPanelProvider`**).
20
+ 7. **Surface elevation** — secondary panel = **level 1** (lighter than sidebar, darker than page). Use **`--secondary-panel-bg`** on **`NestedSecondaryPanelShell`**; derive from **`--brand-tint*`** per active product (**One** indigo, **Prism** rose). See **`docs/shell-surface-elevation-pattern.md`**.
20
21
 
21
22
  ## MUST NOT
22
23
 
23
24
  - Set **`secondaryPanel`** without **`PANELS[id]`** + **`useAutoPanel`** — broken empty rail.
24
25
  - Use this for full product areas that belong as **primary** or **collapsible child** rows.
25
26
  - Invent a parallel zoom / reflow hook for the secondary rail — reuse **`useSidebarReflowZoom`** (the provider already wires it; see §"High-zoom auto-collapse" below).
27
+ - Set secondary panel **`bg-sidebar`** or a fixed rose mix for every product — breaks **One** indigo chrome.
26
28
 
27
29
  ## High-zoom auto-collapse
28
30
 
@@ -37,8 +39,13 @@ Custom panel content (anything you register under `PANELS[id]`) should **read `s
37
39
  ## Reference
38
40
 
39
41
  - `components/app-sidebar.tsx` — `openPanel` on same-route primary click.
40
- - `components/secondary-panel.tsx` — `SecondaryPanelProvider`, `PANELS` registry, **high-zoom auto-collapse**.
42
+ - `components/secondary-panel.tsx` — `SecondaryPanelProvider`, **high-zoom auto-collapse**.
43
+ - `components/secondary-panels/registry.tsx` — **`SECONDARY_PANELS`** map (`question-bank`, `list-hub`, …).
44
+ - `lib/list-hub-nav.ts` + `components/list-hub-secondary-nav.tsx` — second hub reference implementation.
41
45
  - `hooks/use-sidebar-reflow-zoom.ts` — shared zoom / reflow signal.
42
- - `components/templates/nested-secondary-panel-shell.tsx` — expanded vs `compact` (icon rail) widths.
46
+ - `components/templates/nested-secondary-panel-shell.tsx` — expanded vs `compact` (icon rail) widths; **`bg-[var(--secondary-panel-bg)]`**.
47
+ - `app/globals.css` — `--secondary-panel-bg`, `--sidebar`, product **`theme-one`** / **`theme-prism`** blocks.
48
+ - `contexts/product-context.tsx` — `accentOverrideActive`, theme class on `<html>`.
49
+ - **`docs/shell-surface-elevation-pattern.md`**
43
50
  - `components/question-bank-secondary-nav.tsx` + `lib/question-bank-nav.ts`.
44
51
  - **Folder-scoped header customize:** `components/question-bank-page-header.tsx`, `components/question-bank-client.tsx` — **`docs/question-bank-hub-header-pattern.md`**, **`.cursor/rules/exxat-question-bank-hub-header.mdc`**.
@@ -0,0 +1,39 @@
1
+ # Consumer app pattern (`@exxatdesignux/ui`)
2
+
3
+ > **Audience:** Product repos that **install** the design system from npm — not the `apps/web` monorepo reference app.
4
+ > **Handbook:** `packages/ui/consumer-extras/AGENTS.md` · **Upgrade:** `consumer-upgrade-checklist.md` · **Skill:** `.cursor/skills/exxat-consumer-app/SKILL.md`
5
+
6
+ ## Intent
7
+
8
+ A **consumer app** composes **`@exxatdesignux/ui`** primitives and copies **patterns** from the published **`template/`** tree. It does **not** fork parallel table stacks, view routers, or shell tokens.
9
+
10
+ ## MUST
11
+
12
+ 1. **Install** — `@exxatdesignux/ui` + peers; import DS CSS once (`@exxatdesignux/ui/globals.css` or documented entry).
13
+ 2. **Sync extras** — After version bumps: `npx --package=@exxatdesignux/ui@latest exxat-ui sync-extras` → `.cursor/skills/exxat-*` + `docs/exxat-ds/*.md`.
14
+ 3. **Diff template** — Compare `node_modules/@exxatdesignux/ui/template/` for new files (layouts, `ListPageConnectedViewBody`, `FocusedWorkflowPageTemplate`, mocks).
15
+ 4. **List hubs** — One **`useTableState`** row bag; **`ListPageConnectedViewBody`** + **`defineHubViewRenderers`**; same **`supportedViewTypes`** on **`ListPageTemplate`** and **`TablePropertiesDrawer`**.
16
+ 5. **Shell tokens** — Sidebar / secondary panel / page elevation via **`--sidebar`**, **`--secondary-panel-bg`**, **`--background`** — see **`shell-surface-elevation-pattern.md`**.
17
+ 6. **Focused workflows** — Dedicated create/edit/settings routes use **`FocusedWorkflowPageTemplate`** — **`focused-workflow-page-pattern.md`**.
18
+
19
+ ## MUST NOT
20
+
21
+ - Copy only components without porting **AGENTS**, **rules**, and **pattern docs** when behavior changes.
22
+ - Ship hub view tabs with long **`if (view === "table")`** chains instead of **`ListPageConnectedViewBody`**.
23
+ - Keep a second mock array per view while the grid uses **`useTableState`**.
24
+ - Set secondary panel to **`bg-sidebar`** or light **`--brand-tint`** mixes in dark mode.
25
+
26
+ ## Checklist (new consumer feature)
27
+
28
+ - [ ] Read **`consumer-upgrade-checklist.md`** for the installed UI version.
29
+ - [ ] Run **`exxat-ui sync-extras`** if skills/patterns are stale.
30
+ - [ ] Find the closest **`template/`** hub or page; port file names and imports to your app paths.
31
+ - [ ] **List hub:** `lib/<hub>-supported-views.ts`, `lib/data-list-view-registry.ts`, `ListPageConnectedViewBody`, centralized **`tableState.rows`**.
32
+ - [ ] **Form route:** `FocusedWorkflowPageTemplate` + one body layout from **`focused-workflow-layouts.tsx`**.
33
+ - [ ] **Nav + secondary panel:** `secondaryPanel` on nav item, `PANELS` registry, `useAutoPanel` — **`exxat-primary-nav-secondary-panel`** skill.
34
+ - [ ] Re-run **`fa:subset-audit`** when adding Font Awesome glyphs.
35
+
36
+ ## See also
37
+
38
+ - Monorepo reference: `apps/web/` (full product demo)
39
+ - **`.cursor/rules/exxat-consumer-app.mdc`** (when working inside a consumer repo that synced rules)
@@ -25,6 +25,26 @@ The npm package includes a full Next.js reference under:
25
25
 
26
26
  Use it when you need to know **what files exist**, **how shims re-export** `@exxatdesignux/ui`, or **what AGENTS / layout** patterns look like for the current release. Porting is manual: diff template vs your repo and apply intentional changes (imports, new components, CSS entrypoints).
27
27
 
28
+ ### List-page view registry (required for data hubs)
29
+
30
+ After upgrading, confirm each hub table uses **`ListPageConnectedViewBody`** (not long **`if (view === …)`** chains) and that these stay aligned:
31
+
32
+ | File | Purpose |
33
+ |------|---------|
34
+ | `lib/data-list-view-registry.ts` | Render kinds + hub KPI strip rules |
35
+ | `lib/<hub>-supported-views.ts` | What the hub can add/switch to |
36
+ | `components/templates/list-page.tsx` | `supportedViewTypes` on Add view + shortcuts |
37
+ | `components/data-views/list-page-connected-view-body.tsx` | View router |
38
+ | `lib/hub-connected-view-renderers.ts` | **`defineHubViewRenderers(supported, { … })`** — dev warnings when a supported view has no body |
39
+ | `components/data-views/list-page-folder-columns-panel.tsx` | Generic Miller columns for **panel** view (hub wrapper for QB colors/actions) |
40
+
41
+ Pass the **same** `supportedViewTypes` array to **`ListPageTemplate`** and **`TablePropertiesDrawerButton`**. Wrap hub renderers with **`defineHubViewRenderers`**. Import **question-bank-only** tree/folder nav from hub files, not the generic **`data-views`** barrel. See **`docs/exxat-ds/data-views-pattern.md`** § “View registry and connected bodies” and **`consumer-app-pattern.md`** for the full consumer-app checklist.
42
+
43
+ ### Shell + sidebar (after DS token changes)
44
+
45
+ - [ ] Dark mode **secondary panel** uses **`--secondary-panel-bg`** from DS globals (sidebar-accent mix) — spot-check Question bank **Library** rail.
46
+ - [ ] Collapsed **product switcher** — **`SidebarMenuButton` `tooltip=`** + **`DropdownMenuTrigger`** only (no outer **`Tooltip`** wrapping the trigger).
47
+
28
48
  ## 4. Dependency and Node
29
49
 
30
50
  - Keep **`@exxatdesignux/ui`** on the same semver your team tested; prefer explicit **`^x.y.z`** or pinned **`x.y.z`**.
@@ -18,6 +18,8 @@ This document describes how list pages combine **views**, **toolbar** behavior,
18
18
  | **Team page (primary template)** | `TeamClient` = `ListPageTemplate` + `KeyMetrics` + `TeamPageHeader` + `TeamTable` (same composition as `DataListClient`) | `components/team-client.tsx`, `lib/mock/team-kpi.ts` |
19
19
  | **Team roster** | `TeamTable` — `DataTable` + `useTableState` + `TablePropertiesDrawer`; list/board/dashboard read **`tableState.rows`** | `components/team-table.tsx` |
20
20
  | **Dashboard view (list tab)** | **`KeyMetrics`** (`variant="flat"` or `"card"`) — same KPI system as the template metrics strip; **do not** add ad-hoc `Card` grids for entity summaries | `TeamTable` dashboard branch, `lib/mock/team-kpi.ts` |
21
+ | **List hub metrics strip** | **`KeyMetrics variant="flat"`** — transparent cells, OKLCH brand glow only, border hairlines (**no** grey panel) | **`docs/kpi-flat-band-pattern.md`**, Placements / Team / Question bank clients |
22
+ | **Secondary panel chrome** | **`--secondary-panel-bg`** on **`NestedSecondaryPanelShell`** (lighter than sidebar, follows active product) | **`docs/shell-surface-elevation-pattern.md`**, Question bank |
21
23
  | **Export** | `ExportDrawer` | `ListPageTemplate` export props; `DataListClient` |
22
24
  | **View body layout** (gutter + centered max-width for folder / icon / panel-style content) | **`ListPageViewFrame`** (`components/data-views/list-page-view-frame.tsx`, re-exported from `components/data-views`) | **`FolderGridView`** (uses the frame); **`QuestionBankOsFolderView`** — see **`AGENTS.md` §4.5** |
23
25
 
@@ -36,6 +38,41 @@ Non-table view branches (e.g. **folder** icon grid, **panel** finder, OS-style f
36
38
 
37
39
  **Handbook:** **`AGENTS.md` §4.5**. **Cursor:** **`.cursor/rules/exxat-list-page-view-shells.mdc`**. **Skill:** **`.cursor/skills/exxat-list-page-view-shells/SKILL.md`**. **Do not** wrap **`DataTable`** in the frame if that stacks padding with the table toolbar (**`AGENTS.md` §5**).
38
40
 
41
+ ## View registry and connected bodies (extensibility)
42
+
43
+ To add a **new view type** without breaking existing hubs:
44
+
45
+ 1. **Register once** — Add a tile in `lib/data-list-view.ts` (`DATA_LIST_VIEW_TILES`). Capabilities (hub KPI strip, render kind) derive automatically in `lib/data-list-view-registry.ts`.
46
+ 2. **Build the body once** — Add or extend a generic surface under `components/data-views/` (e.g. `ListPageCalendarView`). Entity-specific wiring stays in props (`getEventDate`, board `renderCard`), not a second calendar implementation per hub.
47
+ 3. **Declare what each hub supports** — `lib/<hub>-supported-views.ts` exports a `const` array; pass the same array to **`ListPageTemplate`** (`supportedViewTypes`), the hub table (`supportedViewTypes` → `TablePropertiesDrawerButton`), and rely on defaults if omitted. **Add view**, **⌘1–9** shortcuts, and **Properties → View type** tiles all use `dataListViewTilesForHub` / `dataListViewSelectionTilesForHub` so users cannot pick a view the hub never implemented.
48
+ 4. **Route in the hub table with `ListPageConnectedViewBody`** — Switch on **`getDataListViewRenderKind(view)`**, not raw `view === "…"` chains. Pass one renderer per kind the hub supports via **`defineHubViewRenderers(MY_HUB_SUPPORTED_VIEWS, { … })`** (`lib/hub-connected-view-renderers.ts`) so dev builds warn when a supported view has no body. **Do not** use a default branch that renders dashboard/KPIs; missing renderers show `ListPageViewNotConfigured`.
49
+ 5. **Let the template own hub chrome** — `ListPageTemplate` hides the metrics strip on calendar/dashboard via `showsListPageHubMetricsStrip(activeTab.viewType)`. Hub clients pass `showMetrics` only; they do not reimplement per-tab KPI visibility.
50
+ 6. **Panel / Miller columns** — Reuse **`ListPageFolderColumnsPanel`** (`components/data-views/list-page-folder-columns-panel.tsx`) for folder + record columns; hub-specific chrome (folder colors, actions) lives in a thin wrapper (e.g. `QuestionBankFolderColumnsPanel`). **Do not** export question-bank-only tree/folder nav from the generic `data-views` barrel.
51
+
52
+ ```tsx
53
+ // lib/my-hub-supported-views.ts
54
+ export const MY_HUB_SUPPORTED_VIEWS = ["table", "list", "calendar"] as const satisfies readonly DataListViewType[]
55
+
56
+ // my-hub-client.tsx
57
+ <ListPageTemplate supportedViewTypes={MY_HUB_SUPPORTED_VIEWS} showMetrics={showMetrics} … />
58
+
59
+ // my-hub-table.tsx
60
+ import { defineHubViewRenderers } from "@/lib/hub-connected-view-renderers"
61
+
62
+ return (
63
+ <ListPageConnectedViewBody
64
+ view={view}
65
+ hubLabel="My hub"
66
+ renderers={defineHubViewRenderers(MY_HUB_SUPPORTED_VIEWS, {
67
+ "data-table": <DataTable … />,
68
+ "calendar-with-toolbar": toolbarShell(<ListPageCalendarView rows={tableState.rows} getEventDate={…} />),
69
+ })}
70
+ />
71
+ )
72
+ ```
73
+
74
+ **Checklist for a new view type:** registry tile → `data-views/` component → update each `*-supported-views.ts` that should expose it → add renderer in each `*-table.tsx` (via `defineHubViewRenderers`) → Properties drawer copy in `table-properties/drawer.tsx` if needed → `table-state-lifecycle` picks up types via `DATA_LIST_VIEW_TILES` (no separate allowlist).
75
+
39
76
  ## Architecture
40
77
 
41
78
  - **Page shell** — `ListPageTemplate` owns the views toolbar (tabs), optional metrics, and export drawer. Content for the active tab is rendered via `renderContent`.
@@ -144,11 +181,13 @@ Reference: `components/placements-page-header.tsx`, `components/team-page-header
144
181
 
145
182
  **When to use a new page (route):** The flow is **primary**, **long-form**, **multi-step**, or should have its **own URL** / bookmark / history **without** the parent page behind it — e.g. full create/edit, wizards, or detail that *is* the task.
146
183
 
147
- **Rule of thumb:** **Context + quick** **drawer**; **blocking short choice** **dialog**; **otherwise** **new page**.
184
+ **Focused workflow shell:** For dedicated create/edit, wizards, and sectioned settings, use **`FocusedWorkflowPageTemplate`** + layouts in **`focused-workflow-layouts.tsx`** see **`docs/focused-workflow-page-pattern.md`** and **`AGENTS.md` §14**. **Not** for list hubs (**`ListPageTemplate`**) or Miller-column explorers.
185
+
186
+ **Rule of thumb:** **Context + quick** → **drawer**; **blocking short choice** → **dialog**; **primary / long / wizard / settings** → **focused workflow route** (or other dedicated page).
148
187
 
149
188
  **Modal vs side panel (same route):** When the overlay stays on the same URL, prefer **`docs/drawer-vs-dialog-pattern.md`** and **`.cursor/rules/exxat-drawer-vs-dialog.mdc`** — drawers keep the hub visible; dialogs trap focus for confirms.
150
189
 
151
- Canonical rules: **`AGENTS.md` §6.4**, root **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**.
190
+ Canonical rules: **`AGENTS.md` §6.4**, **§14**, root **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**, **`.cursor/rules/exxat-focused-workflow-page.mdc`**.
152
191
 
153
192
  ---
154
193
 
@@ -168,7 +207,7 @@ When a route is a **primary** destination in nav (main hub for an entity) **and*
168
207
  - [ ] **>10 items** → search, filter, sort, properties (per surface type above).
169
208
  - [ ] **Has data to export** → **More** menu with **Export** + shared `ExportDrawer` pattern.
170
209
  - [ ] **Primary + large / main hub** → `ListPageTemplate`-style shell where applicable.
171
- - [ ] **Page vs drawer vs dialog (§6.4)** — Quick with parent **context** → drawer/sheet; **blocking** confirm → **dialog**; primary or long flows → **new route** (`docs/drawer-vs-dialog-pattern.md`).
210
+ - [ ] **Page vs drawer vs dialog (§6.4)** — Quick with parent **context** → drawer/sheet; **blocking** confirm → **dialog**; primary or long flows → **focused workflow route** (`docs/focused-workflow-page-pattern.md`, **§14**) or other dedicated page (`docs/drawer-vs-dialog-pattern.md`).
172
211
  - [ ] **Primary button** → `Button` default variant (`size="lg"` for parity with Placements), not outline.
173
212
  - [ ] **Dashboard view tab** → `KeyMetrics` + shared KPI helpers from **`tableState.rows`**; no duplicate one-off metric cards.
174
213
  - [ ] **Data view charts** → `ChartFigure` + `chart-keyboard-selection`; layout persistence via **`data-view-dashboard-storage`** (see `AGENTS.md` §4.3).