@nikala-ui/core 0.11.0 → 0.12.0

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 (107) hide show
  1. package/package.json +43 -2
  2. package/registry/api-table.json +21 -0
  3. package/registry/banner.json +1 -1
  4. package/registry/button.json +1 -1
  5. package/registry/callout.json +19 -0
  6. package/registry/checkbox.json +4 -1
  7. package/registry/code-block.json +26 -0
  8. package/registry/code-group.json +20 -0
  9. package/registry/combobox.json +1 -1
  10. package/registry/command.json +3 -2
  11. package/registry/component-viewer.json +25 -0
  12. package/registry/container.json +18 -0
  13. package/registry/context-menu.json +1 -1
  14. package/registry/create-app-updater.json +13 -0
  15. package/registry/create-document-tabs.json +13 -0
  16. package/registry/create-global-shortcut.json +13 -0
  17. package/registry/create-tauri-window.json +13 -0
  18. package/registry/create-tiptap-editor.json +34 -0
  19. package/registry/dialog.json +1 -1
  20. package/registry/dropdown-menu.json +3 -2
  21. package/registry/field.json +1 -1
  22. package/registry/file-tree.json +21 -0
  23. package/registry/footer.json +1 -1
  24. package/registry/form-message.json +3 -2
  25. package/registry/icon-button.json +1 -1
  26. package/registry/index.json +336 -5
  27. package/registry/navbar.json +1 -1
  28. package/registry/navigation-menu.json +1 -1
  29. package/registry/number-input.json +1 -1
  30. package/registry/package-manager-tabs.json +24 -0
  31. package/registry/pager.json +21 -0
  32. package/registry/popover.json +4 -1
  33. package/registry/resizable.json +1 -1
  34. package/registry/rich-text-editor.json +95 -0
  35. package/registry/scroll-area.json +1 -1
  36. package/registry/section-heading.json +21 -0
  37. package/registry/select.json +3 -2
  38. package/registry/sheet.json +1 -1
  39. package/registry/sidebar.json +1 -1
  40. package/registry/status.json +1 -1
  41. package/registry/steps.json +20 -0
  42. package/registry/switch.json +4 -1
  43. package/registry/table-of-contents.json +23 -0
  44. package/registry/tabs.json +4 -1
  45. package/registry/theme-manager.json +6 -5
  46. package/registry/titlebar-tabs.json +24 -0
  47. package/registry/titlebar.json +26 -0
  48. package/registry/toggle-group.json +1 -1
  49. package/registry/updater-modal.json +26 -0
  50. package/src/index.ts +48 -0
  51. package/src/registry/components/ui/api-table.tsx +117 -0
  52. package/src/registry/components/ui/banner.tsx +0 -2
  53. package/src/registry/components/ui/button.tsx +1 -1
  54. package/src/registry/components/ui/callout.tsx +137 -0
  55. package/src/registry/components/ui/checkbox.tsx +1 -1
  56. package/src/registry/components/ui/code-block.tsx +326 -0
  57. package/src/registry/components/ui/code-group.tsx +105 -0
  58. package/src/registry/components/ui/combobox.tsx +83 -18
  59. package/src/registry/components/ui/command.tsx +110 -106
  60. package/src/registry/components/ui/component-viewer.tsx +363 -0
  61. package/src/registry/components/ui/container.tsx +45 -0
  62. package/src/registry/components/ui/context-menu.tsx +67 -22
  63. package/src/registry/components/ui/dialog.tsx +42 -32
  64. package/src/registry/components/ui/dropdown-menu.tsx +69 -31
  65. package/src/registry/components/ui/field.tsx +7 -3
  66. package/src/registry/components/ui/file-tree.tsx +181 -0
  67. package/src/registry/components/ui/footer.tsx +1 -1
  68. package/src/registry/components/ui/form-message.tsx +2 -2
  69. package/src/registry/components/ui/icon-button.tsx +1 -1
  70. package/src/registry/components/ui/navbar.tsx +18 -11
  71. package/src/registry/components/ui/navigation-menu.tsx +2 -2
  72. package/src/registry/components/ui/number-input.tsx +3 -3
  73. package/src/registry/components/ui/package-manager-tabs.tsx +226 -0
  74. package/src/registry/components/ui/pager.tsx +102 -0
  75. package/src/registry/components/ui/popover.tsx +1 -1
  76. package/src/registry/components/ui/resizable.tsx +3 -1
  77. package/src/registry/components/ui/rich-text-editor/bubble-menu.tsx +236 -0
  78. package/src/registry/components/ui/rich-text-editor/editor.tsx +308 -0
  79. package/src/registry/components/ui/rich-text-editor/extensions.ts +116 -0
  80. package/src/registry/components/ui/rich-text-editor/footer.tsx +36 -0
  81. package/src/registry/components/ui/rich-text-editor/image-dialog.tsx +75 -0
  82. package/src/registry/components/ui/rich-text-editor/index.ts +11 -0
  83. package/src/registry/components/ui/rich-text-editor/link-dialog.tsx +48 -0
  84. package/src/registry/components/ui/rich-text-editor/markdown.ts +170 -0
  85. package/src/registry/components/ui/rich-text-editor/slash-command.tsx +301 -0
  86. package/src/registry/components/ui/rich-text-editor/table-controls.tsx +68 -0
  87. package/src/registry/components/ui/rich-text-editor/toolbar.tsx +465 -0
  88. package/src/registry/components/ui/rich-text-editor/use-editor.ts +231 -0
  89. package/src/registry/components/ui/scroll-area.tsx +12 -2
  90. package/src/registry/components/ui/section-heading.tsx +108 -0
  91. package/src/registry/components/ui/select.tsx +16 -19
  92. package/src/registry/components/ui/sheet.tsx +58 -53
  93. package/src/registry/components/ui/sidebar.tsx +4 -4
  94. package/src/registry/components/ui/status.tsx +7 -5
  95. package/src/registry/components/ui/steps.tsx +198 -0
  96. package/src/registry/components/ui/switch.tsx +1 -1
  97. package/src/registry/components/ui/table-of-contents.tsx +131 -0
  98. package/src/registry/components/ui/tabs.tsx +1 -1
  99. package/src/registry/components/ui/theme-toggle.tsx +175 -139
  100. package/src/registry/components/ui/titlebar-tabs.tsx +773 -0
  101. package/src/registry/components/ui/titlebar.tsx +468 -0
  102. package/src/registry/components/ui/toggle-group.tsx +1 -1
  103. package/src/registry/components/ui/updater-modal.tsx +254 -0
  104. package/src/registry/metadata.ts +167 -6
  105. package/src/registry/providers/theme-provider.tsx +16 -8
  106. package/src/registry/providers/theme-script.tsx +29 -9
  107. package/src/registry/providers/theme-transitions.ts +81 -50
