This commit is contained in:
Timothy Jaeryang Baek 2025-01-11 10:05:19 -08:00
parent 7dc108f830
commit be467b390c
24 changed files with 198 additions and 122 deletions

2
.gitignore vendored
View File

@ -92,4 +92,4 @@ typings/
out/
resources/*
resources/python.tar.gz

View File

@ -10,7 +10,8 @@ import { FuseV1Options, FuseVersion } from "@electron/fuses";
const config: ForgeConfig = {
packagerConfig: {
asar: true,
icon: "src/assets/icon.png",
icon: "public/assets/icon.png",
extraResource: ["public/assets", "resources"],
},
rebuildConfig: {},
makers: [

View File

@ -47,8 +47,5 @@
"electron-squirrel-startup": "^1.0.1",
"tar": "^7.4.3",
"update-electron-app": "^3.1.0"
},
"extraResources": [
"resources/py311.tar.gz"
]
}
}

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
public/assets/tray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -1,57 +1,134 @@
import { app, BrowserWindow } from "electron";
import {
app,
protocol,
nativeImage,
Tray,
Menu,
BrowserWindow,
ipcMain,
} from "electron";
import path from "path";
import started from "electron-squirrel-startup";
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (started) {
app.quit();
}
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
icon: "src/assets/icon.png",
webPreferences: {
preload: path.join(__dirname, "preload.js"),
},
// Restrict app to a single instance
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit(); // Quit if another instance is already running
} else {
// Handle second-instance logic
app.on("second-instance", (event, argv, workingDirectory) => {
// This event happens if a second instance is launched
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore(); // Restore if minimized
mainWindow.show(); // Show existing window
mainWindow.focus(); // Focus the existing window
}
});
// and load the index.html of the app.
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
} else {
mainWindow.loadFile(
path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`)
);
}
// Open the DevTools.
mainWindow.webContents.openDevTools();
};
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", createWindow);
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
// Handle creating/removing shortcuts on Windows during installation/uninstallation
if (started) {
app.quit();
}
});
app.on("activate", () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
app.setAboutPanelOptions({
applicationName: "Open WebUI",
iconPath: path.join(__dirname, "assets/icon.png"),
applicationVersion: app.getVersion(),
version: app.getVersion(),
website: "https://openwebui.com",
copyright: `© ${new Date().getFullYear()} Open WebUI (Timothy Jaeryang Baek)`,
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.
// Main application logic
let mainWindow: BrowserWindow | null = null;
let tray: Tray | null = null;
const onReady = () => {
console.log(process.resourcesPath);
mainWindow = new BrowserWindow({
width: 800,
height: 600,
icon: path.join(__dirname, "assets/icon.png"),
webPreferences: {
preload: path.join(__dirname, "preload.js"),
},
});
mainWindow.setIcon(path.join(__dirname, "assets/icon.png"));
// Load index.html or dev server URL
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
} else {
mainWindow.loadFile(
path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`)
);
}
// Create a system tray icon
const image = nativeImage.createFromPath(
path.join(__dirname, "assets/tray.png")
);
tray = new Tray(image.resize({ width: 16, height: 16 }));
const trayMenu = Menu.buildFromTemplate([
{
label: "Show Application",
click: () => {
mainWindow.show(); // Show the main window when clicked
},
},
{
label: "Quit",
click: () => {
app.isQuiting = true; // Mark as quitting
app.quit(); // Quit the application
},
},
]);
tray.setToolTip("Open WebUI");
tray.setContextMenu(trayMenu);
// Handle the close event
mainWindow.on("close", (event) => {
if (!app.isQuiting) {
event.preventDefault(); // Prevent the default close behavior
mainWindow.hide(); // Hide the window instead of closing it
}
});
};
ipcMain.on("load-webui", (event, arg) => {
console.log(arg); // prints "ping"
mainWindow.loadURL("http://localhost:8080");
mainWindow.webContents.once("did-finish-load", () => {
mainWindow.webContents.send("main:data", {
type: "ping", // This is the same type you're listening for in the renderer
});
});
ipcMain.on("send-ping", (event) => {
console.log("Received PING from renderer process");
mainWindow.webContents.send("ping-reply", "PONG from Main Process!");
});
});
// Quit when all windows are closed, except on macOS
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
onReady();
} else {
mainWindow?.show();
}
});
app.on("ready", onReady);
}

View File

@ -1,2 +1,26 @@
// See the Electron documentation for details on how to use preload scripts:
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
import { ipcRenderer, contextBridge } from "electron";
window.addEventListener("DOMContentLoaded", () => {
// Listen for messages from the main process
ipcRenderer.on("main:data", (event, data) => {
// Forward the message to the renderer using window.postMessage
window.postMessage(
{
type: `electron:${data.type}`,
data: data,
},
window.location.origin
);
});
});
contextBridge.exposeInMainWorld("electronAPI", {
sendPing: () => {
console.log("Sending PING to main process...");
ipcRenderer.send("send-ping"); // Send the ping back to the main process
},
loadWebUI: (arg) => {
ipcRenderer.send("load-webui", arg);
},
});

View File

@ -1,12 +1,9 @@
<script lang="ts">
import { onMount } from "svelte";
import Onboarding from "./lib/components/Onboarding.svelte";
onMount(() => {
console.log("Mounted");
});
import Main from "./lib/components/Main.svelte";
onMount(() => {});
</script>
<main class="w-screen h-screen bg-gray-900">
<Onboarding />
<Main />
</main>

View File

@ -1,8 +1,29 @@
@import "tailwindcss";
@font-face {
font-family: "Archivo";
src: url("/assets/fonts/Archivo-Variable.ttf");
font-display: swap;
}
@font-face {
font-family: "InstrumentSerif";
src: url("/assets/fonts/InstrumentSerif-Regular.ttf");
font-display: swap;
}
.font-secondary {
font-family: "InstrumentSerif", sans-serif;
}
html {
font-family: "Archivo";
}
@theme {
--color-*: initial;
--color-white: #fff;
--color-gray-50: #f9f9f9;
--color-gray-100: #ececec;
--color-gray-200: #e3e3e3;

View File

@ -1,25 +1,27 @@
<script lang="ts">
import { onMount } from "svelte";
import ServerList from "./main/ServerList.svelte";
import ServerView from "./main/ServerView.svelte";
onMount(() => {
console.log("Mounted");
});
</script>
<div class="flex flex-row w-full h-full">
<div class="">
<ServerList />
</div>
<div class="my-1.5 mr-1.5 flex-1">
<div class="w-full h-full rounded-lg border border-gray-850">
<ServerView
className="rounded-lg w-full h-full"
url="http://localhost:8080"
<div class="m-auto">
<!-- <div class=" flex justify-center mb-3">
<img
src="./assets/images/splash.png"
class="size-16 dark:invert"
alt="hero"
/>
</div>
</div> -->
<!-- <div class=" text-2xl text-gray-50 font-secondary">Install Open WebUI</div> -->
<button
class=" text-gray-100 hover:text-white transition font-medium cursor-pointer"
onclick={() => {
console.log("clicked");
if (window?.electronAPI) {
window.electronAPI.loadWebUI();
}
}}>Install Open WebUI</button
>
</div>
</div>

View File

@ -1,5 +0,0 @@
<script lang="ts">
import Main from "./Main.svelte";
</script>
<Main />

View File

@ -1,32 +0,0 @@
<script lang="ts">
import Plus from "../icons/Plus.svelte";
import FaviconImage from "../../assets/images/favicon.png";
</script>
<div
class="flex flex-col gap-2.5 w-16 h-full py-3.5 px-2.5 max-h-screen overflow-y-auto bg-gray-900"
>
<div class=" w-full flex justify-center">
<button
class="size-11 flex justify-center self-center bg-gray-800 text-gray-100 rounded-full cursor-pointer"
onclick={() => {
console.log("Clicked");
}}
>
<img src={FaviconImage} class="w-full h-full" />
</button>
</div>
<div class=" w-full flex justify-center">
<button
class="size-11 flex justify-center self-center bg-gray-800 text-gray-100 rounded-full cursor-pointer"
onclick={() => {
console.log("Clicked");
}}
>
<div class="m-auto">
<Plus className=" size-5" strokeWidth="2.5" />
</div>
</button>
</div>
</div>

View File

@ -1,6 +0,0 @@
<script lang="ts">
let { className, url } = $props();
</script>
<!-- iframe -->
<iframe class={className} src={url} frameborder="0"></iframe>