@vantail/create 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/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +189 -0
- package/dist/index.js.map +1 -0
- package/dist/naming.d.ts +6 -0
- package/dist/naming.d.ts.map +1 -0
- package/dist/naming.js +18 -0
- package/dist/naming.js.map +1 -0
- package/package.json +27 -0
- package/templates/react-ts/README.md +34 -0
- package/templates/react-ts/_gitignore +5 -0
- package/templates/react-ts/icon.png +0 -0
- package/templates/react-ts/index.html +12 -0
- package/templates/react-ts/package.json +25 -0
- package/templates/react-ts/src/App.tsx +39 -0
- package/templates/react-ts/src/main.tsx +14 -0
- package/templates/react-ts/src/style.css +60 -0
- package/templates/react-ts/tsconfig.json +14 -0
- package/templates/react-ts/vantail.config.ts +60 -0
- package/templates/react-ts/vite.config.ts +8 -0
- package/templates/svelte-ts/README.md +34 -0
- package/templates/svelte-ts/_gitignore +5 -0
- package/templates/svelte-ts/icon.png +0 -0
- package/templates/svelte-ts/index.html +12 -0
- package/templates/svelte-ts/package.json +22 -0
- package/templates/svelte-ts/src/App.svelte +35 -0
- package/templates/svelte-ts/src/main.ts +9 -0
- package/templates/svelte-ts/src/style.css +60 -0
- package/templates/svelte-ts/src/vite-env.d.ts +3 -0
- package/templates/svelte-ts/svelte.config.js +6 -0
- package/templates/svelte-ts/tsconfig.json +14 -0
- package/templates/svelte-ts/vantail.config.ts +60 -0
- package/templates/svelte-ts/vite.config.ts +8 -0
- package/templates/vanilla-ts/README.md +34 -0
- package/templates/vanilla-ts/_gitignore +5 -0
- package/templates/vanilla-ts/icon.png +0 -0
- package/templates/vanilla-ts/index.html +21 -0
- package/templates/vanilla-ts/package.json +20 -0
- package/templates/vanilla-ts/src/main.ts +36 -0
- package/templates/vanilla-ts/src/style.css +60 -0
- package/templates/vanilla-ts/tsconfig.json +13 -0
- package/templates/vanilla-ts/vantail.config.ts +60 -0
- package/templates/vue-ts/README.md +34 -0
- package/templates/vue-ts/_gitignore +5 -0
- package/templates/vue-ts/icon.png +0 -0
- package/templates/vue-ts/index.html +12 -0
- package/templates/vue-ts/package.json +22 -0
- package/templates/vue-ts/src/App.vue +40 -0
- package/templates/vue-ts/src/main.ts +9 -0
- package/templates/vue-ts/src/style.css +60 -0
- package/templates/vue-ts/tsconfig.json +15 -0
- package/templates/vue-ts/vantail.config.ts +60 -0
- package/templates/vue-ts/vite.config.ts +8 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `npm create @vantail my-app`
|
|
4
|
+
*
|
|
5
|
+
* Copies a template, fills in the two things that are actually specific to a
|
|
6
|
+
* project - its name and its bundle identifier - and gets out of the way.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `npm create @vantail my-app`
|
|
4
|
+
*
|
|
5
|
+
* Copies a template, fills in the two things that are actually specific to a
|
|
6
|
+
* project - its name and its bundle identifier - and gets out of the way.
|
|
7
|
+
*/
|
|
8
|
+
import { cp, readFile, readdir, rename, writeFile } from "node:fs/promises";
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { createInterface } from "node:readline/promises";
|
|
11
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import { suggestIdentifier, toPackageName } from "./naming.js";
|
|
14
|
+
const TEMPLATES = [
|
|
15
|
+
{ id: "react-ts", label: "React + TypeScript" },
|
|
16
|
+
{ id: "svelte-ts", label: "Svelte + TypeScript" },
|
|
17
|
+
{ id: "vue-ts", label: "Vue + TypeScript" },
|
|
18
|
+
{ id: "vanilla-ts", label: "Vanilla TypeScript" },
|
|
19
|
+
];
|
|
20
|
+
const templatesRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..", "templates");
|
|
21
|
+
async function main() {
|
|
22
|
+
const argv = process.argv.slice(2);
|
|
23
|
+
const flags = new Map();
|
|
24
|
+
const positional = [];
|
|
25
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
26
|
+
const arg = argv[index];
|
|
27
|
+
if (arg.startsWith("--")) {
|
|
28
|
+
const [name, inline] = splitFlag(arg.slice(2));
|
|
29
|
+
const next = argv[index + 1];
|
|
30
|
+
if (inline !== undefined) {
|
|
31
|
+
flags.set(name, inline);
|
|
32
|
+
}
|
|
33
|
+
else if (next !== undefined && !next.startsWith("-")) {
|
|
34
|
+
flags.set(name, next);
|
|
35
|
+
index += 1;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
flags.set(name, "true");
|
|
39
|
+
}
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
positional.push(arg);
|
|
43
|
+
}
|
|
44
|
+
const interactive = process.stdin.isTTY === true && flags.get("yes") !== "true";
|
|
45
|
+
const rl = interactive
|
|
46
|
+
? createInterface({ input: process.stdin, output: process.stdout })
|
|
47
|
+
: null;
|
|
48
|
+
try {
|
|
49
|
+
// Only ask when the directory was not given on the command line.
|
|
50
|
+
const asked = positional[0] ??
|
|
51
|
+
(rl ? (await rl.question("Project directory: ")).trim() : "");
|
|
52
|
+
const directory = asked === "" ? "vantail-app" : asked;
|
|
53
|
+
const target = resolve(process.cwd(), directory);
|
|
54
|
+
if (existsSync(target) && (await readdir(target)).length > 0) {
|
|
55
|
+
console.error(`${directory} already exists and is not empty.`);
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
const template = await chooseTemplate(flags.get("template"), rl);
|
|
59
|
+
const name = flags.get("name") ?? basename(target);
|
|
60
|
+
const identifier = flags.get("identifier") ?? suggestIdentifier(name);
|
|
61
|
+
await scaffold({ template, target, name, identifier });
|
|
62
|
+
// Nothing is published to npm yet, so a project scaffolded from a checkout
|
|
63
|
+
// has to point back at it or `npm install` cannot resolve anything.
|
|
64
|
+
const root = flags.get("no-link") === "true" ? undefined : checkout();
|
|
65
|
+
const linked = root ? await linkToCheckout(target, root) : [];
|
|
66
|
+
console.log(`
|
|
67
|
+
Created ${name} in ${directory}
|
|
68
|
+
|
|
69
|
+
cd ${directory}
|
|
70
|
+
npm install
|
|
71
|
+
npm run dev
|
|
72
|
+
`);
|
|
73
|
+
if (linked.length > 0) {
|
|
74
|
+
console.log(`${linked.join(" and ")} point at ${root}.`);
|
|
75
|
+
console.log(`Build them there first: pnpm install && pnpm build && pnpm build:runtime\n`);
|
|
76
|
+
}
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
rl?.close();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function scaffold(input) {
|
|
84
|
+
await cp(join(templatesRoot, input.template), input.target, {
|
|
85
|
+
recursive: true,
|
|
86
|
+
});
|
|
87
|
+
// npm refuses to publish a file called `.gitignore`, so templates ship it
|
|
88
|
+
// under a placeholder name.
|
|
89
|
+
const placeholder = join(input.target, "_gitignore");
|
|
90
|
+
if (existsSync(placeholder)) {
|
|
91
|
+
await rename(placeholder, join(input.target, ".gitignore"));
|
|
92
|
+
}
|
|
93
|
+
await substitute(join(input.target, "package.json"), input);
|
|
94
|
+
await substitute(join(input.target, "vantail.config.ts"), input);
|
|
95
|
+
await substitute(join(input.target, "index.html"), input);
|
|
96
|
+
await substitute(join(input.target, "README.md"), input);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The Vantail checkout this scaffolder is running out of, if it is running out
|
|
100
|
+
* of one rather than an installed package.
|
|
101
|
+
*/
|
|
102
|
+
function checkout() {
|
|
103
|
+
let dir = templatesRoot;
|
|
104
|
+
for (;;) {
|
|
105
|
+
if (existsSync(join(dir, "runtime", "Cargo.toml")) &&
|
|
106
|
+
existsSync(join(dir, "packages"))) {
|
|
107
|
+
return dir;
|
|
108
|
+
}
|
|
109
|
+
const parent = dirname(dir);
|
|
110
|
+
if (parent === dir)
|
|
111
|
+
return undefined;
|
|
112
|
+
dir = parent;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Point the `@vantail/*` dependencies at a local checkout.
|
|
117
|
+
*
|
|
118
|
+
* npm links a `file:` dependency rather than copying it, which is what makes
|
|
119
|
+
* this work end to end: the runtime resolver walks up from the linked package
|
|
120
|
+
* and finds the `cargo build` in the checkout's `target/`, so a scaffolded app
|
|
121
|
+
* runs against a locally built runtime with nothing else configured.
|
|
122
|
+
*
|
|
123
|
+
* Returns the packages it rewrote.
|
|
124
|
+
*/
|
|
125
|
+
async function linkToCheckout(target, root) {
|
|
126
|
+
const path = join(target, "package.json");
|
|
127
|
+
const manifest = JSON.parse(await readFile(path, "utf8"));
|
|
128
|
+
const linked = [];
|
|
129
|
+
for (const group of ["dependencies", "devDependencies"]) {
|
|
130
|
+
const deps = manifest[group];
|
|
131
|
+
if (!deps)
|
|
132
|
+
continue;
|
|
133
|
+
for (const name of Object.keys(deps)) {
|
|
134
|
+
if (!name.startsWith("@vantail/"))
|
|
135
|
+
continue;
|
|
136
|
+
const local = join(root, "packages", name.slice("@vantail/".length));
|
|
137
|
+
if (!existsSync(local))
|
|
138
|
+
continue;
|
|
139
|
+
deps[name] = `file:${local}`;
|
|
140
|
+
linked.push(name);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
await writeFile(path, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
144
|
+
return linked;
|
|
145
|
+
}
|
|
146
|
+
/** Replace the two tokens templates are allowed to contain. */
|
|
147
|
+
async function substitute(path, input) {
|
|
148
|
+
if (!existsSync(path))
|
|
149
|
+
return;
|
|
150
|
+
const source = await readFile(path, "utf8");
|
|
151
|
+
const replaced = source
|
|
152
|
+
.replaceAll("__APP_NAME__", input.name)
|
|
153
|
+
.replaceAll("__PACKAGE_NAME__", toPackageName(input.name))
|
|
154
|
+
.replaceAll("__APP_IDENTIFIER__", input.identifier);
|
|
155
|
+
await writeFile(path, replaced, "utf8");
|
|
156
|
+
}
|
|
157
|
+
async function chooseTemplate(requested, rl) {
|
|
158
|
+
if (requested) {
|
|
159
|
+
const match = TEMPLATES.find((template) => template.id === requested);
|
|
160
|
+
if (!match) {
|
|
161
|
+
throw new Error(`Unknown template "${requested}". Available: ${TEMPLATES.map((t) => t.id).join(", ")}`);
|
|
162
|
+
}
|
|
163
|
+
return match.id;
|
|
164
|
+
}
|
|
165
|
+
if (!rl)
|
|
166
|
+
return "react-ts";
|
|
167
|
+
console.log("\nTemplate:");
|
|
168
|
+
TEMPLATES.forEach((template, index) => {
|
|
169
|
+
console.log(` ${index + 1}. ${template.label}`);
|
|
170
|
+
});
|
|
171
|
+
const answer = (await rl.question("Choose [1]: ")).trim();
|
|
172
|
+
const index = answer === "" ? 0 : Number(answer) - 1;
|
|
173
|
+
return TEMPLATES[index]?.id ?? "react-ts";
|
|
174
|
+
}
|
|
175
|
+
function splitFlag(body) {
|
|
176
|
+
const equals = body.indexOf("=");
|
|
177
|
+
return equals === -1
|
|
178
|
+
? [body, undefined]
|
|
179
|
+
: [body.slice(0, equals), body.slice(equals + 1)];
|
|
180
|
+
}
|
|
181
|
+
main()
|
|
182
|
+
.then((code) => {
|
|
183
|
+
process.exitCode = code;
|
|
184
|
+
})
|
|
185
|
+
.catch((error) => {
|
|
186
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
187
|
+
process.exitCode = 1;
|
|
188
|
+
});
|
|
189
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/naming.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Turning a project name into the identifiers a template needs. */
|
|
2
|
+
/** `My Notes` becomes `com.example.mynotes` - a starting point, not a decree. */
|
|
3
|
+
export declare function suggestIdentifier(name: string): string;
|
|
4
|
+
/** A name npm will accept in `package.json`. */
|
|
5
|
+
export declare function toPackageName(name: string): string;
|
|
6
|
+
//# sourceMappingURL=naming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMtD;AAED,gDAAgD;AAChD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD"}
|
package/dist/naming.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Turning a project name into the identifiers a template needs. */
|
|
2
|
+
/** `My Notes` becomes `com.example.mynotes` - a starting point, not a decree. */
|
|
3
|
+
export function suggestIdentifier(name) {
|
|
4
|
+
const slug = name
|
|
5
|
+
.toLowerCase()
|
|
6
|
+
.replace(/[^a-z0-9]/g, "")
|
|
7
|
+
.slice(0, 32);
|
|
8
|
+
return `com.example.${slug || "app"}`;
|
|
9
|
+
}
|
|
10
|
+
/** A name npm will accept in `package.json`. */
|
|
11
|
+
export function toPackageName(name) {
|
|
12
|
+
const slug = name
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
15
|
+
.replace(/^-+|-+$/g, "");
|
|
16
|
+
return slug || "vantail-app";
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=naming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.js","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,IAAI,GAAG,IAAI;SACd,WAAW,EAAE;SACb,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChB,OAAO,eAAe,IAAI,IAAI,KAAK,EAAE,CAAC;AACxC,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,IAAI,GAAG,IAAI;SACd,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;SAC5B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,OAAO,IAAI,IAAI,aAAa,CAAC;AAC/B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vantail/create",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Scaffold a Vantail application.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Vantail/vantail.git",
|
|
9
|
+
"directory": "packages/create"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/Vantail/vantail",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"templates"
|
|
16
|
+
],
|
|
17
|
+
"bin": {
|
|
18
|
+
"vantail-create": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p tsconfig.json",
|
|
22
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@vantail/shared": "^0.1.0"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# __APP_NAME__
|
|
2
|
+
|
|
3
|
+
Built with [Vantail](https://github.com/jeroenvanwissen/vantail).
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install
|
|
7
|
+
npm run dev # native window against the Vite dev server
|
|
8
|
+
npm run build # build the web assets
|
|
9
|
+
npm run package # produce a distributable application
|
|
10
|
+
npm run doctor # check that everything needed is installed
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
There is no Node.js in this app. `node:fs` and friends do not exist - use
|
|
14
|
+
`@vantail/api` instead:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { dialog, filesystem } from "@vantail/api";
|
|
18
|
+
|
|
19
|
+
const path = await dialog.openFile();
|
|
20
|
+
if (path) console.log(await filesystem.readText(path));
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Native access is denied by default and granted in `vantail.config.ts`. The same
|
|
24
|
+
file also describes the application menu, and can add a tray icon and a
|
|
25
|
+
self-updater.
|
|
26
|
+
|
|
27
|
+
More windows are labels, opened at runtime:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { app, createWindow } from "@vantail/api";
|
|
31
|
+
|
|
32
|
+
const settings = await createWindow("settings", { url: "settings.html" });
|
|
33
|
+
await app.emit("hello", { from: "main" }, { to: "settings" });
|
|
34
|
+
```
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
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>__APP_NAME__</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PACKAGE_NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vantail dev",
|
|
8
|
+
"build": "vantail build",
|
|
9
|
+
"package": "vantail package",
|
|
10
|
+
"doctor": "vantail doctor"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@vantail/api": "^0.1.0",
|
|
14
|
+
"react": "^19.2.0",
|
|
15
|
+
"react-dom": "^19.2.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@vantail/cli": "^0.1.0",
|
|
19
|
+
"@types/react": "^19.2.0",
|
|
20
|
+
"@types/react-dom": "^19.2.0",
|
|
21
|
+
"@vitejs/plugin-react": "^6.0.0",
|
|
22
|
+
"typescript": "^5.9.0",
|
|
23
|
+
"vite": "^8.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { app, dialog, filesystem, VantailError } from "@vantail/api";
|
|
4
|
+
|
|
5
|
+
export function App() {
|
|
6
|
+
const [contents, setContents] = useState<string | null>(null);
|
|
7
|
+
const [path, setPath] = useState<string | null>(null);
|
|
8
|
+
const [error, setError] = useState<string | null>(null);
|
|
9
|
+
|
|
10
|
+
const info = app.infoSync();
|
|
11
|
+
|
|
12
|
+
async function open() {
|
|
13
|
+
setError(null);
|
|
14
|
+
try {
|
|
15
|
+
const picked = await dialog.openFile({ title: "Open a text file" });
|
|
16
|
+
if (!picked) return;
|
|
17
|
+
|
|
18
|
+
// Picking the file in the dialog is what grants access to it - the
|
|
19
|
+
// config above never mentions this path.
|
|
20
|
+
setPath(picked);
|
|
21
|
+
setContents(await filesystem.readText(picked));
|
|
22
|
+
} catch (cause) {
|
|
23
|
+
setError(VantailError.is(cause) ? `${cause.code}: ${cause.message}` : String(cause));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<main>
|
|
29
|
+
<h1>{info?.name ?? "Vantail"}</h1>
|
|
30
|
+
<p className="meta">v{info?.version}</p>
|
|
31
|
+
|
|
32
|
+
<button onClick={() => void open()}>Select file</button>
|
|
33
|
+
|
|
34
|
+
{error ? <p className="error">{error}</p> : null}
|
|
35
|
+
{path ? <p className="meta">{path}</p> : null}
|
|
36
|
+
{contents !== null ? <pre>{contents}</pre> : <p className="meta">No file open.</p>}
|
|
37
|
+
</main>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { StrictMode } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
|
|
4
|
+
import { App } from "./App.js";
|
|
5
|
+
import "./style.css";
|
|
6
|
+
|
|
7
|
+
const container = document.getElementById("root");
|
|
8
|
+
if (!container) throw new Error("index.html is missing #root");
|
|
9
|
+
|
|
10
|
+
createRoot(container).render(
|
|
11
|
+
<StrictMode>
|
|
12
|
+
<App />
|
|
13
|
+
</StrictMode>,
|
|
14
|
+
);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color-scheme: light dark;
|
|
3
|
+
font-family: ui-sans-serif, -apple-system, "Segoe UI", system-ui, sans-serif;
|
|
4
|
+
font-size: 14px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
body {
|
|
8
|
+
margin: 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
main {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
gap: 12px;
|
|
15
|
+
padding: 24px;
|
|
16
|
+
min-height: 100vh;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
h1 {
|
|
21
|
+
margin: 0;
|
|
22
|
+
font-size: 18px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.meta {
|
|
26
|
+
margin: 0;
|
|
27
|
+
opacity: 0.6;
|
|
28
|
+
font-size: 12px;
|
|
29
|
+
overflow-wrap: anywhere;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.error {
|
|
33
|
+
margin: 0;
|
|
34
|
+
color: #d43b3b;
|
|
35
|
+
font-size: 13px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
button {
|
|
39
|
+
align-self: flex-start;
|
|
40
|
+
padding: 6px 12px;
|
|
41
|
+
border-radius: 7px;
|
|
42
|
+
border: 1px solid currentColor;
|
|
43
|
+
background: transparent;
|
|
44
|
+
color: inherit;
|
|
45
|
+
font: inherit;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pre {
|
|
50
|
+
flex: 1;
|
|
51
|
+
margin: 0;
|
|
52
|
+
padding: 12px;
|
|
53
|
+
overflow: auto;
|
|
54
|
+
border-radius: 8px;
|
|
55
|
+
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
56
|
+
font-family: ui-monospace, Menlo, monospace;
|
|
57
|
+
font-size: 12px;
|
|
58
|
+
white-space: pre-wrap;
|
|
59
|
+
overflow-wrap: anywhere;
|
|
60
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"types": ["vite/client"]
|
|
12
|
+
},
|
|
13
|
+
"include": ["src", "vantail.config.ts", "vite.config.ts"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { defineConfig } from "@vantail/cli";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
app: {
|
|
5
|
+
name: "__APP_NAME__",
|
|
6
|
+
identifier: "__APP_IDENTIFIER__",
|
|
7
|
+
version: "0.1.0",
|
|
8
|
+
// A square PNG. Every size each platform asks for is scaled down from it.
|
|
9
|
+
icon: "icon.png",
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
window: {
|
|
13
|
+
title: "__APP_NAME__",
|
|
14
|
+
width: 900,
|
|
15
|
+
height: 640,
|
|
16
|
+
minWidth: 480,
|
|
17
|
+
minHeight: 360,
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
// On macOS this is not decoration: without these predefined items in the
|
|
21
|
+
// menu, Cmd-C, Cmd-V and Cmd-Z do not work anywhere in the application.
|
|
22
|
+
// Add your own submenus alongside them.
|
|
23
|
+
menu: [
|
|
24
|
+
{
|
|
25
|
+
type: "submenu",
|
|
26
|
+
label: "__APP_NAME__",
|
|
27
|
+
items: [
|
|
28
|
+
{ type: "predefined", item: "about" },
|
|
29
|
+
{ type: "separator" },
|
|
30
|
+
{ type: "predefined", item: "hide" },
|
|
31
|
+
{ type: "predefined", item: "quit" },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: "submenu",
|
|
36
|
+
label: "Edit",
|
|
37
|
+
items: [
|
|
38
|
+
{ type: "predefined", item: "undo" },
|
|
39
|
+
{ type: "predefined", item: "redo" },
|
|
40
|
+
{ type: "separator" },
|
|
41
|
+
{ type: "predefined", item: "cut" },
|
|
42
|
+
{ type: "predefined", item: "copy" },
|
|
43
|
+
{ type: "predefined", item: "paste" },
|
|
44
|
+
{ type: "predefined", item: "selectAll" },
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
|
|
49
|
+
// Everything is denied until you ask for it. Start small: `dialog` plus the
|
|
50
|
+
// default `grantFromDialog` is enough to open any file the user picks,
|
|
51
|
+
// without granting standing access to their disk.
|
|
52
|
+
permissions: {
|
|
53
|
+
dialog: true,
|
|
54
|
+
clipboard: true,
|
|
55
|
+
menu: true,
|
|
56
|
+
filesystem: {
|
|
57
|
+
write: ["$APPDATA/**"],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# __APP_NAME__
|
|
2
|
+
|
|
3
|
+
Built with [Vantail](https://github.com/jeroenvanwissen/vantail).
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install
|
|
7
|
+
npm run dev # native window against the Vite dev server
|
|
8
|
+
npm run build # build the web assets
|
|
9
|
+
npm run package # produce a distributable application
|
|
10
|
+
npm run doctor # check that everything needed is installed
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
There is no Node.js in this app. `node:fs` and friends do not exist - use
|
|
14
|
+
`@vantail/api` instead:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { dialog, filesystem } from "@vantail/api";
|
|
18
|
+
|
|
19
|
+
const path = await dialog.openFile();
|
|
20
|
+
if (path) console.log(await filesystem.readText(path));
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Native access is denied by default and granted in `vantail.config.ts`. The same
|
|
24
|
+
file also describes the application menu, and can add a tray icon and a
|
|
25
|
+
self-updater.
|
|
26
|
+
|
|
27
|
+
More windows are labels, opened at runtime:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { app, createWindow } from "@vantail/api";
|
|
31
|
+
|
|
32
|
+
const settings = await createWindow("settings", { url: "settings.html" });
|
|
33
|
+
await app.emit("hello", { from: "main" }, { to: "settings" });
|
|
34
|
+
```
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
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>__APP_NAME__</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="/src/main.ts"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PACKAGE_NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vantail dev",
|
|
8
|
+
"build": "vantail build",
|
|
9
|
+
"package": "vantail package",
|
|
10
|
+
"doctor": "vantail doctor"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@vantail/api": "^0.1.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@vantail/cli": "^0.1.0",
|
|
17
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
18
|
+
"svelte": "^5.56.10",
|
|
19
|
+
"typescript": "^5.9.0",
|
|
20
|
+
"vite": "^8.0.0"
|
|
21
|
+
}
|
|
22
|
+
}
|