@stephen-netu/design-system 0.1.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 (204) hide show
  1. package/README.md +66 -0
  2. package/package.json +130 -0
  3. package/src/b0-app-shell/clarification-overlay/ClarificationOverlay.svelte +221 -0
  4. package/src/b0-app-shell/clarification-overlay/index.ts +1 -0
  5. package/src/b0-app-shell/command-bar/CommandBar.svelte +565 -0
  6. package/src/b0-app-shell/index.ts +14 -0
  7. package/src/base.css +152 -0
  8. package/src/d0-data-viz/BarChart.svelte +236 -0
  9. package/src/d0-data-viz/CheckpointBar.svelte +574 -0
  10. package/src/d0-data-viz/CheckpointPill.svelte +297 -0
  11. package/src/d0-data-viz/MetricCard.svelte +159 -0
  12. package/src/d0-data-viz/SparkLine.svelte +66 -0
  13. package/src/d0-data-viz/StorageMap.svelte +182 -0
  14. package/src/d0-data-viz/Timeline.svelte +188 -0
  15. package/src/d0-data-viz/checkpoint-types.ts +162 -0
  16. package/src/d0-data-viz/d0-tokens.css +32 -0
  17. package/src/d0-data-viz/index.ts +58 -0
  18. package/src/d0-data-viz/storage-map-types.ts +142 -0
  19. package/src/d0-data-viz/theme-integration.ts +134 -0
  20. package/src/d0-data-viz/types.ts +53 -0
  21. package/src/demos/BspSizingInfographic.svelte +386 -0
  22. package/src/demos/BspZoneDemo.svelte +255 -0
  23. package/src/demos/ControlRoomDemo.svelte +570 -0
  24. package/src/demos/NodepadBlocksShowcase.svelte +189 -0
  25. package/src/demos/index.ts +7 -0
  26. package/src/editor/CodeEditor.svelte +188 -0
  27. package/src/editor/FindReplaceDialog.svelte +516 -0
  28. package/src/editor/MarkdownEditor.svelte +660 -0
  29. package/src/editor/index.ts +2 -0
  30. package/src/entity-graph-view/WorldView.svelte +171 -0
  31. package/src/entity-graph-view/index.ts +6 -0
  32. package/src/entity-graph-view/types.ts +364 -0
  33. package/src/epistemic/index.ts +2 -0
  34. package/src/epistemic/types.ts +134 -0
  35. package/src/epistemic/utils.ts +32 -0
  36. package/src/f0-forms/checkbox/Checkbox.svelte +158 -0
  37. package/src/f0-forms/field/FormField.svelte +91 -0
  38. package/src/f0-forms/index.ts +11 -0
  39. package/src/f0-forms/radio/RadioGroup.svelte +192 -0
  40. package/src/f0-forms/search/SearchBar.svelte +99 -0
  41. package/src/f0-forms/select/Select.svelte +198 -0
  42. package/src/f0-forms/textarea/TextArea.svelte +170 -0
  43. package/src/f0-forms/toggle/FormToggle.svelte +147 -0
  44. package/src/f0-forms/validation/validate.ts +47 -0
  45. package/src/fabric/ai/ChatPanel.svelte +648 -0
  46. package/src/fabric/ai/index.ts +11 -0
  47. package/src/fabric/data/index.ts +21 -0
  48. package/src/fabric/feedback/StatusBar.svelte +274 -0
  49. package/src/fabric/feedback/ToastContainer.svelte +122 -0
  50. package/src/fabric/feedback/index.ts +14 -0
  51. package/src/fabric/index.ts +37 -0
  52. package/src/fabric/input/CommandBar.svelte +79 -0
  53. package/src/fabric/input/KeyboardShortcuts.svelte +388 -0
  54. package/src/fabric/input/index.ts +12 -0
  55. package/src/fabric/layout/GlassBox.svelte +193 -0
  56. package/src/fabric/layout/KanbanBoard.svelte +158 -0
  57. package/src/fabric/layout/KanbanCard.svelte +226 -0
  58. package/src/fabric/layout/KanbanColumn.svelte +278 -0
  59. package/src/fabric/layout/index.ts +17 -0
  60. package/src/fabric/navigation/ActivityRail.svelte +271 -0
  61. package/src/fabric/navigation/index.ts +11 -0
  62. package/src/g0-geo/SovereignMap.svelte +149 -0
  63. package/src/g0-geo/index.ts +2 -0
  64. package/src/index.ts +68 -0
  65. package/src/l0-layout/block-writer/BlockConnectionLines.svelte +98 -0
  66. package/src/l0-layout/block-writer/BlockContent.svelte +213 -0
  67. package/src/l0-layout/block-writer/BlockHeader.svelte +230 -0
  68. package/src/l0-layout/block-writer/BlockItem.svelte +177 -0
  69. package/src/l0-layout/block-writer/BlockWriter.svelte +219 -0
  70. package/src/l0-layout/block-writer/block-writer-types.ts +63 -0
  71. package/src/l0-layout/block-writer/index.ts +24 -0
  72. package/src/l0-layout/block-writer/markdown.ts +110 -0
  73. package/src/l0-layout/chat-view/ChatViewLayout.svelte +61 -0
  74. package/src/l0-layout/epistemic/AllayDetailPanel.svelte +113 -0
  75. package/src/l0-layout/epistemic/AssayDetailPanel.svelte +164 -0
  76. package/src/l0-layout/epistemic/AvenueTrace.svelte +253 -0
  77. package/src/l0-layout/epistemic/KnowledgeDetailPanel.svelte +204 -0
  78. package/src/l0-layout/epistemic/ParadigmLens.svelte +170 -0
  79. package/src/l0-layout/epistemic/ProvenanceChain.svelte +164 -0
  80. package/src/l0-layout/epistemic/TrustView.svelte +195 -0
  81. package/src/l0-layout/epistemic/index.ts +7 -0
  82. package/src/l0-layout/grove/AccordCard.svelte +156 -0
  83. package/src/l0-layout/grove/GroveCard.svelte +197 -0
  84. package/src/l0-layout/grove/MemberBadge.svelte +96 -0
  85. package/src/l0-layout/grove/MemberList.svelte +59 -0
  86. package/src/l0-layout/grove/grove-types.ts +29 -0
  87. package/src/l0-layout/grove/index.ts +14 -0
  88. package/src/l0-layout/index.ts +45 -0
  89. package/src/l0-layout/kanban/KanbanBoard.svelte +71 -0
  90. package/src/l0-layout/kanban/KanbanCard.svelte +276 -0
  91. package/src/l0-layout/kanban/KanbanColumn.svelte +198 -0
  92. package/src/l0-layout/kanban/KanbanViewLayout.svelte +61 -0
  93. package/src/l0-layout/workspace/WorkspaceLayout.svelte +93 -0
  94. package/src/n0-node-graph/GraphEditor.svelte +342 -0
  95. package/src/n0-node-graph/GraphHistory.svelte +122 -0
  96. package/src/n0-node-graph/Node.svelte +269 -0
  97. package/src/n0-node-graph/NodeCanvas.svelte +187 -0
  98. package/src/n0-node-graph/NodeEdge.svelte +152 -0
  99. package/src/n0-node-graph/NodePalette.svelte +318 -0
  100. package/src/n0-node-graph/NodePort.svelte +128 -0
  101. package/src/n0-node-graph/index.ts +33 -0
  102. package/src/n0-node-graph/n0-tokens.css +29 -0
  103. package/src/n0-node-graph/node-port-types.ts +19 -0
  104. package/src/n0-node-graph/types.ts +96 -0
  105. package/src/n0-node-graph/validate.test.ts +722 -0
  106. package/src/n0-node-graph/validate.ts +371 -0
  107. package/src/n1-flow-canvas/FlowCanvas.svelte +202 -0
  108. package/src/n1-flow-canvas/graph-state.svelte.ts +95 -0
  109. package/src/n1-flow-canvas/index.ts +21 -0
  110. package/src/n1-flow-canvas/layout.ts +118 -0
  111. package/src/n1-flow-canvas/layout.worker.ts +128 -0
  112. package/src/n1-flow-canvas/types.ts +102 -0
  113. package/src/n1-flow-canvas/utils.ts +146 -0
  114. package/src/n2-manifold-disk/ManifoldDisk.svelte +314 -0
  115. package/src/n2-manifold-disk/index.ts +6 -0
  116. package/src/n2-manifold-disk/poincare.ts +184 -0
  117. package/src/n3-force-graph/ForceGraph.svelte +180 -0
  118. package/src/n3-force-graph/GraphTooltip.svelte +99 -0
  119. package/src/n3-force-graph/animated-edge.ts +107 -0
  120. package/src/n3-force-graph/health-node.ts +128 -0
  121. package/src/n3-force-graph/index.ts +31 -0
  122. package/src/n3-force-graph/types.ts +94 -0
  123. package/src/n4-adaptive-manifold/AdaptiveManifold.svelte +1165 -0
  124. package/src/n4-adaptive-manifold/DetailCard.svelte +212 -0
  125. package/src/n4-adaptive-manifold/SuggestionIndicator.svelte +91 -0
  126. package/src/n4-adaptive-manifold/classifier.ts +139 -0
  127. package/src/n4-adaptive-manifold/index.ts +45 -0
  128. package/src/n4-adaptive-manifold/n4-tokens.css +155 -0
  129. package/src/n4-adaptive-manifold/orchestrator.ts +301 -0
  130. package/src/n4-adaptive-manifold/phase-theme.ts +92 -0
  131. package/src/n4-adaptive-manifold/pinnacle-events.ts +135 -0
  132. package/src/n4-adaptive-manifold/providers/gravitational-provider.ts +191 -0
  133. package/src/n4-adaptive-manifold/providers/manifold-provider.ts +276 -0
  134. package/src/n4-adaptive-manifold/transition.ts +90 -0
  135. package/src/n4-adaptive-manifold/types.ts +313 -0
  136. package/src/p0-primitives/index.ts +6 -0
  137. package/src/p0-primitives/tokens/control-room.css +309 -0
  138. package/src/p0-primitives/tokens/index.ts +6 -0
  139. package/src/p0-primitives/tokens/tokens.css +140 -0
  140. package/src/p0-primitives/tokens/tokens.json +132 -0
  141. package/src/p0-primitives/types/index.ts +123 -0
  142. package/src/p0-primitives/types/plugin-types.ts +74 -0
  143. package/src/p0-primitives/utils/index.ts +39 -0
  144. package/src/platform/hud-protocol.ts +20 -0
  145. package/src/platform/index.ts +3 -0
  146. package/src/s0-state/create-store.ts +84 -0
  147. package/src/s0-state/derived.ts +41 -0
  148. package/src/s0-state/index.ts +6 -0
  149. package/src/showcase/Showcase.svelte +401 -0
  150. package/src/spatial/BspTilingCanvas.svelte +232 -0
  151. package/src/spatial/ForceCanvas.svelte +289 -0
  152. package/src/spatial/LodRenderer.svelte +334 -0
  153. package/src/spatial/SnapZoomCamera.svelte +185 -0
  154. package/src/spatial/ZoneTiler.svelte +311 -0
  155. package/src/spatial/camera-types.ts +45 -0
  156. package/src/spatial/content-proportional-bsp.ts +253 -0
  157. package/src/spatial/force-canvas-types.ts +102 -0
  158. package/src/spatial/index.ts +15 -0
  159. package/src/spatial/lod-types.ts +70 -0
  160. package/src/spatial/zone-tiler-types.ts +177 -0
  161. package/src/stores/vaultStore.svelte +14 -0
  162. package/src/t0-transport/connection.ts +34 -0
  163. package/src/t0-transport/error.ts +37 -0
  164. package/src/t0-transport/events.ts +50 -0
  165. package/src/t0-transport/index.ts +6 -0
  166. package/src/t0-transport/invoke.ts +30 -0
  167. package/src/tauri/index.ts +13 -0
  168. package/src/u0-primitives/allay-gauge/AllayGauge.svelte +90 -0
  169. package/src/u0-primitives/allay-gauge/index.ts +1 -0
  170. package/src/u0-primitives/animated-icon/AnimatedIcon.svelte +273 -0
  171. package/src/u0-primitives/animated-icon/README.md +53 -0
  172. package/src/u0-primitives/animated-icon/index.ts +31 -0
  173. package/src/u0-primitives/assay-badge/AssayBadge.svelte +121 -0
  174. package/src/u0-primitives/assay-badge/AssaySignalBar.svelte +83 -0
  175. package/src/u0-primitives/assay-badge/index.ts +2 -0
  176. package/src/u0-primitives/avatar/Avatar.svelte +177 -0
  177. package/src/u0-primitives/badge/Badge.svelte +149 -0
  178. package/src/u0-primitives/button/Button.svelte +304 -0
  179. package/src/u0-primitives/card/Card.svelte +182 -0
  180. package/src/u0-primitives/dropdown/Dropdown.svelte +305 -0
  181. package/src/u0-primitives/expert-badge/ExpertBadge.svelte +89 -0
  182. package/src/u0-primitives/expert-badge/index.ts +1 -0
  183. package/src/u0-primitives/index.ts +35 -0
  184. package/src/u0-primitives/input/Input.svelte +237 -0
  185. package/src/u0-primitives/modal/Modal.svelte +331 -0
  186. package/src/u0-primitives/modal/index.ts +1 -0
  187. package/src/u0-primitives/spinner/Spinner.svelte +129 -0
  188. package/src/u0-primitives/tabs/Tabs.svelte +225 -0
  189. package/src/u0-primitives/tabs/tabs-types.ts +11 -0
  190. package/src/u0-primitives/toggle/Toggle.svelte +161 -0
  191. package/src/u0-primitives/tooltip/Tooltip.svelte +234 -0
  192. package/src/v0-diagrams/DiagramPanel.svelte +68 -0
  193. package/src/v0-diagrams/MarkmapDiagram.svelte +56 -0
  194. package/src/v0-diagrams/MermaidDiagram.svelte +53 -0
  195. package/src/v0-diagrams/index.ts +4 -0
  196. package/src/v0-diagrams/types.ts +28 -0
  197. package/src/v0-diagrams/v0-tokens.css +6 -0
  198. package/src/vite-env.d.ts +7 -0
  199. package/src/x0-enchanted-blocks/ENCHANTED_BLOCKS_SPEC.md +457 -0
  200. package/src/x0-enchanted-blocks/components/EnchantedBlock.svelte +485 -0
  201. package/src/x0-enchanted-blocks/components/NodepadBlock.svelte +262 -0
  202. package/src/x0-enchanted-blocks/core/block-layout.ts +211 -0
  203. package/src/x0-enchanted-blocks/core/block-types.ts +227 -0
  204. package/src/x0-enchanted-blocks/index.ts +46 -0
