feat(main): add Electron entry + Inbox window shell
Task 2 of the slice plan. Creates the minimal Electron main
process: app entry that opens an Inbox BrowserWindow on
whenReady, an inboxWindow module that handles show/hide/close-
to-tray semantics, an HTML placeholder renderer ("Inkling Inbox
(renderer pending)"), and the minimum @shared/types augmentation
for app.isQuitting (Task 3 expands this file).
Plan tsconfig template adjustment: TypeScript 6 deprecates
baseUrl. Dropped it and made paths entries explicitly relative
("./src/...") so they resolve from tsconfig.json's directory.
Updated both the in-repo tsconfig.json and Task 1 Step 3 in the
plan to match.
Verification: `npm run typecheck` exits 0. Full `npm run dev`
sanity check is deferred until Task 3 (preload) and Task 19
(quickcapture HTML) land — electron-vite.config.ts wires both
entries that don't yet exist.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -181,10 +181,9 @@ If a version is not yet published, run `npm view <pkg> version` and use the late
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"types": ["node"],
|
"types": ["node"],
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@shared/*": ["src/shared/*"],
|
"@shared/*": ["./src/shared/*"],
|
||||||
"@main/*": ["src/main/*"]
|
"@main/*": ["./src/main/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*", "tests/**/*"],
|
"include": ["src/**/*", "tests/**/*"],
|
||||||
|
|||||||
12
src/main/index.ts
Normal file
12
src/main/index.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { app, BrowserWindow } from 'electron';
|
||||||
|
import '@shared/types';
|
||||||
|
import { createInboxWindow } from './windows/inboxWindow.js';
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
createInboxWindow();
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) createInboxWindow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('before-quit', () => { app.isQuitting = true; });
|
||||||
46
src/main/windows/inboxWindow.ts
Normal file
46
src/main/windows/inboxWindow.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { BrowserWindow, app } from 'electron';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
let inboxWindow: BrowserWindow | null = null;
|
||||||
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||||
|
|
||||||
|
export function getInboxWindow(): BrowserWindow | null {
|
||||||
|
return inboxWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createInboxWindow(): BrowserWindow {
|
||||||
|
if (inboxWindow && !inboxWindow.isDestroyed()) {
|
||||||
|
inboxWindow.show();
|
||||||
|
inboxWindow.focus();
|
||||||
|
return inboxWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
inboxWindow = new BrowserWindow({
|
||||||
|
width: 900,
|
||||||
|
height: 720,
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
preload: join(__dirname, '../preload/index.js'),
|
||||||
|
contextIsolation: true,
|
||||||
|
nodeIntegration: false,
|
||||||
|
sandbox: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process.env.ELECTRON_RENDERER_URL) {
|
||||||
|
inboxWindow.loadURL(`${process.env.ELECTRON_RENDERER_URL}/inbox/index.html`);
|
||||||
|
} else {
|
||||||
|
inboxWindow.loadFile(join(__dirname, '../renderer/inbox/index.html'));
|
||||||
|
}
|
||||||
|
|
||||||
|
inboxWindow.on('close', (e) => {
|
||||||
|
if (!app.isQuitting) {
|
||||||
|
e.preventDefault();
|
||||||
|
inboxWindow?.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
inboxWindow.once('ready-to-show', () => inboxWindow?.show());
|
||||||
|
return inboxWindow;
|
||||||
|
}
|
||||||
12
src/renderer/inbox/index.html
Normal file
12
src/renderer/inbox/index.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'" />
|
||||||
|
<title>Inkling</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script>document.getElementById('root').textContent = 'Inkling Inbox (renderer pending)';</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
6
src/shared/types.ts
Normal file
6
src/shared/types.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
declare global {
|
||||||
|
namespace Electron {
|
||||||
|
interface App { isQuitting?: boolean; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export {};
|
||||||
@@ -13,10 +13,9 @@
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"types": ["node"],
|
"types": ["node"],
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@shared/*": ["src/shared/*"],
|
"@shared/*": ["./src/shared/*"],
|
||||||
"@main/*": ["src/main/*"]
|
"@main/*": ["./src/main/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*", "tests/**/*"],
|
"include": ["src/**/*", "tests/**/*"],
|
||||||
|
|||||||
Reference in New Issue
Block a user