@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,318 @@
1
+ <script lang="ts">
2
+ import type { NodeDefinition } from './types';
3
+
4
+ interface NodePaletteProps {
5
+ definitions: NodeDefinition[];
6
+ onselect?: (kind: string) => void;
7
+ }
8
+
9
+ let { definitions, onselect }: NodePaletteProps = $props();
10
+
11
+ let searchQuery = $state('');
12
+
13
+ // Filter definitions by search query
14
+ let filtered = $derived(
15
+ searchQuery.trim() === ''
16
+ ? definitions
17
+ : definitions.filter(def => {
18
+ const q = searchQuery.toLowerCase();
19
+ return (
20
+ def.kind.toLowerCase().includes(q) ||
21
+ def.label.toLowerCase().includes(q) ||
22
+ def.description.toLowerCase().includes(q)
23
+ );
24
+ })
25
+ );
26
+
27
+ // Extract scope from a definition: use first port's type prefix (e.g., "app:ryu")
28
+ // ScopedPortType = `${PortScope}:${string}:${string}` — we take first two segments
29
+ function getScope(def: NodeDefinition): string {
30
+ if (def.ports.length === 0) return 'General';
31
+ const parts = def.ports[0].type.split(':');
32
+ if (parts.length >= 2) return `${parts[0]}:${parts[1]}`;
33
+ return 'General';
34
+ }
35
+
36
+ // Group filtered definitions by scope
37
+ let groups = $derived.by(() => {
38
+ const map = new Map<string, NodeDefinition[]>();
39
+ for (const def of filtered) {
40
+ const scope = getScope(def);
41
+ const list = map.get(scope);
42
+ if (list) {
43
+ list.push(def);
44
+ } else {
45
+ map.set(scope, [def]);
46
+ }
47
+ }
48
+ return map;
49
+ });
50
+
51
+ // Track collapsed group state
52
+ let collapsedGroups = $state<Set<string>>(new Set());
53
+
54
+ function toggleGroup(scope: string) {
55
+ const next = new Set(collapsedGroups);
56
+ if (next.has(scope)) {
57
+ next.delete(scope);
58
+ } else {
59
+ next.add(scope);
60
+ }
61
+ collapsedGroups = next;
62
+ }
63
+
64
+ function handleDragStart(e: DragEvent, def: NodeDefinition) {
65
+ if (!e.dataTransfer) return;
66
+ e.dataTransfer.effectAllowed = 'copy';
67
+ e.dataTransfer.setData(
68
+ 'application/json',
69
+ JSON.stringify({ kind: def.kind, defaultSize: { width: 180, height: 120 } })
70
+ );
71
+ }
72
+
73
+ function handleClick(kind: string) {
74
+ onselect?.(kind);
75
+ }
76
+
77
+ function countPorts(def: NodeDefinition, direction: 'input' | 'output'): number {
78
+ return def.ports.filter(p => p.direction === direction).length;
79
+ }
80
+ </script>
81
+
82
+ <div class="n0-palette" role="complementary" aria-label="Node palette">
83
+ <div class="n0-palette-search">
84
+ <input
85
+ type="text"
86
+ placeholder="Filter nodes..."
87
+ bind:value={searchQuery}
88
+ aria-label="Filter node definitions"
89
+ />
90
+ </div>
91
+
92
+ <div class="n0-palette-list">
93
+ {#each [...groups] as [scope, defs] (scope)}
94
+ <div class="n0-palette-group">
95
+ <button
96
+ class="n0-palette-group-header"
97
+ onclick={() => toggleGroup(scope)}
98
+ aria-expanded={!collapsedGroups.has(scope)}
99
+ >
100
+ <span class="n0-palette-chevron" class:collapsed={collapsedGroups.has(scope)}>
101
+ &#9662;
102
+ </span>
103
+ <span class="n0-palette-group-label">{scope}</span>
104
+ <span class="n0-palette-group-count">{defs.length}</span>
105
+ </button>
106
+
107
+ {#if !collapsedGroups.has(scope)}
108
+ <div class="n0-palette-group-items">
109
+ {#each defs as def (def.kind)}
110
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
111
+ <div
112
+ class="n0-palette-card"
113
+ draggable="true"
114
+ ondragstart={(e) => handleDragStart(e, def)}
115
+ onclick={() => handleClick(def.kind)}
116
+ role="button"
117
+ tabindex="0"
118
+ onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') handleClick(def.kind); }}
119
+ aria-label="Add {def.label} node"
120
+ >
121
+ <div class="n0-palette-card-header">
122
+ <span class="n0-palette-card-label">{def.label}</span>
123
+ <span class="n0-palette-card-kind">{def.kind}</span>
124
+ </div>
125
+ {#if def.description}
126
+ <div class="n0-palette-card-desc">{def.description}</div>
127
+ {/if}
128
+ <div class="n0-palette-card-ports">
129
+ <span class="n0-palette-port-in" title="Inputs">
130
+ &#9654; {countPorts(def, 'input')} in
131
+ </span>
132
+ <span class="n0-palette-port-out" title="Outputs">
133
+ {countPorts(def, 'output')} out &#9654;
134
+ </span>
135
+ </div>
136
+ </div>
137
+ {/each}
138
+ </div>
139
+ {/if}
140
+ </div>
141
+ {/each}
142
+
143
+ {#if filtered.length === 0}
144
+ <div class="n0-palette-empty">No matching nodes</div>
145
+ {/if}
146
+ </div>
147
+ </div>
148
+
149
+ <style>
150
+ .n0-palette {
151
+ display: flex;
152
+ flex-direction: column;
153
+ width: 240px;
154
+ height: 100%;
155
+ background: var(--n0-node-bg);
156
+ border-right: 1px solid var(--n0-node-border);
157
+ overflow: hidden;
158
+ font-family: var(--font-mono, monospace);
159
+ color: var(--color-text, #e8e0d0);
160
+ }
161
+
162
+ .n0-palette-search {
163
+ padding: 8px;
164
+ border-bottom: 1px solid var(--n0-node-border);
165
+ flex-shrink: 0;
166
+ }
167
+
168
+ .n0-palette-search input {
169
+ width: 100%;
170
+ box-sizing: border-box;
171
+ padding: 6px 8px;
172
+ background: var(--n0-canvas-bg);
173
+ border: 1px solid var(--n0-node-border);
174
+ border-radius: var(--radius-sm, 4px);
175
+ color: var(--color-text, #e8e0d0);
176
+ font-family: inherit;
177
+ font-size: 0.8rem;
178
+ outline: none;
179
+ }
180
+
181
+ .n0-palette-search input:focus {
182
+ border-color: var(--n0-node-border-selected);
183
+ }
184
+
185
+ .n0-palette-search input::placeholder {
186
+ color: var(--color-text-muted, #a09880);
187
+ }
188
+
189
+ .n0-palette-list {
190
+ flex: 1;
191
+ overflow-y: auto;
192
+ padding: 4px 0;
193
+ }
194
+
195
+ .n0-palette-group-header {
196
+ display: flex;
197
+ align-items: center;
198
+ gap: 6px;
199
+ width: 100%;
200
+ padding: 6px 8px;
201
+ background: var(--n0-node-header-bg);
202
+ border: none;
203
+ border-bottom: 1px solid var(--n0-node-border);
204
+ color: var(--color-accent, #b87333);
205
+ font-family: inherit;
206
+ font-size: 0.75rem;
207
+ font-weight: 600;
208
+ text-transform: uppercase;
209
+ letter-spacing: 0.04em;
210
+ cursor: pointer;
211
+ text-align: left;
212
+ }
213
+
214
+ .n0-palette-group-header:hover {
215
+ background: rgba(184, 115, 51, 0.15);
216
+ }
217
+
218
+ .n0-palette-chevron {
219
+ display: inline-block;
220
+ font-size: 0.65rem;
221
+ transition: transform 150ms ease;
222
+ }
223
+
224
+ .n0-palette-chevron.collapsed {
225
+ transform: rotate(-90deg);
226
+ }
227
+
228
+ .n0-palette-group-label {
229
+ flex: 1;
230
+ }
231
+
232
+ .n0-palette-group-count {
233
+ font-size: 0.65rem;
234
+ opacity: 0.6;
235
+ }
236
+
237
+ .n0-palette-group-items {
238
+ padding: 4px 8px;
239
+ display: flex;
240
+ flex-direction: column;
241
+ gap: 4px;
242
+ }
243
+
244
+ .n0-palette-card {
245
+ padding: 8px;
246
+ background: var(--n0-canvas-bg);
247
+ border: 1px solid var(--n0-node-border);
248
+ border-radius: var(--n0-node-radius);
249
+ cursor: grab;
250
+ user-select: none;
251
+ transition: border-color 150ms ease;
252
+ }
253
+
254
+ .n0-palette-card:hover {
255
+ border-color: var(--n0-node-border-selected);
256
+ }
257
+
258
+ .n0-palette-card:active {
259
+ cursor: grabbing;
260
+ }
261
+
262
+ .n0-palette-card-header {
263
+ display: flex;
264
+ justify-content: space-between;
265
+ align-items: baseline;
266
+ gap: 4px;
267
+ margin-bottom: 2px;
268
+ }
269
+
270
+ .n0-palette-card-label {
271
+ font-size: 0.8rem;
272
+ font-weight: 600;
273
+ white-space: nowrap;
274
+ overflow: hidden;
275
+ text-overflow: ellipsis;
276
+ }
277
+
278
+ .n0-palette-card-kind {
279
+ font-size: 0.6rem;
280
+ color: var(--color-text-muted, #a09880);
281
+ white-space: nowrap;
282
+ flex-shrink: 0;
283
+ }
284
+
285
+ .n0-palette-card-desc {
286
+ font-size: 0.7rem;
287
+ color: var(--color-text-muted, #a09880);
288
+ line-height: 1.3;
289
+ margin-bottom: 4px;
290
+ display: -webkit-box;
291
+ -webkit-line-clamp: 2;
292
+ line-clamp: 2;
293
+ -webkit-box-orient: vertical;
294
+ overflow: hidden;
295
+ }
296
+
297
+ .n0-palette-card-ports {
298
+ display: flex;
299
+ justify-content: space-between;
300
+ font-size: 0.65rem;
301
+ opacity: 0.7;
302
+ }
303
+
304
+ .n0-palette-port-in {
305
+ color: var(--n0-port-color-input);
306
+ }
307
+
308
+ .n0-palette-port-out {
309
+ color: var(--n0-port-color-output);
310
+ }
311
+
312
+ .n0-palette-empty {
313
+ padding: 16px;
314
+ text-align: center;
315
+ font-size: 0.8rem;
316
+ color: var(--color-text-muted, #a09880);
317
+ }
318
+ </style>
@@ -0,0 +1,128 @@
1
+ <script lang="ts" module>
2
+ import type { PortDirection, PortDefinition } from './types';
3
+ import type { PortDragDetail, PortDropDetail } from './node-port-types';
4
+
5
+ // Re-export for backward compatibility
6
+ export type { PortDragDetail, PortDropDetail } from './node-port-types';
7
+ </script>
8
+
9
+ <script lang="ts">
10
+ interface NodePortProps {
11
+ nodeId: string;
12
+ port: PortDefinition;
13
+ position: { x: number; y: number };
14
+ connected: boolean;
15
+ onportdragstart?: (detail: PortDragDetail) => void;
16
+ onportdrop?: (detail: PortDropDetail) => void;
17
+ }
18
+
19
+ let {
20
+ nodeId,
21
+ port,
22
+ position,
23
+ connected,
24
+ onportdragstart,
25
+ onportdrop,
26
+ }: NodePortProps = $props();
27
+
28
+ let hovering = $state(false);
29
+ let incompatible = $state(false);
30
+
31
+ function handlePointerDown(e: PointerEvent) {
32
+ e.stopPropagation();
33
+ onportdragstart?.({
34
+ nodeId,
35
+ portId: port.id,
36
+ direction: port.direction,
37
+ type: port.type,
38
+ position: { x: position.x, y: position.y },
39
+ });
40
+ }
41
+
42
+ function handlePointerUp(e: PointerEvent) {
43
+ e.stopPropagation();
44
+ onportdrop?.({
45
+ nodeId,
46
+ portId: port.id,
47
+ direction: port.direction,
48
+ type: port.type,
49
+ });
50
+ }
51
+
52
+ function handlePointerEnter() {
53
+ hovering = true;
54
+ }
55
+
56
+ function handlePointerLeave() {
57
+ hovering = false;
58
+ }
59
+
60
+ let fillColor = $derived(
61
+ incompatible
62
+ ? 'var(--n0-port-color-incompatible)'
63
+ : port.direction === 'input'
64
+ ? 'var(--n0-port-color-input)'
65
+ : 'var(--n0-port-color-output)'
66
+ );
67
+
68
+ let stateClass = $derived(
69
+ incompatible
70
+ ? 'incompatible'
71
+ : hovering
72
+ ? 'hovering'
73
+ : connected
74
+ ? 'connected'
75
+ : 'default'
76
+ );
77
+ </script>
78
+
79
+ <circle
80
+ class="n0-port {stateClass}"
81
+ cx={position.x}
82
+ cy={position.y}
83
+ r={6}
84
+ fill={fillColor}
85
+ role="button"
86
+ tabindex="-1"
87
+ onpointerdown={handlePointerDown}
88
+ onpointerup={handlePointerUp}
89
+ onpointerenter={handlePointerEnter}
90
+ onpointerleave={handlePointerLeave}
91
+ >
92
+ <title>{port.label} ({port.type})</title>
93
+ </circle>
94
+
95
+ <style>
96
+ .n0-port {
97
+ cursor: crosshair;
98
+ stroke: rgba(0, 0, 0, 0.3);
99
+ stroke-width: 1.5;
100
+ transition: transform 150ms ease, stroke-width 150ms ease;
101
+ transform-origin: var(--cx) var(--cy);
102
+ transform-box: fill-box;
103
+ }
104
+
105
+ .n0-port.hovering {
106
+ transform: scale(var(--n0-port-hover-scale, 1.3));
107
+ stroke-width: 2;
108
+ }
109
+
110
+ .n0-port.connected {
111
+ stroke: rgba(255, 255, 255, 0.3);
112
+ stroke-width: 2;
113
+ }
114
+
115
+ .n0-port.incompatible {
116
+ stroke: var(--n0-port-color-incompatible);
117
+ stroke-width: 2;
118
+ opacity: 0.7;
119
+ }
120
+
121
+ .n0-port.default {
122
+ opacity: 0.85;
123
+ }
124
+
125
+ .n0-port.default:hover {
126
+ opacity: 1;
127
+ }
128
+ </style>
@@ -0,0 +1,33 @@
1
+ // N0 Node Graph — Barrel Export
2
+
3
+ // Types
4
+ export type {
5
+ PortScope,
6
+ ScopedPortType,
7
+ PortDirection,
8
+ PortDefinition,
9
+ NodeDefinition,
10
+ NodeInstance,
11
+ EdgeDefinition,
12
+ GraphSchema,
13
+ ValidationError,
14
+ ValidationResult,
15
+ Point,
16
+ Transform,
17
+ Size,
18
+ } from './types';
19
+
20
+ // Interaction types
21
+ export type { PortDragDetail, PortDropDetail } from './node-port-types';
22
+
23
+ // Validation
24
+ export { validateGraph } from './validate';
25
+
26
+ // Components
27
+ export { default as NodeCanvas } from './NodeCanvas.svelte';
28
+ export { default as Node } from './Node.svelte';
29
+ export { default as NodePort } from './NodePort.svelte';
30
+ export { default as NodeEdge } from './NodeEdge.svelte';
31
+ export { default as GraphEditor } from './GraphEditor.svelte';
32
+ export { default as NodePalette } from './NodePalette.svelte';
33
+ export { default as GraphHistory } from './GraphHistory.svelte';
@@ -0,0 +1,29 @@
1
+ /* N0 Node Graph — CSS Design Tokens */
2
+ :root {
3
+ /* Canvas */
4
+ --n0-canvas-bg: var(--color-bg-canvas, #1a1a1a);
5
+ --n0-canvas-grid: rgba(255, 255, 255, 0.03);
6
+ --n0-canvas-grid-size: 20px;
7
+
8
+ /* Nodes */
9
+ --n0-node-bg: var(--color-bg-panel, #222);
10
+ --n0-node-border: rgba(184, 115, 51, 0.2);
11
+ --n0-node-border-selected: var(--color-accent, #b87333);
12
+ --n0-node-header-bg: rgba(184, 115, 51, 0.1);
13
+ --n0-node-radius: 8px;
14
+ --n0-node-min-width: 180px;
15
+ --n0-node-max-width: 400px;
16
+
17
+ /* Ports */
18
+ --n0-port-radius: 6px;
19
+ --n0-port-color-input: #7aa2f7;
20
+ --n0-port-color-output: #9ece6a;
21
+ --n0-port-color-incompatible: #c0392b;
22
+ --n0-port-hover-scale: 1.3;
23
+
24
+ /* Edges */
25
+ --n0-edge-width: 2px;
26
+ --n0-edge-color: rgba(184, 115, 51, 0.4);
27
+ --n0-edge-color-hover: var(--color-accent, #b87333);
28
+ --n0-edge-color-creating: rgba(184, 115, 51, 0.6);
29
+ }
@@ -0,0 +1,19 @@
1
+ // N0 Node Graph — Port interaction types
2
+ // Extracted from NodePort.svelte so tsc can resolve them without Svelte type declarations.
3
+
4
+ import type { PortDirection } from './types';
5
+
6
+ export interface PortDragDetail {
7
+ nodeId: string;
8
+ portId: string;
9
+ direction: PortDirection;
10
+ type: string;
11
+ position: { x: number; y: number };
12
+ }
13
+
14
+ export interface PortDropDetail {
15
+ nodeId: string;
16
+ portId: string;
17
+ direction: PortDirection;
18
+ type: string;
19
+ }
@@ -0,0 +1,96 @@
1
+ // N0 Node Graph — Schema Layer Types
2
+ // Pure TypeScript — no Svelte, no DOM dependencies
3
+
4
+ // === Scoped Port Types ===
5
+
6
+ export type PortScope = 'realm' | 'grove' | 'accord' | 'system' | 'app';
7
+
8
+ // scope:id:type — globally unique, no ambiguity
9
+ export type ScopedPortType = `${PortScope}:${string}:${string}`;
10
+
11
+ export type PortDirection = 'input' | 'output';
12
+
13
+ // === Port ===
14
+
15
+ export interface PortDefinition {
16
+ id: string;
17
+ label: string;
18
+ type: ScopedPortType;
19
+ direction: PortDirection;
20
+ required: boolean;
21
+ maxConnections: number;
22
+ }
23
+
24
+ // === Node ===
25
+
26
+ export interface NodeDefinition {
27
+ kind: string;
28
+ label: string;
29
+ description: string;
30
+ ports: PortDefinition[];
31
+ metadata: Record<string, unknown>;
32
+ }
33
+
34
+ export interface NodeInstance {
35
+ id: string;
36
+ kind: string;
37
+ position: Point;
38
+ size: Size;
39
+ data: Record<string, unknown>;
40
+ collapsed: boolean;
41
+ }
42
+
43
+ // === Edge ===
44
+
45
+ export interface EdgeDefinition {
46
+ id: string;
47
+ sourceNodeId: string;
48
+ sourcePortId: string;
49
+ targetNodeId: string;
50
+ targetPortId: string;
51
+ metadata: Record<string, unknown>;
52
+ }
53
+
54
+ // === Graph Schema ===
55
+
56
+ export interface GraphSchema {
57
+ id: string;
58
+ name: string;
59
+ version: string;
60
+ nodeDefinitions: NodeDefinition[];
61
+ nodes: NodeInstance[];
62
+ edges: EdgeDefinition[];
63
+ }
64
+
65
+ // === Validation ===
66
+
67
+ export interface ValidationError {
68
+ code: string;
69
+ message: string;
70
+ nodeId?: string;
71
+ edgeId?: string;
72
+ portId?: string;
73
+ }
74
+
75
+ export interface ValidationResult {
76
+ valid: boolean;
77
+ errors: ValidationError[];
78
+ }
79
+
80
+ // === Geometry ===
81
+
82
+ export interface Point {
83
+ x: number;
84
+ y: number;
85
+ }
86
+
87
+ export interface Transform {
88
+ x: number;
89
+ y: number;
90
+ scale: number;
91
+ }
92
+
93
+ export interface Size {
94
+ width: number;
95
+ height: number;
96
+ }