@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,8 +1,8 @@
1
1
  "use client"
2
2
 
3
3
  /**
4
- * Folder details panel — OsFolderGlyph header + aggregates (`question-bank-inspector` helpers today).
5
- * Reusable across list hubs that share `QuestionBankFolder` / `QuestionBankItem` shapes or adapters.
4
+ * Folder details panel — OsFolderGlyph header + aggregates (`library-inspector` helpers today).
5
+ * Reusable across list hubs that share `LibraryFolder` / `LibraryItem` shapes or adapters.
6
6
  */
7
7
 
8
8
  import * as React from "react"
@@ -12,13 +12,13 @@ import { Button } from "@/components/ui/button"
12
12
  import { Separator } from "@/components/ui/separator"
13
13
  import { Tip } from "@/components/ui/tip"
14
14
  import { cn } from "@/lib/utils"
15
- import type { QuestionBankItem } from "@/lib/mock/question-bank"
16
- import type { QuestionBankFolder } from "@/lib/mock/question-bank-folders"
15
+ import type { LibraryItem } from "@/lib/mock/library"
16
+ import type { LibraryFolder } from "@/lib/mock/library-folders"
17
17
  import {
18
18
  aggregateFolderQuestions,
19
19
  BLOOM_LEVEL_ORDER,
20
20
  questionsInFolderSubtree,
21
- } from "@/lib/mock/question-bank-inspector"
21
+ } from "@/lib/mock/library-inspector"
22
22
 
