@exxatdesignux/ui 0.1.0 → 0.2.7

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 (155) hide show
  1. package/bin/cli.mjs +176 -0
  2. package/bin/init.mjs +15 -1
  3. package/bin/sync-extras.mjs +65 -0
  4. package/consumer-extras/README.md +21 -0
  5. package/consumer-extras/cursor-skills/exxat-accessibility/SKILL.md +282 -0
  6. package/consumer-extras/cursor-skills/exxat-board-cards/SKILL.md +68 -0
  7. package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +99 -0
  8. package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +713 -0
  9. package/consumer-extras/cursor-skills/exxat-fontawesome-icons/SKILL.md +31 -0
  10. package/consumer-extras/cursor-skills/exxat-list-page-view-shells/SKILL.md +36 -0
  11. package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +27 -0
  12. package/consumer-extras/patterns/command-menu-pattern.md +45 -0
  13. package/consumer-extras/patterns/data-views-pattern.md +167 -0
  14. package/package.json +7 -3
  15. package/src/components/ui/sidebar.tsx +7 -2
  16. package/template/.agents/skills/shadcn/SKILL.md +242 -0
  17. package/template/.agents/skills/shadcn/agents/openai.yml +5 -0
  18. package/template/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
  19. package/template/.agents/skills/shadcn/assets/shadcn.png +0 -0
  20. package/template/.agents/skills/shadcn/cli.md +257 -0
  21. package/template/.agents/skills/shadcn/customization.md +202 -0
  22. package/template/.agents/skills/shadcn/evals/evals.json +47 -0
  23. package/template/.agents/skills/shadcn/mcp.md +94 -0
  24. package/template/.agents/skills/shadcn/rules/base-vs-radix.md +306 -0
  25. package/template/.agents/skills/shadcn/rules/composition.md +195 -0
  26. package/template/.agents/skills/shadcn/rules/forms.md +192 -0
  27. package/template/.agents/skills/shadcn/rules/icons.md +101 -0
  28. package/template/.agents/skills/shadcn/rules/styling.md +162 -0
  29. package/template/.claude/skills/exxat-ds-skill/SKILL.md +712 -0
  30. package/template/.cursor/rules/exxat-accessibility.mdc +33 -0
  31. package/template/.cursor/rules/exxat-command-menu.mdc +23 -0
  32. package/template/.cursor/rules/exxat-dashboard-view-charts.mdc +53 -0
  33. package/template/.cursor/rules/exxat-data-tables.mdc +31 -0
  34. package/template/.cursor/rules/exxat-ds-agents.mdc +26 -0
  35. package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +100 -0
  36. package/template/.cursor/rules/exxat-list-page-connected-views.mdc +16 -0
  37. package/template/.cursor/rules/exxat-no-toast.mdc +26 -0
  38. package/template/.cursor/rules/exxat-page-vs-drawer.mdc +22 -0
  39. package/template/.cursor/rules/exxat-table-properties-drawer.mdc +40 -0
  40. package/template/AGENTS.md +52 -11
  41. package/template/app/(app)/dashboard/page.tsx +1 -1
  42. package/template/app/(app)/data-list/[id]/page.tsx +24 -8
  43. package/template/app/(app)/data-list/new/page.tsx +7 -4
  44. package/template/app/(app)/data-list/page.tsx +1 -1
  45. package/template/app/(app)/examples/page.tsx +41 -0
  46. package/template/app/(app)/question-bank/page.tsx +3 -3
  47. package/template/app/globals.css +1 -1
  48. package/template/components/app-sidebar.tsx +52 -35
  49. package/template/components/compliance-table.tsx +79 -0
  50. package/template/components/data-list-client.tsx +36 -25
  51. package/template/components/data-list-table.tsx +797 -10
  52. package/template/components/data-views/finder-panel-view.tsx +405 -0
  53. package/template/components/data-views/folder-grid-view.tsx +86 -0
  54. package/template/components/data-views/index.ts +59 -0
  55. package/template/components/data-views/list-page-split-details-placeholder.tsx +39 -0
  56. package/template/components/data-views/list-page-split-hub-chrome.tsx +60 -0
  57. package/template/components/data-views/list-page-split-hub-tokens.ts +16 -0
  58. package/template/components/data-views/list-page-tree-column-header.tsx +31 -0
  59. package/template/components/data-views/list-page-tree-panel-shell.tsx +91 -0
  60. package/template/components/data-views/list-page-view-frame.tsx +53 -0
  61. package/template/components/data-views/os-folder-glyph.tsx +121 -0
  62. package/template/components/folder-details-shell.tsx +230 -0
  63. package/template/components/hub-tree-panel-view.tsx +672 -0
  64. package/template/components/list-hub-status-badge.tsx +17 -3
  65. package/template/components/page-header.tsx +149 -7
  66. package/template/components/placements-page-header.tsx +14 -8
  67. package/template/components/placements-table-columns.tsx +8 -8
  68. package/template/components/question-bank-client.tsx +157 -39
  69. package/template/components/question-bank-new-folder-sheet.tsx +248 -0
  70. package/template/components/question-bank-os-folder-view.tsx +648 -0
  71. package/template/components/question-bank-page-header.tsx +31 -2
  72. package/template/components/question-bank-panel-activator.tsx +9 -0
  73. package/template/components/question-bank-secondary-nav.tsx +226 -0
  74. package/template/components/question-bank-table.tsx +707 -22
  75. package/template/components/secondary-panel.tsx +41 -107
  76. package/template/components/sites-table.tsx +66 -0
  77. package/template/components/team-client.tsx +7 -0
  78. package/template/components/team-table.tsx +156 -1
  79. package/template/components/templates/list-page.tsx +2 -2
  80. package/template/components/ui/avatar.tsx +1 -1
  81. package/template/components/ui/badge.tsx +1 -1
  82. package/template/components/ui/banner.tsx +1 -1
  83. package/template/components/ui/breadcrumb.tsx +1 -1
  84. package/template/components/ui/button.tsx +1 -1
  85. package/template/components/ui/calendar.tsx +1 -1
  86. package/template/components/ui/card.tsx +1 -1
  87. package/template/components/ui/chart.tsx +1 -1
  88. package/template/components/ui/checkbox.tsx +1 -1
  89. package/template/components/ui/coach-mark.tsx +1 -1
  90. package/template/components/ui/collapsible.tsx +1 -1
  91. package/template/components/ui/command.tsx +1 -1
  92. package/template/components/ui/date-picker-field.tsx +1 -1
  93. package/template/components/ui/dialog.tsx +1 -1
  94. package/template/components/ui/drag-handle-grip.tsx +1 -1
  95. package/template/components/ui/drawer.tsx +1 -1
  96. package/template/components/ui/dropdown-menu.tsx +1 -1
  97. package/template/components/ui/field.tsx +1 -1
  98. package/template/components/ui/form.tsx +1 -1
  99. package/template/components/ui/input-group.tsx +1 -1
  100. package/template/components/ui/input-mask.tsx +1 -1
  101. package/template/components/ui/input.tsx +1 -1
  102. package/template/components/ui/kbd.tsx +1 -1
  103. package/template/components/ui/label.tsx +1 -1
  104. package/template/components/ui/payment-card-fields.tsx +1 -1
  105. package/template/components/ui/popover.tsx +1 -1
  106. package/template/components/ui/radio-group.tsx +1 -1
  107. package/template/components/ui/resizable.tsx +68 -0
  108. package/template/components/ui/select.tsx +1 -1
  109. package/template/components/ui/selection-tile-grid.tsx +1 -1
  110. package/template/components/ui/separator.tsx +1 -1
  111. package/template/components/ui/sheet.tsx +1 -1
  112. package/template/components/ui/sidebar.tsx +1 -1
  113. package/template/components/ui/skeleton.tsx +1 -1
  114. package/template/components/ui/sonner.tsx +1 -1
  115. package/template/components/ui/status-badge.tsx +1 -1
  116. package/template/components/ui/table.tsx +1 -1
  117. package/template/components/ui/tabs.tsx +1 -1
  118. package/template/components/ui/textarea.tsx +1 -1
  119. package/template/components/ui/tip.tsx +1 -1
  120. package/template/components/ui/toggle-group.tsx +1 -1
  121. package/template/components/ui/toggle-switch.tsx +1 -1
  122. package/template/components/ui/toggle.tsx +1 -1
  123. package/template/components/ui/tooltip.tsx +1 -1
  124. package/template/components/ui/view-segmented-control.tsx +1 -1
  125. package/template/docs/data-views-pattern.md +7 -0
  126. package/template/hooks/use-app-theme.ts +1 -1
  127. package/template/hooks/use-coach-mark.ts +1 -1
  128. package/template/hooks/use-location-hash.ts +15 -0
  129. package/template/hooks/use-mobile.ts +1 -1
  130. package/template/hooks/use-mod-key-label.ts +1 -1
  131. package/template/hooks/use-sidebar-reflow-zoom.ts +40 -0
  132. package/template/lib/ask-leo-route-context.ts +25 -57
  133. package/template/lib/coach-mark-registry.ts +13 -13
  134. package/template/lib/command-menu-config.ts +28 -23
  135. package/template/lib/command-menu-search-data.ts +10 -9
  136. package/template/lib/data-list-view-surface.ts +12 -1
  137. package/template/lib/data-list-view.ts +6 -3
  138. package/template/lib/date-filter.ts +1 -1
  139. package/template/lib/mock/dashboard.ts +11 -11
  140. package/template/lib/mock/navigation.tsx +22 -63
  141. package/template/lib/mock/placements-kpi.ts +19 -19
  142. package/template/lib/mock/question-bank-folders.ts +167 -0
  143. package/template/lib/mock/question-bank-header-collaborators.ts +14 -0
  144. package/template/lib/mock/question-bank-inspector.ts +109 -0
  145. package/template/lib/mock/question-bank-kpi.ts +1 -1
  146. package/template/lib/mock/question-bank.ts +80 -0
  147. package/template/lib/question-bank-nav.ts +91 -0
  148. package/template/lib/utils.ts +1 -1
  149. package/template/next.config.mjs +8 -0
  150. package/template/package.json +1 -0
  151. package/template/public/folders/icons8-folder-windows-11.svg +1 -0
  152. package/template/app/(app)/compliance/page.tsx +0 -10
  153. package/template/app/(app)/rotations/page.tsx +0 -15
  154. package/template/app/(app)/sites/all/page.tsx +0 -13
  155. package/template/app/(app)/team/page.tsx +0 -10
