Add v2 rewrite: monorepo with desktop and web apps, shared packages, docs, and wireframes
This commit is contained in:
5
apps/desktop/package.json
Normal file
5
apps/desktop/package.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@mosaiciq/desktop",
|
||||
"private": true,
|
||||
"type": "module"
|
||||
}
|
||||
7
apps/desktop/src/README.md
Normal file
7
apps/desktop/src/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Desktop Source Layout
|
||||
|
||||
- `main.ts`: Electron app lifecycle and browser window setup.
|
||||
- `preload.ts`: isolated bridge exposed to the renderer.
|
||||
- `rpc.ts`: local RPC method handling.
|
||||
|
||||
The desktop app owns Electron APIs. Renderer-facing types come from `packages/contracts`, and reusable non-Electron data belongs in `packages/shared`.
|
||||
46
apps/desktop/src/main.ts
Normal file
46
apps/desktop/src/main.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { app, BrowserWindow, ipcMain } from "electron";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { handleRpc } from "./rpc.js";
|
||||
import type { RpcMethod, RpcRequestMap } from "../../../packages/contracts/src/rpc.js";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const isDev = process.env.VITE_DEV_SERVER_URL || !app.isPackaged;
|
||||
|
||||
async function createWindow() {
|
||||
const win = new BrowserWindow({
|
||||
width: 1440,
|
||||
height: 960,
|
||||
minWidth: 1024,
|
||||
minHeight: 700,
|
||||
title: "MosaicIQ",
|
||||
backgroundColor: "#f8f5ed",
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, "preload.js"),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
sandbox: false
|
||||
}
|
||||
});
|
||||
|
||||
if (isDev) {
|
||||
await win.loadURL(process.env.VITE_DEV_SERVER_URL ?? "http://127.0.0.1:5173");
|
||||
win.webContents.openDevTools({ mode: "detach" });
|
||||
} else {
|
||||
await win.loadFile(path.join(__dirname, "../../../../apps/web/dist/index.html"));
|
||||
}
|
||||
}
|
||||
|
||||
ipcMain.handle("rpc:call", (_event, method: RpcMethod, payload: RpcRequestMap[RpcMethod]) => {
|
||||
return handleRpc(method, payload);
|
||||
});
|
||||
|
||||
app.whenReady().then(createWindow);
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") app.quit();
|
||||
});
|
||||
|
||||
app.on("activate", () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) void createWindow();
|
||||
});
|
||||
21
apps/desktop/src/preload.ts
Normal file
21
apps/desktop/src/preload.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { contextBridge, ipcRenderer } from "electron";
|
||||
import type { RpcClient, RpcMethod, RpcRequestMap } from "../../../packages/contracts/src/rpc.js";
|
||||
|
||||
const api: RpcClient = {
|
||||
call(method, payload) {
|
||||
return ipcRenderer.invoke("rpc:call", method, payload);
|
||||
}
|
||||
};
|
||||
|
||||
contextBridge.exposeInMainWorld("mosaic", api);
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
mosaic: {
|
||||
call<T extends RpcMethod>(
|
||||
method: T,
|
||||
payload: RpcRequestMap[T]
|
||||
): Promise<import("../../../packages/contracts/src/rpc.js").RpcResult<T>>;
|
||||
};
|
||||
}
|
||||
}
|
||||
9
apps/desktop/src/rpc.ts
Normal file
9
apps/desktop/src/rpc.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { RpcMethod, RpcRequestMap, RpcResult } from "../../../packages/contracts/src/rpc.js";
|
||||
import { handleMockRpc } from "../../../packages/shared/src/mockRpc.js";
|
||||
|
||||
export async function handleRpc<T extends RpcMethod>(
|
||||
method: T,
|
||||
payload: RpcRequestMap[T]
|
||||
): Promise<RpcResult<T>> {
|
||||
return handleMockRpc(method, payload);
|
||||
}
|
||||
Reference in New Issue
Block a user