@witchcraft/nuxt-electron 0.0.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 +299 -0
- package/dist/module.d.mts +117 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +362 -0
- package/dist/runtime/components/ElectronWindowControls.d.vue.ts +31 -0
- package/dist/runtime/components/ElectronWindowControls.vue +67 -0
- package/dist/runtime/components/ElectronWindowControls.vue.d.ts +31 -0
- package/dist/runtime/components/WindowControls/CloseButton.d.vue.ts +16 -0
- package/dist/runtime/components/WindowControls/CloseButton.vue +54 -0
- package/dist/runtime/components/WindowControls/CloseButton.vue.d.ts +16 -0
- package/dist/runtime/components/WindowControls/MaximizeButton.d.vue.ts +16 -0
- package/dist/runtime/components/WindowControls/MaximizeButton.vue +33 -0
- package/dist/runtime/components/WindowControls/MaximizeButton.vue.d.ts +16 -0
- package/dist/runtime/components/WindowControls/MinimizeButton.d.vue.ts +16 -0
- package/dist/runtime/components/WindowControls/MinimizeButton.vue +40 -0
- package/dist/runtime/components/WindowControls/MinimizeButton.vue.d.ts +16 -0
- package/dist/runtime/components/WindowControls/PinButton.d.vue.ts +27 -0
- package/dist/runtime/components/WindowControls/PinButton.vue +51 -0
- package/dist/runtime/components/WindowControls/PinButton.vue.d.ts +27 -0
- package/dist/runtime/electron/apiBuilder.d.ts +8 -0
- package/dist/runtime/electron/apiBuilder.js +9 -0
- package/dist/runtime/electron/createBroadcastHandlers.d.ts +4 -0
- package/dist/runtime/electron/createBroadcastHandlers.js +30 -0
- package/dist/runtime/electron/createBroadcaster.d.ts +2 -0
- package/dist/runtime/electron/createBroadcaster.js +7 -0
- package/dist/runtime/electron/createNuxtFileProtocolHandler.d.ts +14 -0
- package/dist/runtime/electron/createNuxtFileProtocolHandler.js +20 -0
- package/dist/runtime/electron/createWindowControlsApi.d.ts +19 -0
- package/dist/runtime/electron/createWindowControlsApi.js +6 -0
- package/dist/runtime/electron/createWindowControlsApiHandler.d.ts +4 -0
- package/dist/runtime/electron/createWindowControlsApiHandler.js +24 -0
- package/dist/runtime/electron/getEventWindow.d.ts +11 -0
- package/dist/runtime/electron/getEventWindow.js +8 -0
- package/dist/runtime/electron/getPaths.d.ts +27 -0
- package/dist/runtime/electron/getPaths.js +33 -0
- package/dist/runtime/electron/getPreloadMeta.d.ts +25 -0
- package/dist/runtime/electron/getPreloadMeta.js +7 -0
- package/dist/runtime/electron/index.d.ts +16 -0
- package/dist/runtime/electron/index.js +16 -0
- package/dist/runtime/electron/promisifyApi.d.ts +40 -0
- package/dist/runtime/electron/promisifyApi.js +41 -0
- package/dist/runtime/electron/promisifyReply.d.ts +8 -0
- package/dist/runtime/electron/promisifyReply.js +27 -0
- package/dist/runtime/electron/registerDevtoolsShortcuts.d.ts +2 -0
- package/dist/runtime/electron/registerDevtoolsShortcuts.js +10 -0
- package/dist/runtime/electron/static.d.ts +12 -0
- package/dist/runtime/electron/static.js +8 -0
- package/dist/runtime/electron/types.d.ts +1 -0
- package/dist/runtime/electron/types.js +0 -0
- package/dist/runtime/electron/useDevDataDir.d.ts +1 -0
- package/dist/runtime/electron/useDevDataDir.js +8 -0
- package/dist/runtime/electron/useNuxtRuntimeConfig.d.ts +2 -0
- package/dist/runtime/electron/useNuxtRuntimeConfig.js +4 -0
- package/dist/runtime/utils/isElectron.d.ts +9 -0
- package/dist/runtime/utils/isElectron.js +3 -0
- package/dist/types.d.mts +3 -0
- package/genDevDesktop.js +47 -0
- package/package.json +93 -0
- package/src/module.ts +549 -0
- package/src/runtime/components/ElectronWindowControls.vue +94 -0
- package/src/runtime/components/WindowControls/CloseButton.vue +56 -0
- package/src/runtime/components/WindowControls/MaximizeButton.vue +35 -0
- package/src/runtime/components/WindowControls/MinimizeButton.vue +42 -0
- package/src/runtime/components/WindowControls/PinButton.vue +56 -0
- package/src/runtime/electron/apiBuilder.ts +27 -0
- package/src/runtime/electron/createBroadcastHandlers.ts +36 -0
- package/src/runtime/electron/createBroadcaster.ts +11 -0
- package/src/runtime/electron/createNuxtFileProtocolHandler.ts +42 -0
- package/src/runtime/electron/createWindowControlsApi.ts +27 -0
- package/src/runtime/electron/createWindowControlsApiHandler.ts +34 -0
- package/src/runtime/electron/getEventWindow.ts +19 -0
- package/src/runtime/electron/getPaths.ts +68 -0
- package/src/runtime/electron/getPreloadMeta.ts +36 -0
- package/src/runtime/electron/index.ts +17 -0
- package/src/runtime/electron/promisifyApi.ts +102 -0
- package/src/runtime/electron/promisifyReply.ts +49 -0
- package/src/runtime/electron/registerDevtoolsShortcuts.ts +12 -0
- package/src/runtime/electron/static.ts +14 -0
- package/src/runtime/electron/types.ts +1 -0
- package/src/runtime/electron/useDevDataDir.ts +8 -0
- package/src/runtime/electron/useNuxtRuntimeConfig.ts +7 -0
- package/src/runtime/utils/isElectron.ts +11 -0
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { crop } from '@alanscodelog/utils/crop';
|
|
2
|
+
import { run } from '@alanscodelog/utils/run';
|
|
3
|
+
import { defineNuxtModule, useLogger, createResolver, addComponentsDir, installModule, addTemplate, extendRouteRules, addImportsDir } from '@nuxt/kit';
|
|
4
|
+
import { nuxtRemoveUneededPages, nuxtFileBasedRouting, nuxtRerouteOutputTo, createConstantCaseVariables } from '@witchcraft/nuxt-utils/utils';
|
|
5
|
+
import { defu } from 'defu';
|
|
6
|
+
import fs from 'node:fs/promises';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { startup, build } from 'vite-plugin-electron';
|
|
9
|
+
import { notBundle } from 'vite-plugin-electron/plugin';
|
|
10
|
+
import { externalizeDeps } from 'vite-plugin-externalize-deps';
|
|
11
|
+
|
|
12
|
+
startup.exit = async () => {
|
|
13
|
+
if ("electronApp" in process) {
|
|
14
|
+
try {
|
|
15
|
+
const app = process.electronApp;
|
|
16
|
+
app.removeAllListeners();
|
|
17
|
+
process.kill(app.pid);
|
|
18
|
+
} catch (e) {
|
|
19
|
+
console.error("Could not kill electron instance/s.");
|
|
20
|
+
console.error(e);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const module = defineNuxtModule({
|
|
25
|
+
meta: {
|
|
26
|
+
name: "electron",
|
|
27
|
+
configKey: "electron"
|
|
28
|
+
},
|
|
29
|
+
// Default configuration options of the Nuxt module
|
|
30
|
+
defaults: {
|
|
31
|
+
srcDir: "~~/app-electron",
|
|
32
|
+
electronBuildDir: "~~/.dist/electron",
|
|
33
|
+
nonElectronNuxtBuildDir: "~~/.dist/web/.output",
|
|
34
|
+
devUserDataDir: "~~/.user-data-dir",
|
|
35
|
+
electronRoute: "/app",
|
|
36
|
+
autoOpen: process.env.AUTO_OPEN?.includes("electron"),
|
|
37
|
+
electronBuildPackScript: "npm run build:electron:pack",
|
|
38
|
+
additionalRoutes: [],
|
|
39
|
+
extraCliArgs: [],
|
|
40
|
+
enable: true,
|
|
41
|
+
electronOnlyRuntimeConfig: {},
|
|
42
|
+
usePreloadScript: true,
|
|
43
|
+
electronViteOptions: {},
|
|
44
|
+
additionalElectronVariables: {},
|
|
45
|
+
additionalViteDefinesToCopy: [],
|
|
46
|
+
notBundleOptions: {}
|
|
47
|
+
},
|
|
48
|
+
async setup(options, nuxt) {
|
|
49
|
+
if (!options.enable) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const moduleName = "@witchcraft/nuxt-electron";
|
|
53
|
+
const logger = useLogger(moduleName);
|
|
54
|
+
const { resolvePath, resolve } = createResolver(import.meta.url);
|
|
55
|
+
addComponentsDir({
|
|
56
|
+
global: true,
|
|
57
|
+
path: resolve("runtime/components")
|
|
58
|
+
});
|
|
59
|
+
await installModule("@witchcraft/ui/nuxt", nuxt.options.witchcraftUi);
|
|
60
|
+
addTemplate({
|
|
61
|
+
filename: "witchcraft-electron.css",
|
|
62
|
+
write: true,
|
|
63
|
+
getContents: () => crop`
|
|
64
|
+
@source "${resolve("runtime/components")}";
|
|
65
|
+
`
|
|
66
|
+
});
|
|
67
|
+
const isDev = nuxt.options.dev;
|
|
68
|
+
const srcDir = await resolvePath(options.srcDir, nuxt.options.alias);
|
|
69
|
+
const nonElectronNuxtBuildDir = await resolvePath(options.nonElectronNuxtBuildDir, nuxt.options.alias);
|
|
70
|
+
const electronRootBuildDir = await resolvePath(options.electronBuildDir, nuxt.options.alias);
|
|
71
|
+
const relativeElectronDir = path.relative(nuxt.options.rootDir, electronRootBuildDir);
|
|
72
|
+
const electronNuxtDir = path.join(relativeElectronDir, ".output");
|
|
73
|
+
const electronBuildDir = path.join(relativeElectronDir, "build");
|
|
74
|
+
const electronProdUrl = `${options.electronRoute}/index.html`;
|
|
75
|
+
const electronRoute = options.electronRoute;
|
|
76
|
+
const electronNuxtPublicDir = path.join(electronNuxtDir, "public");
|
|
77
|
+
const mainScriptPath = path.join(srcDir, "main.ts");
|
|
78
|
+
const preloadScriptPath = path.join(srcDir, "preload.ts");
|
|
79
|
+
const hasMainScript = await fs.stat(mainScriptPath).then(() => true).catch(() => false);
|
|
80
|
+
const hasPreloadScript = !options.usePreloadScript || await fs.stat(preloadScriptPath).then(() => true).catch(() => false);
|
|
81
|
+
const hasScripts = hasMainScript && hasPreloadScript;
|
|
82
|
+
if (!hasScripts) {
|
|
83
|
+
logger.warn(`Missing electron scripts: ${[hasMainScript ? "" : "main.ts", hasPreloadScript ? "" : "preload.ts"].join(", ")}. Skipping electron build.`);
|
|
84
|
+
}
|
|
85
|
+
const isElectronBuild = process.env.BUILD_ELECTRON === "true" && hasScripts;
|
|
86
|
+
const skipElectronPack = process.env.SKIP_ELECTRON_PACK === "true";
|
|
87
|
+
const autoOpen = !!(options.autoOpen && hasScripts && isDev);
|
|
88
|
+
const useWatch = nuxt.options.dev;
|
|
89
|
+
const devUserDataDir = options.devUserDataDir && await resolvePath(options.devUserDataDir, nuxt.options.alias);
|
|
90
|
+
if (devUserDataDir) {
|
|
91
|
+
if (!await fs.stat(devUserDataDir).then(() => true).catch(() => false)) {
|
|
92
|
+
await fs.mkdir(devUserDataDir, {
|
|
93
|
+
recursive: true
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
logger.debug({
|
|
98
|
+
isDev,
|
|
99
|
+
useWatch,
|
|
100
|
+
srcDir,
|
|
101
|
+
prodNonElectronNuxtDir: nonElectronNuxtBuildDir,
|
|
102
|
+
electronRootBuildDir,
|
|
103
|
+
relativeElectronDir,
|
|
104
|
+
electronNuxtDir,
|
|
105
|
+
electronBuildDir,
|
|
106
|
+
electronProdUrl,
|
|
107
|
+
electronRoute,
|
|
108
|
+
electronNuxtPublicDir,
|
|
109
|
+
mainScriptPath,
|
|
110
|
+
preloadScriptPath,
|
|
111
|
+
isElectronBuild,
|
|
112
|
+
skipElectronPack,
|
|
113
|
+
autoOpen,
|
|
114
|
+
devUserDataDir
|
|
115
|
+
});
|
|
116
|
+
let resolveGetViteServer;
|
|
117
|
+
const viteServerPromise = new Promise((resolve2) => {
|
|
118
|
+
resolveGetViteServer = resolve2;
|
|
119
|
+
});
|
|
120
|
+
nuxt.hook("vite:serverCreated", (server) => {
|
|
121
|
+
logger.info(`Resolved vite server.`);
|
|
122
|
+
resolveGetViteServer(server);
|
|
123
|
+
});
|
|
124
|
+
const viteServerUrl = new Promise((resolve2) => {
|
|
125
|
+
nuxt.hook("build:before", () => {
|
|
126
|
+
resolve2(void 0);
|
|
127
|
+
});
|
|
128
|
+
nuxt.hook("listen", (_server, listener) => {
|
|
129
|
+
logger.info(`Resolved server url.`, listener.url);
|
|
130
|
+
resolve2(listener.url);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
const viteConfigPromise = new Promise((resolve2) => {
|
|
134
|
+
nuxt.hook("vite:configResolved", (config) => {
|
|
135
|
+
resolve2(config);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
let maybeWatchers;
|
|
139
|
+
let started = false;
|
|
140
|
+
nuxt.hook("vite:extendConfig", (config) => {
|
|
141
|
+
config.define ??= {};
|
|
142
|
+
config.define["import.meta.electron"] = "false";
|
|
143
|
+
config.define["process.electron"] = "false";
|
|
144
|
+
});
|
|
145
|
+
const buildElectron = async () => {
|
|
146
|
+
if (maybeWatchers || started) return;
|
|
147
|
+
started = true;
|
|
148
|
+
const viteConfig = await viteConfigPromise;
|
|
149
|
+
const electronRuntimeConfig = defu(
|
|
150
|
+
options.electronOnlyRuntimeConfig,
|
|
151
|
+
nuxt.options.runtimeConfig.public
|
|
152
|
+
);
|
|
153
|
+
const additionalElectronVariables = defu(
|
|
154
|
+
options.additionalElectronVariables,
|
|
155
|
+
nuxt.options.electron.additionalElectronVariables
|
|
156
|
+
);
|
|
157
|
+
const additionalViteDefinesToCopy = [
|
|
158
|
+
...options.additionalViteDefinesToCopy,
|
|
159
|
+
...nuxt.options.electron.additionalViteDefinesToCopy ?? []
|
|
160
|
+
];
|
|
161
|
+
const copyFromVite = [
|
|
162
|
+
"__NUXT_VERSION__",
|
|
163
|
+
"process.dev",
|
|
164
|
+
"import.meta.dev",
|
|
165
|
+
"process.test",
|
|
166
|
+
"import.meta.test",
|
|
167
|
+
...additionalViteDefinesToCopy
|
|
168
|
+
];
|
|
169
|
+
const electronVariables = {
|
|
170
|
+
"process.electron": true,
|
|
171
|
+
"import.meta.electron": true,
|
|
172
|
+
...Object.fromEntries(
|
|
173
|
+
copyFromVite.map((v) => [v, viteConfig.define[v]])
|
|
174
|
+
),
|
|
175
|
+
...createConstantCaseVariables({
|
|
176
|
+
electronRoute,
|
|
177
|
+
electronProdUrl,
|
|
178
|
+
electronNuxtDir,
|
|
179
|
+
electronNuxtPublicDir,
|
|
180
|
+
electronBuildDir,
|
|
181
|
+
// ...options.additionalElectronVariables,
|
|
182
|
+
// nuxt's runtimeConfig cannot be used in electron's main since it's built seperately
|
|
183
|
+
// also we must stringify ourselves since escaped double quotes are not preserved in the final output :/
|
|
184
|
+
electronRuntimeConfig: JSON.stringify(electronRuntimeConfig).replaceAll("\\", "\\\\")
|
|
185
|
+
}, "process.env."),
|
|
186
|
+
// wut am having issue with just using STATIC. directly ???
|
|
187
|
+
...createConstantCaseVariables(
|
|
188
|
+
additionalElectronVariables,
|
|
189
|
+
"process.env.",
|
|
190
|
+
{ autoquote: false }
|
|
191
|
+
)
|
|
192
|
+
};
|
|
193
|
+
const electronViteOptions = defu(
|
|
194
|
+
{
|
|
195
|
+
build: {
|
|
196
|
+
// must be false or preload can get deleted when vite rebuilds
|
|
197
|
+
emptyOutDir: false
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
options.electronViteOptions,
|
|
201
|
+
{
|
|
202
|
+
build: {
|
|
203
|
+
outDir: electronBuildDir,
|
|
204
|
+
minify: false
|
|
205
|
+
},
|
|
206
|
+
define: electronVariables,
|
|
207
|
+
resolve: {
|
|
208
|
+
alias: nuxt.options.alias,
|
|
209
|
+
extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"]
|
|
210
|
+
},
|
|
211
|
+
plugins: [externalizeDeps()]
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
const electronCliArgs = [
|
|
215
|
+
".",
|
|
216
|
+
...process.env.NODE_ENV !== "production" && devUserDataDir ? [
|
|
217
|
+
"--user-data-dir",
|
|
218
|
+
devUserDataDir
|
|
219
|
+
] : [],
|
|
220
|
+
...options.extraCliArgs ?? []
|
|
221
|
+
];
|
|
222
|
+
const builds = [
|
|
223
|
+
{
|
|
224
|
+
entry: mainScriptPath,
|
|
225
|
+
onStart: autoOpen ? async () => {
|
|
226
|
+
await startup([...electronCliArgs]);
|
|
227
|
+
} : void 0
|
|
228
|
+
},
|
|
229
|
+
...options.usePreloadScript ? [{
|
|
230
|
+
entry: preloadScriptPath,
|
|
231
|
+
onStart: async () => {
|
|
232
|
+
(await viteServerPromise).hot.send({ type: "full-reload" });
|
|
233
|
+
},
|
|
234
|
+
build: {
|
|
235
|
+
rollupOptions: {
|
|
236
|
+
output: {
|
|
237
|
+
inlineDynamicImports: true
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}] : []
|
|
242
|
+
].map((entry) => ({
|
|
243
|
+
vite: {
|
|
244
|
+
mode: process.env.NODE_ENV,
|
|
245
|
+
...electronViteOptions,
|
|
246
|
+
build: {
|
|
247
|
+
watch: useWatch ? {
|
|
248
|
+
include: [`${srcDir}/**/*`]
|
|
249
|
+
} : null,
|
|
250
|
+
lib: {
|
|
251
|
+
entry: entry.entry,
|
|
252
|
+
formats: entry.entry.includes("preload") ? ["cjs"] : ["es"],
|
|
253
|
+
fileName: () => entry.entry.includes("preload") ? "[name].cjs" : "[name].mjs"
|
|
254
|
+
},
|
|
255
|
+
...electronViteOptions.build
|
|
256
|
+
},
|
|
257
|
+
plugins: [
|
|
258
|
+
autoOpen ? {
|
|
259
|
+
name: "plugin-start-electron",
|
|
260
|
+
async closeBundle() {
|
|
261
|
+
void entry.onStart?.();
|
|
262
|
+
}
|
|
263
|
+
} : void 0,
|
|
264
|
+
// not bundle breaks preload because it tries to required from node_modules
|
|
265
|
+
// and sandboxed windows can't do that
|
|
266
|
+
...!isElectronBuild && !entry.entry.includes("preload") ? [notBundle(options.notBundleOptions)] : [],
|
|
267
|
+
...electronViteOptions.plugins ?? []
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
}));
|
|
271
|
+
logger.debug(builds);
|
|
272
|
+
const devUrl = await viteServerUrl;
|
|
273
|
+
if (devUrl) {
|
|
274
|
+
Object.assign(process.env, {
|
|
275
|
+
VITE_DEV_SERVER_URL: devUrl.slice(0, -1)
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
logger.debug({
|
|
279
|
+
electronViteOptions,
|
|
280
|
+
prodNonElectronNuxtDir: nonElectronNuxtBuildDir,
|
|
281
|
+
electronVariables,
|
|
282
|
+
electronRuntimeConfig,
|
|
283
|
+
electronCliArgs,
|
|
284
|
+
devUrl
|
|
285
|
+
});
|
|
286
|
+
maybeWatchers = await Promise.all(builds.map(
|
|
287
|
+
async (config) => build(config).then((res) => {
|
|
288
|
+
logger.info(`Build done.`);
|
|
289
|
+
return res;
|
|
290
|
+
}).catch((err) => {
|
|
291
|
+
logger.error(`Build failed.`, err);
|
|
292
|
+
process.exit(1);
|
|
293
|
+
})
|
|
294
|
+
));
|
|
295
|
+
if (useWatch) {
|
|
296
|
+
for (const maybeWatcher of maybeWatchers) {
|
|
297
|
+
if (maybeWatcher && "on" in maybeWatcher) {
|
|
298
|
+
maybeWatcher.on("change", (e) => {
|
|
299
|
+
logger.info(`Detected change in: ${e}`);
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
if (autoOpen) {
|
|
306
|
+
nuxt.hook("close", async () => {
|
|
307
|
+
logger.info(`Killing`);
|
|
308
|
+
await startup?.exit();
|
|
309
|
+
});
|
|
310
|
+
nuxt.hook("restart", async () => {
|
|
311
|
+
logger.info(`Killing and Restarting`);
|
|
312
|
+
await startup?.exit();
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
logger.info(`Building Electron: ${isElectronBuild}`);
|
|
316
|
+
if (isElectronBuild) {
|
|
317
|
+
nuxt.hook("build:manifest", (manifest) => {
|
|
318
|
+
for (const key of Object.keys(manifest)) {
|
|
319
|
+
manifest[key].dynamicImports = [];
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
nuxtRemoveUneededPages(nuxt, ["/", electronRoute, ...options.additionalRoutes]);
|
|
323
|
+
extendRouteRules(electronRoute, { ssr: false, prerender: true }, { override: true });
|
|
324
|
+
nuxt.options.router = defu(
|
|
325
|
+
nuxtFileBasedRouting().router,
|
|
326
|
+
nuxt.options.router ?? {}
|
|
327
|
+
);
|
|
328
|
+
nuxtRerouteOutputTo(nuxt, electronNuxtDir);
|
|
329
|
+
nuxt.hook("close", async () => {
|
|
330
|
+
logger.info(`Building Electron`);
|
|
331
|
+
await buildElectron();
|
|
332
|
+
if (!skipElectronPack) {
|
|
333
|
+
logger.info(`Packing Electron`);
|
|
334
|
+
const buildCommand = run(options.electronBuildPackScript, {
|
|
335
|
+
stdio: "inherit"
|
|
336
|
+
});
|
|
337
|
+
await buildCommand.promise.catch((err) => {
|
|
338
|
+
logger.error("Error building electron.", err);
|
|
339
|
+
process.exit(1);
|
|
340
|
+
});
|
|
341
|
+
} else {
|
|
342
|
+
logger.info(`Skipping Electron Pack`);
|
|
343
|
+
}
|
|
344
|
+
logger.info(`Done Building Electron`);
|
|
345
|
+
});
|
|
346
|
+
} else {
|
|
347
|
+
if (isDev) {
|
|
348
|
+
nuxt.hook("ready", async () => {
|
|
349
|
+
logger.info("electron - ready");
|
|
350
|
+
void buildElectron();
|
|
351
|
+
});
|
|
352
|
+
logger.info(`Watching Electron`);
|
|
353
|
+
} else {
|
|
354
|
+
logger.info(`Skipping Electron Build`);
|
|
355
|
+
}
|
|
356
|
+
nuxtRerouteOutputTo(nuxt, nonElectronNuxtBuildDir);
|
|
357
|
+
}
|
|
358
|
+
addImportsDir(resolve("runtime/utils"));
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
export { module as default };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type Component } from "vue";
|
|
2
|
+
import type { WindowControlsApi } from "../electron/types.js.js";
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
borderWidth?: string;
|
|
5
|
+
buttonSize?: string;
|
|
6
|
+
borderRadius?: string;
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* Replace any of the default buttons with your own components.
|
|
10
|
+
*
|
|
11
|
+
* Note that you can get the existing button components (import from `/components/WIndowControls/[name]`) and pass a slot to change the icon then pass your new component here.
|
|
12
|
+
*
|
|
13
|
+
* If using a completely custom component, it must emit an `action` event with the action name as the value.
|
|
14
|
+
*
|
|
15
|
+
* This wrapper component sets the following css variables if you need them:
|
|
16
|
+
* `--electron-wc-size`
|
|
17
|
+
* `--electron-wc-border`
|
|
18
|
+
* `--electron-wc-rounded`
|
|
19
|
+
* `--electron-wc-diagonal` (useful for creating the close cross)
|
|
20
|
+
*/
|
|
21
|
+
components?: Partial<Record<"CloseButton" | "MinimizeButton" | "MaximizeButton" | "PinButton", Component>>;
|
|
22
|
+
buttonsOrder?: ("CloseButton" | "MinimizeButton" | "MaximizeButton" | "PinButton")[];
|
|
23
|
+
handler?: WindowControlsApi;
|
|
24
|
+
};
|
|
25
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
26
|
+
borderWidth: string;
|
|
27
|
+
buttonSize: string;
|
|
28
|
+
borderRadius: string;
|
|
29
|
+
buttonsOrder: ("CloseButton" | "MinimizeButton" | "MaximizeButton" | "PinButton")[];
|
|
30
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ClientOnly>
|
|
3
|
+
<div
|
|
4
|
+
v-if="isElectron()"
|
|
5
|
+
:class="twMerge(`
|
|
6
|
+
flex
|
|
7
|
+
items-center
|
|
8
|
+
gap-2
|
|
9
|
+
`, $attrs.class)"
|
|
10
|
+
v-bind="{ ...$attrs, class: void 0 }"
|
|
11
|
+
:style="`
|
|
12
|
+
--electron-wc-size:${props.buttonSize};
|
|
13
|
+
--electron-wc-border:${props.borderWidth};
|
|
14
|
+
--electron-wc-rounded:${props.borderRadius};
|
|
15
|
+
--electron-wc-diagonal:calc((var(--electron-wc-size) - var(--electron-wc-border)/2)*sqrt(2));
|
|
16
|
+
`"
|
|
17
|
+
>
|
|
18
|
+
<template
|
|
19
|
+
v-for="button in buttonsOrder"
|
|
20
|
+
:key="button"
|
|
21
|
+
>
|
|
22
|
+
<component
|
|
23
|
+
:is="componentsMap[button]"
|
|
24
|
+
@action="actionHandler($event)"
|
|
25
|
+
/>
|
|
26
|
+
</template>
|
|
27
|
+
</div>
|
|
28
|
+
</ClientOnly>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup>
|
|
32
|
+
import { computed, useAttrs } from "vue";
|
|
33
|
+
import CloseButton from "./WindowControls/CloseButton.vue";
|
|
34
|
+
import MaximizeButton from "./WindowControls/MaximizeButton.vue";
|
|
35
|
+
import MinimizeButton from "./WindowControls/MinimizeButton.vue";
|
|
36
|
+
import PinButton from "./WindowControls/PinButton.vue";
|
|
37
|
+
import { twMerge } from "#imports";
|
|
38
|
+
import { isElectron } from "../utils/isElectron.js";
|
|
39
|
+
const $attrs = useAttrs();
|
|
40
|
+
const props = defineProps({
|
|
41
|
+
borderWidth: { type: String, required: false, default: "2px" },
|
|
42
|
+
buttonSize: { type: String, required: false, default: "15px" },
|
|
43
|
+
borderRadius: { type: String, required: false, default: "1.5px" },
|
|
44
|
+
components: { type: Object, required: false },
|
|
45
|
+
buttonsOrder: { type: Array, required: false, default: () => ["PinButton", "MinimizeButton", "MaximizeButton", "CloseButton"] },
|
|
46
|
+
handler: { type: Function, required: false }
|
|
47
|
+
});
|
|
48
|
+
const componentsMap = computed(() => ({
|
|
49
|
+
CloseButton,
|
|
50
|
+
MinimizeButton,
|
|
51
|
+
MaximizeButton,
|
|
52
|
+
PinButton,
|
|
53
|
+
...props.components
|
|
54
|
+
}));
|
|
55
|
+
const actionHandler = computed(() => {
|
|
56
|
+
if (!isElectron()) return void 0;
|
|
57
|
+
if (!props.handler) {
|
|
58
|
+
const defaultHandlerPath = window.electron?.api?.ui?.windowAction;
|
|
59
|
+
if (defaultHandlerPath) {
|
|
60
|
+
return defaultHandlerPath;
|
|
61
|
+
} else {
|
|
62
|
+
console.warn("No ElectronWindowControls handler specified and could not find default handler at `window.electron.api.ui.windowAction`");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return props.handler;
|
|
66
|
+
});
|
|
67
|
+
</script>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type Component } from "vue";
|
|
2
|
+
import type { WindowControlsApi } from "../electron/types.js.js";
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
borderWidth?: string;
|
|
5
|
+
buttonSize?: string;
|
|
6
|
+
borderRadius?: string;
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* Replace any of the default buttons with your own components.
|
|
10
|
+
*
|
|
11
|
+
* Note that you can get the existing button components (import from `/components/WIndowControls/[name]`) and pass a slot to change the icon then pass your new component here.
|
|
12
|
+
*
|
|
13
|
+
* If using a completely custom component, it must emit an `action` event with the action name as the value.
|
|
14
|
+
*
|
|
15
|
+
* This wrapper component sets the following css variables if you need them:
|
|
16
|
+
* `--electron-wc-size`
|
|
17
|
+
* `--electron-wc-border`
|
|
18
|
+
* `--electron-wc-rounded`
|
|
19
|
+
* `--electron-wc-diagonal` (useful for creating the close cross)
|
|
20
|
+
*/
|
|
21
|
+
components?: Partial<Record<"CloseButton" | "MinimizeButton" | "MaximizeButton" | "PinButton", Component>>;
|
|
22
|
+
buttonsOrder?: ("CloseButton" | "MinimizeButton" | "MaximizeButton" | "PinButton")[];
|
|
23
|
+
handler?: WindowControlsApi;
|
|
24
|
+
};
|
|
25
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
26
|
+
borderWidth: string;
|
|
27
|
+
buttonSize: string;
|
|
28
|
+
borderRadius: string;
|
|
29
|
+
buttonsOrder: ("CloseButton" | "MinimizeButton" | "MaximizeButton" | "PinButton")[];
|
|
30
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare var __VLS_10: {};
|
|
2
|
+
type __VLS_Slots = {} & {
|
|
3
|
+
default?: (props: typeof __VLS_10) => any;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
6
|
+
action: (action: "close") => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
8
|
+
onAction?: ((action: "close") => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
10
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
11
|
+
export default _default;
|
|
12
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
13
|
+
new (): {
|
|
14
|
+
$slots: S;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<WButton
|
|
3
|
+
:border="false"
|
|
4
|
+
aria-label="Close"
|
|
5
|
+
class="
|
|
6
|
+
p-0
|
|
7
|
+
[&:hover_.default-icon:after]:bg-accent-500
|
|
8
|
+
[&:hover_.default-icon:before]:bg-accent-500
|
|
9
|
+
[&:hover_.default-icon:after]:shadow-xs
|
|
10
|
+
[&:hover_.default-icon:after]:shadow-fg/50
|
|
11
|
+
[&:hover_.default-icon:before]:shadow-xs
|
|
12
|
+
[&:hover_.default-icon:before]:shadow-fg/50
|
|
13
|
+
|
|
14
|
+
"
|
|
15
|
+
@click="emit('action', 'close')"
|
|
16
|
+
>
|
|
17
|
+
<slot>
|
|
18
|
+
<div
|
|
19
|
+
class="
|
|
20
|
+
default-icon
|
|
21
|
+
relative
|
|
22
|
+
w-[calc(var(--electron-wc-size)-var(--electron-wc-border)/2)]
|
|
23
|
+
h-[calc(var(--electron-wc-size)-var(--electron-wc-border)/2)]
|
|
24
|
+
before:absolute
|
|
25
|
+
before:content-['']
|
|
26
|
+
before:left-0
|
|
27
|
+
before:rotate-45
|
|
28
|
+
before:origin-left
|
|
29
|
+
before:top-[calc(var(--electron-wc-border)/-2)]
|
|
30
|
+
before:w-[var(--electron-wc-diagonal)]
|
|
31
|
+
before:h-[var(--electron-wc-border)]
|
|
32
|
+
before:rounded-(--electron-wc-rounded)
|
|
33
|
+
before:bg-fg
|
|
34
|
+
dark:before:bg-bg
|
|
35
|
+
after:absolute
|
|
36
|
+
after:content-['']
|
|
37
|
+
after:origin-top
|
|
38
|
+
after:right-[calc(var(--electron-wc-border)/-2)]
|
|
39
|
+
after:top-0
|
|
40
|
+
after:rotate-[45deg]
|
|
41
|
+
after:h-[var(--electron-wc-diagonal)]
|
|
42
|
+
after:w-[var(--electron-wc-border)]
|
|
43
|
+
after:bg-fg
|
|
44
|
+
after:rounded-(--electron-wc-rounded)
|
|
45
|
+
dark:after:bg-bg
|
|
46
|
+
"
|
|
47
|
+
/>
|
|
48
|
+
</slot>
|
|
49
|
+
</WButton>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script setup>
|
|
53
|
+
const emit = defineEmits(["action"]);
|
|
54
|
+
</script>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare var __VLS_10: {};
|
|
2
|
+
type __VLS_Slots = {} & {
|
|
3
|
+
default?: (props: typeof __VLS_10) => any;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
6
|
+
action: (action: "close") => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
8
|
+
onAction?: ((action: "close") => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
10
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
11
|
+
export default _default;
|
|
12
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
13
|
+
new (): {
|
|
14
|
+
$slots: S;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare var __VLS_10: {};
|
|
2
|
+
type __VLS_Slots = {} & {
|
|
3
|
+
default?: (props: typeof __VLS_10) => any;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
6
|
+
action: (action: "toggleMaximize") => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
8
|
+
onAction?: ((action: "toggleMaximize") => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
10
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
11
|
+
export default _default;
|
|
12
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
13
|
+
new (): {
|
|
14
|
+
$slots: S;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<WButton
|
|
3
|
+
:border="false"
|
|
4
|
+
aria-label="Toggle Maximize"
|
|
5
|
+
class="
|
|
6
|
+
p-0
|
|
7
|
+
[&:hover_.default-icon]:border-accent-500
|
|
8
|
+
[&:hover_.default-icon]:shadow-xs
|
|
9
|
+
[&:hover_.default-icon]:shadow-fg/50
|
|
10
|
+
|
|
11
|
+
"
|
|
12
|
+
@click="emit('action', 'toggleMaximize')"
|
|
13
|
+
>
|
|
14
|
+
<slot>
|
|
15
|
+
<div
|
|
16
|
+
class="
|
|
17
|
+
default-icon
|
|
18
|
+
border-fg
|
|
19
|
+
dark:border-bg
|
|
20
|
+
hover:border-accent-500
|
|
21
|
+
border-[length:var(--electron-wc-border)]
|
|
22
|
+
rounded-(--electron-wc-rounded)
|
|
23
|
+
w-[var(--electron-wc-size)]
|
|
24
|
+
h-[var(--electron-wc-size)]
|
|
25
|
+
"
|
|
26
|
+
/>
|
|
27
|
+
</slot>
|
|
28
|
+
</WButton>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup>
|
|
32
|
+
const emit = defineEmits(["action"]);
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare var __VLS_10: {};
|
|
2
|
+
type __VLS_Slots = {} & {
|
|
3
|
+
default?: (props: typeof __VLS_10) => any;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
6
|
+
action: (action: "toggleMaximize") => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
8
|
+
onAction?: ((action: "toggleMaximize") => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
10
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
11
|
+
export default _default;
|
|
12
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
13
|
+
new (): {
|
|
14
|
+
$slots: S;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare var __VLS_10: {};
|
|
2
|
+
type __VLS_Slots = {} & {
|
|
3
|
+
default?: (props: typeof __VLS_10) => any;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
6
|
+
action: (action: "minimize") => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
8
|
+
onAction?: ((action: "minimize") => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
10
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
11
|
+
export default _default;
|
|
12
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
13
|
+
new (): {
|
|
14
|
+
$slots: S;
|
|
15
|
+
};
|
|
16
|
+
};
|