@d34dman/flowdrop 0.0.29 → 0.0.30
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.
|
@@ -25,25 +25,34 @@
|
|
|
25
25
|
let categories = $derived(getCategories());
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Get all unique categories from node types
|
|
28
|
+
* Get all unique categories from node types, preserving API order
|
|
29
|
+
* Categories appear in the order their first node appears in the API response
|
|
29
30
|
*/
|
|
30
31
|
function getCategories(): NodeCategory[] {
|
|
31
32
|
const nodes = props.nodes || [];
|
|
32
33
|
if (nodes.length === 0) return [];
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
// Use a Set to track uniqueness while preserving insertion order
|
|
35
|
+
const seen = new SvelteSet<NodeCategory>();
|
|
36
|
+
const orderedCategories: NodeCategory[] = [];
|
|
37
|
+
for (const node of nodes) {
|
|
38
|
+
if (!seen.has(node.category)) {
|
|
39
|
+
seen.add(node.category);
|
|
40
|
+
orderedCategories.push(node.category);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return orderedCategories;
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
/**
|
|
39
47
|
* Filter node types based on search query and selected category
|
|
48
|
+
* Preserves the API order - no client-side sorting applied
|
|
40
49
|
*/
|
|
41
50
|
function getFilteredNodes(): NodeMetadata[] {
|
|
42
51
|
// Use actual node types from props
|
|
43
52
|
let filtered = props.nodes || [];
|
|
44
53
|
|
|
45
54
|
// Filter by category
|
|
46
|
-
if (selectedCategory !==
|
|
55
|
+
if (selectedCategory !== "all") {
|
|
47
56
|
filtered = filtered.filter((node) => node.category === selectedCategory);
|
|
48
57
|
}
|
|
49
58
|
|
|
@@ -58,8 +67,8 @@
|
|
|
58
67
|
);
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
//
|
|
62
|
-
return
|
|
70
|
+
// Return filtered results preserving API order
|
|
71
|
+
return filtered;
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
/**
|
|
@@ -149,12 +158,11 @@
|
|
|
149
158
|
|
|
150
159
|
/**
|
|
151
160
|
* Get node types for category
|
|
161
|
+
* Preserves the API order - no client-side sorting applied
|
|
152
162
|
*/
|
|
153
163
|
function getNodesForCategory(category: NodeCategory): NodeMetadata[] {
|
|
154
164
|
const nodes = props.nodes || [];
|
|
155
|
-
return
|
|
156
|
-
.filter((node) => node.category === category)
|
|
157
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
165
|
+
return nodes.filter((node) => node.category === category);
|
|
158
166
|
}
|
|
159
167
|
|
|
160
168
|
/**
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
} from '../helpers/workflowEditorHelper.js';
|
|
38
38
|
import type { NodeExecutionInfo } from '../types/index.js';
|
|
39
39
|
import { areNodeArraysEqual, areEdgeArraysEqual, throttle } from '../utils/performanceUtils.js';
|
|
40
|
+
import { Toaster } from 'svelte-5-french-toast';
|
|
40
41
|
|
|
41
42
|
interface Props {
|
|
42
43
|
nodes?: NodeMetadata[];
|
|
@@ -457,6 +458,9 @@
|
|
|
457
458
|
</div>
|
|
458
459
|
</SvelteFlowProvider>
|
|
459
460
|
|
|
461
|
+
<!-- Toast notifications container -->
|
|
462
|
+
<Toaster position="bottom-center" />
|
|
463
|
+
|
|
460
464
|
<style>
|
|
461
465
|
.flowdrop-workflow-editor {
|
|
462
466
|
display: flex;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<script lang="ts">
|
|
8
8
|
import { Position, Handle } from '@xyflow/svelte';
|
|
9
9
|
import Icon from '@iconify/svelte';
|
|
10
|
-
import { getDataTypeColor } from '../../utils/colors';
|
|
10
|
+
import { getDataTypeColor, getColorVariants } from '../../utils/colors';
|
|
11
11
|
import type { NodeMetadata } from '../../types/index.js';
|
|
12
12
|
|
|
13
13
|
interface ToolNodeParameter {
|
|
@@ -64,6 +64,19 @@
|
|
|
64
64
|
'1.0.0'
|
|
65
65
|
);
|
|
66
66
|
|
|
67
|
+
// Generate color variants for theming (light tint for background, border tint for borders)
|
|
68
|
+
let colorVariants = $derived(getColorVariants(toolColor));
|
|
69
|
+
|
|
70
|
+
// Build inline style string for CSS custom properties
|
|
71
|
+
// This allows per-node color overrides while defaulting to global CSS variables
|
|
72
|
+
let nodeStyle = $derived(
|
|
73
|
+
[
|
|
74
|
+
`--flowdrop-tool-node-color: ${colorVariants.base}`,
|
|
75
|
+
`--flowdrop-tool-node-color-light: ${colorVariants.light}`,
|
|
76
|
+
`--flowdrop-tool-node-color-border: ${colorVariants.border}`
|
|
77
|
+
].join('; ')
|
|
78
|
+
);
|
|
79
|
+
|
|
67
80
|
// Check for tool interface ports in metadata
|
|
68
81
|
let hasToolInputPort = $derived(
|
|
69
82
|
props.data.metadata?.inputs?.some((port) => port.dataType === 'tool') || false
|
|
@@ -128,6 +141,7 @@
|
|
|
128
141
|
class:flowdrop-tool-node--selected={props.selected}
|
|
129
142
|
class:flowdrop-tool-node--processing={props.isProcessing}
|
|
130
143
|
class:flowdrop-tool-node--error={props.isError}
|
|
144
|
+
style={nodeStyle}
|
|
131
145
|
onclick={handleClick}
|
|
132
146
|
ondblclick={handleDoubleClick}
|
|
133
147
|
onkeydown={handleKeydown}
|
|
@@ -138,7 +152,7 @@
|
|
|
138
152
|
<div class="flowdrop-tool-node__header">
|
|
139
153
|
<div class="flowdrop-tool-node__header-content">
|
|
140
154
|
<!-- Tool Icon -->
|
|
141
|
-
<div class="flowdrop-tool-node__icon-container"
|
|
155
|
+
<div class="flowdrop-tool-node__icon-container">
|
|
142
156
|
<Icon icon={toolIcon} class="flowdrop-tool-node__icon" />
|
|
143
157
|
</div>
|
|
144
158
|
|
|
@@ -214,7 +228,7 @@
|
|
|
214
228
|
|
|
215
229
|
.flowdrop-tool-node--selected {
|
|
216
230
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
217
|
-
border: 2px solid
|
|
231
|
+
border: 2px solid var(--flowdrop-tool-node-color);
|
|
218
232
|
}
|
|
219
233
|
|
|
220
234
|
.flowdrop-tool-node--processing {
|
|
@@ -228,9 +242,9 @@
|
|
|
228
242
|
|
|
229
243
|
.flowdrop-tool-node__header {
|
|
230
244
|
padding: 1rem;
|
|
231
|
-
background-color:
|
|
245
|
+
background-color: var(--flowdrop-tool-node-color-light);
|
|
232
246
|
border-radius: 0.75rem;
|
|
233
|
-
border: 1px solid
|
|
247
|
+
border: 1px solid var(--flowdrop-tool-node-color-border);
|
|
234
248
|
}
|
|
235
249
|
|
|
236
250
|
.flowdrop-tool-node__header-content {
|
|
@@ -248,6 +262,7 @@
|
|
|
248
262
|
height: 2.5rem;
|
|
249
263
|
border-radius: 0.5rem;
|
|
250
264
|
flex-shrink: 0;
|
|
265
|
+
background-color: var(--flowdrop-tool-node-color);
|
|
251
266
|
}
|
|
252
267
|
|
|
253
268
|
.flowdrop-tool-node__info {
|
|
@@ -271,7 +286,7 @@
|
|
|
271
286
|
}
|
|
272
287
|
|
|
273
288
|
.flowdrop-tool-node__badge {
|
|
274
|
-
background-color:
|
|
289
|
+
background-color: var(--flowdrop-tool-node-color);
|
|
275
290
|
color: white;
|
|
276
291
|
font-size: 0.625rem;
|
|
277
292
|
font-weight: 700;
|
|
@@ -375,11 +390,11 @@
|
|
|
375
390
|
|
|
376
391
|
/* Metadata port hover effects */
|
|
377
392
|
:global(.svelte-flow__node-tool .svelte-flow__handle:hover) {
|
|
378
|
-
box-shadow: 0 0 0 2px
|
|
393
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--flowdrop-tool-node-color) 30%, transparent) !important;
|
|
379
394
|
}
|
|
380
395
|
|
|
381
396
|
:global(.svelte-flow__node-tool .svelte-flow__handle:focus) {
|
|
382
|
-
outline: 2px solid
|
|
397
|
+
outline: 2px solid var(--flowdrop-tool-node-color) !important;
|
|
383
398
|
outline-offset: 2px !important;
|
|
384
399
|
}
|
|
385
400
|
</style>
|
package/dist/styles/base.css
CHANGED
|
@@ -1157,6 +1157,11 @@
|
|
|
1157
1157
|
--flowdrop-edge-data-color-hover: var(--color-ref-gray-500);
|
|
1158
1158
|
--flowdrop-edge-data-color-selected: var(--color-ref-violet-600);
|
|
1159
1159
|
|
|
1160
|
+
/* Tool node theming tokens */
|
|
1161
|
+
--flowdrop-tool-node-color: var(--color-ref-amber-500);
|
|
1162
|
+
--flowdrop-tool-node-color-light: var(--color-ref-amber-50);
|
|
1163
|
+
--flowdrop-tool-node-color-border: var(--color-ref-amber-300);
|
|
1164
|
+
|
|
1160
1165
|
/* Semantic text color tokens */
|
|
1161
1166
|
--flowdrop-text-color-error: var(--color-ref-red-600);
|
|
1162
1167
|
--flowdrop-text-color-success: var(--color-ref-green-600);
|
package/dist/utils/colors.d.ts
CHANGED
|
@@ -148,3 +148,45 @@ export declare function isArrayDataType(dataType: string): boolean;
|
|
|
148
148
|
* @returns The element type (e.g., "string") or null if not an array
|
|
149
149
|
*/
|
|
150
150
|
export declare function getArrayElementType(arrayDataType: string): string | null;
|
|
151
|
+
/**
|
|
152
|
+
* Parse a hex color string to RGB components
|
|
153
|
+
* @param hex - Hex color string (e.g., "#f59e0b" or "f59e0b")
|
|
154
|
+
* @returns Object with r, g, b values (0-255) or null if invalid
|
|
155
|
+
*/
|
|
156
|
+
export declare function hexToRgb(hex: string): {
|
|
157
|
+
r: number;
|
|
158
|
+
g: number;
|
|
159
|
+
b: number;
|
|
160
|
+
} | null;
|
|
161
|
+
/**
|
|
162
|
+
* Convert RGB components to hex color string
|
|
163
|
+
* @param r - Red component (0-255)
|
|
164
|
+
* @param g - Green component (0-255)
|
|
165
|
+
* @param b - Blue component (0-255)
|
|
166
|
+
* @returns Hex color string with # prefix
|
|
167
|
+
*/
|
|
168
|
+
export declare function rgbToHex(r: number, g: number, b: number): string;
|
|
169
|
+
/**
|
|
170
|
+
* Generate a light tint of a color (similar to Tailwind's -50 shade)
|
|
171
|
+
* Creates a very light background-friendly version of the color
|
|
172
|
+
* @param hex - Base hex color string
|
|
173
|
+
* @returns Light tint hex color string
|
|
174
|
+
*/
|
|
175
|
+
export declare function getLightTint(hex: string): string;
|
|
176
|
+
/**
|
|
177
|
+
* Generate a border tint of a color (similar to Tailwind's -300 shade)
|
|
178
|
+
* Creates a medium-light version suitable for borders
|
|
179
|
+
* @param hex - Base hex color string
|
|
180
|
+
* @returns Border tint hex color string
|
|
181
|
+
*/
|
|
182
|
+
export declare function getBorderTint(hex: string): string;
|
|
183
|
+
/**
|
|
184
|
+
* Generate color variants for theming a component
|
|
185
|
+
* @param baseColor - Base hex color string
|
|
186
|
+
* @returns Object with base, light, and border color variants
|
|
187
|
+
*/
|
|
188
|
+
export declare function getColorVariants(baseColor: string): {
|
|
189
|
+
base: string;
|
|
190
|
+
light: string;
|
|
191
|
+
border: string;
|
|
192
|
+
};
|
package/dist/utils/colors.js
CHANGED
|
@@ -302,3 +302,80 @@ export function getArrayElementType(arrayDataType) {
|
|
|
302
302
|
}
|
|
303
303
|
return null;
|
|
304
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Parse a hex color string to RGB components
|
|
307
|
+
* @param hex - Hex color string (e.g., "#f59e0b" or "f59e0b")
|
|
308
|
+
* @returns Object with r, g, b values (0-255) or null if invalid
|
|
309
|
+
*/
|
|
310
|
+
export function hexToRgb(hex) {
|
|
311
|
+
const cleanHex = hex.replace(/^#/, "");
|
|
312
|
+
if (!/^[0-9A-Fa-f]{6}$/.test(cleanHex)) {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
const r = parseInt(cleanHex.substring(0, 2), 16);
|
|
316
|
+
const g = parseInt(cleanHex.substring(2, 4), 16);
|
|
317
|
+
const b = parseInt(cleanHex.substring(4, 6), 16);
|
|
318
|
+
return { r, g, b };
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Convert RGB components to hex color string
|
|
322
|
+
* @param r - Red component (0-255)
|
|
323
|
+
* @param g - Green component (0-255)
|
|
324
|
+
* @param b - Blue component (0-255)
|
|
325
|
+
* @returns Hex color string with # prefix
|
|
326
|
+
*/
|
|
327
|
+
export function rgbToHex(r, g, b) {
|
|
328
|
+
const toHex = (value) => {
|
|
329
|
+
const clamped = Math.max(0, Math.min(255, Math.round(value)));
|
|
330
|
+
return clamped.toString(16).padStart(2, "0");
|
|
331
|
+
};
|
|
332
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Generate a light tint of a color (similar to Tailwind's -50 shade)
|
|
336
|
+
* Creates a very light background-friendly version of the color
|
|
337
|
+
* @param hex - Base hex color string
|
|
338
|
+
* @returns Light tint hex color string
|
|
339
|
+
*/
|
|
340
|
+
export function getLightTint(hex) {
|
|
341
|
+
const rgb = hexToRgb(hex);
|
|
342
|
+
if (!rgb) {
|
|
343
|
+
return "#fffbeb"; // Fallback to amber-50
|
|
344
|
+
}
|
|
345
|
+
// Mix with white at 95% to create a very light tint
|
|
346
|
+
const mixRatio = 0.95;
|
|
347
|
+
const r = rgb.r + (255 - rgb.r) * mixRatio;
|
|
348
|
+
const g = rgb.g + (255 - rgb.g) * mixRatio;
|
|
349
|
+
const b = rgb.b + (255 - rgb.b) * mixRatio;
|
|
350
|
+
return rgbToHex(r, g, b);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Generate a border tint of a color (similar to Tailwind's -300 shade)
|
|
354
|
+
* Creates a medium-light version suitable for borders
|
|
355
|
+
* @param hex - Base hex color string
|
|
356
|
+
* @returns Border tint hex color string
|
|
357
|
+
*/
|
|
358
|
+
export function getBorderTint(hex) {
|
|
359
|
+
const rgb = hexToRgb(hex);
|
|
360
|
+
if (!rgb) {
|
|
361
|
+
return "#fcd34d"; // Fallback to amber-300
|
|
362
|
+
}
|
|
363
|
+
// Mix with white at 60% to create a medium-light tint
|
|
364
|
+
const mixRatio = 0.6;
|
|
365
|
+
const r = rgb.r + (255 - rgb.r) * mixRatio;
|
|
366
|
+
const g = rgb.g + (255 - rgb.g) * mixRatio;
|
|
367
|
+
const b = rgb.b + (255 - rgb.b) * mixRatio;
|
|
368
|
+
return rgbToHex(r, g, b);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Generate color variants for theming a component
|
|
372
|
+
* @param baseColor - Base hex color string
|
|
373
|
+
* @returns Object with base, light, and border color variants
|
|
374
|
+
*/
|
|
375
|
+
export function getColorVariants(baseColor) {
|
|
376
|
+
return {
|
|
377
|
+
base: baseColor,
|
|
378
|
+
light: getLightTint(baseColor),
|
|
379
|
+
border: getBorderTint(baseColor)
|
|
380
|
+
};
|
|
381
|
+
}
|