@exxatdesignux/ui 0.5.11 → 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 (476) hide show
  1. package/CHANGELOG.md +26 -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 -2
  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/library-client.tsx +1 -1
  120. package/{template → template-vite}/components/library-hub-client.tsx +2 -2
  121. package/{template → template-vite}/components/library-secondary-nav.tsx +2 -2
  122. package/{template → template-vite}/components/library-table.tsx +35 -27
  123. package/{template → template-vite}/components/new-library-item-form.tsx +1 -1
  124. package/{template → template-vite}/components/page-breadcrumb-trail.tsx +1 -1
  125. package/{template → template-vite}/components/settings-client.tsx +1 -1
  126. package/{template → template-vite}/components/sidebar/app-sidebar.tsx +2 -2
  127. package/{template → template-vite}/components/sidebar/nav-main.tsx +1 -1
  128. package/{template → template-vite}/components/sidebar/nav-user.tsx +1 -1
  129. package/{template → template-vite}/components/sidebar/secondary-nav.tsx +1 -1
  130. package/{template → template-vite}/components/system-banner-slot.tsx +1 -1
  131. package/{template → template-vite}/components/templates/discovery-hub-template.tsx +2 -2
  132. package/{template → template-vite}/components/templates/new-focus-template.tsx +1 -1
  133. package/{template → template-vite}/components/tokens-secondary-nav.tsx +2 -2
  134. package/{template → template-vite}/components/tokens-themes-client.tsx +1 -1
  135. package/{template → template-vite}/hooks/use-secondary-panel-hub-nav.ts +1 -1
  136. package/template-vite/index.html +49 -0
  137. package/template-vite/lib/next-compat.tsx +98 -0
  138. package/{template → template-vite}/package.json +15 -27
  139. package/template-vite/scripts/port-next-imports.mjs +70 -0
  140. package/template-vite/src/App.tsx +103 -0
  141. package/template-vite/src/main.tsx +50 -0
  142. package/{template/app/(app)/error.tsx → template-vite/src/pages/_error.tsx} +12 -24
  143. package/{template/app/(app)/loading.tsx → template-vite/src/pages/_loading.tsx} +4 -2
  144. package/template-vite/src/pages/_not-found.tsx +17 -0
  145. package/template-vite/src/pages/dashboard.tsx +48 -0
  146. package/{template/app/(app)/help/page.tsx → template-vite/src/pages/help.tsx} +3 -2
  147. package/{template/app/(app)/library/layout.tsx → template-vite/src/pages/library/_layout.tsx} +18 -16
  148. package/{template/app/(app)/library/all/page.tsx → template-vite/src/pages/library/all.tsx} +1 -1
  149. package/{template/app/(app)/library/new/page.tsx → template-vite/src/pages/library/new.tsx} +12 -18
  150. package/template-vite/src/routes.tsx +72 -0
  151. package/{template/app → template-vite/src/styles}/globals.css +6 -2
  152. package/{template → template-vite}/tsconfig.json +5 -14
  153. package/template-vite/vite.config.ts +52 -0
  154. package/consumer-extras/cursor-rules/exxat-dashboard-view-charts.mdc +0 -53
  155. package/template/.agents/skills/shadcn/SKILL.md +0 -242
  156. package/template/.agents/skills/shadcn/agents/openai.yml +0 -5
  157. package/template/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
  158. package/template/.agents/skills/shadcn/assets/shadcn.png +0 -0
  159. package/template/.agents/skills/shadcn/cli.md +0 -257
  160. package/template/.agents/skills/shadcn/customization.md +0 -202
  161. package/template/.agents/skills/shadcn/evals/evals.json +0 -47
  162. package/template/.agents/skills/shadcn/mcp.md +0 -94
  163. package/template/.agents/skills/shadcn/rules/base-vs-radix.md +0 -306
  164. package/template/.agents/skills/shadcn/rules/composition.md +0 -195
  165. package/template/.agents/skills/shadcn/rules/forms.md +0 -192
  166. package/template/.agents/skills/shadcn/rules/icons.md +0 -101
  167. package/template/.agents/skills/shadcn/rules/styling.md +0 -162
  168. package/template/.cursor/rules/exxat-accessibility.mdc +0 -33
  169. package/template/.cursor/rules/exxat-data-tables.mdc +0 -32
  170. package/template/.cursor/rules/exxat-ds-agents.mdc +0 -26
  171. package/template/.cursor/rules/exxat-list-page-connected-views.mdc +0 -16
  172. package/template/.cursor/rules/exxat-table-properties-drawer.mdc +0 -40
  173. package/template/.nvmrc +0 -1
  174. package/template/.prettierignore +0 -7
  175. package/template/Logo/Exxat_Prism.svg +0 -39
  176. package/template/Logo/Exxat_one.svg +0 -36
  177. package/template/app/(app)/dashboard/loading.tsx +0 -18
  178. package/template/app/(app)/dashboard/page.tsx +0 -36
  179. package/template/app/(app)/layout.tsx +0 -77
  180. package/template/app/global-error.tsx +0 -63
  181. package/template/app/layout.tsx +0 -133
  182. package/template/app/page.tsx +0 -9
  183. package/template/docs/HANDBOOK.md +0 -187
  184. package/template/docs/blueprints/README.md +0 -86
  185. package/template/docs/blueprints/_template.md +0 -91
  186. package/template/docs/blueprints/board-card.md +0 -123
  187. package/template/docs/blueprints/data-table.md +0 -139
  188. package/template/docs/blueprints/key-metrics.md +0 -128
  189. package/template/docs/blueprints/list-page-template.md +0 -123
  190. package/template/docs/blueprints/page-header.md +0 -130
  191. package/template/docs/card-vs-rows-pattern.md +0 -36
  192. package/template/docs/collaboration-access-pattern.md +0 -116
  193. package/template/docs/command-menu-pattern.md +0 -45
  194. package/template/docs/component-selection-guide.md +0 -224
  195. package/template/docs/components-audit-2026-05.md +0 -158
  196. package/template/docs/consumer-upgrade-checklist.md +0 -52
  197. package/template/docs/data-views-pattern.md +0 -185
  198. package/template/docs/drawer-vs-dialog-pattern.md +0 -50
  199. package/template/docs/glossary.md +0 -59
  200. package/template/docs/hub-supported-views-pattern.md +0 -53
  201. package/template/docs/jobs/README.md +0 -59
  202. package/template/docs/jobs/record-detail.md +0 -177
  203. package/template/docs/kpi-flat-band-pattern.md +0 -57
  204. package/template/docs/kpi-strip-max-four-pattern.md +0 -30
  205. package/template/docs/kpi-trend-pattern.md +0 -58
  206. package/template/docs/large-dataset-strategy.md +0 -155
  207. package/template/docs/library-hub-header-pattern.md +0 -25
  208. package/template/docs/migrations/0001-brand-deep-alias-stabilization.md +0 -95
  209. package/template/docs/migrations/0002-exxat-token-namespace.md +0 -154
  210. package/template/docs/migrations/0003-globals-css-canonical.md +0 -110
  211. package/template/docs/migrations/README.md +0 -100
  212. package/template/docs/migrations/_template.md +0 -64
  213. package/template/docs/modern-saas-patterns.md +0 -165
  214. package/template/docs/perf-memory-pattern.md +0 -206
  215. package/template/docs/reference-implementations.md +0 -153
  216. package/template/docs/shell-surface-elevation-pattern.md +0 -52
  217. package/template/docs/token-taxonomy.md +0 -416
  218. package/template/docs/voice-and-tone.md +0 -262
  219. package/template/ecosystem.config.cjs +0 -32
  220. package/template/next.config.mjs +0 -216
  221. package/template/postcss.config.mjs +0 -8
  222. package/template/public/favicon/favicon.ico +0 -0
  223. package/template/tests/setup.ts +0 -26
  224. package/template/vitest.config.ts +0 -18
  225. /package/{template → template-vite}/.cursor/rules/exxat-dashboard-view-charts.mdc +0 -0
  226. /package/{template → template-vite}/.prettierrc +0 -0
  227. /package/{template → template-vite}/AGENTS.md +0 -0
  228. /package/{template → template-vite}/README.md +0 -0
  229. /package/{template → template-vite}/components/.gitkeep +0 -0
  230. /package/{template → template-vite}/components/ask-leo-composer.tsx +0 -0
  231. /package/{template → template-vite}/components/brand-color-picker.tsx +0 -0
  232. /package/{template → template-vite}/components/chart-area-interactive.tsx +0 -0
  233. /package/{template → template-vite}/components/charts-overview.tsx +0 -0
  234. /package/{template → template-vite}/components/collaboration-access-flow.tsx +0 -0
  235. /package/{template → template-vite}/components/columns-client.tsx +0 -0
  236. /package/{template → template-vite}/components/columns-showcase.tsx +0 -0
  237. /package/{template → template-vite}/components/dashboard-promo-banner.tsx +0 -0
  238. /package/{template → template-vite}/components/dashboard-quota-progress-card.tsx +0 -0
  239. /package/{template → template-vite}/components/dashboard-report-charts.tsx +0 -0
  240. /package/{template → template-vite}/components/dashboard-section-heading.tsx +0 -0
  241. /package/{template → template-vite}/components/dashboard-tabs.tsx +0 -0
  242. /package/{template → template-vite}/components/data-table/filter-date-calendar.tsx +0 -0
  243. /package/{template → template-vite}/components/data-table/filter-text-value-input.tsx +0 -0
  244. /package/{template → template-vite}/components/data-table/index.tsx +0 -0
  245. /package/{template → template-vite}/components/data-table/pagination.tsx +0 -0
  246. /package/{template → template-vite}/components/data-table/types.ts +0 -0
  247. /package/{template → template-vite}/components/data-table/use-table-state.test.ts +0 -0
  248. /package/{template → template-vite}/components/data-table/use-table-state.ts +0 -0
  249. /package/{template → template-vite}/components/data-views/board-card-primitives.tsx +0 -0
  250. /package/{template → template-vite}/components/data-views/data-row-list.tsx +0 -0
  251. /package/{template → template-vite}/components/data-views/finder-panel-view.tsx +0 -0
  252. /package/{template → template-vite}/components/data-views/folder-grid-view.tsx +0 -0
  253. /package/{template → template-vite}/components/data-views/hub-table.tsx +0 -0
  254. /package/{template → template-vite}/components/data-views/index.ts +0 -0
  255. /package/{template → template-vite}/components/data-views/list-page-board-card.tsx +0 -0
  256. /package/{template → template-vite}/components/data-views/list-page-board-template.tsx +0 -0
  257. /package/{template → template-vite}/components/data-views/list-page-connected-view-body.tsx +0 -0
  258. /package/{template → template-vite}/components/data-views/list-page-split-details-placeholder.tsx +0 -0
  259. /package/{template → template-vite}/components/data-views/list-page-split-hub-chrome.tsx +0 -0
  260. /package/{template → template-vite}/components/data-views/list-page-split-hub-tokens.ts +0 -0
  261. /package/{template → template-vite}/components/data-views/list-page-tree-column-header.tsx +0 -0
  262. /package/{template → template-vite}/components/data-views/list-page-tree-panel-shell.tsx +0 -0
  263. /package/{template → template-vite}/components/data-views/list-page-view-frame.tsx +0 -0
  264. /package/{template → template-vite}/components/data-views/os-folder-glyph.tsx +0 -0
  265. /package/{template → template-vite}/components/data-views/outline-tree-menu.tsx +0 -0
  266. /package/{template → template-vite}/components/data-views/table-cells.tsx +0 -0
  267. /package/{template → template-vite}/components/dev-chunk-load-recovery.tsx +0 -0
  268. /package/{template → template-vite}/components/export-drawer.test.tsx +0 -0
  269. /package/{template → template-vite}/components/export-drawer.tsx +0 -0
  270. /package/{template → template-vite}/components/exxat-product-logo.tsx +0 -0
  271. /package/{template → template-vite}/components/folder-details-shell.tsx +0 -0
  272. /package/{template → template-vite}/components/form-layout-01.tsx +0 -0
  273. /package/{template → template-vite}/components/hub-tree-panel-view.tsx +0 -0
  274. /package/{template → template-vite}/components/invite-collaborators-drawer.tsx +0 -0
  275. /package/{template → template-vite}/components/key-metrics-ask-leo-bridge.tsx +0 -0
  276. /package/{template → template-vite}/components/key-metrics.tsx +0 -0
  277. /package/{template → template-vite}/components/leo-insight-indicator.tsx +0 -0
  278. /package/{template → template-vite}/components/leo-typing-dots.tsx +0 -0
  279. /package/{template → template-vite}/components/library-board-view.tsx +0 -0
  280. /package/{template → template-vite}/components/library-dashboard-charts.tsx +0 -0
  281. /package/{template → template-vite}/components/library-favorite-button.tsx +0 -0
  282. /package/{template → template-vite}/components/library-new-folder-sheet.tsx +0 -0
  283. /package/{template → template-vite}/components/library-os-folder-view.tsx +0 -0
  284. /package/{template → template-vite}/components/library-page-header.tsx +0 -0
  285. /package/{template → template-vite}/components/library-panel-activator.tsx +0 -0
  286. /package/{template → template-vite}/components/list-hub-status-badge.tsx +0 -0
  287. /package/{template → template-vite}/components/list-page-dashboard-charts.tsx +0 -0
  288. /package/{template → template-vite}/components/onboarding/getting-started.tsx +0 -0
  289. /package/{template → template-vite}/components/onboarding/index.ts +0 -0
  290. /package/{template → template-vite}/components/onboarding/onboarding-01.tsx +0 -0
  291. /package/{template → template-vite}/components/onboarding/onboarding-02.tsx +0 -0
  292. /package/{template → template-vite}/components/onboarding/onboarding-03.tsx +0 -0
  293. /package/{template → template-vite}/components/onboarding/onboarding-04.tsx +0 -0
  294. /package/{template → template-vite}/components/page-header.tsx +0 -0
  295. /package/{template → template-vite}/components/product-switcher.tsx +0 -0
  296. /package/{template → template-vite}/components/product-wordmark.tsx +0 -0
  297. /package/{template → template-vite}/components/settings-appearance-card.tsx +0 -0
  298. /package/{template → template-vite}/components/settings-form-row.tsx +0 -0
  299. /package/{template → template-vite}/components/sidebar/app-sidebar-dynamic.tsx +0 -0
  300. /package/{template → template-vite}/components/sidebar/index.ts +0 -0
  301. /package/{template → template-vite}/components/sidebar/nav-documents.tsx +0 -0
  302. /package/{template → template-vite}/components/sidebar/nav-secondary.tsx +0 -0
  303. /package/{template → template-vite}/components/sidebar/secondary-panel.tsx +0 -0
  304. /package/{template → template-vite}/components/sidebar/sidebar-auto-collapse.tsx +0 -0
  305. /package/{template → template-vite}/components/sidebar/sidebar-auto-open.tsx +0 -0
  306. /package/{template → template-vite}/components/sidebar/sidebar-shell.tsx +0 -0
  307. /package/{template → template-vite}/components/site-header.tsx +0 -0
  308. /package/{template → template-vite}/components/table-properties/column-row.tsx +0 -0
  309. /package/{template → template-vite}/components/table-properties/draggable-list.ts +0 -0
  310. /package/{template → template-vite}/components/table-properties/drawer-button.tsx +0 -0
  311. /package/{template → template-vite}/components/table-properties/drawer.tsx +0 -0
  312. /package/{template → template-vite}/components/table-properties/filter-card.tsx +0 -0
  313. /package/{template → template-vite}/components/table-properties/index.ts +0 -0
  314. /package/{template → template-vite}/components/table-properties/sort-card.tsx +0 -0
  315. /package/{template → template-vite}/components/table-properties/types.ts +0 -0
  316. /package/{template → template-vite}/components/task-list-panel.tsx +0 -0
  317. /package/{template → template-vite}/components/task-priority-badge.tsx +0 -0
  318. /package/{template → template-vite}/components/templates/dedicated-search-landing-template.tsx +0 -0
  319. /package/{template → template-vite}/components/templates/dedicated-search-results-template.tsx +0 -0
  320. /package/{template → template-vite}/components/templates/list-page.tsx +0 -0
  321. /package/{template → template-vite}/components/templates/nested-secondary-panel-shell.tsx +0 -0
  322. /package/{template → template-vite}/components/templates/primary-page-template.tsx +0 -0
  323. /package/{template → template-vite}/components/templates/secondary-panel-hub-template.tsx +0 -0
  324. /package/{template → template-vite}/components/theme-color-sync.tsx +0 -0
  325. /package/{template → template-vite}/components/theme-provider.tsx +0 -0
  326. /package/{template → template-vite}/components/tinted-icon-disc.tsx +0 -0
  327. /package/{template → template-vite}/components/tokens-hub-auxiliary-views.tsx +0 -0
  328. /package/{template → template-vite}/components/tokens-themes-section.tsx +0 -0
  329. /package/{template → template-vite}/components/ui/accordion.tsx +0 -0
  330. /package/{template → template-vite}/components/ui/ai-thinking-surface.tsx +0 -0
  331. /package/{template → template-vite}/components/ui/alert-dialog.tsx +0 -0
  332. /package/{template → template-vite}/components/ui/avatar.tsx +0 -0
  333. /package/{template → template-vite}/components/ui/badge.tsx +0 -0
  334. /package/{template → template-vite}/components/ui/banner.tsx +0 -0
  335. /package/{template → template-vite}/components/ui/breadcrumb.tsx +0 -0
  336. /package/{template → template-vite}/components/ui/button.tsx +0 -0
  337. /package/{template → template-vite}/components/ui/calendar.tsx +0 -0
  338. /package/{template → template-vite}/components/ui/card.tsx +0 -0
  339. /package/{template → template-vite}/components/ui/chart.tsx +0 -0
  340. /package/{template → template-vite}/components/ui/checkbox.tsx +0 -0
  341. /package/{template → template-vite}/components/ui/coach-mark.tsx +0 -0
  342. /package/{template → template-vite}/components/ui/collapsible.tsx +0 -0
  343. /package/{template → template-vite}/components/ui/command.tsx +0 -0
  344. /package/{template → template-vite}/components/ui/context-menu.tsx +0 -0
  345. /package/{template → template-vite}/components/ui/date-picker-field.tsx +0 -0
  346. /package/{template → template-vite}/components/ui/dialog.tsx +0 -0
  347. /package/{template → template-vite}/components/ui/dot-pattern.tsx +0 -0
  348. /package/{template → template-vite}/components/ui/drag-handle-grip.tsx +0 -0
  349. /package/{template → template-vite}/components/ui/dropdown-menu.tsx +0 -0
  350. /package/{template → template-vite}/components/ui/field.tsx +0 -0
  351. /package/{template → template-vite}/components/ui/form.tsx +0 -0
  352. /package/{template → template-vite}/components/ui/hover-card.tsx +0 -0
  353. /package/{template → template-vite}/components/ui/input-group.tsx +0 -0
  354. /package/{template → template-vite}/components/ui/input-mask.tsx +0 -0
  355. /package/{template → template-vite}/components/ui/input.tsx +0 -0
  356. /package/{template → template-vite}/components/ui/kbd.tsx +0 -0
  357. /package/{template → template-vite}/components/ui/label.tsx +0 -0
  358. /package/{template → template-vite}/components/ui/leo-icon.tsx +0 -0
  359. /package/{template → template-vite}/components/ui/payment-card-fields.tsx +0 -0
  360. /package/{template → template-vite}/components/ui/popover.tsx +0 -0
  361. /package/{template → template-vite}/components/ui/radio-group.tsx +0 -0
  362. /package/{template → template-vite}/components/ui/resizable.tsx +0 -0
  363. /package/{template → template-vite}/components/ui/scroll-area.tsx +0 -0
  364. /package/{template → template-vite}/components/ui/select.tsx +0 -0
  365. /package/{template → template-vite}/components/ui/selection-tile-grid.tsx +0 -0
  366. /package/{template → template-vite}/components/ui/separator.tsx +0 -0
  367. /package/{template → template-vite}/components/ui/sheet.tsx +0 -0
  368. /package/{template → template-vite}/components/ui/sidebar.tsx +0 -0
  369. /package/{template → template-vite}/components/ui/skeleton.tsx +0 -0
  370. /package/{template → template-vite}/components/ui/slider.tsx +0 -0
  371. /package/{template → template-vite}/components/ui/sonner.tsx +0 -0
  372. /package/{template → template-vite}/components/ui/status-badge.tsx +0 -0
  373. /package/{template → template-vite}/components/ui/table.tsx +0 -0
  374. /package/{template → template-vite}/components/ui/tabs.tsx +0 -0
  375. /package/{template → template-vite}/components/ui/textarea.tsx +0 -0
  376. /package/{template → template-vite}/components/ui/tip.tsx +0 -0
  377. /package/{template → template-vite}/components/ui/toggle-group.tsx +0 -0
  378. /package/{template → template-vite}/components/ui/toggle-switch.tsx +0 -0
  379. /package/{template → template-vite}/components/ui/toggle.tsx +0 -0
  380. /package/{template → template-vite}/components/ui/tooltip.tsx +0 -0
  381. /package/{template → template-vite}/components/ui/view-segmented-control.tsx +0 -0
  382. /package/{template → template-vite}/components.json +0 -0
  383. /package/{template → template-vite}/contexts/chart-variant-context.tsx +0 -0
  384. /package/{template → template-vite}/contexts/command-menu-context.tsx +0 -0
  385. /package/{template → template-vite}/contexts/dashboard-view-context.tsx +0 -0
  386. /package/{template → template-vite}/contexts/product-context.tsx +0 -0
  387. /package/{template → template-vite}/contexts/system-banner-context.tsx +0 -0
  388. /package/{template → template-vite}/eslint.config.mjs +0 -0
  389. /package/{template → template-vite}/fontawesome-subset.manifest.json +0 -0
  390. /package/{template → template-vite}/hooks/.gitkeep +0 -0
  391. /package/{template → template-vite}/hooks/use-app-theme.ts +0 -0
  392. /package/{template → template-vite}/hooks/use-coach-mark.ts +0 -0
  393. /package/{template → template-vite}/hooks/use-location-hash.ts +0 -0
  394. /package/{template → template-vite}/hooks/use-mobile.ts +0 -0
  395. /package/{template → template-vite}/hooks/use-mod-key-label.ts +0 -0
  396. /package/{template → template-vite}/hooks/use-sidebar-reflow-zoom.ts +0 -0
  397. /package/{template → template-vite}/lib/.gitkeep +0 -0
  398. /package/{template → template-vite}/lib/ask-leo-route-context.ts +0 -0
  399. /package/{template → template-vite}/lib/chart-keyboard-selection.test.ts +0 -0
  400. /package/{template → template-vite}/lib/chart-keyboard-selection.ts +0 -0
  401. /package/{template → template-vite}/lib/chart-line-dash.ts +0 -0
  402. /package/{template → template-vite}/lib/chunk-load-error.ts +0 -0
  403. /package/{template → template-vite}/lib/coach-mark-registry.ts +0 -0
  404. /package/{template → template-vite}/lib/collaborator-access.ts +0 -0
  405. /package/{template → template-vite}/lib/command-menu-config.ts +0 -0
  406. /package/{template → template-vite}/lib/command-menu-search-data.ts +0 -0
  407. /package/{template → template-vite}/lib/conditional-rule-match.ts +0 -0
  408. /package/{template → template-vite}/lib/dashboard-customize-coach-mark.ts +0 -0
  409. /package/{template → template-vite}/lib/dashboard-layout-merge.ts +0 -0
  410. /package/{template → template-vite}/lib/data-list-display-options.ts +0 -0
  411. /package/{template → template-vite}/lib/data-list-persistence.ts +0 -0
  412. /package/{template → template-vite}/lib/data-list-view-registry.ts +0 -0
  413. /package/{template → template-vite}/lib/data-list-view-surface.ts +0 -0
  414. /package/{template → template-vite}/lib/data-list-view.ts +0 -0
  415. /package/{template → template-vite}/lib/data-view-dashboard-storage.ts +0 -0
  416. /package/{template → template-vite}/lib/date-filter.ts +0 -0
  417. /package/{template → template-vite}/lib/dedicated-search-recents.ts +0 -0
  418. /package/{template → template-vite}/lib/dedicated-search-url.ts +0 -0
  419. /package/{template → template-vite}/lib/dev-log.test.ts +0 -0
  420. /package/{template → template-vite}/lib/dev-log.ts +0 -0
  421. /package/{template → template-vite}/lib/discovery-hub.ts +0 -0
  422. /package/{template → template-vite}/lib/editable-target.ts +0 -0
  423. /package/{template → template-vite}/lib/exxat-palette.json +0 -0
  424. /package/{template → template-vite}/lib/exxat-palette.ts +0 -0
  425. /package/{template → template-vite}/lib/floating-sheet-panel.ts +0 -0
  426. /package/{template → template-vite}/lib/full-hub-supported-views.ts +0 -0
  427. /package/{template → template-vite}/lib/hub-connected-view-renderers.ts +0 -0
  428. /package/{template → template-vite}/lib/initials-from-name.ts +0 -0
  429. /package/{template → template-vite}/lib/library-authoring.ts +0 -0
  430. /package/{template → template-vite}/lib/library-dedicated-search.ts +0 -0
  431. /package/{template → template-vite}/lib/library-hub-search.ts +0 -0
  432. /package/{template → template-vite}/lib/library-nav.ts +0 -0
  433. /package/{template → template-vite}/lib/library-recent-searches.ts +0 -0
  434. /package/{template → template-vite}/lib/library-supported-views.ts +0 -0
  435. /package/{template → template-vite}/lib/list-hub-supported-views.ts +0 -0
  436. /package/{template → template-vite}/lib/list-page-table-properties.ts +0 -0
  437. /package/{template → template-vite}/lib/list-status-badges.ts +0 -0
  438. /package/{template → template-vite}/lib/logo-dev.ts +0 -0
  439. /package/{template → template-vite}/lib/mailto.ts +0 -0
  440. /package/{template → template-vite}/lib/mock/dashboard.ts +0 -0
  441. /package/{template → template-vite}/lib/mock/library-folders.ts +0 -0
  442. /package/{template → template-vite}/lib/mock/library-header-collaborators.ts +0 -0
  443. /package/{template → template-vite}/lib/mock/library-inspector.ts +0 -0
  444. /package/{template → template-vite}/lib/mock/library-kpi.ts +0 -0
  445. /package/{template → template-vite}/lib/mock/library.ts +0 -0
  446. /package/{template → template-vite}/lib/mock/navigation.tsx +0 -0
  447. /package/{template → template-vite}/lib/motion-ui.ts +0 -0
  448. /package/{template → template-vite}/lib/product-brand.ts +0 -0
  449. /package/{template → template-vite}/lib/raf-throttle.ts +0 -0
  450. /package/{template → template-vite}/lib/row-height.ts +0 -0
  451. /package/{template → template-vite}/lib/sidebar-state-cookie.ts +0 -0
  452. /package/{template → template-vite}/lib/stock-portrait.ts +0 -0
  453. /package/{template → template-vite}/lib/table-state-lifecycle.ts +0 -0
  454. /package/{template → template-vite}/lib/utils.test.ts +0 -0
  455. /package/{template → template-vite}/lib/utils.ts +0 -0
  456. /package/{template → template-vite}/public/.gitkeep +0 -0
  457. /package/{template → template-vite}/public/Illustration/Rotation.svg +0 -0
  458. /package/{template → template-vite}/public/avatars/user.svg +0 -0
  459. /package/{template/public → template-vite/public/favicon}/favicon.ico +0 -0
  460. /package/{template/app → template-vite/public}/favicon.ico +0 -0
  461. /package/{template → template-vite}/public/folders/icons8-folder-windows-11.svg +0 -0
  462. /package/{template → template-vite}/public/logos/exxat-one.svg +0 -0
  463. /package/{template → template-vite}/public/logos/exxat-prism.svg +0 -0
  464. /package/{template → template-vite}/public/mock-schools/emory.svg +0 -0
  465. /package/{template → template-vite}/public/mock-schools/rush.svg +0 -0
  466. /package/{template → template-vite}/scripts/fontawesome-subset-audit.mjs +0 -0
  467. /package/{template → template-vite}/scripts/pm2-startup-macos.sh +0 -0
  468. /package/{template → template-vite}/skills-lock.json +0 -0
  469. /package/{template/app/(app)/columns/page.tsx → template-vite/src/pages/columns.tsx} +0 -0
  470. /package/{template/app/(app)/library/find/page.tsx → template-vite/src/pages/library/find.tsx} +0 -0
  471. /package/{template/app/(app)/library/page.tsx → template-vite/src/pages/library/index.tsx} +0 -0
  472. /package/{template/app/(app)/library/list/page.tsx → template-vite/src/pages/library/list.tsx} +0 -0
  473. /package/{template/app/(app)/settings/page.tsx → template-vite/src/pages/settings.tsx} +0 -0
  474. /package/{template/app/(app)/tokens-themes/page.tsx → template-vite/src/pages/tokens-themes.tsx} +0 -0
  475. /package/{template → template-vite}/stores/app-store.ts +0 -0
  476. /package/{template → template-vite}/types/react-payment-inputs.d.ts +0 -0