@@ -0,0 +1,248 @@
1
+ "use client"
2
+
3
+ /**
4
+ * Shared “new folder” floating sheet (same shell as Export) — used by OS folder grid and column panel.
5
+ */
6
+
7
+ import * as React from "react"
8
+ import { Button } from "@/components/ui/button"
9
+ import { Shortcut } from "@/components/ui/dropdown-menu"
10
+ import { Input } from "@/components/ui/input"
11
+ import { Label } from "@/components/ui/label"
12
+ import { Sheet, SheetContent, SheetTitle } from "@/components/ui/sheet"
13
+ import { Tip } from "@/components/ui/tip"
14
+ import { Kbd, KbdGroup } from "@/components/ui/kbd"
15
+ import { cn } from "@/lib/utils"
16
+ import {
17
+ QUESTION_BANK_FOLDER_COLOR_STYLES,
18
+ QUESTION_BANK_FOLDER_ICON_OPTIONS,
19
+ type QuestionBankFolderColorKey,
20
+ } from "@/lib/mock/question-bank-folders"
21
+ import { OsFolderGlyph } from "@/components/data-views/os-folder-glyph"
22
+
23
+ const COLOR_OPTIONS: QuestionBankFolderColorKey[] = [
24
+ "brand",
25
+ "success",
26
+ "warning",
27
+ "destructive",
28
+ "muted",
29
+ "chart1",
30
+ "chart2",
31
+ "chart3",
32
+ ]
33
+
34
+ function FolderTilePreview({
35
+ name,
36
+ colorKey,
37
+ icon,
38
+ className,
39
+ }: {
40
+ name: string
41
+ colorKey: QuestionBankFolderColorKey
42
+ icon: string
43
+ className?: string
44
+ }) {
45
+ const display = name.trim() || "Untitled"
46
+ return (
47
+ <div
48
+ className={cn(
49
+ "flex flex-col items-center gap-4 rounded-2xl border border-border/80 bg-muted/20 p-6 shadow-sm",
50
+ className,
51
+ )}
52
+ >
53
+ <OsFolderGlyph
54
+ colorKey={colorKey}
55
+ icon={icon}
56
+ size="lg"
57
+ decorative={false}
58
+ label={`Folder preview: ${display}`}
59
+ />
60
+ <p className="line-clamp-2 min-h-[2.5rem] w-full text-center text-sm font-medium text-foreground">
61
+ {display}
62
+ </p>
63
+ </div>
64
+ )
65
+ }
66
+
67
+ export interface QuestionBankNewFolderSheetProps {
68
+ open: boolean
69
+ onOpenChange: (open: boolean) => void
70
+ /** Parent folder id for the new folder (`null` = top level). */
71
+ parentFolderId: string | null
72
+ /** Replaces default helper copy under the title. */
73
+ descriptionText?: string
74
+ /** When provided, the sheet is in "customize" mode with these initial values. */
75
+ customizingFolder?: {
76
+ name: string
77
+ icon: string
78
+ colorKey: QuestionBankFolderColorKey
79
+ parentId: string | null
80
+ } | null
81
+ onCreated: (folder: {
82
+ name: string
83
+ icon: string
84
+ colorKey: QuestionBankFolderColorKey
85
+ parentId: string | null
86
+ }) => void
87
+ }
88
+
89
+ export function QuestionBankNewFolderSheet({
90
+ open,
91
+ onOpenChange,
92
+ parentFolderId,
93
+ customizingFolder,
94
+ descriptionText = "Name, color, and icon update the preview. The folder is created in the location shown in the breadcrumb above the grid.",
95
+ onCreated,
96
+ }: QuestionBankNewFolderSheetProps) {
97
+ const [draft, setDraft] = React.useState<{
98
+ name: string
99
+ colorKey: QuestionBankFolderColorKey
100
+ icon: string
101
+ }>({ name: "Untitled", colorKey: "brand", icon: "fa-folder" })
102
+
103
+ React.useEffect(() => {
104
+ if (open) {
105
+ if (customizingFolder) {
106
+ setDraft({ name: customizingFolder.name, colorKey: customizingFolder.colorKey, icon: customizingFolder.icon })
107
+ } else {
108
+ setDraft({ name: "Untitled", colorKey: "brand", icon: "fa-folder" })
109
+ }
110
+ }
111
+ }, [open, customizingFolder])
112
+
113
+ const createDisabled = !draft.name.trim()
114
+
115
+ function commit() {
116
+ const v = draft.name.trim()
117
+ if (!v) return
118
+ onCreated({
119
+ name: v,
120
+ icon: draft.icon,
121
+ colorKey: draft.colorKey,
122
+ parentId: parentFolderId,
123
+ })
124
+ onOpenChange(false)
125
+ }
126
+
127
+ return (
128
+ <Sheet open={open} onOpenChange={onOpenChange}>
129
+ <SheetContent
130
+ data-slot="new-folder-drawer"
131
+ side="right"
132
+ showCloseButton={false}
133
+ showOverlay={false}
134
+ className="z-[60] flex w-full max-w-md flex-col gap-0 overflow-hidden rounded-xl border border-border p-0 shadow-xl sm:max-w-md"
135
+ style={{ top: "0.5rem", bottom: "0.5rem", right: "0.5rem", height: "calc(100vh - 1rem)" }}
136
+ >
137
+ {open ? (
138
+ <>
139
+ <Shortcut keys="Enter" onInvoke={() => !createDisabled && commit()} />
140
+ <Shortcut keys="Esc" onInvoke={() => onOpenChange(false)} />
141
+
142
+ <div className="flex items-center justify-between gap-3 px-4 pt-5 pb-6">
143
+ <SheetTitle className="text-base font-semibold leading-tight">
144
+ {customizingFolder ? "Customize Folder" : "New folder"}
145
+ </SheetTitle>
146
+ <Tip label="Close" side="bottom">
147
+ <Button
148
+ type="button"
149
+ variant="ghost"
150
+ size="icon-sm"
151
+ aria-label="Close"
152
+ onClick={() => onOpenChange(false)}
153
+ >
154
+ <i className="fa-light fa-xmark text-[13px]" aria-hidden="true" />
155
+ </Button>
156
+ </Tip>
157
+ </div>
158
+
159
+ <div className="flex min-h-0 flex-1 flex-col gap-6 overflow-y-auto px-4 pb-4 pt-2">
160
+ <div className="flex flex-col items-center gap-4">
161
+ <FolderTilePreview
162
+ name={draft.name}
163
+ colorKey={draft.colorKey}
164
+ icon={draft.icon}
165
+ className="w-full max-w-[280px]"
166
+ />
167
+ <div className="w-full max-w-[280px] space-y-2">
168
+ <Label htmlFor="new-folder-name-shared">Folder name</Label>
169
+ <Input
170
+ id="new-folder-name-shared"
171
+ value={draft.name}
172
+ onChange={e => setDraft(d => ({ ...d, name: e.target.value }))}
173
+ autoComplete="off"
174
+ aria-describedby="new-folder-panel-desc new-folder-name-hint-shared"
175
+ aria-invalid={createDisabled}
176
+ />
177
+ <p id="new-folder-name-hint-shared" className="text-sm text-muted-foreground">
178
+ Shown under the folder icon in the grid or column.
179
+ </p>
180
+ </div>
181
+ </div>
182
+
183
+ <div>
184
+ <p className="mb-2 text-xs font-medium text-muted-foreground">Color</p>
185
+ <div className="flex flex-wrap gap-2">
186
+ {COLOR_OPTIONS.map(c => (
187
+ <button
188
+ key={c}
189
+ type="button"
190
+ aria-label={`Color ${c}`}
191
+ aria-pressed={draft.colorKey === c}
192
+ className={cn(
193
+ "size-10 rounded-xl border-2 transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
194
+ QUESTION_BANK_FOLDER_COLOR_STYLES[c].tile,
195
+ draft.colorKey === c
196
+ ? "ring-2 ring-ring"
197
+ : "border-transparent opacity-85 hover:opacity-100",
198
+ )}
199
+ onClick={() => setDraft(d => ({ ...d, colorKey: c }))}
200
+ />
201
+ ))}
202
+ </div>
203
+ </div>
204
+
205
+ <div>
206
+ <p className="mb-2 text-xs font-medium text-muted-foreground">Icon</p>
207
+ <div className="grid max-h-48 grid-cols-5 gap-2 overflow-y-auto rounded-xl border border-border p-3">
208
+ {QUESTION_BANK_FOLDER_ICON_OPTIONS.map(ic => (
209
+ <button
210
+ key={ic}
211
+ type="button"
212
+ aria-label={`Icon ${ic.replace(/^fa-/, "").replace(/-/g, " ")}`}
213
+ aria-pressed={draft.icon === ic}
214
+ className={cn(
215
+ "flex size-10 items-center justify-center rounded-lg border text-sm transition-colors",
216
+ draft.icon === ic
217
+ ? "border-brand bg-brand/10 text-brand"
218
+ : "border-transparent hover:bg-muted",
219
+ )}
220
+ onClick={() => setDraft(d => ({ ...d, icon: ic }))}
221
+ >
222
+ <i className={cn("fa-light", ic)} aria-hidden="true" />
223
+ </button>
224
+ ))}
225
+ </div>
226
+ </div>
227
+ </div>
228
+
229
+ <div className="mt-auto flex flex-row flex-wrap justify-end gap-2 border-t border-border px-4 py-4">
230
+ <Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
231
+ Cancel
232
+ <KbdGroup className="ms-1.5">
233
+ <Kbd variant="bare">Esc</Kbd>
234
+ </KbdGroup>
235
+ </Button>
236
+ <Button type="button" disabled={createDisabled} onClick={commit}>
237
+ {customizingFolder ? "Update folder" : "Create folder"}
238
+ <KbdGroup className="ms-1.5">
239
+ <Kbd variant="bare">⏎</Kbd>
240
+ </KbdGroup>
241
+ </Button>
242
+ </div>
243
+ </>
244
+ ) : null}
245
+ </SheetContent>
246
+ </Sheet>
247
+ )
248
+ }