@@ -0,0 +1,254 @@
1
+ import {
2
+ Show,
3
+ splitProps,
4
+ type Component,
5
+ type ParentComponent,
6
+ type JSX,
7
+ } from "solid-js";
8
+ import {
9
+ Dialog,
10
+ DialogContent,
11
+ DialogHeader,
12
+ DialogTitle,
13
+ DialogDescription,
14
+ DialogFooter,
15
+ } from "@/components/ui/dialog";
16
+ import { Button } from "@/components/ui/button";
17
+ import { Badge } from "@/components/ui/badge";
18
+ import { Progress } from "@/components/ui/progress";
19
+ import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
20
+ import type {
21
+ CreateAppUpdaterReturn,
22
+ UpdateManifestInfo,
23
+ UpdateProgressInfo,
24
+ } from "@/hooks/create-app-updater";
25
+ import {
26
+ Download,
27
+ RotateCcw,
28
+ CheckCircle2,
29
+ AlertTriangle,
30
+ ArrowRight,
31
+ Package,
32
+ } from "lucide-solid";
33
+ import { cn } from "@/lib/cn";
34
+
35
+ function formatBytes(bytes: number): string {
36
+ if (!bytes || bytes === 0) return "0 MB";
37
+ const mb = bytes / (1024 * 1024);
38
+ return `${mb.toFixed(1)} MB`;
39
+ }
40
+
41
+ /* --- 1. Sub-components for Clean Modularity & Zero Repetition --- */
42
+
43
+ export interface UpdaterHeaderProps {
44
+ appName: string;
45
+ status: string;
46
+ info?: UpdateManifestInfo | null;
47
+ }
48
+
49
+ export const UpdaterHeader: Component<UpdaterHeaderProps> = (props) => (
50
+ <DialogHeader class="space-y-1.5 text-left">
51
+ <div class="flex items-center justify-between">
52
+ <div class="size-8 rounded-lg bg-primary/10 text-primary flex items-center justify-center">
53
+ <Package class="size-4" />
54
+ </div>
55
+ <Show when={props.info?.version}>
56
+ <div class="flex items-center gap-1.5 text-xs font-mono">
57
+ <span class="text-muted-foreground">{props.info?.currentVersion || "v1.0.0"}</span>
58
+ <ArrowRight class="size-3 text-muted-foreground" />
59
+ <Badge variant="default" class="text-xs px-1.5 py-0 bg-primary text-primary-foreground font-semibold">
60
+ {props.info?.version}
61
+ </Badge>
62
+ </div>
63
+ </Show>
64
+ </div>
65
+
66
+ <DialogTitle class="text-base font-bold tracking-tight text-foreground">
67
+ {props.status === "downloaded"
68
+ ? "Update Ready to Install"
69
+ : props.status === "downloading"
70
+ ? "Downloading Update..."
71
+ : props.status === "up-to-date"
72
+ ? "Up to Date"
73
+ : `New Update Available for ${props.appName}`}
74
+ </DialogTitle>
75
+
76
+ <DialogDescription class="text-xs text-muted-foreground leading-relaxed">
77
+ {props.status === "downloaded"
78
+ ? "The update has been downloaded and verified. Restart to apply changes."
79
+ : props.status === "downloading"
80
+ ? "Please wait while update packages are being downloaded."
81
+ : props.status === "up-to-date"
82
+ ? `${props.appName} is running on the latest version.`
83
+ : "A new version with features and bug fixes is ready to install."}
84
+ </DialogDescription>
85
+ </DialogHeader>
86
+ );
87
+
88
+ export interface UpdaterReleaseNotesProps {
89
+ body?: string;
90
+ date?: string;
91
+ }
92
+
93
+ export const UpdaterReleaseNotes: Component<UpdaterReleaseNotesProps> = (props) => (
94
+ <div class="space-y-1">
95
+ <div class="flex items-center justify-between text-xs text-muted-foreground font-medium">
96
+ <span>Release Notes</span>
97
+ <Show when={props.date}>
98
+ <span class="text-[11px] font-mono">{props.date}</span>
99
+ </Show>
100
+ </div>
101
+ <pre class="max-h-28 overflow-y-auto rounded-md border border-border bg-black/5 dark:bg-black/50 p-2.5 text-xs text-foreground font-mono whitespace-pre-wrap leading-relaxed select-text shadow-inner">
102
+ {props.body}
103
+ </pre>
104
+ </div>
105
+ );
106
+
107
+ export interface UpdaterProgressBarProps {
108
+ progress: UpdateProgressInfo;
109
+ }
110
+
111
+ export const UpdaterProgressBar: Component<UpdaterProgressBarProps> = (props) => (
112
+ <div class="space-y-1.5 py-1">
113
+ <div class="flex items-center justify-between text-xs font-mono">
114
+ <span class="text-muted-foreground font-sans">Progress</span>
115
+ <span class="font-semibold text-primary">{props.progress.percentage}%</span>
116
+ </div>
117
+ <Progress value={props.progress.percentage} class="h-1.5" />
118
+ <div class="flex items-center justify-between text-[11px] font-mono text-muted-foreground">
119
+ <span>{formatBytes(props.progress.downloaded)}</span>
120
+ <span>{formatBytes(props.progress.total)}</span>
121
+ </div>
122
+ </div>
123
+ );
124
+
125
+ /* --- 2. Main UpdaterModal Compound Component --- */
126
+
127
+ export interface UpdaterModalProps {
128
+ open: boolean;
129
+ onOpenChange: (open: boolean) => void;
130
+ updater: CreateAppUpdaterReturn;
131
+ appName?: string;
132
+ class?: string;
133
+ }
134
+
135
+ export const UpdaterModal: Component<UpdaterModalProps> = (props) => {
136
+ const [local, rest] = splitProps(props, [
137
+ "open",
138
+ "onOpenChange",
139
+ "updater",
140
+ "appName",
141
+ "class",
142
+ ]);
143
+
144
+ const appName = () => local.appName || "Nikala Desktop";
145
+ const status = () => local.updater.status();
146
+ const info = () => local.updater.updateInfo();
147
+ const progress = () => local.updater.progress();
148
+ const error = () => local.updater.error();
149
+
150
+ return (
151
+ <Dialog open={local.open} onOpenChange={local.onOpenChange}>
152
+ <DialogContent class={cn("sm:max-w-sm", local.class)}>
153
+ {/* Header */}
154
+ <UpdaterHeader
155
+ appName={appName()}
156
+ status={status()}
157
+ info={info()}
158
+ />
159
+
160
+ {/* Error Alert */}
161
+ <Show when={error()}>
162
+ <Alert variant="destructive" class="py-2 text-xs">
163
+ <AlertTriangle class="size-3.5" />
164
+ <AlertTitle class="font-semibold text-xs">Update Failed</AlertTitle>
165
+ <AlertDescription class="text-[11px]">{error()}</AlertDescription>
166
+ </Alert>
167
+ </Show>
168
+
169
+ {/* Release Notes */}
170
+ <Show when={info()?.body && (status() === "available" || status() === "downloading")}>
171
+ <UpdaterReleaseNotes body={info()?.body} date={info()?.date} />
172
+ </Show>
173
+
174
+ {/* Progress Bar */}
175
+ <Show when={status() === "downloading"}>
176
+ <UpdaterProgressBar progress={progress()} />
177
+ </Show>
178
+
179
+ {/* Success Callout */}
180
+ <Show when={status() === "downloaded"}>
181
+ <div class="flex items-center gap-2.5 p-2.5 rounded-md border border-primary/30 bg-primary/5 text-xs text-foreground">
182
+ <CheckCircle2 class="size-4 text-primary shrink-0" />
183
+ <p class="font-medium text-foreground text-xs">Package downloaded & verified.</p>
184
+ </div>
185
+ </Show>
186
+
187
+ {/* Actions Footer */}
188
+ <DialogFooter class="flex-row items-center justify-end gap-1.5 pt-1">
189
+ <Show when={status() === "available" || status() === "error"}>
190
+ <Button
191
+ variant="outline"
192
+ size="sm"
193
+ onClick={() => local.onOpenChange(false)}
194
+ class="text-xs h-7.5 px-3 cursor-pointer"
195
+ >
196
+ Later
197
+ </Button>
198
+ <Button
199
+ variant="default"
200
+ size="sm"
201
+ onClick={() => local.updater.downloadAndInstall()}
202
+ class="text-xs h-7.5 px-3 gap-1.5 cursor-pointer font-medium"
203
+ >
204
+ <Download class="size-3.5" />
205
+ <span>Update Now</span>
206
+ </Button>
207
+ </Show>
208
+
209
+ <Show when={status() === "downloading"}>
210
+ <Button
211
+ variant="outline"
212
+ size="sm"
213
+ disabled
214
+ class="text-xs h-7.5 w-full opacity-70 justify-center"
215
+ >
216
+ Downloading ({progress().percentage}%)
217
+ </Button>
218
+ </Show>
219
+
220
+ <Show when={status() === "downloaded"}>
221
+ <Button
222
+ variant="outline"
223
+ size="sm"
224
+ onClick={() => local.onOpenChange(false)}
225
+ class="text-xs h-7.5 px-3 cursor-pointer"
226
+ >
227
+ Later
228
+ </Button>
229
+ <Button
230
+ variant="default"
231
+ size="sm"
232
+ onClick={() => local.updater.relaunch()}
233
+ class="text-xs h-7.5 px-3 gap-1.5 cursor-pointer font-semibold shadow-xs"
234
+ >
235
+ <RotateCcw class="size-3.5" />
236
+ <span>Relaunch</span>
237
+ </Button>
238
+ </Show>
239
+
240
+ <Show when={status() === "up-to-date" || status() === "idle"}>
241
+ <Button
242
+ variant="outline"
243
+ size="sm"
244
+ onClick={() => local.onOpenChange(false)}
245
+ class="text-xs h-7.5 px-3 cursor-pointer"
246
+ >
247
+ Close
248
+ </Button>
249
+ </Show>
250
+ </DialogFooter>
251
+ </DialogContent>
252
+ </Dialog>
253
+ );
254
+ };
@@ -56,7 +56,7 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
56
56
  "form-message": {
57
57
  title: "Form Message",
58
58
  description: "Validation message helper connected to createForm errors and touched state.",
59
- registryDependencies: ["field"],
59
+ registryDependencies: ["field", "create-form"],
60
60
  },
