@exxatdesignux/ui 0.5.10 → 0.5.12

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 (478) hide show
  1. package/CHANGELOG.md +37 -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 +13 -2
  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 +92 -12
  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/cursor-skills/exxat-senior-ux/SKILL.md +70 -17
  47. package/consumer-extras/patterns/command-menu-pattern.md +2 -2
  48. package/consumer-extras/patterns/consumer-upgrade-checklist.md +1 -1
  49. package/consumer-extras/patterns/jobs/README.md +1 -1
  50. package/consumer-extras/patterns/perf-memory-pattern.md +115 -150
  51. package/consumer-extras/scripts/dev-guard.mjs +156 -0
  52. package/consumer-extras/templates/README.md +23 -0
  53. package/consumer-extras/templates/handoff.md +190 -0
  54. package/dist/hooks/use-app-theme.d.ts +1 -1
  55. package/package.json +2 -2
  56. package/{template → template-vite}/.claude/skills/exxat-ds-skill/SKILL.md +184 -23
  57. package/template-vite/.cursor/rules/exxat-accessibility.mdc +40 -0
  58. package/template-vite/.cursor/rules/exxat-board-cards.mdc +28 -0
  59. package/template-vite/.cursor/rules/exxat-breadcrumbs-no-back.mdc +22 -0
  60. package/template-vite/.cursor/rules/exxat-card-vs-list-rows.mdc +22 -0
  61. package/template-vite/.cursor/rules/exxat-centralized-list-dataset.mdc +46 -0
  62. package/template-vite/.cursor/rules/exxat-collaboration-access.mdc +33 -0
  63. package/{template → template-vite}/.cursor/rules/exxat-command-menu.mdc +5 -5
  64. package/template-vite/.cursor/rules/exxat-data-tables.mdc +47 -0
  65. package/template-vite/.cursor/rules/exxat-dedicated-search-surfaces.mdc +32 -0
  66. package/template-vite/.cursor/rules/exxat-drawer-vs-dialog.mdc +23 -0
  67. package/template-vite/.cursor/rules/exxat-ds-agents.mdc +87 -0
  68. package/template-vite/.cursor/rules/exxat-fontawesome-icons.mdc +32 -0
  69. package/template-vite/.cursor/rules/exxat-hub-supported-views.mdc +56 -0
  70. package/{template → template-vite}/.cursor/rules/exxat-kbd-shortcuts.mdc +1 -0
  71. package/template-vite/.cursor/rules/exxat-kpi-flat-band.mdc +29 -0
  72. package/template-vite/.cursor/rules/exxat-kpi-max-four.mdc +22 -0
  73. package/template-vite/.cursor/rules/exxat-kpi-trends.mdc +32 -0
  74. package/template-vite/.cursor/rules/exxat-library-hub-header.mdc +29 -0
  75. package/template-vite/.cursor/rules/exxat-list-page-connected-views.mdc +28 -0
  76. package/template-vite/.cursor/rules/exxat-list-page-view-shells.mdc +32 -0
  77. package/{template → template-vite}/.cursor/rules/exxat-mono-ids.mdc +1 -0
  78. package/template-vite/.cursor/rules/exxat-nav-single-active.mdc +32 -0
  79. package/template-vite/.cursor/rules/exxat-no-image-pixel-copy.mdc +46 -0
  80. package/template-vite/.cursor/rules/exxat-no-slds-leakage.mdc +84 -0
  81. package/{template → template-vite}/.cursor/rules/exxat-no-toast.mdc +2 -2
  82. package/template-vite/.cursor/rules/exxat-no-vaul.mdc +26 -0
  83. package/template-vite/.cursor/rules/exxat-page-header-actions.mdc +33 -0
  84. package/{template → template-vite}/.cursor/rules/exxat-page-vs-drawer.mdc +5 -3
  85. package/template-vite/.cursor/rules/exxat-person-identity-display.mdc +48 -0
  86. package/template-vite/.cursor/rules/exxat-primary-nav-secondary-panel.mdc +53 -0
  87. package/template-vite/.cursor/rules/exxat-reuse-before-custom.mdc +37 -0
  88. package/template-vite/.cursor/rules/exxat-sidebar-shell.mdc +41 -0
  89. package/template-vite/.cursor/rules/exxat-table-properties-drawer.mdc +79 -0
  90. package/template-vite/.cursor/rules/exxat-table-row-preview.mdc +25 -0
  91. package/template-vite/.cursor/rules/exxat-tabs-chrome.mdc +33 -0
  92. package/template-vite/.cursor/rules/exxat-token-discipline.mdc +109 -0
  93. package/template-vite/.cursor/rules/exxat-ux-discovery-protocol.mdc +202 -0
  94. package/template-vite/.cursor/rules/exxat-ux-principles.mdc +187 -0
  95. package/template-vite/.cursor/skills/exxat-accessibility/SKILL.md +282 -0
  96. package/template-vite/.cursor/skills/exxat-board-cards/SKILL.md +68 -0
  97. package/template-vite/.cursor/skills/exxat-card-vs-list-rows/SKILL.md +20 -0
  98. package/template-vite/.cursor/skills/exxat-centralized-list-dataset/SKILL.md +99 -0
  99. package/template-vite/.cursor/skills/exxat-collaboration-access/SKILL.md +35 -0
  100. package/template-vite/.cursor/skills/exxat-dedicated-search-surfaces/SKILL.md +45 -0
  101. package/template-vite/.cursor/skills/exxat-drawer-vs-dialog/SKILL.md +20 -0
  102. package/template-vite/.cursor/skills/exxat-ds-skill/SKILL.md +893 -0
  103. package/template-vite/.cursor/skills/exxat-ds-skill/references/accessibility.md +142 -0
  104. package/template-vite/.cursor/skills/exxat-ds-skill/references/coach-marks.md +169 -0
  105. package/template-vite/.cursor/skills/exxat-ds-skill/references/data-table-pattern.md +392 -0
  106. package/template-vite/.cursor/skills/exxat-fontawesome-icons/SKILL.md +31 -0
  107. package/template-vite/.cursor/skills/exxat-kpi-flat-band/SKILL.md +38 -0
  108. package/template-vite/.cursor/skills/exxat-kpi-max-four/SKILL.md +19 -0
  109. package/template-vite/.cursor/skills/exxat-kpi-trends/SKILL.md +29 -0
  110. package/template-vite/.cursor/skills/exxat-list-page-view-shells/SKILL.md +36 -0
  111. package/template-vite/.cursor/skills/exxat-mono-ids/SKILL.md +56 -0
  112. package/template-vite/.cursor/skills/exxat-primary-nav-secondary-panel/SKILL.md +49 -0
  113. package/template-vite/.cursor/skills/exxat-senior-ux/SKILL.md +198 -0
  114. package/template-vite/.cursor/skills/exxat-token-economy/SKILL.md +287 -0
  115. package/template-vite/.cursor/skills/exxat-ux-audit/SKILL.md +303 -0
  116. package/{template → template-vite}/components/ask-leo-sidebar.tsx +10 -8
  117. package/{template → template-vite}/components/command-menu.tsx +1 -1
  118. package/{template → template-vite}/components/data-views/library-folder-tree-branch.tsx +1 -1
  119. package/{template → template-vite}/components/dedicated-search-recents.tsx +1 -1
  120. package/{template → template-vite}/components/dedicated-search-url-composer.tsx +1 -1
  121. package/{template → template-vite}/components/library-client.tsx +1 -1
  122. package/{template → template-vite}/components/library-hub-client.tsx +2 -2
  123. package/{template → template-vite}/components/library-secondary-nav.tsx +2 -2
  124. package/{template → template-vite}/components/library-table.tsx +35 -27
  125. package/{template → template-vite}/components/new-library-item-form.tsx +1 -1
  126. package/{template → template-vite}/components/page-breadcrumb-trail.tsx +1 -1
  127. package/{template → template-vite}/components/settings-client.tsx +1 -1
  128. package/{template → template-vite}/components/sidebar/app-sidebar.tsx +2 -2
  129. package/{template → template-vite}/components/sidebar/nav-main.tsx +1 -1
  130. package/{template → template-vite}/components/sidebar/nav-user.tsx +1 -1
  131. package/{template → template-vite}/components/sidebar/secondary-nav.tsx +1 -1
  132. package/{template → template-vite}/components/system-banner-slot.tsx +1 -1
  133. package/{template → template-vite}/components/templates/discovery-hub-template.tsx +2 -2
  134. package/{template → template-vite}/components/templates/new-focus-template.tsx +1 -1
  135. package/{template → template-vite}/components/tokens-secondary-nav.tsx +2 -2
  136. package/{template → template-vite}/components/tokens-themes-client.tsx +1 -1
  137. package/{template → template-vite}/hooks/use-secondary-panel-hub-nav.ts +1 -1
  138. package/template-vite/index.html +49 -0
  139. package/template-vite/lib/next-compat.tsx +98 -0
  140. package/{template → template-vite}/package.json +15 -27
  141. package/template-vite/scripts/port-next-imports.mjs +70 -0
  142. package/template-vite/src/App.tsx +103 -0
  143. package/template-vite/src/main.tsx +50 -0
  144. package/{template/app/(app)/error.tsx → template-vite/src/pages/_error.tsx} +12 -24
  145. package/{template/app/(app)/loading.tsx → template-vite/src/pages/_loading.tsx} +4 -2
  146. package/template-vite/src/pages/_not-found.tsx +17 -0
  147. package/template-vite/src/pages/dashboard.tsx +48 -0
  148. package/{template/app/(app)/help/page.tsx → template-vite/src/pages/help.tsx} +3 -2
  149. package/{template/app/(app)/library/layout.tsx → template-vite/src/pages/library/_layout.tsx} +18 -16
  150. package/{template/app/(app)/library/all/page.tsx → template-vite/src/pages/library/all.tsx} +1 -1
  151. package/{template/app/(app)/library/new/page.tsx → template-vite/src/pages/library/new.tsx} +12 -18
  152. package/template-vite/src/routes.tsx +72 -0
  153. package/{template/app → template-vite/src/styles}/globals.css +6 -2
  154. package/{template → template-vite}/tsconfig.json +5 -14
  155. package/template-vite/vite.config.ts +52 -0
  156. package/consumer-extras/cursor-rules/exxat-dashboard-view-charts.mdc +0 -53
  157. package/template/.agents/skills/shadcn/SKILL.md +0 -242
  158. package/template/.agents/skills/shadcn/agents/openai.yml +0 -5
  159. package/template/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
  160. package/template/.agents/skills/shadcn/assets/shadcn.png +0 -0
  161. package/template/.agents/skills/shadcn/cli.md +0 -257
  162. package/template/.agents/skills/shadcn/customization.md +0 -202
  163. package/template/.agents/skills/shadcn/evals/evals.json +0 -47
  164. package/template/.agents/skills/shadcn/mcp.md +0 -94
  165. package/template/.agents/skills/shadcn/rules/base-vs-radix.md +0 -306
  166. package/template/.agents/skills/shadcn/rules/composition.md +0 -195
  167. package/template/.agents/skills/shadcn/rules/forms.md +0 -192
  168. package/template/.agents/skills/shadcn/rules/icons.md +0 -101
  169. package/template/.agents/skills/shadcn/rules/styling.md +0 -162
  170. package/template/.cursor/rules/exxat-accessibility.mdc +0 -33
  171. package/template/.cursor/rules/exxat-data-tables.mdc +0 -32
  172. package/template/.cursor/rules/exxat-ds-agents.mdc +0 -26
  173. package/template/.cursor/rules/exxat-list-page-connected-views.mdc +0 -16
  174. package/template/.cursor/rules/exxat-table-properties-drawer.mdc +0 -40
  175. package/template/.nvmrc +0 -1
  176. package/template/.prettierignore +0 -7
  177. package/template/Logo/Exxat_Prism.svg +0 -39
  178. package/template/Logo/Exxat_one.svg +0 -36
  179. package/template/app/(app)/dashboard/loading.tsx +0 -18
  180. package/template/app/(app)/dashboard/page.tsx +0 -36
  181. package/template/app/(app)/layout.tsx +0 -77
  182. package/template/app/global-error.tsx +0 -63
  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/exxat-product-logo.tsx +0 -0
  273. /package/{template → template-vite}/components/folder-details-shell.tsx +0 -0
  274. /package/{template → template-vite}/components/form-layout-01.tsx +0 -0
  275. /package/{template → template-vite}/components/hub-tree-panel-view.tsx +0 -0
  276. /package/{template → template-vite}/components/invite-collaborators-drawer.tsx +0 -0
  277. /package/{template → template-vite}/components/key-metrics-ask-leo-bridge.tsx +0 -0
  278. /package/{template → template-vite}/components/key-metrics.tsx +0 -0
  279. /package/{template → template-vite}/components/leo-insight-indicator.tsx +0 -0
  280. /package/{template → template-vite}/components/leo-typing-dots.tsx +0 -0
  281. /package/{template → template-vite}/components/library-board-view.tsx +0 -0
  282. /package/{template → template-vite}/components/library-dashboard-charts.tsx +0 -0
  283. /package/{template → template-vite}/components/library-favorite-button.tsx +0 -0
  284. /package/{template → template-vite}/components/library-new-folder-sheet.tsx +0 -0
  285. /package/{template → template-vite}/components/library-os-folder-view.tsx +0 -0
  286. /package/{template → template-vite}/components/library-page-header.tsx +0 -0
  287. /package/{template → template-vite}/components/library-panel-activator.tsx +0 -0
  288. /package/{template → template-vite}/components/list-hub-status-badge.tsx +0 -0
  289. /package/{template → template-vite}/components/list-page-dashboard-charts.tsx +0 -0
  290. /package/{template → template-vite}/components/onboarding/getting-started.tsx +0 -0
  291. /package/{template → template-vite}/components/onboarding/index.ts +0 -0
  292. /package/{template → template-vite}/components/onboarding/onboarding-01.tsx +0 -0
  293. /package/{template → template-vite}/components/onboarding/onboarding-02.tsx +0 -0
  294. /package/{template → template-vite}/components/onboarding/onboarding-03.tsx +0 -0
  295. /package/{template → template-vite}/components/onboarding/onboarding-04.tsx +0 -0
  296. /package/{template → template-vite}/components/page-header.tsx +0 -0
  297. /package/{template → template-vite}/components/product-switcher.tsx +0 -0
  298. /package/{template → template-vite}/components/product-wordmark.tsx +0 -0
  299. /package/{template → template-vite}/components/settings-appearance-card.tsx +0 -0
  300. /package/{template → template-vite}/components/settings-form-row.tsx +0 -0
  301. /package/{template → template-vite}/components/sidebar/app-sidebar-dynamic.tsx +0 -0
  302. /package/{template → template-vite}/components/sidebar/index.ts +0 -0
  303. /package/{template → template-vite}/components/sidebar/nav-documents.tsx +0 -0
  304. /package/{template → template-vite}/components/sidebar/nav-secondary.tsx +0 -0
  305. /package/{template → template-vite}/components/sidebar/secondary-panel.tsx +0 -0
  306. /package/{template → template-vite}/components/sidebar/sidebar-auto-collapse.tsx +0 -0
  307. /package/{template → template-vite}/components/sidebar/sidebar-auto-open.tsx +0 -0
  308. /package/{template → template-vite}/components/sidebar/sidebar-shell.tsx +0 -0
  309. /package/{template → template-vite}/components/site-header.tsx +0 -0
  310. /package/{template → template-vite}/components/table-properties/column-row.tsx +0 -0
  311. /package/{template → template-vite}/components/table-properties/draggable-list.ts +0 -0
  312. /package/{template → template-vite}/components/table-properties/drawer-button.tsx +0 -0
  313. /package/{template → template-vite}/components/table-properties/drawer.tsx +0 -0
  314. /package/{template → template-vite}/components/table-properties/filter-card.tsx +0 -0
  315. /package/{template → template-vite}/components/table-properties/index.ts +0 -0
  316. /package/{template → template-vite}/components/table-properties/sort-card.tsx +0 -0
  317. /package/{template → template-vite}/components/table-properties/types.ts +0 -0
  318. /package/{template → template-vite}/components/task-list-panel.tsx +0 -0
  319. /package/{template → template-vite}/components/task-priority-badge.tsx +0 -0
  320. /package/{template → template-vite}/components/templates/dedicated-search-landing-template.tsx +0 -0
  321. /package/{template → template-vite}/components/templates/dedicated-search-results-template.tsx +0 -0
  322. /package/{template → template-vite}/components/templates/list-page.tsx +0 -0
  323. /package/{template → template-vite}/components/templates/nested-secondary-panel-shell.tsx +0 -0
  324. /package/{template → template-vite}/components/templates/primary-page-template.tsx +0 -0
  325. /package/{template → template-vite}/components/templates/secondary-panel-hub-template.tsx +0 -0
  326. /package/{template → template-vite}/components/theme-color-sync.tsx +0 -0
  327. /package/{template → template-vite}/components/theme-provider.tsx +0 -0
  328. /package/{template → template-vite}/components/tinted-icon-disc.tsx +0 -0
  329. /package/{template → template-vite}/components/tokens-hub-auxiliary-views.tsx +0 -0
  330. /package/{template → template-vite}/components/tokens-themes-section.tsx +0 -0
  331. /package/{template → template-vite}/components/ui/accordion.tsx +0 -0
  332. /package/{template → template-vite}/components/ui/ai-thinking-surface.tsx +0 -0
  333. /package/{template → template-vite}/components/ui/alert-dialog.tsx +0 -0
  334. /package/{template → template-vite}/components/ui/avatar.tsx +0 -0
  335. /package/{template → template-vite}/components/ui/badge.tsx +0 -0
  336. /package/{template → template-vite}/components/ui/banner.tsx +0 -0
  337. /package/{template → template-vite}/components/ui/breadcrumb.tsx +0 -0
  338. /package/{template → template-vite}/components/ui/button.tsx +0 -0
  339. /package/{template → template-vite}/components/ui/calendar.tsx +0 -0
  340. /package/{template → template-vite}/components/ui/card.tsx +0 -0
  341. /package/{template → template-vite}/components/ui/chart.tsx +0 -0
  342. /package/{template → template-vite}/components/ui/checkbox.tsx +0 -0
  343. /package/{template → template-vite}/components/ui/coach-mark.tsx +0 -0
  344. /package/{template → template-vite}/components/ui/collapsible.tsx +0 -0
  345. /package/{template → template-vite}/components/ui/command.tsx +0 -0
  346. /package/{template → template-vite}/components/ui/context-menu.tsx +0 -0
  347. /package/{template → template-vite}/components/ui/date-picker-field.tsx +0 -0
  348. /package/{template → template-vite}/components/ui/dialog.tsx +0 -0
  349. /package/{template → template-vite}/components/ui/dot-pattern.tsx +0 -0
  350. /package/{template → template-vite}/components/ui/drag-handle-grip.tsx +0 -0
  351. /package/{template → template-vite}/components/ui/dropdown-menu.tsx +0 -0
  352. /package/{template → template-vite}/components/ui/field.tsx +0 -0
  353. /package/{template → template-vite}/components/ui/form.tsx +0 -0
  354. /package/{template → template-vite}/components/ui/hover-card.tsx +0 -0
  355. /package/{template → template-vite}/components/ui/input-group.tsx +0 -0
  356. /package/{template → template-vite}/components/ui/input-mask.tsx +0 -0
  357. /package/{template → template-vite}/components/ui/input.tsx +0 -0
  358. /package/{template → template-vite}/components/ui/kbd.tsx +0 -0
  359. /package/{template → template-vite}/components/ui/label.tsx +0 -0
  360. /package/{template → template-vite}/components/ui/leo-icon.tsx +0 -0
  361. /package/{template → template-vite}/components/ui/payment-card-fields.tsx +0 -0
  362. /package/{template → template-vite}/components/ui/popover.tsx +0 -0
  363. /package/{template → template-vite}/components/ui/radio-group.tsx +0 -0
  364. /package/{template → template-vite}/components/ui/resizable.tsx +0 -0
  365. /package/{template → template-vite}/components/ui/scroll-area.tsx +0 -0
  366. /package/{template → template-vite}/components/ui/select.tsx +0 -0
  367. /package/{template → template-vite}/components/ui/selection-tile-grid.tsx +0 -0
  368. /package/{template → template-vite}/components/ui/separator.tsx +0 -0
  369. /package/{template → template-vite}/components/ui/sheet.tsx +0 -0
  370. /package/{template → template-vite}/components/ui/sidebar.tsx +0 -0
  371. /package/{template → template-vite}/components/ui/skeleton.tsx +0 -0
  372. /package/{template → template-vite}/components/ui/slider.tsx +0 -0
  373. /package/{template → template-vite}/components/ui/sonner.tsx +0 -0
  374. /package/{template → template-vite}/components/ui/status-badge.tsx +0 -0
  375. /package/{template → template-vite}/components/ui/table.tsx +0 -0
  376. /package/{template → template-vite}/components/ui/tabs.tsx +0 -0
  377. /package/{template → template-vite}/components/ui/textarea.tsx +0 -0
  378. /package/{template → template-vite}/components/ui/tip.tsx +0 -0
  379. /package/{template → template-vite}/components/ui/toggle-group.tsx +0 -0
  380. /package/{template → template-vite}/components/ui/toggle-switch.tsx +0 -0
  381. /package/{template → template-vite}/components/ui/toggle.tsx +0 -0
  382. /package/{template → template-vite}/components/ui/tooltip.tsx +0 -0
  383. /package/{template → template-vite}/components/ui/view-segmented-control.tsx +0 -0
  384. /package/{template → template-vite}/components.json +0 -0
  385. /package/{template → template-vite}/contexts/chart-variant-context.tsx +0 -0
  386. /package/{template → template-vite}/contexts/command-menu-context.tsx +0 -0
  387. /package/{template → template-vite}/contexts/dashboard-view-context.tsx +0 -0
  388. /package/{template → template-vite}/contexts/product-context.tsx +0 -0
  389. /package/{template → template-vite}/contexts/system-banner-context.tsx +0 -0
  390. /package/{template → template-vite}/eslint.config.mjs +0 -0
  391. /package/{template → template-vite}/fontawesome-subset.manifest.json +0 -0
  392. /package/{template → template-vite}/hooks/.gitkeep +0 -0
  393. /package/{template → template-vite}/hooks/use-app-theme.ts +0 -0
  394. /package/{template → template-vite}/hooks/use-coach-mark.ts +0 -0
  395. /package/{template → template-vite}/hooks/use-location-hash.ts +0 -0
  396. /package/{template → template-vite}/hooks/use-mobile.ts +0 -0
  397. /package/{template → template-vite}/hooks/use-mod-key-label.ts +0 -0
  398. /package/{template → template-vite}/hooks/use-sidebar-reflow-zoom.ts +0 -0
  399. /package/{template → template-vite}/lib/.gitkeep +0 -0
  400. /package/{template → template-vite}/lib/ask-leo-route-context.ts +0 -0
  401. /package/{template → template-vite}/lib/chart-keyboard-selection.test.ts +0 -0
  402. /package/{template → template-vite}/lib/chart-keyboard-selection.ts +0 -0
  403. /package/{template → template-vite}/lib/chart-line-dash.ts +0 -0
  404. /package/{template → template-vite}/lib/chunk-load-error.ts +0 -0
  405. /package/{template → template-vite}/lib/coach-mark-registry.ts +0 -0
  406. /package/{template → template-vite}/lib/collaborator-access.ts +0 -0
  407. /package/{template → template-vite}/lib/command-menu-config.ts +0 -0
  408. /package/{template → template-vite}/lib/command-menu-search-data.ts +0 -0
  409. /package/{template → template-vite}/lib/conditional-rule-match.ts +0 -0
  410. /package/{template → template-vite}/lib/dashboard-customize-coach-mark.ts +0 -0
  411. /package/{template → template-vite}/lib/dashboard-layout-merge.ts +0 -0
  412. /package/{template → template-vite}/lib/data-list-display-options.ts +0 -0
  413. /package/{template → template-vite}/lib/data-list-persistence.ts +0 -0
  414. /package/{template → template-vite}/lib/data-list-view-registry.ts +0 -0
  415. /package/{template → template-vite}/lib/data-list-view-surface.ts +0 -0
  416. /package/{template → template-vite}/lib/data-list-view.ts +0 -0
  417. /package/{template → template-vite}/lib/data-view-dashboard-storage.ts +0 -0
  418. /package/{template → template-vite}/lib/date-filter.ts +0 -0
  419. /package/{template → template-vite}/lib/dedicated-search-recents.ts +0 -0
  420. /package/{template → template-vite}/lib/dedicated-search-url.ts +0 -0
  421. /package/{template → template-vite}/lib/dev-log.test.ts +0 -0
  422. /package/{template → template-vite}/lib/dev-log.ts +0 -0
  423. /package/{template → template-vite}/lib/discovery-hub.ts +0 -0
  424. /package/{template → template-vite}/lib/editable-target.ts +0 -0
  425. /package/{template → template-vite}/lib/exxat-palette.json +0 -0
  426. /package/{template → template-vite}/lib/exxat-palette.ts +0 -0
  427. /package/{template → template-vite}/lib/floating-sheet-panel.ts +0 -0
  428. /package/{template → template-vite}/lib/full-hub-supported-views.ts +0 -0
  429. /package/{template → template-vite}/lib/hub-connected-view-renderers.ts +0 -0
  430. /package/{template → template-vite}/lib/initials-from-name.ts +0 -0
  431. /package/{template → template-vite}/lib/library-authoring.ts +0 -0
  432. /package/{template → template-vite}/lib/library-dedicated-search.ts +0 -0
  433. /package/{template → template-vite}/lib/library-hub-search.ts +0 -0
  434. /package/{template → template-vite}/lib/library-nav.ts +0 -0
  435. /package/{template → template-vite}/lib/library-recent-searches.ts +0 -0
  436. /package/{template → template-vite}/lib/library-supported-views.ts +0 -0
  437. /package/{template → template-vite}/lib/list-hub-supported-views.ts +0 -0
  438. /package/{template → template-vite}/lib/list-page-table-properties.ts +0 -0
  439. /package/{template → template-vite}/lib/list-status-badges.ts +0 -0
  440. /package/{template → template-vite}/lib/logo-dev.ts +0 -0
  441. /package/{template → template-vite}/lib/mailto.ts +0 -0
  442. /package/{template → template-vite}/lib/mock/dashboard.ts +0 -0
  443. /package/{template → template-vite}/lib/mock/library-folders.ts +0 -0
  444. /package/{template → template-vite}/lib/mock/library-header-collaborators.ts +0 -0
  445. /package/{template → template-vite}/lib/mock/library-inspector.ts +0 -0
  446. /package/{template → template-vite}/lib/mock/library-kpi.ts +0 -0
  447. /package/{template → template-vite}/lib/mock/library.ts +0 -0
  448. /package/{template → template-vite}/lib/mock/navigation.tsx +0 -0
  449. /package/{template → template-vite}/lib/motion-ui.ts +0 -0
  450. /package/{template → template-vite}/lib/product-brand.ts +0 -0
  451. /package/{template → template-vite}/lib/raf-throttle.ts +0 -0
  452. /package/{template → template-vite}/lib/row-height.ts +0 -0
  453. /package/{template → template-vite}/lib/sidebar-state-cookie.ts +0 -0
  454. /package/{template → template-vite}/lib/stock-portrait.ts +0 -0
  455. /package/{template → template-vite}/lib/table-state-lifecycle.ts +0 -0
  456. /package/{template → template-vite}/lib/utils.test.ts +0 -0
  457. /package/{template → template-vite}/lib/utils.ts +0 -0
  458. /package/{template → template-vite}/public/.gitkeep +0 -0
  459. /package/{template → template-vite}/public/Illustration/Rotation.svg +0 -0
  460. /package/{template → template-vite}/public/avatars/user.svg +0 -0
  461. /package/{template/public → template-vite/public/favicon}/favicon.ico +0 -0
  462. /package/{template/app → template-vite/public}/favicon.ico +0 -0
  463. /package/{template → template-vite}/public/folders/icons8-folder-windows-11.svg +0 -0
  464. /package/{template → template-vite}/public/logos/exxat-one.svg +0 -0
  465. /package/{template → template-vite}/public/logos/exxat-prism.svg +0 -0
  466. /package/{template → template-vite}/public/mock-schools/emory.svg +0 -0
  467. /package/{template → template-vite}/public/mock-schools/rush.svg +0 -0
  468. /package/{template → template-vite}/scripts/fontawesome-subset-audit.mjs +0 -0
  469. /package/{template → template-vite}/scripts/pm2-startup-macos.sh +0 -0
  470. /package/{template → template-vite}/skills-lock.json +0 -0
  471. /package/{template/app/(app)/columns/page.tsx → template-vite/src/pages/columns.tsx} +0 -0
  472. /package/{template/app/(app)/library/find/page.tsx → template-vite/src/pages/library/find.tsx} +0 -0
  473. /package/{template/app/(app)/library/page.tsx → template-vite/src/pages/library/index.tsx} +0 -0
  474. /package/{template/app/(app)/library/list/page.tsx → template-vite/src/pages/library/list.tsx} +0 -0
  475. /package/{template/app/(app)/settings/page.tsx → template-vite/src/pages/settings.tsx} +0 -0
  476. /package/{template/app/(app)/tokens-themes/page.tsx → template-vite/src/pages/tokens-themes.tsx} +0 -0
  477. /package/{template → template-vite}/stores/app-store.ts +0 -0
  478. /package/{template → template-vite}/types/react-payment-inputs.d.ts +0 -0
