create-quadrokit 0.1.0 → 0.2.1
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 +10 -6
- package/biome.monorepo.json +67 -0
- package/dist/index.mjs +361 -0
- package/package.json +10 -4
- package/templates/README.md +39 -0
- package/templates/admin-shell/.cursor/rules/commitlint-conventional.mdc +47 -0
- package/templates/admin-shell/.env.example +2 -0
- package/templates/admin-shell/biome.json +12 -0
- package/templates/admin-shell/index.html +12 -0
- package/templates/admin-shell/package.json +46 -0
- package/templates/admin-shell/postcss.config.js +6 -0
- package/templates/admin-shell/src/components/AppShell.tsx +68 -0
- package/templates/admin-shell/src/i18n.ts +12 -0
- package/templates/admin-shell/src/lib/quadro-client.ts +4 -0
- package/templates/admin-shell/src/locales/en.json +15 -0
- package/templates/admin-shell/src/main.tsx +15 -0
- package/templates/admin-shell/src/pages/AgenciesPage.tsx +69 -0
- package/templates/admin-shell/src/pages/HomePage.tsx +67 -0
- package/templates/admin-shell/src/router.tsx +15 -0
- package/templates/admin-shell/src/stores/useSidebarHint.ts +12 -0
- package/templates/admin-shell/src/vite-env.d.ts +9 -0
- package/templates/admin-shell/tailwind.config.ts +7 -0
- package/templates/admin-shell/tsconfig.app.json +16 -0
- package/templates/admin-shell/tsconfig.json +4 -0
- package/templates/admin-shell/tsconfig.node.json +10 -0
- package/templates/admin-shell/vite.config.ts +25 -0
- package/templates/dashboard/.cursor/rules/commitlint-conventional.mdc +47 -0
- package/templates/dashboard/.env.example +2 -0
- package/templates/dashboard/biome.json +12 -0
- package/templates/dashboard/index.html +12 -0
- package/templates/dashboard/package.json +46 -0
- package/templates/dashboard/postcss.config.js +6 -0
- package/templates/dashboard/src/components/AppShell.tsx +44 -0
- package/templates/dashboard/src/i18n.ts +12 -0
- package/templates/dashboard/src/lib/quadro-client.ts +4 -0
- package/templates/dashboard/src/locales/en.json +15 -0
- package/templates/dashboard/src/main.tsx +15 -0
- package/templates/dashboard/src/pages/AgenciesPage.tsx +69 -0
- package/templates/dashboard/src/pages/HomePage.tsx +67 -0
- package/templates/dashboard/src/router.tsx +15 -0
- package/templates/dashboard/src/stores/useSidebarHint.ts +12 -0
- package/templates/dashboard/src/vite-env.d.ts +9 -0
- package/templates/dashboard/tailwind.config.ts +7 -0
- package/templates/dashboard/tsconfig.app.json +16 -0
- package/templates/dashboard/tsconfig.json +4 -0
- package/templates/dashboard/tsconfig.node.json +10 -0
- package/templates/dashboard/vite.config.ts +25 -0
- package/templates/ecommerce/.cursor/rules/commitlint-conventional.mdc +47 -0
- package/templates/ecommerce/.env.example +2 -0
- package/templates/ecommerce/biome.json +12 -0
- package/templates/ecommerce/index.html +12 -0
- package/templates/ecommerce/package.json +46 -0
- package/templates/ecommerce/postcss.config.js +6 -0
- package/templates/ecommerce/src/components/AppShell.tsx +44 -0
- package/templates/ecommerce/src/i18n.ts +12 -0
- package/templates/ecommerce/src/lib/quadro-client.ts +4 -0
- package/templates/ecommerce/src/locales/en.json +20 -0
- package/templates/ecommerce/src/main.tsx +15 -0
- package/templates/ecommerce/src/pages/AgenciesPage.tsx +69 -0
- package/templates/ecommerce/src/pages/HomePage.tsx +52 -0
- package/templates/ecommerce/src/router.tsx +15 -0
- package/templates/ecommerce/src/stores/useSidebarHint.ts +12 -0
- package/templates/ecommerce/src/vite-env.d.ts +9 -0
- package/templates/ecommerce/tailwind.config.ts +7 -0
- package/templates/ecommerce/tsconfig.app.json +16 -0
- package/templates/ecommerce/tsconfig.json +4 -0
- package/templates/ecommerce/tsconfig.node.json +10 -0
- package/templates/ecommerce/vite.config.ts +25 -0
- package/templates/website/.cursor/rules/commitlint-conventional.mdc +47 -0
- package/templates/website/.env.example +2 -0
- package/templates/website/biome.json +12 -0
- package/templates/website/index.html +12 -0
- package/templates/website/package.json +46 -0
- package/templates/website/postcss.config.js +6 -0
- package/templates/website/src/components/AppShell.tsx +44 -0
- package/templates/website/src/i18n.ts +12 -0
- package/templates/website/src/lib/quadro-client.ts +4 -0
- package/templates/website/src/locales/en.json +21 -0
- package/templates/website/src/main.tsx +15 -0
- package/templates/website/src/pages/AgenciesPage.tsx +69 -0
- package/templates/website/src/pages/HomePage.tsx +83 -0
- package/templates/website/src/router.tsx +15 -0
- package/templates/website/src/stores/useSidebarHint.ts +12 -0
- package/templates/website/src/vite-env.d.ts +9 -0
- package/templates/website/tailwind.config.ts +7 -0
- package/templates/website/tsconfig.app.json +16 -0
- package/templates/website/tsconfig.json +4 -0
- package/templates/website/tsconfig.node.json +10 -0
- package/templates/website/vite.config.ts +25 -0
- package/src/index.ts +0 -237
- package/tsconfig.json +0 -9
package/src/index.ts
DELETED
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
import { cp, mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises'
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
import { fileURLToPath } from 'node:url'
|
|
5
|
-
import prompts from 'prompts'
|
|
6
|
-
|
|
7
|
-
const TEMPLATES = ['dashboard', 'website', 'ecommerce', 'admin-shell'] as const
|
|
8
|
-
type TemplateId = (typeof TEMPLATES)[number]
|
|
9
|
-
|
|
10
|
-
function repoRoot(): string {
|
|
11
|
-
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function parseArgs(argv: string[]) {
|
|
15
|
-
let template: TemplateId | undefined
|
|
16
|
-
let dir: string | undefined
|
|
17
|
-
let keepWorkspace = false
|
|
18
|
-
for (let i = 0; i < argv.length; i++) {
|
|
19
|
-
const a = argv[i]
|
|
20
|
-
if (a === '--template' && argv[i + 1]) {
|
|
21
|
-
template = argv[++i] as TemplateId
|
|
22
|
-
} else if (a === '--dir' && argv[i + 1]) {
|
|
23
|
-
dir = argv[++i]
|
|
24
|
-
} else if (a === '--keep-workspace') {
|
|
25
|
-
keepWorkspace = true
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return { template, dir, keepWorkspace }
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function pathExists(p: string) {
|
|
32
|
-
try {
|
|
33
|
-
await stat(p)
|
|
34
|
-
return true
|
|
35
|
-
} catch {
|
|
36
|
-
return false
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async function copyTemplate(src: string, dest: string) {
|
|
41
|
-
await mkdir(dest, { recursive: true })
|
|
42
|
-
const entries = await readdir(src, { withFileTypes: true })
|
|
43
|
-
for (const e of entries) {
|
|
44
|
-
if (e.name === 'node_modules' || e.name === 'dist' || e.name === '.turbo') {
|
|
45
|
-
continue
|
|
46
|
-
}
|
|
47
|
-
const from = path.join(src, e.name)
|
|
48
|
-
const to = path.join(dest, e.name)
|
|
49
|
-
if (e.isDirectory()) {
|
|
50
|
-
await copyTemplate(from, to)
|
|
51
|
-
} else {
|
|
52
|
-
await cp(from, to)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function rewriteWorkspaceDeps(pkg: Record<string, unknown>) {
|
|
58
|
-
for (const key of ['dependencies', 'devDependencies'] as const) {
|
|
59
|
-
const deps = pkg[key] as Record<string, string> | undefined
|
|
60
|
-
if (!deps) {
|
|
61
|
-
continue
|
|
62
|
-
}
|
|
63
|
-
for (const name of Object.keys(deps)) {
|
|
64
|
-
if (deps[name] === 'workspace:*') {
|
|
65
|
-
deps[name] = '^0.1.0'
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async function patchPackageJson(dest: string, projectName: string, keepWorkspace: boolean) {
|
|
72
|
-
const pkgPath = path.join(dest, 'package.json')
|
|
73
|
-
const raw = await readFile(pkgPath, 'utf8')
|
|
74
|
-
const pkg = JSON.parse(raw) as Record<string, unknown> & {
|
|
75
|
-
dependencies?: Record<string, string>
|
|
76
|
-
}
|
|
77
|
-
pkg.name = projectName
|
|
78
|
-
if (pkg.dependencies) {
|
|
79
|
-
pkg.dependencies = Object.fromEntries(
|
|
80
|
-
Object.entries(pkg.dependencies).filter(([name]) => name !== '@quadrokit/sample-client')
|
|
81
|
-
)
|
|
82
|
-
}
|
|
83
|
-
if (!keepWorkspace) {
|
|
84
|
-
rewriteWorkspaceDeps(pkg)
|
|
85
|
-
}
|
|
86
|
-
await writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8')
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** Standalone Biome config for projects outside the monorepo (no `extends` to repo root). */
|
|
90
|
-
async function writeStandaloneBiome(dest: string, keepWorkspace: boolean) {
|
|
91
|
-
if (keepWorkspace) {
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
const rootBiomePath = path.join(repoRoot(), 'biome.json')
|
|
95
|
-
const rootCfg = JSON.parse(await readFile(rootBiomePath, 'utf8')) as Record<string, unknown>
|
|
96
|
-
const { extends: _ext, ...rest } = rootCfg as Record<string, unknown> & { extends?: unknown }
|
|
97
|
-
const projectBiome = {
|
|
98
|
-
...rest,
|
|
99
|
-
vcs: {
|
|
100
|
-
enabled: true,
|
|
101
|
-
clientKind: 'git',
|
|
102
|
-
useIgnoreFile: false,
|
|
103
|
-
},
|
|
104
|
-
files: {
|
|
105
|
-
includes: ['**', '!**/node_modules', '!**/dist', '!**/.quadrokit'],
|
|
106
|
-
},
|
|
107
|
-
}
|
|
108
|
-
await writeFile(
|
|
109
|
-
path.join(dest, 'biome.json'),
|
|
110
|
-
`${JSON.stringify(projectBiome, null, 2)}\n`,
|
|
111
|
-
'utf8'
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
async function writeQuadroClientImport(dest: string) {
|
|
116
|
-
const p = path.join(dest, 'src', 'lib', 'quadro-client.ts')
|
|
117
|
-
const body = `import { createClient } from '../../.quadrokit/generated/client.gen.js';
|
|
118
|
-
|
|
119
|
-
/** Same-origin \`/rest\` in dev (Vite proxy) and production (reverse proxy). */
|
|
120
|
-
export const quadro = createClient({ baseURL: '/rest' });
|
|
121
|
-
`
|
|
122
|
-
await writeFile(p, body, 'utf8')
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async function seedGenerated(dest: string) {
|
|
126
|
-
const root = repoRoot()
|
|
127
|
-
const genSrc = path.join(root, 'packages', 'sample-client', 'generated')
|
|
128
|
-
const genDest = path.join(dest, '.quadrokit', 'generated')
|
|
129
|
-
if (!(await pathExists(genSrc))) {
|
|
130
|
-
console.warn(
|
|
131
|
-
'Warning: sample generated client not found at packages/sample-client/generated — run `quadrokit-client generate` after install.'
|
|
132
|
-
)
|
|
133
|
-
return
|
|
134
|
-
}
|
|
135
|
-
await mkdir(path.join(dest, '.quadrokit'), { recursive: true })
|
|
136
|
-
await cp(genSrc, genDest, { recursive: true })
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async function writeReadme(dest: string, template: TemplateId) {
|
|
140
|
-
const text = `# ${path.basename(dest)}
|
|
141
|
-
|
|
142
|
-
Created with **create-quadrokit** (template: \`${template}\`).
|
|
143
|
-
|
|
144
|
-
## Next steps
|
|
145
|
-
|
|
146
|
-
1. \`cd ${path.basename(dest)}\` and \`bun install\`
|
|
147
|
-
2. Copy \`.env.example\` to \`.env\` and set \`VITE_4D_ORIGIN\` to your 4D web server.
|
|
148
|
-
3. Regenerate the typed client when your REST catalog changes:
|
|
149
|
-
|
|
150
|
-
\`\`\`bash
|
|
151
|
-
bunx quadrokit-client generate --url "http://localhost:7080/rest/\\$catalog" --token YOUR_TOKEN --out .quadrokit/generated
|
|
152
|
-
\`\`\`
|
|
153
|
-
|
|
154
|
-
4. \`bun run dev\` — the dev server proxies \`/rest\` to \`VITE_4D_ORIGIN\` so **4DSID_** cookies stay same-origin.
|
|
155
|
-
|
|
156
|
-
Production: serve the SPA and reverse-proxy \`/rest\` to 4D on the **same host** as the UI.
|
|
157
|
-
`
|
|
158
|
-
await writeFile(path.join(dest, 'QUADROKIT.md'), text, 'utf8')
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async function main() {
|
|
162
|
-
const argv = process.argv.slice(2)
|
|
163
|
-
const { template: tArg, dir: dirArg, keepWorkspace } = parseArgs(argv)
|
|
164
|
-
|
|
165
|
-
const template =
|
|
166
|
-
tArg && (TEMPLATES as readonly string[]).includes(tArg)
|
|
167
|
-
? tArg
|
|
168
|
-
: (
|
|
169
|
-
await prompts({
|
|
170
|
-
type: 'select',
|
|
171
|
-
name: 'template',
|
|
172
|
-
message: 'Template',
|
|
173
|
-
choices: TEMPLATES.map((value) => ({ title: value, value })),
|
|
174
|
-
})
|
|
175
|
-
).template
|
|
176
|
-
|
|
177
|
-
if (!template) {
|
|
178
|
-
process.exit(1)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const dirAns =
|
|
182
|
-
dirArg ??
|
|
183
|
-
(
|
|
184
|
-
await prompts({
|
|
185
|
-
type: 'text',
|
|
186
|
-
name: 'dir',
|
|
187
|
-
message: 'Project directory',
|
|
188
|
-
initial: `quadro-${template}`,
|
|
189
|
-
})
|
|
190
|
-
).dir
|
|
191
|
-
|
|
192
|
-
if (!dirAns || typeof dirAns !== 'string') {
|
|
193
|
-
process.exit(1)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const dest = path.resolve(process.cwd(), dirAns)
|
|
197
|
-
if (await pathExists(dest)) {
|
|
198
|
-
const files = await readdir(dest)
|
|
199
|
-
if (files.length > 0) {
|
|
200
|
-
console.error(`Directory not empty: ${dest}`)
|
|
201
|
-
process.exit(1)
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const src = path.join(repoRoot(), 'packages', 'templates', template)
|
|
206
|
-
if (!(await pathExists(src))) {
|
|
207
|
-
console.error(`Template not found: ${src}`)
|
|
208
|
-
process.exit(1)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
await copyTemplate(src, dest)
|
|
212
|
-
await writeStandaloneBiome(dest, keepWorkspace)
|
|
213
|
-
await seedGenerated(dest)
|
|
214
|
-
await patchPackageJson(
|
|
215
|
-
dest,
|
|
216
|
-
path
|
|
217
|
-
.basename(dest)
|
|
218
|
-
.replace(/[^a-z0-9-]/gi, '-')
|
|
219
|
-
.toLowerCase() || 'quadro-app',
|
|
220
|
-
keepWorkspace
|
|
221
|
-
)
|
|
222
|
-
await writeQuadroClientImport(dest)
|
|
223
|
-
await writeReadme(dest, template)
|
|
224
|
-
|
|
225
|
-
console.log(`
|
|
226
|
-
Created QuadroKit project at ${dest}
|
|
227
|
-
|
|
228
|
-
cd ${path.basename(dest)}
|
|
229
|
-
bun install
|
|
230
|
-
bun run dev
|
|
231
|
-
`)
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
main().catch((e) => {
|
|
235
|
-
console.error(e)
|
|
236
|
-
process.exit(1)
|
|
237
|
-
})
|