@exxatdesignux/ui 0.3.0 → 0.4.1

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 (214) hide show
  1. package/CHANGELOG.md +701 -6
  2. package/README.md +138 -0
  3. package/bin/init.mjs +134 -31
  4. package/consumer-extras/cursor-rules/exxat-board-cards.mdc +1 -1
  5. package/consumer-extras/cursor-rules/exxat-centralized-list-dataset.mdc +2 -2
  6. package/consumer-extras/cursor-rules/exxat-collaboration-access.mdc +1 -1
  7. package/consumer-extras/cursor-rules/exxat-data-tables.mdc +2 -0
  8. package/consumer-extras/cursor-rules/exxat-dedicated-search-surfaces.mdc +1 -1
  9. package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +3 -3
  10. package/consumer-extras/cursor-rules/exxat-library-hub-header.mdc +28 -0
  11. package/consumer-extras/cursor-rules/exxat-mono-ids.mdc +1 -1
  12. package/consumer-extras/cursor-rules/exxat-person-identity-display.mdc +1 -1
  13. package/consumer-extras/cursor-rules/exxat-primary-nav-secondary-panel.mdc +6 -6
  14. package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +1 -1
  15. package/consumer-extras/cursor-skills/exxat-board-cards/SKILL.md +2 -2
  16. package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +1 -1
  17. package/consumer-extras/cursor-skills/exxat-collaboration-access/SKILL.md +3 -3
  18. package/consumer-extras/cursor-skills/exxat-dedicated-search-surfaces/SKILL.md +2 -2
  19. package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +7 -7
  20. package/consumer-extras/cursor-skills/exxat-kpi-flat-band/SKILL.md +1 -1
  21. package/consumer-extras/cursor-skills/exxat-list-page-view-shells/SKILL.md +1 -1
  22. package/consumer-extras/cursor-skills/exxat-mono-ids/SKILL.md +4 -4
  23. package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +8 -8
  24. package/consumer-extras/cursor-skills/exxat-token-economy/SKILL.md +277 -0
  25. package/consumer-extras/handbook/HANDBOOK.md +2 -0
  26. package/consumer-extras/handbook/glossary.md +2 -1
  27. package/consumer-extras/handbook/reference-implementations.md +31 -4
  28. package/consumer-extras/patterns/collaboration-access-pattern.md +7 -7
  29. package/consumer-extras/patterns/data-views-pattern.md +18 -16
  30. package/consumer-extras/patterns/kpi-flat-band-pattern.md +2 -2
  31. package/dist/components/data-table/index.js +2 -2
  32. package/dist/components/data-table/index.js.map +1 -1
  33. package/dist/components/data-table/pagination.js +3 -3
  34. package/dist/components/data-table/pagination.js.map +1 -1
  35. package/dist/components/data-table/use-table-state.d.ts +1 -1
  36. package/dist/components/data-table/use-table-state.js.map +1 -1
  37. package/dist/components/data-views/data-row-list.js.map +1 -1
  38. package/dist/components/data-views/finder-panel-view.d.ts +1 -1
  39. package/dist/components/data-views/finder-panel-view.js.map +1 -1
  40. package/dist/components/data-views/hub-table.d.ts +9 -3
  41. package/dist/components/data-views/hub-table.js +262 -40
  42. package/dist/components/data-views/hub-table.js.map +1 -1
  43. package/dist/components/data-views/index.js +262 -40
  44. package/dist/components/data-views/index.js.map +1 -1
  45. package/dist/components/data-views/list-page-split-hub-tokens.d.ts +2 -2
  46. package/dist/components/data-views/list-page-split-hub-tokens.js.map +1 -1
  47. package/dist/components/data-views/list-page-tree-column-header.d.ts +1 -1
  48. package/dist/components/data-views/list-page-tree-column-header.js.map +1 -1
  49. package/dist/components/data-views/list-page-tree-panel-shell.js.map +1 -1
  50. package/dist/components/data-views/os-folder-glyph.d.ts +1 -1
  51. package/dist/components/data-views/os-folder-glyph.js.map +1 -1
  52. package/dist/components/ui/avatar.d.ts +1 -1
  53. package/dist/components/ui/key-metrics.js.map +1 -1
  54. package/dist/index.js +136 -39
  55. package/dist/index.js.map +1 -1
  56. package/package.json +3 -2
  57. package/src/components/data-table/index.tsx +2 -2
  58. package/src/components/data-table/pagination.tsx +5 -1
  59. package/src/components/data-table/use-table-state.ts +1 -1
  60. package/src/components/data-views/data-row-list.tsx +1 -1
  61. package/src/components/data-views/finder-panel-view.tsx +2 -2
  62. package/src/components/data-views/hub-table.tsx +149 -41
  63. package/src/components/data-views/list-page-split-hub-tokens.ts +2 -2
  64. package/src/components/data-views/list-page-tree-column-header.tsx +1 -1
  65. package/src/components/data-views/os-folder-glyph.tsx +1 -1
  66. package/src/components/ui/key-metrics.tsx +1 -1
  67. package/template/.claude/skills/exxat-ds-skill/SKILL.md +8 -7
  68. package/template/.cursor/rules/exxat-accessibility.mdc +1 -1
  69. package/template/.cursor/rules/exxat-command-menu.mdc +1 -1
  70. package/template/.cursor/rules/exxat-dashboard-view-charts.mdc +6 -6
  71. package/template/.cursor/rules/exxat-data-tables.mdc +3 -3
  72. package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +5 -5
  73. package/template/.cursor/rules/exxat-mono-ids.mdc +1 -1
  74. package/template/.cursor/rules/exxat-page-vs-drawer.mdc +1 -1
  75. package/template/.cursor/rules/exxat-table-properties-drawer.mdc +1 -1
  76. package/template/AGENTS.md +43 -37
  77. package/template/app/(app)/columns/page.tsx +11 -0
  78. package/template/app/(app)/library/all/page.tsx +11 -0
  79. package/template/app/(app)/library/find/page.tsx +12 -0
  80. package/template/app/(app)/{question-bank → library}/layout.tsx +16 -16
  81. package/template/app/(app)/library/list/page.tsx +12 -0
  82. package/template/app/(app)/{question-bank → library}/new/page.tsx +10 -10
  83. package/template/app/(app)/library/page.tsx +11 -0
  84. package/template/app/(app)/tokens-themes/page.tsx +11 -0
  85. package/template/components/ask-leo-composer.tsx +2 -2
  86. package/template/components/columns-client.tsx +158 -0
  87. package/template/components/columns-showcase.tsx +541 -0
  88. package/template/components/data-views/index.ts +32 -6
  89. package/template/components/data-views/{question-bank-folder-tree-branch.tsx → library-folder-tree-branch.tsx} +19 -19
  90. package/template/components/data-views/table-cells.tsx +673 -0
  91. package/template/components/folder-details-shell.tsx +11 -11
  92. package/template/components/hub-tree-panel-view.tsx +24 -24
  93. package/template/components/{question-bank-board-view.tsx → library-board-view.tsx} +44 -44
  94. package/template/components/{question-bank-client.tsx → library-client.tsx} +82 -82
  95. package/template/components/{question-bank-dashboard-charts.tsx → library-dashboard-charts.tsx} +14 -14
  96. package/template/components/{question-bank-favorite-button.tsx → library-favorite-button.tsx} +7 -7
  97. package/template/components/{question-bank-hub-client.tsx → library-hub-client.tsx} +43 -43
  98. package/template/components/{question-bank-new-folder-sheet.tsx → library-new-folder-sheet.tsx} +14 -14
  99. package/template/components/{question-bank-os-folder-view.tsx → library-os-folder-view.tsx} +31 -31
  100. package/template/components/{question-bank-page-header.tsx → library-page-header.tsx} +6 -6
  101. package/template/components/library-panel-activator.tsx +8 -0
  102. package/template/components/{question-bank-secondary-nav.tsx → library-secondary-nav.tsx} +60 -60
  103. package/template/components/{question-bank-table.tsx → library-table.tsx} +97 -97
  104. package/template/components/list-hub-status-badge.tsx +2 -2
  105. package/template/components/{new-question-composer.tsx → new-library-item-form.tsx} +37 -37
  106. package/template/components/sidebar/app-sidebar.tsx +61 -5
  107. package/template/components/sidebar/secondary-panel.tsx +109 -56
  108. package/template/components/sidebar/sidebar-auto-collapse.tsx +2 -2
  109. package/template/components/sidebar/sidebar-auto-open.tsx +2 -1
  110. package/template/components/table-properties/types.ts +1 -1
  111. package/template/components/templates/discovery-hub-template.tsx +1 -1
  112. package/template/components/templates/new-focus-template.tsx +2 -2
  113. package/template/components/templates/secondary-panel-hub-template.tsx +1 -1
  114. package/template/components/tokens-secondary-nav.tsx +192 -0
  115. package/template/components/tokens-themes-client.tsx +476 -0
  116. package/template/components/tokens-themes-section.tsx +386 -0
  117. package/template/docs/HANDBOOK.md +187 -0
  118. package/template/docs/blueprints/README.md +1 -1
  119. package/template/docs/blueprints/board-card.md +1 -1
  120. package/template/docs/blueprints/data-table.md +2 -2
  121. package/template/docs/blueprints/list-page-template.md +3 -3
  122. package/template/docs/blueprints/page-header.md +4 -4
  123. package/template/docs/collaboration-access-pattern.md +7 -7
  124. package/template/docs/component-selection-guide.md +1 -1
  125. package/template/docs/data-views-pattern.md +18 -16
  126. package/template/docs/glossary.md +58 -0
  127. package/template/docs/kpi-flat-band-pattern.md +3 -3
  128. package/template/docs/kpi-trend-pattern.md +18 -3
  129. package/template/docs/large-dataset-strategy.md +155 -0
  130. package/template/docs/library-hub-header-pattern.md +25 -0
  131. package/template/docs/migrations/_template.md +1 -1
  132. package/template/docs/reference-implementations.md +151 -0
  133. package/template/docs/token-taxonomy.md +1 -1
  134. package/template/docs/voice-and-tone.md +262 -0
  135. package/template/eslint.config.mjs +9 -39
  136. package/template/hooks/use-secondary-panel-hub-nav.ts +10 -10
  137. package/template/lib/ask-leo-route-context.ts +6 -18
  138. package/template/lib/coach-mark-registry.ts +0 -16
  139. package/template/lib/command-menu-config.ts +5 -12
  140. package/template/lib/command-menu-search-data.ts +8 -39
  141. package/template/lib/{question-bank-authoring.ts → library-authoring.ts} +89 -88
  142. package/template/lib/library-dedicated-search.ts +19 -0
  143. package/template/lib/library-hub-search.ts +90 -0
  144. package/template/lib/library-nav.ts +477 -0
  145. package/template/lib/library-recent-searches.ts +22 -0
  146. package/template/lib/{placements-supported-views.ts → library-supported-views.ts} +2 -2
  147. package/template/lib/list-status-badges.ts +16 -104
  148. package/template/lib/mock/dashboard.ts +1 -1
  149. package/template/lib/mock/{question-bank-folders.ts → library-folders.ts} +30 -30
  150. package/template/lib/mock/library-header-collaborators.ts +54 -0
  151. package/template/lib/mock/{question-bank-inspector.ts → library-inspector.ts} +29 -29
  152. package/template/lib/mock/{question-bank-kpi.ts → library-kpi.ts} +20 -20
  153. package/template/lib/mock/library.ts +249 -0
  154. package/template/lib/mock/navigation.tsx +32 -26
  155. package/template/lib/table-state-lifecycle.ts +1 -1
  156. package/template/next.config.mjs +7 -4
  157. package/template/package.json +0 -1
  158. package/tokens/hooks-index.json +2874 -0
  159. package/consumer-extras/cursor-rules/exxat-question-bank-hub-header.mdc +0 -28
  160. package/template/app/(app)/examples/page.tsx +0 -41
  161. package/template/app/(app)/question-bank/find/page.tsx +0 -12
  162. package/template/app/(app)/question-bank/library/page.tsx +0 -11
  163. package/template/app/(app)/question-bank/list/page.tsx +0 -12
  164. package/template/app/(app)/question-bank/page.tsx +0 -11
  165. package/template/components/compliance-board-view.tsx +0 -142
  166. package/template/components/compliance-client.tsx +0 -92
  167. package/template/components/compliance-page-header.tsx +0 -89
  168. package/template/components/compliance-table.tsx +0 -468
  169. package/template/components/data-view-dashboard-charts-compliance.tsx +0 -963
  170. package/template/components/data-view-dashboard-charts-team.tsx +0 -971
  171. package/template/components/data-view-dashboard-charts.tsx +0 -1503
  172. package/template/components/new-placement-back-btn.tsx +0 -28
  173. package/template/components/new-placement-form.tsx +0 -942
  174. package/template/components/placement-board-card.tsx +0 -250
  175. package/template/components/placement-detail.tsx +0 -438
  176. package/template/components/placements-board-view.tsx +0 -397
  177. package/template/components/placements-client.tsx +0 -220
  178. package/template/components/placements-list-view.tsx +0 -124
  179. package/template/components/placements-page-header.tsx +0 -166
  180. package/template/components/placements-table-cells.test.tsx +0 -22
  181. package/template/components/placements-table-cells.tsx +0 -173
  182. package/template/components/placements-table-columns.tsx +0 -210
  183. package/template/components/placements-table.tsx +0 -934
  184. package/template/components/question-bank-panel-activator.tsx +0 -8
  185. package/template/components/rotations-empty-state.tsx +0 -50
  186. package/template/components/rotations-panel-activator.tsx +0 -8
  187. package/template/components/sites-board-view.tsx +0 -67
  188. package/template/components/sites-client.tsx +0 -154
  189. package/template/components/sites-table.tsx +0 -249
  190. package/template/components/team-board-view.tsx +0 -122
  191. package/template/components/team-client.tsx +0 -100
  192. package/template/components/team-page-header.tsx +0 -92
  193. package/template/components/team-table.tsx +0 -553
  194. package/template/docs/question-bank-hub-header-pattern.md +0 -25
  195. package/template/lib/compliance-supported-views.ts +0 -10
  196. package/template/lib/data-view-dashboard-placements-layout.ts +0 -215
  197. package/template/lib/mock/compliance-kpi.ts +0 -61
  198. package/template/lib/mock/compliance.ts +0 -146
  199. package/template/lib/mock/placements-kpi.ts +0 -134
  200. package/template/lib/mock/placements.ts +0 -176
  201. package/template/lib/mock/question-bank-header-collaborators.ts +0 -54
  202. package/template/lib/mock/question-bank.ts +0 -249
  203. package/template/lib/mock/sites-directory.ts +0 -16
  204. package/template/lib/mock/sites-kpi.ts +0 -25
  205. package/template/lib/mock/team-kpi.ts +0 -60
  206. package/template/lib/mock/team.ts +0 -118
  207. package/template/lib/placement-board-card-layout.ts +0 -79
  208. package/template/lib/question-bank-dedicated-search.ts +0 -19
  209. package/template/lib/question-bank-hub-search.ts +0 -90
  210. package/template/lib/question-bank-nav.ts +0 -477
  211. package/template/lib/question-bank-recent-searches.ts +0 -22
  212. package/template/lib/question-bank-supported-views.ts +0 -12
  213. package/template/lib/sites-supported-views.ts +0 -10
  214. package/template/lib/team-supported-views.ts +0 -10
