@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,48 +1,17 @@
1
1
  /**
2
2
  * Searchable ⌘K rows from mock/API data. Wire new sources here — not in `command-menu-config.ts`.
3
+ *
4
+ * In this demo app the global ⌘K palette ships with route + Ask Leo entries only.
5
+ * When a consumer adds a real data source (e.g. a Students hub), build a
6
+ * `CommandMenuGroup` here with `searchOnly: true` so the palette stays
7
+ * lightweight on open and the items only surface once the user types.
3
8
  */
4
9
 
5
- import type { CommandMenuGroup, CommandMenuItem } from "@/lib/command-menu-config"
6
- import { ALL_PLACEMENTS } from "@/lib/mock/placements"
10
+ import type { CommandMenuGroup } from "@/lib/command-menu-config"
7
11
 
8
- function sampleRowSearchItems(): CommandMenuItem[] {
9
- return ALL_PLACEMENTS.map((p) => {
10
- const nameParts = p.student.trim().split(/\s+/)
11
- return {
12
- id: `sample-row-${p.id}`,
13
- label: `Row ${p.id} — ${p.student}`,
14
- icon: "fa-light fa-table",
15
- href: `/data-list/${p.id}`,
16
- keywords: [
17
- `row ${p.id}`,
18
- p.student,
19
- ...nameParts,
20
- p.program,
21
- p.site,
22
- p.internship,
23
- p.specialization,
24
- p.email,
25
- p.supervisor,
26
- p.status,
27
- p.compliance,
28
- ]
29
- .filter(Boolean)
30
- .join(" "),
31
- }
32
- })
33
- }
34
-
35
- /** Built once at module load — avoids remapping all placement rows on every layout render. */
36
- export const COMMAND_MENU_SEARCH_DATA_GROUPS: CommandMenuGroup[] = [
37
- {
38
- id: "sample-rows",
39
- heading: "Demo rows",
40
- items: sampleRowSearchItems(),
41
- searchOnly: true,
42
- },
43
- ]
12
+ /** Demo rows for hubs — none in this app. Real apps populate this from their primary entity. */
13
+ export const COMMAND_MENU_SEARCH_DATA_GROUPS: CommandMenuGroup[] = []
44
14
 
45
- /** Demo rows for the list hub — search-only so the palette stays lightweight on open. */
46
15
  export function getCommandMenuSearchDataGroups(): CommandMenuGroup[] {
47
16
  return COMMAND_MENU_SEARCH_DATA_GROUPS
48
17
  }
@@ -1,19 +1,20 @@
1
1
  /**
2
- * Question bank authoring — health-science domain constants for `NewQuestionAuthoring`.
2
+ * Library authoring — generic demo constants for the new-item composer.
3
3
  *
4
- * Storage in `lib/mock/question-bank.ts` keeps the simple `QuestionBankType` enum
4
+ * Storage in `lib/mock/library.ts` keeps the simple `LibraryItemType` enum
5
5
  * (`multiple_choice` | `true_false` | `short_answer`). The authoring surface
6
- * exposes the richer item-writer model that health-science assessments rely on
7
- * (NBME / NCLEX / OSCE style) and maps back to that base enum on save.
6
+ * exposes a richer item-writer model and maps back to that base enum on save.
7
+ *
8
+ * All copy is intentionally generic so the demo applies to any product domain.
8
9
  */
9
10
 
10
- import type { QuestionBankType, QuestionBankBloomLevel } from "@/lib/mock/question-bank"
11
+ import type { LibraryItemType, LibraryTierLevel } from "@/lib/mock/library"
11
12
 
12
13
  // ─────────────────────────────────────────────────────────────────────────────
13
- // Question type
14
+ // Item type
14
15
  // ─────────────────────────────────────────────────────────────────────────────
15
16
 
16
- /** Authoring-time question type — richer than the storage enum. */
17
+ /** Authoring-time item type — richer than the storage enum. */
17
18
  export type AuthoringQuestionType =
18
19
  | "mcq_single"
