Initial commit

This commit is contained in:
AnRil
2026-05-16 13:43:29 +07:00
commit 688a86b611
208 changed files with 44350 additions and 0 deletions

7
src/preload/index.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
import type { Api } from './index'
declare global {
interface Window {
api: Api
}
}

92
src/preload/index.ts Normal file
View File

@@ -0,0 +1,92 @@
import { contextBridge, ipcRenderer } from 'electron'
import { IPC } from '@shared/ipc'
import type {
AppState,
Challenge,
Exercise,
GameId,
GameStatus,
MatchSummary,
Settings,
Tick
} from '@shared/types'
type Unsub = () => void
type Handler<T> = (payload: T) => void
function on<T>(channel: string, handler: Handler<T>): Unsub {
const listener = (_e: Electron.IpcRendererEvent, payload: T): void => handler(payload)
ipcRenderer.on(channel, listener)
return () => ipcRenderer.removeListener(channel, listener)
}
const api = {
getState: (): Promise<AppState> => ipcRenderer.invoke(IPC.getState),
addExercise: (
input: Omit<Exercise, 'id' | 'nextFireAt' | 'lastDoneAt'>
): Promise<Exercise> => ipcRenderer.invoke(IPC.addExercise, input),
updateExercise: (id: string, patch: Partial<Exercise>): Promise<Exercise> =>
ipcRenderer.invoke(IPC.updateExercise, id, patch),
deleteExercise: (id: string): Promise<boolean> =>
ipcRenderer.invoke(IPC.deleteExercise, id),
toggleExercise: (id: string, enabled: boolean): Promise<Exercise> =>
ipcRenderer.invoke(IPC.toggleExercise, id, enabled),
markDone: (id: string): Promise<Exercise> => ipcRenderer.invoke(IPC.markDone, id),
snooze: (id: string, minutes: number): Promise<Exercise> =>
ipcRenderer.invoke(IPC.snooze, id, minutes),
skip: (id: string): Promise<Exercise> => ipcRenderer.invoke(IPC.skip, id),
updateSettings: (patch: Partial<Settings>): Promise<Settings> =>
ipcRenderer.invoke(IPC.updateSettings, patch),
getAccentColor: (): Promise<string> => ipcRenderer.invoke(IPC.getAccentColor),
getOsTheme: (): Promise<'light' | 'dark'> => ipcRenderer.invoke(IPC.getOsTheme),
pauseAll: (): Promise<void> => ipcRenderer.invoke(IPC.pauseAll),
resumeAll: (): Promise<void> => ipcRenderer.invoke(IPC.resumeAll),
quit: (): Promise<void> => ipcRenderer.invoke(IPC.quit),
reminderClose: (): Promise<void> => ipcRenderer.invoke(IPC.reminderClose),
minimizeMain: (): void => ipcRenderer.send(IPC.minimizeMain),
closeMain: (): void => ipcRenderer.send(IPC.closeMain),
hideMain: (): void => ipcRenderer.send(IPC.hideMain),
// Games
listGames: (): Promise<GameStatus[]> => ipcRenderer.invoke(IPC.gamesList),
installGame: (id: GameId): Promise<GameStatus> =>
ipcRenderer.invoke(IPC.gameInstall, id),
uninstallGame: (id: GameId): Promise<GameStatus> =>
ipcRenderer.invoke(IPC.gameUninstall, id),
toggleGame: (id: GameId, enabled: boolean): Promise<void> =>
ipcRenderer.invoke(IPC.gameToggle, id, enabled),
openGameLaunchOptions: (id: GameId): Promise<void> =>
ipcRenderer.invoke(IPC.gameOpenLaunchOptions, id),
// Challenges
addChallenge: (input: Omit<Challenge, 'id'>): Promise<Challenge> =>
ipcRenderer.invoke(IPC.addChallenge, input),
updateChallenge: (id: string, patch: Partial<Challenge>): Promise<Challenge> =>
ipcRenderer.invoke(IPC.updateChallenge, id, patch),
deleteChallenge: (id: string): Promise<boolean> =>
ipcRenderer.invoke(IPC.deleteChallenge, id),
toggleChallenge: (id: string, enabled: boolean): Promise<Challenge> =>
ipcRenderer.invoke(IPC.toggleChallenge, id, enabled),
closeMatchSummary: (): Promise<void> => ipcRenderer.invoke(IPC.closeMatchSummary),
simulateMatchEnd: (id: GameId, stats: Record<string, number>): Promise<void> =>
ipcRenderer.invoke('dev:simulateMatchEnd', id, stats),
onTick: (h: Handler<Tick[]>): Unsub => on(IPC.evtTick, h),
onFire: (h: Handler<Exercise>): Unsub => on(IPC.evtFire, h),
onMatchEnd: (h: Handler<MatchSummary>): Unsub => on(IPC.evtMatchEnd, h),
onStateChanged: (h: Handler<AppState>): Unsub => on(IPC.evtStateChanged, h),
onThemeChanged: (h: Handler<'light' | 'dark'>): Unsub => on(IPC.evtThemeChanged, h),
onAccentChanged: (h: Handler<string>): Unsub => on(IPC.evtAccentChanged, h),
onGamesChanged: (h: Handler<GameStatus[]>): Unsub => on(IPC.evtGamesChanged, h)
}
contextBridge.exposeInMainWorld('api', api)
export type Api = typeof api