Skip to content

Commit

Permalink
electron: Fix settings window
Browse files Browse the repository at this point in the history
create simple router to make svelte happy
use vite to build electron stuff
specify target to simplify locale initialization
  • Loading branch information
DHrpcs3 committed Feb 1, 2025
1 parent d4bd6db commit f7beb40
Show file tree
Hide file tree
Showing 14 changed files with 240 additions and 84 deletions.
Binary file modified bun.lockb
Binary file not shown.
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"tauri": "tauri",
"electron": "tsc -p src-electron && electron build/main.js",
"electron": "electron build/main.js",
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make"
Expand All @@ -20,33 +20,33 @@
"dependencies": {
"@tauri-apps/api": "^2.2.0",
"@tauri-apps/plugin-shell": "^2.2.0",
"electron-serve": "^2.1.1",
"svelte-hero-icons": "^5.2.0",
"svelte-i18n": "^4.0.1"
},
"devDependencies": {
"@electron-forge/cli": "^7.6.1",
"@electron-forge/maker-deb": "^7.6.1",
"@electron-forge/maker-rpm": "^7.6.1",
"@electron-forge/maker-squirrel": "^7.6.1",
"@electron-forge/maker-zip": "^7.6.1",
"@electron-forge/plugin-auto-unpack-natives": "^7.6.1",
"@electron-forge/plugin-fuses": "^7.6.1",
"@electron/fuses": "^1.8.0",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.16.1",
"@sveltejs/vite-plugin-svelte": "^4.0.4",
"@tauri-apps/cli": "^2.2.7",
"@types/node": "^22.13.0",
"autoprefixer": "^10.4.20",
"electron": "34.0.2",
"electron-squirrel-startup": "^1.0.1",
"postcss": "^8.5.1",
"svelte": "^5.19.6",
"svelte-check": "^4.1.4",
"tailwindcss": "^3.4.17",
"tslib": "^2.8.1",
"typescript": "^5.7.3",
"vite": "^5.4.14",
"electron": "34.0.2",
"@electron-forge/cli": "^7.6.1",
"@electron-forge/maker-deb": "^7.6.1",
"@electron-forge/maker-rpm": "^7.6.1",
"@electron-forge/maker-squirrel": "^7.6.1",
"@electron-forge/maker-zip": "^7.6.1",
"@electron-forge/plugin-auto-unpack-natives": "^7.6.1",
"@electron-forge/plugin-fuses": "^7.6.1",
"@electron/fuses": "^1.8.0",
"electron-squirrel-startup": "^1.0.1"
"vite-plugin-electron": "^0.29.0"
}
}
10 changes: 10 additions & 0 deletions src-electron/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ipcRenderer } from 'electron'

export const electronAPI = {
ipcRenderer: {
send: (channel: string, ...args: any[]) => {
ipcRenderer.send(channel, ...args)
}
}
}

107 changes: 101 additions & 6 deletions src-electron/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,103 @@
import { app, BrowserWindow } from 'electron';
import { app, net, protocol, session, BrowserWindow, ipcMain } from 'electron';
import { getSetting, loadSettings, saveSettings, setSetting } from './settings.js';
import serve from 'electron-serve';

const serveUrl = serve({ directory: '.' });
import { rootPath } from './locations.js';
import { PathLike } from 'fs';
import path from 'path';
import fs from 'fs/promises';
import url from 'url';

await loadSettings();

function setupElectron() {
const directory = rootPath;

protocol.registerSchemesAsPrivileged([
{
scheme: 'app',
privileges: {
standard: true,
secure: true,
allowServiceWorkers: true,
supportFetchAPI: true,
},
},
]);

const fixPath = async (loc: PathLike) => {
loc = loc.toString();
if (loc.length === 0) {
return "index.html";
}

try {
const stat = await fs.stat(loc);
if (stat.isFile()) {
return loc;
}

if (stat.isDirectory()) {
return fixPath(path.join(loc, "index.html"));
}
} catch {
const ext = path.extname(loc);
if (ext === ".html") {
return undefined;
}

try {
if ((await fs.stat(loc + ".html")).isFile()) {
return loc + ".html";
}
} catch { }
}

return undefined;
}

app.on('ready', () => {
session.defaultSession.protocol.handle('app', async (request) => {
const filePath = path.join(directory, decodeURIComponent(new URL(request.url).pathname));

const relativePath = path.relative(directory, filePath);
const isSafe = !relativePath.startsWith('..') && !path.isAbsolute(relativePath);

if (!isSafe) {
return new Response('bad request', {
status: 400,
headers: { 'content-type': 'text/html' }
});
}

try {
const absolutePath = await fixPath(path.join(directory, relativePath));

if (absolutePath) {
return net.fetch(url.pathToFileURL(absolutePath).toString());
}
} catch { }

return new Response('Not Found', {
status: 404,
headers: { 'content-type': 'text/html' }
});
});
});
}

setupElectron();