@@ -1,153 +0,0 @@
1
- # Exxat DS — Reference implementations
2
-
3
- > When a rule says "see the canonical hub" or "see the catalog page", **this is the index**. Open the file. Copy. Don't reinvent.
4
-
5
- Reference pages are the **canonical working implementations** of a pattern. They're the source of truth that rules + blueprints summarize. If a rule conflicts with a reference page, the bug is in the rule — open a PR.
6
-
7
- ---
8
-
9
- ## How to use this page
10
-
11
- 1. Find the row that matches the pattern you're building.
12
- 2. Open the **Reference page** column — that file is the template.
13
- 3. Read the linked **Blueprint** for the framework-agnostic spec.
14
- 4. Read the linked **Rule** for the binding MUST / MUST NOT.
15
- 5. Read the linked **Pattern** for the long-form "why".
16
-
17
- If you find yourself diverging from the reference page, ask **why** before shipping.
18
-
19
- ---
20
-
21
- ## Primary hubs
22
-
23
- | Pattern | Reference page | Blueprint | Rule(s) | Pattern doc |
24
- |---|---|---|---|---|
25
- | Full hub: table + board + dashboard + list + paginated + conditional rules + dashboard customize | `apps/web/components/library-table.tsx` + `library-hub-client.tsx` | [`list-page-template`](./blueprints/list-page-template.md), [`data-table`](./blueprints/data-table.md), [`board-card`](./blueprints/board-card.md), [`key-metrics`](./blueprints/key-metrics.md) | [`exxat-data-tables`](../../../.cursor/rules/exxat-data-tables.mdc), [`exxat-list-page-connected-views`](../../../.cursor/rules/exxat-list-page-connected-views.mdc), [`exxat-centralized-list-dataset`](../../../.cursor/rules/exxat-centralized-list-dataset.mdc) | [`data-views-pattern`](./data-views-pattern.md) |
26
- | Hub with secondary panel scope (folder rail) | `apps/web/components/library-hub-client.tsx` + `library-secondary-nav.tsx` | [`list-page-template`](./blueprints/list-page-template.md) | [`exxat-primary-nav-secondary-panel`](../../../.cursor/rules/exxat-primary-nav-secondary-panel.mdc), [`exxat-library-hub-header`](../../../.cursor/rules/exxat-library-hub-header.mdc) | [`library-hub-header-pattern`](./library-hub-header-pattern.md) |
27
- | Hub with secondary panel scope (URL-driven category rail) — **smallest** secondary-panel reference + built-in pagination chrome | `apps/web/components/tokens-themes-client.tsx` + `tokens-secondary-nav.tsx` | [`list-page-template`](./blueprints/list-page-template.md) | [`exxat-primary-nav-secondary-panel`](../../../.cursor/rules/exxat-primary-nav-secondary-panel.mdc) | [`shell-surface-elevation-pattern`](./shell-surface-elevation-pattern.md) |
28
- | Cell-pattern catalog — **18 SaaS cell patterns** via custom `columnDefs`; **seven views** via **`LibraryTable`** (same Add view as Library). | `apps/web/components/columns-showcase.tsx` + `columns-client.tsx` | [`list-page-template`](./blueprints/list-page-template.md), [`data-table`](./blueprints/data-table.md), [`hub-supported-views-pattern`](./hub-supported-views-pattern.md) | [`exxat-data-tables`](../../../.cursor/rules/exxat-data-tables.mdc), [`exxat-hub-supported-views`](../../../.cursor/rules/exxat-hub-supported-views.mdc) | — |
29
-
30
- > **First-time hub builder:** copy **`library-table.tsx`** + **`library-client.tsx`** for seven-view wiring; use **`columns-showcase.tsx`** for custom columns on **`LibraryItem`**; use **`tokens-themes-client.tsx`** + **`tokens-hub-auxiliary-views.tsx`** for token rows. Read **`hub-supported-views-pattern.md`** before changing Add view.
31
-
32
- ---
33
-
34
- ## Cell primitives (importable)
35
-
36
- Every cell renderer below is exported from `@/components/data-views` (re-exported from `apps/web/components/data-views/table-cells.tsx`). The live catalog page is `/columns`. **Do not re-implement these inside a `ColumnDef['cell']`** — import the name.
37
-
38
- | Cell | Renders | Import |
39
- |------|---------|--------|
40
- | `ProgressCell` | Track + filled bar with auto-tone in thirds; `value`, `max`, `tone`, `label` | `@/components/data-views` |
41
- | `CurrencyCell` | Right-aligned `tabular-nums`; `value`, `currency` (USD), `locale`, `maximumFractionDigits` | same |
42
- | `NumericCell` | Right-aligned plain count; `value`, `fractionDigits` | same |
43
- | `RatingCell` | N of `max` FA stars + value; color + glyph paired (WCAG 1.4.1) | same |
44
- | `SignalBarsCell` | Wi-Fi-style ordinal bars; `level`, `max`, `tone`, `label` (required) | same |
45
- | `BooleanToggleCell` | Inline `ToggleSwitch` with `checked` + `onChange(next)`; stops row click propagation | same |
46
- | `AttachmentCountCell` | Paperclip + count chip; muted dash on `0` | same |
47
- | `ExternalLinkCell` | Truncated host + new-tab icon; `url`, `label?`; `Tip` shows full URL | same |
48
- | `RelativeTimeCell` | "3 hours ago" with `Tip(absolute)`; `iso`, `now?` (deterministic snapshots) | same |
49
- | `PeopleAvatarRailCell` | Face rail with `+N` overflow; `people: PersonStub[]`, **non-overlapping** | same |
50
- | `PillCell` | Outlined badge + leading FA icon; `label`, `icon?` | same |
51
- | `TagListCell` | Soft badges with `+N` overflow; `tags`, `visibleMax?`, `formatLabel?` | same |
52
- | `RowActionsCell<TRow>` | `⋯` overflow dropdown; `row`, `actions: RowActionDef<TRow>[]` (label, icon, onSelect, variant, shortcut, disabled) | same |
53
- | `EMPTY_DASH` | Aria-hidden `—` placeholder for null/undefined cells | same |
54
-
55
- **Anti-references** (do NOT copy):
56
- - ❌ Inlining `Intl.NumberFormat`, `[1,2,3,4,5].map(s => …)` star loops, raw `<a target="_blank">`, `new URL(…).hostname`, or `Intl.RelativeTimeFormat` inside a `cell:`. Import the named cell.
57
- - ❌ Re-implementing `RowActionsCell` per hub with a custom `DropdownMenu`. The generic `RowActionsCell<TRow>` covers `Open / Edit / Duplicate / Archive`-style menus.
58
-
59
- ---
60
-
61
- ## Hub chrome
62
-
63
- | Pattern | Reference page | Blueprint | Rule(s) |
64
- |---|---|---|---|
65
- | Page header — primary hub | `apps/web/components/library-page-header.tsx` | [`page-header`](./blueprints/page-header.md) | [`exxat-collaboration-access`](../../../.cursor/rules/exxat-collaboration-access.mdc), [`exxat-mono-ids`](../../../.cursor/rules/exxat-mono-ids.mdc) |
66
- | Page header — entity / record (no view tabs) | `apps/web/components/page-header.tsx` (variants) | [`page-header`](./blueprints/page-header.md) | — |
67
- | KPI flat band on a hub (clickable tiles + insight card) | `apps/web/components/columns-client.tsx`, `apps/web/components/tokens-themes-client.tsx` | [`key-metrics`](./blueprints/key-metrics.md) | [`exxat-kpi-flat-band`](../../../.cursor/rules/exxat-kpi-flat-band.mdc), [`exxat-kpi-max-four`](../../../.cursor/rules/exxat-kpi-max-four.mdc), [`exxat-kpi-trends`](../../../.cursor/rules/exxat-kpi-trends.mdc) |
68
- | Properties drawer wiring (auto via `HubTable`) | `apps/web/components/library-table.tsx`, `apps/web/components/columns-showcase.tsx` | — | [`exxat-table-properties-drawer`](../../../.cursor/rules/exxat-table-properties-drawer.mdc) |
69
- | Pagination chrome (auto via `HubTable` when `pagination` is toggled) | `apps/web/components/columns-showcase.tsx`, `apps/web/components/tokens-themes-client.tsx` | [`data-table`](./blueprints/data-table.md) | [`exxat-data-tables`](../../../.cursor/rules/exxat-data-tables.mdc) |
70
- | Export drawer + ⋯ menu | `apps/web/components/library-page-header.tsx` + `export-drawer.tsx` | — | [`exxat-drawer-vs-dialog`](../../../.cursor/rules/exxat-drawer-vs-dialog.mdc) |
71
-
72
- ---
73
-
74
- ## Board, list, dashboard views
75
-
76
- | Pattern | Reference page | Blueprint | Rule(s) |
77
- |---|---|---|---|
78
- | Board card (kanban) | `apps/web/components/library-board-view.tsx` | [`board-card`](./blueprints/board-card.md) | [`exxat-board-cards`](../../../.cursor/rules/exxat-board-cards.mdc), [`exxat-card-vs-list-rows`](../../../.cursor/rules/exxat-card-vs-list-rows.mdc) |
79
- | List row (single-column) | `apps/web/components/library-table.tsx` (`renderListRow`) | [`board-card`](./blueprints/board-card.md) (row layout) | [`exxat-card-vs-list-rows`](../../../.cursor/rules/exxat-card-vs-list-rows.mdc) |
80
- | Dashboard view with charts + KPI band | `apps/web/components/library-dashboard-charts.tsx` | [`key-metrics`](./blueprints/key-metrics.md) | [`exxat-dashboard-view-charts`](../.cursor/rules/exxat-dashboard-view-charts.mdc) |
81
-
82
- ---
83
-
84
- ## Search
85
-
86
- | Pattern | Reference page | Rule(s) | Pattern doc |
87
- |---|---|---|---|
88
- | Global command palette (⌘K) | `apps/web/components/command-menu.tsx` + `lib/command-menu-config.ts` | [`exxat-command-menu`](../../../.cursor/rules/exxat-command-menu.mdc) | [`command-menu-pattern`](./command-menu-pattern.md) |
89
- | Dedicated search (landing + results) | `apps/web/components/dedicated-search-*.tsx` | [`exxat-dedicated-search-surfaces`](../../../.cursor/rules/exxat-dedicated-search-surfaces.mdc) | — |
90
- | In-table search (toolbar) | wired by `HubTable` automatically | [`exxat-data-tables`](../../../.cursor/rules/exxat-data-tables.mdc) | [`data-views-pattern`](./data-views-pattern.md) |
91
-
92
- ---
93
-
94
- ## Collaboration
95
-
96
- | Pattern | Reference page | Rule(s) | Pattern doc |
97
- |---|---|---|---|
98
- | Face rail + invite drawer | `apps/web/components/collaboration-access-flow.tsx`, `invite-collaborators-drawer.tsx` | [`exxat-collaboration-access`](../../../.cursor/rules/exxat-collaboration-access.mdc) | [`collaboration-access-pattern`](./collaboration-access-pattern.md) |
99
-
100
- ---
101
-
102
- ## Overlays and confirmations
103
-
104
- | Pattern | Reference page | Rule(s) | Pattern doc |
105
- |---|---|---|---|
106
- | Side drawer (long auxiliary flow) | `apps/web/components/export-drawer.tsx`, `invite-collaborators-drawer.tsx`, `apps/web/components/table-properties/drawer.tsx` | [`exxat-drawer-vs-dialog`](../../../.cursor/rules/exxat-drawer-vs-dialog.mdc), [`exxat-page-vs-drawer`](../../../.cursor/rules/exxat-page-vs-drawer.mdc) | [`drawer-vs-dialog-pattern`](./drawer-vs-dialog-pattern.md) |
107
- | Dialog (blocking short confirm / destructive) | `apps/web/components/ui/alert-dialog.tsx` consumers (search `<AlertDialog`) | [`exxat-drawer-vs-dialog`](../../../.cursor/rules/exxat-drawer-vs-dialog.mdc) | [`drawer-vs-dialog-pattern`](./drawer-vs-dialog-pattern.md) |
108
- | Coach mark / onboarding | `apps/web/lib/coach-mark-registry.ts` consumers (Library dashboard customize) | — | — |
109
-
110
- ---
111
-
112
- ## Settings, tokens, themes
113
-
114
- | Pattern | Reference page | Rule(s) |
115
- |---|---|---|
116
- | Settings page (preferences + sections) | `apps/web/app/(app)/settings/page.tsx` | — |
117
- | Tokens & themes hub (secondary panel + categories + visualizers) | `apps/web/components/tokens-themes-client.tsx`, `tokens-themes-section.tsx`, `tokens-secondary-nav.tsx` | [`exxat-token-discipline`](../../../.cursor/rules/exxat-token-discipline.mdc), [`exxat-primary-nav-secondary-panel`](../../../.cursor/rules/exxat-primary-nav-secondary-panel.mdc) |
118
-
119
- ---
120
-
121
- ## Anti-references (what NOT to copy)
122
-
123
- These exist but are **not** canonical. They predate a rule, are scoped to a one-off, or use a legacy primitive. **Don't copy from them.**
124
-
125
- | Anti-reference | Why not | What to use instead |
126
- |---|---|---|
127
- | Raw `<DataTable>` mounted directly in `ListPageTemplate.renderContent` (historical) | Loses filter chips, Properties drawer, and the new built-in pagination chrome | `HubTable` (see `columns-showcase.tsx`, `tokens-themes-client.tsx`, `library-table.tsx`) |
128
- | Hub-side `PaginationBar` + `CountSyncer` wiring around `DataTable` (the old Placements pattern) | `HubTable` now mounts pagination chrome automatically when the hub passes `pagination` + `onPaginationChange` | Pass `pagination` / `onPaginationChange` / optional `paginationInitialPageSize` / `paginationPageSizeOptions` to `HubTable` |
129
- | Custom search input above a `DataTable` | `HubTable`'s toolbar already does this; duplicating leads to drift | Configure `ColumnDef.filter` + use `HubTable` |
130
- | `toast()` / Sonner / snackbar | Forbidden — see [`exxat-no-toast.mdc`](../../../.cursor/rules/exxat-no-toast.mdc) | `LocalBanner` / `SystemBanner` or inline status |
131
- | Negative-margin overlapping avatars | Forbidden — see [`exxat-person-identity-display.mdc`](../../../.cursor/rules/exxat-person-identity-display.mdc) | `AvatarGroup` (gapped by default) |
132
- | Legacy customer sidebar screenshots (rainbow section text, pink wash, custom pills) | Visual spec for old product — **not** Exxat DS chrome | **`AppSidebar`** + **`SidebarMenuButton`** + **`lib/mock/navigation.tsx`** — [`exxat-sidebar-shell.mdc`](../../../.cursor/rules/exxat-sidebar-shell.mdc) |
133
- | Uploaded screenshots / mockups treated as pixel spec | Images show **intent** (labels, fields, flows) — DS blueprints + reference hubs define **implementation** | [`exxat-no-image-pixel-copy.mdc`](../../../.cursor/rules/exxat-no-image-pixel-copy.mdc) + **`component-selection-guide.md`** |
134
-
135
- ---
136
-
137
- ## Adding a new reference page
138
-
139
- If you build a pattern that **other hubs will copy**, list it here. A reference page is canonical when:
140
-
141
- 1. It satisfies the matching blueprint or rule end-to-end.
142
- 2. It passes the §13 PR-review checklist in [`AGENTS.md`](../AGENTS.md).
143
- 3. The file has a top-level doc comment that names what it's the reference for (e.g. *"Tokens & themes hub — table + secondary-panel category rail; thin wrapper around `<HubTable>` with the new built-in pagination chrome."*).
144
- 4. The matching rule's "Reference implementations" list points back to it.
145
-
146
- ---
147
-
148
- ## See also
149
-
150
- - [`HANDBOOK.md`](./HANDBOOK.md) — start-here doc map
151
- - [`blueprints/README.md`](./blueprints/README.md) — what a blueprint is
152
- - [`component-selection-guide.md`](./component-selection-guide.md) — decision tree across blueprints
153
- - [`apps/web/AGENTS.md` §13](../AGENTS.md) — full PR-review checklist
@@ -1,52 +0,0 @@
1
- # Shell surface elevation (sidebar · secondary panel · page)
2
-
3
- > **Tokens:** `app/globals.css` — `--sidebar`, `--secondary-panel-bg`, `--background`, `--brand-tint*`.
4
- > **Shell:** `components/templates/nested-secondary-panel-shell.tsx` — `bg-[var(--secondary-panel-bg)]`.
5
- > **Cursor:** `.cursor/rules/exxat-primary-nav-secondary-panel.mdc` · `.cursor/skills/exxat-primary-nav-secondary-panel/SKILL.md`
6
-
7
- ## Stack (back → front)
8
-
9
- | Level | Surface | Token / class | Notes |
10
- |-------|---------|---------------|--------|
11
- | **0** | Primary icon rail + app chrome | `--sidebar` (= `--brand-tint` on light product themes) | Darkest brand wash in the shell |
12
- | **1** | Nested secondary panel (Library, etc.) | `--secondary-panel-bg` | **Lighter** than level 0; **same product hue** |
13
- | **2** | Main page / inset content | `--background` | Lightest (white canvas light; dark charcoal dark) |
14
-
15
- **MUST** derive secondary panel fill from **`--brand-tint` / `--brand-tint-light`**, not a fixed rose or neutral grey. When the user selects **Exxat One**, both levels use **indigo hue ~286**; **Prism** uses **rose ~342**; **`theme-custom`** follows `--custom-product-brand-color` via `ProductProvider`.
16
-
17
- ## OKLCH formulas (light)
18
-
19
- ```css
20
- --sidebar: var(--brand-tint);
21
- --secondary-panel-bg: color-mix(in oklch, var(--background) 40%, var(--brand-tint-light) 60%);
22
- ```
23
-
24
- ## OKLCH formulas (dark)
25
-
26
- ```css
27
- --secondary-panel-bg: color-mix(in oklch, var(--card) 32%, var(--brand-tint) 68%);
28
- ```
29
-
30
- Per-product **dark** theme blocks (`.theme-one.dark`, `.theme-prism.dark`, …) set **`--brand-tint-light`** where needed so mixes stay on-hue.
31
-
32
- ## Implementation
33
-
34
- - **`NestedSecondaryPanelShell`** — `bg-[var(--secondary-panel-bg)]`, `ring-sidebar-border` (not generic `ring-border` alone).
35
- - **Do not** set secondary panel to `bg-sidebar` (same as level 0 — loses elevation).
36
- - **Do not** use `color-mix(… var(--sidebar) …)` without brand tokens if it drifts from active product theme.
37
-
38
- ## Product theme classes
39
-
40
- - **`theme-one`** / **`theme-prism`** / **`theme-assessment`** — built-in OKLCH brand scales in `globals.css`.
41
- - **`theme-custom`** — when user picks an accent in Settings; driven by `--custom-product-brand-color`.
42
- - **`ProductProvider`** — applies `theme-one` vs `theme-prism` vs `theme-custom`; accent override only when it **differs** from the product default (see `accentOverrideActive` in `contexts/product-context.tsx`).
43
-
44
- ## Logo vs chrome
45
-
46
- - **Chrome** (sidebar, secondary panel, KPI glow) follows **`--brand-tint` / `--brand-color`** per product.
47
- - **Logo art** (mark + suffix) stays **Exxat pink** via `wordmarkColor` / `markGradient` in `lib/product-brand.ts` — recolouring a product in Settings changes **theme accent**, not corporate logo pink.
48
-
49
- ## See also
50
-
51
- - **`docs/kpi-flat-band-pattern.md`** — flat KPI strip uses brand glow only, no surface
52
- - **`apps/web/AGENTS.md` §4.6** — secondary panel wiring
@@ -1,416 +0,0 @@
1
- # Exxat DS — Token Taxonomy
2
-
3
- **Status:** Authoritative · **Audience:** humans + AI agents · **Standard:** WCAG 2.1 AA
4
- **Machine-readable index:** [`packages/ui/tokens/hooks-index.json`](../../packages/ui/tokens/hooks-index.json) (generated)
5
- **Defining file (canonical):** [`packages/ui/src/globals.css`](../../packages/ui/src/globals.css). Consumer apps (`apps/web/app/globals.css`, the `create-exxat-app` starter at `packages/ui/template/app/globals.css`) are thin shells that `@import "@exxatdesignux/ui/globals.css"` and only declare their own `@source` directive. The dedicated `packages/ui/src/theme.css` file has been **retired** — see [`docs/migrations/0003-globals-css-canonical.md`](./migrations/0003-globals-css-canonical.md).
6
-
7
- This document formalizes the **naming, layering, and ownership** of every CSS
8
- custom property the design system ships. It is the answer to "what do I name a
9
- new token?" and "is there already a token for this?". If something here
10
- disagrees with the CSS, the CSS wins — and this file needs an edit.
11
-
12
- ---
13
-
14
- ## 1. Layering — where a token lives
15
-
16
- Tokens are declared in **four** layers. Higher layers may consume lower ones;
17
- they MUST NOT redefine names from a higher layer with a different meaning.
18
-
19
- | Layer | File | Purpose | Edit when |
20
- |---|---|---|---|
21
- | **L0 — Exxat canonical** | `packages/ui/src/globals.css` `:root` (block tagged `Exxat L0 — canonical namespace`) | SLDS-style flat namespace (`--exxat-color-surface-1`, `--exxat-radius-2`, …). The **official** names the DS scales on. Today these are `var()` aliases of L1; the canonical OKLCH will move here over time. | New product surface tokens, broader brand picker, anything you would otherwise put under "L1 with an Exxat brand prefix" |
22
- | **L1 — shadcn semantic** | `packages/ui/src/globals.css` `:root`/`.dark` | OKLCH literals + back-compat vocabulary (`--background`, `--foreground`, `--brand-color`, …). Required for the upstream shadcn primitives in `components/ui/*`. **Frozen** — do not extend; new tokens go to L0. | Brand color changes, accessibility-driven contrast lifts, new chip/chart slot tied to shadcn names |
23
- | **L2 — Tailwind bridge** | `packages/ui/src/globals.css` `@theme inline` block | Maps primitives to `--color-*` and `--radius-*` so Tailwind v4 emits utility classes (`bg-brand`, `bg-surface-1`, `text-chip-3`, `rounded-2`, …) | Whenever an L0/L1 token needs a Tailwind utility class |
24
- | **L3 — Surface override** | Theme blocks (`.theme-one`, `.theme-prism`, `[data-contrast="high"]`, `[data-text-size]`) | Per-brand / per-mode rebindings of L1 names — never new names | New brand, new contrast mode, new density step |
25
-
26
- > **Rules:**
27
- > 1. A token is **introduced exactly once**. New product tokens land in **L0**.
28
- > 2. L1 (shadcn names) is **frozen** — keep working, do not extend.
29
- > 3. L2 bridges L0/L1 → Tailwind utilities, exactly once per name.
30
- > 4. L3 re-binds existing L1 OKLCH values per theme. L0 inherits via `var(L1)` automatically.
31
-
32
- ---
33
-
34
- ## 2. Namespace map (all current prefixes)
35
-
36
- Every prefix below has a clear role. **New tokens MUST land in one of these
37
- prefixes** — if you cannot place a token, the design system is missing a
38
- prefix; propose one in a PR and document it here first.
39
-
40
- ### 2.0 Exxat L0 — canonical namespace (`--exxat-*`)
41
-
42
- The **official** name layer. Mirrors the SLDS `--slds-g-*` pattern but flat
43
- (no `-g-` for "global" yet, since we have a single product namespace). Today
44
- these resolve to L1 via `var(...)` so every existing theme override flows
45
- through automatically. New components SHOULD prefer L0 names; the linter will
46
- not yet *force* this, but `apps/web/docs/migrations/0002-exxat-token-namespace.md`
47
- tracks the rollout.
48
-
49
- | Category | L0 token | Resolves to L1 |
50
- |---|---|---|
51
- | Surface | `--exxat-color-surface-1` … `-3` | `--background` / `--card` / `--popover` |
52
- | Surface | `--exxat-color-surface-muted` / `-accent` / `-secondary` / `-sidebar` / `-input` | `--muted` / `--accent` / `--secondary` / `--sidebar` / `--input-background` |
53
- | Ink | `--exxat-color-ink-1` / `-2` | `--foreground` / `--muted-foreground` |
54
- | Ink | `--exxat-color-ink-on-surface-2` / `-on-surface-3` | `--card-foreground` / `--popover-foreground` |
55
- | Ink | `--exxat-color-ink-on-brand` / `-on-primary` / `-on-secondary` / `-on-accent` / `-on-destructive` | foreground tokens |
56
- | Brand | `--exxat-color-brand-1` / `-2` / `-3` / `-deep` | `--brand-color` / `-dark` / `-light` / `-deep` |
57
- | Brand | `--exxat-color-brand-tint-1` / `-2` / `-3` | `--brand-tint` / `-subtle` / `-light` |
58
- | Action | `--exxat-color-action-primary` / `-secondary` / `-destructive` | `--primary` / `--secondary` / `--destructive` |
59
- | Border | `--exxat-color-border-1` / `-control-subtle` / `-control-1` / `-control-2` | `--border` ladder (see §6) |
60
- | Focus | `--exxat-color-focus-ring` | `--ring` |
61
- | Overlay | `--exxat-color-overlay` | `--overlay` |
62
- | Chart | `--exxat-color-chart-1` … `-5` | `--chart-1` … `-5` |
63
- | Chip | `--exxat-color-chip-1` … `-5` / `-destructive` | `--chip-1` … `-5` / `-destructive` |
64
- | Radius | `--exxat-radius-1` … `-6` | `4px` / `8px` / `12px` / `16px` / `20px` / `24px` |
65
- | Spacing | `--exxat-spacing-1` / `-2` / `-3` / `-4` / `-5` / `-6` / `-8` / `-12` | Tailwind base scale |
66
- | Control | `--exxat-control-height-1` / `-2` / `-3` | `--control-height-sm` / `-` / `-touch` |
67
-
68
- **Tailwind utilities** are emitted via L2 bridges in `@theme inline`:
69
-
70
- | L0 token | Tailwind utility |
71
- |---|---|
72
- | `--exxat-color-surface-1` | `bg-surface-1`, `text-surface-1`, `border-surface-1`, … |
73
- | `--exxat-color-ink-1` / `-2` | `text-ink-1`, `text-ink-2` |
74
- | `--exxat-color-brand-1` … `-3` | `bg-brand-1`, `bg-brand-2`, `bg-brand-3` |
75
- | `--exxat-color-brand-tint-1` … `-3` | `bg-brand-tint-1`, … |
76
- | `--exxat-color-border-1` | `border-1` |
77
- | `--exxat-color-focus-ring` | `ring-focus-ring` |
78
- | `--exxat-radius-1` … `-6` | `rounded-1` … `rounded-6` |
79
-
80
- > The existing `bg-background`, `bg-brand`, `rounded-md`, etc. are not going
81
- > away — they alias to the same OKLCH. Both forms work side-by-side; **new code**
82
- > should reach for the L0 form for clarity and grep-ability (`grep --exxat-`
83
- > finds every product token without false positives from shadcn names).
84
-
85
- ### 2.1 Semantic surface (shadcn core, L1 — frozen)
86
-
87
- Inherited from shadcn / Radix and treated as the **stable** semantic vocabulary
88
- across every shadcn component. Do not rename — downstream `components/ui/*`
89
- expects these.
90
-
91
- | Token | Role |
92
- |---|---|
93
- | `--background` / `--foreground` | Page canvas + ink |
94
- | `--card` / `--card-foreground` | Raised card surfaces |
95
- | `--popover` / `--popover-foreground` | Floating menus, tooltips, dropdowns |
96
- | `--primary` / `--primary-foreground` | Default CTA color (neutral charcoal, **not** brand — see §3) |
97
- | `--secondary` / `--secondary-foreground` | Secondary button + de-emphasized surface |
98
- | `--muted` / `--muted-foreground` | Muted body copy, subtle backgrounds |
99
- | `--accent` / `--accent-foreground` | Hovered list rows, low-contrast chips |
100
- | `--destructive` / `--destructive-foreground` | Errors, delete confirms |
101
- | `--border` | Decorative dividers (no AA requirement) |
102
- | `--border-control` / `--border-control-3` / `--border-control-35` / `--control-border` | Form-field borders — see §6 for the contrast ladder |
103
- | `--input` / `--input-background` | Input outline + fill |
104
- | `--ring` | Focus ring (≥ 3:1, SC 2.4.11) |
105
- | `--overlay` | Modal / sheet / drawer scrim |
106
-
107
- ### 2.2 Brand (`--brand-*`)
108
-
109
- The **product accent** — different from `--primary` (which is neutral). Exxat
110
- ships **two** brand themes (Exxat One = lavender 286.1, Exxat Prism = rose 343)
111
- plus user-picked custom brand.
112
-
113
- | Token | Role |
114
- |---|---|
115
- | `--brand-color` | Solid brand fill (used on chips, links, charts when product) |
116
- | `--brand-color-light` / `--brand-color-dark` / `--brand-color-deep` | Brand scale (light / dark / deepest) |
117
- | `--brand-foreground` | Ink on a solid brand fill |
118
- | `--brand-tint` / `--brand-tint-light` / `--brand-tint-subtle` | Wash surfaces (sidebar, secondary panel) |
119
- | `--brand-preview-one` / `--brand-preview-prism` | Fixed swatches for the brand picker — **never change with the active theme** |
120
-
121
- ### 2.3 Sidebar + secondary panel (`--sidebar-*`, `--secondary-panel-bg`)
122
-
123
- Three-level brand chrome stack. See `docs/shell-surface-elevation-pattern.md`.
124
-
125
- | Token | Role |
126
- |---|---|
127
- | `--sidebar` / `--sidebar-foreground` | Primary sidebar (= `--brand-tint` on product themes) |
128
- | `--sidebar-primary` / `--sidebar-primary-foreground` | Solid pill / active hint on sidebar |
129
- | `--sidebar-accent` / `--sidebar-accent-foreground` | Hovered/active row in sidebar |
130
- | `--sidebar-border` | Inner divider |
131
- | `--sidebar-ring` | Focus ring inside sidebar |
132
- | `--sidebar-section-label-foreground` | Section title — mixed against real `--sidebar`, not `--background` |
133
- | `--secondary-panel-bg` | Nested panel (Library) — level 1 between sidebar and canvas |
134
-
135
- ### 2.4 Chips / badges (`--chip-*`)
136
-
137
- A five-slot **AA-compliant** palette for tags, kanban badges, and small status
138
- chips. All slots maintain ≥ 4.5:1 against `--background`.
139
-
140
- | Token | Hue (light) |
141
- |---|---|
142
- | `--chip-1` | indigo (264) |
143
- | `--chip-2` | teal (184) |
144
- | `--chip-3` | slate (227) |
145
- | `--chip-4` | amber (84) |
146
- | `--chip-5` | orange (70) |
147
- | `--chip-destructive` | red (25) |
148
-
149
- Use through `lib/list-status-badges.ts` (`LIST_HUB_STATUS_TINT_*`). Do not pick a
150
- chip slot to mean "this entity uses indigo" — pick by **semantic intent**
151
- (success / warning / neutral / danger / info).
152
-
153
- ### 2.5 Charts (`--chart-*`)
154
-
155
- Five slots scoped for `recharts` series. They are **darker** than chip slots
156
- because chart areas are larger and need denser pigment.
157
-
158
- | Token | Hue |
159
- |---|---|
160
- | `--chart-1` | blue (264) |
161
- | `--chart-2` | green-teal (184) |
162
- | `--chart-3` | slate (227) |
163
- | `--chart-4` | amber (84) |
164
- | `--chart-5` | orange (70) |
165
-
166
- Insights derived from charts use `--insight-severity-*-bg` / `-fg` (KPI strip).
167
-
168
- ### 2.6 Interactive hover (`--interactive-hover-*`)
169
-
170
- Single source for ghost-button hover, list-row hover, table chrome hover.
171
- Replaces ad-hoc `hover:bg-muted` so theming + dark mode flip together.
172
-
173
- | Token | Role |
174
- |---|---|
175
- | `--interactive-hover` | Default opaque hover fill |
176
- | `--interactive-hover-foreground` | Ink on hover |
177
- | `--interactive-hover-subtle` / `-soft` / `-medium` / `-strong` | Opacity ladder (50 / 40 / 60 / 70 mix) |
178
- | `--interactive-hover-row` | List/table row hover (accent-mixed) |
179
-
180
- ### 2.7 DataTable (`--dt-*`)
181
-
182
- Pinned cells must be **opaque** so they sit above scrolled rows. These tokens
183
- exist because `var(--muted)` alone gives translucent surfaces in dark mode.
184
-
185
- | Token | Role |
186
- |---|---|
187
- | `--dt-row-bg` | Base row fill (opaque) |
188
- | `--dt-row-hover` | Hovered row |
189
- | `--dt-row-selected` / `--dt-row-selected-fg` | Selection state |
190
- | `--dt-header-bg` | Header row |
191
- | `--dt-group-bg` | Group / divider row |
192
- | `--dt-new-row-bg` / `--dt-new-row-border` | "Just created" highlight |
193
-
194
- ### 2.8 KPI strip (`--key-metrics-*`, `--insight-severity-*`)
195
-
196
- Used by `KeyMetrics` (both `variant="flat"` and `variant="card"`). See
197
- `docs/kpi-flat-band-pattern.md`.
198
-
199
- | Token | Role |
200
- |---|---|
201
- | `--key-metrics-flat-cell-bg` | Transparent on `variant="flat"` |
202
- | `--key-metrics-flat-divider` | Cell-border hairline |
203
- | `--key-metrics-flat-band-radial` | OKLCH brand glow at bottom |
204
- | `--key-metrics-flat-band-shadow` | `none` on flat |
205
- | `--key-metrics-card-glow-radial` | Card-variant glow |
206
- | `--insight-severity-warning-bg` / `-fg` | Yellow severity (chart-4 mix) |
207
- | `--insight-severity-info-bg` / `-fg` | Blue severity (chart-1 mix) |
208
-
209
- ### 2.9 Conditional formatting (`--conditional-rule-*`)
210
-
211
- Row backgrounds for table conditional-format rules. Already six slots — adding
212
- more requires expanding the rule type in `lib/table-conditional-format.ts`.
213
-
214
- ### 2.10 Icon discs (`--icon-disc-*`)
215
-
216
- Soft tinted backgrounds for icon "discs" (KPI cards, banner avatars).
217
- Bg ≈ 14% mix, fg from `--chip-*` / `--brand-color-dark`.
218
-
219
- ### 2.11 Avatar (`--avatar-initials-*`)
220
-
221
- Bg + fg for initials avatars in `DataTable` cells. Pair brand wash with deep
222
- brand ink for ≥ 4.5:1 on white rows.
223
-
224
- ### 2.12 Leo (Ask Leo) (`--leo-*`)
225
-
226
- | Token | Role |
227
- |---|---|
228
- | `--leo-surface-tint-a` / `-b` | Top / bottom of the AI panel wash |
229
- | `--leo-surface-gradient` | Full linear wash |
230
-
231
- ### 2.13 Layout + density (`--header-height`, `--control-*`, `--table-row-height`, `--scaling`)
232
-
233
- Sized in **px** so JS can `parseFloat` them. Multiply by `--scaling` for future
234
- density modes.
235
-
236
- ### 2.14 Border radius (`--radius`, `--radius-sm`/`-md`/`-lg`/`-xl`/`-2xl`/`-3xl`)
237
-
238
- `--radius` is the **base** (8px). The named scale lives at L2 (`@theme inline`)
239
- so Tailwind emits `rounded-sm`, `rounded-md`, etc.
240
-
241
- ### 2.15 Shadows + transitions (`--shadow-*`, `--transition-*`)
242
-
243
- | Token | Role |
244
- |---|---|
245
- | `--shadow-sm` / `-md` / `-lg` | Three-step elevation |
246
- | `--transition-fast` / `-normal` / `-colors` | Standard durations |
247
- | `--sticky-edge-fade` | Edge-of-pinned-column gradient |
248
-
249
- ### 2.16 Promo / banner (`--banner-prism-bg`)
250
-
251
- Rose hue 343, used **universally** as the Exxat Prism promo highlight — does
252
- not flip with the active theme.
253
-
254
- ### 2.17 OS chrome (`--theme-color-chrome`)
255
-
256
- Mirrored into `<meta name="theme-color">` so the browser titlebar matches the
257
- sidebar. Hex literal here is **intentional** — it is consumed by the browser
258
- parser, not CSS.
259
-
260
- ---
261
-
262
- ## 3. Color identity rules
263
-
264
- 1. **`--primary` is neutral**, not brand. The product accent is `--brand-color`.
265
- This matches Exxat's design language (neutral charcoal CTAs, lavender/rose
266
- reserved for surfaces and chips). When a button **must** carry the brand,
267
- use `bg-brand-color text-brand-foreground` — not `bg-primary`.
268
- 2. **Brand washes (`--brand-tint*`) are surfaces; brand colors
269
- (`--brand-color*`) are ink/fills.** Mixing the roles produces low-contrast
270
- chips and washed-out sidebars.
271
- 3. **Chip ≠ chart.** Chip tokens are sized for inline chips; chart tokens are
272
- sized for filled SVG areas. Re-use a chip color on a chart fill (or vice
273
- versa) only when the design explicitly calls for it.
274
- 4. **Every theme MUST keep `--brand-preview-one` and `--brand-preview-prism`
275
- fixed.** They drive the brand picker swatch — flipping them with the
276
- selected theme defeats the picker.
277
-
278
- ---
279
-
280
- ## 4. Naming a new token — checklist
281
-
282
- Run this list **before** opening `globals.css`:
283
-
284
- - [ ] **Does an L0 alias already exist?** (`--exxat-color-surface-1`,
285
- `--exxat-color-brand-1`, `--exxat-radius-2`, …) — prefer L0 for new
286
- consumers; the L1 shadcn name is the back-compat alias.
287
- - [ ] If the token is new, **name it at L0 first** (`--exxat-<category>-<slot>`).
288
- Add an L1 mirror **only** if a shadcn primitive in `components/ui/*`
289
- needs it — that's the only place L1 is still required.
290
- - [ ] Can it be expressed with an existing semantic token? (`--exxat-color-surface-muted`
291
- instead of `--exxat-color-surface-4`, `--brand-color-dark` instead of
292
- `--brand-deeper`)
293
- - [ ] Does it belong to a **scoped surface** (`KeyMetrics`, `DataTable`, Leo,
294
- sidebar, secondary panel)? If yes, **prefix with that surface**, e.g.
295
- `--key-metrics-*`, `--dt-*`, `--leo-*`. Do **not** drop scoped tokens at
296
- the top level.
297
- - [ ] Is it a **decoration** or a **decision**? Decorations (gradients, fades,
298
- shadows) live alongside the surface tokens they decorate. Decisions
299
- (semantic intent: warning, info, success) live with chips / charts /
300
- insight tokens.
301
- - [ ] Does it need a Tailwind utility (`bg-*`, `text-*`, `border-*`)? If yes,
302
- add the `--color-<name>` bridge in `@theme inline` in **both** globals
303
- files.
304
- - [ ] Does dark mode / high contrast / Prism need different OKLCH? Override at
305
- L3 — never branch by emitting a new token name.
306
- - [ ] Is it derived (e.g. 14% mix of `--brand-color`)? Use `color-mix(in oklch,
307
- …)` so theme overrides cascade automatically.
308
- - [ ] Add the bridge in `packages/ui/src/globals.css` `@theme inline`. App
309
- consumers @import that file, so a single edit is enough — no manual
310
- mirroring across `apps/web/app/globals.css` / `template/app/globals.css`.
311
-
312
- If you tick all the boxes, also:
313
-
314
- 1. Add an entry to this file (the right §).
315
- 2. Re-run `pnpm --filter @exxatdesignux/ui tokens:index` (see §7) to refresh
316
- `packages/ui/tokens/hooks-index.json`.
317
-
318
- ---
319
-
320
- ## 5. Deprecation policy
321
-
322
- Tokens follow the same **add → mark deprecated → remove** lifecycle as code:
323
-
324
- 1. **Add** the new token; switch components to consume it.
325
- 2. **Mark deprecated** in `packages/ui/src/globals.css` with a comment:
326
- ```css
327
- /* @deprecated v0.2.18 — use --brand-color-dark; remove in v0.4.0 */
328
- --brand-deep: var(--brand-color-dark);
329
- ```
330
- 3. **Migrate** consumers (script + grep + manual review). Document in
331
- `docs/migrations/<NNNN>-<slug>.md`.
332
- 4. **Remove** in the version named in the deprecation comment. Bump
333
- `@exxatdesignux/ui` major or document in `CHANGELOG.md`.
334
-
335
- Active deprecations are listed in `docs/migrations/README.md`.
336
-
337
- ---
338
-
339
- ## 6. Form-field border contrast ladder
340
-
341
- Form-field borders are a recurring source of WCAG SC 1.4.11 (3:1 UI contrast)
342
- failures. Use the right rung — do not guess:
343
-
344
- | Token | OKLCH L | Contrast vs `oklch(1 0 0)` | When to use |
345
- |---|---|---|---|
346
- | `--border` | 0.92 | < 3:1 | **Decorative only** — card dividers, list separators |
347
- | `--border-control` | 0.82 | < 3:1 | Layout chrome where contrast is not required |
348
- | `--border-control-3` | 0.62 | ≈ 3:1 | Form-field border **minimum** — passes AA |
349
- | `--border-control-35` | 0.25 | > 3.5:1 | Form-field border **recommended** — passes AA + 16% buffer |
350
- | `--control-border` (alias of `--border-control-3`) | — | — | Default form-field border slot |
351
-
352
- If you find yourself reaching for `--border` on an `<input>`, stop — use
353
- `--control-border`.
354
-
355
- ---
356
-
357
- ## 7. Machine-readable hooks index
358
-
359
- Tooling (linters, codegens, design-tool sync) needs to discover tokens
360
- programmatically. Run:
361
-
362
- ```bash
363
- pnpm --filter @exxatdesignux/ui tokens:index
364
- ```
365
-
366
- This regenerates [`packages/ui/tokens/hooks-index.json`](../../packages/ui/tokens/hooks-index.json),
367
- which mirrors SLDS's `hooks-index.json` shape. The current index contains
368
- **195 tokens** across **41 namespaces** (including the 12 Exxat L0 sub-namespaces
369
- `exxat-surface`, `exxat-ink`, `exxat-brand`, `exxat-action`, `exxat-border`,
370
- `exxat-focus`, `exxat-overlay`, `exxat-chart`, `exxat-chip`, `exxat-radius`,
371
- `exxat-spacing`, `exxat-control`):
372
-
373
- ```jsonc
374
- {
375
- "version": "0.2.18",
376
- "source": "packages/ui/src/globals.css",
377
- "generatedAt": "ISO-8601",
378
- "tokens": {
379
- "--exxat-color-brand-1": {
380
- "namespace": "exxat-brand",
381
- "category": "color",
382
- "values": { "light": "var(--brand-color)" },
383
- "tailwindUtilities": ["bg-brand-1", "text-brand-1", "border-brand-1", "ring-brand-1"],
384
- "deprecated": false
385
- },
386
- "--brand-color": {
387
- "namespace": "brand",
388
- "category": "color",
389
- "values": {
390
- "light": "oklch(0.50 0.14 286.1)",
391
- "dark": "oklch(0.50 0.14 286.1)",
392
- "theme-one": "oklch(0.50 0.14 286.1)",
393
- "theme-prism": "oklch(0.57 0.24 342)",
394
- "high-contrast": "oklch(0.06 0 0)"
395
- },
396
- "tailwindUtilities": ["bg-brand", "text-brand", "border-brand", "ring-brand"],
397
- "deprecated": false
398
- }
399
- }
400
- }
401
- ```
402
-
403
- CI runs `tokens:index` and fails if the committed JSON is stale.
404
-
405
- ---
406
-
407
- ## 8. References
408
-
409
- - `packages/ui/src/globals.css` — **single source of truth** for L1 / L2 / L3 primitives + Tailwind bridges
410
- - `apps/web/app/globals.css`, `packages/ui/template/app/globals.css` — thin shells (`@import` + `@source`)
411
- - `apps/web/docs/shell-surface-elevation-pattern.md` — sidebar / secondary panel
412
- - `apps/web/docs/kpi-flat-band-pattern.md` — `--key-metrics-flat-*`
413
- - `apps/web/docs/kpi-trend-pattern.md` — `--insight-severity-*` polarity
414
- - `.cursor/rules/exxat-token-discipline.mdc` — enforcement rule (don't ship hex
415
- literals, don't use deprecated tokens)
416
- - `docs/migrations/` — token rename + removal history