19
20
  | "mcq_multiple"
@@ -38,17 +39,17 @@ export interface AuthoringQuestionTypeOption {
38
39
  /** "Single best answer", "Multiple response", etc. — appears under the title. */
39
40
  badge?: string
40
41
  /** Maps to the storage type when persisting. */
41
- storageType: QuestionBankType
42
+ storageType: LibraryItemType
42
43
  }
43
44
 
44
45
  export const AUTHORING_QUESTION_TYPES: readonly AuthoringQuestionTypeOption[] = [
45
46
  {
46
47
  value: "mcq_single",
47
- label: "Multiple choice",
48
- shortLabel: "Multiple choice",
48
+ label: "Single choice",
49
+ shortLabel: "Single choice",
49
50
  icon: "fa-list-radio",
50
51
  description:
51
- "NBME-style. Stem describes a clinical scenario; pick the one best option. Default 5 distractors.",
52
+ "One correct answer from a set of options. Default 5 distractors.",
52
53
  tileSummary: "Single correct answer from a set of options",
53
54
  badge: "Single best answer",
54
55
  storageType: "multiple_choice",
@@ -59,7 +60,7 @@ export const AUTHORING_QUESTION_TYPES: readonly AuthoringQuestionTypeOption[] =
59
60
  shortLabel: "Multi-select",
60
61
  icon: "fa-list-check",
61
62
  description:
62
- "NCLEX-style. Learner selects every correct option from the list. Common for safety and prioritisation items.",
63
+ "Select every correct option from the list. Optional partial credit.",
63
64
  tileSummary: "One or more correct answers — partial credit",
64
65
  badge: "Multiple response",
65
66
  storageType: "multiple_choice",
@@ -70,7 +71,7 @@ export const AUTHORING_QUESTION_TYPES: readonly AuthoringQuestionTypeOption[] =
70
71
  shortLabel: "True / False",
71
72
  icon: "fa-circle-half-stroke",
72
73
  description:
73
- "Use sparingly best for unambiguous facts. Avoid for nuanced clinical judgment.",
74
+ "Use for simple, unambiguous statements.",
74
75
  tileSummary: "Binary statement — quick recall",
75
76
  storageType: "true_false",
76
77
  },
@@ -80,7 +81,7 @@ export const AUTHORING_QUESTION_TYPES: readonly AuthoringQuestionTypeOption[] =
80
81
  shortLabel: "Short answer",
81
82
  icon: "fa-input-text",
82
83
  description:
83
- "Free-text response with a model answer + acceptable variants. Good for definitions and one-line answers.",
84
+ "Free-text response with an expected answer + acceptable variants.",
84
85
  tileSummary: "Single word or short phrase, exact-match",
85
86
  storageType: "short_answer",
86
87
  },
@@ -90,7 +91,7 @@ export const AUTHORING_QUESTION_TYPES: readonly AuthoringQuestionTypeOption[] =
90
91
  shortLabel: "Numeric",
91
92
  icon: "fa-input-numeric",
92
93
  description:
93
- "Number-only response with optional units and a ± tolerance band. Auto-graded on submission.",
94
+ "Number-only response with optional units and a ± tolerance band.",
94
95
  tileSummary: "Number with units and tolerance band",
95
96
  badge: "Auto-graded",
96
97
  storageType: "short_answer",
@@ -101,7 +102,7 @@ export const AUTHORING_QUESTION_TYPES: readonly AuthoringQuestionTypeOption[] =
101
102
  shortLabel: "Essay",
102
103
  icon: "fa-paragraph",
103
104
  description:
104
- "Long-form response graded against a rubric. Use for clinical reasoning and care-plan items.",
105
+ "Long-form response graded against a rubric.",
105
106
  tileSummary: "Long response — rubric-graded",
106
107
  badge: "Rubric",
107
108
  storageType: "short_answer",
@@ -112,7 +113,7 @@ export const AUTHORING_QUESTION_TYPES: readonly AuthoringQuestionTypeOption[] =
112
113
  shortLabel: "Fill in the blank",