23
23
  function DetailBreadcrumbNav({ segments }: { segments: { id: string; label: string }[] }) {
24
24
  if (segments.length === 0) return null
@@ -70,9 +70,9 @@ function InspectorSectionTitle({ children, id }: { children: React.ReactNode; id
70
70
  }
71
71
 
72
72
  export interface FolderDetailsShellProps {
73
- folder: QuestionBankFolder
74
- folders: QuestionBankFolder[]
75
- questions: QuestionBankItem[]
73
+ folder: LibraryFolder
74
+ folders: LibraryFolder[]
75
+ questions: LibraryItem[]
76
76
  /** Clears selection (tree inspector dismiss). */
77
77
  onClearSelection?: () => void
78
78
  }
@@ -89,8 +89,8 @@ export function FolderDetailsShell({
89
89
  const diffSum = diffAgg.easy + diffAgg.medium + diffAgg.hard
90
90
  const maxBloomCount = Math.max(1, ...BLOOM_LEVEL_ORDER.map(level => bloom[level] ?? 0))
91
91
 
92
- const breadcrumbs: QuestionBankFolder[] = []
93
- let cur: QuestionBankFolder | undefined = folder
92
+ const breadcrumbs: LibraryFolder[] = []
93
+ let cur: LibraryFolder | undefined = folder
94
94
  while (cur) {
95
95
  breadcrumbs.unshift(cur)
96
96
  cur = folders.find(f => f.id === cur?.parentId)
@@ -114,7 +114,7 @@ export function FolderDetailsShell({
114
114
  <div className="min-w-0 flex-1">
115
115
  <h2 className="text-base font-semibold leading-tight tracking-tight text-foreground">
116
116
  <span className="truncate">{folder.name}</span>
117
- <span className="font-normal text-muted-foreground"> · Question Bank</span>
117
+ <span className="font-normal text-muted-foreground"> · Library</span>
118
118
  </h2>
119
119
  <p className="mt-1 text-sm font-semibold tabular-nums text-foreground">
120
120
  {totalQuestions} question{totalQuestions !== 1 ? "s" : ""}
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * **Tree view** — `ListPageTreePanelShell` + outline tree + read-only details (`FolderDetailsShell`).
5
- * Hub wiring (folders, mock sheet) stays in the caller; this module hosts question-bank demo wiring only.
5
+ * Hub wiring (folders, mock sheet) stays in the caller; this module hosts library demo wiring only.
6
6
  */
7
7
 
8
8
  import * as React from "react"
@@ -39,12 +39,12 @@ import {
39
39
  import { ListPageTreePanelShell } from "@/components/data-views/list-page-tree-panel-shell"
40
40
  import { ListPageSplitDetailsPlaceholder } from "@/components/data-views/list-page-split-details-placeholder"
41
41
  import { ListPageTreeColumnHeader } from "@/components/data-views/list-page-tree-column-header"
42
- import { QuestionBankNewFolderSheet } from "@/components/question-bank-new-folder-sheet"
42
+ import { LibraryNewFolderSheet } from "@/components/library-new-folder-sheet"
43
43
  import type {
44
- QuestionBankItem,
45
- QuestionBankDifficulty,
46
- } from "@/lib/mock/question-bank"
47
- import type { QuestionBankFolder, QuestionBankFolderColorKey } from "@/lib/mock/question-bank-folders"
44
+ LibraryItem,
45
+ LibraryLevel,
46
+ } from "@/lib/mock/library"
47
+ import type { LibraryFolder, LibraryFolderColorKey } from "@/lib/mock/library-folders"
48
48
  import { formatDateUS } from "@/lib/date-filter"
49
49
  import {
50
50
  deriveBloomLevel,
@@ -52,14 +52,14 @@ import {
52
52
  deriveQuestionItemCode,
53
53
  deriveTags,
54
54
  QUESTION_TYPE_ABBREV,
55
- } from "@/lib/mock/question-bank-inspector"
55
+ } from "@/lib/mock/library-inspector"
56
56
  import { FolderDetailsShell } from "@/components/folder-details-shell"
57
57
  import { initialsFromDisplayName } from "@/lib/initials-from-name"
58
58
 
59
- const DIFFICULTY_LABEL: Record<QuestionBankDifficulty, string> = {
60
- easy: "Easy",
61
- medium: "Medium",
62
- hard: "Hard",
59
+ const DIFFICULTY_LABEL: Record<LibraryLevel, string> = {
60
+ easy: "Low",
61
+ medium: "Normal",
62
+ hard: "High",
63
63
  }
64
64
 
65
65
  // ============================================================================
@@ -67,9 +67,9 @@ const DIFFICULTY_LABEL: Record<QuestionBankDifficulty, string> = {
67
67
  // ============================================================================
68
68
 
69
69
  interface TreeItemProps {
70
- folder: QuestionBankFolder
71
- folders: QuestionBankFolder[]
72
- questions: QuestionBankItem[]
70
+ folder: LibraryFolder
71
+ folders: LibraryFolder[]
72
+ questions: LibraryItem[]
73
73
  selectedItemId: string | null
74
74
  onSelectItem: (itemId: string) => void
75
75
  }
@@ -226,8 +226,8 @@ function InspectorSectionTitle({ children, id }: { children: React.ReactNode; id
226
226
 
227
227
  interface DetailsPanelProps {
228
228
  selectedItemId: string | null
229
- folders: QuestionBankFolder[]
230
- questions: QuestionBankItem[]
229
+ folders: LibraryFolder[]
230
+ questions: LibraryItem[]
231
231
  /** Clears tree selection (header dismiss). */
232
232
  onClearSelection?: () => void
233
233
  }
@@ -534,14 +534,14 @@ function DetailsPanel({ selectedItemId, folders, questions, onClearSelection }:
534
534
  }
535
535
 
536
536
  // ============================================================================
537
- // HubTreePanelView — tree + details wiring (question bank demo; reusable shell above)
537
+ // HubTreePanelView — tree + details wiring (library demo; reusable shell above)
538
538
  // ============================================================================
539
539
 
540
540
  export interface HubTreePanelViewProps {
541
- items: QuestionBankItem[]
542
- folders: QuestionBankFolder[]
543
- onItemsChange: (items: QuestionBankItem[]) => void
544
- onFoldersChange: (folders: QuestionBankFolder[]) => void
541
+ items: LibraryItem[]
542
+ folders: LibraryFolder[]
543
+ onItemsChange: (items: LibraryItem[]) => void
544
+ onFoldersChange: (folders: LibraryFolder[]) => void
545
545
  }
546
546
 
547
547
  export function HubTreePanelView({
@@ -552,7 +552,7 @@ export function HubTreePanelView({
552
552
  const [selectedItemId, setSelectedItemId] = React.useState<string | null>(null)
553
553
  const [newFolderOpen, setNewFolderOpen] = React.useState(false)
554
554
  const [newFolderParentId, setNewFolderParentId] = React.useState<string | null>(null)
555
- const [customizingFolder, setCustomizingFolder] = React.useState<QuestionBankFolder | null>(null)
555
+ const [customizingFolder, setCustomizingFolder] = React.useState<LibraryFolder | null>(null)
556
556
 
557
557
  const rootFolders = React.useMemo(
558
558
  () => folders.filter(f => f.parentId === null).sort((a, b) => a.name.localeCompare(b.name)),
@@ -560,7 +560,7 @@ export function HubTreePanelView({
560
560
  )
561
561
 
562
562
  const handleNewFolderCreated = React.useCallback(
563
- (newFolder: { name: string; icon: string; colorKey: QuestionBankFolderColorKey; parentId: string | null }) => {
563
+ (newFolder: { name: string; icon: string; colorKey: LibraryFolderColorKey; parentId: string | null }) => {
564
564
  if (customizingFolder) {
565
565
  onFoldersChange(
566
566
  folders.map(f =>
@@ -652,7 +652,7 @@ export function HubTreePanelView({
652
652
  }
653
653
  />
654
654
 
655
- <QuestionBankNewFolderSheet
655
+ <LibraryNewFolderSheet
656
656
  open={newFolderOpen}
657
657
  onOpenChange={setNewFolderOpen}
658
658
  parentFolderId={customizingFolder?.parentId ?? newFolderParentId}
@@ -3,10 +3,10 @@
3
3
  import * as React from "react"
4
4
  import { initialsFromDisplayName } from "@/lib/initials-from-name"
5
5
  import type {
6
- QuestionBankDifficulty,
7
- QuestionBankItem,
8
- QuestionBankType,
9
- } from "@/lib/mock/question-bank"
6
+ LibraryLevel,
7
+ LibraryItem,
8
+ LibraryItemType,
9
+ } from "@/lib/mock/library"
10
10
  import {
11
11
  LIST_HUB_STATUS_TINT_DANGER,
12
12
  LIST_HUB_STATUS_TINT_INFO,
@@ -28,81 +28,81 @@ import {
28
28
  type ListPageBoardColumnDef,
29
29
  } from "@/components/data-views/list-page-board-template"
30
30
  import {
31
- QuestionBankFavoriteButton,
32
- QUESTION_BANK_FAVORITE_HOVER_GROUP,
33
- } from "@/components/question-bank-favorite-button"
31
+ LibraryFavoriteButton,
32
+ LIBRARY_FAVORITE_HOVER_GROUP,
33
+ } from "@/components/library-favorite-button"
34
34
  import { cn } from "@/lib/utils"
35
35
 
36
36
  const NEUTRAL_COUNT_BADGE = "bg-muted/90 text-foreground"
37
37
 
38
- const TYPE_LABEL: Record<QuestionBankType, string> = {
39
- multiple_choice: "Multiple choice",
40
- true_false: "True / false",
41
- short_answer: "Short answer",
38
+ const TYPE_LABEL: Record<LibraryItemType, string> = {
39
+ multiple_choice: "Type 1",
40
+ true_false: "Type 2",
41
+ short_answer: "Type 3",
42
42
  }
43
43
 
44
- const DIFF_LABEL: Record<QuestionBankDifficulty, string> = {
45
- easy: "Easy",
46
- medium: "Medium",
47
- hard: "Hard",
44
+ const DIFF_LABEL: Record<LibraryLevel, string> = {
45
+ easy: "Low",
46
+ medium: "Normal",
47
+ hard: "High",
48
48
  }
49
49
 
50
- const DIFF_BADGE: Record<QuestionBankDifficulty, string> = {
50
+ const DIFF_BADGE: Record<LibraryLevel, string> = {
51
51
  easy: LIST_HUB_STATUS_TINT_SUCCESS,
52
52
  medium: LIST_HUB_STATUS_TINT_WARNING,
53
53
  hard: LIST_HUB_STATUS_TINT_DANGER,
54
54
  }
55
55
 
56
- const TYPE_BADGE: Record<QuestionBankType, string> = {
56
+ const TYPE_BADGE: Record<LibraryItemType, string> = {
57
57
  multiple_choice: LIST_HUB_STATUS_TINT_NEUTRAL,
58
58
  true_false: LIST_HUB_STATUS_TINT_INFO,
59
59
  short_answer: LIST_HUB_STATUS_TINT_WARNING,
60
60
  }
61
61
 
62
- const DIFF_ORDER: QuestionBankDifficulty[] = ["easy", "medium", "hard"]
63
- const TYPE_ORDER: QuestionBankType[] = ["multiple_choice", "true_false", "short_answer"]
62
+ const DIFF_ORDER: LibraryLevel[] = ["easy", "medium", "hard"]
63
+ const TYPE_ORDER: LibraryItemType[] = ["multiple_choice", "true_false", "short_answer"]
64
64
 
65
- function topicBoardColumns(rows: QuestionBankItem[]): {
66
- columns: ListPageBoardColumnDef<QuestionBankItem>[]
65
+ function topicBoardColumns(rows: LibraryItem[]): {
66
+ columns: ListPageBoardColumnDef<LibraryItem>[]
67
67
  badgeMap: Record<string, string>
68
68
  } {
69
69
  const topics = [...new Set(rows.map(r => r.topic))].sort((a, b) => a.localeCompare(b))
70
- const columns: ListPageBoardColumnDef<QuestionBankItem>[] = topics.map(topic => ({
70
+ const columns: ListPageBoardColumnDef<LibraryItem>[] = topics.map(topic => ({
71
71
  id: `topic:${topic}`,
72
72
  label: topic,
73
- filter: (r: QuestionBankItem) => r.topic === topic,
73
+ filter: (r: LibraryItem) => r.topic === topic,
74
74
  }))
75
75
  const badgeMap = Object.fromEntries(topics.map(t => [`topic:${t}`, NEUTRAL_COUNT_BADGE]))
76
76
  return { columns, badgeMap }
77
77
  }
78
78
 
79
79
  function difficultyBoardColumns(): {
80
- columns: ListPageBoardColumnDef<QuestionBankItem>[]
80
+ columns: ListPageBoardColumnDef<LibraryItem>[]
81
81
  badgeMap: Record<string, string>
82
82
  } {
83
- const columns: ListPageBoardColumnDef<QuestionBankItem>[] = DIFF_ORDER.map(d => ({
83
+ const columns: ListPageBoardColumnDef<LibraryItem>[] = DIFF_ORDER.map(d => ({
84
84
  id: d,
85
85
  label: DIFF_LABEL[d],
86
- filter: (r: QuestionBankItem) => r.difficulty === d,
86
+ filter: (r: LibraryItem) => r.difficulty === d,
87
87
  }))
88
88
  const badgeMap = Object.fromEntries(DIFF_ORDER.map(d => [d, DIFF_BADGE[d]]))
89
89
  return { columns, badgeMap }
90
90
  }
91
91
 
92
92
  function typeBoardColumns(): {
93
- columns: ListPageBoardColumnDef<QuestionBankItem>[]
93
+ columns: ListPageBoardColumnDef<LibraryItem>[]
94
94
  badgeMap: Record<string, string>
95
95
  } {
96
- const columns: ListPageBoardColumnDef<QuestionBankItem>[] = TYPE_ORDER.map(t => ({
96
+ const columns: ListPageBoardColumnDef<LibraryItem>[] = TYPE_ORDER.map(t => ({
97
97
  id: t,
98
98
  label: TYPE_LABEL[t],
99
- filter: (r: QuestionBankItem) => r.type === t,
99
+ filter: (r: LibraryItem) => r.type === t,
100
100
  }))
101
101
  const badgeMap = Object.fromEntries(TYPE_ORDER.map(t => [t, TYPE_BADGE[t]]))
102
102
  return { columns, badgeMap }
103
103
  }
104
104
 
105
- function useQuestionBankBoardModel(rows: QuestionBankItem[], groupByColumnKey: string) {
105
+ function useLibraryBoardModel(rows: LibraryItem[], groupByColumnKey: string) {
106
106
  return React.useMemo(() => {
107
107
  if (groupByColumnKey === "topic") {
108
108
  const { columns, badgeMap } = topicBoardColumns(rows)
@@ -121,19 +121,19 @@ function useQuestionBankBoardModel(rows: QuestionBankItem[], groupByColumnKey: s
121
121
  }, [rows, groupByColumnKey])
122
122
  }
123
123
 
124
- function QuestionBankBoardCard({
124
+ function LibraryBoardCard({
125
125
  row,
126
126
  onToggleFavorite,
127
127
  onRowActivate,
128
128
  }: {
129
- row: QuestionBankItem
130
- onToggleFavorite: (row: QuestionBankItem) => void
131
- onRowActivate?: (row: QuestionBankItem) => void
129
+ row: LibraryItem
130
+ onToggleFavorite: (row: LibraryItem) => void
131
+ onRowActivate?: (row: LibraryItem) => void
132
132
  }) {
133
133
  const initials = initialsFromDisplayName(row.author)
134
134
  return (
135
135
  <ListPageBoardCard
136
- className={cn(QUESTION_BANK_FAVORITE_HOVER_GROUP, "w-full")}
136
+ className={cn(LIBRARY_FAVORITE_HOVER_GROUP, "w-full")}
137
137
  onClick={onRowActivate ? () => onRowActivate(row) : undefined}
138
138
  >
139
139
  <ListPageBoardCardHeader>
@@ -148,7 +148,7 @@ function QuestionBankBoardCard({
148
148
  )}
149
149
  trailing={(
150
150
  <div className="flex shrink-0 items-start gap-1">
151
- <QuestionBankFavoriteButton row={row} onToggleFavorite={onToggleFavorite} />
151
+ <LibraryFavoriteButton row={row} onToggleFavorite={onToggleFavorite} />
152
152
  <ListPageBoardCardAvatar initials={initials} />
153
153
  </div>
154
154
  )}
@@ -166,26 +166,26 @@ function QuestionBankBoardCard({
166
166
  )
167
167
  }
168
168
 
169
- export const QUESTION_BANK_BOARD_GROUP_OPTIONS = [
169
+ export const LIBRARY_BOARD_GROUP_OPTIONS = [
170
170
  { key: "topic", label: "Topic" },
171
171
  { key: "difficulty", label: "Difficulty" },
172
172
  { key: "type", label: "Type" },
173
173
  ] as const
174
174
 
175
- export function QuestionBankBoardView({
175
+ export function LibraryBoardView({
176
176
  rows,
177
177
  groupByColumnKey,
178
178
  onToggleFavorite,
179
179
  onRowActivate,
180
180
  }: {
181
- rows: QuestionBankItem[]
181
+ rows: LibraryItem[]
182
182
  groupByColumnKey: string
183
- onToggleFavorite: (row: QuestionBankItem) => void
184
- onRowActivate?: (row: QuestionBankItem) => void
183
+ onToggleFavorite: (row: LibraryItem) => void
184
+ onRowActivate?: (row: LibraryItem) => void
185
185
  }) {
186
- const allowed = QUESTION_BANK_BOARD_GROUP_OPTIONS.some(o => o.key === groupByColumnKey)
186
+ const allowed = LIBRARY_BOARD_GROUP_OPTIONS.some(o => o.key === groupByColumnKey)
187
187
  const key = allowed ? groupByColumnKey : "topic"
188
- const { columns, badgeMap } = useQuestionBankBoardModel(rows, key)
188
+ const { columns, badgeMap } = useLibraryBoardModel(rows, key)
189
189
 
190
190
  return (
191
191
  <ListPageBoardTemplate
@@ -195,7 +195,7 @@ export function QuestionBankBoardView({
195
195
  columnCountBadgeClassName={badgeMap}
196
196
  emptyColumnLabel="No questions"
197
197
  renderCard={row => (
198
- <QuestionBankBoardCard row={row} onToggleFavorite={onToggleFavorite} onRowActivate={onRowActivate} />
198
+ <LibraryBoardCard row={row} onToggleFavorite={onToggleFavorite} onRowActivate={onRowActivate} />
199
199
  )}
200
200
  />
201
201
  )