@@ -1,7 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  /**
4
- * Question bank — thin wrapper around the centralized `<HubTable>`. Owns column defs,
4
+ * Library — thin wrapper around the centralized `<HubTable>`. Owns column defs,
5
5
  * folder/panel/tree-panel custom views, the new-folder + customize-folder sheet, and
6
6
  * forwards URL search via `HubTable.syncedSearchFromUrl`.
7
7
  *
@@ -21,7 +21,7 @@ import {
21
21
  type HubTableRenderers,
22
22
  type HubTableRendererArgs,
23
23
  } from "@/components/data-views"
24
- import { QUESTION_BANK_SUPPORTED_VIEWS } from "@/lib/question-bank-supported-views"
24
+ import { LIBRARY_SUPPORTED_VIEWS } from "@/lib/library-supported-views"
25
25
  import { Button } from "@/components/ui/button"
26
26
  import {
27
27
  DropdownMenu,
@@ -48,14 +48,14 @@ import {
48
48
  LIST_PAGE_SPLIT_MILLER_COLUMN_PANEL_CLASS,
49
49
  } from "@/components/data-views/list-page-split-hub-tokens"
50
50
  import { ListPageTreeColumnHeader } from "@/components/data-views/list-page-tree-column-header"
51
- import { QuestionBankBoardView, QUESTION_BANK_BOARD_GROUP_OPTIONS } from "@/components/question-bank-board-view"
51
+ import { LibraryBoardView, LIBRARY_BOARD_GROUP_OPTIONS } from "@/components/library-board-view"
52
52
  import { ListPageBoardCard } from "@/components/data-views/list-page-board-card"
53
53
  import {
54
- QuestionBankFavoriteButton,
55
- QUESTION_BANK_FAVORITE_HOVER_GROUP,
56
- } from "@/components/question-bank-favorite-button"
57
- import { QuestionBankOsFolderView } from "@/components/question-bank-os-folder-view"
58
- import { QuestionBankNewFolderSheet } from "@/components/question-bank-new-folder-sheet"
54
+ LibraryFavoriteButton,
55
+ LIBRARY_FAVORITE_HOVER_GROUP,
56
+ } from "@/components/library-favorite-button"
57
+ import { LibraryOsFolderView } from "@/components/library-os-folder-view"
58
+ import { LibraryNewFolderSheet } from "@/components/library-new-folder-sheet"
59
59
  import { FolderDetailsShell } from "@/components/folder-details-shell"
60
60
  import { HubTreePanelView } from "@/components/hub-tree-panel-view"
61
61
  import { AvatarInitials } from "@/components/ui/avatar"
@@ -63,29 +63,29 @@ import { cn } from "@/lib/utils"
63
63
  import { formatDateUS } from "@/lib/date-filter"
64
64
  import { initialsFromDisplayName } from "@/lib/initials-from-name"
65
65
  import {
66
- newQuestionBankQuestionId,
67
- type QuestionBankDifficulty,
68
- type QuestionBankItem,
69
- type QuestionBankType,
70
- } from "@/lib/mock/question-bank"
66
+ newLibraryQuestionId,
67
+ type LibraryLevel,
68
+ type LibraryItem,
69
+ type LibraryItemType,
70
+ } from "@/lib/mock/library"
71
71
  import {
72
- type QuestionBankFolder,
73
- QUESTION_BANK_FOLDER_COLOR_STYLES,
74
- QUESTION_BANK_FOLDER_ICON_COLORS,
75
- } from "@/lib/mock/question-bank-folders"
72
+ type LibraryFolder,
73
+ LIBRARY_FOLDER_COLOR_STYLES,
74
+ LIBRARY_FOLDER_ICON_COLORS,
75
+ } from "@/lib/mock/library-folders"
76
76
  import {
77
- toggleQuestionBankItemFavorite,
78
- applyQuestionBankHubDisplayFilters,
79
- type QuestionBankLandingFilterState,
80
- type QuestionBankNavState,
81
- } from "@/lib/question-bank-nav"
77
+ toggleLibraryItemFavorite,
78
+ applyLibraryHubDisplayFilters,
79
+ type LibraryLandingFilterState,
80
+ type LibraryNavState,
81
+ } from "@/lib/library-nav"
82
82
 
83
83
  // ─── Dynamic dashboard charts section ────────────────────────────────────────
84
84
 
85
- const QuestionBankDashboardChartsSection = dynamic(
85
+ const LibraryDashboardChartsSection = dynamic(
86
86
  () =>
87
- import("@/components/question-bank-dashboard-charts").then(mod => ({
88
- default: mod.QuestionBankDashboardChartsSection,
87
+ import("@/components/library-dashboard-charts").then(mod => ({
88
+ default: mod.LibraryDashboardChartsSection,
89
89
  })),
90
90
  {
91
91
  ssr: false,
@@ -114,46 +114,46 @@ const QuestionBankDashboardChartsSection = dynamic(
114
114
 
115
115
  // ─── Constants ───────────────────────────────────────────────────────────────
116
116
 
117
- const TYPE_LABEL: Record<QuestionBankType, string> = {
118
- multiple_choice: "Multiple choice",
119
- true_false: "True / false",
120
- short_answer: "Short answer",
117
+ const TYPE_LABEL: Record<LibraryItemType, string> = {
118
+ multiple_choice: "Type 1",
119
+ true_false: "Type 2",
120
+ short_answer: "Type 3",
121
121
  }
122
122
 
123
- const DIFFICULTY_LABEL: Record<QuestionBankDifficulty, string> = {
124
- easy: "Easy",
125
- medium: "Medium",
126
- hard: "Hard",
123
+ const DIFFICULTY_LABEL: Record<LibraryLevel, string> = {
124
+ easy: "Low",
125
+ medium: "Normal",
126
+ hard: "High",
127
127
  }
128
128
 
129
- const TYPE_FILTER_OPTS = (Object.keys(TYPE_LABEL) as QuestionBankType[]).map(k => ({
129
+ const TYPE_FILTER_OPTS = (Object.keys(TYPE_LABEL) as LibraryItemType[]).map(k => ({
130
130
  value: k,
131
131
  label: TYPE_LABEL[k],
132
132
  }))
133
133
 
134
- const DIFFICULTY_FILTER_OPTS = (Object.keys(DIFFICULTY_LABEL) as QuestionBankDifficulty[]).map(k => ({
134
+ const DIFFICULTY_FILTER_OPTS = (Object.keys(DIFFICULTY_LABEL) as LibraryLevel[]).map(k => ({
135
135
  value: k,
136
136
  label: DIFFICULTY_LABEL[k],
137
137
  }))
138
138
 
139
- function newQuestionBankItemId() {
139
+ function newLibraryItemId() {
140
140
  return `q-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`
141
141
  }
142
142
 
143
- function defaultFolderIdForColumnParent(parentId: string | null, folders: QuestionBankFolder[]): string | null {
143
+ function defaultFolderIdForColumnParent(parentId: string | null, folders: LibraryFolder[]): string | null {
144
144
  if (parentId !== null) return parentId
145
145
  const roots = [...folders].filter(f => f.parentId === null).sort((a, b) => a.name.localeCompare(b.name))
146
146
  return roots[0]?.id ?? null
147
147
  }
148
148
 
149
- function uniqueTopics(items: QuestionBankItem[]) {
149
+ function uniqueTopics(items: LibraryItem[]) {
150
150
  return [...new Set(items.map(i => i.topic))].sort().map(t => ({ value: t, label: t }))
151
151
  }
152
152
 
153
- function buildQuestionBankColumns(
154
- items: QuestionBankItem[],
155
- opts: { onToggleFavorite: (row: QuestionBankItem) => void },
156
- ): ColumnDef<QuestionBankItem>[] {
153
+ function buildLibraryColumns(
154
+ items: LibraryItem[],
155
+ opts: { onToggleFavorite: (row: LibraryItem) => void },
156
+ ): ColumnDef<LibraryItem>[] {
157
157
  const topicOpts = uniqueTopics(items)
158
158
  const { onToggleFavorite } = opts
159
159
  return [
@@ -168,12 +168,12 @@ function buildQuestionBankColumns(
168
168
  defaultPin: "left",
169
169
  filter: { type: "text", icon: "fa-file-lines", operators: ["contains", "not_contains"] },
170
170
  cell: row => (
171
- <div className={cn(QUESTION_BANK_FAVORITE_HOVER_GROUP, "flex min-w-0 items-start gap-2")}>
171
+ <div className={cn(LIBRARY_FAVORITE_HOVER_GROUP, "flex min-w-0 items-start gap-2")}>
172
172
  <div className="flex min-w-0 flex-1 flex-col gap-0.5 pe-1">
173
173
  <span className="line-clamp-2 text-sm font-medium text-foreground">{row.stem}</span>
174
174
  <span className="font-mono text-xs text-muted-foreground">{row.questionId}</span>
175
175
  </div>
176
- <QuestionBankFavoriteButton row={row} onToggleFavorite={onToggleFavorite} />
176
+ <LibraryFavoriteButton row={row} onToggleFavorite={onToggleFavorite} />
177
177
  </div>
178
178
  ),
179
179
  },
@@ -283,21 +283,21 @@ function buildQuestionBankColumns(
283
283
  // ─── Folder columns panel (custom multi-column miller view) ─────────────────
284
284
 
285
285
  interface HubFolderColumnsPanelProps {
286
- folders: QuestionBankFolder[]
287
- rows: QuestionBankItem[]
288
- panelRenderDetail: (row: QuestionBankItem) => React.ReactNode
286
+ folders: LibraryFolder[]
287
+ rows: LibraryItem[]
288
+ panelRenderDetail: (row: LibraryItem) => React.ReactNode
289
289
  onAddFolder: (parentId: string | null) => void
290
290
  onAddQuestion: (parentId: string | null) => void
291
- onCustomizeFolder?: (folder: QuestionBankFolder) => void
291
+ onCustomizeFolder?: (folder: LibraryFolder) => void
292
292
  }
293
293
 
294
- type HierarchyItem = QuestionBankFolder | QuestionBankItem
294
+ type HierarchyItem = LibraryFolder | LibraryItem
295
295
 
296
- function isFolder(item: HierarchyItem): item is QuestionBankFolder {
296
+ function isFolder(item: HierarchyItem): item is LibraryFolder {
297
297
  return "parentId" in item
298
298
  }
299
299
 
300
- function isQuestion(item: HierarchyItem): item is QuestionBankItem {
300
+ function isQuestion(item: HierarchyItem): item is LibraryItem {
301
301
  return "stem" in item
302
302
  }
303
303
 
@@ -332,7 +332,7 @@ function HubFolderColumnsPanel({
332
332
  if (isFirstRenderRef.current && selectedPath.length > 0) {
333
333
  const lastItem = selectedPath[selectedPath.length - 1]
334
334
  if (isFolder(lastItem)) {
335
- const folder = lastItem as QuestionBankFolder
335
+ const folder = lastItem as LibraryFolder
336
336
  const subfolders = folders.filter(f => f.parentId === folder.id).sort((a, b) => a.name.localeCompare(b.name))
337
337
  const questionsInFolder = rows.filter(r => r.folderId === folder.id)
338
338
  const items: HierarchyItem[] = [...subfolders, ...questionsInFolder]
@@ -362,8 +362,8 @@ function HubFolderColumnsPanel({
362
362
  }, [selectedPath, rootFolders, folders, rows])
363
363
 
364
364
  const selectedLeaf = selectedPath.length > 0 ? selectedPath.at(-1)! : null
365
- const selectedQuestion = selectedLeaf && isQuestion(selectedLeaf) ? (selectedLeaf as QuestionBankItem) : null
366
- const selectedFolderLeaf = selectedLeaf && isFolder(selectedLeaf) ? (selectedLeaf as QuestionBankFolder) : null
365
+ const selectedQuestion = selectedLeaf && isQuestion(selectedLeaf) ? (selectedLeaf as LibraryItem) : null
366
+ const selectedFolderLeaf = selectedLeaf && isFolder(selectedLeaf) ? (selectedLeaf as LibraryFolder) : null
367
367
 
368
368
  return (
369
369
  <ResizablePanelGroup direction="horizontal" className="flex h-full min-h-0 w-full flex-1 overflow-hidden">
@@ -381,7 +381,7 @@ function HubFolderColumnsPanel({
381
381
  depth === 0
382
382
  ? "Categories"
383
383
  : selectedPath[depth - 1] && isFolder(selectedPath[depth - 1])
384
- ? (selectedPath[depth - 1] as QuestionBankFolder).name
384
+ ? (selectedPath[depth - 1] as LibraryFolder).name
385
385
  : "Items"
386
386
  }
387
387
  trailing={
@@ -442,7 +442,7 @@ function HubFolderColumnsPanel({
442
442
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset",
443
443
  isSelected ? "bg-accent text-accent-foreground" : "text-foreground",
444
444
  isFolder_ && !isSelected && folder?.colorKey && depth > 0
445
- ? QUESTION_BANK_FOLDER_COLOR_STYLES[folder.colorKey]?.tile
445
+ ? LIBRARY_FOLDER_COLOR_STYLES[folder.colorKey]?.tile
446
446
  : "",
447
447
  )}
448
448
  aria-selected={isSelected}
@@ -453,7 +453,7 @@ function HubFolderColumnsPanel({
453
453
  className={cn(
454
454
  "fa-folder text-sm shrink-0",
455
455
  isSelected ? "fa-solid" : "fa-light",
456
- folder?.colorKey && QUESTION_BANK_FOLDER_ICON_COLORS[folder.colorKey],
456
+ folder?.colorKey && LIBRARY_FOLDER_ICON_COLORS[folder.colorKey],
457
457
  )}
458
458
  aria-hidden="true"
459
459
  />
@@ -472,7 +472,7 @@ function HubFolderColumnsPanel({
472
472
  {isFolder_
473
473
  ? itemCount
474
474
  : question?.type === "multiple_choice"
475
- ? "MCQ"
475
+ ? "T1"
476
476
  : question?.difficulty?.charAt(0).toUpperCase()}
477
477
  </span>
478
478
  </button>
@@ -529,7 +529,7 @@ function HubFolderColumnsPanel({
529
529
 
530
530
  // ─── Detail renderer reused by panel + tree-panel ───────────────────────────
531
531
 
532
- function questionBankPanelDetail(row: QuestionBankItem) {
532
+ function libraryPanelDetail(row: LibraryItem) {
533
533
  return (
534
534
  <div className="flex min-w-0 flex-col gap-4">
535
535
  <div>
@@ -579,27 +579,27 @@ function questionBankPanelDetail(row: QuestionBankItem) {
579
579
 
580
580
  // ─── Public component ───────────────────────────────────────────────────────
581
581
 
582
- export type QuestionBankTableHandle = HubTableHandle
582
+ export type LibraryTableHandle = HubTableHandle
583
583
 
584
- export interface QuestionBankTableProps {
585
- items: QuestionBankItem[]
584
+ export interface LibraryTableProps {
585
+ items: LibraryItem[]
586
586
  /** When set, table / board / tree rows are limited to this nav scope (secondary sidebar). */