61
61
  field: {
62
62
  title: "Field",
@@ -69,6 +69,11 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
69
69
  description: "A versatile container component with header, content, and footer sections.",
70
70
  dependencies: ["clsx", "tailwind-merge"],
71
71
  },
72
+ container: {
73
+ title: "Container",
74
+ description: "A responsive layout container constraining maximum width with semantic padding tokens.",
75
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
76
+ },
72
77
  badge: {
73
78
  title: "Badge",
74
79
  description: "A small badge component for status indicators and tags.",
@@ -103,11 +108,13 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
103
108
  title: "Switch",
104
109
  description: "A control that allows the user to toggle between checked and unchecked states.",
105
110
  dependencies: ["clsx", "tailwind-merge"],
111
+ registryDependencies: ["create-controllable-signal"],
106
112
  },
107
113
  checkbox: {
108
114
  title: "Checkbox",
109
115
  description: "A control that allows the user to toggle between checked and unchecked options.",
110
116
  dependencies: ["clsx", "tailwind-merge"],
117
+ registryDependencies: ["create-controllable-signal"],
111
118
  },
112
119
  "radio-group": {
113
120
  title: "Radio Group",
@@ -118,7 +125,7 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
118
125
  title: "Select",
119
126
  description: "Displays a list of options for the user to pick from, built on Kobalte primitives.",
120
127
  dependencies: ["clsx", "tailwind-merge", "@kobalte/core"],
121
- registryDependencies: ["scroll-area"],
128
+ registryDependencies: ["scroll-area", "create-click-outside"],
122
129
  },
