create-visualbuild-app 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -0
- package/package.json +85 -0
- package/scripts/create-builder-app.mjs +501 -0
- package/scripts/vb-dev.mjs +32 -0
- package/scripts/vb-generate.mjs +224 -0
- package/templates/default/app/README.md +21 -0
- package/templates/default/app/eslint.config.js +25 -0
- package/templates/default/app/index.html +15 -0
- package/templates/default/app/src/index.css +23 -0
- package/templates/default/app/src/main.tsx +10 -0
- package/templates/default/app/tsconfig.app.json +21 -0
- package/templates/default/app/tsconfig.json +7 -0
- package/templates/default/app/tsconfig.node.json +19 -0
- package/templates/default/app/visualbuild/generated-files.json +3 -0
- package/templates/default/app/visualbuild/pages.json +12 -0
- package/templates/default/app/vite.config.ts +7 -0
- package/templates/default/builder/README.md +21 -0
- package/templates/default/builder/eslint.config.js +25 -0
- package/templates/default/builder/tsconfig.app.json +21 -0
- package/templates/default/builder/tsconfig.json +7 -0
- package/templates/default/builder/tsconfig.node.json +22 -0
- package/visual-app-builder/index.html +15 -0
- package/visual-app-builder/server/parseReactPage.ts +571 -0
- package/visual-app-builder/shared/generateReactSource.d.mts +37 -0
- package/visual-app-builder/shared/generateReactSource.mjs +443 -0
- package/visual-app-builder/src/App.tsx +874 -0
- package/visual-app-builder/src/components/Canvas.tsx +1059 -0
- package/visual-app-builder/src/components/CodePanel.tsx +812 -0
- package/visual-app-builder/src/components/ComponentSidebar.tsx +302 -0
- package/visual-app-builder/src/components/PageSwitcher.tsx +161 -0
- package/visual-app-builder/src/components/ProjectExplorer.tsx +1054 -0
- package/visual-app-builder/src/components/PropertiesPanel.tsx +692 -0
- package/visual-app-builder/src/components/Topbar.tsx +128 -0
- package/visual-app-builder/src/data/componentRegistry.tsx +292 -0
- package/visual-app-builder/src/data/primitiveRegistry.ts +368 -0
- package/visual-app-builder/src/index.css +111 -0
- package/visual-app-builder/src/main.tsx +10 -0
- package/visual-app-builder/src/stores/useAppStore.ts +1265 -0
- package/visual-app-builder/src/tailwindGeneratedSafelist.ts +36 -0
- package/visual-app-builder/src/types/index.ts +261 -0
- package/visual-app-builder/src/utils/codegen.ts +66 -0
- package/visual-app-builder/src/utils/projectFiles.ts +146 -0
- package/visual-app-builder/src/utils/projectPersistence.ts +177 -0
- package/visual-app-builder/vite.config.ts +1479 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import type { PrimitiveDefinition, PrimitiveType, PropSchema } from '../types'
|
|
2
|
+
|
|
3
|
+
const commonProps = {
|
|
4
|
+
id: { type: 'string', label: 'ID', default: '' },
|
|
5
|
+
className: { type: 'string', label: 'Tailwind classes', default: '' },
|
|
6
|
+
} as const
|
|
7
|
+
|
|
8
|
+
const textProp = { type: 'string', label: 'Text', default: 'Text' } as const
|
|
9
|
+
const textAreaProp = { type: 'text', label: 'Text', default: 'Text' } as const
|
|
10
|
+
|
|
11
|
+
function node(
|
|
12
|
+
type: PrimitiveType,
|
|
13
|
+
category: string,
|
|
14
|
+
description: string,
|
|
15
|
+
defaultProps: Record<string, unknown> = {},
|
|
16
|
+
propSchema: Record<string, PropSchema> = commonProps,
|
|
17
|
+
acceptsChildren = true
|
|
18
|
+
): PrimitiveDefinition {
|
|
19
|
+
return {
|
|
20
|
+
type,
|
|
21
|
+
label: type,
|
|
22
|
+
category,
|
|
23
|
+
icon: type,
|
|
24
|
+
description,
|
|
25
|
+
defaultProps,
|
|
26
|
+
propSchema,
|
|
27
|
+
acceptsChildren,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function textNode(
|
|
32
|
+
type: PrimitiveType,
|
|
33
|
+
category: string,
|
|
34
|
+
description: string,
|
|
35
|
+
text: string,
|
|
36
|
+
className = ''
|
|
37
|
+
): PrimitiveDefinition {
|
|
38
|
+
return node(
|
|
39
|
+
type,
|
|
40
|
+
category,
|
|
41
|
+
description,
|
|
42
|
+
{ text, className },
|
|
43
|
+
{
|
|
44
|
+
text: { ...textProp, default: text },
|
|
45
|
+
...commonProps,
|
|
46
|
+
},
|
|
47
|
+
false
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const primitiveRegistry: Record<PrimitiveType, PrimitiveDefinition> = {
|
|
52
|
+
header: node('header', 'Semantic', 'Introductory page or section content', {
|
|
53
|
+
className: 'w-full',
|
|
54
|
+
}),
|
|
55
|
+
nav: node('nav', 'Semantic', 'Navigation region', {
|
|
56
|
+
className: 'flex items-center justify-between px-6 py-3 bg-gray-900 text-white',
|
|
57
|
+
}),
|
|
58
|
+
main: node('main', 'Semantic', 'Primary page content', {
|
|
59
|
+
className: 'w-full min-h-screen',
|
|
60
|
+
}),
|
|
61
|
+
section: node('section', 'Semantic', 'Standalone page section', {
|
|
62
|
+
className: 'w-full px-6 py-10',
|
|
63
|
+
}),
|
|
64
|
+
article: node('article', 'Semantic', 'Self-contained content region', {
|
|
65
|
+
className: 'w-full bg-white border border-gray-200 p-5 shadow-sm',
|
|
66
|
+
}),
|
|
67
|
+
aside: node('aside', 'Semantic', 'Secondary sidebar content', {
|
|
68
|
+
className: 'w-full',
|
|
69
|
+
}),
|
|
70
|
+
footer: node('footer', 'Semantic', 'Footer region', {
|
|
71
|
+
className: 'w-full bg-gray-900 text-gray-400 text-center py-4 text-xs',
|
|
72
|
+
}),
|
|
73
|
+
address: textNode(
|
|
74
|
+
'address',
|
|
75
|
+
'Semantic',
|
|
76
|
+
'Contact information',
|
|
77
|
+
'Contact information',
|
|
78
|
+
'not-italic'
|
|
79
|
+
),
|
|
80
|
+
hgroup: node('hgroup', 'Semantic', 'Grouped heading content', {
|
|
81
|
+
className: 'space-y-2',
|
|
82
|
+
}),
|
|
83
|
+
|
|
84
|
+
div: node('div', 'Layout', 'Generic layout box', {
|
|
85
|
+
className: 'w-full min-h-12',
|
|
86
|
+
}),
|
|
87
|
+
span: textNode('span', 'Layout', 'Inline text wrapper', 'Inline text', 'text-sm'),
|
|
88
|
+
|
|
89
|
+
h1: textNode('h1', 'Text', 'Main heading', 'Heading', 'text-3xl font-bold'),
|
|
90
|
+
h2: textNode(
|
|
91
|
+
'h2',
|
|
92
|
+
'Text',
|
|
93
|
+
'Section heading',
|
|
94
|
+
'Section heading',
|
|
95
|
+
'text-2xl font-semibold'
|
|
96
|
+
),
|
|
97
|
+
h3: textNode('h3', 'Text', 'Small heading', 'Small heading', 'text-xl font-semibold'),
|
|
98
|
+
h4: textNode('h4', 'Text', 'Fourth-level heading', 'Heading', 'text-lg font-semibold'),
|
|
99
|
+
h5: textNode('h5', 'Text', 'Fifth-level heading', 'Heading', 'text-base font-semibold'),
|
|
100
|
+
h6: textNode('h6', 'Text', 'Sixth-level heading', 'Heading', 'text-sm font-semibold'),
|
|
101
|
+
p: node(
|
|
102
|
+
'p',
|
|
103
|
+
'Text',
|
|
104
|
+
'Paragraph text',
|
|
105
|
+
{ text: 'Paragraph text', className: 'text-sm text-gray-600' },
|
|
106
|
+
{
|
|
107
|
+
text: { ...textAreaProp, default: 'Paragraph text' },
|
|
108
|
+
...commonProps,
|
|
109
|
+
},
|
|
110
|
+
false
|
|
111
|
+
),
|
|
112
|
+
br: node('br', 'Text', 'Line break', {}, commonProps, false),
|
|
113
|
+
hr: node('hr', 'Text', 'Thematic divider', { className: 'border-gray-200' }, commonProps, false),
|
|
114
|
+
pre: textNode('pre', 'Text', 'Preformatted text', 'Preformatted text', 'font-mono text-sm'),
|
|
115
|
+
blockquote: textNode(
|
|
116
|
+
'blockquote',
|
|
117
|
+
'Text',
|
|
118
|
+
'Quoted block',
|
|
119
|
+
'Quote text',
|
|
120
|
+
'border-l-4 border-gray-300 pl-4 italic'
|
|
121
|
+
),
|
|
122
|
+
strong: textNode('strong', 'Text', 'Strong importance', 'Strong text', 'font-bold'),
|
|
123
|
+
b: textNode('b', 'Text', 'Bold text', 'Bold text', 'font-bold'),
|
|
124
|
+
em: textNode('em', 'Text', 'Emphasized text', 'Emphasized text', 'italic'),
|
|
125
|
+
i: textNode('i', 'Text', 'Italic text', 'Italic text', 'italic'),
|
|
126
|
+
u: textNode('u', 'Text', 'Underlined text', 'Underlined text', 'underline'),
|
|
127
|
+
s: textNode('s', 'Text', 'Struck-through text', 'Struck text', 'line-through'),
|
|
128
|
+
small: textNode('small', 'Text', 'Small print text', 'Small text', 'text-xs'),
|
|
129
|
+
mark: textNode('mark', 'Text', 'Highlighted text', 'Highlighted text', 'bg-yellow-200'),
|
|
130
|
+
sub: textNode('sub', 'Text', 'Subscript text', 'subscript'),
|
|
131
|
+
sup: textNode('sup', 'Text', 'Superscript text', 'superscript'),
|
|
132
|
+
code: textNode('code', 'Text', 'Inline code', 'code', 'font-mono text-sm'),
|
|
133
|
+
kbd: textNode('kbd', 'Text', 'Keyboard input', 'Ctrl K', 'font-mono text-xs'),
|
|
134
|
+
samp: textNode('samp', 'Text', 'Sample output', 'Sample output', 'font-mono text-sm'),
|
|
135
|
+
var: textNode('var', 'Text', 'Variable text', 'variable', 'italic'),
|
|
136
|
+
abbr: textNode('abbr', 'Text', 'Abbreviation', 'HTML'),
|
|
137
|
+
cite: textNode('cite', 'Text', 'Citation title', 'Citation', 'italic'),
|
|
138
|
+
q: textNode('q', 'Text', 'Inline quotation', 'Inline quote'),
|
|
139
|
+
time: textNode('time', 'Text', 'Time or date', '2026-07-10'),
|
|
140
|
+
|
|
141
|
+
a: node(
|
|
142
|
+
'a',
|
|
143
|
+
'Links & Lists',
|
|
144
|
+
'Anchor link',
|
|
145
|
+
{ text: 'Link', href: '#', target: '_self', className: 'text-sm text-blue-600' },
|
|
146
|
+
{
|
|
147
|
+
text: { type: 'string', label: 'Text', default: 'Link' },
|
|
148
|
+
href: { type: 'string', label: 'Href', default: '#' },
|
|
149
|
+
target: {
|
|
150
|
+
type: 'select',
|
|
151
|
+
label: 'Target',
|
|
152
|
+
default: '_self',
|
|
153
|
+
options: ['_self', '_blank'],
|
|
154
|
+
},
|
|
155
|
+
...commonProps,
|
|
156
|
+
},
|
|
157
|
+
false
|
|
158
|
+
),
|
|
159
|
+
ul: node('ul', 'Links & Lists', 'Unordered list', { className: 'list-disc pl-6' }),
|
|
160
|
+
ol: node('ol', 'Links & Lists', 'Ordered list', { className: 'list-decimal pl-6' }),
|
|
161
|
+
li: textNode('li', 'Links & Lists', 'List item', 'List item'),
|
|
162
|
+
dl: node('dl', 'Links & Lists', 'Description list', { className: 'space-y-2' }),
|
|
163
|
+
dt: textNode('dt', 'Links & Lists', 'Description term', 'Term', 'font-semibold'),
|
|
164
|
+
dd: textNode('dd', 'Links & Lists', 'Description details', 'Description', 'ml-4'),
|
|
165
|
+
menu: node('menu', 'Links & Lists', 'Menu list', { className: 'flex gap-2' }),
|
|
166
|
+
|
|
167
|
+
img: node(
|
|
168
|
+
'img',
|
|
169
|
+
'Media',
|
|
170
|
+
'Image element',
|
|
171
|
+
{ src: '', alt: '', className: 'max-w-full' },
|
|
172
|
+
{
|
|
173
|
+
src: { type: 'string', label: 'Source', default: '' },
|
|
174
|
+
alt: { type: 'string', label: 'Alt text', default: '' },
|
|
175
|
+
...commonProps,
|
|
176
|
+
},
|
|
177
|
+
false
|
|
178
|
+
),
|
|
179
|
+
picture: node('picture', 'Media', 'Responsive image wrapper'),
|
|
180
|
+
source: node(
|
|
181
|
+
'source',
|
|
182
|
+
'Media',
|
|
183
|
+
'Media source',
|
|
184
|
+
{ src: '', type: '' },
|
|
185
|
+
{
|
|
186
|
+
src: { type: 'string', label: 'Source', default: '' },
|
|
187
|
+
type: { type: 'string', label: 'MIME type', default: '' },
|
|
188
|
+
...commonProps,
|
|
189
|
+
},
|
|
190
|
+
false
|
|
191
|
+
),
|
|
192
|
+
figure: node('figure', 'Media', 'Figure with optional caption', {
|
|
193
|
+
className: 'w-full',
|
|
194
|
+
}),
|
|
195
|
+
figcaption: textNode('figcaption', 'Media', 'Figure caption', 'Caption', 'text-sm text-gray-500'),
|
|
196
|
+
video: node(
|
|
197
|
+
'video',
|
|
198
|
+
'Media',
|
|
199
|
+
'Video player',
|
|
200
|
+
{ src: '', controls: true, className: 'w-full' },
|
|
201
|
+
{
|
|
202
|
+
src: { type: 'string', label: 'Source', default: '' },
|
|
203
|
+
controls: { type: 'boolean', label: 'Controls', default: true },
|
|
204
|
+
...commonProps,
|
|
205
|
+
},
|
|
206
|
+
false
|
|
207
|
+
),
|
|
208
|
+
audio: node(
|
|
209
|
+
'audio',
|
|
210
|
+
'Media',
|
|
211
|
+
'Audio player',
|
|
212
|
+
{ src: '', controls: true },
|
|
213
|
+
{
|
|
214
|
+
src: { type: 'string', label: 'Source', default: '' },
|
|
215
|
+
controls: { type: 'boolean', label: 'Controls', default: true },
|
|
216
|
+
...commonProps,
|
|
217
|
+
},
|
|
218
|
+
false
|
|
219
|
+
),
|
|
220
|
+
iframe: node(
|
|
221
|
+
'iframe',
|
|
222
|
+
'Media',
|
|
223
|
+
'Embedded frame',
|
|
224
|
+
{ src: '', title: 'Embedded content', className: 'w-full aspect-video' },
|
|
225
|
+
{
|
|
226
|
+
src: { type: 'string', label: 'Source', default: '' },
|
|
227
|
+
title: { type: 'string', label: 'Title', default: 'Embedded content' },
|
|
228
|
+
...commonProps,
|
|
229
|
+
},
|
|
230
|
+
false
|
|
231
|
+
),
|
|
232
|
+
canvas: node('canvas', 'Media', 'Canvas drawing surface', { className: 'w-full min-h-48' }, commonProps, false),
|
|
233
|
+
svg: node('svg', 'Media', 'Inline SVG container', { className: 'w-6 h-6' }),
|
|
234
|
+
|
|
235
|
+
form: node('form', 'Forms', 'Form container', { className: 'space-y-4' }),
|
|
236
|
+
label: node(
|
|
237
|
+
'label',
|
|
238
|
+
'Forms',
|
|
239
|
+
'Form label',
|
|
240
|
+
{ text: 'Label', htmlFor: '', className: 'text-sm font-medium' },
|
|
241
|
+
{
|
|
242
|
+
text: { type: 'string', label: 'Text', default: 'Label' },
|
|
243
|
+
htmlFor: { type: 'string', label: 'For', default: '' },
|
|
244
|
+
...commonProps,
|
|
245
|
+
},
|
|
246
|
+
false
|
|
247
|
+
),
|
|
248
|
+
input: node(
|
|
249
|
+
'input',
|
|
250
|
+
'Forms',
|
|
251
|
+
'Text input',
|
|
252
|
+
{ type: 'text', name: '', placeholder: 'Enter text', className: 'w-full border border-gray-300 px-3 py-2' },
|
|
253
|
+
{
|
|
254
|
+
type: { type: 'string', label: 'Type', default: 'text' },
|
|
255
|
+
name: { type: 'string', label: 'Name', default: '' },
|
|
256
|
+
placeholder: { type: 'string', label: 'Placeholder', default: 'Enter text' },
|
|
257
|
+
...commonProps,
|
|
258
|
+
},
|
|
259
|
+
false
|
|
260
|
+
),
|
|
261
|
+
textarea: node(
|
|
262
|
+
'textarea',
|
|
263
|
+
'Forms',
|
|
264
|
+
'Multiline text input',
|
|
265
|
+
{ text: '', name: '', placeholder: 'Enter text', className: 'w-full min-h-24 border border-gray-300 px-3 py-2' },
|
|
266
|
+
{
|
|
267
|
+
text: { ...textAreaProp, default: '' },
|
|
268
|
+
name: { type: 'string', label: 'Name', default: '' },
|
|
269
|
+
placeholder: { type: 'string', label: 'Placeholder', default: 'Enter text' },
|
|
270
|
+
...commonProps,
|
|
271
|
+
},
|
|
272
|
+
false
|
|
273
|
+
),
|
|
274
|
+
button: node(
|
|
275
|
+
'button',
|
|
276
|
+
'Forms',
|
|
277
|
+
'Native button',
|
|
278
|
+
{ text: 'Button', type: 'button', className: 'px-4 py-2 rounded bg-gray-900 text-white text-sm' },
|
|
279
|
+
{
|
|
280
|
+
text: { type: 'string', label: 'Text', default: 'Button' },
|
|
281
|
+
type: {
|
|
282
|
+
type: 'select',
|
|
283
|
+
label: 'Type',
|
|
284
|
+
default: 'button',
|
|
285
|
+
options: ['button', 'submit', 'reset'],
|
|
286
|
+
},
|
|
287
|
+
...commonProps,
|
|
288
|
+
},
|
|
289
|
+
false
|
|
290
|
+
),
|
|
291
|
+
select: node('select', 'Forms', 'Select input', {
|
|
292
|
+
className: 'w-full border border-gray-300 px-3 py-2',
|
|
293
|
+
}),
|
|
294
|
+
option: node(
|
|
295
|
+
'option',
|
|
296
|
+
'Forms',
|
|
297
|
+
'Select option',
|
|
298
|
+
{ text: 'Option', value: '' },
|
|
299
|
+
{
|
|
300
|
+
text: { type: 'string', label: 'Text', default: 'Option' },
|
|
301
|
+
value: { type: 'string', label: 'Value', default: '' },
|
|
302
|
+
...commonProps,
|
|
303
|
+
},
|
|
304
|
+
false
|
|
305
|
+
),
|
|
306
|
+
optgroup: node(
|
|
307
|
+
'optgroup',
|
|
308
|
+
'Forms',
|
|
309
|
+
'Option group',
|
|
310
|
+
{ label: 'Group' },
|
|
311
|
+
{
|
|
312
|
+
label: { type: 'string', label: 'Label', default: 'Group' },
|
|
313
|
+
...commonProps,
|
|
314
|
+
}
|
|
315
|
+
),
|
|
316
|
+
fieldset: node('fieldset', 'Forms', 'Grouped form fields', {
|
|
317
|
+
className: 'border border-gray-300 p-4',
|
|
318
|
+
}),
|
|
319
|
+
legend: textNode('legend', 'Forms', 'Fieldset legend', 'Legend', 'px-1 text-sm font-medium'),
|
|
320
|
+
datalist: node('datalist', 'Forms', 'Autocomplete options'),
|
|
321
|
+
output: textNode('output', 'Forms', 'Calculation output', 'Output'),
|
|
322
|
+
progress: node(
|
|
323
|
+
'progress',
|
|
324
|
+
'Forms',
|
|
325
|
+
'Progress indicator',
|
|
326
|
+
{ value: 40, max: 100, className: 'w-full' },
|
|
327
|
+
{
|
|
328
|
+
value: { type: 'number', label: 'Value', default: 40 },
|
|
329
|
+
max: { type: 'number', label: 'Max', default: 100 },
|
|
330
|
+
...commonProps,
|
|
331
|
+
},
|
|
332
|
+
false
|
|
333
|
+
),
|
|
334
|
+
meter: node(
|
|
335
|
+
'meter',
|
|
336
|
+
'Forms',
|
|
337
|
+
'Scalar measurement',
|
|
338
|
+
{ value: 40, min: 0, max: 100, className: 'w-full' },
|
|
339
|
+
{
|
|
340
|
+
value: { type: 'number', label: 'Value', default: 40 },
|
|
341
|
+
min: { type: 'number', label: 'Min', default: 0 },
|
|
342
|
+
max: { type: 'number', label: 'Max', default: 100 },
|
|
343
|
+
...commonProps,
|
|
344
|
+
},
|
|
345
|
+
false
|
|
346
|
+
),
|
|
347
|
+
|
|
348
|
+
table: node('table', 'Tables', 'Table', { className: 'w-full border-collapse' }),
|
|
349
|
+
caption: textNode('caption', 'Tables', 'Table caption', 'Caption', 'caption-top text-sm'),
|
|
350
|
+
thead: node('thead', 'Tables', 'Table header group'),
|
|
351
|
+
tbody: node('tbody', 'Tables', 'Table body group'),
|
|
352
|
+
tfoot: node('tfoot', 'Tables', 'Table footer group'),
|
|
353
|
+
tr: node('tr', 'Tables', 'Table row'),
|
|
354
|
+
th: textNode('th', 'Tables', 'Header cell', 'Header', 'border px-3 py-2 text-left font-semibold'),
|
|
355
|
+
td: textNode('td', 'Tables', 'Table cell', 'Cell', 'border px-3 py-2'),
|
|
356
|
+
colgroup: node('colgroup', 'Tables', 'Column group'),
|
|
357
|
+
col: node('col', 'Tables', 'Table column', {}, commonProps, false),
|
|
358
|
+
|
|
359
|
+
details: node('details', 'Interactive', 'Disclosure container', {
|
|
360
|
+
className: 'w-full',
|
|
361
|
+
}),
|
|
362
|
+
summary: textNode('summary', 'Interactive', 'Disclosure summary', 'Summary', 'cursor-pointer'),
|
|
363
|
+
dialog: node('dialog', 'Interactive', 'Dialog element', {
|
|
364
|
+
className: 'rounded border border-gray-200 p-4',
|
|
365
|
+
}),
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export const primitives = Object.values(primitiveRegistry)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
@import "tailwindcss" source(none);
|
|
2
|
+
@source ".";
|
|
3
|
+
@source "../.visualbuild-runtime-classes.html";
|
|
4
|
+
|
|
5
|
+
*,
|
|
6
|
+
*::before,
|
|
7
|
+
*::after {
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
html,
|
|
12
|
+
body,
|
|
13
|
+
#root {
|
|
14
|
+
width: 100%;
|
|
15
|
+
height: 100%;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
body {
|
|
20
|
+
font-family: "Inter", system-ui, sans-serif;
|
|
21
|
+
-webkit-font-smoothing: antialiased;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
[data-vb-editor-node="true"] {
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
[data-vb-editor-node="true"]:hover,
|
|
29
|
+
[data-vb-hovered="true"] {
|
|
30
|
+
outline: 2px solid rgb(96 165 250 / 0.95) !important;
|
|
31
|
+
outline-offset: -2px;
|
|
32
|
+
box-shadow: 0 0 0 1px rgb(96 165 250 / 0.25);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
[data-vb-selected="true"] {
|
|
36
|
+
outline: 2px solid rgb(37 99 235) !important;
|
|
37
|
+
outline-offset: -2px;
|
|
38
|
+
box-shadow: 0 0 0 1px rgb(37 99 235 / 0.25);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
[data-vb-drop-target="true"] {
|
|
42
|
+
outline: 2px solid rgb(59 130 246) !important;
|
|
43
|
+
outline-offset: -2px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
[data-vb-dragging="true"] {
|
|
47
|
+
cursor: grabbing;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.vb-empty-node-placeholder {
|
|
51
|
+
pointer-events: none;
|
|
52
|
+
display: flex;
|
|
53
|
+
min-height: 2rem;
|
|
54
|
+
width: 100%;
|
|
55
|
+
align-items: center;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
border: 1px dashed rgb(147 197 253 / 0.85);
|
|
58
|
+
border-radius: 6px;
|
|
59
|
+
background: rgb(239 246 255 / 0.72);
|
|
60
|
+
color: rgb(37 99 235);
|
|
61
|
+
font-size: 11px;
|
|
62
|
+
font-weight: 500;
|
|
63
|
+
line-height: 1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.vb-canvas-editor-frame {
|
|
67
|
+
outline: 1px solid rgb(229 231 235);
|
|
68
|
+
outline-offset: -1px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.vb-canvas-editor-frame[data-vb-canvas-over="true"] {
|
|
72
|
+
outline: 2px solid rgb(59 130 246);
|
|
73
|
+
outline-offset: -2px;
|
|
74
|
+
box-shadow: inset 0 0 0 2px rgb(147 197 253 / 0.45);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
select option {
|
|
78
|
+
color: #111827;
|
|
79
|
+
background: #ffffff;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Scrollbars */
|
|
83
|
+
|
|
84
|
+
::-webkit-scrollbar {
|
|
85
|
+
width: 4px;
|
|
86
|
+
height: 4px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
::-webkit-scrollbar-track {
|
|
90
|
+
background: transparent;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
::-webkit-scrollbar-thumb {
|
|
94
|
+
background: #2d3139;
|
|
95
|
+
border-radius: 999px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
::-webkit-scrollbar-thumb:hover {
|
|
99
|
+
background: #3d4249;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@theme {
|
|
104
|
+
--color-canvas: #f8f9fa;
|
|
105
|
+
--color-sidebar: #1a1d23;
|
|
106
|
+
--color-panel: #1a1d23;
|
|
107
|
+
--color-topbar: #13151a;
|
|
108
|
+
|
|
109
|
+
--color-accent: #4f6ef7;
|
|
110
|
+
--color-accent-hover: #3d5ce0;
|
|
111
|
+
}
|