feat(core): add Electron runtime, services, and app composition

This commit is contained in:
2026-02-22 21:43:43 -08:00
parent 448ce03fd4
commit d3fd47f0ec
562 changed files with 69719 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
type TrayIconLike = {
isEmpty: () => boolean;
resize: (options: { width: number; height: number; quality?: 'best' | 'better' | 'good' }) => TrayIconLike;
setTemplateImage: (enabled: boolean) => void;
};
type TrayLike = {
setContextMenu: (menu: any) => void;
setToolTip: (tooltip: string) => void;
on: (event: 'click', handler: () => void) => void;
destroy: () => void;
};
export function createEnsureTrayHandler(deps: {
getTray: () => TrayLike | null;
setTray: (tray: TrayLike | null) => void;
buildTrayMenu: () => any;
resolveTrayIconPath: () => string | null;
createImageFromPath: (iconPath: string) => TrayIconLike;
createEmptyImage: () => TrayIconLike;
createTray: (icon: TrayIconLike) => TrayLike;
trayTooltip: string;
platform: string;
logWarn: (message: string) => void;
ensureOverlayVisibleFromTrayClick: () => void;
}) {
return (): void => {
const existingTray = deps.getTray();
if (existingTray) {
existingTray.setContextMenu(deps.buildTrayMenu());
return;
}
const iconPath = deps.resolveTrayIconPath();
let trayIcon = iconPath ? deps.createImageFromPath(iconPath) : deps.createEmptyImage();
if (trayIcon.isEmpty()) {
deps.logWarn('Tray icon asset not found; using empty icon placeholder.');
}
if (deps.platform === 'darwin' && !trayIcon.isEmpty()) {
trayIcon = trayIcon.resize({ width: 18, height: 18, quality: 'best' });
trayIcon.setTemplateImage(true);
}
if (deps.platform === 'linux' && !trayIcon.isEmpty()) {
trayIcon = trayIcon.resize({ width: 20, height: 20 });
}
const tray = deps.createTray(trayIcon);
tray.setToolTip(deps.trayTooltip);
tray.setContextMenu(deps.buildTrayMenu());
tray.on('click', () => {
deps.ensureOverlayVisibleFromTrayClick();
});
deps.setTray(tray);
};
}
export function createDestroyTrayHandler(deps: {
getTray: () => TrayLike | null;
setTray: (tray: TrayLike | null) => void;
}) {
return (): void => {
const tray = deps.getTray();
if (!tray) return;
tray.destroy();
deps.setTray(null);
};
}