123
130
  combobox: {
124
131
  title: "Combobox",
@@ -130,6 +137,7 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
130
137
  title: "Tabs",
131
138
  description: "A set of layered sections of content displayed one at a time.",
132
139
  dependencies: ["clsx", "tailwind-merge"],
140
+ registryDependencies: ["create-controllable-signal"],
133
141
  },
134
142
  accordion: {
135
143
  title: "Accordion",
@@ -162,13 +170,13 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
162
170
  title: "Dropdown Menu",
163
171
  description: "Displays a menu to the user—such as a set of actions or functions—triggered by a button or avatar.",
164
172
  dependencies: ["clsx", "tailwind-merge", "@kobalte/core"],
165
- registryDependencies: ["scroll-area"],
173
+ registryDependencies: ["scroll-area", "create-click-outside"],
166
174
  },
167
175
  "theme-manager": {
168
176
  title: "Theme Manager",
169
177
  description: "Zero-dependency ThemeProvider and ThemeToggle component for switching light, dark, and system themes.",
170
178
  dependencies: ["clsx", "tailwind-merge", "@kobalte/core", "lucide-solid"],
171
- registryDependencies: ["button", "dropdown-menu"],
179
+ registryDependencies: ["button", "dropdown-menu", "create-color-mode"],
172
180
  },
