create-electro 1.0.5
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/LICENSE +21 -0
- package/README.md +24 -0
- package/bin/create-electro.mjs +9 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +10 -0
- package/package.json +54 -0
- package/template/monorepo/README.md +19 -0
- package/template/monorepo/electro.config.ts +6 -0
- package/template/monorepo/package.json +26 -0
- package/template/monorepo/pnpm-workspace.yaml +3 -0
- package/template/monorepo/runtime/electro-env.d.ts +90 -0
- package/template/monorepo/runtime/package.json +15 -0
- package/template/monorepo/runtime/runtime.config.ts +5 -0
- package/template/monorepo/runtime/src/main.ts +25 -0
- package/template/monorepo/runtime/src/modules/app.module.ts +35 -0
- package/template/monorepo/runtime/src/modules/app.shell.service.ts +54 -0
- package/template/monorepo/runtime/src/modules/app.view.ts +22 -0
- package/template/monorepo/runtime/src/modules/app.window.ts +54 -0
- package/template/monorepo/runtime/src/modules/notes/notes.module.ts +8 -0
- package/template/monorepo/runtime/src/modules/notes/notes.service.ts +55 -0
- package/template/monorepo/runtime/tsconfig.json +11 -0
- package/template/monorepo/views/main/electro-env.d.ts +51 -0
- package/template/monorepo/views/main/index.html +12 -0
- package/template/monorepo/views/main/package.json +17 -0
- package/template/monorepo/views/main/src/app.css +1254 -0
- package/template/monorepo/views/main/src/app.tsx +464 -0
- package/template/monorepo/views/main/src/icon.svg +11 -0
- package/template/monorepo/views/main/src/main.tsx +12 -0
- package/template/monorepo/views/main/tsconfig.json +9 -0
- package/template/monorepo/views/main/view.config.ts +8 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Anton Ryuben
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# create-electro
|
|
2
|
+
|
|
3
|
+
Scaffold a new ElectroJS application with the supported monorepo-first layout.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm create electro@latest my-app
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
or
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm create electro my-app
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The generated project contains:
|
|
18
|
+
|
|
19
|
+
- a root `electro.config.ts`
|
|
20
|
+
- a `runtime/` package
|
|
21
|
+
- a `views/main/` package
|
|
22
|
+
- package-local `electro-env.d.ts` starter files
|
|
23
|
+
|
|
24
|
+
ElectroJS documents and supports this monorepo-style layout. Other layouts are outside the documented path.
|
package/dist/index.d.mts
ADDED
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import{basename as e,dirname as t,join as n,resolve as r}from"node:path";import{fileURLToPath as i}from"node:url";import{mkdir as a,readFile as o,readdir as s,stat as c,writeFile as l}from"node:fs/promises";const u=i(new URL(`../template/monorepo`,import.meta.url));function d(e){let t=e.trim().toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``);return t.length>0?t:`electro-app`}function f(e){return e.split(/[^a-zA-Z0-9]+/).filter(e=>e.length>0).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}function p(e){let t=d(e);return{packageName:t,displayName:f(t)}}function m(e){return{__DISPLAY_NAME__:e.displayName,__ELECTRON_VERSION__:`41.0.4`,__FRAMEWORK_VERSION__:`2.0.0`,__NODE_TYPES_VERSION__:`^25.5.0`,__PACKAGE_MANAGER__:`pnpm@10.32.1`,__PACKAGE_NAME__:e.packageName,__REACT_DOM_TYPES_VERSION__:`^19.2.3`,__REACT_TYPES_VERSION__:`^19.2.14`,__REACT_VERSION__:`^19.2.4`,__TYPESCRIPT_VERSION__:`^6.0.2`,__VITE_REACT_PLUGIN_VERSION__:`^6.0.1`,__VITE_VERSION__:`^8.0.2`}}function h(e,t){let n=e;for(let[e,r]of Object.entries(t))n=n.replaceAll(e,r);return n}async function g(e){try{return await c(e),!0}catch{return!1}}async function _(e,t){if(!await g(e)){await a(e,{recursive:!0});return}if((await s(e)).length>0&&!t)throw Error(`Target directory "${e}" is not empty. Use --force to overwrite scaffold files.`)}async function v(e,t=e){let r=await s(t,{withFileTypes:!0}),i=[];for(let a of r){let r=n(t,a.name);if(a.isDirectory()){i.push(...await v(e,r));continue}a.isFile()&&i.push(r)}return i.sort()}async function y(e,r){let i=m(r),s=await v(u),c=[];for(let r of s){let s=n(e,r.slice(u.length+1)),d=h(await o(r,`utf8`),i);await a(t(s),{recursive:!0}),await l(s,d,`utf8`),c.push(s)}return c.sort()}async function b(e){return await _(e.projectDir,e.force),y(e.projectDir,p(e.projectName))}function x(){console.log(`create-electro
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
npm create electro@latest [project-name]
|
|
5
|
+
pnpm create electro [project-name]
|
|
6
|
+
|
|
7
|
+
Options:
|
|
8
|
+
-f, --force Overwrite scaffold files in a non-empty directory
|
|
9
|
+
-h, --help Show this help message
|
|
10
|
+
`)}function S(e){let t=!1,n=!1,r=`electro-app`;for(let i of e){if(i===`--force`||i===`-f`){t=!0;continue}if(i===`--help`||i===`-h`){n=!0;continue}if(i.startsWith(`-`))throw Error(`Unknown option "${i}".`);r=i}return{force:t,help:n,targetDir:r}}function C(e){return e===`.`||e===`./`?null:e}async function w(t=process.argv.slice(2)){let n=S(t);if(n.help){x();return}let i=r(process.cwd(),n.targetDir),a=e(i),o=await b({force:n.force,projectDir:i,projectName:a});console.log(`\nScaffolded ElectroJS app in ${i}`),console.log(`Created ${o.length} file(s).\n`),console.log(`Next steps:`);let s=C(n.targetDir);s&&console.log(` cd ${s}`),console.log(` pnpm install`),console.log(` pnpm run dev`)}const T=process.argv[1];T&&r(T)===i(import.meta.url)&&await w(process.argv.slice(2)).catch(e=>{let t=e instanceof Error?e.message:String(e);console.error(t),process.exitCode=1});export{w as runCli};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-electro",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "Scaffold a new ElectroJS Electron app with the recommended monorepo layout",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"create",
|
|
7
|
+
"electro",
|
|
8
|
+
"electrojs",
|
|
9
|
+
"electron",
|
|
10
|
+
"scaffold",
|
|
11
|
+
"starter",
|
|
12
|
+
"template",
|
|
13
|
+
"vite"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://electrojs.myraxbyte.dev/",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/MyraxByte/electrojs/issues"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/MyraxByte/electrojs.git",
|
|
23
|
+
"directory": "packages/create-electro"
|
|
24
|
+
},
|
|
25
|
+
"bin": {
|
|
26
|
+
"create-electro": "./bin/create-electro.mjs"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin",
|
|
30
|
+
"dist",
|
|
31
|
+
"template",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"type": "module",
|
|
35
|
+
"main": "./dist/index.mjs",
|
|
36
|
+
"types": "./dist/index.d.mts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.mts",
|
|
40
|
+
"import": "./dist/index.mjs"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"tsdown": "^0.21.4",
|
|
48
|
+
"vitest": "^4.1.1"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsdown",
|
|
52
|
+
"test": "vitest"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# **DISPLAY_NAME**
|
|
2
|
+
|
|
3
|
+
ElectroJS monorepo application scaffolded with `create-electro`.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm install
|
|
9
|
+
pnpm run dev
|
|
10
|
+
pnpm run generate
|
|
11
|
+
pnpm run build
|
|
12
|
+
pnpm run preview
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Layout
|
|
16
|
+
|
|
17
|
+
- `runtime/` contains the Electron main-process runtime package
|
|
18
|
+
- `views/main/` contains the first renderer package
|
|
19
|
+
- `electro.config.ts` wires runtime and views together through explicit package specifiers
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PACKAGE_NAME__",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "electro dev",
|
|
8
|
+
"build": "electro build",
|
|
9
|
+
"preview": "electro preview",
|
|
10
|
+
"generate": "electro generate"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@electrojs/cli": "__FRAMEWORK_VERSION__",
|
|
14
|
+
"@electrojs/config": "__FRAMEWORK_VERSION__",
|
|
15
|
+
"@types/node": "__NODE_TYPES_VERSION__",
|
|
16
|
+
"electron": "__ELECTRON_VERSION__",
|
|
17
|
+
"typescript": "__TYPESCRIPT_VERSION__",
|
|
18
|
+
"vite": "__VITE_VERSION__"
|
|
19
|
+
},
|
|
20
|
+
"packageManager": "__PACKAGE_MANAGER__",
|
|
21
|
+
"pnpm": {
|
|
22
|
+
"onlyBuiltDependencies": [
|
|
23
|
+
"electron"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Auto-generated by ElectroJS codegen. Do not edit.
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
// ElectroJS runtime authoring contract types — provides IDE completions for modules, signals, jobs, windows, and runtime-declared views.
|
|
4
|
+
|
|
5
|
+
export {};
|
|
6
|
+
|
|
7
|
+
type _Instance<T> = T extends abstract new (...args: never[]) => infer R ? R : never;
|
|
8
|
+
type _ModuleAuthoringApi<TModuleId extends import("@electrojs/runtime").ModuleRegistryId> = import("@electrojs/runtime").ModuleAuthoringApi<TModuleId>;
|
|
9
|
+
type _WindowAuthoringApi = import("@electrojs/runtime").WindowAuthoringApi;
|
|
10
|
+
type _ViewAuthoringApi = import("@electrojs/runtime").ViewAuthoringApi;
|
|
11
|
+
type _InvokeMethod<T, K extends PropertyKey> = K extends keyof _Instance<T>
|
|
12
|
+
? _Instance<T>[K] extends (...args: infer A) => infer V
|
|
13
|
+
? (...args: A) => Promise<Awaited<V>>
|
|
14
|
+
: never
|
|
15
|
+
: never;
|
|
16
|
+
|
|
17
|
+
declare module "@electrojs/runtime" {
|
|
18
|
+
interface ModuleMethodMap {
|
|
19
|
+
"notes:createNote": _InvokeMethod<typeof import("./src/modules/notes/notes.service").NotesService, "createNote">;
|
|
20
|
+
"notes:getNotes": _InvokeMethod<typeof import("./src/modules/notes/notes.service").NotesService, "getNotes">;
|
|
21
|
+
"notes:deleteNote": _InvokeMethod<typeof import("./src/modules/notes/notes.service").NotesService, "deleteNote">;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface ModuleApiRegistry {
|
|
25
|
+
app: {};
|
|
26
|
+
notes: {
|
|
27
|
+
createNote: _InvokeMethod<typeof import("./src/modules/notes/notes.service").NotesService, "createNote">;
|
|
28
|
+
getNotes: _InvokeMethod<typeof import("./src/modules/notes/notes.service").NotesService, "getNotes">;
|
|
29
|
+
deleteNote: _InvokeMethod<typeof import("./src/modules/notes/notes.service").NotesService, "deleteNote">;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface ModuleSignalPayloadMap {}
|
|
34
|
+
|
|
35
|
+
interface ModuleJobRegistry {
|
|
36
|
+
app: never;
|
|
37
|
+
notes: never;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface InjectableClassRegistry {
|
|
41
|
+
NotesService: typeof import("./src/modules/notes/notes.service").NotesService;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface WindowClassRegistry {
|
|
45
|
+
main: typeof import("./src/modules/app.window").MainWindow;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface ViewClassRegistry {
|
|
49
|
+
main: typeof import("./src/modules/app.view").MainView;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
declare module "@electrojs/common" {
|
|
54
|
+
interface ViewAccessRegistry {
|
|
55
|
+
"notes:createNote": true;
|
|
56
|
+
"notes:getNotes": true;
|
|
57
|
+
"notes:deleteNote": true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface ViewSignalRegistry {}
|
|
61
|
+
|
|
62
|
+
interface BundledViewIdRegistry {
|
|
63
|
+
main: true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
import "./src/modules/app.module";
|
|
68
|
+
declare module "./src/modules/app.module" {
|
|
69
|
+
interface AppModule extends _ModuleAuthoringApi<"app"> {}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
import "./src/modules/notes/notes.module";
|
|
73
|
+
declare module "./src/modules/notes/notes.module" {
|
|
74
|
+
interface NotesModule extends _ModuleAuthoringApi<"notes"> {}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
import "./src/modules/notes/notes.service";
|
|
78
|
+
declare module "./src/modules/notes/notes.service" {
|
|
79
|
+
interface NotesService extends _ModuleAuthoringApi<"notes"> {}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
import "./src/modules/app.window";
|
|
83
|
+
declare module "./src/modules/app.window" {
|
|
84
|
+
interface MainWindow extends _WindowAuthoringApi {}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
import "./src/modules/app.view";
|
|
88
|
+
declare module "./src/modules/app.view" {
|
|
89
|
+
interface MainView extends _ViewAuthoringApi {}
|
|
90
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "runtime",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"devDependencies": {
|
|
7
|
+
"@electrojs/common": "__FRAMEWORK_VERSION__",
|
|
8
|
+
"@electrojs/config": "__FRAMEWORK_VERSION__",
|
|
9
|
+
"@electrojs/runtime": "__FRAMEWORK_VERSION__",
|
|
10
|
+
"@types/node": "__NODE_TYPES_VERSION__",
|
|
11
|
+
"electron": "__ELECTRON_VERSION__",
|
|
12
|
+
"typescript": "__TYPESCRIPT_VERSION__",
|
|
13
|
+
"vite": "__VITE_VERSION__"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AppKernel, createConsoleLogger } from "@electrojs/runtime";
|
|
2
|
+
import { app } from "electron";
|
|
3
|
+
import { AppModule } from "./modules/app.module";
|
|
4
|
+
|
|
5
|
+
const kernel = AppKernel.create(AppModule, {
|
|
6
|
+
logger: createConsoleLogger(),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
if (!app.requestSingleInstanceLock()) {
|
|
10
|
+
app.quit();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
app.on("window-all-closed", () => {
|
|
14
|
+
if (process.platform !== "darwin") {
|
|
15
|
+
app.quit();
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
app.on("before-quit", () => {
|
|
20
|
+
void kernel.shutdown();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
void app.whenReady().then(async () => {
|
|
24
|
+
await kernel.start();
|
|
25
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Module } from "@electrojs/common";
|
|
2
|
+
import { app } from "electron";
|
|
3
|
+
import { inject } from "@electrojs/runtime";
|
|
4
|
+
import { ShellService } from "./app.shell.service";
|
|
5
|
+
import { NotesModule } from "./notes/notes.module";
|
|
6
|
+
import { MainView } from "./app.view";
|
|
7
|
+
import { MainWindow } from "./app.window";
|
|
8
|
+
|
|
9
|
+
@Module({
|
|
10
|
+
imports: [NotesModule],
|
|
11
|
+
providers: [ShellService],
|
|
12
|
+
views: [MainView],
|
|
13
|
+
windows: [MainWindow],
|
|
14
|
+
})
|
|
15
|
+
export class AppModule {
|
|
16
|
+
private readonly window = inject(MainWindow);
|
|
17
|
+
|
|
18
|
+
async onInit() {
|
|
19
|
+
this.window.register();
|
|
20
|
+
|
|
21
|
+
app.on("activate", async () => {
|
|
22
|
+
if (!this.window.window) {
|
|
23
|
+
this.window.register();
|
|
24
|
+
await this.window.open();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.window.show();
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async onReady() {
|
|
33
|
+
await this.window.open();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Injectable, command, query } from "@electrojs/common";
|
|
2
|
+
import { inject } from "@electrojs/runtime";
|
|
3
|
+
import { shell } from "electron";
|
|
4
|
+
import { MainWindow } from "./app.window";
|
|
5
|
+
|
|
6
|
+
const DOCS_URL = "https://electrojs.myraxbyte.dev/";
|
|
7
|
+
|
|
8
|
+
export interface ShellState {
|
|
9
|
+
readonly platform: string;
|
|
10
|
+
readonly isMaximized: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@Injectable()
|
|
14
|
+
export class ShellService {
|
|
15
|
+
private readonly mainWindow = inject(MainWindow);
|
|
16
|
+
|
|
17
|
+
@query()
|
|
18
|
+
public getShellState(): ShellState {
|
|
19
|
+
return {
|
|
20
|
+
platform: process.platform,
|
|
21
|
+
isMaximized: this.mainWindow.window?.isMaximized() ?? false,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@command()
|
|
26
|
+
public minimizeWindow(): void {
|
|
27
|
+
this.mainWindow.window?.minimize();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@command()
|
|
31
|
+
public toggleMaximizeWindow(): ShellState {
|
|
32
|
+
const window = this.mainWindow.window;
|
|
33
|
+
|
|
34
|
+
if (window) {
|
|
35
|
+
if (window.isMaximized()) {
|
|
36
|
+
window.unmaximize();
|
|
37
|
+
} else {
|
|
38
|
+
window.maximize();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return this.getShellState();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@command()
|
|
46
|
+
public closeWindow(): void {
|
|
47
|
+
this.mainWindow.window?.close();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@command()
|
|
51
|
+
public async openDocumentation(): Promise<void> {
|
|
52
|
+
await shell.openExternal(DOCS_URL);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { View } from "@electrojs/common";
|
|
2
|
+
import { ViewProvider } from "@electrojs/runtime";
|
|
3
|
+
|
|
4
|
+
@View({
|
|
5
|
+
access: [
|
|
6
|
+
"app:getShellState",
|
|
7
|
+
"app:minimizeWindow",
|
|
8
|
+
"app:toggleMaximizeWindow",
|
|
9
|
+
"app:closeWindow",
|
|
10
|
+
"app:openDocumentation",
|
|
11
|
+
"notes:createNote",
|
|
12
|
+
"notes:getNotes",
|
|
13
|
+
"notes:deleteNote",
|
|
14
|
+
],
|
|
15
|
+
source: "view:main",
|
|
16
|
+
configuration: {},
|
|
17
|
+
})
|
|
18
|
+
export class MainView extends ViewProvider {
|
|
19
|
+
public resize(width: number, height: number) {
|
|
20
|
+
this.contentView?.setBounds({ x: 0, y: 0, width, height });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Window } from "@electrojs/common";
|
|
2
|
+
import { inject, WindowProvider } from "@electrojs/runtime";
|
|
3
|
+
import { shell } from "electron";
|
|
4
|
+
import { MainView } from "./app.view";
|
|
5
|
+
import { app, Menu } from "electron/main";
|
|
6
|
+
|
|
7
|
+
const isMacOS = process.platform === "darwin";
|
|
8
|
+
const isWindows = process.platform === "win32";
|
|
9
|
+
|
|
10
|
+
@Window({
|
|
11
|
+
id: "main",
|
|
12
|
+
configuration: {
|
|
13
|
+
width: 1360,
|
|
14
|
+
height: 860,
|
|
15
|
+
minWidth: 1120,
|
|
16
|
+
minHeight: 720,
|
|
17
|
+
show: false,
|
|
18
|
+
frame: false,
|
|
19
|
+
transparent: true,
|
|
20
|
+
visualEffectState: "active",
|
|
21
|
+
backgroundColor: "#00000000",
|
|
22
|
+
...(isMacOS && { vibrancy: "fullscreen-ui" }),
|
|
23
|
+
...(isWindows && { backgroundMaterial: "mica" }),
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
export class MainWindow extends WindowProvider {
|
|
27
|
+
private readonly view = inject(MainView);
|
|
28
|
+
|
|
29
|
+
public register() {
|
|
30
|
+
this.create();
|
|
31
|
+
this.window?.on("resize", () => this.onResize());
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public onResize() {
|
|
35
|
+
const bounds = this.window?.getBounds();
|
|
36
|
+
this.view.resize(bounds?.width ?? 0, bounds?.height ?? 0);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async open() {
|
|
40
|
+
await this.view.load();
|
|
41
|
+
this.onResize();
|
|
42
|
+
this.view.setBackgroundColor("#00000000");
|
|
43
|
+
if (isMacOS) {
|
|
44
|
+
this.view.setWindowButtonVisibility(false);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.mount(this.view);
|
|
48
|
+
this.view.webContents?.setWindowOpenHandler((details) => {
|
|
49
|
+
void shell.openExternal(details.url);
|
|
50
|
+
return { action: "deny" };
|
|
51
|
+
});
|
|
52
|
+
this.show();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Injectable, command, query } from "@electrojs/common";
|
|
2
|
+
|
|
3
|
+
export interface Note {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly title: string;
|
|
6
|
+
readonly content: string;
|
|
7
|
+
readonly createdAt: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@Injectable()
|
|
11
|
+
export class NotesService {
|
|
12
|
+
private readonly notes: Note[] = [
|
|
13
|
+
{
|
|
14
|
+
id: "bridge-demo",
|
|
15
|
+
title: "Bridge is connected",
|
|
16
|
+
content: "This note was loaded via bridge.notes.getNotes() — a @query method in the runtime. Try creating and deleting notes to test @command methods.",
|
|
17
|
+
createdAt: new Date().toISOString(),
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "architecture",
|
|
21
|
+
title: "How this app works",
|
|
22
|
+
content: "AppModule composes the runtime graph. ShellService exposes window controls. NotesService handles CRUD. Everything is typed end-to-end.",
|
|
23
|
+
createdAt: new Date().toISOString(),
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
@query()
|
|
28
|
+
getNotes(): Note[] {
|
|
29
|
+
return [...this.notes];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@command()
|
|
33
|
+
createNote(title: string, content: string): Note {
|
|
34
|
+
const note: Note = {
|
|
35
|
+
id: crypto.randomUUID(),
|
|
36
|
+
title,
|
|
37
|
+
content,
|
|
38
|
+
createdAt: new Date().toISOString(),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
this.notes.unshift(note);
|
|
42
|
+
return note;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@command()
|
|
46
|
+
deleteNote(id: string): boolean {
|
|
47
|
+
const index = this.notes.findIndex((note) => note.id === id);
|
|
48
|
+
if (index === -1) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.notes.splice(index, 1);
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Auto-generated by ElectroJS codegen. Do not edit.
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
// ElectroJS renderer bridge contract types — provides IDE completions for bridge access and forwarded signals.
|
|
4
|
+
|
|
5
|
+
export {};
|
|
6
|
+
|
|
7
|
+
type _Instance<T> = T extends abstract new (...args: never[]) => infer R ? R : never;
|
|
8
|
+
type _BridgeInputFromMethod<T, K extends PropertyKey> = K extends keyof _Instance<T>
|
|
9
|
+
? _Instance<T>[K] extends (...args: infer A) => infer _Ignored
|
|
10
|
+
? A extends []
|
|
11
|
+
? undefined
|
|
12
|
+
: A extends [infer TOnly]
|
|
13
|
+
? TOnly
|
|
14
|
+
: A
|
|
15
|
+
: never
|
|
16
|
+
: never;
|
|
17
|
+
type _BridgeOutputFromMethod<T, K extends PropertyKey> = K extends keyof _Instance<T>
|
|
18
|
+
? _Instance<T>[K] extends (...args: infer _Args) => infer V
|
|
19
|
+
? Awaited<V>
|
|
20
|
+
: never
|
|
21
|
+
: never;
|
|
22
|
+
|
|
23
|
+
declare module "@electrojs/renderer" {
|
|
24
|
+
interface BridgeQueries {
|
|
25
|
+
"notes:getNotes": import("@electrojs/renderer").BridgeContractEntry<
|
|
26
|
+
_BridgeInputFromMethod<typeof import("../../runtime/src/modules/notes/notes.service").NotesService, "getNotes">,
|
|
27
|
+
_BridgeOutputFromMethod<typeof import("../../runtime/src/modules/notes/notes.service").NotesService, "getNotes">
|
|
28
|
+
>;
|
|
29
|
+
"notes:createNote": import("@electrojs/renderer").BridgeContractEntry<
|
|
30
|
+
_BridgeInputFromMethod<typeof import("../../runtime/src/modules/notes/notes.service").NotesService, "createNote">,
|
|
31
|
+
_BridgeOutputFromMethod<typeof import("../../runtime/src/modules/notes/notes.service").NotesService, "createNote">
|
|
32
|
+
>;
|
|
33
|
+
"notes:deleteNote": import("@electrojs/renderer").BridgeContractEntry<
|
|
34
|
+
_BridgeInputFromMethod<typeof import("../../runtime/src/modules/notes/notes.service").NotesService, "deleteNote">,
|
|
35
|
+
_BridgeOutputFromMethod<typeof import("../../runtime/src/modules/notes/notes.service").NotesService, "deleteNote">
|
|
36
|
+
>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface BridgeCommands {
|
|
40
|
+
"notes:createNote": import("@electrojs/renderer").BridgeContractEntry<
|
|
41
|
+
_BridgeInputFromMethod<typeof import("../../runtime/src/modules/notes/notes.service").NotesService, "createNote">,
|
|
42
|
+
_BridgeOutputFromMethod<typeof import("../../runtime/src/modules/notes/notes.service").NotesService, "createNote">
|
|
43
|
+
>;
|
|
44
|
+
"notes:deleteNote": import("@electrojs/renderer").BridgeContractEntry<
|
|
45
|
+
_BridgeInputFromMethod<typeof import("../../runtime/src/modules/notes/notes.service").NotesService, "deleteNote">,
|
|
46
|
+
_BridgeOutputFromMethod<typeof import("../../runtime/src/modules/notes/notes.service").NotesService, "deleteNote">
|
|
47
|
+
>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface BridgeSignals {}
|
|
51
|
+
}
|
|
@@ -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>__DISPLAY_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,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@views/main",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"devDependencies": {
|
|
7
|
+
"@electrojs/config": "__FRAMEWORK_VERSION__",
|
|
8
|
+
"@electrojs/renderer": "__FRAMEWORK_VERSION__",
|
|
9
|
+
"@types/react": "__REACT_TYPES_VERSION__",
|
|
10
|
+
"@types/react-dom": "__REACT_DOM_TYPES_VERSION__",
|
|
11
|
+
"@vitejs/plugin-react": "__VITE_REACT_PLUGIN_VERSION__",
|
|
12
|
+
"react": "__REACT_VERSION__",
|
|
13
|
+
"react-dom": "__REACT_VERSION__",
|
|
14
|
+
"typescript": "__TYPESCRIPT_VERSION__",
|
|
15
|
+
"vite": "__VITE_VERSION__"
|
|
16
|
+
}
|
|
17
|
+
}
|