@@ -0,0 +1,142 @@
1
+ # WCAG 2.1 AA — Full Accessibility Checklist
2
+
3
+ This is the single source of truth for all accessibility requirements in Exxat DS. Every component, edit, or feature must pass ALL applicable sections before it is considered done.
4
+
5
+ ---
6
+
7
+ ## 1. Interactive Elements
8
+
9
+ - Every `<button>` has visible text OR `aria-label`
10
+ - Icon-only buttons: `aria-label` + wrap with `<Tip>` (from `@/components/ui/tip`) — no exceptions
11
+ - Stateful buttons describe current state: `aria-label="Sort ascending — click to sort descending"`
12
+ - Links describe destination (no "click here"); new-window links: "(opens in new tab)"
13
+ - No nested interactive elements (button inside button, anchor inside button)
14
+ - Custom clickable `<div>`/`<span>`: `role="button"` + `tabIndex={0}` + `onKeyDown` (Enter/Space)
15
+ - Disabled: use native `disabled` or `aria-disabled="true"`; keep discoverable by screen readers
16
+
17
+ ## 2. Keyboard
18
+
19
+ - ALL interactions reachable by keyboard alone — zero mouse-only features
20
+ - Tab order follows visual reading order
21
+ - Skip link → `#main-content` (verify after layout changes)
22
+ - `Enter`/`Space` activate buttons; `Escape` closes modals/popovers; `Arrow keys` in composite widgets
23
+ - `focus-visible:` ring on ALL interactive elements (≥ 2px, 3:1 contrast against adjacent colors)
24
+ - Hidden elements (opacity-0): `group-focus-within:opacity-100` for keyboard visibility
25
+ - Modal: focus trapped inside, returns to trigger on close
26
+ - Multi-step forms: move focus to step heading on advance (`tabIndex={-1}` + `.focus()`)
27
+ - Popover/Dropdown: `initialFocus` on first interactive child
28
+
29
+ ## 3. Forms & Inputs
30
+
31
+ - Every `<input>`/`<textarea>`/`<select>` has `<label>` (visible or `sr-only`) OR `aria-label`
32
+ - Labels use `htmlFor` matching input `id`; placeholder is NOT a label
33
+ - Errors: `aria-describedby` → error element + `aria-invalid="true"` + visible descriptive text
34
+ - Required fields: `aria-required="true"` or HTML `required`
35
+ - Grouped controls: `<fieldset>` + `<legend>` or `role="group"` + `aria-labelledby`
36
+ - Dates: ALWAYS Calendar + Popover picker; format MM/DD/YYYY; `initialFocus` on Calendar open
37
+ - Toggle/Switch: `role="switch"` + `aria-checked` + `<label htmlFor>`
38
+
39
+ ## 4. Semantic Structure
40
+
41
+ - One `<main>` per page with `id="main-content"` + `tabIndex={-1}` (required for skip link)
42
+ - Heading hierarchy: one `<h1>` (via `PageHeader`), logical `<h2>` → `<h3>` (no skipping)
43
+ - `SiteHeader` title in the breadcrumb bar is NOT an `<h1>`
44
+ - Multiple `<nav>` elements: each must have `aria-label`
45
+ - Modal/Sheet/Dialog: `DialogTitle`/`SheetTitle` ALWAYS present — use `sr-only` if visually hidden
46
+ - `<aside>` panels: `aria-label` (e.g. "Ask Leo assistant", "Rotation navigation")
47
+ - Data tables: `<table>` + `<thead>` + `<th scope="col">`; sortable columns: `aria-sort` on `<th>`
48
+ - Listbox: `role="listbox"` + `role="option"` + `aria-selected`
49
+
50
+ ## 5. Tooltips
51
+
52
+ - Use `<Tip>` from `@/components/ui/tip` — NEVER the HTML `title` attribute
53
+ - Open on BOTH hover AND keyboard focus
54
+ - Every icon-only button gets `<Tip>` — no exceptions
55
+ - Tooltip content is supplementary; never the sole source of critical information
56
+
57
+ ## 6. Color & Contrast
58
+
59
+ - **Normal text**: 4.5:1 ratio
60
+ - **Large text** (≥18px regular / ≥14px bold): 3:1
61
+ - **UI components** (borders, focus rings): 3:1
62
+ - Status conveyed NEVER by color alone — always include text label or icon alongside
63
+ - Error states: red + icon + descriptive text (not just red color)
64
+ - Decorative icons: `aria-hidden="true"`
65
+ - All ratios apply in BOTH light AND dark themes
66
+ - Hover states visibly distinct in dark mode (brand-tinted `--accent`, not grey)
67
+ - Test against all themes: Lavender × Prism × light × dark × high-contrast
68
+
69
+ ## 7. Dynamic Content
70
+
71
+ - Count changes (filter results, badge updates): `aria-live="polite"` on the element
72
+ - Toast/snackbar notifications: `role="status"` or `aria-live="polite"`
73
+ - Loading states: `aria-busy="true"` on the loading container
74
+ - Progress indicators: `role="progressbar"` + `aria-valuenow/min/max`
75
+
76
+ ## 8. Images & Media
77
+
78
+ - Informative images: descriptive `alt` text
79
+ - Decorative images: `alt=""` or `aria-hidden="true"`
80
+ - SVG icons accompanying text: `aria-hidden="true"`
81
+ - Standalone SVG (no adjacent text): `role="img"` + `aria-label`
82
+
83
+ ## 9. ARIA Roles — Critical Rules
84
+
85
+ ### Tabs
86
+ - `role="tablist"` → only `role="tab"` (or equivalent tab semantics) as direct children
87
+ - **Never** put `role="button"`, menus (`aria-haspopup`), remove buttons, or other controls **inside** the `tablist` container
88
+ - Tab panels: `role="tabpanel"` + `aria-labelledby`
89
+
90
+ ### View Switchers (tabs + per-tab settings + remove)
91
+ - These are composite toolbar widgets — use `role="toolbar"` + `aria-label`
92
+ - Use `aria-pressed` on toggle-style controls within the toolbar
93
+ - Do NOT misuse `tablist`/`tab` for mixed-control toolbars
94
+
95
+ ### Touch Targets (WCAG 2.2 — 2.5.8)
96
+ - Interactive controls: minimum **24×24 CSS pixels**, OR 24px spacing so hit areas don't overlap
97
+ - Icon-only buttons: `size-6` or `min-h-6 min-w-6` — **never** `size-4` as the sole target
98
+
99
+ ## 10. Component-Specific Requirements
100
+
101
+ | Component | Requirements |
102
+ |-----------|-------------|
103
+ | Sidebar nav | `aria-current="page"` on active link; badges include value in `aria-label`; collapsed state → tooltip shows label |
104
+ | DataTable header column menu | `group-focus-within/th:opacity-100`; wrap trigger with `<Tip label="Column options">` |
105
+ | Sort button | `<Tip label="Sort by {col}">` + `aria-sort` attribute on `<th>` |
106
+ | Selection checkbox | `aria-label="Select {row name}"` |
107
+ | Tabs | `role="tablist"` / `role="tab"` / `role="tabpanel"` + `aria-selected` + arrow key navigation |
108
+ | Dropdown | `aria-haspopup` + `aria-expanded` (Radix handles automatically) |
109
+ | Filter pill | Keyboard-navigable; Escape closes the popover |
110
+ | Modal/Dialog | Focus trap + Escape closes + `aria-hidden` on background (Radix handles automatically) |
111
+ | Sheet/Drawer | `SheetTitle` required; floating style defined in component reuse rules |
112
+ | Ask Leo sidebar | `<aside aria-label="Ask Leo assistant">` |
113
+
114
+ ## 11. Pre-Completion Testing Protocol
115
+
116
+ Run for EVERY task before marking done:
117
+
118
+ 1. **Keyboard:** Tab through all changed elements — can you reach and activate every control without a mouse?
119
+ 2. **Focus ring:** Visible on every interactive element after tabbing to it?
120
+ 3. **Tooltips:** Every icon-only button has `<Tip>`?
121
+ 4. **Labels:** Every input has a label? Every button has text or `aria-label`?
122
+ 5. **Color contrast:** Text ≥ 4.5:1, UI ≥ 3:1? (Check with browser devtools or axe)
123
+ 6. **Dark mode:** Repeat contrast check in dark theme
124
+ 7. **200% zoom:** Layout usable at 200% browser zoom?
125
+ 8. **axe audit:** Run axe (DevTools extension) on any page where you touched views toolbar, tabs, or primary list surfaces
126
+
127
+ ## Quick Reference Card
128
+
129
+ ```
130
+ Icon button → aria-label + <Tip>
131
+ Toggle/Switch → role="switch" + aria-checked
132
+ Dropdown → aria-haspopup + aria-expanded (Radix auto)
133
+ Tab → role="tab" + aria-selected
134
+ Sort column → aria-sort on <th>
135
+ Live count → aria-live="polite"
136
+ Error message → id + aria-describedby on input
137
+ Date input → Calendar + Popover + initialFocus
138
+ Modal → DialogTitle (required) + focus trap
139
+ Progress → role="progressbar" + aria-valuenow/min/max
140
+ Tablist → only tab-role children (no buttons/menus inside)
141
+ View switcher → role="toolbar" + aria-label + aria-pressed
142
+ ```
@@ -0,0 +1,169 @@
1
+ # Coach Marks — Implementation Guide
2
+
3
+ > **Use coach marks for onboarding flows and feature discovery.** Every tour is defined once, targets elements by CSS selector, and is managed centrally from the Settings page.
4
+
5
+ ---
6
+
7
+ ## Architecture
8
+
9
+ | Component | Location | Purpose |
10
+ |-----------|----------|---------|
11
+ | `CoachMark` | `@/components/ui/coach-mark` | Selector-targeted popover with spotlight overlay, brand-colored background |
12
+ | `useCoachMark` | `@/hooks/use-coach-mark` | Flow state manager — step navigation, localStorage persistence, element targeting |
13
+ | `CoachMarkStep` | `@/hooks/use-coach-mark` (type) | Step definition — target selector, side, align, title, description, optional image |
14
+ | Coach mark registry | `@/lib/coach-mark-registry` | Central definition of all flows for the Settings page |
15
+ | Settings page | `@/components/settings-client` + `app/(app)/settings/page.tsx` | UI to view, reset, and preview all coach mark flows |
16
+
17
+ ---
18
+
19
+ ## How It Works
20
+
21
+ 1. **Selector-based targeting** — each step has a `target` CSS selector (e.g. `[aria-label='Properties']`). The coach mark finds the element, scrolls it into view, and positions a popover next to it.
22
+ 2. **Spotlight overlay** — a semi-transparent backdrop with an SVG mask cutout highlights the target element with a ring.
23
+ 3. **Brand background** — the popover uses `bg-brand-deep text-white` for high visibility. Buttons are white/inverted.
24
+ 4. **localStorage persistence** — once completed or skipped, a flow is marked as dismissed and won't show again unless reset from Settings.
25
+ 5. **Per-step positioning** — each step can specify its own `side` and `align` for optimal placement relative to the target.
26
+
27
+ ---
28
+
29
+ ## Adding a New Coach Mark Flow
30
+
31
+ ### Step 1 — Define the steps
32
+
33
+ ```tsx
34
+ import type { CoachMarkStep } from "@/hooks/use-coach-mark"
35
+
36
+ const MY_TOUR_STEPS: CoachMarkStep[] = [
37
+ {
38
+ id: "step-1",
39
+ target: "[aria-label='My Widget']", // CSS selector for the target element
40
+ side: "bottom", // popover side: top | bottom | left | right
41
+ align: "start", // popover alignment: start | center | end
42
+ title: "Meet My Widget",
43
+ description: "This widget helps you do X. Click to explore.",
44
+ },
45
+ {
46
+ id: "step-2",
47
+ target: "button[aria-label='Settings']",
48
+ side: "left",
49
+ align: "center",
50
+ title: "Customise Settings",
51
+ description: "Open settings to configure Y and Z.",
52
+ image: "https://example.com/screenshot.jpg", // optional hero image
53
+ imageAlt: "Settings panel screenshot", // required when image is provided
54
+ },
55
+ ]
56
+ ```
57
+
58
+ ### Step 2 — Wire the hook and component
59
+
60
+ ```tsx
61
+ import { CoachMark } from "@/components/ui/coach-mark"
62
+ import { useCoachMark } from "@/hooks/use-coach-mark"
63
+
64
+ function MyPageClient() {
65
+ const tour = useCoachMark({
66
+ flowId: "my-feature-tour", // unique ID — used as localStorage key
67
+ steps: MY_TOUR_STEPS,
68
+ delay: 1200, // ms before first appearance
69
+ })
70
+
71
+ return (
72
+ <>
73
+ <CoachMark state={tour} />
74
+ {/* rest of your page */}
75
+ </>
76
+ )
77
+ }
78
+ ```
79
+
80
+ **Key points:**
81
+ - `CoachMark` renders via portal — place it anywhere, it does NOT wrap children
82
+ - The component handles element lookup, scrolling, spotlight overlay, and positioning
83
+ - On flow completion, `localStorage` marks the flow as dismissed
84
+
85
+ ### Step 3 — Register in the coach mark registry
86
+
87
+ Add your flow to `lib/coach-mark-registry.ts`:
88
+
89
+ ```ts
90
+ {
91
+ id: "my-feature-tour",
92
+ name: "My Feature Tour",
93
+ description: "Introduces the main controls and settings for My Feature.",
94
+ page: "My Feature",
95
+ pageUrl: "/my-feature",
96
+ stepCount: 2,
97
+ }
98
+ ```
99
+
100
+ This makes it appear in the Settings page where users can reset or preview it.
101
+
102
+ ---
103
+
104
+ ## Variants
105
+
106
+ | Variant | How to use |
107
+ |---------|-----------|
108
+ | **Single step** | Pass a 1-item array to `steps` — no step indicator shown, button says "Got it" |
109
+ | **Multi-step flow** | Pass 2+ items — shows step dots, Skip, Back, Next buttons |
110
+ | **With image** | Set `image` + `imageAlt` on the step — hero image appears above the content |
111
+ | **Without image** | Omit `image` — text-only popover |
112
+
113
+ ---
114
+
115
+ ## Target Selector Best Practices
116
+
117
+ Use stable, semantic selectors that survive refactors:
118
+
119
+ | Prefer | Avoid |
120
+ |--------|-------|
121
+ | `[aria-label='Properties']` | `.css-class-name` |
122
+ | `[role='toolbar'][aria-label='Views']` | `div:nth-child(3)` |
123
+ | `button[aria-label='Search']` | `#auto-generated-id` |
124
+ | `h1` | `.page-header > div > h1` |
125
+
126
+ If no stable selector exists, add a `data-coach-mark="step-name"` attribute to the target element.
127
+
128
+ ---
129
+
130
+ ## Existing Flows
131
+
132
+ | Flow ID | Page | Steps | What it covers |
133
+ |---------|------|-------|---------------|
134
+ | `dashboard-tour` | Dashboard | 4 | Welcome, Key Metrics, AI Insights, Ask Leo |
135
+ | `placements-views-tour` | Placements | 6 | View tabs, view settings, add view, search, filter, Properties |
136
+
137
+ ---
138
+
139
+ ## Settings Page
140
+
141
+ The Settings page at `/settings` (`components/settings-client.tsx`) provides:
142
+
143
+ - **List of all registered flows** from `lib/coach-mark-registry.ts`
144
+ - **Status** — Completed vs Active per flow
145
+ - **Reset** — clears localStorage so the tour replays on next visit
146
+ - **Preview** — resets the flow and navigates to its page
147
+ - **Reset all** — clears all coach mark dismissals
148
+
149
+ ---
150
+
151
+ ## Utilities (exported from `use-coach-mark`)
152
+
153
+ | Function | Purpose |
154
+ |----------|---------|
155
+ | `getAllCoachMarkKeys()` | List all dismissed coach mark flow IDs |
156
+ | `resetCoachMarkFlow(flowId)` | Clear dismissal for one flow |
157
+ | `resetAllCoachMarks()` | Clear all dismissals |
158
+
159
+ ---
160
+
161
+ ## Rules
162
+
163
+ 1. **Always register new flows** in `lib/coach-mark-registry.ts` so they appear in Settings
164
+ 2. **Use CSS selectors based on ARIA attributes** — they're stable and semantic
165
+ 3. **Brand background is mandatory** — coach marks use `bg-brand-deep text-white`, not `bg-popover`
166
+ 4. **No wrapping children** — `CoachMark` targets elements by selector, never wraps them
167
+ 5. **Keep flows short** — 3–6 steps per flow is ideal; split longer tours into separate flows
168
+ 6. **Add `data-coach-mark` attributes** if no stable selector exists on the target element
169
+ 7. **Set appropriate `delay`** — 800–1200ms gives the page time to render before the first step appears