173
181
  banner: {
174
182
  title: "Banner",
@@ -201,7 +209,7 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
201
209
  "lucide-solid",
202
210
  "@kobalte/core",
203
211
  ],
204
- registryDependencies: ["kbd", "input-group", "list", "scroll-area"],
212
+ registryDependencies: ["kbd", "input-group", "list", "scroll-area", "create-keybindings"],
205
213
  },
206
214
  toast: {
207
215
  title: "Toast / Sonner",
@@ -217,6 +225,7 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
217
225
  title: "Popover",
218
226
  description: "Displays rich content in a portal layer triggered by a button, built on Kobalte primitives.",
219
227
  dependencies: ["clsx", "tailwind-merge", "@kobalte/core", "lucide-solid"],
228
+ registryDependencies: ["create-click-outside"],
220
229
  },
221
230
  progress: {
222
231
  title: "Progress",
@@ -342,6 +351,12 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
342
351
  dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
343
352
  registryDependencies: ["create-pagination"],
344
353
  },
354
+ pager: {
355
+ title: "Pager",
356
+ description: "Previous and next article navigation links with card previews for documentation and blog layouts.",
357
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
358
+ registryDependencies: ["card"],
359
+ },
345
360
  message: {
346
361
  title: "Message",
347
362
  description: "A structured chat and conversation message layout with avatars, alignment, headers, footers, and actions.",
@@ -363,6 +378,112 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
363
378
  dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
364
379
  registryDependencies: ["tooltip", "skeleton", "separator"],
365
380
  },
