@motiadev/workbench 0.5.11-beta.120-433270 → 0.5.11-beta.120-685453
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/dist/index.d.ts +2 -0
- package/dist/index.html +21 -1
- package/dist/index.js +1 -0
- package/dist/middleware.js +15 -2
- package/dist/src/App.js +6 -27
- package/dist/src/components/flow/hooks/use-get-flow-state.js +1 -0
- package/dist/src/components/flow/node-organizer.js +4 -38
- package/dist/src/components/header/header.js +1 -1
- package/dist/src/components/logs/logs-page.js +1 -1
- package/dist/src/components/observability/trace-item/trace-item.js +1 -1
- package/dist/src/components/observability/traces-groups.js +1 -1
- package/dist/src/components/sidebar/sidebar.js +1 -1
- package/dist/src/components/tutorial/engine/tutorial-engine.d.ts +12 -0
- package/dist/src/components/tutorial/engine/tutorial-engine.js +36 -0
- package/dist/src/components/tutorial/engine/tutorial-types.d.ts +22 -0
- package/dist/src/components/tutorial/engine/tutorial-types.js +1 -0
- package/dist/src/components/tutorial/engine/workbench-xpath.d.ts +39 -0
- package/dist/src/components/tutorial/engine/workbench-xpath.js +39 -0
- package/dist/src/components/tutorial/hooks/tutorial-utils.d.ts +1 -0
- package/dist/src/components/tutorial/hooks/tutorial-utils.js +17 -0
- package/dist/src/components/tutorial/hooks/use-tutorial-engine.d.ts +14 -0
- package/dist/src/components/tutorial/hooks/use-tutorial-engine.js +162 -0
- package/dist/src/components/tutorial/hooks/use-tutorial.d.ts +5 -0
- package/dist/src/components/tutorial/hooks/use-tutorial.js +10 -0
- package/dist/src/components/tutorial/tutorial-button.js +20 -0
- package/dist/src/components/tutorial/tutorial-step.d.ts +14 -0
- package/dist/src/components/tutorial/tutorial-step.js +18 -0
- package/dist/src/components/tutorial/tutorial.css +210 -0
- package/dist/src/components/tutorial/tutorial.d.ts +2 -0
- package/dist/src/components/tutorial/tutorial.js +8 -0
- package/dist/src/components/ui/theme-toggle.js +0 -8
- package/dist/src/publicComponents/base-node/base-node.js +3 -1
- package/dist/src/publicComponents/base-node/code-display.d.ts +9 -0
- package/dist/src/publicComponents/base-node/code-display.js +64 -0
- package/dist/src/publicComponents/base-node/feature-card.d.ts +9 -0
- package/dist/src/publicComponents/base-node/feature-card.js +5 -0
- package/dist/src/publicComponents/base-node/node-sidebar.d.ts +2 -0
- package/dist/src/publicComponents/base-node/node-sidebar.js +4 -5
- package/dist/src/stores/use-flow-store.d.ts +3 -5
- package/dist/src/stores/use-global-store.d.ts +3 -5
- package/dist/src/stores/use-tabs-store.d.ts +3 -5
- package/dist/src/stores/use-theme-store.d.ts +5 -6
- package/dist/src/types/file.d.ts +7 -0
- package/dist/src/types/file.js +1 -0
- package/dist/tsconfig.app.tsbuildinfo +1 -1
- package/dist/tsconfig.node.tsbuildinfo +1 -1
- package/package.json +13 -12
- package/dist/src/components/ui/tutorial-button.js +0 -69
- /package/dist/src/components/{ui → tutorial}/tutorial-button.d.ts +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { MotiaTutorial } from '../engine/tutorial-engine';
|
|
3
|
+
export const useTutorial = () => {
|
|
4
|
+
const open = () => MotiaTutorial.open();
|
|
5
|
+
const [steps, setSteps] = useState([]);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
MotiaTutorial.onStepsRegistered(() => setSteps(MotiaTutorial.steps));
|
|
8
|
+
}, []);
|
|
9
|
+
return { open, steps };
|
|
10
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '@motiadev/ui';
|
|
3
|
+
import { Book } from 'lucide-react';
|
|
4
|
+
import { useTutorial } from './hooks/use-tutorial';
|
|
5
|
+
import { Tooltip } from '../ui/tooltip';
|
|
6
|
+
export const TutorialButton = () => {
|
|
7
|
+
const { open, steps } = useTutorial();
|
|
8
|
+
const isTutorialFlowMissing = steps.length === 0;
|
|
9
|
+
const onTutorialButtonClick = () => {
|
|
10
|
+
if (!isTutorialFlowMissing) {
|
|
11
|
+
open();
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
console.log(isTutorialFlowMissing);
|
|
15
|
+
const trigger = (_jsxs(Button, { "data-testid": "tutorial-trigger", variant: "default", onClick: () => onTutorialButtonClick(), children: [_jsx(Book, { className: "h-4 w-4" }), "Tutorial"] }));
|
|
16
|
+
if (isTutorialFlowMissing) {
|
|
17
|
+
return (_jsx(Tooltip, { content: _jsxs("div", { className: "flex flex-col gap-4 p-4 max-w-[320px]", children: [_jsx("p", { className: "text-sm wrap-break-word p-0 m-0", children: "In order to start the tutorial, you need to download the tutorial steps using the Motia CLI. In your terminal execute the following command to create a new project:" }), _jsx("pre", { className: "text-sm font-bold", children: "npx motia@latest create" })] }), children: trigger }));
|
|
18
|
+
}
|
|
19
|
+
return trigger;
|
|
20
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TutorialImage } from './engine/tutorial-types';
|
|
3
|
+
type TutorialStepProps = {
|
|
4
|
+
step: number;
|
|
5
|
+
totalSteps: number;
|
|
6
|
+
title: string;
|
|
7
|
+
description: React.ReactNode;
|
|
8
|
+
link?: string;
|
|
9
|
+
image?: TutorialImage;
|
|
10
|
+
onNext: () => void;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
};
|
|
13
|
+
export declare const TutorialStep: React.ForwardRefExoticComponent<TutorialStepProps & React.RefAttributes<HTMLDivElement>>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useEffect } from 'react';
|
|
3
|
+
export const TutorialStep = forwardRef(({ step, totalSteps, title, description, link, image, onNext, onClose }, ref) => {
|
|
4
|
+
useEffect(() => {
|
|
5
|
+
const handleKeyDown = (e) => {
|
|
6
|
+
if (e.key === 'Escape') {
|
|
7
|
+
onClose();
|
|
8
|
+
}
|
|
9
|
+
else if (e.key === 'ArrowRight') {
|
|
10
|
+
onNext();
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
14
|
+
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
15
|
+
}, [onClose, onNext]);
|
|
16
|
+
return (_jsxs("div", { ref: ref, className: "driver-popover", children: [image && (_jsx("img", { src: image.src, alt: "Step visual", className: "driver-popover-image object-cover", style: { height: image.height, width: '100%' } })), _jsx("div", { className: "driver-popover-title", children: _jsx("h2", { className: "popover-title", children: title }) }), _jsx("div", { className: "driver-popover-description", children: description }), link && (_jsx("a", { href: link, target: "_blank", className: "text-foreground text-xs font-semibold px-4 hover:underline", children: "Learn more" })), _jsxs("div", { className: "driver-popover-footer flex items-center justify-between", children: [_jsxs("div", { className: "text-sm text-muted-foreground font-semibold", children: [step, " ", _jsx("span", { className: "text-foreground", children: "/" }), " ", totalSteps] }), _jsx("div", { className: "driver-popover-navigation-btns flex gap-2", children: _jsx("button", { className: "driver-popover-next-btn", onClick: onNext, children: step < totalSteps ? 'Continue' : 'Finish' }) })] }), step < totalSteps && (_jsx("div", { className: "tutorial-opt-out-container", children: _jsx("button", { className: "tutorial-opt-out-button", onClick: onClose, children: "Close" }) }))] }));
|
|
17
|
+
});
|
|
18
|
+
TutorialStep.displayName = 'TutorialStep';
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
@import '@motiadev/ui/styles.css';
|
|
2
|
+
@import '@motiadev/ui/globals.css';
|
|
3
|
+
@import 'tw-animate-css';
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--tutorial-text-color: var(--dark-800);
|
|
7
|
+
--tutorial-border: var(--light-1000);
|
|
8
|
+
--tutorial-code-bg: rgb(24, 24, 24, 0.1);
|
|
9
|
+
--tutorial-code-text: var(--text-body);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.dark {
|
|
13
|
+
--tutorial-border: rgb(65, 65, 65);
|
|
14
|
+
--tutorial-text-color: var(--light-800);
|
|
15
|
+
--tutorial-code-bg: rgb(24, 24, 24, 0.4);
|
|
16
|
+
--tutorial-code-text: var(--light-1000);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.driver-popover {
|
|
20
|
+
z-index: 10000;
|
|
21
|
+
width: 400px;
|
|
22
|
+
max-width: 100%;
|
|
23
|
+
background-color: var(--background);
|
|
24
|
+
padding: 0;
|
|
25
|
+
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, #0000001a), 0 4px 6px -4px var(--tw-shadow-color, #0000001a);
|
|
26
|
+
box-shadow:
|
|
27
|
+
var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow),
|
|
28
|
+
var(--tw-shadow);
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-flow: column;
|
|
31
|
+
border: 1px solid var(--tutorial-border);
|
|
32
|
+
border-radius: 16px;
|
|
33
|
+
|
|
34
|
+
transition: all 0.3s ease-in-out;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.driver-popover-image {
|
|
38
|
+
border-radius: 16px 16px 0 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.driver-popover-intro-step {
|
|
42
|
+
max-width: 400px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.popover-title {
|
|
46
|
+
font-size: 18px;
|
|
47
|
+
font-weight: 700;
|
|
48
|
+
font-weight: var(--font-weight-600);
|
|
49
|
+
line-height: 1.2;
|
|
50
|
+
color: var(--text-header);
|
|
51
|
+
font-family: var(--default-font-family);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.driver-popover-description * {
|
|
55
|
+
line-height: 1.25;
|
|
56
|
+
font-size: 14px;
|
|
57
|
+
font-weight: 500;
|
|
58
|
+
font-family: var(--default-font-family);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.driver-popover-title {
|
|
62
|
+
padding: 16px 16px 0 16px;
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.driver-popover-description {
|
|
67
|
+
padding: 16px;
|
|
68
|
+
|
|
69
|
+
:not(b) {
|
|
70
|
+
color: var(--tutorial-text-color);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
b {
|
|
74
|
+
font-weight: 800;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
ul {
|
|
78
|
+
list-style-type: disc;
|
|
79
|
+
margin-left: 24px;
|
|
80
|
+
|
|
81
|
+
&.no-decoration {
|
|
82
|
+
list-style-type: none;
|
|
83
|
+
}
|
|
84
|
+
&.square-decoration {
|
|
85
|
+
list-style-type: square;
|
|
86
|
+
padding-left: 4px;
|
|
87
|
+
}
|
|
88
|
+
&.double-indented {
|
|
89
|
+
margin-left: calc(var(--spacing) * 4);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
a {
|
|
94
|
+
text-decoration: underline;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.driver-popover-progress-text {
|
|
99
|
+
color: var(--text-placeholder);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.tutorial-opt-out-container {
|
|
103
|
+
display: flex;
|
|
104
|
+
flex-flow: column;
|
|
105
|
+
align-items: center;
|
|
106
|
+
border-top: 1px solid var(--border);
|
|
107
|
+
padding: 16px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.tutorial-opt-out-button {
|
|
111
|
+
font-size: 14px;
|
|
112
|
+
font-weight: 600;
|
|
113
|
+
font-family: var(--default-font-family);
|
|
114
|
+
background: transparent;
|
|
115
|
+
border: none;
|
|
116
|
+
color: var(--text-body);
|
|
117
|
+
text-shadow: none;
|
|
118
|
+
cursor: pointer;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.driver-popover-navigation-btns {
|
|
122
|
+
position: relative;
|
|
123
|
+
flex-grow: 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.driver-popover-navigation-btns:hover:before {
|
|
127
|
+
content: 'Use arrow keys to navigate';
|
|
128
|
+
position: absolute;
|
|
129
|
+
color: white;
|
|
130
|
+
top: -20px;
|
|
131
|
+
right: 0;
|
|
132
|
+
text-align: right;
|
|
133
|
+
width: 180%;
|
|
134
|
+
height: 100%;
|
|
135
|
+
|
|
136
|
+
font-size: 12px;
|
|
137
|
+
font-weight: 500;
|
|
138
|
+
font-family: var(--default-font-family);
|
|
139
|
+
color: var(--text-body);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.driver-popover-navigation-btns button {
|
|
143
|
+
cursor: pointer;
|
|
144
|
+
border-radius: 999px;
|
|
145
|
+
color: white;
|
|
146
|
+
font-family: var(--default-font-family);
|
|
147
|
+
border: 0;
|
|
148
|
+
font-size: 16px;
|
|
149
|
+
font-weight: 500;
|
|
150
|
+
line-height: 125%;
|
|
151
|
+
letter-spacing: -0.25px;
|
|
152
|
+
text-shadow: none;
|
|
153
|
+
position: relative;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.driver-popover-btn-disabled {
|
|
157
|
+
display: none;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.driver-popover-next-btn, .driver-popover-next-btn:hover {
|
|
161
|
+
background-color: var(--accent-1000);
|
|
162
|
+
color: white;
|
|
163
|
+
padding: 16px 32px;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.driver-popover-footer {
|
|
167
|
+
padding: 16px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.driver-popover-arrow {
|
|
171
|
+
border-width: 8px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.driver-popover-arrow-side-top {
|
|
175
|
+
margin-top: 1px;
|
|
176
|
+
border-top-color: var(--tutorial-border);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.driver-popover-arrow-side-bottom {
|
|
180
|
+
margin-bottom: 1px;
|
|
181
|
+
border-bottom-color: var(--tutorial-border);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.driver-popover-arrow-side-left {
|
|
185
|
+
margin-left: 1px;
|
|
186
|
+
border-left-color: var(--tutorial-border);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.driver-popover-arrow-side-right {
|
|
190
|
+
margin-right: 1px;
|
|
191
|
+
border-right-color: var(--tutorial-border);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.code-preview {
|
|
195
|
+
overflow-x: auto;
|
|
196
|
+
background: var(--tutorial-code-bg);
|
|
197
|
+
padding: 16px;
|
|
198
|
+
border-radius: 8px;
|
|
199
|
+
|
|
200
|
+
code {
|
|
201
|
+
font-size: 14px;
|
|
202
|
+
font-weight: 400;
|
|
203
|
+
color: var(--tutorial-code-text);
|
|
204
|
+
font-family: var(--font-dm-mono);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.driver-popover-close-btn {
|
|
209
|
+
display: none;
|
|
210
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useTutorialEngine } from './hooks/use-tutorial-engine';
|
|
3
|
+
import { TutorialStep } from './tutorial-step';
|
|
4
|
+
import './tutorial.css';
|
|
5
|
+
export const Tutorial = () => {
|
|
6
|
+
const engine = useTutorialEngine();
|
|
7
|
+
return (_jsxs("div", { children: [_jsx("div", { className: "fixed inset-0 z-[9999]" }), _jsx("div", { className: "absolute top-5 left-5 w-full h-full rounded-lg shadow-[0_0_0_9999px_rgba(0,0,0,0.5)] z-[10000] pointer-events-none", ref: engine.highlighterRef }), _jsx(TutorialStep, { ref: engine.ref, step: engine.currentStep, totalSteps: engine.totalSteps, title: engine.title, description: engine.description, link: engine.link, image: engine.image, onNext: () => engine.moveStep(engine.currentStepRef.current + 1), onClose: engine.onClose })] }));
|
|
8
|
+
};
|
|
@@ -2,19 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Moon, Sun } from 'lucide-react';
|
|
3
3
|
import { useThemeStore } from '@/stores/use-theme-store';
|
|
4
4
|
import { cn } from '@/lib/utils';
|
|
5
|
-
import { useEffect } from 'react';
|
|
6
5
|
export const ThemeToggle = () => {
|
|
7
6
|
const theme = useThemeStore((state) => state.theme);
|
|
8
7
|
const setTheme = useThemeStore((state) => state.setTheme);
|
|
9
8
|
const toggleTheme = () => {
|
|
10
9
|
setTheme(theme === 'light' ? 'dark' : 'light');
|
|
11
10
|
};
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
const url = new URL(window.location.href);
|
|
14
|
-
const colorScheme = url.searchParams.get('color-scheme');
|
|
15
|
-
if (colorScheme) {
|
|
16
|
-
setTheme(colorScheme);
|
|
17
|
-
}
|
|
18
|
-
}, [setTheme]);
|
|
19
11
|
return (_jsxs("button", { onClick: toggleTheme, className: "relative flex items-center cursor-pointer w-16 h-8 border bg-muted-foreground/10 rounded-full p-1 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", "aria-label": `Switch to ${theme === 'light' ? 'dark' : 'light'} theme`, children: [_jsx("div", { className: cn('absolute w-6 h-6 bg-background border border-border rounded-full shadow-sm transition-transform duration-200 ease-in-out', theme === 'dark' ? 'translate-x-8' : 'translate-x-0') }), _jsx("div", { className: "flex items-center justify-center w-6 h-6 z-10", children: _jsx(Sun, { className: cn('h-3.5 w-3.5 transition-colors duration-200', theme === 'light' ? 'text-foreground' : 'text-muted-foreground') }) }), _jsx("div", { className: "flex items-center justify-center w-6 h-6 z-10 ml-2", children: _jsx(Moon, { className: cn('h-3.5 w-3.5 transition-colors duration-200', theme === 'dark' ? 'text-foreground' : 'text-muted-foreground') }) })] }));
|
|
20
12
|
};
|
|
@@ -10,10 +10,12 @@ export const BaseNode = ({ title, variant, children, disableSourceHandle, disabl
|
|
|
10
10
|
const [isOpen, setIsOpen] = useState(false);
|
|
11
11
|
const { sourcePosition, targetPosition, toggleTargetPosition, toggleSourcePosition } = useHandlePositions(data);
|
|
12
12
|
const [content, setContent] = useState(null);
|
|
13
|
+
const [features, setFeatures] = useState([]);
|
|
13
14
|
const fetchContent = useCallback(async () => {
|
|
14
15
|
const response = await fetch(`/step/${data.id}`);
|
|
15
16
|
const responseData = await response.json();
|
|
16
17
|
setContent(responseData.content);
|
|
18
|
+
setFeatures(responseData.features);
|
|
17
19
|
}, [data.id]);
|
|
18
20
|
useEffect(() => {
|
|
19
21
|
if (data.id && isOpen) {
|
|
@@ -24,5 +26,5 @@ export const BaseNode = ({ title, variant, children, disableSourceHandle, disabl
|
|
|
24
26
|
'bg-muted-foreground/20': isOpen,
|
|
25
27
|
}), children: [_jsx("div", { className: "rounded-lg bg-background border-1 border-muted-foreground/30 border-solid", "data-testid": `node-${title?.toLowerCase().replace(/ /g, '-')}`, children: _jsxs("div", { className: "group relative", children: [_jsx(NodeHeader, { text: title, variant: variant, className: "border-b-2 border-muted-foreground/10", children: _jsx("div", { className: "flex justify-end", children: _jsx(Button, { "data-testid": `open-code-preview-button-${title?.toLowerCase()}`, variant: "ghost", className: "h-5 p-0.5", onClick: () => setIsOpen(true), children: _jsx(ScanSearch, { className: "w-4 h-4" }) }) }) }), subtitle && _jsx("div", { className: "py-4 px-6 text-sm text-muted-foreground", children: subtitle }), children && (_jsx("div", { className: "p-2", children: _jsx("div", { className: cn('space-y-3 p-4 text-sm text-muted-foreground', {
|
|
26
28
|
'bg-card': variant !== 'noop',
|
|
27
|
-
}), children: children }) })), !disableTargetHandle && (_jsx(BaseHandle, { type: "target", position: targetPosition, onTogglePosition: toggleTargetPosition })), !disableSourceHandle && (_jsx(BaseHandle, { type: "source", position: sourcePosition, onTogglePosition: toggleSourcePosition }))] }) }), content && (_jsx(NodeSidebar, { content: content, title: title, subtitle: subtitle, variant: variant, language: language, isOpen: isOpen, onClose: () => setIsOpen(false) }))] }));
|
|
29
|
+
}), children: children }) })), !disableTargetHandle && (_jsx(BaseHandle, { type: "target", position: targetPosition, onTogglePosition: toggleTargetPosition })), !disableSourceHandle && (_jsx(BaseHandle, { type: "source", position: sourcePosition, onTogglePosition: toggleSourcePosition }))] }) }), content && (_jsx(NodeSidebar, { features: features, content: content, title: title, subtitle: subtitle, variant: variant, language: language, isOpen: isOpen, onClose: () => setIsOpen(false) }))] }));
|
|
28
30
|
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useThemeStore } from '@/stores/use-theme-store';
|
|
3
|
+
import { FeatureCard } from './feature-card';
|
|
4
|
+
import { useRef, useState } from 'react';
|
|
5
|
+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
|
6
|
+
import { dracula, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|
7
|
+
import { LanguageIndicator } from './language-indicator';
|
|
8
|
+
const codeTagProps = {
|
|
9
|
+
style: {
|
|
10
|
+
fontFamily: 'DM Mono, monospace',
|
|
11
|
+
fontSize: '16px',
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
const customStyle = {
|
|
15
|
+
margin: 0,
|
|
16
|
+
borderRadius: 0,
|
|
17
|
+
padding: 0,
|
|
18
|
+
};
|
|
19
|
+
const isHighlighted = (lines, lineNumber) => {
|
|
20
|
+
return lines.some((line) => {
|
|
21
|
+
const [start, end] = line.split('-').map((num) => parseInt(num, 10));
|
|
22
|
+
if (end !== undefined) {
|
|
23
|
+
return lineNumber >= start && lineNumber <= end;
|
|
24
|
+
}
|
|
25
|
+
return lineNumber == start;
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
const getFirstLineNumber = (line) => {
|
|
29
|
+
const [start] = line.split('-').map((num) => parseInt(num, 10));
|
|
30
|
+
return start;
|
|
31
|
+
};
|
|
32
|
+
export const CodeDisplay = ({ code, language, features }) => {
|
|
33
|
+
const theme = useThemeStore((state) => state.theme);
|
|
34
|
+
const themeStyle = theme === 'dark' ? dracula : oneLight;
|
|
35
|
+
const [highlightedLines, setHighlightedLines] = useState([]);
|
|
36
|
+
const [selectedFeature, setSelectedFeature] = useState(null);
|
|
37
|
+
const ref = useRef(null);
|
|
38
|
+
const handleFeatureClick = (feature) => {
|
|
39
|
+
setSelectedFeature(feature);
|
|
40
|
+
setHighlightedLines(feature.lines);
|
|
41
|
+
const lineNumber = getFirstLineNumber(feature.lines[0]);
|
|
42
|
+
const line = ref.current?.querySelector(`[data-line-number="${lineNumber}"]`);
|
|
43
|
+
if (line) {
|
|
44
|
+
line.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
return (_jsxs("div", { className: "flex flex-col h-full overflow-hidden", children: [_jsxs("div", { className: "flex items-center py-2 px-5 dark:bg-[#1e1e1e] gap-2 justify-center", children: [_jsx("div", { className: "text-sm text-muted-foreground", children: "Read only" }), _jsx("div", { className: "flex-1" }), _jsx(LanguageIndicator, { language: language, className: "w-4 h-4", size: 16, showLabel: true })] }), _jsxs("div", { className: "flex flex-row h-[calc(100%-36px)]", children: [features && features.length > 0 && (_jsx("div", { className: "flex flex-col gap-2 p-2 bg-card overflow-y-auto min-w-[200px] w-[300px]", children: features.map((feature, index) => (_jsx(FeatureCard, { feature: feature, highlighted: selectedFeature === feature, onClick: () => handleFeatureClick(feature), onHover: () => handleFeatureClick(feature) }, index))) })), _jsx("div", { className: "overflow-y-auto", ref: ref, children: _jsx(SyntaxHighlighter, { showLineNumbers: true, language: language, style: themeStyle, codeTagProps: codeTagProps, customStyle: customStyle, wrapLines: true, lineProps: (lineNumber) => {
|
|
48
|
+
if (isHighlighted(highlightedLines, lineNumber)) {
|
|
49
|
+
return {
|
|
50
|
+
'data-line-number': lineNumber,
|
|
51
|
+
style: {
|
|
52
|
+
borderLeft: '2px solid var(--accent-1000)',
|
|
53
|
+
backgroundColor: 'rgb(from var(--accent-1000) r g b / 0.2)',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
'data-line-number': lineNumber,
|
|
59
|
+
style: {
|
|
60
|
+
borderLeft: '2px solid transparent',
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}, children: code }) })] })] }));
|
|
64
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '@/lib/utils';
|
|
3
|
+
export const FeatureCard = ({ feature, highlighted, onClick, onHover }) => {
|
|
4
|
+
return (_jsxs("div", { "data-feature-id": feature.id, className: cn('p-4 rounded-lg bg-card shadow-sm cursor-pointer hover:bg-card/50 border-2 border-transparent', highlighted && 'border-2 border-accent-1000 bg-accent-100'), onClick: onClick, onMouseEnter: onHover, children: [_jsx("div", { className: "text-md font-semibold text-foreground leading-tight whitespace-nowrap mb-2", children: feature.title }), _jsx("div", { className: "text-sm font-medium text-muted-foreground leading-tight", children: feature.description }), feature.link && (_jsx("div", { className: "text-sm font-medium text-muted-foreground leading-tight", children: _jsx("a", { href: feature.link, children: "Learn more" }) }))] }));
|
|
5
|
+
};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import { JsonEditor } from '@/components/endpoints/json-editor';
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
2
|
import { Sidebar } from '@/components/sidebar/sidebar';
|
|
4
3
|
import { X } from 'lucide-react';
|
|
5
|
-
import {
|
|
6
|
-
export const NodeSidebar = ({ content, title, subtitle, language, isOpen, onClose }) => {
|
|
4
|
+
import { CodeDisplay } from './code-display';
|
|
5
|
+
export const NodeSidebar = ({ content, title, subtitle, language, isOpen, onClose, features, }) => {
|
|
7
6
|
if (!isOpen)
|
|
8
7
|
return null;
|
|
9
|
-
return (
|
|
8
|
+
return (_jsx(Sidebar, { title: title, subtitle: subtitle, initialWidth: 900, contentClassName: "p-0 h-full gap-0", onClose: onClose, actions: [{ icon: _jsx(X, {}), onClick: onClose, label: 'Close' }], children: _jsx(CodeDisplay, { code: content, language: language, features: features }) }));
|
|
10
9
|
};
|
|
@@ -4,17 +4,15 @@ type UseFlowStore = {
|
|
|
4
4
|
flows: string[];
|
|
5
5
|
setFlows: (flows: string[]) => void;
|
|
6
6
|
};
|
|
7
|
-
export declare const useFlowStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<UseFlowStore>, "
|
|
8
|
-
setState(partial: UseFlowStore | Partial<UseFlowStore> | ((state: UseFlowStore) => UseFlowStore | Partial<UseFlowStore>), replace?: false | undefined): unknown;
|
|
9
|
-
setState(state: UseFlowStore | ((state: UseFlowStore) => UseFlowStore), replace: true): unknown;
|
|
7
|
+
export declare const useFlowStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<UseFlowStore>, "persist"> & {
|
|
10
8
|
persist: {
|
|
11
|
-
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<UseFlowStore, UseFlowStore
|
|
9
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<UseFlowStore, UseFlowStore>>) => void;
|
|
12
10
|
clearStorage: () => void;
|
|
13
11
|
rehydrate: () => Promise<void> | void;
|
|
14
12
|
hasHydrated: () => boolean;
|
|
15
13
|
onHydrate: (fn: (state: UseFlowStore) => void) => () => void;
|
|
16
14
|
onFinishHydration: (fn: (state: UseFlowStore) => void) => () => void;
|
|
17
|
-
getOptions: () => Partial<import("zustand/middleware").PersistOptions<UseFlowStore, UseFlowStore
|
|
15
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<UseFlowStore, UseFlowStore>>;
|
|
18
16
|
};
|
|
19
17
|
}>;
|
|
20
18
|
export {};
|
|
@@ -10,17 +10,15 @@ type UseGlobalStore = {
|
|
|
10
10
|
selectedLogId?: string;
|
|
11
11
|
selectLogId: (logId?: string) => void;
|
|
12
12
|
};
|
|
13
|
-
export declare const useGlobalStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<UseGlobalStore>, "
|
|
14
|
-
setState(partial: UseGlobalStore | Partial<UseGlobalStore> | ((state: UseGlobalStore) => UseGlobalStore | Partial<UseGlobalStore>), replace?: false | undefined): unknown;
|
|
15
|
-
setState(state: UseGlobalStore | ((state: UseGlobalStore) => UseGlobalStore), replace: true): unknown;
|
|
13
|
+
export declare const useGlobalStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<UseGlobalStore>, "persist"> & {
|
|
16
14
|
persist: {
|
|
17
|
-
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<UseGlobalStore, UseGlobalStore
|
|
15
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<UseGlobalStore, UseGlobalStore>>) => void;
|
|
18
16
|
clearStorage: () => void;
|
|
19
17
|
rehydrate: () => Promise<void> | void;
|
|
20
18
|
hasHydrated: () => boolean;
|
|
21
19
|
onHydrate: (fn: (state: UseGlobalStore) => void) => () => void;
|
|
22
20
|
onFinishHydration: (fn: (state: UseGlobalStore) => void) => () => void;
|
|
23
|
-
getOptions: () => Partial<import("zustand/middleware").PersistOptions<UseGlobalStore, UseGlobalStore
|
|
21
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<UseGlobalStore, UseGlobalStore>>;
|
|
24
22
|
};
|
|
25
23
|
}>;
|
|
26
24
|
export {};
|
|
@@ -3,17 +3,15 @@ interface TabsState {
|
|
|
3
3
|
setTopTab: (tab: string) => void;
|
|
4
4
|
setBottomTab: (tab: string) => void;
|
|
5
5
|
}
|
|
6
|
-
export declare const useTabsStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<TabsState>, "
|
|
7
|
-
setState(partial: TabsState | Partial<TabsState> | ((state: TabsState) => TabsState | Partial<TabsState>), replace?: false | undefined): unknown;
|
|
8
|
-
setState(state: TabsState | ((state: TabsState) => TabsState), replace: true): unknown;
|
|
6
|
+
export declare const useTabsStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<TabsState>, "persist"> & {
|
|
9
7
|
persist: {
|
|
10
|
-
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<TabsState, TabsState
|
|
8
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<TabsState, TabsState>>) => void;
|
|
11
9
|
clearStorage: () => void;
|
|
12
10
|
rehydrate: () => Promise<void> | void;
|
|
13
11
|
hasHydrated: () => boolean;
|
|
14
12
|
onHydrate: (fn: (state: TabsState) => void) => () => void;
|
|
15
13
|
onFinishHydration: (fn: (state: TabsState) => void) => () => void;
|
|
16
|
-
getOptions: () => Partial<import("zustand/middleware").PersistOptions<TabsState, TabsState
|
|
14
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<TabsState, TabsState>>;
|
|
17
15
|
};
|
|
18
16
|
}>;
|
|
19
17
|
export {};
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
type Theme = 'dark' | 'light' | 'system';
|
|
2
2
|
export type ThemeState = {
|
|
3
3
|
theme: Theme;
|
|
4
4
|
setTheme: (theme: Theme) => void;
|
|
5
5
|
};
|
|
6
|
-
export declare const useThemeStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<ThemeState>, "
|
|
7
|
-
setState(partial: ThemeState | Partial<ThemeState> | ((state: ThemeState) => ThemeState | Partial<ThemeState>), replace?: false | undefined): unknown;
|
|
8
|
-
setState(state: ThemeState | ((state: ThemeState) => ThemeState), replace: true): unknown;
|
|
6
|
+
export declare const useThemeStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<ThemeState>, "persist"> & {
|
|
9
7
|
persist: {
|
|
10
|
-
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<ThemeState, unknown
|
|
8
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<ThemeState, unknown>>) => void;
|
|
11
9
|
clearStorage: () => void;
|
|
12
10
|
rehydrate: () => Promise<void> | void;
|
|
13
11
|
hasHydrated: () => boolean;
|
|
14
12
|
onHydrate: (fn: (state: ThemeState) => void) => () => void;
|
|
15
13
|
onFinishHydration: (fn: (state: ThemeState) => void) => () => void;
|
|
16
|
-
getOptions: () => Partial<import("zustand/middleware").PersistOptions<ThemeState, unknown
|
|
14
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<ThemeState, unknown>>;
|
|
17
15
|
};
|
|
18
16
|
}>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|