@exxatdesignux/ui 0.5.11 → 0.5.13

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 (477) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/bin/cli.mjs +70 -1
  3. package/bin/init.mjs +18 -4
  4. package/bin/sync-extras.mjs +28 -4
  5. package/consumer-extras/README.md +41 -5
  6. package/consumer-extras/cursor-rules/exxat-accessibility.mdc +2 -1
  7. package/consumer-extras/cursor-rules/exxat-board-cards.mdc +5 -3
  8. package/consumer-extras/cursor-rules/exxat-breadcrumbs-no-back.mdc +1 -0
  9. package/consumer-extras/cursor-rules/exxat-card-vs-list-rows.mdc +1 -0
  10. package/consumer-extras/cursor-rules/exxat-centralized-list-dataset.mdc +4 -2
  11. package/consumer-extras/cursor-rules/exxat-collaboration-access.mdc +1 -0
  12. package/consumer-extras/cursor-rules/exxat-command-menu.mdc +3 -2
  13. package/consumer-extras/cursor-rules/exxat-data-tables.mdc +5 -3
  14. package/consumer-extras/cursor-rules/exxat-dedicated-search-surfaces.mdc +7 -0
  15. package/consumer-extras/cursor-rules/exxat-drawer-vs-dialog.mdc +2 -1
  16. package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +1 -0
  17. package/consumer-extras/cursor-rules/exxat-fontawesome-icons.mdc +1 -0
  18. package/consumer-extras/cursor-rules/exxat-hub-supported-views.mdc +6 -4
  19. package/consumer-extras/cursor-rules/exxat-kbd-shortcuts.mdc +6 -5
  20. package/consumer-extras/cursor-rules/exxat-kpi-flat-band.mdc +1 -0
  21. package/consumer-extras/cursor-rules/exxat-kpi-max-four.mdc +1 -0
  22. package/consumer-extras/cursor-rules/exxat-kpi-trends.mdc +1 -0
  23. package/consumer-extras/cursor-rules/exxat-library-hub-header.mdc +2 -1
  24. package/consumer-extras/cursor-rules/exxat-list-page-connected-views.mdc +6 -2
  25. package/consumer-extras/cursor-rules/exxat-list-page-view-shells.mdc +2 -1
  26. package/consumer-extras/cursor-rules/exxat-mono-ids.mdc +2 -1
  27. package/consumer-extras/cursor-rules/exxat-nav-single-active.mdc +4 -3
  28. package/consumer-extras/cursor-rules/exxat-no-image-pixel-copy.mdc +25 -14
  29. package/consumer-extras/cursor-rules/exxat-no-slds-leakage.mdc +8 -2
  30. package/consumer-extras/cursor-rules/exxat-no-toast.mdc +1 -0
  31. package/consumer-extras/cursor-rules/exxat-no-vaul.mdc +2 -1
  32. package/consumer-extras/cursor-rules/exxat-page-header-actions.mdc +6 -4
  33. package/consumer-extras/cursor-rules/exxat-page-vs-drawer.mdc +2 -1
  34. package/consumer-extras/cursor-rules/exxat-person-identity-display.mdc +1 -0
  35. package/consumer-extras/cursor-rules/exxat-primary-nav-secondary-panel.mdc +2 -1
  36. package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +1 -0
  37. package/consumer-extras/cursor-rules/exxat-sidebar-shell.mdc +13 -7
  38. package/consumer-extras/cursor-rules/exxat-table-properties-drawer.mdc +5 -3
  39. package/consumer-extras/cursor-rules/exxat-table-row-preview.mdc +1 -0
  40. package/consumer-extras/cursor-rules/exxat-tabs-chrome.mdc +6 -4
  41. package/consumer-extras/cursor-rules/exxat-token-discipline.mdc +6 -0
  42. package/consumer-extras/cursor-rules/exxat-ux-discovery-protocol.mdc +28 -0
  43. package/consumer-extras/cursor-rules/exxat-ux-principles.mdc +1 -0
  44. package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +1 -1
  45. package/consumer-extras/cursor-skills/exxat-kpi-trends/SKILL.md +5 -3
  46. package/consumer-extras/patterns/command-menu-pattern.md +2 -2
  47. package/consumer-extras/patterns/consumer-upgrade-checklist.md +1 -1
  48. package/consumer-extras/patterns/jobs/README.md +1 -1
  49. package/consumer-extras/patterns/perf-memory-pattern.md +115 -150
  50. package/consumer-extras/scripts/dev-guard.mjs +156 -0
  51. package/consumer-extras/templates/README.md +23 -0
  52. package/consumer-extras/templates/handoff.md +190 -0
  53. package/package.json +2 -3
  54. package/{template → template-vite}/.claude/skills/exxat-ds-skill/SKILL.md +184 -23
  55. package/template-vite/.cursor/rules/exxat-accessibility.mdc +40 -0
  56. package/template-vite/.cursor/rules/exxat-board-cards.mdc +28 -0
  57. package/template-vite/.cursor/rules/exxat-breadcrumbs-no-back.mdc +22 -0
  58. package/template-vite/.cursor/rules/exxat-card-vs-list-rows.mdc +22 -0
  59. package/template-vite/.cursor/rules/exxat-centralized-list-dataset.mdc +46 -0
  60. package/template-vite/.cursor/rules/exxat-collaboration-access.mdc +33 -0
  61. package/{template → template-vite}/.cursor/rules/exxat-command-menu.mdc +5 -5
  62. package/template-vite/.cursor/rules/exxat-data-tables.mdc +47 -0
  63. package/template-vite/.cursor/rules/exxat-dedicated-search-surfaces.mdc +32 -0
  64. package/template-vite/.cursor/rules/exxat-drawer-vs-dialog.mdc +23 -0
  65. package/template-vite/.cursor/rules/exxat-ds-agents.mdc +87 -0
  66. package/template-vite/.cursor/rules/exxat-fontawesome-icons.mdc +32 -0
  67. package/template-vite/.cursor/rules/exxat-hub-supported-views.mdc +56 -0
  68. package/{template → template-vite}/.cursor/rules/exxat-kbd-shortcuts.mdc +1 -0
  69. package/template-vite/.cursor/rules/exxat-kpi-flat-band.mdc +29 -0
  70. package/template-vite/.cursor/rules/exxat-kpi-max-four.mdc +22 -0
  71. package/template-vite/.cursor/rules/exxat-kpi-trends.mdc +32 -0
  72. package/template-vite/.cursor/rules/exxat-library-hub-header.mdc +29 -0
  73. package/template-vite/.cursor/rules/exxat-list-page-connected-views.mdc +28 -0
  74. package/template-vite/.cursor/rules/exxat-list-page-view-shells.mdc +32 -0
  75. package/{template → template-vite}/.cursor/rules/exxat-mono-ids.mdc +1 -0
  76. package/template-vite/.cursor/rules/exxat-nav-single-active.mdc +32 -0
  77. package/template-vite/.cursor/rules/exxat-no-image-pixel-copy.mdc +46 -0
  78. package/template-vite/.cursor/rules/exxat-no-slds-leakage.mdc +84 -0
  79. package/{template → template-vite}/.cursor/rules/exxat-no-toast.mdc +2 -2
  80. package/template-vite/.cursor/rules/exxat-no-vaul.mdc +26 -0
  81. package/template-vite/.cursor/rules/exxat-page-header-actions.mdc +33 -0
  82. package/{template → template-vite}/.cursor/rules/exxat-page-vs-drawer.mdc +5 -3
  83. package/template-vite/.cursor/rules/exxat-person-identity-display.mdc +48 -0
  84. package/template-vite/.cursor/rules/exxat-primary-nav-secondary-panel.mdc +53 -0
  85. package/template-vite/.cursor/rules/exxat-reuse-before-custom.mdc +37 -0
  86. package/template-vite/.cursor/rules/exxat-sidebar-shell.mdc +41 -0
  87. package/template-vite/.cursor/rules/exxat-table-properties-drawer.mdc +79 -0
  88. package/template-vite/.cursor/rules/exxat-table-row-preview.mdc +25 -0
  89. package/template-vite/.cursor/rules/exxat-tabs-chrome.mdc +33 -0
  90. package/template-vite/.cursor/rules/exxat-token-discipline.mdc +109 -0
  91. package/template-vite/.cursor/rules/exxat-ux-discovery-protocol.mdc +202 -0
  92. package/template-vite/.cursor/rules/exxat-ux-principles.mdc +187 -0
  93. package/template-vite/.cursor/skills/exxat-accessibility/SKILL.md +282 -0
  94. package/template-vite/.cursor/skills/exxat-board-cards/SKILL.md +68 -0
  95. package/template-vite/.cursor/skills/exxat-card-vs-list-rows/SKILL.md +20 -0
  96. package/template-vite/.cursor/skills/exxat-centralized-list-dataset/SKILL.md +99 -0
  97. package/template-vite/.cursor/skills/exxat-collaboration-access/SKILL.md +35 -0
  98. package/template-vite/.cursor/skills/exxat-dedicated-search-surfaces/SKILL.md +45 -0
  99. package/template-vite/.cursor/skills/exxat-drawer-vs-dialog/SKILL.md +20 -0
  100. package/template-vite/.cursor/skills/exxat-ds-skill/SKILL.md +893 -0
  101. package/template-vite/.cursor/skills/exxat-ds-skill/references/accessibility.md +142 -0
  102. package/template-vite/.cursor/skills/exxat-ds-skill/references/coach-marks.md +169 -0
  103. package/template-vite/.cursor/skills/exxat-ds-skill/references/data-table-pattern.md +392 -0
  104. package/template-vite/.cursor/skills/exxat-fontawesome-icons/SKILL.md +31 -0
  105. package/template-vite/.cursor/skills/exxat-kpi-flat-band/SKILL.md +38 -0
  106. package/template-vite/.cursor/skills/exxat-kpi-max-four/SKILL.md +19 -0
  107. package/template-vite/.cursor/skills/exxat-kpi-trends/SKILL.md +29 -0
  108. package/template-vite/.cursor/skills/exxat-list-page-view-shells/SKILL.md +36 -0
  109. package/template-vite/.cursor/skills/exxat-mono-ids/SKILL.md +56 -0
  110. package/template-vite/.cursor/skills/exxat-primary-nav-secondary-panel/SKILL.md +49 -0
  111. package/template-vite/.cursor/skills/exxat-senior-ux/SKILL.md +198 -0
  112. package/template-vite/.cursor/skills/exxat-token-economy/SKILL.md +287 -0
  113. package/template-vite/.cursor/skills/exxat-ux-audit/SKILL.md +303 -0
  114. package/{template → template-vite}/components/ask-leo-sidebar.tsx +10 -8
  115. package/{template → template-vite}/components/command-menu.tsx +1 -1
  116. package/{template → template-vite}/components/data-views/library-folder-tree-branch.tsx +1 -1
  117. package/{template → template-vite}/components/dedicated-search-recents.tsx +1 -1
  118. package/{template → template-vite}/components/dedicated-search-url-composer.tsx +1 -1
  119. package/{template → template-vite}/components/exxat-product-logo.tsx +3 -3
  120. package/{template → template-vite}/components/library-client.tsx +1 -1
  121. package/{template → template-vite}/components/library-hub-client.tsx +2 -2
  122. package/{template → template-vite}/components/library-secondary-nav.tsx +2 -2
  123. package/{template → template-vite}/components/library-table.tsx +35 -27
  124. package/{template → template-vite}/components/new-library-item-form.tsx +1 -1
  125. package/{template → template-vite}/components/page-breadcrumb-trail.tsx +1 -1
  126. package/{template → template-vite}/components/settings-client.tsx +1 -1
  127. package/{template → template-vite}/components/sidebar/app-sidebar.tsx +2 -2
  128. package/{template → template-vite}/components/sidebar/nav-main.tsx +1 -1
  129. package/{template → template-vite}/components/sidebar/nav-user.tsx +1 -1
  130. package/{template → template-vite}/components/sidebar/secondary-nav.tsx +1 -1
  131. package/{template → template-vite}/components/system-banner-slot.tsx +1 -1
  132. package/{template → template-vite}/components/templates/discovery-hub-template.tsx +2 -2
  133. package/{template → template-vite}/components/templates/new-focus-template.tsx +1 -1
  134. package/{template → template-vite}/components/tokens-secondary-nav.tsx +2 -2
  135. package/{template → template-vite}/components/tokens-themes-client.tsx +1 -1
  136. package/{template → template-vite}/hooks/use-secondary-panel-hub-nav.ts +1 -1
  137. package/template-vite/index.html +49 -0
  138. package/template-vite/lib/next-compat.tsx +98 -0
  139. package/{template → template-vite}/package.json +15 -27
  140. package/template-vite/scripts/port-next-imports.mjs +70 -0
  141. package/template-vite/src/App.tsx +103 -0
  142. package/template-vite/src/main.tsx +50 -0
  143. package/{template/app/(app)/error.tsx → template-vite/src/pages/_error.tsx} +12 -24
  144. package/{template/app/(app)/loading.tsx → template-vite/src/pages/_loading.tsx} +4 -2
  145. package/template-vite/src/pages/_not-found.tsx +17 -0
  146. package/template-vite/src/pages/dashboard.tsx +48 -0
  147. package/{template/app/(app)/help/page.tsx → template-vite/src/pages/help.tsx} +3 -2
  148. package/{template/app/(app)/library/layout.tsx → template-vite/src/pages/library/_layout.tsx} +18 -16
  149. package/{template/app/(app)/library/all/page.tsx → template-vite/src/pages/library/all.tsx} +1 -1
  150. package/{template/app/(app)/library/new/page.tsx → template-vite/src/pages/library/new.tsx} +12 -18
  151. package/template-vite/src/routes.tsx +72 -0
  152. package/template-vite/src/styles/globals.css +25 -0
  153. package/{template → template-vite}/tsconfig.json +5 -14
  154. package/template-vite/vite.config.ts +52 -0
  155. package/consumer-extras/cursor-rules/exxat-dashboard-view-charts.mdc +0 -53
  156. package/template/.agents/skills/shadcn/SKILL.md +0 -242
  157. package/template/.agents/skills/shadcn/agents/openai.yml +0 -5
  158. package/template/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
  159. package/template/.agents/skills/shadcn/assets/shadcn.png +0 -0
  160. package/template/.agents/skills/shadcn/cli.md +0 -257
  161. package/template/.agents/skills/shadcn/customization.md +0 -202
  162. package/template/.agents/skills/shadcn/evals/evals.json +0 -47
  163. package/template/.agents/skills/shadcn/mcp.md +0 -94
  164. package/template/.agents/skills/shadcn/rules/base-vs-radix.md +0 -306
  165. package/template/.agents/skills/shadcn/rules/composition.md +0 -195
  166. package/template/.agents/skills/shadcn/rules/forms.md +0 -192
  167. package/template/.agents/skills/shadcn/rules/icons.md +0 -101
  168. package/template/.agents/skills/shadcn/rules/styling.md +0 -162
  169. package/template/.cursor/rules/exxat-accessibility.mdc +0 -33
  170. package/template/.cursor/rules/exxat-data-tables.mdc +0 -32
  171. package/template/.cursor/rules/exxat-ds-agents.mdc +0 -26
  172. package/template/.cursor/rules/exxat-list-page-connected-views.mdc +0 -16
  173. package/template/.cursor/rules/exxat-table-properties-drawer.mdc +0 -40
  174. package/template/.nvmrc +0 -1
  175. package/template/.prettierignore +0 -7
  176. package/template/Logo/Exxat_Prism.svg +0 -39
  177. package/template/Logo/Exxat_one.svg +0 -36
  178. package/template/app/(app)/dashboard/loading.tsx +0 -18
  179. package/template/app/(app)/dashboard/page.tsx +0 -36
  180. package/template/app/(app)/layout.tsx +0 -77
  181. package/template/app/global-error.tsx +0 -63
  182. package/template/app/globals.css +0 -20
  183. package/template/app/layout.tsx +0 -133
  184. package/template/app/page.tsx +0 -9
  185. package/template/docs/HANDBOOK.md +0 -187
  186. package/template/docs/blueprints/README.md +0 -86
  187. package/template/docs/blueprints/_template.md +0 -91
  188. package/template/docs/blueprints/board-card.md +0 -123
  189. package/template/docs/blueprints/data-table.md +0 -139
  190. package/template/docs/blueprints/key-metrics.md +0 -128
  191. package/template/docs/blueprints/list-page-template.md +0 -123
  192. package/template/docs/blueprints/page-header.md +0 -130
  193. package/template/docs/card-vs-rows-pattern.md +0 -36
  194. package/template/docs/collaboration-access-pattern.md +0 -116
  195. package/template/docs/command-menu-pattern.md +0 -45
  196. package/template/docs/component-selection-guide.md +0 -224
  197. package/template/docs/components-audit-2026-05.md +0 -158
  198. package/template/docs/consumer-upgrade-checklist.md +0 -52
  199. package/template/docs/data-views-pattern.md +0 -185
  200. package/template/docs/drawer-vs-dialog-pattern.md +0 -50
  201. package/template/docs/glossary.md +0 -59
  202. package/template/docs/hub-supported-views-pattern.md +0 -53
  203. package/template/docs/jobs/README.md +0 -59
  204. package/template/docs/jobs/record-detail.md +0 -177
  205. package/template/docs/kpi-flat-band-pattern.md +0 -57
  206. package/template/docs/kpi-strip-max-four-pattern.md +0 -30
  207. package/template/docs/kpi-trend-pattern.md +0 -58
  208. package/template/docs/large-dataset-strategy.md +0 -155
  209. package/template/docs/library-hub-header-pattern.md +0 -25
  210. package/template/docs/migrations/0001-brand-deep-alias-stabilization.md +0 -95
  211. package/template/docs/migrations/0002-exxat-token-namespace.md +0 -154
  212. package/template/docs/migrations/0003-globals-css-canonical.md +0 -110
  213. package/template/docs/migrations/README.md +0 -100
  214. package/template/docs/migrations/_template.md +0 -64
  215. package/template/docs/modern-saas-patterns.md +0 -165
  216. package/template/docs/perf-memory-pattern.md +0 -206
  217. package/template/docs/reference-implementations.md +0 -153
  218. package/template/docs/shell-surface-elevation-pattern.md +0 -52
  219. package/template/docs/token-taxonomy.md +0 -416
  220. package/template/docs/voice-and-tone.md +0 -262
  221. package/template/ecosystem.config.cjs +0 -32
  222. package/template/next.config.mjs +0 -216
  223. package/template/postcss.config.mjs +0 -8
  224. package/template/public/favicon/favicon.ico +0 -0
  225. package/template/tests/setup.ts +0 -26
  226. package/template/vitest.config.ts +0 -18
  227. /package/{template → template-vite}/.cursor/rules/exxat-dashboard-view-charts.mdc +0 -0
  228. /package/{template → template-vite}/.prettierrc +0 -0
  229. /package/{template → template-vite}/AGENTS.md +0 -0
  230. /package/{template → template-vite}/README.md +0 -0
  231. /package/{template → template-vite}/components/.gitkeep +0 -0
  232. /package/{template → template-vite}/components/ask-leo-composer.tsx +0 -0
  233. /package/{template → template-vite}/components/brand-color-picker.tsx +0 -0
  234. /package/{template → template-vite}/components/chart-area-interactive.tsx +0 -0
  235. /package/{template → template-vite}/components/charts-overview.tsx +0 -0
  236. /package/{template → template-vite}/components/collaboration-access-flow.tsx +0 -0
  237. /package/{template → template-vite}/components/columns-client.tsx +0 -0
  238. /package/{template → template-vite}/components/columns-showcase.tsx +0 -0
  239. /package/{template → template-vite}/components/dashboard-promo-banner.tsx +0 -0
  240. /package/{template → template-vite}/components/dashboard-quota-progress-card.tsx +0 -0
  241. /package/{template → template-vite}/components/dashboard-report-charts.tsx +0 -0
  242. /package/{template → template-vite}/components/dashboard-section-heading.tsx +0 -0
  243. /package/{template → template-vite}/components/dashboard-tabs.tsx +0 -0
  244. /package/{template → template-vite}/components/data-table/filter-date-calendar.tsx +0 -0
  245. /package/{template → template-vite}/components/data-table/filter-text-value-input.tsx +0 -0
  246. /package/{template → template-vite}/components/data-table/index.tsx +0 -0
  247. /package/{template → template-vite}/components/data-table/pagination.tsx +0 -0
  248. /package/{template → template-vite}/components/data-table/types.ts +0 -0
  249. /package/{template → template-vite}/components/data-table/use-table-state.test.ts +0 -0
  250. /package/{template → template-vite}/components/data-table/use-table-state.ts +0 -0
  251. /package/{template → template-vite}/components/data-views/board-card-primitives.tsx +0 -0
  252. /package/{template → template-vite}/components/data-views/data-row-list.tsx +0 -0
  253. /package/{template → template-vite}/components/data-views/finder-panel-view.tsx +0 -0
  254. /package/{template → template-vite}/components/data-views/folder-grid-view.tsx +0 -0
  255. /package/{template → template-vite}/components/data-views/hub-table.tsx +0 -0
  256. /package/{template → template-vite}/components/data-views/index.ts +0 -0
  257. /package/{template → template-vite}/components/data-views/list-page-board-card.tsx +0 -0
  258. /package/{template → template-vite}/components/data-views/list-page-board-template.tsx +0 -0
  259. /package/{template → template-vite}/components/data-views/list-page-connected-view-body.tsx +0 -0
  260. /package/{template → template-vite}/components/data-views/list-page-split-details-placeholder.tsx +0 -0
  261. /package/{template → template-vite}/components/data-views/list-page-split-hub-chrome.tsx +0 -0
  262. /package/{template → template-vite}/components/data-views/list-page-split-hub-tokens.ts +0 -0
  263. /package/{template → template-vite}/components/data-views/list-page-tree-column-header.tsx +0 -0
  264. /package/{template → template-vite}/components/data-views/list-page-tree-panel-shell.tsx +0 -0
  265. /package/{template → template-vite}/components/data-views/list-page-view-frame.tsx +0 -0
  266. /package/{template → template-vite}/components/data-views/os-folder-glyph.tsx +0 -0
  267. /package/{template → template-vite}/components/data-views/outline-tree-menu.tsx +0 -0
  268. /package/{template → template-vite}/components/data-views/table-cells.tsx +0 -0
  269. /package/{template → template-vite}/components/dev-chunk-load-recovery.tsx +0 -0
  270. /package/{template → template-vite}/components/export-drawer.test.tsx +0 -0
  271. /package/{template → template-vite}/components/export-drawer.tsx +0 -0
  272. /package/{template → template-vite}/components/folder-details-shell.tsx +0 -0
  273. /package/{template → template-vite}/components/form-layout-01.tsx +0 -0
  274. /package/{template → template-vite}/components/hub-tree-panel-view.tsx +0 -0
  275. /package/{template → template-vite}/components/invite-collaborators-drawer.tsx +0 -0
  276. /package/{template → template-vite}/components/key-metrics-ask-leo-bridge.tsx +0 -0
  277. /package/{template → template-vite}/components/key-metrics.tsx +0 -0
  278. /package/{template → template-vite}/components/leo-insight-indicator.tsx +0 -0
  279. /package/{template → template-vite}/components/leo-typing-dots.tsx +0 -0
  280. /package/{template → template-vite}/components/library-board-view.tsx +0 -0
  281. /package/{template → template-vite}/components/library-dashboard-charts.tsx +0 -0
  282. /package/{template → template-vite}/components/library-favorite-button.tsx +0 -0
  283. /package/{template → template-vite}/components/library-new-folder-sheet.tsx +0 -0
  284. /package/{template → template-vite}/components/library-os-folder-view.tsx +0 -0
  285. /package/{template → template-vite}/components/library-page-header.tsx +0 -0
  286. /package/{template → template-vite}/components/library-panel-activator.tsx +0 -0
  287. /package/{template → template-vite}/components/list-hub-status-badge.tsx +0 -0
  288. /package/{template → template-vite}/components/list-page-dashboard-charts.tsx +0 -0
  289. /package/{template → template-vite}/components/onboarding/getting-started.tsx +0 -0
  290. /package/{template → template-vite}/components/onboarding/index.ts +0 -0
  291. /package/{template → template-vite}/components/onboarding/onboarding-01.tsx +0 -0
  292. /package/{template → template-vite}/components/onboarding/onboarding-02.tsx +0 -0
  293. /package/{template → template-vite}/components/onboarding/onboarding-03.tsx +0 -0
  294. /package/{template → template-vite}/components/onboarding/onboarding-04.tsx +0 -0
  295. /package/{template → template-vite}/components/page-header.tsx +0 -0
  296. /package/{template → template-vite}/components/product-switcher.tsx +0 -0
  297. /package/{template → template-vite}/components/product-wordmark.tsx +0 -0
  298. /package/{template → template-vite}/components/settings-appearance-card.tsx +0 -0
  299. /package/{template → template-vite}/components/settings-form-row.tsx +0 -0
  300. /package/{template → template-vite}/components/sidebar/app-sidebar-dynamic.tsx +0 -0
  301. /package/{template → template-vite}/components/sidebar/index.ts +0 -0
  302. /package/{template → template-vite}/components/sidebar/nav-documents.tsx +0 -0
  303. /package/{template → template-vite}/components/sidebar/nav-secondary.tsx +0 -0
  304. /package/{template → template-vite}/components/sidebar/secondary-panel.tsx +0 -0
  305. /package/{template → template-vite}/components/sidebar/sidebar-auto-collapse.tsx +0 -0
  306. /package/{template → template-vite}/components/sidebar/sidebar-auto-open.tsx +0 -0
  307. /package/{template → template-vite}/components/sidebar/sidebar-shell.tsx +0 -0
  308. /package/{template → template-vite}/components/site-header.tsx +0 -0
  309. /package/{template → template-vite}/components/table-properties/column-row.tsx +0 -0
  310. /package/{template → template-vite}/components/table-properties/draggable-list.ts +0 -0
  311. /package/{template → template-vite}/components/table-properties/drawer-button.tsx +0 -0
  312. /package/{template → template-vite}/components/table-properties/drawer.tsx +0 -0
  313. /package/{template → template-vite}/components/table-properties/filter-card.tsx +0 -0
  314. /package/{template → template-vite}/components/table-properties/index.ts +0 -0
  315. /package/{template → template-vite}/components/table-properties/sort-card.tsx +0 -0
  316. /package/{template → template-vite}/components/table-properties/types.ts +0 -0
  317. /package/{template → template-vite}/components/task-list-panel.tsx +0 -0
  318. /package/{template → template-vite}/components/task-priority-badge.tsx +0 -0
  319. /package/{template → template-vite}/components/templates/dedicated-search-landing-template.tsx +0 -0
  320. /package/{template → template-vite}/components/templates/dedicated-search-results-template.tsx +0 -0
  321. /package/{template → template-vite}/components/templates/list-page.tsx +0 -0
  322. /package/{template → template-vite}/components/templates/nested-secondary-panel-shell.tsx +0 -0
  323. /package/{template → template-vite}/components/templates/primary-page-template.tsx +0 -0
  324. /package/{template → template-vite}/components/templates/secondary-panel-hub-template.tsx +0 -0
  325. /package/{template → template-vite}/components/theme-color-sync.tsx +0 -0
  326. /package/{template → template-vite}/components/theme-provider.tsx +0 -0
  327. /package/{template → template-vite}/components/tinted-icon-disc.tsx +0 -0
  328. /package/{template → template-vite}/components/tokens-hub-auxiliary-views.tsx +0 -0
  329. /package/{template → template-vite}/components/tokens-themes-section.tsx +0 -0
  330. /package/{template → template-vite}/components/ui/accordion.tsx +0 -0
  331. /package/{template → template-vite}/components/ui/ai-thinking-surface.tsx +0 -0
  332. /package/{template → template-vite}/components/ui/alert-dialog.tsx +0 -0
  333. /package/{template → template-vite}/components/ui/avatar.tsx +0 -0
  334. /package/{template → template-vite}/components/ui/badge.tsx +0 -0
  335. /package/{template → template-vite}/components/ui/banner.tsx +0 -0
  336. /package/{template → template-vite}/components/ui/breadcrumb.tsx +0 -0
  337. /package/{template → template-vite}/components/ui/button.tsx +0 -0
  338. /package/{template → template-vite}/components/ui/calendar.tsx +0 -0
  339. /package/{template → template-vite}/components/ui/card.tsx +0 -0
  340. /package/{template → template-vite}/components/ui/chart.tsx +0 -0
  341. /package/{template → template-vite}/components/ui/checkbox.tsx +0 -0
  342. /package/{template → template-vite}/components/ui/coach-mark.tsx +0 -0
  343. /package/{template → template-vite}/components/ui/collapsible.tsx +0 -0
  344. /package/{template → template-vite}/components/ui/command.tsx +0 -0
  345. /package/{template → template-vite}/components/ui/context-menu.tsx +0 -0
  346. /package/{template → template-vite}/components/ui/date-picker-field.tsx +0 -0
  347. /package/{template → template-vite}/components/ui/dialog.tsx +0 -0
  348. /package/{template → template-vite}/components/ui/dot-pattern.tsx +0 -0
  349. /package/{template → template-vite}/components/ui/drag-handle-grip.tsx +0 -0
  350. /package/{template → template-vite}/components/ui/dropdown-menu.tsx +0 -0
  351. /package/{template → template-vite}/components/ui/field.tsx +0 -0
  352. /package/{template → template-vite}/components/ui/form.tsx +0 -0
  353. /package/{template → template-vite}/components/ui/hover-card.tsx +0 -0
  354. /package/{template → template-vite}/components/ui/input-group.tsx +0 -0
  355. /package/{template → template-vite}/components/ui/input-mask.tsx +0 -0
  356. /package/{template → template-vite}/components/ui/input.tsx +0 -0
  357. /package/{template → template-vite}/components/ui/kbd.tsx +0 -0
  358. /package/{template → template-vite}/components/ui/label.tsx +0 -0
  359. /package/{template → template-vite}/components/ui/leo-icon.tsx +0 -0
  360. /package/{template → template-vite}/components/ui/payment-card-fields.tsx +0 -0
  361. /package/{template → template-vite}/components/ui/popover.tsx +0 -0
  362. /package/{template → template-vite}/components/ui/radio-group.tsx +0 -0
  363. /package/{template → template-vite}/components/ui/resizable.tsx +0 -0
  364. /package/{template → template-vite}/components/ui/scroll-area.tsx +0 -0
  365. /package/{template → template-vite}/components/ui/select.tsx +0 -0
  366. /package/{template → template-vite}/components/ui/selection-tile-grid.tsx +0 -0
  367. /package/{template → template-vite}/components/ui/separator.tsx +0 -0
  368. /package/{template → template-vite}/components/ui/sheet.tsx +0 -0
  369. /package/{template → template-vite}/components/ui/sidebar.tsx +0 -0
  370. /package/{template → template-vite}/components/ui/skeleton.tsx +0 -0
  371. /package/{template → template-vite}/components/ui/slider.tsx +0 -0
  372. /package/{template → template-vite}/components/ui/sonner.tsx +0 -0
  373. /package/{template → template-vite}/components/ui/status-badge.tsx +0 -0
  374. /package/{template → template-vite}/components/ui/table.tsx +0 -0
  375. /package/{template → template-vite}/components/ui/tabs.tsx +0 -0
  376. /package/{template → template-vite}/components/ui/textarea.tsx +0 -0
  377. /package/{template → template-vite}/components/ui/tip.tsx +0 -0
  378. /package/{template → template-vite}/components/ui/toggle-group.tsx +0 -0
  379. /package/{template → template-vite}/components/ui/toggle-switch.tsx +0 -0
  380. /package/{template → template-vite}/components/ui/toggle.tsx +0 -0
  381. /package/{template → template-vite}/components/ui/tooltip.tsx +0 -0
  382. /package/{template → template-vite}/components/ui/view-segmented-control.tsx +0 -0
  383. /package/{template → template-vite}/components.json +0 -0
  384. /package/{template → template-vite}/contexts/chart-variant-context.tsx +0 -0
  385. /package/{template → template-vite}/contexts/command-menu-context.tsx +0 -0
  386. /package/{template → template-vite}/contexts/dashboard-view-context.tsx +0 -0
  387. /package/{template → template-vite}/contexts/product-context.tsx +0 -0
  388. /package/{template → template-vite}/contexts/system-banner-context.tsx +0 -0
  389. /package/{template → template-vite}/eslint.config.mjs +0 -0
  390. /package/{template → template-vite}/fontawesome-subset.manifest.json +0 -0
  391. /package/{template → template-vite}/hooks/.gitkeep +0 -0
  392. /package/{template → template-vite}/hooks/use-app-theme.ts +0 -0
  393. /package/{template → template-vite}/hooks/use-coach-mark.ts +0 -0
  394. /package/{template → template-vite}/hooks/use-location-hash.ts +0 -0
  395. /package/{template → template-vite}/hooks/use-mobile.ts +0 -0
  396. /package/{template → template-vite}/hooks/use-mod-key-label.ts +0 -0
  397. /package/{template → template-vite}/hooks/use-sidebar-reflow-zoom.ts +0 -0
  398. /package/{template → template-vite}/lib/.gitkeep +0 -0
  399. /package/{template → template-vite}/lib/ask-leo-route-context.ts +0 -0
  400. /package/{template → template-vite}/lib/chart-keyboard-selection.test.ts +0 -0
  401. /package/{template → template-vite}/lib/chart-keyboard-selection.ts +0 -0
  402. /package/{template → template-vite}/lib/chart-line-dash.ts +0 -0
  403. /package/{template → template-vite}/lib/chunk-load-error.ts +0 -0
  404. /package/{template → template-vite}/lib/coach-mark-registry.ts +0 -0
  405. /package/{template → template-vite}/lib/collaborator-access.ts +0 -0
  406. /package/{template → template-vite}/lib/command-menu-config.ts +0 -0
  407. /package/{template → template-vite}/lib/command-menu-search-data.ts +0 -0
  408. /package/{template → template-vite}/lib/conditional-rule-match.ts +0 -0
  409. /package/{template → template-vite}/lib/dashboard-customize-coach-mark.ts +0 -0
  410. /package/{template → template-vite}/lib/dashboard-layout-merge.ts +0 -0
  411. /package/{template → template-vite}/lib/data-list-display-options.ts +0 -0
  412. /package/{template → template-vite}/lib/data-list-persistence.ts +0 -0
  413. /package/{template → template-vite}/lib/data-list-view-registry.ts +0 -0
  414. /package/{template → template-vite}/lib/data-list-view-surface.ts +0 -0
  415. /package/{template → template-vite}/lib/data-list-view.ts +0 -0
  416. /package/{template → template-vite}/lib/data-view-dashboard-storage.ts +0 -0
  417. /package/{template → template-vite}/lib/date-filter.ts +0 -0
  418. /package/{template → template-vite}/lib/dedicated-search-recents.ts +0 -0
  419. /package/{template → template-vite}/lib/dedicated-search-url.ts +0 -0
  420. /package/{template → template-vite}/lib/dev-log.test.ts +0 -0
  421. /package/{template → template-vite}/lib/dev-log.ts +0 -0
  422. /package/{template → template-vite}/lib/discovery-hub.ts +0 -0
  423. /package/{template → template-vite}/lib/editable-target.ts +0 -0
  424. /package/{template → template-vite}/lib/exxat-palette.json +0 -0
  425. /package/{template → template-vite}/lib/exxat-palette.ts +0 -0
  426. /package/{template → template-vite}/lib/floating-sheet-panel.ts +0 -0
  427. /package/{template → template-vite}/lib/full-hub-supported-views.ts +0 -0
  428. /package/{template → template-vite}/lib/hub-connected-view-renderers.ts +0 -0
  429. /package/{template → template-vite}/lib/initials-from-name.ts +0 -0
  430. /package/{template → template-vite}/lib/library-authoring.ts +0 -0
  431. /package/{template → template-vite}/lib/library-dedicated-search.ts +0 -0
  432. /package/{template → template-vite}/lib/library-hub-search.ts +0 -0
  433. /package/{template → template-vite}/lib/library-nav.ts +0 -0
  434. /package/{template → template-vite}/lib/library-recent-searches.ts +0 -0
  435. /package/{template → template-vite}/lib/library-supported-views.ts +0 -0
  436. /package/{template → template-vite}/lib/list-hub-supported-views.ts +0 -0
  437. /package/{template → template-vite}/lib/list-page-table-properties.ts +0 -0
  438. /package/{template → template-vite}/lib/list-status-badges.ts +0 -0
  439. /package/{template → template-vite}/lib/logo-dev.ts +0 -0
  440. /package/{template → template-vite}/lib/mailto.ts +0 -0
  441. /package/{template → template-vite}/lib/mock/dashboard.ts +0 -0
  442. /package/{template → template-vite}/lib/mock/library-folders.ts +0 -0
  443. /package/{template → template-vite}/lib/mock/library-header-collaborators.ts +0 -0
  444. /package/{template → template-vite}/lib/mock/library-inspector.ts +0 -0
  445. /package/{template → template-vite}/lib/mock/library-kpi.ts +0 -0
  446. /package/{template → template-vite}/lib/mock/library.ts +0 -0
  447. /package/{template → template-vite}/lib/mock/navigation.tsx +0 -0
  448. /package/{template → template-vite}/lib/motion-ui.ts +0 -0
  449. /package/{template → template-vite}/lib/product-brand.ts +0 -0
  450. /package/{template → template-vite}/lib/raf-throttle.ts +0 -0
  451. /package/{template → template-vite}/lib/row-height.ts +0 -0
  452. /package/{template → template-vite}/lib/sidebar-state-cookie.ts +0 -0
  453. /package/{template → template-vite}/lib/stock-portrait.ts +0 -0
  454. /package/{template → template-vite}/lib/table-state-lifecycle.ts +0 -0
  455. /package/{template → template-vite}/lib/utils.test.ts +0 -0
  456. /package/{template → template-vite}/lib/utils.ts +0 -0
  457. /package/{template → template-vite}/public/.gitkeep +0 -0
  458. /package/{template → template-vite}/public/Illustration/Rotation.svg +0 -0
  459. /package/{template → template-vite}/public/avatars/user.svg +0 -0
  460. /package/{template/public → template-vite/public/favicon}/favicon.ico +0 -0
  461. /package/{template/app → template-vite/public}/favicon.ico +0 -0
  462. /package/{template → template-vite}/public/folders/icons8-folder-windows-11.svg +0 -0
  463. /package/{template → template-vite}/public/logos/exxat-one.svg +0 -0
  464. /package/{template → template-vite}/public/logos/exxat-prism.svg +0 -0
  465. /package/{template → template-vite}/public/mock-schools/emory.svg +0 -0
  466. /package/{template → template-vite}/public/mock-schools/rush.svg +0 -0
  467. /package/{template → template-vite}/scripts/fontawesome-subset-audit.mjs +0 -0
  468. /package/{template → template-vite}/scripts/pm2-startup-macos.sh +0 -0
  469. /package/{template → template-vite}/skills-lock.json +0 -0
  470. /package/{template/app/(app)/columns/page.tsx → template-vite/src/pages/columns.tsx} +0 -0
  471. /package/{template/app/(app)/library/find/page.tsx → template-vite/src/pages/library/find.tsx} +0 -0
  472. /package/{template/app/(app)/library/page.tsx → template-vite/src/pages/library/index.tsx} +0 -0
  473. /package/{template/app/(app)/library/list/page.tsx → template-vite/src/pages/library/list.tsx} +0 -0
  474. /package/{template/app/(app)/settings/page.tsx → template-vite/src/pages/settings.tsx} +0 -0
  475. /package/{template/app/(app)/tokens-themes/page.tsx → template-vite/src/pages/tokens-themes.tsx} +0 -0
  476. /package/{template → template-vite}/stores/app-store.ts +0 -0
  477. /package/{template → template-vite}/types/react-payment-inputs.d.ts +0 -0
