@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.
- package/CHANGELOG.md +701 -6
- package/README.md +138 -0
- package/bin/init.mjs +134 -31
- package/consumer-extras/cursor-rules/exxat-board-cards.mdc +1 -1
- package/consumer-extras/cursor-rules/exxat-centralized-list-dataset.mdc +2 -2
- package/consumer-extras/cursor-rules/exxat-collaboration-access.mdc +1 -1
- package/consumer-extras/cursor-rules/exxat-data-tables.mdc +2 -0
- package/consumer-extras/cursor-rules/exxat-dedicated-search-surfaces.mdc +1 -1
- package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +3 -3
- package/consumer-extras/cursor-rules/exxat-library-hub-header.mdc +28 -0
- package/consumer-extras/cursor-rules/exxat-mono-ids.mdc +1 -1
- package/consumer-extras/cursor-rules/exxat-person-identity-display.mdc +1 -1
- package/consumer-extras/cursor-rules/exxat-primary-nav-secondary-panel.mdc +6 -6
- package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +1 -1
- package/consumer-extras/cursor-skills/exxat-board-cards/SKILL.md +2 -2
- package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-collaboration-access/SKILL.md +3 -3
- package/consumer-extras/cursor-skills/exxat-dedicated-search-surfaces/SKILL.md +2 -2
- package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +7 -7
- package/consumer-extras/cursor-skills/exxat-kpi-flat-band/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-list-page-view-shells/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-mono-ids/SKILL.md +4 -4
- package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +8 -8
- package/consumer-extras/cursor-skills/exxat-token-economy/SKILL.md +277 -0
- package/consumer-extras/handbook/HANDBOOK.md +2 -0
- package/consumer-extras/handbook/glossary.md +2 -1
- package/consumer-extras/handbook/reference-implementations.md +31 -4
- package/consumer-extras/patterns/collaboration-access-pattern.md +7 -7
- package/consumer-extras/patterns/data-views-pattern.md +18 -16
- package/consumer-extras/patterns/kpi-flat-band-pattern.md +2 -2
- package/dist/components/data-table/index.js +2 -2
- package/dist/components/data-table/index.js.map +1 -1
- package/dist/components/data-table/pagination.js +3 -3
- package/dist/components/data-table/pagination.js.map +1 -1
- package/dist/components/data-table/use-table-state.d.ts +1 -1
- package/dist/components/data-table/use-table-state.js.map +1 -1
- package/dist/components/data-views/data-row-list.js.map +1 -1
- package/dist/components/data-views/finder-panel-view.d.ts +1 -1
- package/dist/components/data-views/finder-panel-view.js.map +1 -1
- package/dist/components/data-views/hub-table.d.ts +9 -3
- package/dist/components/data-views/hub-table.js +262 -40
- package/dist/components/data-views/hub-table.js.map +1 -1
- package/dist/components/data-views/index.js +262 -40
- package/dist/components/data-views/index.js.map +1 -1
- package/dist/components/data-views/list-page-split-hub-tokens.d.ts +2 -2
- package/dist/components/data-views/list-page-split-hub-tokens.js.map +1 -1
- package/dist/components/data-views/list-page-tree-column-header.d.ts +1 -1
- package/dist/components/data-views/list-page-tree-column-header.js.map +1 -1
- package/dist/components/data-views/list-page-tree-panel-shell.js.map +1 -1
- package/dist/components/data-views/os-folder-glyph.d.ts +1 -1
- package/dist/components/data-views/os-folder-glyph.js.map +1 -1
- package/dist/components/ui/avatar.d.ts +1 -1
- package/dist/components/ui/key-metrics.js.map +1 -1
- package/dist/index.js +136 -39
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/components/data-table/index.tsx +2 -2
- package/src/components/data-table/pagination.tsx +5 -1
- package/src/components/data-table/use-table-state.ts +1 -1
- package/src/components/data-views/data-row-list.tsx +1 -1
- package/src/components/data-views/finder-panel-view.tsx +2 -2
- package/src/components/data-views/hub-table.tsx +149 -41
- package/src/components/data-views/list-page-split-hub-tokens.ts +2 -2
- package/src/components/data-views/list-page-tree-column-header.tsx +1 -1
- package/src/components/data-views/os-folder-glyph.tsx +1 -1
- package/src/components/ui/key-metrics.tsx +1 -1
- package/template/.claude/skills/exxat-ds-skill/SKILL.md +8 -7
- package/template/.cursor/rules/exxat-accessibility.mdc +1 -1
- package/template/.cursor/rules/exxat-command-menu.mdc +1 -1
- package/template/.cursor/rules/exxat-dashboard-view-charts.mdc +6 -6
- package/template/.cursor/rules/exxat-data-tables.mdc +3 -3
- package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +5 -5
- package/template/.cursor/rules/exxat-mono-ids.mdc +1 -1
- package/template/.cursor/rules/exxat-page-vs-drawer.mdc +1 -1
- package/template/.cursor/rules/exxat-table-properties-drawer.mdc +1 -1
- package/template/AGENTS.md +43 -37
- package/template/app/(app)/columns/page.tsx +11 -0
- package/template/app/(app)/library/all/page.tsx +11 -0
- package/template/app/(app)/library/find/page.tsx +12 -0
- package/template/app/(app)/{question-bank → library}/layout.tsx +16 -16
- package/template/app/(app)/library/list/page.tsx +12 -0
- package/template/app/(app)/{question-bank → library}/new/page.tsx +10 -10
- package/template/app/(app)/library/page.tsx +11 -0
- package/template/app/(app)/tokens-themes/page.tsx +11 -0
- package/template/components/ask-leo-composer.tsx +2 -2
- package/template/components/columns-client.tsx +158 -0
- package/template/components/columns-showcase.tsx +541 -0
- package/template/components/data-views/index.ts +32 -6
- package/template/components/data-views/{question-bank-folder-tree-branch.tsx → library-folder-tree-branch.tsx} +19 -19
- package/template/components/data-views/table-cells.tsx +673 -0
- package/template/components/folder-details-shell.tsx +11 -11
- package/template/components/hub-tree-panel-view.tsx +24 -24
- package/template/components/{question-bank-board-view.tsx → library-board-view.tsx} +44 -44
- package/template/components/{question-bank-client.tsx → library-client.tsx} +82 -82
- package/template/components/{question-bank-dashboard-charts.tsx → library-dashboard-charts.tsx} +14 -14
- package/template/components/{question-bank-favorite-button.tsx → library-favorite-button.tsx} +7 -7
- package/template/components/{question-bank-hub-client.tsx → library-hub-client.tsx} +43 -43
- package/template/components/{question-bank-new-folder-sheet.tsx → library-new-folder-sheet.tsx} +14 -14
- package/template/components/{question-bank-os-folder-view.tsx → library-os-folder-view.tsx} +31 -31
- package/template/components/{question-bank-page-header.tsx → library-page-header.tsx} +6 -6
- package/template/components/library-panel-activator.tsx +8 -0
- package/template/components/{question-bank-secondary-nav.tsx → library-secondary-nav.tsx} +60 -60
- package/template/components/{question-bank-table.tsx → library-table.tsx} +97 -97
- package/template/components/list-hub-status-badge.tsx +2 -2
- package/template/components/{new-question-composer.tsx → new-library-item-form.tsx} +37 -37
- package/template/components/sidebar/app-sidebar.tsx +61 -5
- package/template/components/sidebar/secondary-panel.tsx +109 -56
- package/template/components/sidebar/sidebar-auto-collapse.tsx +2 -2
- package/template/components/sidebar/sidebar-auto-open.tsx +2 -1
- package/template/components/table-properties/types.ts +1 -1
- package/template/components/templates/discovery-hub-template.tsx +1 -1
- package/template/components/templates/new-focus-template.tsx +2 -2
- package/template/components/templates/secondary-panel-hub-template.tsx +1 -1
- package/template/components/tokens-secondary-nav.tsx +192 -0
- package/template/components/tokens-themes-client.tsx +476 -0
- package/template/components/tokens-themes-section.tsx +386 -0
- package/template/docs/HANDBOOK.md +187 -0
- package/template/docs/blueprints/README.md +1 -1
- package/template/docs/blueprints/board-card.md +1 -1
- package/template/docs/blueprints/data-table.md +2 -2
- package/template/docs/blueprints/list-page-template.md +3 -3
- package/template/docs/blueprints/page-header.md +4 -4
- package/template/docs/collaboration-access-pattern.md +7 -7
- package/template/docs/component-selection-guide.md +1 -1
- package/template/docs/data-views-pattern.md +18 -16
- package/template/docs/glossary.md +58 -0
- package/template/docs/kpi-flat-band-pattern.md +3 -3
- package/template/docs/kpi-trend-pattern.md +18 -3
- package/template/docs/large-dataset-strategy.md +155 -0
- package/template/docs/library-hub-header-pattern.md +25 -0
- package/template/docs/migrations/_template.md +1 -1
- package/template/docs/reference-implementations.md +151 -0
- package/template/docs/token-taxonomy.md +1 -1
- package/template/docs/voice-and-tone.md +262 -0
- package/template/eslint.config.mjs +9 -39
- package/template/hooks/use-secondary-panel-hub-nav.ts +10 -10
- package/template/lib/ask-leo-route-context.ts +6 -18
- package/template/lib/coach-mark-registry.ts +0 -16
- package/template/lib/command-menu-config.ts +5 -12
- package/template/lib/command-menu-search-data.ts +8 -39
- package/template/lib/{question-bank-authoring.ts → library-authoring.ts} +89 -88
- package/template/lib/library-dedicated-search.ts +19 -0
- package/template/lib/library-hub-search.ts +90 -0
- package/template/lib/library-nav.ts +477 -0
- package/template/lib/library-recent-searches.ts +22 -0
- package/template/lib/{placements-supported-views.ts → library-supported-views.ts} +2 -2
- package/template/lib/list-status-badges.ts +16 -104
- package/template/lib/mock/dashboard.ts +1 -1
- package/template/lib/mock/{question-bank-folders.ts → library-folders.ts} +30 -30
- package/template/lib/mock/library-header-collaborators.ts +54 -0
- package/template/lib/mock/{question-bank-inspector.ts → library-inspector.ts} +29 -29
- package/template/lib/mock/{question-bank-kpi.ts → library-kpi.ts} +20 -20
- package/template/lib/mock/library.ts +249 -0
- package/template/lib/mock/navigation.tsx +32 -26
- package/template/lib/table-state-lifecycle.ts +1 -1
- package/template/next.config.mjs +7 -4
- package/template/package.json +0 -1
- package/tokens/hooks-index.json +2874 -0
- package/consumer-extras/cursor-rules/exxat-question-bank-hub-header.mdc +0 -28
- package/template/app/(app)/examples/page.tsx +0 -41
- package/template/app/(app)/question-bank/find/page.tsx +0 -12
- package/template/app/(app)/question-bank/library/page.tsx +0 -11
- package/template/app/(app)/question-bank/list/page.tsx +0 -12
- package/template/app/(app)/question-bank/page.tsx +0 -11
- package/template/components/compliance-board-view.tsx +0 -142
- package/template/components/compliance-client.tsx +0 -92
- package/template/components/compliance-page-header.tsx +0 -89
- package/template/components/compliance-table.tsx +0 -468
- package/template/components/data-view-dashboard-charts-compliance.tsx +0 -963
- package/template/components/data-view-dashboard-charts-team.tsx +0 -971
- package/template/components/data-view-dashboard-charts.tsx +0 -1503
- package/template/components/new-placement-back-btn.tsx +0 -28
- package/template/components/new-placement-form.tsx +0 -942
- package/template/components/placement-board-card.tsx +0 -250
- package/template/components/placement-detail.tsx +0 -438
- package/template/components/placements-board-view.tsx +0 -397
- package/template/components/placements-client.tsx +0 -220
- package/template/components/placements-list-view.tsx +0 -124
- package/template/components/placements-page-header.tsx +0 -166
- package/template/components/placements-table-cells.test.tsx +0 -22
- package/template/components/placements-table-cells.tsx +0 -173
- package/template/components/placements-table-columns.tsx +0 -210
- package/template/components/placements-table.tsx +0 -934
- package/template/components/question-bank-panel-activator.tsx +0 -8
- package/template/components/rotations-empty-state.tsx +0 -50
- package/template/components/rotations-panel-activator.tsx +0 -8
- package/template/components/sites-board-view.tsx +0 -67
- package/template/components/sites-client.tsx +0 -154
- package/template/components/sites-table.tsx +0 -249
- package/template/components/team-board-view.tsx +0 -122
- package/template/components/team-client.tsx +0 -100
- package/template/components/team-page-header.tsx +0 -92
- package/template/components/team-table.tsx +0 -553
- package/template/docs/question-bank-hub-header-pattern.md +0 -25
- package/template/lib/compliance-supported-views.ts +0 -10
- package/template/lib/data-view-dashboard-placements-layout.ts +0 -215
- package/template/lib/mock/compliance-kpi.ts +0 -61
- package/template/lib/mock/compliance.ts +0 -146
- package/template/lib/mock/placements-kpi.ts +0 -134
- package/template/lib/mock/placements.ts +0 -176
- package/template/lib/mock/question-bank-header-collaborators.ts +0 -54
- package/template/lib/mock/question-bank.ts +0 -249
- package/template/lib/mock/sites-directory.ts +0 -16
- package/template/lib/mock/sites-kpi.ts +0 -25
- package/template/lib/mock/team-kpi.ts +0 -60
- package/template/lib/mock/team.ts +0 -118
- package/template/lib/placement-board-card-layout.ts +0 -79
- package/template/lib/question-bank-dedicated-search.ts +0 -19
- package/template/lib/question-bank-hub-search.ts +0 -90
- package/template/lib/question-bank-nav.ts +0 -477
- package/template/lib/question-bank-recent-searches.ts +0 -22
- package/template/lib/question-bank-supported-views.ts +0 -12
- package/template/lib/sites-supported-views.ts +0 -10
- 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
|
|
6
|
-
import { ALL_PLACEMENTS } from "@/lib/mock/placements"
|
|
10
|
+
import type { CommandMenuGroup } from "@/lib/command-menu-config"
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
*
|
|
2
|
+
* Library authoring — generic demo constants for the new-item composer.
|
|
3
3
|
*
|
|
4
|
-
* Storage in `lib/mock/
|
|
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
|
|
7
|
-
*
|
|
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 {
|
|
11
|
+
import type { LibraryItemType, LibraryTierLevel } from "@/lib/mock/library"
|
|
11
12
|
|
|
12
13
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
|
-
//
|
|
14
|
+
// Item type
|
|
14
15
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
15
16
|
|
|
16
|
-
/** Authoring-time
|
|
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:
|
|
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: "
|
|
48
|
-
shortLabel: "
|
|
48
|
+
label: "Single choice",
|
|
49
|
+
shortLabel: "Single choice",
|
|
49
50
|
icon: "fa-list-radio",
|
|
50
51
|
description:
|
|
51
|
-
"
|
|
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
|
-
"
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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}};
|
|
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
|
|
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
|
|
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 —
|
|
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
|
-
//
|
|
158
|
+
// Level + tier + cognitive level
|
|
158
159
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
159
160
|
|
|
160
161
|
export const AUTHORING_DIFFICULTY_OPTIONS = [
|
|
161
|
-
{ value: "easy", label: "
|
|
162
|
-
{ value: "medium", label: "
|
|
163
|
-
{ value: "hard", label: "
|
|
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:
|
|
167
|
-
{ value: "
|
|
168
|
-
{ value: "
|
|
169
|
-
{ value: "
|
|
170
|
-
{ value: "
|
|
171
|
-
{ value: "
|
|
172
|
-
{ value: "
|
|
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
|
-
/**
|
|
176
|
+
/** Cognitive level — broader bucketing for analytics. */
|
|
176
177
|
export const AUTHORING_COG_LEVEL_OPTIONS = [
|
|
177
|
-
{ value: "recall", label: "Recall", hint: "Definitions
|
|
178
|
-
{ value: "application", label: "Application", hint: "Apply concept to a new
|
|
179
|
-
{ value: "analysis", label: "Analysis", hint: "Compare, evaluate, synthesise
|
|
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
|
-
//
|
|
185
|
+
// Category / subject / track / phase
|
|
185
186
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
186
187
|
|
|
187
188
|
export const AUTHORING_SUBJECT_AREAS = [
|
|
188
|
-
"
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"
|
|
193
|
-
"
|
|
194
|
-
"
|
|
195
|
-
"
|
|
196
|
-
"
|
|
197
|
-
"
|
|
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: "
|
|
203
|
-
{ value: "
|
|
204
|
-
{ value: "
|
|
205
|
-
{ value: "
|
|
206
|
-
{ value: "
|
|
207
|
-
{ value: "
|
|
208
|
-
{ value: "
|
|
209
|
-
{ value: "
|
|
210
|
-
{ value: "
|
|
211
|
-
{ value: "
|
|
212
|
-
{ value: "
|
|
213
|
-
{ value: "
|
|
214
|
-
{ value: "
|
|
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
|
-
"
|
|
220
|
-
"
|
|
221
|
-
"
|
|
222
|
-
"
|
|
223
|
-
"
|
|
224
|
-
"
|
|
225
|
-
"
|
|
226
|
-
"
|
|
227
|
-
"
|
|
228
|
-
"
|
|
229
|
-
"
|
|
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: "
|
|
235
|
-
{ value: "clinical", label: "
|
|
236
|
-
{ value: "residency", label: "
|
|
237
|
-
{ value: "ce", label: "
|
|
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
|
|
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
|
|
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: "
|
|
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
|
|
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
|
|
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
|
-
/**
|
|
289
|
-
export const AUTHORING_STEM_PLACEHOLDER = `
|
|
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
|
|
293
|
+
"Which option fits best?"
|
|
293
294
|
|
|
294
|
-
/** Best-practice
|
|
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
|
|
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
|
|
300
|
-
* Format: `
|
|
301
|
-
* into
|
|
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 `
|
|
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
|