create-zenbu-app 0.0.4 → 0.0.6
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.mjs +100 -6
- package/package.json +1 -1
- package/template/_gitignore +3 -0
- package/template/package.json +3 -1
- package/template/src/main/schema.ts.tmpl +16 -0
- package/template/src/main/services/app.ts.tmpl +5 -8
- package/template/src/main/services/repo.ts.tmpl +11 -0
- package/template/src/renderer/App.tsx.tmpl +83 -24
- package/template/src/renderer/app.css +3 -0
- package/template/src/renderer/installing.html +118 -0
- package/template/vite.config.ts.tmpl +2 -1
- package/template/zenbu.config.ts.tmpl +11 -8
package/dist/index.mjs
CHANGED
|
@@ -7,10 +7,67 @@ import { spawnSync } from "node:child_process";
|
|
|
7
7
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
8
|
const TEMPLATE_DIR = path.resolve(__dirname, "..", "template");
|
|
9
9
|
const argv = process.argv.slice(2);
|
|
10
|
-
const
|
|
10
|
+
const flagsSet = new Set(argv.filter((a) => a.startsWith("-")));
|
|
11
11
|
const positional = argv.filter((a) => !a.startsWith("-"));
|
|
12
|
-
const yes =
|
|
12
|
+
const yes = flagsSet.has("--yes") || flagsSet.has("-y");
|
|
13
|
+
const noInstall = flagsSet.has("--no-install");
|
|
13
14
|
const ZENBU_LOCAL_CORE = process.env.ZENBU_LOCAL_CORE;
|
|
15
|
+
/**
|
|
16
|
+
* Detect the PM that invoked `create-zenbu-app`. Order:
|
|
17
|
+
* 1. `process.versions.bun` → bun (covers `bunx create-zenbu-app`).
|
|
18
|
+
* 2. `npm_config_user_agent` → "<pm>/<version> ..." (set by all of npm,
|
|
19
|
+
* pnpm, yarn classic, yarn berry).
|
|
20
|
+
* 3. Shell out to `<detected-name> --version` if user_agent only carries
|
|
21
|
+
* the bare name without a parseable version.
|
|
22
|
+
* 4. Fallback to pnpm with a hardcoded sane default.
|
|
23
|
+
*/
|
|
24
|
+
function detectPackageManager() {
|
|
25
|
+
if (process.versions.bun) return {
|
|
26
|
+
type: "bun",
|
|
27
|
+
version: process.versions.bun,
|
|
28
|
+
fallback: false
|
|
29
|
+
};
|
|
30
|
+
const ua = process.env.npm_config_user_agent;
|
|
31
|
+
if (ua) {
|
|
32
|
+
const first = ua.split(" ")[0];
|
|
33
|
+
if (first) {
|
|
34
|
+
const slash = first.indexOf("/");
|
|
35
|
+
const name = (slash >= 0 ? first.slice(0, slash) : first).toLowerCase();
|
|
36
|
+
const version = slash >= 0 ? first.slice(slash + 1) : "";
|
|
37
|
+
if (name === "pnpm" || name === "npm" || name === "yarn" || name === "bun") {
|
|
38
|
+
if (version && /^\d/.test(version)) return {
|
|
39
|
+
type: name,
|
|
40
|
+
version,
|
|
41
|
+
fallback: false
|
|
42
|
+
};
|
|
43
|
+
const probed = probeVersion(name);
|
|
44
|
+
if (probed) return {
|
|
45
|
+
type: name,
|
|
46
|
+
version: probed,
|
|
47
|
+
fallback: false
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
type: "pnpm",
|
|
54
|
+
version: "10.33.0",
|
|
55
|
+
fallback: true
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function probeVersion(pm) {
|
|
59
|
+
const res = spawnSync(pm, ["--version"], {
|
|
60
|
+
encoding: "utf8",
|
|
61
|
+
stdio: [
|
|
62
|
+
"ignore",
|
|
63
|
+
"pipe",
|
|
64
|
+
"ignore"
|
|
65
|
+
]
|
|
66
|
+
});
|
|
67
|
+
if (res.status !== 0) return null;
|
|
68
|
+
const match = (res.stdout ?? "").trim().match(/\d+\.\d+\.\d+(?:[-+][\w.]+)?/);
|
|
69
|
+
return match ? match[0] : null;
|
|
70
|
+
}
|
|
14
71
|
function renderTemplate(value, projectName) {
|
|
15
72
|
return value.replace(/\{\{projectName\}\}/g, projectName);
|
|
16
73
|
}
|
|
@@ -27,6 +84,19 @@ function copyDirSync(src, dest, projectName) {
|
|
|
27
84
|
}
|
|
28
85
|
}
|
|
29
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Replace the `// {{packageManager}}` marker in the scaffolded
|
|
89
|
+
* `zenbu.config.ts` with a real `packageManager: { ... }` line. Idempotent
|
|
90
|
+
* — running this twice yields the same file.
|
|
91
|
+
*/
|
|
92
|
+
function seedPackageManager(projectDir, pm) {
|
|
93
|
+
const configPath = path.join(projectDir, "zenbu.config.ts");
|
|
94
|
+
if (!fs.existsSync(configPath)) return;
|
|
95
|
+
const original = fs.readFileSync(configPath, "utf8");
|
|
96
|
+
const literal = `packageManager: { type: "${pm.type}", version: "${pm.version}" },`;
|
|
97
|
+
const replaced = original.replace(/\/\/\s*\{\{packageManager\}\}/, literal);
|
|
98
|
+
if (replaced !== original) fs.writeFileSync(configPath, replaced);
|
|
99
|
+
}
|
|
30
100
|
function rewireToLocalCore(projectDir, corePath) {
|
|
31
101
|
const pkgPath = path.join(projectDir, "package.json");
|
|
32
102
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
@@ -63,6 +133,19 @@ function gitInitWithInitialCommit(projectDir) {
|
|
|
63
133
|
}
|
|
64
134
|
});
|
|
65
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Run `<pm> install` in the freshly-scaffolded project so the user can go
|
|
138
|
+
* straight to `pnpm dev`/`bun dev`/etc. without the extra step. We run with
|
|
139
|
+
* the user's globally-installed PM (which is what they used to invoke us in
|
|
140
|
+
* the first place), so this won't hit the bundled toolchain — that only
|
|
141
|
+
* matters at the .app's first launch on the consumer's machine.
|
|
142
|
+
*/
|
|
143
|
+
function runInstall(projectDir, pm) {
|
|
144
|
+
return spawnSync(pm.type, ["install"], {
|
|
145
|
+
cwd: projectDir,
|
|
146
|
+
stdio: "inherit"
|
|
147
|
+
}).status === 0;
|
|
148
|
+
}
|
|
66
149
|
function main() {
|
|
67
150
|
const projectName = positional[0] ?? ".";
|
|
68
151
|
if (projectName === "." && !yes) {
|
|
@@ -70,7 +153,7 @@ function main() {
|
|
|
70
153
|
process.exit(1);
|
|
71
154
|
}
|
|
72
155
|
const projectDir = path.resolve(process.cwd(), projectName);
|
|
73
|
-
const displayName =
|
|
156
|
+
const displayName = path.basename(projectDir);
|
|
74
157
|
if (fs.existsSync(projectDir)) {
|
|
75
158
|
const entries = fs.readdirSync(projectDir).filter((e) => e !== ".git");
|
|
76
159
|
const allowedExisting = projectName === "." && fs.existsSync(path.join(projectDir, "package.json"));
|
|
@@ -79,19 +162,30 @@ function main() {
|
|
|
79
162
|
process.exit(1);
|
|
80
163
|
}
|
|
81
164
|
}
|
|
82
|
-
|
|
165
|
+
const pm = detectPackageManager();
|
|
166
|
+
console.log(`\nScaffolding Zenbu app in "${displayName}"...`);
|
|
167
|
+
if (pm.fallback) console.log(` → couldn't detect invoking package manager; defaulting to ${pm.type}@${pm.version}.`);
|
|
168
|
+
else console.log(` → detected ${pm.type}@${pm.version} as the invoking package manager`);
|
|
169
|
+
console.log("");
|
|
83
170
|
copyDirSync(TEMPLATE_DIR, projectDir, displayName);
|
|
84
171
|
const gi = path.join(projectDir, "_gitignore");
|
|
85
172
|
if (fs.existsSync(gi)) fs.renameSync(gi, path.join(projectDir, ".gitignore"));
|
|
173
|
+
seedPackageManager(projectDir, pm);
|
|
86
174
|
if (ZENBU_LOCAL_CORE) {
|
|
87
175
|
const corePath = path.resolve(ZENBU_LOCAL_CORE);
|
|
88
176
|
rewireToLocalCore(projectDir, corePath);
|
|
89
177
|
console.log(` → linked @zenbujs/core -> ${corePath}`);
|
|
90
178
|
}
|
|
179
|
+
let installed = false;
|
|
180
|
+
if (!noInstall) {
|
|
181
|
+
console.log(` → running ${pm.type} install\n`);
|
|
182
|
+
installed = runInstall(projectDir, pm);
|
|
183
|
+
if (!installed) console.warn(` → ${pm.type} install failed; you can retry manually after the scaffold completes.\n`);
|
|
184
|
+
}
|
|
91
185
|
if (!fs.existsSync(path.join(projectDir, ".git"))) gitInitWithInitialCommit(projectDir);
|
|
92
186
|
const cdHint = projectName === "." ? "" : `cd ${displayName} && `;
|
|
93
|
-
console.log(`Done. Next:\n\n ${cdHint}
|
|
94
|
-
console.log(`
|
|
187
|
+
if (installed) console.log(`Done. Next:\n\n ${cdHint}${pm.type} dev\n`);
|
|
188
|
+
else console.log(`Done. Next:\n\n ${cdHint}${pm.type} install\n ${pm.type} dev\n`);
|
|
95
189
|
}
|
|
96
190
|
try {
|
|
97
191
|
main();
|
package/package.json
CHANGED
package/template/_gitignore
CHANGED
package/template/package.json
CHANGED
|
@@ -12,10 +12,12 @@
|
|
|
12
12
|
"db:generate": "zen db generate"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@zenbujs/core": "0.0.
|
|
15
|
+
"@zenbujs/core": "^0.0.9",
|
|
16
|
+
"@tailwindcss/vite": "^4.2.0",
|
|
16
17
|
"@vitejs/plugin-react": "^5.0.0",
|
|
17
18
|
"react": "^19.0.0",
|
|
18
19
|
"react-dom": "^19.0.0",
|
|
20
|
+
"tailwindcss": "^4.2.0",
|
|
19
21
|
"vite": "^6.0.0",
|
|
20
22
|
"zod": "^4.0.0"
|
|
21
23
|
},
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createSchema, InferRoot, InferSchema, z } from "@zenbujs/core/db"
|
|
2
|
+
|
|
3
|
+
export const schema = createSchema({
|
|
4
|
+
issues: z
|
|
5
|
+
.array(
|
|
6
|
+
z.object({
|
|
7
|
+
id: z.string(),
|
|
8
|
+
title: z.string(),
|
|
9
|
+
createdAt: z.number(),
|
|
10
|
+
}),
|
|
11
|
+
)
|
|
12
|
+
.default([]),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export type AppSchema = InferSchema<typeof schema>
|
|
16
|
+
export type SchemaRoot = InferRoot<AppSchema>
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Service } from "@zenbujs/core/runtime"
|
|
2
2
|
import { WindowService } from "@zenbujs/core/services"
|
|
3
3
|
|
|
4
|
-
export class AppService extends
|
|
5
|
-
|
|
4
|
+
export class AppService extends Service.create({
|
|
5
|
+
key: "app",
|
|
6
|
+
deps: { window: WindowService },
|
|
6
7
|
}) {
|
|
7
|
-
static key = "app"
|
|
8
|
-
|
|
9
8
|
async evaluate() {
|
|
10
|
-
await this.ctx.window.openView({
|
|
9
|
+
await this.ctx.window.openView({ type: "app" })
|
|
11
10
|
}
|
|
12
11
|
}
|
|
13
|
-
|
|
14
|
-
runtime.register(AppService, import.meta)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Service } from "@zenbujs/core/runtime"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sample RPC service. Methods on the class are callable from the renderer
|
|
5
|
+
* via `useRpc()` — see `src/renderer/App.tsx`.
|
|
6
|
+
*/
|
|
7
|
+
export class Repo extends Service.create({ key: "repo" }) {
|
|
8
|
+
async getCwd() {
|
|
9
|
+
return process.cwd()
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -1,43 +1,102 @@
|
|
|
1
|
+
import { ZenbuProvider, useDb, useDbClient, useRpc } from "@zenbujs/core/react"
|
|
2
|
+
import { useState } from "react"
|
|
3
|
+
|
|
1
4
|
function Titlebar() {
|
|
2
5
|
return (
|
|
3
6
|
<div
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
alignItems: "center",
|
|
8
|
-
justifyContent: "flex-end",
|
|
9
|
-
padding: "0 12px 0 72px",
|
|
10
|
-
// @ts-expect-error webkit property
|
|
11
|
-
WebkitAppRegion: "drag",
|
|
12
|
-
flexShrink: 0,
|
|
13
|
-
}}
|
|
7
|
+
className="h-10 flex items-center justify-end px-3 pl-[72px] shrink-0"
|
|
8
|
+
// @ts-expect-error webkit property
|
|
9
|
+
style={{ WebkitAppRegion: "drag" }}
|
|
14
10
|
/>
|
|
15
11
|
)
|
|
16
12
|
}
|
|
17
13
|
|
|
18
14
|
function Home() {
|
|
15
|
+
const db = useDb()
|
|
16
|
+
const client = useDbClient()
|
|
17
|
+
const rpc = useRpc()
|
|
18
|
+
const [cwd, setCwd] = useState<string | null>(null)
|
|
19
|
+
|
|
20
|
+
const issues = db.plugin.app.issues
|
|
21
|
+
|
|
19
22
|
return (
|
|
20
|
-
<main
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
padding: "0 32px 32px",
|
|
24
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
25
|
-
color: "var(--foreground, #e5e5e5)",
|
|
26
|
-
}}
|
|
27
|
-
>
|
|
28
|
-
<h1>Welcome to Zenbu</h1>
|
|
29
|
-
<p style={{ color: "var(--muted-foreground, #999)", marginTop: 8 }}>
|
|
23
|
+
<main className="flex-1 px-8 pb-8 font-sans text-[#e5e5e5]">
|
|
24
|
+
<h1 className="text-2xl font-bold mb-2">Welcome to Zenbu</h1>
|
|
25
|
+
<p className="text-[#888] mb-6">
|
|
30
26
|
Edit <code>src/renderer/App.tsx</code> to get started.
|
|
31
27
|
</p>
|
|
28
|
+
|
|
29
|
+
<form
|
|
30
|
+
className="flex flex-col gap-3 bg-[#18181b] rounded-xl p-4 max-w-md mb-6"
|
|
31
|
+
onSubmit={(e) => {
|
|
32
|
+
e.preventDefault()
|
|
33
|
+
const form = e.currentTarget
|
|
34
|
+
const title = (form.elements.namedItem("title") as HTMLInputElement).value
|
|
35
|
+
if (!title.trim()) return
|
|
36
|
+
client.update((db) => {
|
|
37
|
+
db.plugin.app.issues.push({
|
|
38
|
+
id: crypto.randomUUID(),
|
|
39
|
+
title,
|
|
40
|
+
createdAt: Date.now(),
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
form.reset()
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
<input
|
|
47
|
+
name="title"
|
|
48
|
+
placeholder="New issue title"
|
|
49
|
+
autoComplete="off"
|
|
50
|
+
className="px-3 py-2 rounded bg-[#222] border border-[#333] outline-none focus:border-indigo-500"
|
|
51
|
+
/>
|
|
52
|
+
<button
|
|
53
|
+
type="submit"
|
|
54
|
+
className="bg-indigo-600 hover:bg-indigo-700 transition text-white font-semibold px-4 py-2 rounded"
|
|
55
|
+
>
|
|
56
|
+
+ add
|
|
57
|
+
</button>
|
|
58
|
+
</form>
|
|
59
|
+
|
|
60
|
+
<div className="max-w-md mb-6">
|
|
61
|
+
{issues.length === 0 ? (
|
|
62
|
+
<div className="text-[#888] italic">No issues yet — try adding one.</div>
|
|
63
|
+
) : (
|
|
64
|
+
issues.map((issue) => (
|
|
65
|
+
<div
|
|
66
|
+
key={issue.id}
|
|
67
|
+
className="mb-2 p-3 rounded-lg bg-[#222] border border-[#2a2a2a] flex items-center justify-between"
|
|
68
|
+
>
|
|
69
|
+
<span>{issue.title}</span>
|
|
70
|
+
<span className="text-xs text-[#666]">
|
|
71
|
+
{new Date(issue.createdAt).toLocaleTimeString()}
|
|
72
|
+
</span>
|
|
73
|
+
</div>
|
|
74
|
+
))
|
|
75
|
+
)}
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<button
|
|
79
|
+
className="bg-zinc-800 hover:bg-zinc-700 px-4 py-2 rounded text-sm"
|
|
80
|
+
onClick={async () => setCwd(await rpc.repo.getCwd())}
|
|
81
|
+
>
|
|
82
|
+
rpc → main process cwd
|
|
83
|
+
</button>
|
|
84
|
+
{cwd && (
|
|
85
|
+
<div className="mt-2 p-2 rounded bg-[#232328] text-[#b0b0b0] w-fit text-xs">
|
|
86
|
+
{cwd}
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
32
89
|
</main>
|
|
33
90
|
)
|
|
34
91
|
}
|
|
35
92
|
|
|
36
93
|
export function App() {
|
|
37
94
|
return (
|
|
38
|
-
<
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
95
|
+
<ZenbuProvider>
|
|
96
|
+
<div className="flex flex-col min-h-screen">
|
|
97
|
+
<Titlebar />
|
|
98
|
+
<Home />
|
|
99
|
+
</div>
|
|
100
|
+
</ZenbuProvider>
|
|
42
101
|
)
|
|
43
102
|
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="zenbu-bg" content="#111">
|
|
6
|
+
<title>Installing</title>
|
|
7
|
+
<style>
|
|
8
|
+
html, body {
|
|
9
|
+
height: 100%;
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
background: #111;
|
|
13
|
+
color: #ddd;
|
|
14
|
+
font: 13px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
|
|
15
|
+
-webkit-app-region: drag;
|
|
16
|
+
user-select: none;
|
|
17
|
+
}
|
|
18
|
+
body {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
gap: 18px;
|
|
24
|
+
padding: 32px;
|
|
25
|
+
box-sizing: border-box;
|
|
26
|
+
}
|
|
27
|
+
.label {
|
|
28
|
+
font-size: 14px;
|
|
29
|
+
color: #f0f0f0;
|
|
30
|
+
letter-spacing: 0.2px;
|
|
31
|
+
min-height: 1.4em;
|
|
32
|
+
text-align: center;
|
|
33
|
+
}
|
|
34
|
+
.bar {
|
|
35
|
+
width: min(360px, 70%);
|
|
36
|
+
height: 4px;
|
|
37
|
+
background: #2a2a2a;
|
|
38
|
+
border-radius: 2px;
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
position: relative;
|
|
41
|
+
}
|
|
42
|
+
.bar-fill {
|
|
43
|
+
position: absolute;
|
|
44
|
+
inset: 0 auto 0 0;
|
|
45
|
+
width: 0%;
|
|
46
|
+
background: #f0f0f0;
|
|
47
|
+
transition: width 180ms ease-out;
|
|
48
|
+
}
|
|
49
|
+
.bar.indeterminate .bar-fill {
|
|
50
|
+
width: 30%;
|
|
51
|
+
animation: slide 1.2s ease-in-out infinite;
|
|
52
|
+
}
|
|
53
|
+
@keyframes slide {
|
|
54
|
+
0% { transform: translateX(-100%); }
|
|
55
|
+
100% { transform: translateX(366%); }
|
|
56
|
+
}
|
|
57
|
+
.message {
|
|
58
|
+
font-size: 11px;
|
|
59
|
+
color: #888;
|
|
60
|
+
font-family: "SF Mono", Menlo, Consolas, monospace;
|
|
61
|
+
max-width: min(420px, 90%);
|
|
62
|
+
text-align: center;
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
text-overflow: ellipsis;
|
|
65
|
+
white-space: nowrap;
|
|
66
|
+
min-height: 1.4em;
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
69
|
+
</head>
|
|
70
|
+
<body>
|
|
71
|
+
<div class="label" id="label">Starting…</div>
|
|
72
|
+
<div class="bar indeterminate" id="bar"><div class="bar-fill" id="fill"></div></div>
|
|
73
|
+
<div class="message" id="message"></div>
|
|
74
|
+
<script>
|
|
75
|
+
// The framework's built-in preload exposes `window.zenbuInstall` with
|
|
76
|
+
// `.on(event, cb)` returning an unsubscribe function. Events:
|
|
77
|
+
// step: { id: "clone" | "fetch" | "install" | "handoff", label }
|
|
78
|
+
// message: { text }
|
|
79
|
+
// progress: { phase?, loaded?, total?, ratio? }
|
|
80
|
+
// done: { id }
|
|
81
|
+
// error: { id?, message }
|
|
82
|
+
const api = window.zenbuInstall;
|
|
83
|
+
const labelEl = document.getElementById("label");
|
|
84
|
+
const messageEl = document.getElementById("message");
|
|
85
|
+
const barEl = document.getElementById("bar");
|
|
86
|
+
const fillEl = document.getElementById("fill");
|
|
87
|
+
if (api) {
|
|
88
|
+
api.on("step", (p) => {
|
|
89
|
+
if (p && p.label) labelEl.textContent = p.label;
|
|
90
|
+
barEl.classList.add("indeterminate");
|
|
91
|
+
fillEl.style.width = "";
|
|
92
|
+
});
|
|
93
|
+
api.on("message", (p) => {
|
|
94
|
+
if (p && p.text) messageEl.textContent = p.text;
|
|
95
|
+
});
|
|
96
|
+
api.on("progress", (p) => {
|
|
97
|
+
const ratio = p && typeof p.ratio === "number" ? p.ratio : null;
|
|
98
|
+
if (ratio != null && ratio >= 0) {
|
|
99
|
+
barEl.classList.remove("indeterminate");
|
|
100
|
+
fillEl.style.width = Math.max(2, Math.min(100, ratio * 100)) + "%";
|
|
101
|
+
} else {
|
|
102
|
+
barEl.classList.add("indeterminate");
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
api.on("done", () => {
|
|
106
|
+
messageEl.textContent = "";
|
|
107
|
+
});
|
|
108
|
+
api.on("error", (p) => {
|
|
109
|
+
labelEl.textContent = "Failed";
|
|
110
|
+
if (p && p.message) messageEl.textContent = p.message;
|
|
111
|
+
barEl.classList.remove("indeterminate");
|
|
112
|
+
fillEl.style.width = "100%";
|
|
113
|
+
fillEl.style.background = "#d04444";
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
</script>
|
|
117
|
+
</body>
|
|
118
|
+
</html>
|
|
@@ -2,12 +2,13 @@ import path from "node:path"
|
|
|
2
2
|
import { fileURLToPath } from "node:url"
|
|
3
3
|
import { defineConfig } from "vite"
|
|
4
4
|
import react from "@vitejs/plugin-react"
|
|
5
|
+
import tailwindcss from "@tailwindcss/vite"
|
|
5
6
|
|
|
6
7
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
7
8
|
|
|
8
9
|
export default defineConfig({
|
|
9
10
|
root: path.resolve(__dirname, "src", "renderer"),
|
|
10
|
-
plugins: [react()],
|
|
11
|
+
plugins: [react(), tailwindcss()],
|
|
11
12
|
resolve: {
|
|
12
13
|
alias: {
|
|
13
14
|
"@": path.resolve(__dirname, "src", "renderer"),
|
|
@@ -2,9 +2,7 @@ import {
|
|
|
2
2
|
defineConfig,
|
|
3
3
|
definePlugin,
|
|
4
4
|
defineBuildConfig,
|
|
5
|
-
|
|
6
|
-
dropFiles,
|
|
7
|
-
} from "@zenbujs/core/config";
|
|
5
|
+
} from "@zenbujs/core/config"
|
|
8
6
|
|
|
9
7
|
export default defineConfig({
|
|
10
8
|
// Where the kyju database lives (relative to this file).
|
|
@@ -19,6 +17,7 @@ export default defineConfig({
|
|
|
19
17
|
definePlugin({
|
|
20
18
|
name: "app",
|
|
21
19
|
services: ["./src/main/services/*.ts"],
|
|
20
|
+
schema: "./src/main/schema.ts",
|
|
22
21
|
}),
|
|
23
22
|
],
|
|
24
23
|
|
|
@@ -26,10 +25,18 @@ export default defineConfig({
|
|
|
26
25
|
// `zen build:electron` (signed .app via electron-builder). Set
|
|
27
26
|
// `mirror.target` to "<owner>/<repo>" before shipping.
|
|
28
27
|
build: defineBuildConfig({
|
|
28
|
+
// {{packageManager}}
|
|
29
|
+
// The .app's "host version" — bump every time you ship a new
|
|
30
|
+
// .app build. Each commit's `package.json#zenbu.host` semver range
|
|
31
|
+
// is checked against this value at launch (and from
|
|
32
|
+
// `UpdaterService.update()`); incompatible commits are skipped, so
|
|
33
|
+
// older .apps stay pinned to source they can actually run.
|
|
34
|
+
hostVersion: "0.0.1",
|
|
29
35
|
source: ".",
|
|
30
36
|
out: ".zenbu/build/source",
|
|
31
37
|
include: [
|
|
32
38
|
"src/**/*",
|
|
39
|
+
".gitignore",
|
|
33
40
|
"package.json",
|
|
34
41
|
"pnpm-lock.yaml",
|
|
35
42
|
"tsconfig.json",
|
|
@@ -43,10 +50,6 @@ export default defineConfig({
|
|
|
43
50
|
"src/**/*.spec.tsx",
|
|
44
51
|
"src/dev-only/**",
|
|
45
52
|
],
|
|
46
|
-
transforms: [
|
|
47
|
-
stripIfDisabled({ FLAG_BETA: false }),
|
|
48
|
-
dropFiles(/\.stories\.tsx?$/),
|
|
49
|
-
],
|
|
50
53
|
// mirror: { target: "{{owner}}/{{repo}}", branch: "main" },
|
|
51
54
|
}),
|
|
52
|
-
})
|
|
55
|
+
})
|