@@ -1,91 +0,0 @@
1
- # Blueprint: <Name>
2
-
3
- > **Status:** Draft / Stable. **Owner:** <team or person>. **Implements:** <SC refs>.
4
-
5
- ## 1. Intent
6
-
7
- What user need does this pattern solve? In one paragraph.
8
-
9
- **Use when:**
10
- - Bullet
11
- - Bullet
12
-
13
- **Do NOT use when:**
14
- - Bullet
15
-
16
- ## 2. Anatomy
17
-
18
- ASCII / markdown sketch with labelled slots. List every named slot and whether
19
- it is required, optional, or conditional.
20
-
21
- ```
22
- ┌──────────────────────────────────────────┐
23
- │ [icon] Title [actions] │ ← slot: title-row (required)
24
- │ ─────────────────────────────────────── │
25
- │ subtitle · ID · meta │ ← slot: meta (optional)
26
- └──────────────────────────────────────────┘
27
- ```
28
-
29
- | Slot | Required? | What it carries |
30
- |---|---|---|
31
- | `title` | required | Single H1 string |
32
- | `icon` | optional | FA glyph or product mark |
33
- | `actions` | optional | Primary CTA + optional `⋯` overflow |
34
- | `meta` | optional | Count · freshness · sort summary |
35
-
36
- ## 3. States
37
-
38
- | State | Visual / behavior |
39
- |---|---|
40
- | Default | … |
41
- | Loading | … |
42
- | Empty | … |
43
- | Error | … |
44
- | RTL | … |
45
-
46
- ## 4. Tokens consumed
47
-
48
- List every token the blueprint references from
49
- [`docs/token-taxonomy.md`](../token-taxonomy.md). Be precise — no "a brand
50
- color"; name `--brand-color`.
51
-
52
- | Token | Used for |
53
- |---|---|
54
- | `--background` / `--foreground` | Surface + ink |
55
- | … | … |
56
-
57
- ## 5. Accessibility
58
-
59
- | WCAG SC | How this blueprint complies |
60
- |---|---|
61
- | 1.1.1 Non-text content | Icons are decorative (Case A) when adjacent to text; standalone icons follow Case B (label + tooltip) |
62
- | 1.3.1 Info & relationships | … |
63
- | 2.1.1 Keyboard | Tab order: … |
64
- | 2.4.6 Headings / labels | The title slot is the `<h1>` for the route |
65
- | 2.4.11 Focus visible | Inherits `:focus-visible` ring (≥ 3:1) |
66
-
67
- ## 6. Variants
68
-
69
- | Variant | When to use | Differences from default |
70
- |---|---|---|
71
- | `base` | … | — |
72
-
73
- ## 7. Implementation
74
-
75
- | Framework | Component(s) | File |
76
- |---|---|---|
77
- | **React (this app)** | `PrimaryComponent` + `RelatedComponent` | `apps/web/components/<file>.tsx` |
78
- | Mobile | — | — |
79
- | Figma | — | — |
80
-
81
- ## 8. Do / Don't
82
-
83
- | ✅ Do | ❌ Don't |
84
- |---|---|
85
- | Bullet | Bullet |
86
-
87
- ## 9. References
88
-
89
- - `apps/web/docs/<related-narrative>.md`
90
- - `.cursor/rules/<related-rule>.mdc`
91
- - `apps/web/AGENTS.md` §<section>
@@ -1,123 +0,0 @@
1
- # Blueprint: Board card
2
-
3
- > **Status:** Stable. **Owner:** Design system. **Implements:** SC 1.1.1, 1.3.1, 2.5.8, 4.1.2.
4
-
5
- ## 1. Intent
6
-
7
- A **board card** is the kanban-tile presentation of a single hub record (e.g.
8
- one Placement, one Team member, one Question-bank item) when the active view
9
- is `board`. The card surfaces the most-scannable summary fields — title, owner
10
- avatar, status chip, 1-3 meta lines — and is sized so a column holds 6-10
11
- cards on a 1280-wide viewport.
12
-
13
- **Use when:**
14
-
15
- - The hub's `board` view tab is active.
16
- - The record has a **status** (or equivalent grouping) that drives column placement.
17
- - Users compare ~6-30 records side-by-side and would benefit from owner / status visibility.
18
-
19
- **Do NOT use when:**
20
-
21
- - The record needs ≥ 4 fields to be useful at a glance (use list / table).
22
- - The dataset has > ~100 records per column (board UX collapses; use table + filters).
23
- - The hub does not model status / lifecycle (use folder grid or list).
24
-
25
- ## 2. Anatomy
26
-
27
- ```
28
- ┌──────────────────────────────────────────────┐
29
- │ Title row [avatar] │ ← slot: title (required) + trailing (optional)
30
- │ ──────────────────────────────────────────── │
31
- │ [status chip] │ ← slot: badgeRow (optional, when status exists)
32
- │ ──────────────────────────────────────────── │
33
- │ Body — primary stat (large) + sub label │ ← slot: body (optional)
34
- │ ▣ row icon · meta label · meta value │
35
- │ ▣ row icon · meta label · meta value │
36
- └──────────────────────────────────────────────┘
37
- ```
38
-
39
- | Slot | Required? | What it carries |
40
- |---|---|---|
41
- | `title` | required | `ListPageBoardCardTitleRow` — single-line truncated title |
42
- | `trailing` | optional | `ListPageBoardCardAvatar` (owner) or another single glyph |
43
- | `badgeRow` | optional | `ListPageBoardCardBadgeRow` + `ListHubStatusBadge surface="board"` |
44
- | `body` | optional | `ListPageBoardCardBody` containing `BoardCardTwoLineBlock` / `BoardCardIconRow` |
45
- | `footer` | optional | Counts, freshness, or a small CTA — kept low-emphasis |
46
-
47
- The shell is `ListPageBoardCard` (`Card size="sm"` treatment) — do NOT compose
48
- a bespoke `<button>` + border-class wrapper for the same pattern.
49
-
50
- ## 3. States
51
-
52
- | State | Visual / behavior |
53
- |---|---|
54
- | Default | Surface 2 background, hairline border, no shadow |
55
- | Hover | Border deepens; subtle elevation shift (matches `Card size="sm"`) |
56
- | Focused | `:focus-visible` ring on the outer element (≥ 3:1) |
57
- | Selected (drag source / active drag target) | `data-selected` border + brand tint |
58
- | Loading | Skeleton shell mirroring title row + badge row + body |
59
- | Empty column | Column footer shows "+ Add" affordance with `aria-label` per column |
60
- | RTL | All trailing slots flip; status chip flips alignment |
61
-
62
- ## 4. Tokens consumed
63
-
64
- | Token | Used for |
65
- |---|---|
66
- | `--exxat-color-surface-2` / `--card` | Card background |
67
- | `--exxat-color-border-1` / `--border` | Card hairline |
68
- | `--exxat-color-ink-1` / `--foreground` | Title text |
69
- | `--exxat-color-ink-2` / `--muted-foreground` | Meta label text |
70
- | `--exxat-color-focus-ring` / `--ring` | `:focus-visible` ring |
71
- | `--exxat-radius-2` / `--radius-md` | Card corners |
72
- | Status-tint variables (`LIST_HUB_STATUS_TINT_*`) | Status chip background + text |
73
-
74
- ## 5. Accessibility
75
-
76
- | WCAG SC | How this blueprint complies |
77
- |---|---|
78
- | 1.1.1 Non-text content | Icons in `BoardCardIconRow` are decorative when paired with a visible label (Case A); standalone glyphs get Case B label + tooltip |
79
- | 1.3.1 Info & relationships | The card is one `<article>` (or `role="listitem"` inside the column's `role="list"`); status, owner, and meta rows are programmatically related to the title |
80
- | 2.5.8 Target size | The whole card is the primary click target — ≥ 24×24 CSS px; small icon controls inside use `size-6` (≥ 24px) |
81
- | 4.1.2 Name / role / value | If the card is interactive (opens detail) it is rendered as `<button>` with an accessible name combining title + status |
82
-
83
- ## 6. Variants
84
-
85
- | Variant | When to use | Differences from default |
86
- |---|---|---|
87
- | `base` | Most hubs | Title + status badge + body |
88
- | `no-status` | Hubs without lifecycle (Library items) | Omit `badgeRow`; body carries the differentiator |
89
- | `compact` | Dense boards (10+ cards visible) | Drop body; show title + status + avatar only |
90
- | `with-progress` | Workflow boards with completion bar | Add a `<Progress>` row in the body slot |
91
-
92
- ## 6.1 List-row counterpart
93
-
94
- `ListPageBoardCard layout="row"` is the same component shape rendered as a
95
- horizontal row for the `list` view tab. Use one renderer for both views so the
96
- **title / status / owner / meta** mapping stays consistent — never define two
97
- parallel components for "card" and "row" of the same hub.
98
-
99
- ## 7. Implementation
100
-
101
- | Framework | Component(s) | File |
102
- |---|---|---|
103
- | **React (this app)** | `ListPageBoardCard` + `ListPageBoardCardTitleRow` + `ListPageBoardCardBadgeRow` + `ListPageBoardCardBody` + `BoardCardTwoLineBlock` + `BoardCardIconRow` + `ListHubStatusBadge` | `@exxatdesignux/ui/components/data-views` + `apps/web/lib/list-status-badges.ts` |
104
- | Board template | `ListPageBoardTemplate` (column shells + `renderCard`) | `@exxatdesignux/ui/components/data-views/list-page-board-template` |
105
- | Mobile | — | — |
106
- | Figma | "Board card – hub" component in DS library | — |
107
-
108
- ## 8. Do / Don't
109
-
110
- | ✅ Do | ❌ Don't |
111
- |---|---|
112
- | Use `ListPageBoardCard` as the shell; compose primitives inside | Wrap a bespoke `<button>` with border / padding utility classes for the same pattern |
113
- | Status: `ListHubStatusBadge surface="board"` + entity-specific map from `lib/list-status-badges.ts` | Show status as plain body text when the hub uses `ListHubStatusBadge` elsewhere |
114
- | Pull rows from `tableState.rows` so board honors filters / search | Hydrate cards from a separate `BOARD_MOCK[]` array |
115
- | Match list-row + table-row + card field choices via one mapper per hub | Define a card-only field projection that diverges from the table |
116
- | Use `Tip` on any icon-only control inside the card | Rely on `aria-label` alone for icon-only affordances inside the card |
117
-
118
- ## 9. References
119
-
120
- - `apps/web/docs/data-views-pattern.md` — board UI section
121
- - `.cursor/rules/exxat-board-cards.mdc`, `exxat-centralized-list-dataset.mdc`, `exxat-card-vs-list-rows.mdc`
122
- - `apps/web/AGENTS.md` §4.4 (board cards), §13 (checklist)
123
- - `apps/web/lib/list-status-badges.ts` — `LIST_HUB_STATUS_TINT_*` + entity maps
@@ -1,139 +0,0 @@
1
- # Blueprint: Data Table
2
-
3
- > **Status:** Stable. **Owner:** Exxat DS core. **Implements:** WCAG 2.1 AA. **References:** SC 1.3.1, 2.1.1, 2.4.3, 2.4.6, 2.5.8, 4.1.2.
4
-
5
- ## 1. Intent
6
-
7
- A **data table** is the canonical Exxat surface for browsing a homogeneous,
8
- comparable dataset (placements, team members, questions, compliance records).
9
- It pairs a **sortable / filterable / columnable grid** with a single state
10
- object (`useTableState`) that **every connected view** — list, board,
11
- dashboard, folder, panel — reads from.
12
-
13
- **Use when:**
14
- - The hub shows ≥ ~10 comparable records.
15
- - Users need to sort, filter, pin columns, change density, or export the data.
16
- - The hub is a primary nav destination.
17
-
18
- **Do NOT use when:**
19
- - The hub is **visual browse** (kanban, gallery, finder) — use
20
- `ListPageBoardCard` + `data-views/` primitives. See
21
- [`card-vs-rows-pattern.md`](../card-vs-rows-pattern.md).
22
- - The data is < ~10 rows and never grows — a simple list (or `<dl>`) suffices.
23
- - The view is read-only inside an analytics card — that may use minimal markup
24
- per [`AGENTS.md` §3](../../AGENTS.md).
25
-
26
- ## 2. Anatomy
27
-
28
- ```
29
- ┌─ ListPageTemplate ────────────────────────────────────────────────────┐
30
- │ [view tabs] [Add view +] [metrics slot] │
31
- │ ├ DataTableToolbar ──────────────────────────────────────────────┐ │
32
- │ │ [search] [filter chips] [sort] [columns] [⋯ properties] │ │
33
- │ ├ DataTable header ──────────────────────────────────────────────┤ │
34
- │ │ Col A ↕ │ Col B │ Col C │ … │ │
35
- │ ├ DataTable body ───────────────────────────────────────────────┤ │
36
- │ │ …rows from `tableState.rows`… │ │
37
- │ ├ DataTablePaginated footer (optional) ──────────────────────────┤ │
38
- │ │ ‹ 1 / N › │ │
39
- │ └────────────────────────────────────────────────────────────────┘ │
40
- └───────────────────────────────────────────────────────────────────────┘
41
- ```
42
-
43
- | Slot | Required? | What it carries |
44
- |---|---|---|
45
- | `view tabs` | required when ≥ 1 view type | `table / list / board / dashboard` per `ListPageTemplate` |
46
- | `toolbar.search` | required | `⌘K` / `Ctrl K` find-in-list |
47
- | `toolbar.filter` | required when entity has filterable fields | Shared `FilterFieldDef` chips |
48
- | `toolbar.sort` | optional (column headers also sort) | Multi-column sort summary |
49
- | `toolbar.columns` | required | Column visibility / order chooser |
50
- | `toolbar.overflow` | required | `⋯` → `TablePropertiesDrawer` |
51
- | `header` | required | One row of column heads; sortable cells expose `aria-sort` |
52
- | `body` | required | Rows from **`tableState.rows`** — no parallel data source |
53
- | `pagination` | optional | When the result set exceeds the virtualization budget |
54
-
55
- ## 3. States
56
-
57
- | State | Visual / behavior |
58
- |---|---|
59
- | Empty result | Inline empty-state row (icon + 1 sentence + clear filters action) |
60
- | Empty entity | Empty-state card (no rows in entity) |
61
- | Loading | Skeleton header + 5 skeleton rows; toolbar still interactable |
62
- | Sorted | Active column shows ↑ / ↓ with `aria-sort`; multi-sort shows index pill |
63
- | Filtered | Chips in toolbar; "X of Y" indicator |
64
- | Selected rows | Row check + bulk-action bar above toolbar |
65
- | Pinned cells | Opaque using `--dt-row-bg` / `--dt-header-bg` (never translucent) |
66
- | New row (just created) | `--dt-new-row-bg` + `--dt-new-row-border` (fades after N seconds) |
67
- | RTL | Header sort arrows and column resize handles mirror |
68
-
69
- ## 4. Tokens consumed
70
-
71
- | Token | Used for |
72
- |---|---|
73
- | `--dt-row-bg`, `--dt-row-hover`, `--dt-row-selected`, `--dt-row-selected-fg` | Row chrome (must be **opaque** for pinned cells) |
74
- | `--dt-header-bg`, `--dt-group-bg` | Header + group rows |
75
- | `--dt-new-row-bg`, `--dt-new-row-border` | "Just created" highlight |
76
- | `--sticky-edge-fade` | Edge-of-pinned-column gradient |
77
- | `--border` | Hairlines between rows / columns |
78
- | `--ring` | Focus ring on cells, sort headers, row actions |
79
- | `--interactive-hover-row` | Hover-row tint |
80
- | `--avatar-initials-bg`, `--avatar-initials-fg` | Initials cells |
81
- | `--font-mono` (via `font-mono tabular-nums` class) | System IDs in cells |
82
- | `--table-row-height` | Default row height (`48px * --scaling`) |
83
-
84
- ## 5. Accessibility
85
-
86
- | WCAG SC | How this blueprint complies |
87
- |---|---|
88
- | 1.3.1 Info & relationships | `<table>` / `<thead>` / `<tbody>` / `<tr>` / `<th scope="col">` semantics preserved through TanStack Table renderers |
89
- | 1.4.3 Contrast | Row hover + selection tints stay ≥ 4.5:1 against `--foreground` |
90
- | 1.4.11 UI contrast | Cell borders use `--border`; focus uses `--ring` (≥ 3:1) |
91
- | 2.1.1 Keyboard | Cells reachable by `Tab`; arrow-key cell nav inside the body; `Esc` clears active filter chip |
92
- | 2.4.3 Focus order | Header → toolbar → body → pagination; never traps |
93
- | 2.4.6 Headings & labels | Column heads are `<th>` with visible text labels; icon-only sort affordance carries `aria-label` + `Tooltip` (SC 1.1.1 Case C) |
94
- | 2.5.8 Target size | Sort handles, sort/filter chips, row checkboxes ≥ 24×24 CSS px |
95
- | 4.1.2 Name, role, value | Sortable headers expose `aria-sort`; row selection checkboxes expose checked state |
96
-
97
- ## 6. Variants
98
-
99
- | Variant | When to use | Differences |
100
- |---|---|---|
101
- | `DataTable` | Default — virtualized, sticky header | All features above |
102
- | `DataTablePaginated` | Server-paginated result sets where virtualization is wrong | Page footer + page-size selector |
103
- | `DataTable size="compact"` | Dense data (admin tools, reconciliation views) | Reduced `--table-row-height` |
104
-
105
- ## 7. Implementation
106
-
107
- | Framework | Component(s) | File |
108
- |---|---|---|
109
- | **React (this app)** | `DataTable`, `DataTablePaginated`, `useTableState`, `DataTableToolbar`, `TablePropertiesDrawer`, **importable cell renderers** in `components/data-views/table-cells.tsx` (`ProgressCell`, `CurrencyCell`, `RatingCell`, `RowActionsCell<TRow>`, …) | [`packages/ui/src/components/data-table/`](../../../../packages/ui/src/components/data-table/), [`apps/web/components/data-views/table-cells.tsx`](../../components/data-views/table-cells.tsx), [`packages/ui/src/components/table-properties/`](../../../../packages/ui/src/components/table-properties/) |
110
- | Mobile | — | — |
111
- | Figma | — | — |
112
-
113
- Reference compositions:
114
-
115
- - **Placements** — `PlacementsClient` + `PlacementsTable` (most complete reference)
116
- - **Team** — `TeamClient` + `TeamTable`
117
- - **Compliance** — `ComplianceClient` + `ComplianceTable`
118
- - **Library** — `LibraryClient` + `LibraryTable` (adds folder
119
- scope from URL)
120
-
121
- ## 8. Do / Don't
122
-
123
- | ✅ Do | ❌ Don't |
124
- |---|---|
125
- | Use **one** `useTableState` per logical table; pass `tableState.rows` to every connected view (list/board/dashboard) | Hydrate a board / list view from a parallel mock array — the count will diverge from the table |
126
- | Wrap the table in `ListPageTemplate` so view tabs exist | Render `DataTable` directly under `PageHeader` for a primary hub |
127
- | Pass `currentView` + `onViewChange` to `TablePropertiesDrawer` so Properties matches the active tab | Mount `TablePropertiesDrawer` on a multi-view page without `currentView` — it defaults to "Table display" copy on Board |
128
- | Use `font-mono tabular-nums` on system IDs only | Apply `font-mono` to names, statuses, or dates |
129
- | Mark sort headers with `aria-sort` and visible direction glyph | Use color alone to communicate sort direction |
130
- | Search keyboard hint shows `⌘K` (no Alt) | Use `⌘⌥K` for the table search — that chord is Ask Leo |
131
-
132
- ## 9. References
133
-
134
- - [`apps/web/docs/data-views-pattern.md`](../data-views-pattern.md) — architecture narrative
135
- - [`.cursor/rules/exxat-data-tables.mdc`](../../../.cursor/rules/exxat-data-tables.mdc) — the mandatory stack
136
- - [`.cursor/rules/exxat-list-page-connected-views.mdc`](../../../.cursor/rules/exxat-list-page-connected-views.mdc) — `tableState.rows` across views
137
- - [`.cursor/rules/exxat-centralized-list-dataset.mdc`](../../../.cursor/rules/exxat-centralized-list-dataset.mdc) — one dataset rule
138
- - [`.cursor/rules/exxat-table-properties-drawer.mdc`](../../../.cursor/rules/exxat-table-properties-drawer.mdc) — Properties drawer + active view
139
- - [`apps/web/AGENTS.md`](../../AGENTS.md) §3, §4, §5
@@ -1,128 +0,0 @@
1
- # Blueprint: Key metrics (KPI strip + dashboard tiles)
2
-
3
- > **Status:** Stable. **Owner:** Design system. **Implements:** SC 1.3.1, 1.4.3, 1.4.11, 2.4.6, 4.1.2.
4
-
5
- ## 1. Intent
6
-
7
- A **key-metrics strip** summarizes a hub's headline numbers — count, % share,
8
- average, freshness — in 1-4 horizontal tiles. Each tile carries a label, a
9
- formatted value, and an optional **trend chip** (`+12% MoM`, `↓ 0.4 day`,
10
- `stable`). The strip exists in two variants:
11
-
12
- - `variant="flat"` — transparent band glued under `ListPageTemplate` headers
13
- (brand glow + cell hairlines, no surface panel).
14
- - `variant="card"` — solid card with header / actions / chart annotations
15
- (dashboard "Key metrics" section).
16
-
17
- Both feed from the **same row bag** the hub's `DataTable` shows, so the
18
- numbers reflect active filters / search.
19
-
20
- **Use when:**
21
-
22
- - The hub's headline answer can be expressed in **≤ 4 numbers**.
23
- - The numbers update in response to filters, search, or a date scope.
24
- - The user benefits from a trend chip (signed delta + period label).
25
-
26
- **Do NOT use when:**
27
-
28
- - You need 5 + tiles (push secondary stats into a `MetricInsight`, a chart, or
29
- another section — never raise `KEY_METRICS_KPI_COUNT_MAX` without DS review).
30
- - The metric is a long-form chart (use `Chart` family, possibly with a
31
- `MetricInsight` mini-callout inside).
32
-
33
- ## 2. Anatomy
34
-
35
- ```
36
- flat:
37
- ─────────────────────────────────────────────────────────────────
38
- │ Label Value [+12% MoM ▲] │ Label Value [−0.4d ▼] │
39
- ─────────────────────────────────────────────────────────────────
40
- ↑ hairline between cells (no panel)
41
- ```
42
-
43
- ```
44
- card:
45
- ┌──────────────────────────────────────────────┐
46
- │ Key metrics [Ask Leo] │ ← header (label + actions)
47
- │ ──────────────────────────────────────────── │
48
- │ Label Value [trend] ↪ insight chip │ ← MetricItem rows
49
- │ Label Value [trend] │
50
- └──────────────────────────────────────────────┘
51
- ```
52
-
53
- | Slot | Required? | What it carries |
54
- |---|---|---|
55
- | `metrics` | required | `MetricItem[]` (≤ 4) — label, value, optional trend, optional polarity |
56
- | `variant` | required | `"flat"` (list-hub strip) or `"card"` (dashboard tile) |
57
- | `insight` | optional | `MetricInsight` — a narrative chip (e.g. "Renewals up 12% MoM") |
58
- | `headerActions` | optional (card only) | Ask-Leo trigger or drill-down button |
59
- | `loading` | optional | Skeleton state — same layout, no values |
60
-
61
- ## 3. States
62
-
63
- | State | Visual / behavior |
64
- |---|---|
65
- | Default | Tiles render label + value + optional trend |
66
- | Loading | Skeleton bars in the value + trend positions, label visible |
67
- | Empty | Value = `0` (or `—` for averages), trend = `neutral` |
68
- | Trend up + favorable | Up arrow + positive tint |
69
- | Trend up + unfavorable (`trendPolarity: "lower_is_better"`) | Up arrow + destructive tint |
70
- | Trend neutral / informational | Muted tint, arrow still shows direction |
71
- | RTL | Trend chip flips alignment; arrows stay direction-correct (logical, not visual) |
72
-
73
- ## 4. Tokens consumed
74
-
75
- | Token | Used for |
76
- |---|---|
77
- | `--exxat-color-surface-muted` / `--muted` | Card variant header band |
78
- | `--exxat-color-surface-2` / `--card` | Card variant background |
79
- | `--exxat-color-brand-tint-1` / `--brand-tint` | Flat variant OKLCH brand glow |
80
- | `--exxat-color-border-1` / `--border` | Cell hairlines (flat variant) |
81
- | `--exxat-color-ink-1` / `--foreground` | Value text |
82
- | `--exxat-color-ink-2` / `--muted-foreground` | Label + meta text |
83
- | Trend chip tokens (positive / destructive / neutral) | Trend tint + foreground |
84
-
85
- ## 5. Accessibility
86
-
87
- | WCAG SC | How this blueprint complies |
88
- |---|---|
89
- | 1.3.1 Info & relationships | The strip is `role="group"` + `aria-label="Key metrics"`; each tile is a `<dl>`-style label / value pair |
90
- | 1.4.3 Contrast | Trend chip text + tile value ≥ 4.5:1; trend icon ≥ 3:1 |
91
- | 1.4.11 Non-text contrast | Trend chip border / glyph ≥ 3:1 against tile background |
92
- | 2.4.6 Headings / labels | Each tile's label is the accessible name; value is `aria-describedby` |
93
- | 4.1.2 Name / role / value | Trend chip has `aria-label` like "Trending up 12% month over month" (via `metricTrendAriaQualifier`) |
94
-
95
- ## 6. Variants
96
-
97
- | Variant | When to use | Differences from default |
98
- |---|---|---|
99
- | `flat` | List-page hub headers — transparent band under `ListPageTemplate` | No surface panel; OKLCH brand glow; hairlines only |
100
- | `card` | Dashboards (Data tab, embed widgets) | Solid card chrome + header + optional Ask Leo trigger |
101
- | `compact` | Embedded in another card (chart annotation) | 1-2 tiles inline with the chart legend |
102
- | `mini` | Inside a chart card | Single tile rendered next to the chart title |
103
-
104
- ## 7. Implementation
105
-
106
- | Framework | Component(s) | File |
107
- |---|---|---|
108
- | **React (this app)** | `KeyMetrics` + `MetricItem` + `MetricInsight` + `metricTrendTone` + `metricTrendAriaQualifier` | `@exxatdesignux/ui/components/key-metrics` |
109
- | Service injection (Ask Leo) | `KeyMetricsProvider` (in `apps/web/components/key-metrics-ask-leo-bridge.tsx`) | Wires `useAskLeo` → DS context |
110
- | Mobile | — | — |
111
- | Figma | "Key metrics – flat" and "Key metrics – card" frames | — |
112
-
113
- ## 8. Do / Don't
114
-
115
- | ✅ Do | ❌ Don't |
116
- |---|---|
117
- | Cap visible tiles at 4 (`KEY_METRICS_KPI_COUNT_MAX`) | Add a fifth tile by raising the constant without DS review |
118
- | Set `trendPolarity: "lower_is_better"` for metrics where up = bad (defects, overdue, low-quality flags) | Always paint "up" as the favorable tint |
119
- | Feed KPI builders with `tableState.rows` so numbers honor filters | Pass raw mock arrays — the numbers will lie when filters change |
120
- | Use `variant="flat"` on hub headers and `variant="card"` in dashboards | Build a bespoke 3-column tile grid duplicating `KeyMetrics` |
121
- | Pair trend with a `MetricInsight` for narrative context | Show a bare delta with no period header or qualifier |
122
-
123
- ## 9. References
124
-
125
- - `apps/web/docs/kpi-flat-band-pattern.md`, `kpi-strip-max-four-pattern.md`, `kpi-trend-pattern.md`
126
- - `.cursor/rules/exxat-kpi-flat-band.mdc`, `exxat-kpi-max-four.mdc`, `exxat-kpi-trends.mdc`
127
- - `apps/web/AGENTS.md` §4.1 (template metrics slot), §4.3 (charts + mini-metrics)
128
- - `apps/web/lib/dashboard-layout-merge.ts` — `KEY_METRICS_KPI_COUNT_MAX`, `clampKeyMetricsKpiCount`
@@ -1,123 +0,0 @@
1
- # Blueprint: List page template
2
-
3
- > **Status:** Stable. **Owner:** Design system. **Implements:** SC 1.3.1, 2.1.1, 2.4.3, 2.4.6, 4.1.2.
4
-
5
- ## 1. Intent
6
-
7
- A **list page** is the canonical hub surface for browsing a homogeneous
8
- collection of records (Placements, Team, Compliance, Library items, …).
9
- It pairs a single `DataTable` with view-tab variants (table · list · board ·
10
- dashboard · folder · panel · tree), one shared filter / sort / column model,
11
- and a metric strip that consumes the same filtered row bag.
12
-
13
- **Use when:**
14
-
15
- - The route is the **primary** destination for an entity (a hub, not a detail).
16
- - Users compare records and filter / sort across them.
17
- - The same dataset can be productively shown as a table **and** as one or more
18
- alternate views (board, dashboard, etc.).
19
-
20
- **Do NOT use when:**
21
-
22
- - The page is a **detail** view of a single record (use a record-home page).
23
- - The dataset is < ~10 items and never needs filters (use a card grid).
24
- - The flow is a multi-step **wizard** or **form** (use a primary-page template
25
- with a focus mode).
26
-
27
- ## 2. Anatomy
28
-
29
- ```
30
- ┌──────────────────────────────────────────────────────────┐
31
- │ PageHeader (title · subtitle · primary CTA · ⋯ menu) │ ← slot: header (required)
32
- ├──────────────────────────────────────────────────────────┤
33
- │ KeyMetrics flat band (≤ 4 tiles · trend chips · …) │ ← slot: metrics (optional)
34
- ├──────────────────────────────────────────────────────────┤
35
- │ View tabs [ Table · Board · Dashboard · Folder · … ] │ ← slot: viewTabs (required, ≥ 1)
36
- ├──────────────────────────────────────────────────────────┤
37
- │ Toolbar (search · filter chips · ⋯ properties) │ ← managed by HubTable
38
- │ ┌─────────────────────────────────────────────────┐ │
39
- │ │ Active view body — TABLE / BOARD / … │ │ ← rendered by HubTable + renderers
40
- │ └─────────────────────────────────────────────────┘ │
41
- └──────────────────────────────────────────────────────────┘
42
- ```
43
-
44
- | Slot | Required? | What it carries |
45
- |---|---|---|
46
- | `header` | required | `PageHeader` (object-home / record-home / collaboration variant) |
47
- | `metrics` | optional | `KeyMetrics variant="flat"` — ≤ 4 tiles fed by the same `tableState.rows` |
48
- | `viewTabs` | required (≥ 1) | `ViewTab[]` with `viewType`, `icon`, `label`, optional `filterId` |
49
- | `renderContent` | required | `(tab, updateTab) => ReactNode` that returns the active view body |
50
- | `beforeSiteHeader` | optional | Banner / promo strip rendered above the site header |
51
- | `tablePropertiesRef` | optional | Imperative handle so the ⋯ menu can open the Properties drawer |
52
-
53
- `ListPageTemplate` itself owns the **header + metrics + view-tab control**.
54
- The view body is rendered by `HubTable` (or a custom non-table view) and
55
- **shares one `useTableState`** instance across every view.
56
-
57
- ## 3. States
58
-
59
- | State | Visual / behavior |
60
- |---|---|
61
- | Default | Header + metrics + active view body |
62
- | No metrics declared | Metrics band is omitted; no empty gap |
63
- | No rows | Active view shows entity-specific empty state; KPI tiles show zeros + neutral trend |
64
- | Filters applied | Toolbar chips reflect filters; KPI tiles recalculate against filtered rows |
65
- | Switching views | `tab.id` is the React key so table state survives (sort, search, columns) |
66
- | Loading | Render skeleton state in `renderContent`; metric tiles use the `metric-card` skeleton |
67
- | RTL | All chrome (toolbar, view tabs, properties drawer) flips with `dir="rtl"` |
68
-
69
- ## 4. Tokens consumed
70
-
71
- | Token | Used for |
72
- |---|---|
73
- | `--exxat-color-surface-1` / `--background` | Page canvas |
74
- | `--exxat-color-surface-2` / `--card` | Header + table chrome |
75
- | `--exxat-color-surface-muted` / `--muted` | View-tab inactive bg, KPI flat band glow |
76
- | `--exxat-color-brand-1` / `--brand-color` | Active view tab, primary CTA |
77
- | `--exxat-color-border-1` / `--border` | Hairlines between chrome zones |
78
- | `--exxat-color-focus-ring` / `--ring` | `:focus-visible` ring on toolbar / tabs |
79
- | `--exxat-radius-2` / `--radius` | Page chrome radii |
80
-
81
- ## 5. Accessibility
82
-
83
- | WCAG SC | How this blueprint complies |
84
- |---|---|
85
- | 1.3.1 Info & relationships | View tabs use `role="tablist"`; toolbar uses `role="toolbar"`; metrics use `role="group"` + name |
86
- | 2.1.1 Keyboard | Tab through header → tabs → toolbar → grid; arrow keys between tabs and column headers |
87
- | 2.4.3 Focus order | Tab order matches reading order top-to-bottom |
88
- | 2.4.6 Headings / labels | Header title is the route `<h1>`; each view tab announces its label |
89
- | 4.1.2 Name / role / value | View tabs expose `aria-selected`; properties drawer toggle has `aria-haspopup="dialog"` |
90
-
91
- ## 6. Variants
92
-
93
- | Variant | When to use | Differences from default |
94
- |---|---|---|
95
- | `base` | Most hubs | Header + metrics + tabs + view body |
96
- | `no-metrics` | Hubs where KPI summary adds noise (e.g. Library: too many heterogeneous folders) | Omit `metrics` prop |
97
- | `with-banner` | Pages that need a promo or alert above the header | Use `beforeSiteHeader` slot |
98
- | `secondary-panel-hub` | Hubs scoped by a sidebar panel (Library) | Wrap in `SecondaryPanelHubTemplate`; same `useTableState` |
99
-
100
- ## 7. Implementation
101
-
102
- | Framework | Component(s) | File |
103
- |---|---|---|
104
- | **React (this app)** | `ListPageTemplate` + `HubTable` + `useTableState` + `TablePropertiesDrawer` | `@exxatdesignux/ui/components/templates/list-page`, `@exxatdesignux/ui/components/data-views`, `@exxatdesignux/ui/components/data-table` |
105
- | Mobile | — | — |
106
- | Figma | Pattern: "List page – hub" frame in the DS library | — |
107
-
108
- ## 8. Do / Don't
109
-
110
- | ✅ Do | ❌ Don't |
111
- |---|---|
112
- | One `useTableState` per hub; every view reads `tableState.rows` | Mount a second mock array for "board only" or "tree only" |
113
- | Pass `currentView` + `onViewChange` into `TablePropertiesDrawer` | Leave `currentView` unset on a multi-view hub (Properties drawer assumes table) |
114
- | Use `key={tab.id}` in `renderContent` so table state survives | Use `key={tab.viewType}` (resets state when switching views) |
115
- | Pull metrics from `tableState.rows` so they react to filters / search | Pass raw mock arrays to KPI builders (numbers will lie when filters change) |
116
- | Cap the metrics strip at 4 KPI tiles | Add a fifth tile by raising `KEY_METRICS_KPI_COUNT_MAX` without DS review |
117
-
118
- ## 9. References
119
-
120
- - `apps/web/docs/data-views-pattern.md` — connected views narrative
121
- - `apps/web/docs/kpi-flat-band-pattern.md`, `kpi-strip-max-four-pattern.md`, `kpi-trend-pattern.md`
122
- - `.cursor/rules/exxat-list-page-connected-views.mdc`, `exxat-centralized-list-dataset.mdc`, `exxat-table-properties-drawer.mdc`, `exxat-list-page-view-shells.mdc`
123
- - `apps/web/AGENTS.md` §4.1 (template), §4.2 (Properties drawer), §4.5 (view shells)