113
114
  icon: "fa-text-size",
114
115
  description:
115
- "Sentence with one or more {{blanks}}; learners type the missing word(s). List accepted answers per blank.",
116
+ "Sentence with one or more {{blanks}}; respondents type the missing word(s).",
116
117
  tileSummary: "Sentence with one or more blanks to fill",
117
118
  storageType: "short_answer",
118
119
  },
@@ -123,7 +124,7 @@ export const AUTHORING_QUESTION_TYPES: readonly AuthoringQuestionTypeOption[] =
123
124
  icon: "fa-arrow-right-arrow-left",
124
125
  description:
125
126
  "Two columns — pair each prompt on the left to its correct match on the right.",
126
- tileSummary: "Pair terms on the left to definitions on the right",
127
+ tileSummary: "Pair entries on the left to entries on the right",
127
128
  storageType: "multiple_choice",
128
129
  },
129
130
  {
@@ -132,7 +133,7 @@ export const AUTHORING_QUESTION_TYPES: readonly AuthoringQuestionTypeOption[] =
132
133
  shortLabel: "Ordering",
133
134
  icon: "fa-list-ol",
134
135
  description:
135
- "Show the steps; the learner re-orders them into the correct sequence (e.g. ACLS algorithm steps).",
136
+ "Show steps; respondents re-order them into the correct sequence.",
136
137
  tileSummary: "Place items in the correct sequence",
137
138
  storageType: "multiple_choice",
138
139
  },
@@ -142,7 +143,7 @@ export const AUTHORING_QUESTION_TYPES: readonly AuthoringQuestionTypeOption[] =
142
143
  shortLabel: "Hotspot",
143
144
  icon: "fa-bullseye-pointer",
144
145
  description:
145
- "Image-based item — learner clicks the correct region (e.g. anatomy, x-ray, ECG).",
146
+ "Image-based item — respondents click the correct region.",
146
147
  tileSummary: "Click the correct region of an image",
147
148
  badge: "Image-based",
148
149
  storageType: "multiple_choice",
@@ -154,87 +155,87 @@ export function authoringQuestionType(value: AuthoringQuestionType): AuthoringQu
154
155
  }
155
156
 
156
157
  // ─────────────────────────────────────────────────────────────────────────────
157
- // Difficulty + Bloom + cognitive level (NBME)
158
+ // Level + tier + cognitive level
158
159
  // ─────────────────────────────────────────────────────────────────────────────
159
160
 
160
161
  export const AUTHORING_DIFFICULTY_OPTIONS = [
161
- { value: "easy", label: "Easy", description: "Recall · expected 80% correct" },
162
- { value: "medium", label: "Medium", description: "Application · 50–80% correct" },
163
- { value: "hard", label: "Hard", description: "Analysis · 50% correct" },
162
+ { value: "easy", label: "Low", description: "Quick recall most respondents complete" },
163
+ { value: "medium", label: "Normal", description: "Standard application mixed completion" },
164
+ { value: "hard", label: "High", description: "Deeper analysis fewer respondents complete" },
164
165
  ] as const
165
166
 