ipcMain.on('window/create', (_event, options) => {
const win = new BrowserWindow({
webPreferences: {
preload: path.join(rootPath, "preload.mjs"),
devTools: true
},
...options,
});

win.loadURL(`app://-/${options.url}`);
});

const createWindow = () => {
const windowSetting = getSetting('window');

Expand All @@ -15,14 +107,17 @@ const createWindow = () => {
height: windowSetting.height,
x: windowSetting.x,
y: windowSetting.y,
fullscreen: windowSetting.fullscreen
fullscreen: windowSetting.fullscreen,
webPreferences: {
preload: path.join(rootPath, "preload.mjs")
}
});

if (windowSetting.devTools) {
win.webContents.openDevTools();
}

serveUrl(win);
win.loadURL("app://-");

win.on('close', () => {
const bounds = win.getBounds();
Expand Down
12 changes: 12 additions & 0 deletions src-electron/src/preload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { contextBridge } from 'electron'
import { electronAPI } from './api.js';

if (process.contextIsolated) {
try {
contextBridge.exposeInMainWorld('electron', electronAPI);
} catch (error) {
console.error(error);
}
} else {
(window as any).electron = electronAPI;
}
3 changes: 3 additions & 0 deletions src-electron/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@
},
"include": [
"src/**/*"
],
"exclude": [
"src/preload.ts"
]
}
12 changes: 12 additions & 0 deletions src-electron/tsconfig.preload.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "Preserve",
"moduleResolution": "bundler",
"resolveJsonModule": false
},
"include": [
"src/preload.ts"
],
"exclude": []
}
26 changes: 3 additions & 23 deletions src/components/Header.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { Icon, Squares2x2, ListBullet, Cog6Tooth } from "svelte-hero-icons";
import { gridLayout } from "../stores";
import { _ } from "svelte-i18n";
import { openWindow } from "helpers/window";
export let searchTerm: string;
Expand All @@ -15,31 +16,10 @@
async function createSettings() {
console.log("Making settings widow");
try {
const tauri = await import("@tauri-apps/api/webviewWindow");
const settingsWindow = new tauri.WebviewWindow("settings", {
url: "/settings",
title: "Settings",
});
settingsWindow.once("tauri://created", () => {
console.log("Window created");
});
settingsWindow.once("tauri://error", (err) => {
console.log(err);
});
return;
} catch (e) {}
const electron = await import("electron");
const settingsWindow = new electron.BrowserWindow({
openWindow({
url: "/settings",
title: "Settings",
});
settingsWindow.loadFile("/settings");
}
</script>

Expand Down
7 changes: 7 additions & 0 deletions src/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { electronAPI } from '../src-electron/src/api.js'

declare global {
interface Window {
electron: typeof electronAPI;
}
}
17 changes: 17 additions & 0 deletions src/helpers/window.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export async function openWindow(options: { url: string, title: string }) {
if (window.electron) {
window.electron.ipcRenderer.send("window/create", options);
return;
}

const tauri = await import("@tauri-apps/api/webviewWindow");
const settingsWindow = new tauri.WebviewWindow("settings", options);

settingsWindow.once("tauri://created", () => {
console.log("Window created");
});

settingsWindow.once("tauri://error", async (err) => {
console.log(err);
});
}
2 changes: 1 addition & 1 deletion src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { register, init, getLocaleFromNavigator } from "svelte-i18n";

register("en", () => import("./locales/en.json"));

export const localeInitialized = init({
await init({
fallbackLocale: "en",
initialLocale: getLocaleFromNavigator()
});
19 changes: 8 additions & 11 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import Footer from "components/Footer.svelte";
import { Game, Region } from "models/Game";
import GameLibrary from "components/GameLibrary.svelte";
import { localeInitialized } from "../i18n";
let sonicGame = new Game(
const sonicGame = new Game(
"Sonic Mania",
"./icon0.png",
"SEGA",
Expand All @@ -14,7 +13,7 @@
"CUSA07023",
197927919,
);
let weAreDoomedGame = new Game(
const weAreDoomedGame = new Game(
"WE ARE DOOMED",
"./icon1.png",
"Vertex Pop Inc.",
Expand All @@ -23,7 +22,7 @@
"CUSA02394",
32903780,
);
let games = [sonicGame, weAreDoomedGame];
const games = [sonicGame, weAreDoomedGame];
let filteredGames: Game[] = [];
let searchTerm = "";
Expand All @@ -42,11 +41,9 @@
</script>

<div class="min-h-full h-full flex flex-col">
{#await localeInitialized then}
<Header bind:searchTerm on:input={searchGames} />
<div class="flex-grow overflow-y-scroll">
<GameLibrary games={filteredGames} />
</div>
<Footer bind:gameCount />
{/await}
<Header bind:searchTerm on:input={searchGames} />
<div class="flex-grow overflow-y-scroll">
<GameLibrary games={filteredGames} />
</div>
<Footer bind:gameCount />
</div>
Loading

0 comments on commit f7beb40

Please sign in to comment.