381
+ titlebar: {
382
+ title: "Titlebar",
383
+ description: "A native-feeling custom titlebar for frameless desktop windows supporting macOS Traffic Lights and Windows 11 controls.",
384
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
385
+ registryDependencies: ["titlebar-tabs", "button", "tooltip", "create-tauri-window", "create-document-tabs"],
386
+ },
387
+ "titlebar-tabs": {
388
+ title: "Titlebar Tabs",
389
+ description: "Native draggable tab bar integrated directly inside desktop titlebars for multi-document applications.",
390
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
391
+ registryDependencies: ["button", "tooltip", "create-document-tabs"],
392
+ },
393
+ "updater-modal": {
394
+ title: "Updater Modal",
395
+ description: "An automated application auto-updater dialog for Tauri v2 with release notes preview, download progress bar, and relaunch actions.",
396
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
397
+ registryDependencies: ["dialog", "button", "badge", "progress", "alert", "create-app-updater"],
398
+ },
399
+ "rich-text-editor": {
400
+ title: "Rich Text Editor",
401
+ description: "A full-featured WYSIWYG rich text editor with toolbar, bubble formatting, tables, task lists, and image uploads built on Tiptap.",
402
+ dependencies: [
403
+ "@tiptap/core",
404
+ "@tiptap/starter-kit",
405
+ "@tiptap/extension-link",
406
+ "@tiptap/extension-image",
407
+ "@tiptap/extension-placeholder",
408
+ "@tiptap/extension-task-list",
409
+ "@tiptap/extension-task-item",
410
+ "@tiptap/extension-table",
411
+ "@tiptap/extension-table-row",
412
+ "@tiptap/extension-table-cell",
413
+ "@tiptap/extension-table-header",
414
+ "@tiptap/extension-underline",
415
+ "@tiptap/extension-text-align",
416
+ "@tiptap/extension-highlight",
417
+ "@tiptap/extension-character-count",
418
+ "@tiptap/extension-subscript",
419
+ "@tiptap/extension-superscript",
420
+ "@tiptap/extension-typography",
421
+ "tiptap-markdown",
422
+ "clsx",
423
+ "tailwind-merge",
424
+ "lucide-solid",
425
+ ],
426
+ registryDependencies: ["create-tiptap-editor"],
427
+ },
428
+ callout: {
429
+ title: "Callout",
430
+ description: "A semantic callout and alert block with status variants, icons, and titles for documentation and notices.",
431
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
432
+ },
433
+ "code-block": {
434
+ title: "Code Block",
435
+ description: "A code block container with filename header, language indicator, and interactive copy to clipboard button.",
436
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid", "shiki"],
437
+ registryDependencies: ["button", "badge", "tooltip", "tabs", "create-clipboard"],
438
+ },
439
+ "package-manager-tabs": {
440
+ title: "Package Manager Tabs",
441
+ description: "An interactive command tab bar supporting customizable package managers (bun, pnpm, npm, yarn, deno, bunx, npx) with copy functionality.",
442
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
443
+ registryDependencies: ["button", "tooltip", "tabs", "create-clipboard"],
444
+ },
445
+ "code-group": {
446
+ title: "Code Group",
447
+ description: "A compound tabbed code container for organizing multiple files, languages, and snippets built on Tabs.",
448
+ dependencies: ["clsx", "tailwind-merge"],
449
+ registryDependencies: ["tabs"],
450
+ },
451
+ steps: {
452
+ title: "Steps",
453
+ description: "A vertical multi-step instruction container with connecting progress line and numbered step indicators.",
454
+ dependencies: ["clsx", "tailwind-merge"],
455
+ registryDependencies: ["badge"],
456
+ },
457
+ "file-tree": {
458
+ title: "File Tree",
459
+ description: "An interactive hierarchical directory file tree component built on Collapsible.",
460
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
461
+ registryDependencies: ["collapsible"],
462
+ },
463
+ "section-heading": {
464
+ title: "Section Heading",
465
+ description: "A reusable heading block with title, optional badge, and description. Supports page and section variants.",
466
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
467
+ registryDependencies: ["badge"],
468
+ },
469
+ "api-table": {
470
+ title: "API Table",
471
+ description: "A structured, clean API reference table component for documenting props, options, and events.",
472
+ dependencies: ["clsx", "tailwind-merge"],
473
+ registryDependencies: ["table", "section-heading"],
474
+ },
475
+ "component-viewer": {
476
+ title: "Component Viewer",
477
+ description: "An interactive preview canvas and code viewer container with responsive viewports, canvas grid, and AI prompts.",
478
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
479
+ registryDependencies: ["tabs", "button", "tooltip", "code-block", "create-clipboard"],
480
+ },
481
+ "table-of-contents": {
482
+ title: "Table of Contents",
483
+ description: "An accessible heading navigation tree with ScrollSpy tracking and smooth scrolling, composed of ScrollArea and List.",
484
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
485
+ registryDependencies: ["scroll-area", "list", "create-scroll-position"],
486
+ },
366
487
  };
367
488
 