587
- navState?: QuestionBankNavState
587
+ navState?: LibraryNavState
588
588
  /** URL toolbar search binding (`?q=`) — omit on search landing so hub `q` does not pre-fill the grid search. */
589
589
  urlListSearch?: string
590
590
  /** When true, dedicated search shell: hub landing row filters; table toolbar search stays independent of URL `q`. */
591
591
  searchLanding?: boolean
592
592
  /** Applied with nav filters before `useTableState` when {@link searchLanding} is true. */
593
- landingFilters?: QuestionBankLandingFilterState | null
593
+ landingFilters?: LibraryLandingFilterState | null
594
594
  view?: DataListViewType
595
595
  onViewChange?: (v: DataListViewType) => void
596
- folders: QuestionBankFolder[]
597
- onFoldersChange: React.Dispatch<React.SetStateAction<QuestionBankFolder[]>>
598
- onItemsChange: React.Dispatch<React.SetStateAction<QuestionBankItem[]>>
596
+ folders: LibraryFolder[]
597
+ onFoldersChange: React.Dispatch<React.SetStateAction<LibraryFolder[]>>
598
+ onItemsChange: React.Dispatch<React.SetStateAction<LibraryItem[]>>
599
599
  }
600
600
 
601
- export const QuestionBankTable = React.forwardRef<QuestionBankTableHandle, QuestionBankTableProps>(
602
- function QuestionBankTable(
601
+ export const LibraryTable = React.forwardRef<LibraryTableHandle, LibraryTableProps>(
602
+ function LibraryTable(
603
603
  {
604
604
  items,
605
605
  navState,
@@ -617,25 +617,25 @@ export const QuestionBankTable = React.forwardRef<QuestionBankTableHandle, Quest
617
617
  const tableSourceItems = React.useMemo(() => {
618
618
  const nav = navState ?? { scope: "all" as const, folderId: null }
619
619
  const landing = searchLanding ? (landingFilters ?? null) : null
620
- return applyQuestionBankHubDisplayFilters(items, folders, nav, landing)
620
+ return applyLibraryHubDisplayFilters(items, folders, nav, landing)
621
621
  }, [items, folders, navState, searchLanding, landingFilters])
622
622
 
623
623
  const toggleFavorite = React.useCallback(
624
- (row: QuestionBankItem) => {
625
- onItemsChange(prev => prev.map(r => (r.id === row.id ? toggleQuestionBankItemFavorite(r) : r)))
624
+ (row: LibraryItem) => {
625
+ onItemsChange(prev => prev.map(r => (r.id === row.id ? toggleLibraryItemFavorite(r) : r)))
626
626
  },
627
627
  [onItemsChange],
628
628
  )
629
629
 
630
630
  const columns = React.useMemo(
631
- () => buildQuestionBankColumns(tableSourceItems, { onToggleFavorite: toggleFavorite }),
631
+ () => buildLibraryColumns(tableSourceItems, { onToggleFavorite: toggleFavorite }),
632
632
  [tableSourceItems, toggleFavorite],
633
633
  )
634
634
 
635
635
  // ─ New-folder / customize-folder modal state (shared by panel + tree-panel) ────
636
636
  const [newFolderOpen, setNewFolderOpen] = React.useState(false)
637
637
  const [newFolderParentId, setNewFolderParentId] = React.useState<string | null>(null)
638
- const [customizingFolder, setCustomizingFolder] = React.useState<QuestionBankFolder | null>(null)
638
+ const [customizingFolder, setCustomizingFolder] = React.useState<LibraryFolder | null>(null)
639
639
 
640
640
  const openNewFolderForColumn = React.useCallback((parentId: string | null) => {
641
641
  setNewFolderParentId(parentId)
@@ -643,7 +643,7 @@ export const QuestionBankTable = React.forwardRef<QuestionBankTableHandle, Quest
643
643
  setNewFolderOpen(true)
644
644
  }, [])
645
645
 
646
- const openCustomizeFolderSheet = React.useCallback((folder: QuestionBankFolder) => {
646
+ const openCustomizeFolderSheet = React.useCallback((folder: LibraryFolder) => {
647
647
  setCustomizingFolder(folder)
648
648
  setNewFolderOpen(true)
649
649
  }, [])
@@ -659,8 +659,8 @@ export const QuestionBankTable = React.forwardRef<QuestionBankTableHandle, Quest
659
659
  onItemsChange(prev => [
660
660
  ...prev,
661
661
  {
662
- id: newQuestionBankItemId(),
663
- questionId: newQuestionBankQuestionId(),
662
+ id: newLibraryItemId(),
663
+ questionId: newLibraryQuestionId(),
664
664
  stem: "New question",
665
665
  topic: "General",
666
666
  type: "short_answer",
@@ -685,16 +685,16 @@ export const QuestionBankTable = React.forwardRef<QuestionBankTableHandle, Quest
685
685
  )
686
686
 
687
687
  // ─ Renderers ──────────────────────────────────────────────────────────────
688
- const renderers: HubTableRenderers<QuestionBankItem> = {
688
+ const renderers: HubTableRenderers<LibraryItem> = {
689
689
  "board-with-toolbar": ({ state, toolbarShell, displayOptions }) => {
690
- const boardGroupKey = QUESTION_BANK_BOARD_GROUP_OPTIONS.some(
690
+ const boardGroupKey = LIBRARY_BOARD_GROUP_OPTIONS.some(
691
691
  o => o.key === displayOptions.boardGroupByColumnKey,
692
692
  )
693
693
  ? displayOptions.boardGroupByColumnKey
694
694
  : "topic"
695
695
  return toolbarShell(
696
- <QuestionBankBoardView
697
- rows={state.rows as QuestionBankItem[]}
696
+ <LibraryBoardView
697
+ rows={state.rows as LibraryItem[]}
698
698
  groupByColumnKey={boardGroupKey}
699
699
  onToggleFavorite={toggleFavorite}
700
700
  onRowActivate={row => state.toggleRow(row.id)}
@@ -703,20 +703,20 @@ export const QuestionBankTable = React.forwardRef<QuestionBankTableHandle, Quest
703
703
  },
704
704
  "folder-with-toolbar": ({ state, toolbarShell }) =>
705
705
  toolbarShell(
706
- <QuestionBankOsFolderView
706
+ <LibraryOsFolderView
707
707
  folders={folders}
708
708
  onFoldersChange={onFoldersChange}
709
- questions={state.rows as QuestionBankItem[]}
709
+ questions={state.rows as LibraryItem[]}
710
710
  onQuestionsChange={onItemsChange}
711
711
  />,
712
712
  ),
713
713
  "panel-with-toolbar": ({ state, toolbarShell }) =>
714
714
  toolbarShell(
715
- <ListPageSplitHubChrome aria-label="Question bank folder columns">
715
+ <ListPageSplitHubChrome aria-label="Library folder columns">
716
716
  <HubFolderColumnsPanel
717
717
  folders={folders}
718
- rows={state.rows as QuestionBankItem[]}
719
- panelRenderDetail={questionBankPanelDetail}
718
+ rows={state.rows as LibraryItem[]}
719
+ panelRenderDetail={libraryPanelDetail}
720
720
  onAddFolder={openNewFolderForColumn}
721
721
  onAddQuestion={addQuestionInColumn}
722
722
  onCustomizeFolder={openCustomizeFolderSheet}
@@ -727,7 +727,7 @@ export const QuestionBankTable = React.forwardRef<QuestionBankTableHandle, Quest
727
727
  toolbarShell(
728
728
  <div className="flex min-h-0 flex-1 flex-col">
729
729
  <HubTreePanelView
730
- items={state.rows as QuestionBankItem[]}
730
+ items={state.rows as LibraryItem[]}
731
731
  folders={folders}
732
732
  onItemsChange={onItemsChange}
733
733
  onFoldersChange={onFoldersChange}
@@ -737,39 +737,39 @@ export const QuestionBankTable = React.forwardRef<QuestionBankTableHandle, Quest
737
737
  "dashboard-with-toolbar": ({ state, toolbar }) => (
738
738
  <div className="flex min-h-0 flex-1 flex-col">
739
739
  {toolbar}
740
- <QuestionBankDashboardChartsSection rows={state.rows as QuestionBankItem[]} />
740
+ <LibraryDashboardChartsSection rows={state.rows as LibraryItem[]} />
741
741
  </div>
742
742
  ),
743
743
  }
744
744
 
745
745
  return (
746
746
  <>
747
- <HubTable<QuestionBankItem>
747
+ <HubTable<LibraryItem>
748
748
  rows={tableSourceItems}
749
749
  columns={columns}
750
750
  view={view}
751
751
  onViewChange={onViewChange}
752
- supportedViewTypes={QUESTION_BANK_SUPPORTED_VIEWS}
753
- hubLabel="Question bank"
754
- lifecycleTabLabel="Question bank"
752
+ supportedViewTypes={LIBRARY_SUPPORTED_VIEWS}
753
+ hubLabel="Library"
754
+ lifecycleTabLabel="Library"
755
755
  searchAriaLabel="Search questions"
756
756
  getRowId={row => row.id}
757
757
  getRowSelectionLabel={row => row.stem}
758
758
  defaultSort={{ key: "updatedAt", dir: "desc" }}
759
759
  emptyState={<p className="text-sm text-muted-foreground">No questions in the bank.</p>}
760
- boardGroupByColumnOptions={[...QUESTION_BANK_BOARD_GROUP_OPTIONS]}
760
+ boardGroupByColumnOptions={[...LIBRARY_BOARD_GROUP_OPTIONS]}
761
761
  renderFilterOptionValue={renderFilterOptionValue}
762
762
  syncedSearchFromUrl={searchLanding ? undefined : urlListSearch}
763
763
  listAriaLabel="Questions"
764
764
  listEmptyState="No questions match your filters."
765
765
  renderListRow={row => (
766
766
  <ListPageBoardCard
767
- className={QUESTION_BANK_FAVORITE_HOVER_GROUP}
767
+ className={LIBRARY_FAVORITE_HOVER_GROUP}
768
768
  layout="row"
769
769
  rowContainerClassName="flex w-full flex-col gap-1 sm:flex-row sm:items-center sm:gap-4"
770
770
  rowEnd={
771
771
  <div className="flex shrink-0 items-center gap-1">
772
- <QuestionBankFavoriteButton row={row} onToggleFavorite={toggleFavorite} />
772
+ <LibraryFavoriteButton row={row} onToggleFavorite={toggleFavorite} />
773
773
  <i className="fa-light fa-chevron-right text-xs text-muted-foreground" aria-hidden="true" />
774
774
  </div>
775
775
  }
@@ -801,7 +801,7 @@ export const QuestionBankTable = React.forwardRef<QuestionBankTableHandle, Quest
801
801
  renderers={renderers}
802
802
  handleRef={ref}
803
803
  />
804
- <QuestionBankNewFolderSheet
804
+ <LibraryNewFolderSheet
805
805
  open={newFolderOpen}
806
806
  onOpenChange={setNewFolderOpen}
807
807
  parentFolderId={customizingFolder?.parentId ?? newFolderParentId}
@@ -836,4 +836,4 @@ export const QuestionBankTable = React.forwardRef<QuestionBankTableHandle, Quest
836
836
  },
837
837
  )
838
838
 
839
- QuestionBankTable.displayName = "QuestionBankTable"
839
+ LibraryTable.displayName = "LibraryTable"
@@ -1,7 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  /**
4
- * Consistent status chip for list hubs (Team, Compliance, Question bank, future entities).
4
+ * Consistent status chip for list hubs (Team, Compliance, Library, future entities).
5
5
  * Pair label + tint + icon from `lib/list-status-badges.ts`; do not hand-roll Badge markup per page.
6
6
  */
7
7
 
@@ -9,7 +9,7 @@ import * as React from "react"
9
9
  import { Badge } from "@/components/ui/badge"
10
10
  import { cn } from "@/lib/utils"
11
11
 
12
- /** Table column + list view rows — same shell as Team / Compliance / Question bank grids. */
12
+ /** Table column + list view rows — same shell as Team / Compliance / Library grids. */
13
13
  export const LIST_HUB_STATUS_BADGE_TABLE_SHELL =
14
14
  "inline-flex items-center gap-1 text-xs font-medium"
15
15