@flowdrop/flowdrop 1.3.0 → 1.5.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.
- package/README.md +68 -24
- package/dist/adapters/WorkflowAdapter.js +2 -22
- package/dist/adapters/agentspec/autoLayout.d.ts +51 -5
- package/dist/adapters/agentspec/autoLayout.js +120 -23
- package/dist/chat/commandClassifier.d.ts +19 -0
- package/dist/chat/commandClassifier.js +30 -0
- package/dist/chat/index.d.ts +27 -0
- package/dist/chat/index.js +32 -0
- package/dist/chat/responseParser.d.ts +21 -0
- package/dist/chat/responseParser.js +87 -0
- package/dist/commands/batch.d.ts +18 -0
- package/dist/commands/batch.js +56 -0
- package/dist/commands/executor.d.ts +37 -0
- package/dist/commands/executor.js +1044 -0
- package/dist/commands/index.d.ts +14 -0
- package/dist/commands/index.js +17 -0
- package/dist/commands/parser.d.ts +16 -0
- package/dist/commands/parser.js +278 -0
- package/dist/commands/positioner.d.ts +19 -0
- package/dist/commands/positioner.js +33 -0
- package/dist/commands/storeIntegration.svelte.d.ts +16 -0
- package/dist/commands/storeIntegration.svelte.js +67 -0
- package/dist/commands/types.d.ts +343 -0
- package/dist/commands/types.js +45 -0
- package/dist/components/App.svelte +431 -17
- package/dist/components/App.svelte.d.ts +10 -0
- package/dist/components/CanvasBanner.stories.svelte +6 -2
- package/dist/components/CanvasController.svelte +38 -0
- package/dist/components/CanvasController.svelte.d.ts +32 -0
- package/dist/components/ConfigMappingRow.svelte +130 -0
- package/dist/components/ConfigMappingRow.svelte.d.ts +8 -0
- package/dist/components/ConfigPanel.svelte +56 -7
- package/dist/components/ConfigPanel.svelte.d.ts +2 -0
- package/dist/components/FlowDropEdge.svelte +8 -57
- package/dist/components/Logo.svelte +14 -14
- package/dist/components/LogsSidebar.svelte +5 -5
- package/dist/components/Navbar.svelte +58 -10
- package/dist/components/Navbar.svelte.d.ts +7 -0
- package/dist/components/NodeSidebar.svelte +238 -362
- package/dist/components/NodeSwapPicker.svelte +537 -0
- package/dist/components/NodeSwapPicker.svelte.d.ts +16 -0
- package/dist/components/PortMappingRow.svelte +209 -0
- package/dist/components/PortMappingRow.svelte.d.ts +12 -0
- package/dist/components/SwapMappingEditor.svelte +550 -0
- package/dist/components/SwapMappingEditor.svelte.d.ts +12 -0
- package/dist/components/WorkflowEditor.svelte +99 -4
- package/dist/components/WorkflowEditor.svelte.d.ts +8 -0
- package/dist/components/chat/AIChatPanel.svelte +658 -0
- package/dist/components/chat/AIChatPanel.svelte.d.ts +13 -0
- package/dist/components/chat/CommandPreview.svelte +184 -0
- package/dist/components/chat/CommandPreview.svelte.d.ts +9 -0
- package/dist/components/console/CommandConsole.stories.svelte +93 -0
- package/dist/components/console/CommandConsole.stories.svelte.d.ts +27 -0
- package/dist/components/console/CommandConsole.svelte +259 -0
- package/dist/components/console/CommandConsole.svelte.d.ts +11 -0
- package/dist/components/console/ConsoleAutocomplete.svelte +139 -0
- package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +21 -0
- package/dist/components/console/ConsoleInput.svelte +712 -0
- package/dist/components/console/ConsoleInput.svelte.d.ts +16 -0
- package/dist/components/console/ConsoleOutput.svelte +121 -0
- package/dist/components/console/ConsoleOutput.svelte.d.ts +11 -0
- package/dist/components/console/formatters.d.ts +26 -0
- package/dist/components/console/formatters.js +118 -0
- package/dist/components/interrupt/index.d.ts +1 -0
- package/dist/components/interrupt/index.js +1 -0
- package/dist/components/nodes/SimpleNode.stories.svelte +64 -0
- package/dist/components/nodes/SimpleNode.svelte +27 -11
- package/dist/components/nodes/SquareNode.stories.svelte +45 -0
- package/dist/components/nodes/SquareNode.svelte +27 -11
- package/dist/components/nodes/WorkflowNode.stories.svelte +63 -0
- package/dist/config/endpoints.d.ts +8 -0
- package/dist/config/endpoints.js +5 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +9 -0
- package/dist/editor/index.d.ts +3 -1
- package/dist/editor/index.js +4 -2
- package/dist/helpers/proximityConnect.js +8 -1
- package/dist/helpers/workflowEditorHelper.d.ts +3 -53
- package/dist/helpers/workflowEditorHelper.js +13 -228
- package/dist/playground/index.d.ts +1 -1
- package/dist/playground/index.js +1 -1
- package/dist/schemas/v1/workflow.schema.json +107 -22
- package/dist/services/chatService.d.ts +65 -0
- package/dist/services/chatService.js +131 -0
- package/dist/services/historyService.d.ts +6 -4
- package/dist/services/historyService.js +21 -6
- package/dist/skins/slate.js +16 -0
- package/dist/stores/interruptStore.svelte.js +6 -1
- package/dist/stores/playgroundStore.svelte.d.ts +1 -1
- package/dist/stores/playgroundStore.svelte.js +11 -2
- package/dist/stores/portCoordinateStore.svelte.d.ts +4 -0
- package/dist/stores/portCoordinateStore.svelte.js +20 -26
- package/dist/stores/workflowStore.svelte.d.ts +31 -2
- package/dist/stores/workflowStore.svelte.js +84 -64
- package/dist/stories/EdgeDecorator.svelte +4 -4
- package/dist/styles/base.css +48 -0
- package/dist/svelte-app.d.ts +7 -1
- package/dist/svelte-app.js +4 -1
- package/dist/types/chat.d.ts +63 -0
- package/dist/types/chat.js +9 -0
- package/dist/types/events.d.ts +28 -2
- package/dist/types/events.js +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/settings.d.ts +6 -0
- package/dist/types/settings.js +3 -0
- package/dist/utils/edgeStyling.d.ts +42 -0
- package/dist/utils/edgeStyling.js +176 -0
- package/dist/utils/nodeIds.d.ts +31 -0
- package/dist/utils/nodeIds.js +42 -0
- package/dist/utils/nodeSwap.d.ts +221 -0
- package/dist/utils/nodeSwap.js +686 -0
- package/package.json +6 -1
- package/dist/helpers/nodeLayoutHelper.d.ts +0 -14
- package/dist/helpers/nodeLayoutHelper.js +0 -19
|
@@ -15,11 +15,8 @@
|
|
|
15
15
|
import { getNodeIcon, getCategoryIcon } from "../utils/icons.js";
|
|
16
16
|
import { getCategoryColorToken } from "../utils/colors.js";
|
|
17
17
|
import { getCategoryLabel } from "../stores/categoriesStore.svelte.js";
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
getUiSettings,
|
|
21
|
-
updateSettings,
|
|
22
|
-
} from "../stores/settingsStore.svelte.js";
|
|
18
|
+
import { getUiSettings } from "../stores/settingsStore.svelte.js";
|
|
19
|
+
import { extractConfigDefaults } from "../utils/nodeIds.js";
|
|
23
20
|
|
|
24
21
|
interface Props {
|
|
25
22
|
nodes: NodeMetadata[];
|
|
@@ -36,16 +33,6 @@
|
|
|
36
33
|
// svelte-ignore state_referenced_locally — initial default, user selects interactively
|
|
37
34
|
let selectedCategory = $state(props.selectedCategory || "all");
|
|
38
35
|
|
|
39
|
-
/**
|
|
40
|
-
* Toggle the sidebar collapsed state
|
|
41
|
-
* Persists the new state to settings
|
|
42
|
-
*/
|
|
43
|
-
function toggleSidebar(): void {
|
|
44
|
-
updateSettings({
|
|
45
|
-
ui: { sidebarCollapsed: !getUiSettings().sidebarCollapsed },
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
36
|
/**
|
|
50
37
|
* Check if a node is compatible with the active workflow format.
|
|
51
38
|
* Nodes without formats are universal (compatible with all formats).
|
|
@@ -67,6 +54,17 @@
|
|
|
67
54
|
let filteredNodes = $derived(getFilteredNodes());
|
|
68
55
|
let categories = $derived(getCategories());
|
|
69
56
|
|
|
57
|
+
/** Group already-filtered results by category in a single pass */
|
|
58
|
+
let filteredNodesByCategory = $derived.by(() => {
|
|
59
|
+
const map = new Map<string, NodeMetadata[]>();
|
|
60
|
+
for (const node of filteredNodes) {
|
|
61
|
+
let list = map.get(node.category);
|
|
62
|
+
if (!list) { list = []; map.set(node.category, list); }
|
|
63
|
+
list.push(node);
|
|
64
|
+
}
|
|
65
|
+
return map;
|
|
66
|
+
});
|
|
67
|
+
|
|
70
68
|
/**
|
|
71
69
|
* Get all unique categories from node types, preserving API order
|
|
72
70
|
* Categories appear in the order their first node appears in the API response
|
|
@@ -74,7 +72,7 @@
|
|
|
74
72
|
function getCategories(): NodeCategory[] {
|
|
75
73
|
if (formatCompatibleNodes.length === 0) return [];
|
|
76
74
|
// Use a Set to track uniqueness while preserving insertion order
|
|
77
|
-
const seen = new
|
|
75
|
+
const seen = new Set<NodeCategory>();
|
|
78
76
|
const orderedCategories: NodeCategory[] = [];
|
|
79
77
|
for (const node of formatCompatibleNodes) {
|
|
80
78
|
if (!seen.has(node.category)) {
|
|
@@ -119,31 +117,13 @@
|
|
|
119
117
|
function handleNodeDragStart(event: DragEvent, nodeType: NodeMetadata): void {
|
|
120
118
|
if (!event.dataTransfer) return;
|
|
121
119
|
|
|
122
|
-
// Extract initial config from configSchema with proper null checks
|
|
123
|
-
let initialConfig: Record<string, unknown> = {};
|
|
124
|
-
if (
|
|
125
|
-
nodeType.configSchema &&
|
|
126
|
-
typeof nodeType.configSchema === "object" &&
|
|
127
|
-
nodeType.configSchema.properties &&
|
|
128
|
-
typeof nodeType.configSchema.properties === "object"
|
|
129
|
-
) {
|
|
130
|
-
// JSON Schema format - extract defaults
|
|
131
|
-
Object.entries(nodeType.configSchema.properties).forEach(
|
|
132
|
-
([key, prop]) => {
|
|
133
|
-
if (prop && typeof prop === "object" && "default" in prop) {
|
|
134
|
-
initialConfig[key] = prop.default;
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
120
|
// Create a new node instance from the node type
|
|
141
121
|
const newNodeData = {
|
|
142
122
|
type: "node",
|
|
143
123
|
nodeType: nodeType.id,
|
|
144
124
|
nodeData: {
|
|
145
125
|
label: nodeType.name,
|
|
146
|
-
config:
|
|
126
|
+
config: extractConfigDefaults(nodeType.configSchema),
|
|
147
127
|
metadata: nodeType,
|
|
148
128
|
},
|
|
149
129
|
};
|
|
@@ -188,93 +168,83 @@
|
|
|
188
168
|
return getCategoryLabel(category);
|
|
189
169
|
}
|
|
190
170
|
|
|
191
|
-
/**
|
|
192
|
-
* Get node types for category
|
|
193
|
-
* Preserves the API order - no client-side sorting applied
|
|
194
|
-
*/
|
|
195
|
-
function getNodesForCategory(category: NodeCategory): NodeMetadata[] {
|
|
196
|
-
return formatCompatibleNodes.filter((node) => node.category === category);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Get filtered nodes for category
|
|
201
|
-
*/
|
|
202
|
-
function getFilteredNodesForCategory(category: NodeCategory): NodeMetadata[] {
|
|
203
|
-
let nodes = getNodesForCategory(category);
|
|
204
|
-
|
|
205
|
-
// Filter by search query
|
|
206
|
-
if (searchInput.trim()) {
|
|
207
|
-
const query = searchInput.toLowerCase();
|
|
208
|
-
nodes = nodes.filter(
|
|
209
|
-
(node) =>
|
|
210
|
-
node.name.toLowerCase().includes(query) ||
|
|
211
|
-
node.description.toLowerCase().includes(query) ||
|
|
212
|
-
node.tags?.some((tag) => tag.toLowerCase().includes(query)),
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return nodes;
|
|
217
|
-
}
|
|
218
171
|
</script>
|
|
219
172
|
|
|
220
|
-
<!-- Components Sidebar
|
|
173
|
+
<!-- Components Sidebar -->
|
|
221
174
|
<aside
|
|
222
175
|
class="flowdrop-sidebar flowdrop-sidebar--container"
|
|
223
176
|
class:flowdrop-sidebar--collapsed={isCollapsed}
|
|
224
177
|
class:flowdrop-sidebar--compact={getUiSettings().compactMode}
|
|
225
|
-
style:width="{isCollapsed ?
|
|
178
|
+
style:width="{isCollapsed ? 0 : getUiSettings().sidebarWidth}px"
|
|
226
179
|
aria-label="Components sidebar"
|
|
227
180
|
>
|
|
228
|
-
<!--
|
|
229
|
-
<div class="flowdrop-
|
|
230
|
-
<
|
|
231
|
-
class="flowdrop-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
<div class="flowdrop-sidebar__title">
|
|
240
|
-
<h2 class="flowdrop-text--lg flowdrop-font--bold">Components</h2>
|
|
181
|
+
<!-- Search Section — visibility controlled by --fd-sidebar-search-display -->
|
|
182
|
+
<div class="flowdrop-sidebar__search">
|
|
183
|
+
<div class="flowdrop-join flowdrop-w--full">
|
|
184
|
+
<div class="flowdrop-join__item flowdrop-flex--1">
|
|
185
|
+
<input
|
|
186
|
+
type="text"
|
|
187
|
+
placeholder="Search components..."
|
|
188
|
+
class="flowdrop-input flowdrop-join__item flowdrop-w--full"
|
|
189
|
+
bind:value={searchInput}
|
|
190
|
+
oninput={handleSearchChange}
|
|
191
|
+
/>
|
|
241
192
|
</div>
|
|
242
|
-
|
|
193
|
+
<button
|
|
194
|
+
class="flowdrop-btn flowdrop-join__item"
|
|
195
|
+
aria-label="Search components"
|
|
196
|
+
>
|
|
197
|
+
<Icon icon="mdi:magnify" class="flowdrop-icon" />
|
|
198
|
+
</button>
|
|
199
|
+
</div>
|
|
243
200
|
</div>
|
|
244
201
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
202
|
+
<!-- Node Types List -->
|
|
203
|
+
<div class="flowdrop-sidebar__content">
|
|
204
|
+
{#if props.nodes?.length === 0}
|
|
205
|
+
<!-- No node types available -->
|
|
206
|
+
<div class="flowdrop-hero">
|
|
207
|
+
<div class="flowdrop-hero__content">
|
|
208
|
+
{#if props.loading}
|
|
209
|
+
<div class="flowdrop-mb--4">
|
|
210
|
+
<LoadingSpinner size="md" text="Loading from server..." />
|
|
211
|
+
</div>
|
|
212
|
+
{:else}
|
|
213
|
+
<div class="flowdrop-hero__icon">
|
|
214
|
+
<svg
|
|
215
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
216
|
+
width="1em"
|
|
217
|
+
height="1em"
|
|
218
|
+
viewBox="0 0 24 24"
|
|
219
|
+
fill="none"
|
|
220
|
+
stroke="currentColor"
|
|
221
|
+
stroke-width="1.5"
|
|
222
|
+
stroke-linecap="round"
|
|
223
|
+
stroke-linejoin="round"
|
|
224
|
+
>
|
|
225
|
+
<path
|
|
226
|
+
d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"
|
|
227
|
+
/>
|
|
228
|
+
<polyline points="3.27 6.96 12 12.01 20.73 6.96" />
|
|
229
|
+
<line x1="12" y1="22.08" x2="12" y2="12" />
|
|
230
|
+
</svg>
|
|
231
|
+
</div>
|
|
232
|
+
<h3 class="flowdrop-hero__title">No node types available</h3>
|
|
233
|
+
<p class="flowdrop-hero__description">
|
|
234
|
+
Node type definitions will appear here
|
|
235
|
+
</p>
|
|
236
|
+
{/if}
|
|
257
237
|
</div>
|
|
258
|
-
<button
|
|
259
|
-
class="flowdrop-btn flowdrop-join__item"
|
|
260
|
-
aria-label="Search components"
|
|
261
|
-
>
|
|
262
|
-
<Icon icon="mdi:magnify" class="flowdrop-icon" />
|
|
263
|
-
</button>
|
|
264
238
|
</div>
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
<div class="flowdrop-
|
|
273
|
-
|
|
274
|
-
<div class="flowdrop-mb--4">
|
|
275
|
-
<LoadingSpinner size="md" text="Loading from server..." />
|
|
276
|
-
</div>
|
|
277
|
-
{:else}
|
|
239
|
+
{:else if searchInput.trim()}
|
|
240
|
+
<!-- Search Results -->
|
|
241
|
+
<div class="flowdrop-p--4">
|
|
242
|
+
<div class="flowdrop-divider">
|
|
243
|
+
<h3 class="flowdrop-divider__text">Search Results</h3>
|
|
244
|
+
</div>
|
|
245
|
+
{#if filteredNodes.length === 0}
|
|
246
|
+
<div class="flowdrop-hero">
|
|
247
|
+
<div class="flowdrop-hero__content">
|
|
278
248
|
<div class="flowdrop-hero__icon">
|
|
279
249
|
<svg
|
|
280
250
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -287,117 +257,131 @@
|
|
|
287
257
|
stroke-linecap="round"
|
|
288
258
|
stroke-linejoin="round"
|
|
289
259
|
>
|
|
290
|
-
<
|
|
291
|
-
|
|
292
|
-
/>
|
|
293
|
-
<polyline points="3.27 6.96 12 12.01 20.73 6.96" />
|
|
294
|
-
<line x1="12" y1="22.08" x2="12" y2="12" />
|
|
260
|
+
<circle cx="11" cy="11" r="8" />
|
|
261
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
295
262
|
</svg>
|
|
296
263
|
</div>
|
|
297
|
-
<h3 class="flowdrop-hero__title">No
|
|
264
|
+
<h3 class="flowdrop-hero__title">No components found</h3>
|
|
298
265
|
<p class="flowdrop-hero__description">
|
|
299
|
-
|
|
266
|
+
Try adjusting your search
|
|
300
267
|
</p>
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
<div class="flowdrop-divider">
|
|
308
|
-
<h3 class="flowdrop-divider__text">Search Results</h3>
|
|
268
|
+
{#if props.loading}
|
|
269
|
+
<div class="flowdrop-mb--4">
|
|
270
|
+
<LoadingSpinner size="sm" text="Loading components..." />
|
|
271
|
+
</div>
|
|
272
|
+
{/if}
|
|
273
|
+
</div>
|
|
309
274
|
</div>
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
stroke-linejoin="round"
|
|
275
|
+
{:else}
|
|
276
|
+
<div class="flowdrop-node-list">
|
|
277
|
+
{#each filteredNodes as nodeType (nodeType.id)}
|
|
278
|
+
<div
|
|
279
|
+
class="flowdrop-card flowdrop-card--compact flowdrop-node-item"
|
|
280
|
+
draggable="true"
|
|
281
|
+
ondragstart={(e) => handleNodeDragStart(e, nodeType)}
|
|
282
|
+
role="button"
|
|
283
|
+
tabindex="0"
|
|
284
|
+
>
|
|
285
|
+
<div class="flowdrop-card__body flowdrop-p--1 flowdrop-py--1">
|
|
286
|
+
<div
|
|
287
|
+
class="flowdrop-flex flowdrop-gap--2 flowdrop-items--center"
|
|
324
288
|
>
|
|
325
|
-
|
|
326
|
-
<
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
289
|
+
<!-- Node Type Icon with Squircle Background -->
|
|
290
|
+
<span
|
|
291
|
+
class="flowdrop-node-icon"
|
|
292
|
+
style="--_icon-color: {getCategoryColorToken(
|
|
293
|
+
nodeType.category,
|
|
294
|
+
)}"
|
|
295
|
+
>
|
|
296
|
+
<Icon
|
|
297
|
+
icon={getNodeIcon(nodeType.icon, nodeType.category)}
|
|
298
|
+
/>
|
|
299
|
+
</span>
|
|
300
|
+
|
|
301
|
+
<!-- Node Type Info - Icon and Title only -->
|
|
302
|
+
<h4
|
|
303
|
+
class="flowdrop-text--sm flowdrop-font--medium flowdrop-truncate flowdrop-flex--1"
|
|
304
|
+
>
|
|
305
|
+
{nodeType.name}
|
|
306
|
+
</h4>
|
|
336
307
|
</div>
|
|
337
|
-
|
|
308
|
+
<p
|
|
309
|
+
class="flowdrop-text--xs flowdrop-text--gray flowdrop-truncate flowdrop-mt--1 flowdrop-ml--0"
|
|
310
|
+
>
|
|
311
|
+
{nodeType.description}
|
|
312
|
+
</p>
|
|
313
|
+
</div>
|
|
338
314
|
</div>
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
315
|
+
{/each}
|
|
316
|
+
</div>
|
|
317
|
+
{/if}
|
|
318
|
+
</div>
|
|
319
|
+
{:else}
|
|
320
|
+
<!-- Show categories with details when no search is active -->
|
|
321
|
+
<div class="flowdrop-p--4">
|
|
322
|
+
<!-- Category-specific details -->
|
|
323
|
+
<div class="flowdrop-category-list">
|
|
324
|
+
{#each categories as category (category)}
|
|
325
|
+
{@const categoryNodes = filteredNodesByCategory.get(category) ?? []}
|
|
326
|
+
{#if categoryNodes.length > 0}
|
|
327
|
+
<!-- Flat style: label + dot+name rows (shown/hidden via CSS token) -->
|
|
328
|
+
<div class="fd-sidebar-flat-section">
|
|
329
|
+
<div class="fd-sidebar-flat-category">
|
|
330
|
+
{getCategoryDisplayName(category).toUpperCase()}
|
|
331
|
+
</div>
|
|
332
|
+
<div class="fd-sidebar-flat-list">
|
|
333
|
+
{#each categoryNodes as nodeType (nodeType.id)}
|
|
351
334
|
<div
|
|
352
|
-
class="
|
|
335
|
+
class="fd-sidebar-flat-item"
|
|
336
|
+
draggable="true"
|
|
337
|
+
ondragstart={(e) => handleNodeDragStart(e, nodeType)}
|
|
338
|
+
onclick={() => handleNodeClick(nodeType)}
|
|
339
|
+
role="button"
|
|
340
|
+
tabindex="0"
|
|
341
|
+
onkeydown={(e) => {
|
|
342
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
343
|
+
e.preventDefault();
|
|
344
|
+
handleNodeClick(nodeType);
|
|
345
|
+
}
|
|
346
|
+
}}
|
|
353
347
|
>
|
|
354
|
-
<!-- Node Type Icon with Squircle Background -->
|
|
355
348
|
<span
|
|
356
|
-
class="
|
|
357
|
-
style="
|
|
349
|
+
class="fd-sidebar-flat-dot"
|
|
350
|
+
style="background: {getCategoryColorToken(
|
|
358
351
|
nodeType.category,
|
|
359
352
|
)}"
|
|
360
|
-
>
|
|
361
|
-
|
|
362
|
-
icon={getNodeIcon(nodeType.icon, nodeType.category)}
|
|
363
|
-
/>
|
|
364
|
-
</span>
|
|
365
|
-
|
|
366
|
-
<!-- Node Type Info - Icon and Title only -->
|
|
367
|
-
<h4
|
|
368
|
-
class="flowdrop-text--sm flowdrop-font--medium flowdrop-truncate flowdrop-flex--1"
|
|
369
|
-
>
|
|
370
|
-
{nodeType.name}
|
|
371
|
-
</h4>
|
|
353
|
+
></span>
|
|
354
|
+
<span class="fd-sidebar-flat-name">{nodeType.name}</span>
|
|
372
355
|
</div>
|
|
373
|
-
|
|
374
|
-
|
|
356
|
+
{/each}
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
|
+
<!-- Card style: <details> accordion (shown/hidden via CSS token) -->
|
|
360
|
+
<details
|
|
361
|
+
class="flowdrop-details fd-sidebar-card-section"
|
|
362
|
+
open={props.categoriesDefaultOpen || undefined}
|
|
363
|
+
>
|
|
364
|
+
<summary class="flowdrop-details__summary">
|
|
365
|
+
<div
|
|
366
|
+
class="flowdrop-flex flowdrop-gap--2 flowdrop-items--center"
|
|
367
|
+
>
|
|
368
|
+
<span
|
|
369
|
+
class="flowdrop-node-icon"
|
|
370
|
+
style="--_icon-color: {getCategoryColorToken(category)}"
|
|
375
371
|
>
|
|
376
|
-
{
|
|
377
|
-
</
|
|
372
|
+
<Icon icon={getCategoryIcon(category)} />
|
|
373
|
+
</span>
|
|
374
|
+
<span>{getCategoryDisplayName(category)}</span>
|
|
378
375
|
</div>
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
</div>
|
|
382
|
-
{/if}
|
|
383
|
-
</div>
|
|
384
|
-
{:else}
|
|
385
|
-
<!-- Show categories with details when no search is active -->
|
|
386
|
-
<div class="flowdrop-p--4">
|
|
387
|
-
<!-- Category-specific details -->
|
|
388
|
-
<div class="flowdrop-category-list">
|
|
389
|
-
{#each categories as category (category)}
|
|
390
|
-
{@const categoryNodes = getFilteredNodesForCategory(category)}
|
|
391
|
-
{#if categoryNodes.length > 0}
|
|
392
|
-
<!-- Flat style: label + dot+name rows (shown/hidden via CSS token) -->
|
|
393
|
-
<div class="fd-sidebar-flat-section">
|
|
394
|
-
<div class="fd-sidebar-flat-category">
|
|
395
|
-
{getCategoryDisplayName(category).toUpperCase()}
|
|
376
|
+
<div class="flowdrop-badge flowdrop-badge--secondary">
|
|
377
|
+
{categoryNodes.length}
|
|
396
378
|
</div>
|
|
397
|
-
|
|
379
|
+
</summary>
|
|
380
|
+
<div class="flowdrop-details__content">
|
|
381
|
+
<div class="flowdrop-node-list">
|
|
398
382
|
{#each categoryNodes as nodeType (nodeType.id)}
|
|
399
383
|
<div
|
|
400
|
-
class="
|
|
384
|
+
class="flowdrop-card flowdrop-card--compact flowdrop-node-item"
|
|
401
385
|
draggable="true"
|
|
402
386
|
ondragstart={(e) => handleNodeDragStart(e, nodeType)}
|
|
403
387
|
onclick={() => handleNodeClick(nodeType)}
|
|
@@ -410,122 +394,71 @@
|
|
|
410
394
|
}
|
|
411
395
|
}}
|
|
412
396
|
>
|
|
413
|
-
<span
|
|
414
|
-
class="fd-sidebar-flat-dot"
|
|
415
|
-
style="background: {getCategoryColorToken(
|
|
416
|
-
nodeType.category,
|
|
417
|
-
)}"
|
|
418
|
-
></span>
|
|
419
|
-
<span class="fd-sidebar-flat-name">{nodeType.name}</span
|
|
420
|
-
>
|
|
421
|
-
</div>
|
|
422
|
-
{/each}
|
|
423
|
-
</div>
|
|
424
|
-
</div>
|
|
425
|
-
<!-- Card style: <details> accordion (shown/hidden via CSS token) -->
|
|
426
|
-
<details
|
|
427
|
-
class="flowdrop-details fd-sidebar-card-section"
|
|
428
|
-
open={props.categoriesDefaultOpen || undefined}
|
|
429
|
-
>
|
|
430
|
-
<summary class="flowdrop-details__summary">
|
|
431
|
-
<div
|
|
432
|
-
class="flowdrop-flex flowdrop-gap--2 flowdrop-items--center"
|
|
433
|
-
>
|
|
434
|
-
<span
|
|
435
|
-
class="flowdrop-node-icon"
|
|
436
|
-
style="--_icon-color: {getCategoryColorToken(category)}"
|
|
437
|
-
>
|
|
438
|
-
<Icon icon={getCategoryIcon(category)} />
|
|
439
|
-
</span>
|
|
440
|
-
<span>{getCategoryDisplayName(category)}</span>
|
|
441
|
-
</div>
|
|
442
|
-
<div class="flowdrop-badge flowdrop-badge--secondary">
|
|
443
|
-
{categoryNodes.length}
|
|
444
|
-
</div>
|
|
445
|
-
</summary>
|
|
446
|
-
<div class="flowdrop-details__content">
|
|
447
|
-
<div class="flowdrop-node-list">
|
|
448
|
-
{#each categoryNodes as nodeType (nodeType.id)}
|
|
449
397
|
<div
|
|
450
|
-
class="flowdrop-
|
|
451
|
-
draggable="true"
|
|
452
|
-
ondragstart={(e) => handleNodeDragStart(e, nodeType)}
|
|
453
|
-
onclick={() => handleNodeClick(nodeType)}
|
|
454
|
-
role="button"
|
|
455
|
-
tabindex="0"
|
|
456
|
-
onkeydown={(e) => {
|
|
457
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
458
|
-
e.preventDefault();
|
|
459
|
-
handleNodeClick(nodeType);
|
|
460
|
-
}
|
|
461
|
-
}}
|
|
398
|
+
class="flowdrop-card__body flowdrop-p--1 flowdrop-py--1"
|
|
462
399
|
>
|
|
463
400
|
<div
|
|
464
|
-
class="flowdrop-
|
|
401
|
+
class="flowdrop-flex flowdrop-gap--2 flowdrop-items--center"
|
|
465
402
|
>
|
|
466
|
-
|
|
467
|
-
|
|
403
|
+
<!-- Node Type Icon with Squircle Background -->
|
|
404
|
+
<span
|
|
405
|
+
class="flowdrop-node-icon"
|
|
406
|
+
style="--_icon-color: {getCategoryColorToken(
|
|
407
|
+
nodeType.category,
|
|
408
|
+
)}"
|
|
468
409
|
>
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
style="--_icon-color: {getCategoryColorToken(
|
|
410
|
+
<Icon
|
|
411
|
+
icon={getNodeIcon(
|
|
412
|
+
nodeType.icon,
|
|
473
413
|
nodeType.category,
|
|
474
|
-
)}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
/>
|
|
482
|
-
</span>
|
|
483
|
-
|
|
484
|
-
<!-- Node Type Info - Icon and Title only -->
|
|
485
|
-
<h4
|
|
486
|
-
class="flowdrop-text--sm flowdrop-font--medium flowdrop-truncate flowdrop-flex--1"
|
|
487
|
-
>
|
|
488
|
-
{nodeType.name}
|
|
489
|
-
</h4>
|
|
490
|
-
</div>
|
|
491
|
-
<p
|
|
492
|
-
class="flowdrop-text--xs flowdrop-text--gray flowdrop-truncate flowdrop-mt--1 flowdrop-ml--0"
|
|
414
|
+
)}
|
|
415
|
+
/>
|
|
416
|
+
</span>
|
|
417
|
+
|
|
418
|
+
<!-- Node Type Info - Icon and Title only -->
|
|
419
|
+
<h4
|
|
420
|
+
class="flowdrop-text--sm flowdrop-font--medium flowdrop-truncate flowdrop-flex--1"
|
|
493
421
|
>
|
|
494
|
-
{nodeType.
|
|
495
|
-
</
|
|
422
|
+
{nodeType.name}
|
|
423
|
+
</h4>
|
|
496
424
|
</div>
|
|
425
|
+
<p
|
|
426
|
+
class="flowdrop-text--xs flowdrop-text--gray flowdrop-truncate flowdrop-mt--1 flowdrop-ml--0"
|
|
427
|
+
>
|
|
428
|
+
{nodeType.description}
|
|
429
|
+
</p>
|
|
497
430
|
</div>
|
|
498
|
-
|
|
499
|
-
|
|
431
|
+
</div>
|
|
432
|
+
{/each}
|
|
500
433
|
</div>
|
|
501
|
-
</
|
|
502
|
-
|
|
503
|
-
{/
|
|
504
|
-
|
|
434
|
+
</div>
|
|
435
|
+
</details>
|
|
436
|
+
{/if}
|
|
437
|
+
{/each}
|
|
505
438
|
</div>
|
|
506
|
-
|
|
507
|
-
|
|
439
|
+
</div>
|
|
440
|
+
{/if}
|
|
441
|
+
</div>
|
|
508
442
|
|
|
509
|
-
|
|
510
|
-
|
|
443
|
+
<!-- Footer -->
|
|
444
|
+
<div class="flowdrop-sidebar__footer">
|
|
445
|
+
<div class="flowdrop-flex flowdrop-gap--4">
|
|
511
446
|
<div class="flowdrop-flex flowdrop-gap--4">
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
{/if}
|
|
525
|
-
</div>
|
|
447
|
+
{#if props.loading && props.nodes?.length === 0}
|
|
448
|
+
<span class="flowdrop-text--xs flowdrop-text--gray"
|
|
449
|
+
>Loading components...</span
|
|
450
|
+
>
|
|
451
|
+
{:else}
|
|
452
|
+
<span class="flowdrop-text--xs flowdrop-text--gray"
|
|
453
|
+
>Total: {props.nodes?.length || 0} components</span
|
|
454
|
+
>
|
|
455
|
+
<span class="flowdrop-text--xs flowdrop-text--gray"
|
|
456
|
+
>Showing: {filteredNodes.length}</span
|
|
457
|
+
>
|
|
458
|
+
{/if}
|
|
526
459
|
</div>
|
|
527
460
|
</div>
|
|
528
|
-
|
|
461
|
+
</div>
|
|
529
462
|
</aside>
|
|
530
463
|
|
|
531
464
|
<style>
|
|
@@ -549,21 +482,14 @@
|
|
|
549
482
|
height: 100%;
|
|
550
483
|
}
|
|
551
484
|
|
|
552
|
-
/* Collapsed state */
|
|
485
|
+
/* Collapsed state — fully hidden */
|
|
553
486
|
.flowdrop-sidebar--collapsed {
|
|
554
487
|
overflow: hidden;
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
.flowdrop-sidebar--collapsed .flowdrop-sidebar__header {
|
|
558
|
-
justify-content: center;
|
|
559
|
-
padding: 0.75rem 0.5rem;
|
|
488
|
+
border-right: none;
|
|
489
|
+
box-shadow: none;
|
|
560
490
|
}
|
|
561
491
|
|
|
562
492
|
/* Compact mode styles */
|
|
563
|
-
.flowdrop-sidebar--compact .flowdrop-sidebar__header {
|
|
564
|
-
padding: 0.5rem 0.75rem;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
493
|
.flowdrop-sidebar--compact .flowdrop-sidebar__search {
|
|
568
494
|
padding: 0.5rem 0.75rem;
|
|
569
495
|
}
|
|
@@ -591,56 +517,6 @@
|
|
|
591
517
|
gap: 0.25rem;
|
|
592
518
|
}
|
|
593
519
|
|
|
594
|
-
/* Toggle button */
|
|
595
|
-
.flowdrop-sidebar__toggle {
|
|
596
|
-
display: flex;
|
|
597
|
-
align-items: center;
|
|
598
|
-
justify-content: center;
|
|
599
|
-
width: 2rem;
|
|
600
|
-
height: 2rem;
|
|
601
|
-
border: none;
|
|
602
|
-
background: transparent;
|
|
603
|
-
color: var(--fd-muted-foreground);
|
|
604
|
-
border-radius: var(--fd-radius-md);
|
|
605
|
-
cursor: pointer;
|
|
606
|
-
transition:
|
|
607
|
-
color var(--fd-transition-fast),
|
|
608
|
-
background-color var(--fd-transition-fast);
|
|
609
|
-
flex-shrink: 0;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
.flowdrop-sidebar__toggle:hover {
|
|
613
|
-
color: var(--fd-foreground);
|
|
614
|
-
background-color: var(--fd-subtle);
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
.flowdrop-sidebar__toggle:focus {
|
|
618
|
-
outline: none;
|
|
619
|
-
box-shadow: 0 0 0 2px var(--fd-ring);
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
.flowdrop-sidebar__header {
|
|
623
|
-
background: var(--fd-header);
|
|
624
|
-
border-bottom: 1px solid var(--fd-border);
|
|
625
|
-
padding: 0.75rem 1rem;
|
|
626
|
-
display: var(--fd-sidebar-header-display, flex);
|
|
627
|
-
align-items: center;
|
|
628
|
-
justify-content: space-between;
|
|
629
|
-
flex-shrink: 0;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
.flowdrop-sidebar__title {
|
|
633
|
-
display: flex;
|
|
634
|
-
align-items: center;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
.flowdrop-sidebar__title h2 {
|
|
638
|
-
font-size: 1rem;
|
|
639
|
-
font-weight: 600;
|
|
640
|
-
margin: 0;
|
|
641
|
-
color: var(--fd-foreground);
|
|
642
|
-
}
|
|
643
|
-
|
|
644
520
|
.flowdrop-sidebar__search {
|
|
645
521
|
padding: 0.75rem 1rem;
|
|
646
522
|
background-color: var(--fd-background);
|