dr-widget 0.1.3__py3-none-any.whl

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 (127) hide show
  1. dr_widget/__init__.py +5 -0
  2. dr_widget/py.typed +0 -0
  3. dr_widget/widgets/__init__.py +5 -0
  4. dr_widget/widgets/config_file_manager/.gitignore +24 -0
  5. dr_widget/widgets/config_file_manager/.vscode/extensions.json +3 -0
  6. dr_widget/widgets/config_file_manager/README.md +89 -0
  7. dr_widget/widgets/config_file_manager/__init__.py +283 -0
  8. dr_widget/widgets/config_file_manager/components.json +16 -0
  9. dr_widget/widgets/config_file_manager/index.html +12 -0
  10. dr_widget/widgets/config_file_manager/jsrepo.json +18 -0
  11. dr_widget/widgets/config_file_manager/package.json +49 -0
  12. dr_widget/widgets/config_file_manager/postcss.config.js +6 -0
  13. dr_widget/widgets/config_file_manager/public/fonts/Inter-roman.var.woff2 +0 -0
  14. dr_widget/widgets/config_file_manager/public/vite.svg +1 -0
  15. dr_widget/widgets/config_file_manager/src/App.svelte +62 -0
  16. dr_widget/widgets/config_file_manager/src/ConfigFileManager.svelte +605 -0
  17. dr_widget/widgets/config_file_manager/src/app.css +134 -0
  18. dr_widget/widgets/config_file_manager/src/index.js +5 -0
  19. dr_widget/widgets/config_file_manager/src/lib/@test_state.json +20 -0
  20. dr_widget/widgets/config_file_manager/src/lib/Counter.svelte +10 -0
  21. dr_widget/widgets/config_file_manager/src/lib/components/file-drop/BrowseConfigsPanel.svelte +137 -0
  22. dr_widget/widgets/config_file_manager/src/lib/components/file-drop/ComplexJsonViewer.svelte +94 -0
  23. dr_widget/widgets/config_file_manager/src/lib/components/file-drop/ConfigViewerPanel.svelte +282 -0
  24. dr_widget/widgets/config_file_manager/src/lib/components/file-drop/LoadedConfigPreview.svelte +74 -0
  25. dr_widget/widgets/config_file_manager/src/lib/components/file-drop/SaveConfigPanel.svelte +449 -0
  26. dr_widget/widgets/config_file_manager/src/lib/components/file-drop/SelectedFileRow.svelte +38 -0
  27. dr_widget/widgets/config_file_manager/src/lib/components/file-drop/SelectedFilesList.svelte +30 -0
  28. dr_widget/widgets/config_file_manager/src/lib/components/file-drop/SimpleJsonViewer.svelte +405 -0
  29. dr_widget/widgets/config_file_manager/src/lib/components/ui/badge/badge.svelte +50 -0
  30. dr_widget/widgets/config_file_manager/src/lib/components/ui/badge/index.ts +2 -0
  31. dr_widget/widgets/config_file_manager/src/lib/components/ui/button/button.svelte +128 -0
  32. dr_widget/widgets/config_file_manager/src/lib/components/ui/button/index.ts +27 -0
  33. dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-action.svelte +20 -0
  34. dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-content.svelte +15 -0
  35. dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-description.svelte +20 -0
  36. dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-footer.svelte +20 -0
  37. dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-header.svelte +23 -0
  38. dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-title.svelte +20 -0
  39. dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card.svelte +23 -0
  40. dr_widget/widgets/config_file_manager/src/lib/components/ui/card/index.ts +25 -0
  41. dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-close.svelte +11 -0
  42. dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-content.svelte +47 -0
  43. dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-description.svelte +21 -0
  44. dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-footer.svelte +24 -0
  45. dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-header.svelte +24 -0
  46. dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-overlay.svelte +24 -0
  47. dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-title.svelte +21 -0
  48. dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
  49. dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/index.ts +41 -0
  50. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-close.svelte +11 -0
  51. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-content.svelte +41 -0
  52. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-description.svelte +21 -0
  53. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-footer.svelte +24 -0
  54. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-header.svelte +24 -0
  55. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-nested.svelte +16 -0
  56. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-overlay.svelte +24 -0
  57. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-title.svelte +21 -0
  58. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-trigger.svelte +11 -0
  59. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer.svelte +16 -0
  60. dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/index.ts +45 -0
  61. dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty-content.svelte +23 -0
  62. dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty-description.svelte +23 -0
  63. dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty-header.svelte +20 -0
  64. dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty-media.svelte +41 -0
  65. dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty-title.svelte +20 -0
  66. dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty.svelte +23 -0
  67. dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/index.ts +22 -0
  68. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-content.svelte +20 -0
  69. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-description.svelte +25 -0
  70. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-error.svelte +58 -0
  71. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-group.svelte +23 -0
  72. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-label.svelte +26 -0
  73. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-legend.svelte +29 -0
  74. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-separator.svelte +38 -0
  75. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-set.svelte +24 -0
  76. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-title.svelte +23 -0
  77. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field.svelte +53 -0
  78. dr_widget/widgets/config_file_manager/src/lib/components/ui/field/index.ts +33 -0
  79. dr_widget/widgets/config_file_manager/src/lib/components/ui/file-drop-zone/file-drop-zone.svelte +178 -0
  80. dr_widget/widgets/config_file_manager/src/lib/components/ui/file-drop-zone/index.ts +29 -0
  81. dr_widget/widgets/config_file_manager/src/lib/components/ui/file-drop-zone/types.ts +51 -0
  82. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/index.ts +34 -0
  83. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-actions.svelte +20 -0
  84. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-content.svelte +20 -0
  85. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-description.svelte +24 -0
  86. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-footer.svelte +20 -0
  87. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-group.svelte +21 -0
  88. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-header.svelte +20 -0
  89. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-media.svelte +42 -0
  90. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-separator.svelte +19 -0
  91. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-title.svelte +20 -0
  92. dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item.svelte +60 -0
  93. dr_widget/widgets/config_file_manager/src/lib/components/ui/label/index.ts +7 -0
  94. dr_widget/widgets/config_file_manager/src/lib/components/ui/label/label.svelte +20 -0
  95. dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/index.ts +13 -0
  96. dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-content.svelte +29 -0
  97. dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-description.svelte +20 -0
  98. dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-footer.svelte +29 -0
  99. dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-header.svelte +29 -0
  100. dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-title.svelte +20 -0
  101. dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-trigger.svelte +24 -0
  102. dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal.svelte +24 -0
  103. dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal.svelte.ts +32 -0
  104. dr_widget/widgets/config_file_manager/src/lib/components/ui/separator/index.ts +7 -0
  105. dr_widget/widgets/config_file_manager/src/lib/components/ui/separator/separator.svelte +21 -0
  106. dr_widget/widgets/config_file_manager/src/lib/components/ui/tabs/index.ts +16 -0
  107. dr_widget/widgets/config_file_manager/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
  108. dr_widget/widgets/config_file_manager/src/lib/components/ui/tabs/tabs-list.svelte +20 -0
  109. dr_widget/widgets/config_file_manager/src/lib/components/ui/tabs/tabs-trigger.svelte +20 -0
  110. dr_widget/widgets/config_file_manager/src/lib/components/ui/tabs/tabs.svelte +19 -0
  111. dr_widget/widgets/config_file_manager/src/lib/hooks/use-file-bindings.ts +189 -0
  112. dr_widget/widgets/config_file_manager/src/lib/react/JsonTreeCanvas.tsx +207 -0
  113. dr_widget/widgets/config_file_manager/src/lib/utils/config-format.ts +113 -0
  114. dr_widget/widgets/config_file_manager/src/lib/utils/utils.ts +21 -0
  115. dr_widget/widgets/config_file_manager/src/lib/utils.ts +17 -0
  116. dr_widget/widgets/config_file_manager/src/main.js +7 -0
  117. dr_widget/widgets/config_file_manager/static/fonts/Inter-roman.var.woff2 +0 -0
  118. dr_widget/widgets/config_file_manager/static/index.js +9719 -0
  119. dr_widget/widgets/config_file_manager/static/style.css +1 -0
  120. dr_widget/widgets/config_file_manager/static/vite.svg +1 -0
  121. dr_widget/widgets/config_file_manager/svelte.config.js +8 -0
  122. dr_widget/widgets/config_file_manager/tailwind.config.js +12 -0
  123. dr_widget/widgets/config_file_manager/tsconfig.json +28 -0
  124. dr_widget/widgets/config_file_manager/vite.config.js +36 -0
  125. dr_widget-0.1.3.dist-info/METADATA +62 -0
  126. dr_widget-0.1.3.dist-info/RECORD +127 -0
  127. dr_widget-0.1.3.dist-info/WHEEL +4 -0