166
- export const AUTHORING_BLOOM_OPTIONS: readonly { value: QuestionBankBloomLevel; label: string; hint: string }[] = [
167
- { value: "Remember", label: "Remember", hint: "Recall facts, terms, basic concepts" },
168
- { value: "Understand", label: "Understand", hint: "Explain, summarise, classify" },
169
- { value: "Apply", label: "Apply", hint: "Use knowledge in a new situation" },
170
- { value: "Analyze", label: "Analyze", hint: "Break information apart, examine relationships" },
171
- { value: "Evaluate", label: "Evaluate", hint: "Justify a stand, defend a decision" },
172
- { value: "Create", label: "Create", hint: "Produce new or original work" },
167
+ export const AUTHORING_BLOOM_OPTIONS: readonly { value: LibraryTierLevel; label: string; hint: string }[] = [
168
+ { value: "Tier 1", label: "Tier 1", hint: "Recall basic facts" },
169
+ { value: "Tier 2", label: "Tier 2", hint: "Explain, summarise, classify" },
170
+ { value: "Tier 3", label: "Tier 3", hint: "Use knowledge in a new situation" },
171
+ { value: "Tier 4", label: "Tier 4", hint: "Break information apart, examine relationships" },
172
+ { value: "Tier 5", label: "Tier 5", hint: "Justify a stand, defend a decision" },
173
+ { value: "Tier 6", label: "Tier 6", hint: "Produce new or original work" },
173
174
  ] as const
174
175
 
175
- /** NBME-aligned cognitive level — separate from Bloom (broader). */
176
+ /** Cognitive level — broader bucketing for analytics. */
176
177
  export const AUTHORING_COG_LEVEL_OPTIONS = [
177
- { value: "recall", label: "Recall", hint: "Definitions, mechanisms, anatomy" },
178
- { value: "application", label: "Application", hint: "Apply concept to a new patient scenario" },
179
- { value: "analysis", label: "Analysis", hint: "Compare, evaluate, synthesise findings" },
178
+ { value: "recall", label: "Recall", hint: "Definitions and core concepts" },
179
+ { value: "application", label: "Application", hint: "Apply concept to a new scenario" },
180
+ { value: "analysis", label: "Analysis", hint: "Compare, evaluate, synthesise" },
180
181
  ] as const
181
182
  export type AuthoringCogLevel = typeof AUTHORING_COG_LEVEL_OPTIONS[number]["value"]
182
183
 
183
184
  // ─────────────────────────────────────────────────────────────────────────────
184
- // Subject area / body system / discipline / phase
185
+ // Category / subject / track / phase
185
186
  // ─────────────────────────────────────────────────────────────────────────────
186
187
 
187
188
  export const AUTHORING_SUBJECT_AREAS = [
188
- "Anatomy",
189
- "Physiology",
190
- "Pathology",
191
- "Pharmacology",
192
- "Microbiology & immunology",
193
- "Behavioral science",
194
- "Biochemistry & genetics",
195
- "Public health & epidemiology",
196
- "Clinical skills",
197
- "Communication & ethics",
189
+ "Category 1",
190
+ "Category 2",
191
+ "Category 3",
192
+ "Category 4",
193
+ "Category 5",
194
+ "Category 6",
195
+ "Category 7",
196
+ "Category 8",
197
+ "Category 9",
198
+ "Category 10",
198
199
  ] as const
199
200
  export type AuthoringSubjectArea = typeof AUTHORING_SUBJECT_AREAS[number]
200
201
 
201
202
  export const AUTHORING_BODY_SYSTEMS = [
202
- { value: "cardiovascular", label: "Cardiovascular", icon: "fa-heart-pulse" },
203
- { value: "respiratory", label: "Respiratory", icon: "fa-lungs" },
204
- { value: "renal", label: "Renal & urinary", icon: "fa-droplet" },
205
- { value: "gastrointestinal", label: "Gastrointestinal", icon: "fa-stomach" },
206
- { value: "endocrine", label: "Endocrine", icon: "fa-flask" },
207
- { value: "musculoskeletal", label: "Musculoskeletal", icon: "fa-bone" },
208
- { value: "nervous", label: "Nervous", icon: "fa-brain" },
209
- { value: "reproductive", label: "Reproductive", icon: "fa-venus-mars" },
210
- { value: "hematologic", label: "Hematologic & oncologic", icon: "fa-vial" },
211
- { value: "immune", label: "Immune", icon: "fa-shield-virus" },
212
- { value: "skin", label: "Skin & subcutaneous", icon: "fa-hand-dots" },
213
- { value: "behavioral_psych", label: "Behavioral / psych", icon: "fa-comments" },
214
- { value: "multisystem", label: "Multisystem", icon: "fa-circle-nodes" },
203
+ { value: "topic-a", label: "Topic A", icon: "fa-circle" },
204
+ { value: "topic-b", label: "Topic B", icon: "fa-circle" },
205
+ { value: "topic-c", label: "Topic C", icon: "fa-circle" },
206
+ { value: "topic-d", label: "Topic D", icon: "fa-circle" },
207
+ { value: "topic-e", label: "Topic E", icon: "fa-circle" },
208
+ { value: "topic-f", label: "Topic F", icon: "fa-circle" },
209
+ { value: "topic-g", label: "Topic G", icon: "fa-circle" },
210
+ { value: "topic-h", label: "Topic H", icon: "fa-circle" },
211
+ { value: "topic-i", label: "Topic I", icon: "fa-circle" },
212
+ { value: "topic-j", label: "Topic J", icon: "fa-circle" },
213
+ { value: "topic-k", label: "Topic K", icon: "fa-circle" },
214
+ { value: "topic-l", label: "Topic L", icon: "fa-circle" },
215
+ { value: "topic-multi", label: "Multi-topic", icon: "fa-circle-nodes" },
215
216
  ] as const
216
217
  export type AuthoringBodySystem = typeof AUTHORING_BODY_SYSTEMS[number]["value"]
217
218
 
218
219
  export const AUTHORING_DISCIPLINES = [
219
- "Medicine (MD / DO)",
220
- "Nursing (BSN / MSN)",
221
- "Pharmacy (PharmD)",
222
- "Dental (DMD / DDS)",
223
- "Physical therapy (DPT)",
224
- "Occupational therapy",
225
- "Physician assistant",
226
- "Respiratory therapy",
227
- "Medical lab science",
228
- "Radiologic sciences",
229
- "Public health (MPH)",
220
+ "Track 1",
221
+ "Track 2",
222
+ "Track 3",
223
+ "Track 4",
224
+ "Track 5",
225
+ "Track 6",
226
+ "Track 7",
227
+ "Track 8",
228
+ "Track 9",
229
+ "Track 10",
230
+ "Track 11",
230
231
  ] as const
231
232
  export type AuthoringDiscipline = typeof AUTHORING_DISCIPLINES[number]
232
233
 
233
234
  export const AUTHORING_PHASES = [
234
- { value: "preclinical", label: "Pre-clinical", hint: "Foundational sciences" },
235
- { value: "clinical", label: "Clinical", hint: "Clerkships / practicum" },
236
- { value: "residency", label: "Residency / fellowship", hint: "Post-graduate training" },
237
- { value: "ce", label: "Continuing education", hint: "Practising clinicians" },
235
+ { value: "preclinical", label: "Phase 1", hint: "Early stage" },
236
+ { value: "clinical", label: "Phase 2", hint: "Practice stage" },
237
+ { value: "residency", label: "Phase 3", hint: "Advanced stage" },
238
+ { value: "ce", label: "Phase 4", hint: "Ongoing stage" },
238
239
  ] as const
239
240
  export type AuthoringPhase = typeof AUTHORING_PHASES[number]["value"]
240
241
 
@@ -248,31 +249,31 @@ export const AUTHORING_STATUS_OPTIONS: readonly { value: AuthoringStatus; label:
248
249
  {
249
250
  value: "draft",
250
251
  label: "Draft",
251
- description: "Visible only to authors. Not eligible for assessments.",
252
+ description: "Visible only to owners. Not eligible for use.",
252
253
  icon: "fa-file-pen",
253
254
  },
254
255
  {
255
256
  value: "in_review",
256
257
  label: "In review",
257
- description: "Awaiting subject-matter expert peer review.",
258
+ description: "Awaiting peer review.",
258
259
  icon: "fa-magnifying-glass",
259
260
  },
260
261
  {
261
262
  value: "approved",
262
263
  label: "Approved",
263
- description: "SME signed off. Ready to publish to the live bank.",
264
+ description: "Reviewer signed off. Ready to publish.",
264
265
  icon: "fa-circle-check",
265
266
  },
266
267
  {
267
268
  value: "published",
268
269
  label: "Published",
269
- description: "Live in the bank. Available for exam / quiz selection.",
270
+ description: "Live in the library. Available for use.",
270
271
  icon: "fa-broadcast-tower",
271
272
  },
272
273
  {
273
274
  value: "retired",
274
275
  label: "Retired",
275
- description: "Removed from active use. Kept for audit and reuse history.",
276
+ description: "Removed from active use. Kept for history.",
276
277
  icon: "fa-box-archive",
277
278
  },
278
279
  ] as const
@@ -285,24 +286,24 @@ export const AUTHORING_DEFAULT_OPTION_COUNT = 5
285
286
  export const AUTHORING_MIN_OPTION_COUNT = 2
286
287
  export const AUTHORING_MAX_OPTION_COUNT = 8
287
288
 
288
- /** Stem placeholder — modelled on a typical NBME / clerkship vignette. */
289
- export const AUTHORING_STEM_PLACEHOLDER = `A 58-year-old man presents to the emergency department with substernal chest pressure that began two hours ago while mowing the lawn. The pain radiates to the left jaw and is associated with diaphoresis and nausea. Past medical history is significant for hypertension and type 2 diabetes mellitus. Vital signs show blood pressure 158/92 mm Hg, heart rate 102/min, respirations 20/min. Physical examination is notable for an S4 gallop. ECG shows 2 mm ST-segment elevation in leads II, III, and aVF.`
289
+ /** Name placeholder — generic primary line for the demo composer. */
290
+ export const AUTHORING_STEM_PLACEHOLDER = `Item 13 sample primary line for a new library entry. Describe the item in one or two sentences so respondents understand the prompt without needing extra context. Use placeholder content that demonstrates the layout without committing to a specific product domain.`
290
291
 
291
292
  export const AUTHORING_LEAD_IN_PLACEHOLDER =
292
- "Which of the following is the most likely diagnosis?"
293
+ "Which option fits best?"
293
294
 
294
- /** Best-practice rationale prompt — author-side, not student-facing. */
295
+ /** Best-practice notes prompt — owner-side, not respondent-facing. */
295
296
  export const AUTHORING_RATIONALE_PLACEHOLDER =
296
- "Explain why this option is correct (or why this distractor is plausible). Cite mechanism, guideline, or reference where possible."
297
+ "Explain why this option is correct (or why this distractor is plausible). Cite the source or reference where possible."
297
298
 
298
299
  /**
299
- * Draft question handle assigned when the composer route loads.
300
- * Format: `Q-YYMM-XXXX` (e.g. `Q-2605-A3F2`). Generate on the server and pass
301
- * into `NewQuestionComposer` so SSR and hydration share one value.
300
+ * Draft item handle assigned when the composer route loads.
301
+ * Format: `LIB-YYMM-XXXX` (e.g. `LIB-2605-A3F2`). Generate on the server and pass
302
+ * into the composer so SSR and hydration share one value.
302
303
  */
303
304
  export function generateDraftQuestionId(now = new Date()): string {
304
305
  const yy = String(now.getFullYear()).slice(-2)
305
306
  const mm = String(now.getMonth() + 1).padStart(2, "0")
306
307
  const rand = Math.random().toString(16).slice(2, 6).toUpperCase().padEnd(4, "0")
307
- return `Q-${yy}${mm}-${rand}`
308
+ return `LIB-${yy}${mm}-${rand}`
308
309
  }
@@ -0,0 +1,19 @@
1
+ import { patchLibraryUrlSearchParams } from "@/lib/library-nav"
2
+
3
+ /** Rotating example queries for dedicated search composers on list/find surfaces. */
4
+ export const LIBRARY_DEDICATED_SEARCH_PLACEHOLDERS = [
5
+ "items tagged with Tag 1 and Category 2",
6
+ "everything Owner A edited this month",
7
+ "Folder 1 entries marked High",
8
+ "find LIB-2026-001 and anything like it",
9
+ "drafts from the most recent reference set",
10
+ "Type 1 items I still need for the demo block",
11
+ ] as const
12
+
13
+ export function patchLibraryDedicatedSearchParams(
14
+ current: URLSearchParams,
15
+ submittedText: string,
16
+ ): URLSearchParams {
17
+ const t = submittedText.trim()
18
+ return patchLibraryUrlSearchParams(current, { q: t || null })
19
+ }
@@ -0,0 +1,90 @@
1
+ import type { DiscoveryHubSearchGroup } from "@/lib/discovery-hub"
2
+ import {
3
+ LIBRARY_ENTRY_PATH,
4
+ LIBRARY_ALL_PATH,
5
+ } from "@/lib/library-nav"
6
+
7
+ export type { DiscoveryHubSearchGroup, DiscoveryHubSearchItem } from "@/lib/discovery-hub"
8
+
9
+ export function buildLibraryHubSearchGroups(): DiscoveryHubSearchGroup[] {
10
+ return [
11
+ {
12
+ id: "ai-create",
13
+ heading: "Create with AI",
14
+ items: [
15
+ {
16
+ id: "ai-mcq",
17
+ label: "Draft a choice-style item from a prompt",
18
+ keywords: "ai leo create item choice prompt",
19
+ askLeoPrompt:
20
+ "Help me draft a new choice-style library item. Ask clarifying questions about category, level, and intent before proposing a name and options.",
21
+ },
22
+ {
23
+ id: "ai-osce",
24
+ label: "Generate a checklist from a sample scenario",
25
+ keywords: "ai leo checklist scenario",
26
+ askLeoPrompt:
27
+ "I want to generate a checklist from a sample scenario. Walk me through the scenario details you need, then propose observable steps and scoring notes.",
28
+ },
29
+ {
30
+ id: "ai-remediation",
31
+ label: "Turn flagged items into follow-up entries",
32
+ keywords: "ai leo follow-up review flagged items",
33
+ askLeoPrompt:
34
+ "Turn a list of flagged items into follow-up library entries. Ask what category and level to target, then suggest short-text or choice-style follow-ups.",
35
+ },
36
+ {
37
+ id: "ai-bank-outline",
38
+ label: "Outline a new library section",
39
+ keywords: "ai leo outline library section folders",
40
+ askLeoPrompt:
41
+ "Help me outline a new library section. Suggest folder structure, item types, and a balanced mix of levels before we add items.",
42
+ },
43
+ ],
44
+ },
45
+ {
46
+ id: "actions",
47
+ heading: "Quick actions",
48
+ items: [
49
+ {
50
+ id: "browse-library",
51
+ label: "Browse the library",
52
+ keywords: "library table folder panel tree views",
53
+ icon: "fa-light fa-table-list",
54
+ href: LIBRARY_ALL_PATH,
55
+ },
56
+ {
57
+ id: "browse-my",
58
+ label: "Open my items",
59
+ keywords: "my items owner scope",
60
+ icon: "fa-light fa-user",
61
+ href: `${LIBRARY_ALL_PATH}?scope=my`,
62
+ },
63
+ {
64
+ id: "new-question",
65
+ label: "Create new item",
66
+ keywords: "new item create draft owner",
67
+ icon: "fa-light fa-plus",
68
+ askLeoPrompt:
69
+ "Help me create a new library item. Start by asking for category, item type, level, and intent, then draft the name, options, and notes.",
70
+ },
71
+ {
72
+ id: "hub-entry",
73
+ label: "Library home",
74
+ keywords: "home hub search",
75
+ icon: "fa-light fa-house",
76
+ href: LIBRARY_ENTRY_PATH,
77
+ },
78
+ ],
79
+ },
80
+ ]
81
+ }
82
+
83
+ export const LIBRARY_HUB_SEARCH_PLACEHOLDER =
84
+ "Search items, folders, or describe what you want to create…"
85
+
86
+ export const LIBRARY_HUB_ASK_LEO_PROMPTS = [
87
+ "Draft five choice-style items for Category 1",
88
+ "Suggest folder names for a new library section",
89
+ "Rewrite this name for clarity",
90
+ ] as const