@exxatdesignux/ui 0.2.16 → 0.2.18

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 (111) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +149 -4
  3. package/consumer-extras/cursor-skills/exxat-ds-skill/references/accessibility.md +142 -0
  4. package/consumer-extras/cursor-skills/exxat-ds-skill/references/coach-marks.md +169 -0
  5. package/consumer-extras/cursor-skills/exxat-ds-skill/references/data-table-pattern.md +382 -0
  6. package/consumer-extras/cursor-skills/exxat-kpi-flat-band/SKILL.md +38 -0
  7. package/consumer-extras/cursor-skills/exxat-mono-ids/SKILL.md +56 -0
  8. package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +19 -0
  9. package/consumer-extras/patterns/data-views-pattern.md +2 -0
  10. package/consumer-extras/patterns/kpi-flat-band-pattern.md +57 -0
  11. package/consumer-extras/patterns/shell-surface-elevation-pattern.md +52 -0
  12. package/package.json +3 -3
  13. package/src/components/ui/banner.tsx +2 -0
  14. package/src/components/ui/chart.tsx +57 -2
  15. package/src/components/ui/sidebar.tsx +3 -2
  16. package/src/globals.css +65 -14
  17. package/src/theme.css +3 -3
  18. package/template/.claude/skills/exxat-ds-skill/SKILL.md +1 -1
  19. package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +1 -1
  20. package/template/.cursor/rules/exxat-mono-ids.mdc +30 -0
  21. package/template/AGENTS.md +27 -17
  22. package/template/app/(app)/data-list/page.tsx +2 -2
  23. package/template/app/(app)/error.tsx +22 -6
  24. package/template/app/(app)/layout.tsx +13 -6
  25. package/template/app/(app)/question-bank/layout.tsx +18 -5
  26. package/template/app/(app)/question-bank/new/page.tsx +58 -0
  27. package/template/app/global-error.tsx +63 -0
  28. package/template/app/globals.css +151 -14
  29. package/template/app/layout.tsx +43 -5
  30. package/template/components/app-sidebar.tsx +68 -33
  31. package/template/components/ask-leo-sidebar.tsx +0 -2
  32. package/template/components/brand-color-picker.tsx +344 -0
  33. package/template/components/compliance-list-view.tsx +33 -51
  34. package/template/components/compliance-table.tsx +4 -0
  35. package/template/components/data-table/index.tsx +99 -91
  36. package/template/components/data-table/pagination.tsx +0 -1
  37. package/template/components/data-table/types.ts +4 -1
  38. package/template/components/data-table/use-table-state.ts +276 -100
  39. package/template/components/data-views/data-row-list.tsx +183 -0
  40. package/template/components/data-views/index.ts +7 -3
  41. package/template/components/data-views/os-folder-glyph.tsx +8 -0
  42. package/template/components/dev-chunk-load-recovery.tsx +41 -0
  43. package/template/components/export-drawer.tsx +1 -1
  44. package/template/components/exxat-product-logo.tsx +168 -317
  45. package/template/components/invite-collaborators-drawer.tsx +5 -3
  46. package/template/components/key-metrics.tsx +122 -62
  47. package/template/components/new-placement-form.tsx +4 -2
  48. package/template/components/new-question-composer.tsx +2208 -0
  49. package/template/components/page-breadcrumb-trail.tsx +131 -0
  50. package/template/components/page-header.tsx +2 -1
  51. package/template/components/{data-views/placement-board-card.tsx → placement-board-card.tsx} +2 -2
  52. package/template/components/placement-detail.tsx +1 -1
  53. package/template/components/placements-board-view.tsx +1 -1
  54. package/template/components/{data-list-client.tsx → placements-client.tsx} +9 -7
  55. package/template/components/placements-list-view.tsx +19 -133
  56. package/template/components/{data-list-table-cells.test.tsx → placements-table-cells.test.tsx} +2 -2
  57. package/template/components/{data-list-table-cells.tsx → placements-table-cells.tsx} +1 -1
  58. package/template/components/placements-table-columns.tsx +2 -2
  59. package/template/components/{data-list-table.tsx → placements-table.tsx} +42 -66
  60. package/template/components/product-switcher.tsx +24 -7
  61. package/template/components/product-wordmark.tsx +282 -0
  62. package/template/components/question-bank-client.tsx +20 -2
  63. package/template/components/question-bank-hub-client.tsx +105 -115
  64. package/template/components/question-bank-list-view.tsx +30 -54
  65. package/template/components/question-bank-new-folder-sheet.tsx +1 -1
  66. package/template/components/question-bank-secondary-nav.tsx +0 -3
  67. package/template/components/question-bank-table.tsx +19 -6
  68. package/template/components/rotations-empty-state.tsx +3 -0
  69. package/template/components/secondary-panel.tsx +23 -3
  70. package/template/components/settings-appearance-card.tsx +584 -141
  71. package/template/components/sidebar-shell.tsx +2 -1
  72. package/template/components/site-header.tsx +36 -31
  73. package/template/components/sites-list-view.tsx +31 -36
  74. package/template/components/sites-table.tsx +4 -0
  75. package/template/components/table-properties/drawer-button.tsx +38 -20
  76. package/template/components/table-properties/drawer.tsx +17 -14
  77. package/template/components/team-client.tsx +1 -1
  78. package/template/components/team-list-view.tsx +34 -50
  79. package/template/components/team-table.tsx +8 -3
  80. package/template/components/templates/list-page.tsx +12 -9
  81. package/template/components/templates/nested-secondary-panel-shell.tsx +10 -4
  82. package/template/components/ui/dot-pattern.tsx +50 -26
  83. package/template/components/ui/leo-icon.tsx +23 -3
  84. package/template/contexts/product-context.tsx +70 -7
  85. package/template/contexts/system-banner-context.tsx +112 -4
  86. package/template/docs/data-views-pattern.md +2 -0
  87. package/template/docs/kpi-flat-band-pattern.md +57 -0
  88. package/template/docs/kpi-strip-max-four-pattern.md +1 -0
  89. package/template/docs/shell-surface-elevation-pattern.md +52 -0
  90. package/template/eslint.config.mjs +18 -0
  91. package/template/hooks/use-sidebar-reflow-zoom.ts +21 -11
  92. package/template/lib/chunk-load-error.ts +13 -0
  93. package/template/lib/conditional-rule-match.ts +87 -22
  94. package/template/lib/data-list-persistence.ts +57 -257
  95. package/template/lib/data-list-view.ts +6 -0
  96. package/template/lib/dev-log.test.ts +6 -5
  97. package/template/lib/exxat-palette.json +1462 -0
  98. package/template/lib/exxat-palette.ts +136 -0
  99. package/template/lib/list-page-table-properties.ts +1 -1
  100. package/template/lib/list-status-badges.ts +1 -1
  101. package/template/lib/mailto.ts +29 -0
  102. package/template/lib/placement-board-card-layout.ts +1 -1
  103. package/template/lib/product-brand.ts +268 -0
  104. package/template/lib/question-bank-authoring.ts +308 -0
  105. package/template/lib/question-bank-nav.ts +44 -0
  106. package/template/lib/raf-throttle.ts +45 -0
  107. package/template/lib/sidebar-state-cookie.ts +9 -0
  108. package/template/lib/table-state-lifecycle.ts +521 -0
  109. package/template/next.config.mjs +156 -0
  110. package/template/package.json +3 -3
  111. package/template/stores/app-store.ts +46 -1
