@foresthubai/workflow-builder 0.3.0 → 0.4.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/LICENSE +661 -661
- package/NOTICE +16 -16
- package/README.md +110 -93
- package/dist/components/ui/command.d.ts +2 -2
- package/dist/components/ui/input.d.ts +1 -1
- package/dist/components/ui/resizable.d.ts +1 -1
- package/dist/components/ui/textarea.d.ts +1 -1
- package/dist/graph/BaseNode.js +10 -10
- package/dist/graph/reactFlowRegistry.d.ts.map +1 -1
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +6 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/toolbars/CanvasTabsToolbar.d.ts +11 -0
- package/dist/toolbars/CanvasTabsToolbar.d.ts.map +1 -0
- package/dist/toolbars/CanvasTabsToolbar.js +101 -0
- package/dist/toolbars/CanvasTabsToolbar.js.map +1 -0
- package/package.json +2 -2
- package/src/BuilderLayout.tsx +345 -345
- package/src/Canvas.tsx +261 -261
- package/src/CanvasEditor.tsx +142 -142
- package/src/CanvasTabsToolbar.tsx +176 -176
- package/src/RightConfigPanel.tsx +266 -266
- package/src/WorkflowBuilder.tsx +412 -412
- package/src/cn.ts +6 -6
- package/src/components/ui/add-button.tsx +39 -39
- package/src/components/ui/alert-dialog.tsx +141 -141
- package/src/components/ui/alert.tsx +59 -59
- package/src/components/ui/badge.tsx +36 -36
- package/src/components/ui/button.tsx +85 -85
- package/src/components/ui/card.tsx +79 -79
- package/src/components/ui/checkbox.tsx +28 -28
- package/src/components/ui/collapsible.tsx +9 -9
- package/src/components/ui/command.tsx +153 -153
- package/src/components/ui/delete-button.tsx +23 -23
- package/src/components/ui/dialog.tsx +125 -125
- package/src/components/ui/dropdown-menu.tsx +198 -198
- package/src/components/ui/input.tsx +55 -55
- package/src/components/ui/label.tsx +24 -24
- package/src/components/ui/readonly-banner.tsx +15 -15
- package/src/components/ui/resizable.tsx +43 -43
- package/src/components/ui/scroll-area.tsx +102 -102
- package/src/components/ui/select.tsx +160 -160
- package/src/components/ui/separator.tsx +29 -29
- package/src/components/ui/switch.tsx +27 -27
- package/src/components/ui/textarea.tsx +51 -51
- package/src/components/ui/toast.tsx +127 -127
- package/src/components/ui/toaster.tsx +33 -33
- package/src/components/ui/toggle-group.tsx +59 -59
- package/src/components/ui/toggle.tsx +43 -43
- package/src/components/ui/tooltip.tsx +32 -32
- package/src/dialogs/NodePickerDialog.tsx +84 -84
- package/src/dialogs/ValidationDialog.tsx +184 -184
- package/src/graph/BaseNode.tsx +557 -557
- package/src/graph/CustomEdge.tsx +185 -185
- package/src/graph/CustomNode.tsx +16 -16
- package/src/graph/FunctionCallNode.tsx +30 -30
- package/src/graph/PortHandle.tsx +189 -189
- package/src/graph/reactFlowRegistry.ts +26 -26
- package/src/hooks/use-toast.ts +125 -125
- package/src/hooks/useAvailableVariables.ts +20 -20
- package/src/hooks/useCanvasHistory.ts +22 -22
- package/src/hooks/useCanvasTabs.ts +168 -168
- package/src/hooks/useFunctionDiagnosticsSync.ts +40 -40
- package/src/hooks/useFunctionRegistry.ts +26 -26
- package/src/hooks/useFunctions.ts +44 -44
- package/src/hooks/useGraph.ts +161 -161
- package/src/hooks/useNodeDefinitions.ts +82 -82
- package/src/hooks/useParamErrors.ts +26 -26
- package/src/hooks/useResolvedTheme.ts +30 -30
- package/src/hooks/useResourceDiagnosticsSync.ts +58 -58
- package/src/hooks/useSuppressThemeTransition.ts +79 -79
- package/src/hooks/useWorkflowSerialization.ts +127 -127
- package/src/i18n/index.ts +53 -53
- package/src/i18n/locales/de.json +501 -501
- package/src/i18n/locales/en.json +557 -557
- package/src/index.ts +27 -27
- package/src/inputs/ExpressionInput.tsx +297 -297
- package/src/inputs/ParameterEditor.tsx +515 -515
- package/src/inputs/PortSection.tsx +144 -144
- package/src/panels/BuilderSidebar.tsx +301 -301
- package/src/panels/ChannelConfigPanel.tsx +49 -49
- package/src/panels/ChannelsPanel.tsx +28 -28
- package/src/panels/DebugConsolePanel.tsx +73 -73
- package/src/panels/DebugContextPanel.tsx +77 -77
- package/src/panels/DebugExternalIOPanel.tsx +180 -180
- package/src/panels/DiagnosticsPanel.tsx +170 -170
- package/src/panels/EdgeConfigPanel.tsx +104 -104
- package/src/panels/FunctionConfigPanel.tsx +179 -179
- package/src/panels/FunctionListPanel.tsx +45 -45
- package/src/panels/MemoryConfigPanel.tsx +55 -55
- package/src/panels/MemoryPanel.tsx +40 -40
- package/src/panels/ModelConfigPanel.tsx +41 -41
- package/src/panels/ModelsPanel.tsx +36 -36
- package/src/panels/NodeConfigPanel.tsx +630 -630
- package/src/panels/NodeLibrary.tsx +288 -288
- package/src/panels/ResourceConfigPanel.tsx +132 -132
- package/src/panels/ResourceListPanel.tsx +113 -113
- package/src/panels/VariableConfigPanel.tsx +161 -161
- package/src/panels/VariablesPanel.tsx +145 -145
- package/src/stores/canvasStore.test.ts +44 -44
- package/src/stores/canvasStore.ts +245 -245
- package/src/stores/debugStore.ts +74 -74
- package/src/stores/diagnosticsStore.ts +130 -130
- package/src/stores/editorStore.ts +202 -202
- package/src/styles/index.css +526 -526
- package/src/utils/categoryConstants.ts +26 -26
- package/src/utils/channelOperations.ts +86 -86
- package/src/utils/connectionRules.ts +137 -137
- package/src/utils/functionOperations.ts +179 -179
- package/src/utils/graphOperations.ts +550 -550
- package/src/utils/history.ts +207 -207
- package/src/utils/memoryOperations.ts +57 -57
- package/src/utils/migrateFunctionNodes.ts +107 -107
- package/src/utils/modelOperations.ts +55 -55
- package/src/utils/paramDisplay.ts +71 -71
- package/src/utils/resourceHelpers.ts +32 -32
- package/src/utils/translation.ts +28 -28
- package/src/utils/variableOperations.ts +75 -75
- package/tailwind-preset.ts +166 -166
package/src/styles/index.css
CHANGED
|
@@ -1,526 +1,526 @@
|
|
|
1
|
-
/* ReactFlow's required CSS — without this, nodes can't be dragged/selected and
|
|
2
|
-
the canvas chrome (controls, minimap, viewport transforms) renders unstyled. */
|
|
3
|
-
@import "@xyflow/react/dist/style.css";
|
|
4
|
-
|
|
5
|
-
@tailwind base;
|
|
6
|
-
@tailwind components;
|
|
7
|
-
@tailwind utilities;
|
|
8
|
-
|
|
9
|
-
/* Color-mode switch must snap, not fade. useSuppressThemeTransition adds
|
|
10
|
-
`theme-changing` while the embedder flips the `light` class on <html> and
|
|
11
|
-
removes it once React has committed the new colorMode, killing every
|
|
12
|
-
color/background/border transition in between (canvas tabs, the builder
|
|
13
|
-
sidebar, ReactFlow's controls and node chrome) so they change in lockstep
|
|
14
|
-
with the rest of the UI instead of animating to the new tokens. */
|
|
15
|
-
.theme-changing,
|
|
16
|
-
.theme-changing *,
|
|
17
|
-
.theme-changing *::before,
|
|
18
|
-
.theme-changing *::after {
|
|
19
|
-
transition: none !important;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/* Definition of the design system. All colors, gradients, fonts, etc should be defined here.
|
|
23
|
-
All colors MUST be HSL.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
@layer base {
|
|
27
|
-
/*
|
|
28
|
-
* Token system: two layers
|
|
29
|
-
*
|
|
30
|
-
* 1. SURFACES (independent per mode) — background, card, popover, border, etc.
|
|
31
|
-
* These are *materials*: white card vs dark card aren't the same hue shifted,
|
|
32
|
-
* they're different identities. Defined separately in :root and .light.
|
|
33
|
-
*
|
|
34
|
-
* 2. SIGNALS (canonical hue, per-mode lightness) — node categories, channel
|
|
35
|
-
* types, badge severity. These are *identity markers*:
|
|
36
|
-
* "logic" should be recognizably the same green in both modes. Hue/sat
|
|
37
|
-
* stay fixed; only --signal-l changes per mode.
|
|
38
|
-
*
|
|
39
|
-
* Consumers using opacity (hsl(var(--node-X) / 0.3)) automatically tint
|
|
40
|
-
* toward the surface behind them, so the same canonical color reads well
|
|
41
|
-
* on both dark and light surfaces.
|
|
42
|
-
*/
|
|
43
|
-
:root {
|
|
44
|
-
/* ════════════════════════════════════════════════════════════
|
|
45
|
-
* GENERAL UI — surfaces, text, controls. (DARK MODE = default)
|
|
46
|
-
*
|
|
47
|
-
* These are the colors an embedding app SHARES with the builder:
|
|
48
|
-
* buttons, panels, inputs, menus, status. A host that reuses this
|
|
49
|
-
* preset reuses everything in this block. Hue 40, saturation ~2%:
|
|
50
|
-
* a faint warm gray, premium and nearly neutral.
|
|
51
|
-
* (.light overrides these values further down.)
|
|
52
|
-
* ════════════════════════════════════════════════════════════ */
|
|
53
|
-
|
|
54
|
-
/* App shell / page background, and the default text drawn on it. */
|
|
55
|
-
--background: 40 2% 8%;
|
|
56
|
-
--foreground: 0 0% 95%;
|
|
57
|
-
|
|
58
|
-
/* Card surface — builder panels, list rows, AND node bodies. Matches
|
|
59
|
-
--sidebar-background and --panel-background so all chrome shares one
|
|
60
|
-
panel color. --card-foreground is text drawn on a card. */
|
|
61
|
-
--card: 40 2% 18%;
|
|
62
|
-
--card-foreground: 0 0% 95%;
|
|
63
|
-
|
|
64
|
-
/* Popover / dropdown / menu surface (lifted slightly above cards). */
|
|
65
|
-
--popover: 40 2% 22%;
|
|
66
|
-
--popover-foreground: 0 0% 95%;
|
|
67
|
-
|
|
68
|
-
/* PRIMARY = the vibrant brand green. Active text/icons (text-primary),
|
|
69
|
-
primary buttons, the focus ring. --primary-foreground is text ON it. */
|
|
70
|
-
--primary: 158 53% 42%;
|
|
71
|
-
--primary-foreground: 0 0% 100%;
|
|
72
|
-
--primary-glow: 158 53% 52%;
|
|
73
|
-
|
|
74
|
-
/* Secondary neutral surface — secondary buttons. */
|
|
75
|
-
--secondary: 40 2% 24%;
|
|
76
|
-
--secondary-foreground: 0 0% 95%;
|
|
77
|
-
|
|
78
|
-
/* MUTED = subtle neutral fill (hover backgrounds, bg-muted/50). Its
|
|
79
|
-
--muted-foreground is the canonical SUBTEXT color: port labels,
|
|
80
|
-
descriptions, "<arg>:" hints, and any secondary text. */
|
|
81
|
-
--muted: 40 2% 22%;
|
|
82
|
-
--muted-foreground: 0 0% 65%;
|
|
83
|
-
|
|
84
|
-
/* ACCENT = the muted/selection green. Fills selected list rows and
|
|
85
|
-
focused menu/command/select items (bg-accent). The calm "this is
|
|
86
|
-
selected" wash; vibrant interactions use --primary instead. */
|
|
87
|
-
--accent: 158 16% 22%;
|
|
88
|
-
--accent-foreground: 0 0% 95%;
|
|
89
|
-
|
|
90
|
-
/* DESTRUCTIVE = error red — delete buttons, error text/badges/borders. */
|
|
91
|
-
--destructive: 0 78% 58%;
|
|
92
|
-
--destructive-foreground: 0 0% 100%;
|
|
93
|
-
|
|
94
|
-
/* BORDER = every DOM border: panels, cards, separators, AND form-field
|
|
95
|
-
borders (the preset aliases border-input to this — one border color). */
|
|
96
|
-
--border: 40 2% 26%;
|
|
97
|
-
/* RING = focus highlight around inputs/buttons. */
|
|
98
|
-
--ring: 158 53% 42%;
|
|
99
|
-
/* OVERLAY = dialog/backdrop scrim. */
|
|
100
|
-
--overlay: 0 0% 0% / 0.8;
|
|
101
|
-
|
|
102
|
-
/* FIELD = form-input fill, darker than --card so inputs read as recessed
|
|
103
|
-
(--border draws their outline). */
|
|
104
|
-
--field: 40 2% 14%;
|
|
105
|
-
|
|
106
|
-
--radius: 0.5rem;
|
|
107
|
-
|
|
108
|
-
/* Status accents (semantic, full-saturation). */
|
|
109
|
-
--success: 158 53% 42%;
|
|
110
|
-
--success-foreground: 0 0% 100%;
|
|
111
|
-
--warning: 38 92% 50%;
|
|
112
|
-
--warning-foreground: 0 0% 100%;
|
|
113
|
-
|
|
114
|
-
/* Sidebar — app-shell chrome, shared with the host's AppSidebar. */
|
|
115
|
-
--sidebar-background: 40 2% 18%;
|
|
116
|
-
--sidebar-foreground: 0 0% 95%;
|
|
117
|
-
--sidebar-primary: 158 53% 42%;
|
|
118
|
-
--sidebar-primary-foreground: 0 0% 100%;
|
|
119
|
-
--sidebar-accent: 40 2% 24%;
|
|
120
|
-
--sidebar-accent-foreground: 0 0% 95%;
|
|
121
|
-
--sidebar-border: 40 2% 26%;
|
|
122
|
-
--sidebar-ring: 158 53% 42%;
|
|
123
|
-
|
|
124
|
-
/* Gradients — page background and glass components. */
|
|
125
|
-
--gradient-subtle: linear-gradient(135deg, hsl(40 2% 8%), hsl(40 2% 18%));
|
|
126
|
-
--gradient-glass: linear-gradient(135deg, var(--glass-bg-light), var(--glass-bg-medium));
|
|
127
|
-
|
|
128
|
-
/* Shadows — black at moderate alpha; in dark mode the eye can't see much
|
|
129
|
-
against near-black surfaces, so elevated states lean on the glow tokens. */
|
|
130
|
-
--shadow-sm: 0 2px 4px 0 hsl(0 0% 0% / 0.4);
|
|
131
|
-
--shadow-md: 0 4px 12px -2px hsl(0 0% 0% / 0.5);
|
|
132
|
-
--shadow-lg: 0 12px 24px -4px hsl(0 0% 0% / 0.6);
|
|
133
|
-
--shadow-glow: 0 0 20px hsl(158 53% 42% / 0.4);
|
|
134
|
-
|
|
135
|
-
/* ════════════════════════════════════════════════════════════
|
|
136
|
-
* BUILDER / GRAPH ONLY — canvas, edges, ports, node categories.
|
|
137
|
-
*
|
|
138
|
-
* Embedding apps do NOT use these; they're specific to the React
|
|
139
|
-
* Flow editing surface and are mostly consumed INLINE by the graph
|
|
140
|
-
* layer (CustomEdge / PortHandle / BaseNode), not via Tailwind classes.
|
|
141
|
-
* ════════════════════════════════════════════════════════════ */
|
|
142
|
-
|
|
143
|
-
/* Canvas = editing surface behind nodes (sits between --background and
|
|
144
|
-
--card for a subtle elevation). */
|
|
145
|
-
--canvas-background: 40 2% 14%;
|
|
146
|
-
|
|
147
|
-
/* Edge/connection color — ALSO the node OUTLINE color, so edges and node
|
|
148
|
-
borders share one graph-line color. */
|
|
149
|
-
--edge-default: 40 5% 58%;
|
|
150
|
-
|
|
151
|
-
/* Builder panel chrome (inspectors/sidebars inside the editor). */
|
|
152
|
-
--panel-background: 40 2% 18%;
|
|
153
|
-
--panel-border: 40 2% 26%;
|
|
154
|
-
|
|
155
|
-
/* Selection glow — uniform halo around selected nodes/edges, independent
|
|
156
|
-
of category color so multi-selection stays calm. */
|
|
157
|
-
--selection-glow: 0 0% 100%;
|
|
158
|
-
|
|
159
|
-
/* Drop shadow cast under nodes. */
|
|
160
|
-
--node-shadow: 40 2% 5%;
|
|
161
|
-
|
|
162
|
-
/* SIGNAL TUNING — node category hues are fixed; only saturation and
|
|
163
|
-
lightness shift per mode (see .light). */
|
|
164
|
-
--signal-s: 70%; /* signal saturation */
|
|
165
|
-
--signal-l: 58%; /* signal lightness (dark mode) */
|
|
166
|
-
|
|
167
|
-
/* NODE CATEGORY SIGNALS — one identity color per node type. */
|
|
168
|
-
--node-agent: 273 var(--signal-s) var(--signal-l);
|
|
169
|
-
--node-input: 195 var(--signal-s) var(--signal-l);
|
|
170
|
-
--node-output: 142 var(--signal-s) var(--signal-l);
|
|
171
|
-
--node-trigger: 32 88% var(--signal-l);
|
|
172
|
-
--node-logic: 175 var(--signal-s) var(--signal-l);
|
|
173
|
-
--node-data: 42 85% var(--signal-l);
|
|
174
|
-
--node-tool: 200 80% var(--signal-l);
|
|
175
|
-
--node-function: 320 var(--signal-s) var(--signal-l);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.light {
|
|
179
|
-
/* ═══ GENERAL UI (light overrides — a different material, not a shift) ═══ */
|
|
180
|
-
--background: 220 14% 96%;
|
|
181
|
-
--foreground: 220 15% 15%;
|
|
182
|
-
--card: 0 0% 100%;
|
|
183
|
-
--card-foreground: 220 15% 15%;
|
|
184
|
-
--popover: 0 0% 100%;
|
|
185
|
-
--popover-foreground: 220 15% 15%;
|
|
186
|
-
--primary: 158 53% 38%;
|
|
187
|
-
--primary-foreground: 0 0% 100%;
|
|
188
|
-
--primary-glow: 158 53% 48%;
|
|
189
|
-
--secondary: 220 12% 92%;
|
|
190
|
-
--secondary-foreground: 220 15% 15%;
|
|
191
|
-
--muted: 220 12% 94%;
|
|
192
|
-
--muted-foreground: 220 8% 46%;
|
|
193
|
-
--accent: 158 40% 93%;
|
|
194
|
-
--accent-foreground: 220 15% 15%;
|
|
195
|
-
--destructive: 0 72% 45%;
|
|
196
|
-
--destructive-foreground: 0 0% 100%;
|
|
197
|
-
--border: 220 13% 88%;
|
|
198
|
-
--ring: 158 53% 42%;
|
|
199
|
-
--overlay: 0 0% 0% / 0.5;
|
|
200
|
-
/* Field fill — clearly darker than the white card so inputs read recessed. */
|
|
201
|
-
--field: 220 14% 92%;
|
|
202
|
-
--success: 158 53% 38%;
|
|
203
|
-
--success-foreground: 0 0% 100%;
|
|
204
|
-
--warning: 32 92% 42%;
|
|
205
|
-
--warning-foreground: 0 0% 100%;
|
|
206
|
-
--sidebar-background: 220 14% 98%;
|
|
207
|
-
--sidebar-foreground: 220 15% 15%;
|
|
208
|
-
--sidebar-primary: 158 53% 38%;
|
|
209
|
-
--sidebar-primary-foreground: 0 0% 100%;
|
|
210
|
-
--sidebar-accent: 220 12% 94%;
|
|
211
|
-
--sidebar-accent-foreground: 220 15% 15%;
|
|
212
|
-
--sidebar-border: 220 13% 88%;
|
|
213
|
-
--sidebar-ring: 158 53% 38%;
|
|
214
|
-
/* Shadows — dark ink on light surfaces. Alpha kept high enough that cards
|
|
215
|
-
read with clear elevation (matching dark mode's 0.4-alpha prominence),
|
|
216
|
-
while staying soft so they don't smudge on white. */
|
|
217
|
-
--shadow-sm: 0 1px 3px 0 hsl(220 15% 25% / 0.16), 0 2px 6px -1px hsl(220 15% 25% / 0.12);
|
|
218
|
-
--shadow-md: 0 4px 8px -1px hsl(220 15% 25% / 0.18), 0 8px 16px -2px hsl(220 15% 25% / 0.14);
|
|
219
|
-
--shadow-lg: 0 4px 8px -2px hsl(220 15% 25% / 0.12), 0 12px 24px -4px hsl(220 15% 25% / 0.18);
|
|
220
|
-
--shadow-glow: 0 0 24px hsl(158 53% 42% / 0.25);
|
|
221
|
-
|
|
222
|
-
/* ═══ BUILDER / GRAPH ONLY (light overrides) ═══ */
|
|
223
|
-
/* Canvas sits deeper than the app shell so the editing surface is
|
|
224
|
-
clearly distinct from chrome. */
|
|
225
|
-
--canvas-background: 220 14% 92%;
|
|
226
|
-
--edge-default: 220 8% 45%;
|
|
227
|
-
--panel-background: 0 0% 100%;
|
|
228
|
-
--panel-border: 220 13% 88%;
|
|
229
|
-
/* Selection glow — dark in light mode for high contrast on white. */
|
|
230
|
-
--selection-glow: 220 15% 15%;
|
|
231
|
-
/* Same node hues as dark; only saturation/lightness drop for legibility. */
|
|
232
|
-
--signal-s: 68%;
|
|
233
|
-
--signal-l: 42%;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
@layer base {
|
|
238
|
-
* {
|
|
239
|
-
@apply border-border;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/* Base look is scoped to the builder's own root — NOT <body>. The host owns
|
|
243
|
-
page chrome (background, page font, overscroll); the builder only dresses
|
|
244
|
-
itself. font-sans (Poppins) is inherited from the .fh-builder root;
|
|
245
|
-
headings get the Inter display face, scoped so it can't restyle host pages. */
|
|
246
|
-
.fh-builder :is(h1, h2, h3, h4, h5, h6) {
|
|
247
|
-
font-family: Inter, system-ui, sans-serif;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/* Glass Forest Design System */
|
|
252
|
-
@layer components {
|
|
253
|
-
/* Core Glass Components - Verstärkte Glass-Effekte */
|
|
254
|
-
.glass-forest-card {
|
|
255
|
-
@apply bg-card/60 backdrop-blur-xl border border-white/10 rounded-2xl shadow-lg transition-all duration-300;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
.glass-forest-card:hover {
|
|
259
|
-
@apply bg-card/70 shadow-xl scale-[1.02] border-primary/20;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
.glass-forest-panel {
|
|
263
|
-
@apply bg-card/70 backdrop-blur-2xl border border-white/10 shadow-xl;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
.glass-forest-button {
|
|
267
|
-
@apply bg-card/40 backdrop-blur-md border border-border rounded-full transition-all duration-300;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
.glass-forest-button:hover {
|
|
271
|
-
@apply bg-card/60 border-primary/30 shadow-lg -translate-y-0.5;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
.glass-forest-button-primary {
|
|
275
|
-
@apply bg-primary text-primary-foreground rounded-full shadow-sm border-0;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
.glass-forest-button-primary:hover {
|
|
279
|
-
@apply shadow-xl scale-[1.02] -translate-y-0.5;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
.glass-forest-input {
|
|
283
|
-
@apply bg-card/40 backdrop-blur-lg border border-border rounded-2xl transition-all duration-300;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
.glass-forest-input:focus {
|
|
287
|
-
@apply bg-card/60 border-primary outline-none ring-2 ring-primary/20;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/* Organic Hover Effects */
|
|
291
|
-
.hover-glow {
|
|
292
|
-
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
.hover-glow:hover {
|
|
296
|
-
box-shadow: var(--glow-green);
|
|
297
|
-
transform: translateY(-2px);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
.hover-lift {
|
|
301
|
-
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
.hover-lift:hover {
|
|
305
|
-
transform: translateY(-4px) scale(1.02);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/* Workflow Builder Glass Styles - Mehr Transparenz */
|
|
309
|
-
.workflow-builder-panel {
|
|
310
|
-
@apply bg-card/70 backdrop-blur-2xl border border-white/10 shadow-xl;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
.block-card {
|
|
314
|
-
@apply bg-card/60 backdrop-blur-xl border border-white/10 rounded-2xl shadow-lg cursor-pointer transition-all duration-300;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
.block-card:hover {
|
|
318
|
-
@apply bg-card/70 shadow-xl scale-[1.02];
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
.block-node-glass {
|
|
322
|
-
@apply bg-card/70 backdrop-blur-xl rounded-2xl border border-white/10 shadow-xl transition-all duration-300;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
.block-node-glass:hover {
|
|
326
|
-
@apply shadow-2xl scale-[1.02] bg-card/80;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/* Loading & Status */
|
|
330
|
-
.loading-organic {
|
|
331
|
-
@apply animate-pulse-organic rounded-full bg-primary/20;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
.status-dot {
|
|
335
|
-
@apply w-2 h-2 rounded-full animate-pulse-organic;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
.status-success .status-dot {
|
|
339
|
-
@apply bg-success;
|
|
340
|
-
box-shadow: var(--glow-green);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
.status-warning .status-dot {
|
|
344
|
-
@apply bg-warning;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
@layer utilities {
|
|
349
|
-
/* Organic Animations */
|
|
350
|
-
@keyframes pulse-organic {
|
|
351
|
-
0%,
|
|
352
|
-
100% {
|
|
353
|
-
opacity: 1;
|
|
354
|
-
transform: scale(1);
|
|
355
|
-
}
|
|
356
|
-
50% {
|
|
357
|
-
opacity: 0.8;
|
|
358
|
-
transform: scale(1.05);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
@keyframes ripple-expand {
|
|
363
|
-
0% {
|
|
364
|
-
transform: scale(0.8);
|
|
365
|
-
opacity: 0;
|
|
366
|
-
}
|
|
367
|
-
50% {
|
|
368
|
-
opacity: 0.6;
|
|
369
|
-
}
|
|
370
|
-
100% {
|
|
371
|
-
transform: scale(2);
|
|
372
|
-
opacity: 0;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
@keyframes light-trail {
|
|
377
|
-
0% {
|
|
378
|
-
opacity: 0;
|
|
379
|
-
transform: translateY(0);
|
|
380
|
-
}
|
|
381
|
-
50% {
|
|
382
|
-
opacity: 1;
|
|
383
|
-
}
|
|
384
|
-
100% {
|
|
385
|
-
opacity: 0;
|
|
386
|
-
transform: translateY(-20px);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
@keyframes fade-in {
|
|
391
|
-
from {
|
|
392
|
-
opacity: 0;
|
|
393
|
-
transform: translateY(10px);
|
|
394
|
-
}
|
|
395
|
-
to {
|
|
396
|
-
opacity: 1;
|
|
397
|
-
transform: translateY(0);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
@keyframes glow-pulse {
|
|
402
|
-
0%,
|
|
403
|
-
100% {
|
|
404
|
-
box-shadow: var(--glow-green);
|
|
405
|
-
}
|
|
406
|
-
50% {
|
|
407
|
-
box-shadow: var(--glow-combined);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/* Animation Classes */
|
|
412
|
-
.animate-pulse-organic {
|
|
413
|
-
animation: pulse-organic 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
.animate-ripple {
|
|
417
|
-
animation: ripple-expand 1.5s ease-out;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
.animate-glow-pulse {
|
|
421
|
-
animation: glow-pulse 2s ease-in-out infinite;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
.animate-fade-in {
|
|
425
|
-
animation: fade-in 0.3s ease-out;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/* Line clamp utilities */
|
|
429
|
-
.line-clamp-1 {
|
|
430
|
-
overflow: hidden;
|
|
431
|
-
display: -webkit-box;
|
|
432
|
-
-webkit-box-orient: vertical;
|
|
433
|
-
-webkit-line-clamp: 1;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
.line-clamp-2 {
|
|
437
|
-
overflow: hidden;
|
|
438
|
-
display: -webkit-box;
|
|
439
|
-
-webkit-box-orient: vertical;
|
|
440
|
-
-webkit-line-clamp: 2;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
.line-clamp-3 {
|
|
444
|
-
overflow: hidden;
|
|
445
|
-
display: -webkit-box;
|
|
446
|
-
-webkit-box-orient: vertical;
|
|
447
|
-
-webkit-line-clamp: 3;
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/* ════════════════════════════════════════════════════════════
|
|
452
|
-
* Themed thin scrollbars — uniform across every scrollable region
|
|
453
|
-
* inside the builder (sidebar, right panel, tabs toolbar, dropdowns,
|
|
454
|
-
* dialogs, debug console).
|
|
455
|
-
*
|
|
456
|
-
* Two scopes, both opt-in:
|
|
457
|
-
* - `.fh-builder` covers everything rendered inside the
|
|
458
|
-
* builder DOM subtree.
|
|
459
|
-
* - `.fh-builder-portal` covers Radix Content nodes that portal to
|
|
460
|
-
* <body> (DropdownMenu, Dialog, AlertDialog, Select, Tooltip), so
|
|
461
|
-
* they don't drop back to the host's native scrollbar just because
|
|
462
|
-
* they live outside the builder root in the DOM. Same marker used
|
|
463
|
-
* to pin `font-sans` on those nodes.
|
|
464
|
-
*
|
|
465
|
-
* Host pages are never touched: every rule is anchored on one of these
|
|
466
|
-
* two classes; no `body`/`html`/universal selector escapes them. Thumb
|
|
467
|
-
* uses --muted-foreground at low opacity so it reads as a faint hint of
|
|
468
|
-
* the subtext color on both card and popover surfaces, in both modes.
|
|
469
|
-
*
|
|
470
|
-
* Width 6px: thin enough that the 6px reflow when it appears is barely
|
|
471
|
-
* perceptible, while still big enough to grab. We deliberately don't
|
|
472
|
-
* use `scrollbar-gutter: stable` (which would reserve the gutter even
|
|
473
|
-
* when nothing overflows) — most panels never need a scrollbar, and
|
|
474
|
-
* the permanent gap looks worse than the rare reflow.
|
|
475
|
-
* ════════════════════════════════════════════════════════════ */
|
|
476
|
-
.fh-builder,
|
|
477
|
-
.fh-builder *,
|
|
478
|
-
.fh-builder-portal,
|
|
479
|
-
.fh-builder-portal * {
|
|
480
|
-
scrollbar-width: thin;
|
|
481
|
-
scrollbar-color: hsl(var(--muted-foreground) / 0.35) transparent;
|
|
482
|
-
}
|
|
483
|
-
.fh-builder ::-webkit-scrollbar,
|
|
484
|
-
.fh-builder-portal::-webkit-scrollbar,
|
|
485
|
-
.fh-builder-portal ::-webkit-scrollbar {
|
|
486
|
-
width: 6px;
|
|
487
|
-
height: 6px;
|
|
488
|
-
}
|
|
489
|
-
.fh-builder ::-webkit-scrollbar-track,
|
|
490
|
-
.fh-builder-portal::-webkit-scrollbar-track,
|
|
491
|
-
.fh-builder-portal ::-webkit-scrollbar-track {
|
|
492
|
-
background: transparent;
|
|
493
|
-
}
|
|
494
|
-
.fh-builder ::-webkit-scrollbar-thumb,
|
|
495
|
-
.fh-builder-portal::-webkit-scrollbar-thumb,
|
|
496
|
-
.fh-builder-portal ::-webkit-scrollbar-thumb {
|
|
497
|
-
background-color: hsl(var(--muted-foreground) / 0.3);
|
|
498
|
-
border-radius: 9999px;
|
|
499
|
-
}
|
|
500
|
-
.fh-builder ::-webkit-scrollbar-thumb:hover,
|
|
501
|
-
.fh-builder-portal::-webkit-scrollbar-thumb:hover,
|
|
502
|
-
.fh-builder-portal ::-webkit-scrollbar-thumb:hover {
|
|
503
|
-
background-color: hsl(var(--muted-foreground) / 0.55);
|
|
504
|
-
}
|
|
505
|
-
.fh-builder ::-webkit-scrollbar-corner,
|
|
506
|
-
.fh-builder-portal::-webkit-scrollbar-corner,
|
|
507
|
-
.fh-builder-portal ::-webkit-scrollbar-corner {
|
|
508
|
-
background: transparent;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
/* Suppress ReactFlow's built-in selection outline — we use custom glow via editorStore */
|
|
512
|
-
.react-flow__node.selected,
|
|
513
|
-
.react-flow__edge.selected {
|
|
514
|
-
outline: none !important;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/* Debug cursor pulse animation for node highlighting */
|
|
518
|
-
@keyframes debug-cursor-pulse {
|
|
519
|
-
0%,
|
|
520
|
-
100% {
|
|
521
|
-
opacity: 1;
|
|
522
|
-
}
|
|
523
|
-
50% {
|
|
524
|
-
opacity: 0.6;
|
|
525
|
-
}
|
|
526
|
-
}
|
|
1
|
+
/* ReactFlow's required CSS — without this, nodes can't be dragged/selected and
|
|
2
|
+
the canvas chrome (controls, minimap, viewport transforms) renders unstyled. */
|
|
3
|
+
@import "@xyflow/react/dist/style.css";
|
|
4
|
+
|
|
5
|
+
@tailwind base;
|
|
6
|
+
@tailwind components;
|
|
7
|
+
@tailwind utilities;
|
|
8
|
+
|
|
9
|
+
/* Color-mode switch must snap, not fade. useSuppressThemeTransition adds
|
|
10
|
+
`theme-changing` while the embedder flips the `light` class on <html> and
|
|
11
|
+
removes it once React has committed the new colorMode, killing every
|
|
12
|
+
color/background/border transition in between (canvas tabs, the builder
|
|
13
|
+
sidebar, ReactFlow's controls and node chrome) so they change in lockstep
|
|
14
|
+
with the rest of the UI instead of animating to the new tokens. */
|
|
15
|
+
.theme-changing,
|
|
16
|
+
.theme-changing *,
|
|
17
|
+
.theme-changing *::before,
|
|
18
|
+
.theme-changing *::after {
|
|
19
|
+
transition: none !important;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Definition of the design system. All colors, gradients, fonts, etc should be defined here.
|
|
23
|
+
All colors MUST be HSL.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
@layer base {
|
|
27
|
+
/*
|
|
28
|
+
* Token system: two layers
|
|
29
|
+
*
|
|
30
|
+
* 1. SURFACES (independent per mode) — background, card, popover, border, etc.
|
|
31
|
+
* These are *materials*: white card vs dark card aren't the same hue shifted,
|
|
32
|
+
* they're different identities. Defined separately in :root and .light.
|
|
33
|
+
*
|
|
34
|
+
* 2. SIGNALS (canonical hue, per-mode lightness) — node categories, channel
|
|
35
|
+
* types, badge severity. These are *identity markers*:
|
|
36
|
+
* "logic" should be recognizably the same green in both modes. Hue/sat
|
|
37
|
+
* stay fixed; only --signal-l changes per mode.
|
|
38
|
+
*
|
|
39
|
+
* Consumers using opacity (hsl(var(--node-X) / 0.3)) automatically tint
|
|
40
|
+
* toward the surface behind them, so the same canonical color reads well
|
|
41
|
+
* on both dark and light surfaces.
|
|
42
|
+
*/
|
|
43
|
+
:root {
|
|
44
|
+
/* ════════════════════════════════════════════════════════════
|
|
45
|
+
* GENERAL UI — surfaces, text, controls. (DARK MODE = default)
|
|
46
|
+
*
|
|
47
|
+
* These are the colors an embedding app SHARES with the builder:
|
|
48
|
+
* buttons, panels, inputs, menus, status. A host that reuses this
|
|
49
|
+
* preset reuses everything in this block. Hue 40, saturation ~2%:
|
|
50
|
+
* a faint warm gray, premium and nearly neutral.
|
|
51
|
+
* (.light overrides these values further down.)
|
|
52
|
+
* ════════════════════════════════════════════════════════════ */
|
|
53
|
+
|
|
54
|
+
/* App shell / page background, and the default text drawn on it. */
|
|
55
|
+
--background: 40 2% 8%;
|
|
56
|
+
--foreground: 0 0% 95%;
|
|
57
|
+
|
|
58
|
+
/* Card surface — builder panels, list rows, AND node bodies. Matches
|
|
59
|
+
--sidebar-background and --panel-background so all chrome shares one
|
|
60
|
+
panel color. --card-foreground is text drawn on a card. */
|
|
61
|
+
--card: 40 2% 18%;
|
|
62
|
+
--card-foreground: 0 0% 95%;
|
|
63
|
+
|
|
64
|
+
/* Popover / dropdown / menu surface (lifted slightly above cards). */
|
|
65
|
+
--popover: 40 2% 22%;
|
|
66
|
+
--popover-foreground: 0 0% 95%;
|
|
67
|
+
|
|
68
|
+
/* PRIMARY = the vibrant brand green. Active text/icons (text-primary),
|
|
69
|
+
primary buttons, the focus ring. --primary-foreground is text ON it. */
|
|
70
|
+
--primary: 158 53% 42%;
|
|
71
|
+
--primary-foreground: 0 0% 100%;
|
|
72
|
+
--primary-glow: 158 53% 52%;
|
|
73
|
+
|
|
74
|
+
/* Secondary neutral surface — secondary buttons. */
|
|
75
|
+
--secondary: 40 2% 24%;
|
|
76
|
+
--secondary-foreground: 0 0% 95%;
|
|
77
|
+
|
|
78
|
+
/* MUTED = subtle neutral fill (hover backgrounds, bg-muted/50). Its
|
|
79
|
+
--muted-foreground is the canonical SUBTEXT color: port labels,
|
|
80
|
+
descriptions, "<arg>:" hints, and any secondary text. */
|
|
81
|
+
--muted: 40 2% 22%;
|
|
82
|
+
--muted-foreground: 0 0% 65%;
|
|
83
|
+
|
|
84
|
+
/* ACCENT = the muted/selection green. Fills selected list rows and
|
|
85
|
+
focused menu/command/select items (bg-accent). The calm "this is
|
|
86
|
+
selected" wash; vibrant interactions use --primary instead. */
|
|
87
|
+
--accent: 158 16% 22%;
|
|
88
|
+
--accent-foreground: 0 0% 95%;
|
|
89
|
+
|
|
90
|
+
/* DESTRUCTIVE = error red — delete buttons, error text/badges/borders. */
|
|
91
|
+
--destructive: 0 78% 58%;
|
|
92
|
+
--destructive-foreground: 0 0% 100%;
|
|
93
|
+
|
|
94
|
+
/* BORDER = every DOM border: panels, cards, separators, AND form-field
|
|
95
|
+
borders (the preset aliases border-input to this — one border color). */
|
|
96
|
+
--border: 40 2% 26%;
|
|
97
|
+
/* RING = focus highlight around inputs/buttons. */
|
|
98
|
+
--ring: 158 53% 42%;
|
|
99
|
+
/* OVERLAY = dialog/backdrop scrim. */
|
|
100
|
+
--overlay: 0 0% 0% / 0.8;
|
|
101
|
+
|
|
102
|
+
/* FIELD = form-input fill, darker than --card so inputs read as recessed
|
|
103
|
+
(--border draws their outline). */
|
|
104
|
+
--field: 40 2% 14%;
|
|
105
|
+
|
|
106
|
+
--radius: 0.5rem;
|
|
107
|
+
|
|
108
|
+
/* Status accents (semantic, full-saturation). */
|
|
109
|
+
--success: 158 53% 42%;
|
|
110
|
+
--success-foreground: 0 0% 100%;
|
|
111
|
+
--warning: 38 92% 50%;
|
|
112
|
+
--warning-foreground: 0 0% 100%;
|
|
113
|
+
|
|
114
|
+
/* Sidebar — app-shell chrome, shared with the host's AppSidebar. */
|
|
115
|
+
--sidebar-background: 40 2% 18%;
|
|
116
|
+
--sidebar-foreground: 0 0% 95%;
|
|
117
|
+
--sidebar-primary: 158 53% 42%;
|
|
118
|
+
--sidebar-primary-foreground: 0 0% 100%;
|
|
119
|
+
--sidebar-accent: 40 2% 24%;
|
|
120
|
+
--sidebar-accent-foreground: 0 0% 95%;
|
|
121
|
+
--sidebar-border: 40 2% 26%;
|
|
122
|
+
--sidebar-ring: 158 53% 42%;
|
|
123
|
+
|
|
124
|
+
/* Gradients — page background and glass components. */
|
|
125
|
+
--gradient-subtle: linear-gradient(135deg, hsl(40 2% 8%), hsl(40 2% 18%));
|
|
126
|
+
--gradient-glass: linear-gradient(135deg, var(--glass-bg-light), var(--glass-bg-medium));
|
|
127
|
+
|
|
128
|
+
/* Shadows — black at moderate alpha; in dark mode the eye can't see much
|
|
129
|
+
against near-black surfaces, so elevated states lean on the glow tokens. */
|
|
130
|
+
--shadow-sm: 0 2px 4px 0 hsl(0 0% 0% / 0.4);
|
|
131
|
+
--shadow-md: 0 4px 12px -2px hsl(0 0% 0% / 0.5);
|
|
132
|
+
--shadow-lg: 0 12px 24px -4px hsl(0 0% 0% / 0.6);
|
|
133
|
+
--shadow-glow: 0 0 20px hsl(158 53% 42% / 0.4);
|
|
134
|
+
|
|
135
|
+
/* ════════════════════════════════════════════════════════════
|
|
136
|
+
* BUILDER / GRAPH ONLY — canvas, edges, ports, node categories.
|
|
137
|
+
*
|
|
138
|
+
* Embedding apps do NOT use these; they're specific to the React
|
|
139
|
+
* Flow editing surface and are mostly consumed INLINE by the graph
|
|
140
|
+
* layer (CustomEdge / PortHandle / BaseNode), not via Tailwind classes.
|
|
141
|
+
* ════════════════════════════════════════════════════════════ */
|
|
142
|
+
|
|
143
|
+
/* Canvas = editing surface behind nodes (sits between --background and
|
|
144
|
+
--card for a subtle elevation). */
|
|
145
|
+
--canvas-background: 40 2% 14%;
|
|
146
|
+
|
|
147
|
+
/* Edge/connection color — ALSO the node OUTLINE color, so edges and node
|
|
148
|
+
borders share one graph-line color. */
|
|
149
|
+
--edge-default: 40 5% 58%;
|
|
150
|
+
|
|
151
|
+
/* Builder panel chrome (inspectors/sidebars inside the editor). */
|
|
152
|
+
--panel-background: 40 2% 18%;
|
|
153
|
+
--panel-border: 40 2% 26%;
|
|
154
|
+
|
|
155
|
+
/* Selection glow — uniform halo around selected nodes/edges, independent
|
|
156
|
+
of category color so multi-selection stays calm. */
|
|
157
|
+
--selection-glow: 0 0% 100%;
|
|
158
|
+
|
|
159
|
+
/* Drop shadow cast under nodes. */
|
|
160
|
+
--node-shadow: 40 2% 5%;
|
|
161
|
+
|
|
162
|
+
/* SIGNAL TUNING — node category hues are fixed; only saturation and
|
|
163
|
+
lightness shift per mode (see .light). */
|
|
164
|
+
--signal-s: 70%; /* signal saturation */
|
|
165
|
+
--signal-l: 58%; /* signal lightness (dark mode) */
|
|
166
|
+
|
|
167
|
+
/* NODE CATEGORY SIGNALS — one identity color per node type. */
|
|
168
|
+
--node-agent: 273 var(--signal-s) var(--signal-l);
|
|
169
|
+
--node-input: 195 var(--signal-s) var(--signal-l);
|
|
170
|
+
--node-output: 142 var(--signal-s) var(--signal-l);
|
|
171
|
+
--node-trigger: 32 88% var(--signal-l);
|
|
172
|
+
--node-logic: 175 var(--signal-s) var(--signal-l);
|
|
173
|
+
--node-data: 42 85% var(--signal-l);
|
|
174
|
+
--node-tool: 200 80% var(--signal-l);
|
|
175
|
+
--node-function: 320 var(--signal-s) var(--signal-l);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.light {
|
|
179
|
+
/* ═══ GENERAL UI (light overrides — a different material, not a shift) ═══ */
|
|
180
|
+
--background: 220 14% 96%;
|
|
181
|
+
--foreground: 220 15% 15%;
|
|
182
|
+
--card: 0 0% 100%;
|
|
183
|
+
--card-foreground: 220 15% 15%;
|
|
184
|
+
--popover: 0 0% 100%;
|
|
185
|
+
--popover-foreground: 220 15% 15%;
|
|
186
|
+
--primary: 158 53% 38%;
|
|
187
|
+
--primary-foreground: 0 0% 100%;
|
|
188
|
+
--primary-glow: 158 53% 48%;
|
|
189
|
+
--secondary: 220 12% 92%;
|
|
190
|
+
--secondary-foreground: 220 15% 15%;
|
|
191
|
+
--muted: 220 12% 94%;
|
|
192
|
+
--muted-foreground: 220 8% 46%;
|
|
193
|
+
--accent: 158 40% 93%;
|
|
194
|
+
--accent-foreground: 220 15% 15%;
|
|
195
|
+
--destructive: 0 72% 45%;
|
|
196
|
+
--destructive-foreground: 0 0% 100%;
|
|
197
|
+
--border: 220 13% 88%;
|
|
198
|
+
--ring: 158 53% 42%;
|
|
199
|
+
--overlay: 0 0% 0% / 0.5;
|
|
200
|
+
/* Field fill — clearly darker than the white card so inputs read recessed. */
|
|
201
|
+
--field: 220 14% 92%;
|
|
202
|
+
--success: 158 53% 38%;
|
|
203
|
+
--success-foreground: 0 0% 100%;
|
|
204
|
+
--warning: 32 92% 42%;
|
|
205
|
+
--warning-foreground: 0 0% 100%;
|
|
206
|
+
--sidebar-background: 220 14% 98%;
|
|
207
|
+
--sidebar-foreground: 220 15% 15%;
|
|
208
|
+
--sidebar-primary: 158 53% 38%;
|
|
209
|
+
--sidebar-primary-foreground: 0 0% 100%;
|
|
210
|
+
--sidebar-accent: 220 12% 94%;
|
|
211
|
+
--sidebar-accent-foreground: 220 15% 15%;
|
|
212
|
+
--sidebar-border: 220 13% 88%;
|
|
213
|
+
--sidebar-ring: 158 53% 38%;
|
|
214
|
+
/* Shadows — dark ink on light surfaces. Alpha kept high enough that cards
|
|
215
|
+
read with clear elevation (matching dark mode's 0.4-alpha prominence),
|
|
216
|
+
while staying soft so they don't smudge on white. */
|
|
217
|
+
--shadow-sm: 0 1px 3px 0 hsl(220 15% 25% / 0.16), 0 2px 6px -1px hsl(220 15% 25% / 0.12);
|
|
218
|
+
--shadow-md: 0 4px 8px -1px hsl(220 15% 25% / 0.18), 0 8px 16px -2px hsl(220 15% 25% / 0.14);
|
|
219
|
+
--shadow-lg: 0 4px 8px -2px hsl(220 15% 25% / 0.12), 0 12px 24px -4px hsl(220 15% 25% / 0.18);
|
|
220
|
+
--shadow-glow: 0 0 24px hsl(158 53% 42% / 0.25);
|
|
221
|
+
|
|
222
|
+
/* ═══ BUILDER / GRAPH ONLY (light overrides) ═══ */
|
|
223
|
+
/* Canvas sits deeper than the app shell so the editing surface is
|
|
224
|
+
clearly distinct from chrome. */
|
|
225
|
+
--canvas-background: 220 14% 92%;
|
|
226
|
+
--edge-default: 220 8% 45%;
|
|
227
|
+
--panel-background: 0 0% 100%;
|
|
228
|
+
--panel-border: 220 13% 88%;
|
|
229
|
+
/* Selection glow — dark in light mode for high contrast on white. */
|
|
230
|
+
--selection-glow: 220 15% 15%;
|
|
231
|
+
/* Same node hues as dark; only saturation/lightness drop for legibility. */
|
|
232
|
+
--signal-s: 68%;
|
|
233
|
+
--signal-l: 42%;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@layer base {
|
|
238
|
+
* {
|
|
239
|
+
@apply border-border;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/* Base look is scoped to the builder's own root — NOT <body>. The host owns
|
|
243
|
+
page chrome (background, page font, overscroll); the builder only dresses
|
|
244
|
+
itself. font-sans (Poppins) is inherited from the .fh-builder root;
|
|
245
|
+
headings get the Inter display face, scoped so it can't restyle host pages. */
|
|
246
|
+
.fh-builder :is(h1, h2, h3, h4, h5, h6) {
|
|
247
|
+
font-family: Inter, system-ui, sans-serif;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/* Glass Forest Design System */
|
|
252
|
+
@layer components {
|
|
253
|
+
/* Core Glass Components - Verstärkte Glass-Effekte */
|
|
254
|
+
.glass-forest-card {
|
|
255
|
+
@apply bg-card/60 backdrop-blur-xl border border-white/10 rounded-2xl shadow-lg transition-all duration-300;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.glass-forest-card:hover {
|
|
259
|
+
@apply bg-card/70 shadow-xl scale-[1.02] border-primary/20;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.glass-forest-panel {
|
|
263
|
+
@apply bg-card/70 backdrop-blur-2xl border border-white/10 shadow-xl;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.glass-forest-button {
|
|
267
|
+
@apply bg-card/40 backdrop-blur-md border border-border rounded-full transition-all duration-300;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.glass-forest-button:hover {
|
|
271
|
+
@apply bg-card/60 border-primary/30 shadow-lg -translate-y-0.5;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.glass-forest-button-primary {
|
|
275
|
+
@apply bg-primary text-primary-foreground rounded-full shadow-sm border-0;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.glass-forest-button-primary:hover {
|
|
279
|
+
@apply shadow-xl scale-[1.02] -translate-y-0.5;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.glass-forest-input {
|
|
283
|
+
@apply bg-card/40 backdrop-blur-lg border border-border rounded-2xl transition-all duration-300;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.glass-forest-input:focus {
|
|
287
|
+
@apply bg-card/60 border-primary outline-none ring-2 ring-primary/20;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* Organic Hover Effects */
|
|
291
|
+
.hover-glow {
|
|
292
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.hover-glow:hover {
|
|
296
|
+
box-shadow: var(--glow-green);
|
|
297
|
+
transform: translateY(-2px);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.hover-lift {
|
|
301
|
+
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.hover-lift:hover {
|
|
305
|
+
transform: translateY(-4px) scale(1.02);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/* Workflow Builder Glass Styles - Mehr Transparenz */
|
|
309
|
+
.workflow-builder-panel {
|
|
310
|
+
@apply bg-card/70 backdrop-blur-2xl border border-white/10 shadow-xl;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.block-card {
|
|
314
|
+
@apply bg-card/60 backdrop-blur-xl border border-white/10 rounded-2xl shadow-lg cursor-pointer transition-all duration-300;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.block-card:hover {
|
|
318
|
+
@apply bg-card/70 shadow-xl scale-[1.02];
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.block-node-glass {
|
|
322
|
+
@apply bg-card/70 backdrop-blur-xl rounded-2xl border border-white/10 shadow-xl transition-all duration-300;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.block-node-glass:hover {
|
|
326
|
+
@apply shadow-2xl scale-[1.02] bg-card/80;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* Loading & Status */
|
|
330
|
+
.loading-organic {
|
|
331
|
+
@apply animate-pulse-organic rounded-full bg-primary/20;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.status-dot {
|
|
335
|
+
@apply w-2 h-2 rounded-full animate-pulse-organic;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.status-success .status-dot {
|
|
339
|
+
@apply bg-success;
|
|
340
|
+
box-shadow: var(--glow-green);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.status-warning .status-dot {
|
|
344
|
+
@apply bg-warning;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
@layer utilities {
|
|
349
|
+
/* Organic Animations */
|
|
350
|
+
@keyframes pulse-organic {
|
|
351
|
+
0%,
|
|
352
|
+
100% {
|
|
353
|
+
opacity: 1;
|
|
354
|
+
transform: scale(1);
|
|
355
|
+
}
|
|
356
|
+
50% {
|
|
357
|
+
opacity: 0.8;
|
|
358
|
+
transform: scale(1.05);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
@keyframes ripple-expand {
|
|
363
|
+
0% {
|
|
364
|
+
transform: scale(0.8);
|
|
365
|
+
opacity: 0;
|
|
366
|
+
}
|
|
367
|
+
50% {
|
|
368
|
+
opacity: 0.6;
|
|
369
|
+
}
|
|
370
|
+
100% {
|
|
371
|
+
transform: scale(2);
|
|
372
|
+
opacity: 0;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
@keyframes light-trail {
|
|
377
|
+
0% {
|
|
378
|
+
opacity: 0;
|
|
379
|
+
transform: translateY(0);
|
|
380
|
+
}
|
|
381
|
+
50% {
|
|
382
|
+
opacity: 1;
|
|
383
|
+
}
|
|
384
|
+
100% {
|
|
385
|
+
opacity: 0;
|
|
386
|
+
transform: translateY(-20px);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
@keyframes fade-in {
|
|
391
|
+
from {
|
|
392
|
+
opacity: 0;
|
|
393
|
+
transform: translateY(10px);
|
|
394
|
+
}
|
|
395
|
+
to {
|
|
396
|
+
opacity: 1;
|
|
397
|
+
transform: translateY(0);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
@keyframes glow-pulse {
|
|
402
|
+
0%,
|
|
403
|
+
100% {
|
|
404
|
+
box-shadow: var(--glow-green);
|
|
405
|
+
}
|
|
406
|
+
50% {
|
|
407
|
+
box-shadow: var(--glow-combined);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/* Animation Classes */
|
|
412
|
+
.animate-pulse-organic {
|
|
413
|
+
animation: pulse-organic 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.animate-ripple {
|
|
417
|
+
animation: ripple-expand 1.5s ease-out;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.animate-glow-pulse {
|
|
421
|
+
animation: glow-pulse 2s ease-in-out infinite;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.animate-fade-in {
|
|
425
|
+
animation: fade-in 0.3s ease-out;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/* Line clamp utilities */
|
|
429
|
+
.line-clamp-1 {
|
|
430
|
+
overflow: hidden;
|
|
431
|
+
display: -webkit-box;
|
|
432
|
+
-webkit-box-orient: vertical;
|
|
433
|
+
-webkit-line-clamp: 1;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.line-clamp-2 {
|
|
437
|
+
overflow: hidden;
|
|
438
|
+
display: -webkit-box;
|
|
439
|
+
-webkit-box-orient: vertical;
|
|
440
|
+
-webkit-line-clamp: 2;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.line-clamp-3 {
|
|
444
|
+
overflow: hidden;
|
|
445
|
+
display: -webkit-box;
|
|
446
|
+
-webkit-box-orient: vertical;
|
|
447
|
+
-webkit-line-clamp: 3;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/* ════════════════════════════════════════════════════════════
|
|
452
|
+
* Themed thin scrollbars — uniform across every scrollable region
|
|
453
|
+
* inside the builder (sidebar, right panel, tabs toolbar, dropdowns,
|
|
454
|
+
* dialogs, debug console).
|
|
455
|
+
*
|
|
456
|
+
* Two scopes, both opt-in:
|
|
457
|
+
* - `.fh-builder` covers everything rendered inside the
|
|
458
|
+
* builder DOM subtree.
|
|
459
|
+
* - `.fh-builder-portal` covers Radix Content nodes that portal to
|
|
460
|
+
* <body> (DropdownMenu, Dialog, AlertDialog, Select, Tooltip), so
|
|
461
|
+
* they don't drop back to the host's native scrollbar just because
|
|
462
|
+
* they live outside the builder root in the DOM. Same marker used
|
|
463
|
+
* to pin `font-sans` on those nodes.
|
|
464
|
+
*
|
|
465
|
+
* Host pages are never touched: every rule is anchored on one of these
|
|
466
|
+
* two classes; no `body`/`html`/universal selector escapes them. Thumb
|
|
467
|
+
* uses --muted-foreground at low opacity so it reads as a faint hint of
|
|
468
|
+
* the subtext color on both card and popover surfaces, in both modes.
|
|
469
|
+
*
|
|
470
|
+
* Width 6px: thin enough that the 6px reflow when it appears is barely
|
|
471
|
+
* perceptible, while still big enough to grab. We deliberately don't
|
|
472
|
+
* use `scrollbar-gutter: stable` (which would reserve the gutter even
|
|
473
|
+
* when nothing overflows) — most panels never need a scrollbar, and
|
|
474
|
+
* the permanent gap looks worse than the rare reflow.
|
|
475
|
+
* ════════════════════════════════════════════════════════════ */
|
|
476
|
+
.fh-builder,
|
|
477
|
+
.fh-builder *,
|
|
478
|
+
.fh-builder-portal,
|
|
479
|
+
.fh-builder-portal * {
|
|
480
|
+
scrollbar-width: thin;
|
|
481
|
+
scrollbar-color: hsl(var(--muted-foreground) / 0.35) transparent;
|
|
482
|
+
}
|
|
483
|
+
.fh-builder ::-webkit-scrollbar,
|
|
484
|
+
.fh-builder-portal::-webkit-scrollbar,
|
|
485
|
+
.fh-builder-portal ::-webkit-scrollbar {
|
|
486
|
+
width: 6px;
|
|
487
|
+
height: 6px;
|
|
488
|
+
}
|
|
489
|
+
.fh-builder ::-webkit-scrollbar-track,
|
|
490
|
+
.fh-builder-portal::-webkit-scrollbar-track,
|
|
491
|
+
.fh-builder-portal ::-webkit-scrollbar-track {
|
|
492
|
+
background: transparent;
|
|
493
|
+
}
|
|
494
|
+
.fh-builder ::-webkit-scrollbar-thumb,
|
|
495
|
+
.fh-builder-portal::-webkit-scrollbar-thumb,
|
|
496
|
+
.fh-builder-portal ::-webkit-scrollbar-thumb {
|
|
497
|
+
background-color: hsl(var(--muted-foreground) / 0.3);
|
|
498
|
+
border-radius: 9999px;
|
|
499
|
+
}
|
|
500
|
+
.fh-builder ::-webkit-scrollbar-thumb:hover,
|
|
501
|
+
.fh-builder-portal::-webkit-scrollbar-thumb:hover,
|
|
502
|
+
.fh-builder-portal ::-webkit-scrollbar-thumb:hover {
|
|
503
|
+
background-color: hsl(var(--muted-foreground) / 0.55);
|
|
504
|
+
}
|
|
505
|
+
.fh-builder ::-webkit-scrollbar-corner,
|
|
506
|
+
.fh-builder-portal::-webkit-scrollbar-corner,
|
|
507
|
+
.fh-builder-portal ::-webkit-scrollbar-corner {
|
|
508
|
+
background: transparent;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/* Suppress ReactFlow's built-in selection outline — we use custom glow via editorStore */
|
|
512
|
+
.react-flow__node.selected,
|
|
513
|
+
.react-flow__edge.selected {
|
|
514
|
+
outline: none !important;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/* Debug cursor pulse animation for node highlighting */
|
|
518
|
+
@keyframes debug-cursor-pulse {
|
|
519
|
+
0%,
|
|
520
|
+
100% {
|
|
521
|
+
opacity: 1;
|
|
522
|
+
}
|
|
523
|
+
50% {
|
|
524
|
+
opacity: 0.6;
|
|
525
|
+
}
|
|
526
|
+
}
|