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,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from 'node:child_process'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
|
|
7
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
8
|
+
const targetAppDir = path.resolve(process.argv[2] ?? packageRoot)
|
|
9
|
+
const viteBin = path.join(packageRoot, 'node_modules', 'vite', 'bin', 'vite.js')
|
|
10
|
+
const viteConfig = path.join(packageRoot, 'visual-app-builder', 'vite.config.ts')
|
|
11
|
+
|
|
12
|
+
const child = spawn(
|
|
13
|
+
process.execPath,
|
|
14
|
+
[viteBin, '--config', viteConfig, '--host', '127.0.0.1', '--port', '7371'],
|
|
15
|
+
{
|
|
16
|
+
cwd: packageRoot,
|
|
17
|
+
env: {
|
|
18
|
+
...process.env,
|
|
19
|
+
VISUALBUILD_APP_DIR: targetAppDir,
|
|
20
|
+
},
|
|
21
|
+
stdio: 'inherit',
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
child.on('exit', (code, signal) => {
|
|
26
|
+
if (signal) {
|
|
27
|
+
process.kill(process.pid, signal)
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
process.exit(code ?? 0)
|
|
32
|
+
})
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import {
|
|
4
|
+
generateAppSource,
|
|
5
|
+
generateLayoutSource,
|
|
6
|
+
generatePageSource,
|
|
7
|
+
getPageSourcePath,
|
|
8
|
+
normalizeProjectPath,
|
|
9
|
+
} from '../visual-app-builder/shared/generateReactSource.mjs'
|
|
10
|
+
|
|
11
|
+
const root = path.resolve(process.argv[2] ?? process.cwd())
|
|
12
|
+
const schemaPath = path.join(root, 'visualbuild', 'pages.json')
|
|
13
|
+
const outputRoot = path.join(root, 'src')
|
|
14
|
+
const manifestPath = path.join(root, 'visualbuild', 'generated-files.json')
|
|
15
|
+
const diagnosticMarker = 'VISUALBUILD_DIAGNOSTIC:'
|
|
16
|
+
|
|
17
|
+
class GeneratorDiagnosticError extends Error {
|
|
18
|
+
constructor(code, message, suggestion) {
|
|
19
|
+
super(message)
|
|
20
|
+
this.name = 'GeneratorDiagnosticError'
|
|
21
|
+
this.code = code
|
|
22
|
+
this.suggestion = suggestion
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function validatePages(pages) {
|
|
27
|
+
const seenRoutes = new Set()
|
|
28
|
+
const seenSourcePaths = new Set()
|
|
29
|
+
|
|
30
|
+
for (const page of pages) {
|
|
31
|
+
if (!page.name || typeof page.name !== 'string') {
|
|
32
|
+
throw new GeneratorDiagnosticError(
|
|
33
|
+
'INVALID_PAGE_NAME',
|
|
34
|
+
'Every page needs a name.',
|
|
35
|
+
'Give each page a non-empty name in the page manager.'
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!page.route || typeof page.route !== 'string') {
|
|
40
|
+
throw new GeneratorDiagnosticError(
|
|
41
|
+
'MISSING_PAGE_ROUTE',
|
|
42
|
+
`Page "${page.name}" needs a route.`,
|
|
43
|
+
'Add a route in the page manager before saving.'
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!page.route.startsWith('/')) {
|
|
48
|
+
throw new GeneratorDiagnosticError(
|
|
49
|
+
'INVALID_PAGE_ROUTE',
|
|
50
|
+
`Route "${page.route}" must start with "/".`,
|
|
51
|
+
`Change the route to "/${page.route.replace(/^\/+/, '')}".`
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (seenRoutes.has(page.route)) {
|
|
56
|
+
throw new GeneratorDiagnosticError(
|
|
57
|
+
'DUPLICATE_PAGE_ROUTE',
|
|
58
|
+
`Duplicate route found: ${page.route}`,
|
|
59
|
+
'Give every registered page a unique route.'
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const sourcePath = getPageSourcePath(page)
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
!sourcePath.startsWith('src/') ||
|
|
67
|
+
!/\.(jsx|tsx)$/i.test(sourcePath) ||
|
|
68
|
+
sourcePath.includes('/../') ||
|
|
69
|
+
sourcePath.endsWith('/..')
|
|
70
|
+
) {
|
|
71
|
+
throw new GeneratorDiagnosticError(
|
|
72
|
+
'INVALID_PAGE_SOURCE_PATH',
|
|
73
|
+
`Page "${page.name}" needs a .jsx or .tsx sourcePath inside src.`,
|
|
74
|
+
'Move the page source under src and use a .jsx or .tsx extension.'
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (
|
|
79
|
+
sourcePath === 'src/App.tsx' ||
|
|
80
|
+
sourcePath === 'src/layouts/AppLayout.tsx'
|
|
81
|
+
) {
|
|
82
|
+
throw new GeneratorDiagnosticError(
|
|
83
|
+
'RESERVED_PAGE_SOURCE_PATH',
|
|
84
|
+
`Page source path is reserved: ${sourcePath}`,
|
|
85
|
+
'Choose a page file that does not replace App.tsx or AppLayout.tsx.'
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (seenSourcePaths.has(sourcePath)) {
|
|
90
|
+
throw new GeneratorDiagnosticError(
|
|
91
|
+
'DUPLICATE_PAGE_SOURCE_PATH',
|
|
92
|
+
`Duplicate page source path found: ${sourcePath}`,
|
|
93
|
+
'Give every registered page its own source file.'
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
seenRoutes.add(page.route)
|
|
98
|
+
seenSourcePaths.add(sourcePath)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function writeFile(filePath, contents) {
|
|
103
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
|
104
|
+
await fs.writeFile(filePath, contents)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getManagedFilePath(relativePath) {
|
|
108
|
+
const normalizedPath = normalizeProjectPath(relativePath)
|
|
109
|
+
const absolutePath = path.resolve(root, ...normalizedPath.split('/'))
|
|
110
|
+
const relativeToRoot = path.relative(root, absolutePath)
|
|
111
|
+
|
|
112
|
+
if (
|
|
113
|
+
!normalizedPath ||
|
|
114
|
+
relativeToRoot.startsWith('..') ||
|
|
115
|
+
path.isAbsolute(relativeToRoot)
|
|
116
|
+
) {
|
|
117
|
+
throw new GeneratorDiagnosticError(
|
|
118
|
+
'UNSAFE_GENERATED_PATH',
|
|
119
|
+
`Generated file cannot leave the project: ${relativePath}`,
|
|
120
|
+
'Use a project-relative source path inside src.'
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return absolutePath
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function readGeneratedManifest() {
|
|
128
|
+
try {
|
|
129
|
+
const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'))
|
|
130
|
+
|
|
131
|
+
return Array.isArray(manifest.files)
|
|
132
|
+
? manifest.files.map(normalizeProjectPath)
|
|
133
|
+
: []
|
|
134
|
+
} catch {
|
|
135
|
+
return []
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function writeGeneratedManifest(files) {
|
|
140
|
+
await writeFile(
|
|
141
|
+
manifestPath,
|
|
142
|
+
`${JSON.stringify({ files: [...files].sort() }, null, 2)}\n`
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function main() {
|
|
147
|
+
const rawSchema = await fs.readFile(schemaPath, 'utf8')
|
|
148
|
+
const schema = JSON.parse(rawSchema)
|
|
149
|
+
const pages = schema.pages ?? []
|
|
150
|
+
const appShell = schema.appShell ?? { header: null, footer: null }
|
|
151
|
+
|
|
152
|
+
validatePages(pages)
|
|
153
|
+
|
|
154
|
+
await fs.mkdir(outputRoot, { recursive: true })
|
|
155
|
+
const previousManagedFiles = await readGeneratedManifest()
|
|
156
|
+
const nextManagedFiles = new Set([
|
|
157
|
+
'src/App.tsx',
|
|
158
|
+
...pages.map(getPageSourcePath),
|
|
159
|
+
])
|
|
160
|
+
|
|
161
|
+
if (appShell.header || appShell.footer) {
|
|
162
|
+
nextManagedFiles.add('src/layouts/AppLayout.tsx')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
for (const staleFile of previousManagedFiles) {
|
|
166
|
+
if (!nextManagedFiles.has(staleFile)) {
|
|
167
|
+
await fs.rm(getManagedFilePath(staleFile), { force: true })
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
for (const page of pages) {
|
|
172
|
+
await writeFile(
|
|
173
|
+
getManagedFilePath(getPageSourcePath(page)),
|
|
174
|
+
generatePageSource(page)
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (appShell.header || appShell.footer) {
|
|
179
|
+
await writeFile(
|
|
180
|
+
path.join(outputRoot, 'layouts', 'AppLayout.tsx'),
|
|
181
|
+
generateLayoutSource(appShell)
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
await writeFile(
|
|
186
|
+
path.join(outputRoot, 'App.tsx'),
|
|
187
|
+
generateAppSource(pages, appShell)
|
|
188
|
+
)
|
|
189
|
+
await writeGeneratedManifest(nextManagedFiles)
|
|
190
|
+
|
|
191
|
+
console.log(`Generated ${pages.length} page(s) into src`)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
main().catch((error) => {
|
|
195
|
+
const diagnostic = createGeneratorDiagnostic(error)
|
|
196
|
+
console.error(`${diagnosticMarker}${JSON.stringify(diagnostic)}`)
|
|
197
|
+
process.exit(1)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
function createGeneratorDiagnostic(error) {
|
|
201
|
+
const isInvalidJson = error instanceof SyntaxError
|
|
202
|
+
const message =
|
|
203
|
+
error instanceof Error ? error.message : 'React source generation failed.'
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
severity: 'error',
|
|
207
|
+
phase: 'generate',
|
|
208
|
+
code: isInvalidJson
|
|
209
|
+
? 'INVALID_SCHEMA_JSON'
|
|
210
|
+
: error instanceof GeneratorDiagnosticError
|
|
211
|
+
? error.code
|
|
212
|
+
: 'GENERATION_FAILED',
|
|
213
|
+
title: isInvalidJson
|
|
214
|
+
? 'Project schema is not valid JSON'
|
|
215
|
+
: 'React source generation failed',
|
|
216
|
+
message,
|
|
217
|
+
path: 'visualbuild/pages.json',
|
|
218
|
+
suggestion: isInvalidJson
|
|
219
|
+
? 'Fix the JSON syntax, then save again. The last generated React files were kept.'
|
|
220
|
+
: error instanceof GeneratorDiagnosticError
|
|
221
|
+
? error.suggestion
|
|
222
|
+
: 'Review the page schema and try again. The last generated React files were kept.',
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# __DISPLAY_NAME__
|
|
2
|
+
|
|
3
|
+
This is the deployable React application generated by VisualBuild. It contains
|
|
4
|
+
only the source and dependencies required to run the application.
|
|
5
|
+
|
|
6
|
+
## Run
|
|
7
|
+
|
|
8
|
+
```powershell
|
|
9
|
+
npm install
|
|
10
|
+
npm.cmd run dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Build
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
npm.cmd run build
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The visual schema lives in `visualbuild/pages.json`. The optional sibling
|
|
20
|
+
`visual-builder` project can edit this application visually and regenerate its
|
|
21
|
+
managed React files. This application remains runnable without that editor.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import globals from 'globals'
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
4
|
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
5
|
+
import tseslint from 'typescript-eslint'
|
|
6
|
+
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
7
|
+
|
|
8
|
+
export default defineConfig([
|
|
9
|
+
globalIgnores(['dist']),
|
|
10
|
+
{
|
|
11
|
+
files: ['**/*.{ts,tsx}'],
|
|
12
|
+
extends: [
|
|
13
|
+
js.configs.recommended,
|
|
14
|
+
tseslint.configs.recommended,
|
|
15
|
+
reactHooks.configs.flat.recommended,
|
|
16
|
+
reactRefresh.configs.vite,
|
|
17
|
+
],
|
|
18
|
+
languageOptions: {
|
|
19
|
+
globals: globals.browser,
|
|
20
|
+
parserOptions: {
|
|
21
|
+
tsconfigRootDir: import.meta.dirname,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
])
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>__DISPLAY_NAME__</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="root"></div>
|
|
13
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
*,
|
|
4
|
+
*::before,
|
|
5
|
+
*::after {
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
body {
|
|
10
|
+
margin: 0;
|
|
11
|
+
min-width: 320px;
|
|
12
|
+
min-height: 100vh;
|
|
13
|
+
font-family:
|
|
14
|
+
Inter,
|
|
15
|
+
system-ui,
|
|
16
|
+
-apple-system,
|
|
17
|
+
BlinkMacSystemFont,
|
|
18
|
+
"Segoe UI",
|
|
19
|
+
sans-serif;
|
|
20
|
+
background: #f8fafc;
|
|
21
|
+
color: #111827;
|
|
22
|
+
-webkit-font-smoothing: antialiased;
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
+
"target": "es2023",
|
|
5
|
+
"lib": ["ES2023", "DOM"],
|
|
6
|
+
"module": "esnext",
|
|
7
|
+
"types": ["vite/client"],
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"moduleResolution": "bundler",
|
|
10
|
+
"allowImportingTsExtensions": true,
|
|
11
|
+
"verbatimModuleSyntax": true,
|
|
12
|
+
"moduleDetection": "force",
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"erasableSyntaxOnly": true,
|
|
18
|
+
"noFallthroughCasesInSwitch": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["src"]
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
+
"target": "es2023",
|
|
5
|
+
"lib": ["ES2023"],
|
|
6
|
+
"types": ["node"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"module": "nodenext",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"noUnusedLocals": true,
|
|
14
|
+
"noUnusedParameters": true,
|
|
15
|
+
"erasableSyntaxOnly": true,
|
|
16
|
+
"noFallthroughCasesInSwitch": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["vite.config.ts"]
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# VisualBuild Editor
|
|
2
|
+
|
|
3
|
+
This package contains the optional VisualBuild editor and generator for the
|
|
4
|
+
sibling `__PROJECT_NAME__` React application.
|
|
5
|
+
|
|
6
|
+
## Run
|
|
7
|
+
|
|
8
|
+
```powershell
|
|
9
|
+
npm install
|
|
10
|
+
npm.cmd run visual-builder
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Generate Without Opening The Editor
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
npm.cmd run vb:generate
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The editor reads and writes `../__PROJECT_NAME__/visualbuild/pages.json` and
|
|
20
|
+
manages generated files in `../__PROJECT_NAME__/src`. It is intentionally
|
|
21
|
+
separate from the deployable application and does not need to be deployed.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import globals from 'globals'
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
4
|
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
5
|
+
import tseslint from 'typescript-eslint'
|
|
6
|
+
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
7
|
+
|
|
8
|
+
export default defineConfig([
|
|
9
|
+
globalIgnores(['dist']),
|
|
10
|
+
{
|
|
11
|
+
files: ['**/*.{ts,tsx}'],
|
|
12
|
+
extends: [
|
|
13
|
+
js.configs.recommended,
|
|
14
|
+
tseslint.configs.recommended,
|
|
15
|
+
reactHooks.configs.flat.recommended,
|
|
16
|
+
reactRefresh.configs.vite,
|
|
17
|
+
],
|
|
18
|
+
languageOptions: {
|
|
19
|
+
globals: globals.browser,
|
|
20
|
+
parserOptions: {
|
|
21
|
+
tsconfigRootDir: import.meta.dirname,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
])
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
+
"target": "es2023",
|
|
5
|
+
"lib": ["ES2023", "DOM"],
|
|
6
|
+
"module": "esnext",
|
|
7
|
+
"types": ["vite/client"],
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"moduleResolution": "bundler",
|
|
10
|
+
"allowImportingTsExtensions": true,
|
|
11
|
+
"verbatimModuleSyntax": true,
|
|
12
|
+
"moduleDetection": "force",
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"erasableSyntaxOnly": true,
|
|
18
|
+
"noFallthroughCasesInSwitch": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["visual-app-builder/src"]
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
+
"target": "es2023",
|
|
5
|
+
"lib": ["ES2023"],
|
|
6
|
+
"types": ["node"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"module": "nodenext",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"noUnusedLocals": true,
|
|
14
|
+
"noUnusedParameters": true,
|
|
15
|
+
"erasableSyntaxOnly": true,
|
|
16
|
+
"noFallthroughCasesInSwitch": true
|
|
17
|
+
},
|
|
18
|
+
"include": [
|
|
19
|
+
"visual-app-builder/vite.config.ts",
|
|
20
|
+
"visual-app-builder/server/**/*.ts"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>VisualBuild</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="root"></div>
|
|
13
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|