@@ -0,0 +1,305 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ export interface DropdownItem {
5
+ id: string;
6
+ label: string;
7
+ icon?: Snippet;
8
+ shortcut?: string;
9
+ disabled?: boolean;
10
+ danger?: boolean;
11
+ }
12
+
13
+ interface Props {
14
+ items: DropdownItem[];
15
+ trigger: Snippet;
16
+ align?: 'left' | 'right' | 'center';
17
+ width?: string;
18
+ class?: string;
19
+ onselect?: (item: DropdownItem) => void;
20
+ }
21
+
22
+ let {
23
+ items = [],
24
+ trigger,
25
+ align = 'left',
26
+ width = '240px',
27
+ class: className = '',
28
+ onselect
29
+ }: Props = $props();
30
+
31
+ let isOpen = $state(false);
32
+ let menuNode = $state<HTMLElement | null>(null);
33
+ let triggerNode = $state<HTMLElement | null>(null);
34
+ let focusedIndex = $state(-1);
35
+
36
+ function toggleMenu() {
37
+ isOpen = !isOpen;
38
+ if (isOpen) {
39
+ focusedIndex = -1; // Reset focus when opening
40
+ }
41
+ }
42
+
43
+ function closeMenu() {
44
+ isOpen = false;
45
+ focusedIndex = -1;
46
+ }
47
+
48
+ function handleSelect(item: DropdownItem) {
49
+ if (item.disabled) return;
50
+ onselect?.(item);
51
+ closeMenu();
52
+ // Return focus to trigger
53
+ triggerNode?.querySelector('button')?.focus();
54
+ }
55
+
56
+ // Handle clicks outside
57
+ function handleWindowClick(e: MouseEvent) {
58
+ if (isOpen && menuNode && triggerNode && !menuNode.contains(e.target as Node) && !triggerNode.contains(e.target as Node)) {
59
+ closeMenu();
60
+ }
61
+ }
62
+
63
+ // Keyboard navigation
64
+ function handleKeydown(e: KeyboardEvent) {
65
+ if (!isOpen) {
66
+ if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {
67
+ e.preventDefault();
68
+ toggleMenu();
69
+ // Target next tick logic essentially
70
+ setTimeout(() => {
71
+ focusedIndex = items.findIndex(i => !i.disabled);
72
+ focusItem(focusedIndex);
73
+ }, 0);
74
+ }
75
+ return;
76
+ }
77
+
78
+ switch (e.key) {
79
+ case 'Escape':
80
+ e.preventDefault();
81
+ closeMenu();
82
+ triggerNode?.querySelector('button')?.focus();
83
+ break;
84
+ case 'ArrowDown':
85
+ e.preventDefault();
86
+ focusedIndex = findNextFocusable(focusedIndex, 1);
87
+ focusItem(focusedIndex);
88
+ break;
89
+ case 'ArrowUp':
90
+ e.preventDefault();
91
+ focusedIndex = findNextFocusable(focusedIndex, -1);
92
+ focusItem(focusedIndex);
93
+ break;
94
+ case 'Home':
95
+ e.preventDefault();
96
+ focusedIndex = findNextFocusable(-1, 1);
97
+ focusItem(focusedIndex);
98
+ break;
99
+ case 'End':
100
+ e.preventDefault();
101
+ focusedIndex = findNextFocusable(items.length, -1);
102
+ focusItem(focusedIndex);
103
+ break;
104
+ case 'Enter':
105
+ case ' ':
106
+ e.preventDefault();
107
+ if (focusedIndex >= 0 && !items[focusedIndex].disabled) {
108
+ handleSelect(items[focusedIndex]);
109
+ }
110
+ break;
111
+ }
112
+ }
113
+
114
+ function findNextFocusable(startIndex: number, direction: 1 | -1): number {
115
+ // Guard: if no items are focusable, bail early
116
+ if (items.every(i => i.disabled)) return startIndex;
117
+ let nextIndex = startIndex + direction;
118
+ while (nextIndex >= 0 && nextIndex < items.length) {
119
+ if (!items[nextIndex].disabled) {
120
+ return nextIndex;
121
+ }
122
+ nextIndex += direction;
123
+ }
124
+ // Wrap around
125
+ if (nextIndex < 0) return findNextFocusable(items.length, -1);
126
+ if (nextIndex >= items.length) return findNextFocusable(-1, 1);
127
+ return startIndex;
128
+ }
129
+
130
+ function focusItem(index: number) {
131
+ if (menuNode && index >= 0) {
132
+ const items = menuNode.querySelectorAll('[role="menuitem"]');
133
+ (items[index] as HTMLElement)?.focus();
134
+ }
135
+ }
136
+ </script>
137
+
138
+ <svelte:window onclick={handleWindowClick} />
139
+
140
+ <div class="ds-dropdown-wrapper {className}">
141
+ <!-- trigger slot wrapper needs the ref and keyboard events -->
142
+ <div
143
+ bind:this={triggerNode}
144
+ onkeydown={handleKeydown}
145
+ role="button"
146
+ tabindex="0"
147
+ class="ds-dropdown-trigger"
148
+ aria-expanded={isOpen}
149
+ aria-haspopup="menu"
150
+ onclick={toggleMenu}
151
+ >
152
+ {@render trigger()}
153
+ </div>
154
+
155
+ {#if isOpen}
156
+ <div
157
+ bind:this={menuNode}
158
+ class="ds-dropdown-menu align-{align}"
159
+ style="width: {width};"
160
+ role="menu"
161
+ tabindex="-1"
162
+ onkeydown={handleKeydown}
163
+ >
164
+ {#each items as item, i (item.id)}
165
+ <button
166
+ class="ds-dropdown-item"
167
+ class:is-danger={item.danger}
168
+ role="menuitem"
169
+ tabindex={i === focusedIndex ? 0 : -1}
170
+ disabled={item.disabled}
171
+ aria-disabled={item.disabled}
172
+ onclick={(e) => { e.stopPropagation(); handleSelect(item); }}
173
+ onmouseenter={() => focusedIndex = i}
174
+ >
175
+ {#if item.icon}
176
+ <span class="ds-dropdown-icon">
177
+ {@render item.icon()}
178
+ </span>
179
+ {/if}
180
+
181
+ <span class="ds-dropdown-label">{item.label}</span>
182
+
183
+ {#if item.shortcut}
184
+ <span class="ds-dropdown-shortcut">{item.shortcut}</span>
185
+ {/if}
186
+ </button>
187
+ {/each}
188
+ </div>
189
+ {/if}
190
+ </div>
191
+
192
+ <style>
193
+ .ds-dropdown-wrapper {
194
+ position: relative;
195
+ display: inline-block;
196
+ }
197
+
198
+ .ds-dropdown-trigger {
199
+ display: inline-block;
200
+ }
201
+
202
+ .ds-dropdown-menu {
203
+ position: absolute;
204
+ top: calc(100% + var(--space-2));
205
+ background: var(--color-bg-panel-elevated);
206
+ border: 1px solid var(--border-default);
207
+ border-radius: var(--radius-md);
208
+ box-shadow: var(--shadow-lg), 0 0 0 1px rgba(0,0,0,0.5);
209
+ padding: var(--space-1);
210
+ z-index: 1000;
211
+ animation: ds-scale-in var(--transition-fast) transform-origin;
212
+ }
213
+
214
+ /* Alignments */
215
+ .align-left { left: 0; transform-origin: top left; }
216
+ .align-right { right: 0; transform-origin: top right; }
217
+ .align-center { left: 50%; transform: translateX(-50%); transform-origin: top center; }
218
+
219
+ .ds-dropdown-item {
220
+ display: flex;
221
+ align-items: center;
222
+ width: 100%;
223
+ padding: var(--space-2) var(--space-3);
224
+ border: none;
225
+ background: transparent;
226
+ border-radius: var(--radius-sm);
227
+ color: var(--color-text-primary);
228
+ font-family: var(--font-sans);
229
+ font-size: var(--text-sm);
230
+ text-align: left;
231
+ cursor: pointer;
232
+ transition: background var(--transition-fast), color var(--transition-fast);
233
+ }
234
+
235
+ .ds-dropdown-item:hover,
236
+ .ds-dropdown-item:focus {
237
+ background: var(--color-bg-panel);
238
+ outline: none;
239
+ }
240
+
241
+ .ds-dropdown-item:focus-visible {
242
+ background: rgba(184, 115, 51, 0.15); /* Suble brass focus */
243
+ }
244
+
245
+ .ds-dropdown-item:disabled {
246
+ opacity: 0.4;
247
+ cursor: not-allowed;
248
+ }
249
+
250
+ /* Danger Item */
251
+ .ds-dropdown-item.is-danger {
252
+ color: var(--color-error);
253
+ }
254
+
255
+ .ds-dropdown-item.is-danger:hover,
256
+ .ds-dropdown-item.is-danger:focus {
257
+ background: rgba(166, 94, 94, 0.1);
258
+ }
259
+
260
+ .ds-dropdown-icon {
261
+ display: flex;
262
+ margin-right: var(--space-3);
263
+ color: var(--color-text-secondary);
264
+ }
265
+
266
+ .ds-dropdown-item.is-danger .ds-dropdown-icon {
267
+ color: var(--color-error);
268
+ }
269
+
270
+ .ds-dropdown-item:hover:not(.is-danger) .ds-dropdown-icon {
271
+ color: var(--color-accent);
272
+ }
273
+
274
+ .ds-dropdown-label {
275
+ flex: 1;
276
+ white-space: nowrap;
277
+ overflow: hidden;
278
+ text-overflow: ellipsis;
279
+ }
280
+
281
+ .ds-dropdown-shortcut {
282
+ margin-left: var(--space-4);
283
+ font-family: var(--font-mono);
284
+ font-size: var(--text-xs);
285
+ color: var(--color-text-muted);
286
+ background: var(--color-bg-app);
287
+ padding: 2px 6px;
288
+ border-radius: var(--radius-sm, 4px);
289
+ border: 1px solid var(--border-subtle);
290
+ }
291
+
292
+ @keyframes ds-scale-in {
293
+ from { opacity: 0; transform: scale(0.95); }
294
+ to { opacity: 1; transform: scale(1); }
295
+ }
296
+
297
+ .align-center {
298
+ animation-name: ds-scale-in-center;
299
+ }
300
+
301
+ @keyframes ds-scale-in-center {
302
+ from { opacity: 0; transform: translateX(-50%) scale(0.95); }
303
+ to { opacity: 1; transform: translateX(-50%) scale(1); }
304
+ }
305
+ </style>
@@ -0,0 +1,89 @@
1
+ <script lang="ts">
2
+ import type { ExpertIdentity } from '../../epistemic/types.js';
3
+
4
+ interface Props {
5
+ expert: ExpertIdentity;
6
+ size?: 'sm' | 'md';
7
+ showName?: boolean;
8
+ class?: string;
9
+ }
10
+
11
+ let {
12
+ expert,
13
+ size = 'md',
14
+ showName = true,
15
+ class: className = '',
16
+ }: Props = $props();
17
+
18
+ const EXPERT_ICONS: Record<ExpertIdentity['name'], string> = {
19
+ Atelier: '◈',
20
+ Agora: '◇',
21
+ Ryu: '◆',
22
+ SOVEREIGN: '●',
23
+ Agent: '◎',
24
+ };
25
+
26
+ const EXPERT_COLOR_VARS: Record<ExpertIdentity['name'], string> = {
27
+ Atelier: 'var(--expert-atelier)',
28
+ Agora: 'var(--expert-agora)',
29
+ Ryu: 'var(--expert-ryu)',
30
+ SOVEREIGN: 'var(--expert-sovereign)',
31
+ Agent: 'var(--expert-agent)',
32
+ };
33
+
34
+ const icon = $derived(EXPERT_ICONS[expert.name] ?? '○');
35
+ const color = $derived(EXPERT_COLOR_VARS[expert.name] ?? 'var(--color-text-secondary)');
36
+ const displayName = $derived(
37
+ expert.name === 'Agent' && expert.agentId
38
+ ? `Agent:${expert.agentId.slice(0, 6)}`
39
+ : expert.name
40
+ );
41
+ const titleText = $derived(`${expert.name} — ${expert.domain}`);
42
+ </script>
43
+
44
+ <span
45
+ class="ds-expert-badge size-{size} {className}"
46
+ style="--badge-color: {color};"
47
+ title={titleText}
48
+ aria-label="Expert: {displayName}"
49
+ >
50
+ <span class="icon">{icon}</span>
51
+ {#if showName && size !== 'sm'}
52
+ <span class="name">{displayName}</span>
53
+ {/if}
54
+ </span>
55
+
56
+ <style>
57
+ .ds-expert-badge {
58
+ display: inline-flex;
59
+ align-items: center;
60
+ gap: var(--space-1);
61
+ padding: 2px var(--space-2);
62
+ border-radius: var(--radius-full);
63
+ border: 1px solid color-mix(in srgb, var(--badge-color) 30%, transparent);
64
+ background: color-mix(in srgb, var(--badge-color) 8%, transparent);
65
+ font-family: var(--font-sans);
66
+ font-size: var(--text-xs);
67
+ color: var(--badge-color);
68
+ white-space: nowrap;
69
+ cursor: default;
70
+ line-height: 1.4;
71
+ }
72
+
73
+ .size-sm {
74
+ padding: 2px;
75
+ border: none;
76
+ background: transparent;
77
+ font-size: var(--text-sm);
78
+ }
79
+
80
+ .icon {
81
+ font-size: 0.9em;
82
+ line-height: 1;
83
+ }
84
+
85
+ .name {
86
+ font-weight: 500;
87
+ font-size: var(--text-xs);
88
+ }
89
+ </style>
@@ -0,0 +1 @@
1
+ export { default as ExpertBadge } from './ExpertBadge.svelte';
@@ -0,0 +1,35 @@
1
+ // U0 Primitives — Atomic UI components
2
+
3
+ export { default as Button } from './button/Button.svelte';
4
+ export { default as Input } from './input/Input.svelte';
5
+ export { default as Card } from './card/Card.svelte';
6
+ export { default as Badge } from './badge/Badge.svelte';
7
+ export { default as Avatar } from './avatar/Avatar.svelte';
8
+ export { default as Toggle } from './toggle/Toggle.svelte';
9
+ export { default as Tooltip } from './tooltip/Tooltip.svelte';
10
+ export { default as Dropdown } from './dropdown/Dropdown.svelte';
11
+ export { default as Tabs } from './tabs/Tabs.svelte';
12
+ export type { Tab } from './tabs/tabs-types';
13
+ export { default as Spinner } from './spinner/Spinner.svelte';
14
+ export { default as Modal } from './modal/Modal.svelte';
15
+ export { default as AnimatedIcon } from './animated-icon/AnimatedIcon.svelte';
16
+ export type { AnimatedIconName, AnimationType } from './animated-icon/index.js';
17
+ export * from './assay-badge/index.js';
18
+ export * from './allay-gauge/index.js';
19
+ export * from './expert-badge/index.js';
20
+
21
+ // Re-export types
22
+ export type {
23
+ ButtonProps,
24
+ InputProps,
25
+ CardProps,
26
+ BadgeProps,
27
+ ToggleProps,
28
+ SpinnerProps,
29
+ TabsProps,
30
+ ModalProps,
31
+ TooltipProps,
32
+ DropdownProps,
33
+ DropdownItem,
34
+ AvatarProps,
35
+ } from '../p0-primitives/types';
@@ -0,0 +1,237 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ value?: string;
6
+ type?: 'text' | 'search' | 'password' | 'email' | 'url';
7
+ placeholder?: string;
8
+ disabled?: boolean;
9
+ error?: boolean;
10
+ class?: string;
11
+ id?: string;
12
+ name?: string;
13
+ iconLeading?: Snippet;
14
+ iconTrailing?: Snippet;
15
+ }
16
+
17
+ let {
18
+ value = $bindable(''),
19
+ type = 'text',
20
+ placeholder = '',
21
+ disabled = false,
22
+ error = false,
23
+ class: className = '',
24
+ id,
25
+ name,
26
+ iconLeading,
27
+ iconTrailing
28
+ }: Props = $props();
29
+
30
+ let isFocused = $state(false);
31
+ let showPassword = $state(false);
32
+
33
+ let currentType = $derived(type === 'password' && showPassword ? 'text' : type);
34
+
35
+ function handleFocus() {
36
+ isFocused = true;
37
+ }
38
+
39
+ function handleBlur() {
40
+ isFocused = false;
41
+ }
42
+
43
+ function togglePassword() {
44
+ showPassword = !showPassword;
45
+ }
46
+ </script>
47
+
48
+ <div
49
+ class="ds-input-wrapper {className}"
50
+ class:is-focused={isFocused}
51
+ class:is-disabled={disabled}
52
+ class:has-error={error}
53
+ class:has-leading={!!iconLeading}
54
+ class:has-trailing={!!iconTrailing || type === 'password'}
55
+ >
56
+ {#if iconLeading}
57
+ <div class="ds-input-icon leading">
58
+ {@render iconLeading()}
59
+ </div>
60
+ {/if}
61
+
62
+ <input
63
+ {id}
64
+ {name}
65
+ type={currentType}
66
+ bind:value
67
+ {placeholder}
68
+ {disabled}
69
+ onfocus={handleFocus}
70
+ onblur={handleBlur}
71
+ class="ds-input-element"
72
+ />
73
+
74
+ {#if type === 'password'}
75
+ <button
76
+ type="button"
77
+ class="ds-input-action trailing"
78
+ onclick={togglePassword}
79
+ aria-label={showPassword ? "Hide password" : "Show password"}
80
+ tabindex="-1"
81
+ >
82
+ {#if showPassword}
83
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
84
+ <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path>
85
+ <line x1="1" y1="1" x2="23" y2="23"></line>
86
+ </svg>
87
+ {:else}
88
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
89
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
90
+ <circle cx="12" cy="12" r="3"></circle>
91
+ </svg>
92
+ {/if}
93
+ </button>
94
+ {:else if iconTrailing}
95
+ <div class="ds-input-icon trailing">
96
+ {@render iconTrailing()}
97
+ </div>
98
+ {/if}
99
+
100
+ <!-- Animated bottom border glow -->
101
+ <div class="ds-input-glow"></div>
102
+ </div>
103
+
104
+ <style>
105
+ .ds-input-wrapper {
106
+ position: relative;
107
+ display: flex;
108
+ align-items: center;
109
+ width: 100%;
110
+ background: var(--color-bg-panel);
111
+ border: 1px solid var(--border-default);
112
+ border-radius: var(--radius-md);
113
+ transition: all var(--transition-fast);
114
+ overflow: hidden;
115
+ }
116
+
117
+ .ds-input-wrapper:hover:not(.is-disabled) {
118
+ border-color: var(--border-hover);
119
+ background: var(--color-bg-panel-elevated);
120
+ }
121
+
122
+ .ds-input-wrapper.is-focused {
123
+ border-color: var(--color-accent);
124
+ background: var(--color-bg-app); /* Darker inside when focused */
125
+ box-shadow: inset 0 1px 3px rgba(0,0,0,0.2);
126
+ }
127
+
128
+ .ds-input-wrapper.has-error {
129
+ border-color: var(--color-error);
130
+ }
131
+
132
+ .ds-input-wrapper.is-disabled {
133
+ opacity: 0.5;
134
+ background: rgba(0,0,0,0.2);
135
+ cursor: not-allowed;
136
+ }
137
+
138
+ .ds-input-element {
139
+ flex: 1;
140
+ width: 100%;
141
+ height: 2.25rem;
142
+ padding: 0 var(--space-3);
143
+ background: transparent;
144
+ border: none;
145
+ outline: none;
146
+ color: var(--color-text-primary);
147
+ font-family: var(--font-sans);
148
+ font-size: var(--text-sm);
149
+ }
150
+
151
+ .ds-input-wrapper.has-leading .ds-input-element {
152
+ padding-left: var(--space-8);
153
+ }
154
+
155
+ .ds-input-wrapper.has-trailing .ds-input-element {
156
+ padding-right: var(--space-8);
157
+ }
158
+
159
+ .ds-input-element::placeholder {
160
+ color: var(--color-text-muted);
161
+ }
162
+
163
+ .ds-input-element:disabled {
164
+ cursor: not-allowed;
165
+ }
166
+
167
+ /* Icons */
168
+ .ds-input-icon, .ds-input-action {
169
+ position: absolute;
170
+ top: 50%;
171
+ transform: translateY(-50%);
172
+ display: flex;
173
+ align-items: center;
174
+ justify-content: center;
175
+ color: var(--color-text-muted);
176
+ width: var(--space-8);
177
+ height: 100%;
178
+ transition: color var(--transition-fast);
179
+ }
180
+
181
+ .ds-input-icon :global(svg), .ds-input-action svg {
182
+ width: 1em;
183
+ height: 1em;
184
+ }
185
+
186
+ .ds-input-wrapper.is-focused .ds-input-icon.leading {
187
+ color: var(--color-accent);
188
+ }
189
+
190
+ .leading { left: 0; }
191
+ .trailing { right: 0; }
192
+
193
+ /* Actions (like password toggle) */
194
+ .ds-input-action {
195
+ background: transparent;
196
+ border: none;
197
+ cursor: pointer;
198
+ border-radius: var(--radius-sm);
199
+ }
200
+
201
+ .ds-input-action:hover {
202
+ color: var(--color-text-primary);
203
+ }
204
+
205
+ .ds-input-action:focus-visible {
206
+ outline: 2px solid var(--color-accent);
207
+ outline-offset: -2px;
208
+ }
209
+
210
+ /* Animated Bottom Glow Line */
211
+ .ds-input-glow {
212
+ position: absolute;
213
+ bottom: 0;
214
+ left: 0;
215
+ width: 100%;
216
+ height: 1px;
217
+ background: var(--color-accent);
218
+ transform: scaleX(0);
219
+ transform-origin: center;
220
+ transition: transform var(--transition-normal);
221
+ box-shadow: 0 -1px 4px var(--color-accent-glow);
222
+ }
223
+
224
+ .ds-input-wrapper.is-focused .ds-input-glow {
225
+ transform: scaleX(1);
226
+ }
227
+
228
+ .ds-input-wrapper.has-error .ds-input-glow {
229
+ background: var(--color-error);
230
+ box-shadow: 0 -1px 4px rgba(166, 94, 94, 0.4);
231
+ }
232
+
233
+ @media (prefers-reduced-motion: reduce) {
234
+ .ds-input-wrapper { transition: none; }
235
+ .ds-input-glow { transition: none; }
236
+ }
237
+ </style>