@@ -0,0 +1,405 @@
1
+ <script lang="ts">
2
+ import SimpleJsonViewer from './SimpleJsonViewer.svelte';
3
+
4
+ type Primitive = string | number | boolean | null | undefined;
5
+ type DiffStatus = "added" | "removed" | "changed" | "unchanged";
6
+
7
+ const {
8
+ data,
9
+ baseline,
10
+ dirty = false,
11
+ diffContext = "unchanged",
12
+ depth = 2,
13
+ currentDepth = 0,
14
+ isLast = true,
15
+ preserveKeyOrder = false,
16
+ } = $props<{
17
+ data?: unknown;
18
+ baseline?: unknown;
19
+ dirty?: boolean;
20
+ diffContext?: DiffStatus;
21
+ depth?: number;
22
+ currentDepth?: number;
23
+ isLast?: boolean;
24
+ preserveKeyOrder?: boolean;
25
+ }>();
26
+
27
+ let items = $state<string[]>([]);
28
+ let isArray = $state(false);
29
+ let brackets = $state<[string, string]>(["{", "}"]);
30
+ let collapsed = $state(false);
31
+ let diffMeta = $state<
32
+ Record<
33
+ string,
34
+ {
35
+ status: DiffStatus;
36
+ hasCurrent: boolean;
37
+ hasPrevious: boolean;
38
+ currentValue: unknown;
39
+ previousValue: unknown;
40
+ }
41
+ >
42
+ >({});
43
+
44
+ const getType = (value: unknown): string => {
45
+ if (value === null) return "null";
46
+ return typeof value;
47
+ };
48
+
49
+ const isObjectLike = (value: unknown): value is Record<string, unknown> =>
50
+ typeof value === "object" && value !== null;
51
+
52
+ const deepEqual = (a: unknown, b: unknown): boolean => {
53
+ if (a === b) return true;
54
+
55
+ if (typeof a !== typeof b) return false;
56
+
57
+ if (Array.isArray(a) && Array.isArray(b)) {
58
+ if (a.length !== b.length) return false;
59
+ return a.every((item, index) => deepEqual(item, b[index]));
60
+ }
61
+
62
+ if (isObjectLike(a) && isObjectLike(b)) {
63
+ const keysA = Object.keys(a);
64
+ const keysB = Object.keys(b);
65
+ if (keysA.length !== keysB.length) return false;
66
+ return keysA.every((key) => deepEqual(a[key], b[key]));
67
+ }
68
+
69
+ return false;
70
+ };
71
+
72
+ const hasRemainingCurrentValues = (startIndex: number): boolean => {
73
+ for (let i = startIndex + 1; i < items.length; i += 1) {
74
+ if (diffMeta[items[i]]?.hasCurrent) {
75
+ return true;
76
+ }
77
+ }
78
+ return false;
79
+ };
80
+
81
+ const stringify = (value: unknown): string => JSON.stringify(value);
82
+
83
+ const formatPrimitive = (value: Primitive): string => {
84
+ const type = getType(value);
85
+ if (type === "string") return stringify(value);
86
+ if (type === "number" || type === "bigint") return String(value);
87
+ if (type === "boolean") return value ? "true" : "false";
88
+ if (value === null) return "null";
89
+ if (value === undefined) return "undefined";
90
+ return String(value);
91
+ };
92
+
93
+ const toggleCollapsed = () => {
94
+ collapsed = !collapsed;
95
+ };
96
+
97
+ const handleKeyPress = (event: KeyboardEvent) => {
98
+ if (["Enter", " "].includes(event.key)) {
99
+ event.preventDefault();
100
+ toggleCollapsed();
101
+ }
102
+ };
103
+
104
+ $effect(() => {
105
+ const source = data ?? baseline;
106
+ const type = getType(source);
107
+
108
+ if (type === "object") {
109
+ const currentObj = isObjectLike(data) ? data : undefined;
110
+ const baselineObj = isObjectLike(baseline) ? baseline : undefined;
111
+
112
+ const currentKeys = currentObj ? Object.keys(currentObj) : [];
113
+ const baselineKeys = baselineObj ? Object.keys(baselineObj) : [];
114
+
115
+ const keys: string[] = [];
116
+ const seen = new Set<string>();
117
+ const appendKeys = (list: string[]) => {
118
+ for (const key of list) {
119
+ if (!seen.has(key)) {
120
+ keys.push(key);
121
+ seen.add(key);
122
+ }
123
+ }
124
+ };
125
+
126
+ appendKeys(currentKeys);
127
+ if (dirty && baselineObj) {
128
+ appendKeys(baselineKeys);
129
+ }
130
+
131
+ if (!preserveKeyOrder) {
132
+ const sortKeys = Array.isArray(source)
133
+ ? (keysToSort: string[]) =>
134
+ keysToSort.sort((a, b) => Number(a) - Number(b))
135
+ : (keysToSort: string[]) =>
136
+ keysToSort.sort((a, b) =>
137
+ a.localeCompare(b, undefined, { numeric: true }),
138
+ );
139
+
140
+ sortKeys(keys);
141
+ }
142
+
143
+ const meta: typeof diffMeta = {};
144
+
145
+ for (const key of keys) {
146
+ const hasCurrent = Boolean(currentObj && key in currentObj);
147
+ const hasPrevious = Boolean(baselineObj && key in baselineObj);
148
+ const currentValue = hasCurrent ? currentObj?.[key] : undefined;
149
+ const previousValue = hasPrevious ? baselineObj?.[key] : undefined;
150
+
151
+ let status: DiffStatus = "unchanged";
152
+
153
+ if (dirty && baselineObj) {
154
+ if (hasCurrent && !hasPrevious) {
155
+ status = "added";
156
+ } else if (!hasCurrent && hasPrevious) {
157
+ status = "removed";
158
+ } else if (!deepEqual(currentValue, previousValue)) {
159
+ status = "changed";
160
+ }
161
+ }
162
+
163
+ meta[key] = {
164
+ status,
165
+ hasCurrent,
166
+ hasPrevious,
167
+ currentValue,
168
+ previousValue,
169
+ };
170
+ }
171
+
172
+ items = keys;
173
+ diffMeta = meta;
174
+ isArray = Array.isArray(source);
175
+ brackets = isArray ? ["[", "]"] : ["{", "}"];
176
+ } else {
177
+ items = [];
178
+ isArray = false;
179
+ brackets = ["{", "}"];
180
+ diffMeta = {};
181
+ }
182
+ });
183
+
184
+ $effect(() => {
185
+ collapsed = depth < currentDepth;
186
+ });
187
+ </script>
188
+
189
+ {#if data === undefined && (!dirty || baseline === undefined)}
190
+ <div
191
+ class="flex h-80 w-full items-center justify-center rounded-md border border-dashed border-zinc-200 bg-zinc-50 text-sm text-zinc-500 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-400"
192
+ >
193
+ <p>No JSON selected.</p>
194
+ </div>
195
+ {:else}
196
+ {#if !items.length}
197
+ <span class="_jsonBkt empty" class:isArray={isArray}>
198
+ {brackets[0]}{brackets[1]}
199
+ </span>{#if !isLast}<span class="_jsonSep">,</span>{/if}
200
+ {:else if collapsed}
201
+ <span
202
+ class="_jsonBkt"
203
+ class:isArray={isArray}
204
+ role="button"
205
+ tabindex="0"
206
+ onclick={toggleCollapsed}
207
+ onkeydown={handleKeyPress}
208
+ >{brackets[0]}...{brackets[1]}</span>{#if !isLast && collapsed}<span class="_jsonSep">,</span>{/if}
209
+ {:else}
210
+ <span
211
+ class="_jsonBkt"
212
+ class:isArray={isArray}
213
+ class:diff-block-added={diffContext === "added"}
214
+ class:diff-block-removed={diffContext === "removed"}
215
+ role="button"
216
+ tabindex="0"
217
+ onclick={toggleCollapsed}
218
+ onkeydown={handleKeyPress}
219
+ >{brackets[0]}</span>
220
+ <ul class="_jsonList">
221
+ {#each items as key, idx}
222
+ {@const meta = diffMeta[key]}
223
+ {#if meta}
224
+ {@const currentValue = meta.currentValue}
225
+ {@const previousValue = meta.previousValue}
226
+ {@const valueType = getType(
227
+ meta.hasCurrent ? currentValue : previousValue,
228
+ )}
229
+
230
+ <li class:diff-removed-row={meta.status === "removed"}>
231
+ {#if !isArray}
232
+ <span
233
+ class="_jsonKey"
234
+ class:diff-removed-text={meta.status === "removed"}
235
+ >
236
+ {stringify(key)}
237
+ </span>
238
+ <span class="_jsonSep">:</span>
239
+ {/if}
240
+
241
+ {#if (meta.hasCurrent ? getType(currentValue) : getType(previousValue)) ===
242
+ "object"}
243
+ <SimpleJsonViewer
244
+ data={meta.hasCurrent ? currentValue : undefined}
245
+ baseline={meta.hasPrevious ? previousValue : undefined}
246
+ {depth}
247
+ dirty={dirty}
248
+ diffContext={meta.status}
249
+ currentDepth={currentDepth + 1}
250
+ isLast={!hasRemainingCurrentValues(idx)}
251
+ />
252
+ {:else if meta.hasCurrent}
253
+ <span
254
+ class="_jsonVal {getType(currentValue)}"
255
+ class:diff-added={meta.status === "added" || meta.status === "changed"}
256
+ >
257
+ {formatPrimitive(currentValue as Primitive)}
258
+ </span><!--
259
+ -->{#if meta.status === "changed" && meta.hasPrevious}
260
+ <span class="diff-previous-label">Updated from</span>
261
+ <span class="_jsonVal {getType(previousValue)} diff-removed">
262
+ {formatPrimitive(previousValue as Primitive)}
263
+ </span>
264
+ {/if}<!--
265
+ -->{#if meta.hasCurrent && hasRemainingCurrentValues(idx)}<span class="_jsonSep">,</span>{/if}
266
+ {:else if meta.hasPrevious}
267
+ <span class="_jsonVal {valueType} diff-removed">
268
+ {formatPrimitive(previousValue as Primitive)}
269
+ </span>
270
+ <span class="diff-previous-label">Removed</span>
271
+ {/if}
272
+ </li>
273
+ {/if}
274
+ {/each}
275
+ </ul>
276
+ <span
277
+ class="_jsonBkt"
278
+ class:isArray={isArray}
279
+ class:diff-block-added={diffContext === "added"}
280
+ class:diff-block-removed={diffContext === "removed"}
281
+ role="button"
282
+ tabindex="0"
283
+ onclick={toggleCollapsed}
284
+ onkeydown={handleKeyPress}
285
+ >{brackets[1]}</span>{#if !isLast && diffContext !== "removed"}<span class="_jsonSep">,</span>{/if}
286
+ {/if}
287
+ {/if}
288
+
289
+ <style>
290
+ :global(.dark) {
291
+ --jsonBracketHoverBackground: rgba(63, 63, 70, 0.4);
292
+ --jsonBorderLeft: 1px dashed rgba(63, 63, 70, 0.6);
293
+ --jsonValColor: rgba(228, 228, 231, 0.8);
294
+ }
295
+
296
+ :where(._jsonList) {
297
+ list-style: none;
298
+ margin: 0;
299
+ padding: 0;
300
+ padding-left: var(--jsonPaddingLeft, 1rem);
301
+ border-left: var(--jsonBorderLeft, 1px dotted);
302
+ }
303
+
304
+ :where(._jsonBkt) {
305
+ color: var(--jsonBracketColor, currentcolor);
306
+ border-radius: 0.25rem;
307
+ padding: 0.1rem 0.25rem;
308
+ }
309
+
310
+ :where(._jsonBkt):not(.empty):hover,
311
+ :where(._jsonBkt):focus-visible {
312
+ cursor: pointer;
313
+ outline: none;
314
+ background: var(--jsonBracketHoverBackground, #e5e7eb);
315
+ }
316
+
317
+ :where(._jsonSep) {
318
+ color: var(--jsonSeparatorColor, currentcolor);
319
+ }
320
+
321
+ :where(._jsonKey) {
322
+ color: var(--jsonKeyColor, currentcolor);
323
+ margin-right: 0.35rem;
324
+ }
325
+
326
+ :where(._jsonVal) {
327
+ color: var(--jsonValColor, #9ca3af);
328
+ }
329
+
330
+ :where(._jsonVal).string {
331
+ color: var(--jsonValStringColor, #059669);
332
+ }
333
+
334
+ :where(._jsonVal).number {
335
+ color: var(--jsonValNumberColor, #d97706);
336
+ }
337
+
338
+ :where(._jsonVal).boolean {
339
+ color: var(--jsonValBooleanColor, #2563eb);
340
+ }
341
+
342
+ :where(.diff-added) {
343
+ background: var(--jsonDiffAddedBg, rgba(34, 197, 94, 0.14));
344
+ color: var(--jsonDiffAddedColor, #166534);
345
+ padding: 0.125rem 0.25rem;
346
+ border-radius: 0.25rem;
347
+ }
348
+
349
+ :where(.diff-removed) {
350
+ background: var(--jsonDiffRemovedBg, rgba(239, 68, 68, 0.16));
351
+ color: var(--jsonDiffRemovedColor, #b91c1c);
352
+ padding: 0.125rem 0.25rem;
353
+ border-radius: 0.25rem;
354
+ text-decoration: line-through;
355
+ }
356
+
357
+ .diff-removed-text {
358
+ color: var(--jsonDiffRemovedColor, #b91c1c);
359
+ }
360
+
361
+ .diff-removed-row {
362
+ display: flex;
363
+ align-items: baseline;
364
+ gap: 0.35rem;
365
+ }
366
+
367
+ .diff-previous-label {
368
+ margin-left: 0.35rem;
369
+ margin-right: 0.25rem;
370
+ font-size: 0.65rem;
371
+ text-transform: uppercase;
372
+ letter-spacing: 0.05em;
373
+ color: var(--jsonDiffLabelColor, #52525b);
374
+ }
375
+
376
+ .diff-block-added {
377
+ background: var(--jsonDiffAddedBg, rgba(34, 197, 94, 0.08));
378
+ }
379
+
380
+ .diff-block-removed {
381
+ background: var(--jsonDiffRemovedBg, rgba(239, 68, 68, 0.08));
382
+ }
383
+
384
+ :global(.dark) :where(.diff-added) {
385
+ background: rgba(34, 197, 94, 0.24);
386
+ color: #bbf7d0;
387
+ }
388
+
389
+ :global(.dark) :where(.diff-removed) {
390
+ background: rgba(239, 68, 68, 0.22);
391
+ color: #fecaca;
392
+ }
393
+
394
+ :global(.dark) .diff-previous-label {
395
+ color: #a1a1aa;
396
+ }
397
+
398
+ :global(.dark) .diff-block-added {
399
+ background: rgba(34, 197, 94, 0.18);
400
+ }
401
+
402
+ :global(.dark) .diff-block-removed {
403
+ background: rgba(239, 68, 68, 0.18);
404
+ }
405
+ </style>
@@ -0,0 +1,50 @@
1
+ <script lang="ts" module>
2
+ import { type VariantProps, tv } from "tailwind-variants";
3
+
4
+ export const badgeVariants = tv({
5
+ base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden whitespace-nowrap rounded-full border px-2 py-0.5 text-xs font-medium transition-[color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none [&>svg]:size-3",
6
+ variants: {
7
+ variant: {
8
+ default:
9
+ "bg-primary text-primary-foreground [a&]:hover:bg-primary/90 border-transparent",
10
+ secondary:
11
+ "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90 border-transparent",
12
+ destructive:
13
+ "bg-destructive [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/70 border-transparent text-white",
14
+ outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ variant: "default",
19
+ },
20
+ });
21
+
22
+ export type BadgeVariant = VariantProps<typeof badgeVariants>["variant"];
23
+ </script>
24
+
25
+ <script lang="ts">
26
+ import type { HTMLAnchorAttributes } from "svelte/elements";
27
+ import { cn, type WithElementRef } from "$lib/utils.js";
28
+
29
+ let {
30
+ ref = $bindable(null),
31
+ href,
32
+ class: className,
33
+ variant = "default",
34
+ children,
35
+ ...restProps
36
+ }: WithElementRef<HTMLAnchorAttributes> & {
37
+ variant?: BadgeVariant;
38
+ } = $props();
39
+ </script>
40
+
41
+ <svelte:element
42
+ this={href ? "a" : "span"}
43
+ bind:this={ref}
44
+ data-slot="badge"
45
+ {href}
46
+ class={cn(badgeVariants({ variant }), className)}
47
+ {...restProps}
48
+ >
49
+ {@render children?.()}
50
+ </svelte:element>
@@ -0,0 +1,2 @@
1
+ export { default as Badge } from "./badge.svelte";
2
+ export { badgeVariants, type BadgeVariant } from "./badge.svelte";
@@ -0,0 +1,128 @@
1
+ <!--
2
+ Installed from @ieedan/shadcn-svelte-extras
3
+ -->
4
+
5
+ <script lang="ts" module>
6
+ import type { WithChildren, WithoutChildren } from 'bits-ui';
7
+ import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
8
+ import { type VariantProps, tv } from 'tailwind-variants';
9
+
10
+ export const buttonVariants = tv({
11
+ base: "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive focus-visible:border-ring focus-visible:ring-ring/50 relative inline-flex shrink-0 items-center justify-center gap-2 overflow-hidden rounded-md text-sm font-medium whitespace-nowrap outline-hidden transition-all select-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
12
+ variants: {
13
+ variant: {
14
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90 shadow-2xs',
15
+ destructive:
16
+ 'bg-destructive hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 text-white shadow-2xs',
17
+ outline:
18
+ 'bg-background hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50 border shadow-2xs',
19
+ secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-2xs',
20
+ ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
21
+ link: 'text-primary underline-offset-4 hover:underline'
22
+ },
23
+ size: {
24
+ default: 'h-9 px-4 py-2 has-[>svg]:px-3',
25
+ sm: 'h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5',
26
+ lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
27
+ icon: 'size-9'
28
+ }
29
+ },
30
+ defaultVariants: {
31
+ variant: 'default',
32
+ size: 'default'
33
+ }
34
+ });
35
+
36
+ export type ButtonVariant = VariantProps<typeof buttonVariants>['variant'];
37
+ export type ButtonSize = VariantProps<typeof buttonVariants>['size'];
38
+
39
+ export type ButtonPropsWithoutHTML = WithChildren<{
40
+ ref?: HTMLElement | null;
41
+ variant?: ButtonVariant;
42
+ size?: ButtonSize;
43
+ loading?: boolean;
44
+ onClickPromise?: (
45
+ e: MouseEvent & {
46
+ currentTarget: EventTarget & HTMLButtonElement;
47
+ }
48
+ ) => Promise<void>;
49
+ }>;
50
+
51
+ export type AnchorElementProps = ButtonPropsWithoutHTML &
52
+ WithoutChildren<Omit<HTMLAnchorAttributes, 'href' | 'type'>> & {
53
+ href: HTMLAnchorAttributes['href'];
54
+ type?: never;
55
+ disabled?: HTMLButtonAttributes['disabled'];
56
+ };
57
+
58
+ export type ButtonElementProps = ButtonPropsWithoutHTML &
59
+ WithoutChildren<Omit<HTMLButtonAttributes, 'type' | 'href'>> & {
60
+ type?: HTMLButtonAttributes['type'];
61
+ href?: never;
62
+ disabled?: HTMLButtonAttributes['disabled'];
63
+ };
64
+
65
+ export type ButtonProps = AnchorElementProps | ButtonElementProps;
66
+ </script>
67
+
68
+ <script lang="ts">
69
+ import { cn } from '../../../utils/utils.js';
70
+ import LoaderCircleIcon from '@lucide/svelte/icons/loader-circle';
71
+
72
+ let {
73
+ ref = $bindable(null),
74
+ variant = 'default',
75
+ size = 'default',
76
+ href = undefined,
77
+ type = 'button',
78
+ loading = false,
79
+ disabled = false,
80
+ tabindex = 0,
81
+ onclick,
82
+ onClickPromise,
83
+ class: className,
84
+ children,
85
+ ...rest
86
+ }: ButtonProps = $props();
87
+ </script>
88
+
89
+ <!-- This approach to disabled links is inspired by bits-ui see: https://github.com/huntabyte/bits-ui/pull/1055 -->
90
+ <svelte:element
91
+ this={href ? 'a' : 'button'}
92
+ {...rest}
93
+ data-slot="button"
94
+ type={href ? undefined : type}
95
+ href={href && !disabled ? href : undefined}
96
+ disabled={href ? undefined : disabled || loading}
97
+ aria-disabled={href ? disabled : undefined}
98
+ role={href && disabled ? 'link' : undefined}
99
+ tabindex={href && disabled ? -1 : tabindex}
100
+ class={cn(buttonVariants({ variant, size }), className)}
101
+ bind:this={ref}
102
+ onclick={async (
103
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
104
+ e: any
105
+ ) => {
106
+ onclick?.(e);
107
+
108
+ if (type === undefined) return;
109
+
110
+ if (onClickPromise) {
111
+ loading = true;
112
+
113
+ await onClickPromise(e);
114
+
115
+ loading = false;
116
+ }
117
+ }}
118
+ >
119
+ {#if type !== undefined && loading}
120
+ <div class="absolute flex size-full place-items-center justify-center bg-inherit">
121
+ <div class="flex animate-spin place-items-center justify-center">
122
+ <LoaderCircleIcon class="size-4" />
123
+ </div>
124
+ </div>
125
+ <span class="sr-only">Loading</span>
126
+ {/if}
127
+ {@render children?.()}
128
+ </svelte:element>
@@ -0,0 +1,27 @@
1
+ /*
2
+ Installed from @ieedan/shadcn-svelte-extras
3
+ */
4
+
5
+ import Root, {
6
+ type ButtonProps,
7
+ type ButtonSize,
8
+ type ButtonVariant,
9
+ type AnchorElementProps,
10
+ type ButtonElementProps,
11
+ type ButtonPropsWithoutHTML,
12
+ buttonVariants,
13
+ } from "./button.svelte";
14
+
15
+ export {
16
+ Root,
17
+ type ButtonProps as Props,
18
+ //
19
+ Root as Button,
20
+ buttonVariants,
21
+ type ButtonProps,
22
+ type ButtonSize,
23
+ type ButtonVariant,
24
+ type AnchorElementProps,
25
+ type ButtonElementProps,
26
+ type ButtonPropsWithoutHTML,
27
+ };
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "$lib/utils.js";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div
14
+ bind:this={ref}
15
+ data-slot="card-action"
16
+ class={cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </div>
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn, type WithElementRef } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div bind:this={ref} data-slot="card-content" class={cn("px-6", className)} {...restProps}>
14
+ {@render children?.()}
15
+ </div>
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn, type WithElementRef } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLParagraphElement>> = $props();
11
+ </script>
12
+
13
+ <p
14
+ bind:this={ref}
15
+ data-slot="card-description"
16
+ class={cn("text-muted-foreground text-sm", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </p>
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "$lib/utils.js";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div
14
+ bind:this={ref}
15
+ data-slot="card-footer"
16
+ class={cn("[.border-t]:pt-6 flex items-center px-6", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </div>