368
489
  /**
@@ -541,6 +662,47 @@ export const HOOK_METADATA: Record<string, ComponentMeta> = {
541
662
  title: "createChatScroll",
542
663
  description: "SolidJS reactive primitive for automated chat container scrolling with manual scroll-up detection",
543
664
  },
665
+ "create-tauri-window": {
666
+ title: "createTauriWindow",
667
+ description: "SolidJS reactive primitive for interacting with and controlling Tauri v2 application window states",
668
+ },
669
+ "create-global-shortcut": {
670
+ title: "createGlobalShortcut",
671
+ description: "SolidJS reactive primitive for registering OS-level global keyboard shortcuts via Tauri v2 plugin",
672
+ },
673
+ "create-app-updater": {
674
+ title: "createAppUpdater",
675
+ description: "SolidJS reactive primitive for controlling and observing Tauri v2 application updates",
676
+ },
677
+ "create-document-tabs": {
678
+ title: "createDocumentTabs",
679
+ description: "SolidJS reactive primitive for managing multi-document tabs, editor buffers, and browser tab stacks with adjacent activation and pinned state",
680
+ },
681
+ "create-tiptap-editor": {
682
+ title: "createTiptapEditor",
683
+ description: "Fine-grained reactive SolidJS primitive for managing Tiptap rich text editor instances, signals, and formatting commands.",
684
+ dependencies: [
685
+ "@tiptap/core",
686
+ "@tiptap/starter-kit",
687
+ "@tiptap/extension-link",
688
+ "@tiptap/extension-image",
689
+ "@tiptap/extension-placeholder",
690
+ "@tiptap/extension-task-list",
691
+ "@tiptap/extension-task-item",
692
+ "@tiptap/extension-table",
693
+ "@tiptap/extension-table-row",
694
+ "@tiptap/extension-table-cell",
695
+ "@tiptap/extension-table-header",
696
+ "@tiptap/extension-underline",
697
+ "@tiptap/extension-text-align",
698
+ "@tiptap/extension-highlight",
699
+ "@tiptap/extension-character-count",
700
+ "@tiptap/extension-subscript",
701
+ "@tiptap/extension-superscript",
702
+ "@tiptap/extension-typography",
703
+ "tiptap-markdown",
704
+ ],
705
+ },
544
706
  };
545
707
 
546
708
  /**
@@ -578,4 +740,3 @@ export const BLOCK_METADATA: Record<string, ComponentMeta> = {
578
740
  registryDependencies: ["card", "input", "label", "button", "alert", "form", "field", "form-message"],
579
741
  },
580
742
  };
581
-
@@ -10,7 +10,7 @@ import {
10
10
  } from "solid-js";
11
11
 
12
12
  export type Theme = "light" | "dark" | "system";
13
- export type AccentColor = "wine" | "violet" | "sky" | "emerald" | "rose" | "amber" | "zinc";
13
+ export type AccentColor = "yellow" | "red" | "violet" | "sky" | "emerald" | "zinc";
14
14
  export type Radius = "0" | "0.3" | "0.5" | "0.75" | "1.0";
15
15
 
16
16
  export interface ThemeProviderProps {
@@ -28,13 +28,12 @@ const ACCENT_COLORS: Record<
28
28
  AccentColor,
29
29
  { light: string; dark: string; lightFg: string; darkFg: string }
30
30
  > = {
31
- wine: { light: "#722f37", dark: "#9e3b47", lightFg: "#ffffff", darkFg: "#ffffff" },
32
- violet: { light: "#7c3aed", dark: "#8b5cf6", lightFg: "#ffffff", darkFg: "#ffffff" },
33
- sky: { light: "#0284c7", dark: "#38bdf8", lightFg: "#ffffff", darkFg: "#0f172a" },
34
- emerald: { light: "#059669", dark: "#34d399", lightFg: "#ffffff", darkFg: "#052e16" },
35
- rose: { light: "#e11d48", dark: "#fb7185", lightFg: "#ffffff", darkFg: "#ffffff" },
36
- amber: { light: "#d97706", dark: "#fbbf24", lightFg: "#ffffff", darkFg: "#111827" },
37
- zinc: { light: "#18181b", dark: "#fafafa", lightFg: "#fafafa", darkFg: "#18181b" },
31
+ yellow: { light: "oklch(0.795 0.184 86.047)", dark: "oklch(0.852 0.199 91.936)", lightFg: "oklch(0.145 0 0)", darkFg: "oklch(0.145 0 0)" },
32
+ red: { light: "oklch(0.577 0.245 27.325)", dark: "oklch(0.637 0.237 25.331)", lightFg: "oklch(0.985 0 0)", darkFg: "oklch(0.985 0 0)" },
33
+ violet: { light: "oklch(0.541 0.281 293.009)", dark: "oklch(0.606 0.25 292.717)", lightFg: "oklch(0.985 0 0)", darkFg: "oklch(0.985 0 0)" },
34
+ sky: { light: "oklch(0.588 0.158 241.966)", dark: "oklch(0.672 0.154 238.29)", lightFg: "oklch(0.985 0 0)", darkFg: "oklch(0.145 0 0)" },
35
+ emerald: { light: "oklch(0.596 0.145 163.225)", dark: "oklch(0.696 0.17 162.48)", lightFg: "oklch(0.985 0 0)", darkFg: "oklch(0.145 0 0)" },
36
+ zinc: { light: "oklch(0.205 0 0)", dark: "oklch(0.985 0 0)", lightFg: "oklch(0.985 0 0)", darkFg: "oklch(0.205 0 0)" },
38
37
  };
39
38
 
40
39
  interface ThemeProviderContextValue {
@@ -106,6 +105,7 @@ export const ThemeProvider: ParentComponent<ThemeProviderProps> = (props) => {
106
105
  resolvedDark = targetTheme === "dark";
107
106
  root.classList.add(targetTheme);
108
107
  }
108
+ root.style.colorScheme = resolvedDark ? "dark" : "light";
109
109
 
110
110
  // Override --primary CSS variables ONLY if explicitly chosen
111
111
  if (currentAccent && ACCENT_COLORS[currentAccent]) {
@@ -115,11 +115,16 @@ export const ThemeProvider: ParentComponent<ThemeProviderProps> = (props) => {
115
115
 
116
116
  root.style.setProperty("--primary", primaryHex);
117
117
  root.style.setProperty("--primary-foreground", primaryFgHex);
118
+ } else {
119
+ root.style.removeProperty("--primary");
120
+ root.style.removeProperty("--primary-foreground");
118
121
  }
119
122
 
120
123
  // Override --radius CSS variable ONLY if explicitly chosen
121
124
  if (currentRadius) {
122
125
  root.style.setProperty("--radius", `${currentRadius}rem`);
126
+ } else {
127
+ root.style.removeProperty("--radius");
123
128
  }
124
129
  };
125
130
 
@@ -135,7 +140,9 @@ export const ThemeProvider: ParentComponent<ThemeProviderProps> = (props) => {
135
140
  try {
136
141
  localStorage.setItem(`${storageKey}-mode`, t);
137
142
  if (a) localStorage.setItem(`${storageKey}-accent`, a);
143
+ else localStorage.removeItem(`${storageKey}-accent`);
138
144
  if (r) localStorage.setItem(`${storageKey}-radius`, r);
145
+ else localStorage.removeItem(`${storageKey}-radius`);
139
146
  } catch { }
140
147
  }
141
148
  });
@@ -150,6 +157,7 @@ export const ThemeProvider: ParentComponent<ThemeProviderProps> = (props) => {
150
157
  const root = document.documentElement;
151
158
  root.classList.remove("light", "dark");
152
159
  root.classList.add(e.matches ? "dark" : "light");
160
+ root.style.colorScheme = e.matches ? "dark" : "light";
153
161
 
154
162
  const currentAccent = accent();
155
163
  if (currentAccent && ACCENT_COLORS[currentAccent]) {
@@ -1,4 +1,5 @@
1
- import { type Component } from "solid-js";
1
+ import { isServer } from "solid-js/web";
2
+ import type { Component } from "solid-js";
2
3
 
3
4
  export interface ThemeScriptProps {
4
5
  /** Storage key namespace used in localStorage (default: "nikala-theme") */
