use tauri for desktop

This commit is contained in:
KingKDot
2026-05-11 20:04:13 -05:00
parent 76cb47f8eb
commit 1ce15b59fd
78 changed files with 673 additions and 5900 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 100 KiB

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Overlord – Connect</title>
<title>Overlord - Connect</title>
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="vendor/inter/400.css" />
<link rel="stylesheet" href="vendor/inter/600.css" />
@@ -12,7 +12,6 @@
<script src="renderer.js" defer></script>
</head>
<body>
<!-- Background particles (matches Overlord login aesthetic) -->
<div class="particles">
<div class="particle"></div>
<div class="particle"></div>
-147
View File
@@ -1,147 +0,0 @@
const { app, BrowserWindow, ipcMain } = require("electron");
const path = require("path");
const fs = require("fs");
const https = require("https");
const http = require("http");
// ── Persistence ──────────────────────────────────────────────
app.setAppUserModelId("com.overlord.desktop");
const CONFIG_DIR = path.join(app.getPath("userData"), "overlord-desktop");
const CONFIG_FILE = path.join(CONFIG_DIR, "connection.json");
function loadSavedConnection() {
try {
if (fs.existsSync(CONFIG_FILE)) {
const raw = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
if (raw && typeof raw.host === "string" && typeof raw.port === "number") {
return {
host: raw.host,
port: raw.port,
useTLS: raw.useTLS !== false,
};
}
}
} catch {
// ignore corrupt config
}
return null;
}
function saveConnection(conn) {
fs.mkdirSync(CONFIG_DIR, { recursive: true });
fs.writeFileSync(CONFIG_FILE, JSON.stringify(conn, null, 2));
}
// ── Window ───────────────────────────────────────────────────
let win;
let serverBaseUrl = null; // e.g. "https://1.2.3.4:5173"
let pendingError = null; // error message to show on the connect page after a failed load
// ── Server probe ─────────────────────────────────────────────
// Checks whether a server is reachable before telling Electron to navigate to it.
function probeServer(url) {
return new Promise((resolve, reject) => {
const mod = url.startsWith("https") ? https : http;
const req = mod.get(url, { rejectUnauthorized: false, timeout: 8000 }, (res) => {
res.resume(); // drain so the socket can be reused
resolve();
});
req.on("timeout", () => {
req.destroy();
reject(new Error("timeout"));
});
req.on("error", reject);
});
}
function createWindow() {
win = new BrowserWindow({
width: 1280,
height: 800,
title: "Overlord",
icon: path.join(__dirname, "icon.ico"),
webPreferences: {
preload: path.join(__dirname, "preload.js"),
contextIsolation: true,
nodeIntegration: false,
},
});
win.loadFile(path.join(__dirname, "connect", "index.html"));
// Allow self-signed certs on the target Overlord server
win.webContents.session.setCertificateVerifyProc((_req, cb) => cb(0));
// If the server URL fails to load mid-session (e.g. server stopped), bounce back
// to the connect screen with a helpful error instead of showing a white page.
win.webContents.on("did-fail-load", (_event, errorCode, _errorDescription, validatedURL) => {
// ERR_ABORTED (-3) fires on normal navigation cancellations – ignore it.
if (errorCode === -3) return;
if (serverBaseUrl && validatedURL && validatedURL.startsWith(serverBaseUrl)) {
pendingError =
"Lost connection to the Overlord server. " +
"Make sure the server is still running, then try connecting again. " +
"See the README if you need help starting the server.";
serverBaseUrl = null;
win.loadFile(path.join(__dirname, "connect", "index.html"));
}
});
}
app.whenReady().then(createWindow);
app.on("window-all-closed", () => {
app.quit();
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
// ── IPC handlers ─────────────────────────────────────────────
ipcMain.handle("get-saved-connection", () => {
return loadSavedConnection();
});
ipcMain.handle("get-pending-error", () => {
const err = pendingError;
pendingError = null;
return err;
});
ipcMain.handle("connect-to-server", async (_event, { host, port, useTLS }) => {
if (!host || host.trim().length === 0) {
return { success: false, error: "Host is required" };
}
if (port < 1 || port > 65535) {
return { success: false, error: "Port must be between 1 and 65535" };
}
const protocol = useTLS ? "https" : "http";
const url = `${protocol}://${host.trim()}:${port}`;
// Probe the server before navigating so we never end up on a white screen.
try {
await probeServer(url);
} catch {
return {
success: false,
error:
"Cannot reach the Overlord server at that address. " +
"Make sure the server is running before connecting — " +
"see the README for setup instructions.",
};
}
saveConnection({ host: host.trim(), port, useTLS });
serverBaseUrl = url;
win.loadURL(url);
return { success: true };
});
ipcMain.handle("go-back-to-connect", () => {
serverBaseUrl = null;
win.loadFile(path.join(__dirname, "connect", "index.html"));
});
-8
View File
@@ -1,8 +0,0 @@
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("overlord", {
getSavedConnection: () => ipcRenderer.invoke("get-saved-connection"),
getPendingError: () => ipcRenderer.invoke("get-pending-error"),
connectToServer: (opts) => ipcRenderer.invoke("connect-to-server", opts),
goBackToConnect: () => ipcRenderer.invoke("go-back-to-connect"),
});
@@ -1,3 +1,5 @@
const { invoke } = window.__TAURI__.core;
const form = document.getElementById("connect-form");
const hostInput = document.getElementById("host");
const portInput = document.getElementById("port");
@@ -10,26 +12,20 @@ function setStatus(msg, type = "info") {
statusEl.innerHTML = msg;
}
// Load saved connection on startup and surface any pending error from a
// previous session (e.g. the server dropped mid-session and we bounced back).
(async () => {
try {
const saved = await window.overlord.getSavedConnection();
const saved = await invoke("get_saved_connection");
if (saved) {
hostInput.value = saved.host;
portInput.value = String(saved.port);
tlsCheckbox.checked = saved.useTLS;
tlsCheckbox.checked = saved.useTls;
}
} catch {
// first run, no saved data
}
} catch { }
try {
const err = await window.overlord.getPendingError();
const err = await invoke("get_pending_error");
if (err) setStatus(err, "error");
} catch {
// ignore
}
} catch { }
})();
form.addEventListener("submit", async (e) => {
@@ -37,7 +33,7 @@ form.addEventListener("submit", async (e) => {
const host = hostInput.value.trim();
const port = parseInt(portInput.value, 10);
const useTLS = tlsCheckbox.checked;
const useTls = tlsCheckbox.checked;
if (!host) {
setStatus("Please enter a host address.", "error");
@@ -53,7 +49,7 @@ form.addEventListener("submit", async (e) => {
setStatus('<span class="spinner"></span> Connecting…', "info");
try {
const result = await window.overlord.connectToServer({ host, port, useTLS });
const result = await invoke("connect_to_server", { host, port, useTls });
if (result.success) {
setStatus("Connected! Loading Overlord…", "ok");
@@ -63,8 +59,8 @@ form.addEventListener("submit", async (e) => {
connectBtn.querySelector(".btn-text").textContent = "Connect";
}
} catch (err) {
setStatus(err?.message || "Connection failed.", "error");
setStatus(err?.message || String(err) || "Connection failed.", "error");
connectBtn.disabled = false;
connectBtn.querySelector(".btn-text").textContent = "Connect";
}
});
});