diff --git a/frontend/assets-build/icons/latte.svg b/frontend/assets-build/icons/latte.svg
new file mode 100644
index 0000000..927b015
--- /dev/null
+++ b/frontend/assets-build/icons/latte.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/frontend/assets-build/icons/mocha.svg b/frontend/assets-build/icons/mocha.svg
new file mode 100644
index 0000000..be50aab
--- /dev/null
+++ b/frontend/assets-build/icons/mocha.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/frontend/assets-build/icons/nord.svg b/frontend/assets-build/icons/nord.svg
new file mode 100644
index 0000000..831f6fd
--- /dev/null
+++ b/frontend/assets-build/icons/nord.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/frontend/assets-build/icons/steam.svg b/frontend/assets-build/icons/steam.svg
new file mode 100644
index 0000000..991fece
--- /dev/null
+++ b/frontend/assets-build/icons/steam.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/frontend/assets-build/icons/tokyo.svg b/frontend/assets-build/icons/tokyo.svg
new file mode 100644
index 0000000..e7ed4c7
--- /dev/null
+++ b/frontend/assets-build/icons/tokyo.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/frontend/electron/main.ts b/frontend/electron/main.ts
index 8d3335c..09c1cb8 100644
--- a/frontend/electron/main.ts
+++ b/frontend/electron/main.ts
@@ -135,7 +135,14 @@ const createTray = () => {
tray = new Tray(icon);
tray.setToolTip('Ultimate Ban Tracker');
tray.on('click', () => { if (mainWindow) { mainWindow.show(); mainWindow.focus(); } });
- updateTrayMenu();
+
+ // Load initial themed icon
+ const config = store.get('serverConfig');
+ if (config?.theme) {
+ setAppIcon(config.theme);
+ } else {
+ updateTrayMenu(); // Fallback to refresh menu
+ }
} catch (e) { }
};
@@ -162,6 +169,25 @@ const updateTrayMenu = () => {
tray.setContextMenu(contextMenu);
};
+const setAppIcon = (themeName: string = 'steam') => {
+ const assetsDir = path.join(__dirname, '..', 'assets-build', 'icons');
+ const iconPath = path.join(assetsDir, `${themeName}.svg`);
+
+ if (!fs.existsSync(iconPath)) return;
+
+ const icon = nativeImage.createFromPath(iconPath);
+
+ // Update Tray
+ if (tray) {
+ tray.setImage(icon.resize({ width: 16, height: 16 }));
+ }
+
+ // Update Main Window
+ if (mainWindow) {
+ mainWindow.setIcon(icon);
+ }
+};
+
// --- Steam Logic ---
const killSteam = async () => {
return new Promise((resolve) => {
@@ -571,6 +597,13 @@ ipcMain.handle('admin-delete-user', async (event, userId: string) => { initBacke
ipcMain.handle('admin-get-accounts', async () => { initBackend(); return backend ? await backend.getAdminAccounts() : []; });
ipcMain.handle('admin-remove-account', async (event, steamId: string) => { initBackend(); if (backend) await backend.forceRemoveAccount(steamId); return true; });
+ipcMain.handle('force-sync', async () => { await syncAccounts(true); return true; });
+
+ipcMain.handle('update-app-icon', (event, themeName: string) => {
+ setAppIcon(themeName);
+ return true;
+});
+
ipcMain.handle('switch-account', async (event, loginName: string) => {
if (!loginName) return false;
try {
diff --git a/frontend/electron/preload.ts b/frontend/electron/preload.ts
index 5da78f1..f18d9d4 100644
--- a/frontend/electron/preload.ts
+++ b/frontend/electron/preload.ts
@@ -10,6 +10,7 @@ contextBridge.exposeInMainWorld('electronAPI', {
revokeAccountAccess: (steamId: string, targetSteamId: string) => ipcRenderer.invoke('revoke-account-access', steamId, targetSteamId),
revokeAllAccountAccess: (steamId: string) => ipcRenderer.invoke('revoke-all-account-access', steamId),
openExternal: (url: string) => ipcRenderer.invoke('open-external', url),
+ updateAppIcon: (theme: string) => ipcRenderer.invoke('update-app-icon', theme),
openSteamAppLogin: () => ipcRenderer.invoke('open-steam-app-login'),
openSteamLogin: (steamId: string) => ipcRenderer.invoke('open-steam-login', steamId),
diff --git a/frontend/src/theme/ThemeContext.tsx b/frontend/src/theme/ThemeContext.tsx
index 2f58364..4eb94a4 100644
--- a/frontend/src/theme/ThemeContext.tsx
+++ b/frontend/src/theme/ThemeContext.tsx
@@ -31,8 +31,18 @@ export const AppThemeProvider: React.FC<{ children: React.ReactNode }> = ({ chil
if (api?.updateServerConfig) {
await api.updateServerConfig({ theme });
}
+ if (api?.updateAppIcon) {
+ await api.updateAppIcon(theme);
+ }
};
+ useEffect(() => {
+ const api = (window as any).electronAPI;
+ if (api?.updateAppIcon && currentTheme) {
+ api.updateAppIcon(currentTheme);
+ }
+ }, [currentTheme]);
+
const theme = useMemo(() => getTheme(currentTheme), [currentTheme]);
return (