@@ -15,6 +16,7 @@ export interface ThemeScriptProps {
15
16
  * Pre-hydration inline script executed synchronously before DOM paint to prevent theme flickering (anti-FOUC).
16
17
  */
17
18
  export const ThemeScript: Component<ThemeScriptProps> = (props) => {
19
+ if (!isServer) return null;
18
20
  const key = props.storageKey || "nikala-theme";
19
21
  const defTheme = props.defaultTheme || "system";
20
22
  const defAccent = props.defaultAccent || "";
@@ -35,17 +37,35 @@ export const ThemeScript: Component<ThemeScriptProps> = (props) => {
35
37
  root.style.colorScheme = resolvedDark ? 'dark' : 'light';
36
38
 
37
39
  var colorMap = {
38
- wine: resolvedDark ? '#9e3b47' : '#722f37',
39
- violet: resolvedDark ? '#8b5cf6' : '#7c3aed',
40
- sky: resolvedDark ? '#38bdf8' : '#0284c7',
41
- emerald: resolvedDark ? '#34d399' : '#059669',
42
- rose: resolvedDark ? '#fb7185' : '#e11d48',
43
- amber: resolvedDark ? '#fbbf24' : '#d97706',
44
- zinc: resolvedDark ? '#fafafa' : '#18181b'
40
+ yellow: {
41
+ primary: resolvedDark ? 'oklch(0.852 0.199 91.936)' : 'oklch(0.795 0.184 86.047)',
42
+ foreground: 'oklch(0.145 0 0)'
43
+ },
44
+ red: {
45
+ primary: resolvedDark ? 'oklch(0.637 0.237 25.331)' : 'oklch(0.577 0.245 27.325)',
46
+ foreground: 'oklch(0.985 0 0)'
47
+ },
48
+ violet: {
49
+ primary: resolvedDark ? 'oklch(0.606 0.25 292.717)' : 'oklch(0.541 0.281 293.009)',
50
+ foreground: 'oklch(0.985 0 0)'
51
+ },
52
+ sky: {
53
+ primary: resolvedDark ? 'oklch(0.672 0.154 238.29)' : 'oklch(0.588 0.158 241.966)',
54
+ foreground: resolvedDark ? 'oklch(0.145 0 0)' : 'oklch(0.985 0 0)'
55
+ },
56
+ emerald: {
57
+ primary: resolvedDark ? 'oklch(0.696 0.17 162.48)' : 'oklch(0.596 0.145 163.225)',
58
+ foreground: resolvedDark ? 'oklch(0.145 0 0)' : 'oklch(0.985 0 0)'
59
+ },
60
+ zinc: {
61
+ primary: resolvedDark ? 'oklch(0.985 0 0)' : 'oklch(0.205 0 0)',
62
+ foreground: resolvedDark ? 'oklch(0.205 0 0)' : 'oklch(0.985 0 0)'
63
+ }
45
64
  };
46
65
 
47
66
  if (accent && colorMap[accent]) {
48
- root.style.setProperty('--primary', colorMap[accent]);
67
+ root.style.setProperty('--primary', colorMap[accent].primary);
68
+ root.style.setProperty('--primary-foreground', colorMap[accent].foreground);
49
69
  }
50
70
 
51
71
  if (radius) {