@@ -50,7 +50,7 @@
50
50
  "react-hook-form": "^7.72.0",
51
51
  "react-resizable-panels": "^4.10.0",
52
52
  "recharts": "^2.15.4",
53
- "shadcn": "^4.1.0",
53
+ "shadcn": "^4.7.0",
54
54
  "sonner": "^2.0.7",
55
55
  "tailwind-merge": "^3.5.0",
56
56
  "tw-animate-css": "^1.4.0",
@@ -71,8 +71,8 @@
71
71
  "eslint": "^9.39.4",
72
72
  "eslint-config-next": "16.2.6",
73
73
  "jsdom": "^26.1.0",
74
- "pm2": "^6.0.14",
75
- "postcss": "^8",
74
+ "pm2": "^7.0.1",
75
+ "postcss": "^8.5.14",
76
76
  "prettier": "^3.8.1",
77
77
  "prettier-plugin-tailwindcss": "^0.7.2",
78
78
  "tailwindcss": "^4.2.1",
@@ -11,12 +11,37 @@
11
11
  import { create } from "zustand"
12
12
  import { persist } from "zustand/middleware"
13
13
 
14
- export type Product = "exxat-one" | "exxat-prism"
14
+ export type Product = "exxat-one" | "exxat-prism" | "exxat-assessment" | "exxat-custom"
15
+
16
+ export interface CustomProductBrand {
17
+ suffix: string
18
+ brandColor: string
19
+ }
20
+
21
+ export const DEFAULT_CUSTOM_PRODUCT_BRAND: CustomProductBrand = {
22
+ suffix: "Assessment",
23
+ brandColor: "oklch(0.7 0.0913 159.88)",
24
+ }
15
25
 
16
26
  interface AppState {
17
27
  /** Currently active product — drives theme class and sidebar logo */
18
28
  product: Product
19
29
  setProduct: (product: Product) => void
30
+ customProductBrand: CustomProductBrand | null
31
+ setCustomProductBrand: (brand: CustomProductBrand | null) => void
32
+ /**
33
+ * Per-product brand color overrides — drives the mark gradient + wordmark
34
+ * suffix tint when the user picks a custom color for a built-in product
35
+ * (Exxat One / Prism / Assessment) or the custom slot. Settings →
36
+ * Appearance → Product uses these so the color picker actually re-colours
37
+ * the rendered logo (mark + suffix), instead of just the unused `brandColor`
38
+ * on the underlying `ProductBrandConfig`.
39
+ */
40
+ productBrandColors: Partial<Record<Product, string>>
41
+ setProductBrandColor: (product: Product, color: string | null) => void
42
+ hiddenProductIds: Product[]
43
+ hideProduct: (product: Product) => void
44
+ showProduct: (product: Product) => void
20
45
  }
21
46
 
22
47
  export const useAppStore = create<AppState>()(
@@ -24,6 +49,26 @@ export const useAppStore = create<AppState>()(
24
49
  (set) => ({
25
50
  product: "exxat-one",
26
51
  setProduct: (product) => set({ product }),
52
+ customProductBrand: DEFAULT_CUSTOM_PRODUCT_BRAND,
53
+ setCustomProductBrand: (customProductBrand) => set({ customProductBrand }),
54
+ productBrandColors: {},
55
+ setProductBrandColor: (product, color) =>
56
+ set(state => {
57
+ const next = { ...state.productBrandColors }
58
+ if (color && color.trim()) {
59
+ next[product] = color.trim()
60
+ } else {
61
+ delete next[product]
62
+ }
63
+ return { productBrandColors: next }
64
+ }),
65
+ hiddenProductIds: [],
66
+ hideProduct: (product) => set(state => ({
67
+ hiddenProductIds: Array.from(new Set([...state.hiddenProductIds, product])),
68
+ })),
69
+ showProduct: (product) => set(state => ({
70
+ hiddenProductIds: state.hiddenProductIds.filter(id => id !== product),
71
+ })),
27
72
  }),
28
73
  {
29
74
  name: "exxat-app",