From acfc97a078c823dd65b22378878694921812748f Mon Sep 17 00:00:00 2001 From: GabiZar Date: Fri, 13 Feb 2026 13:18:12 +0100 Subject: [PATCH] Add themes and clean main.js and style.css --- main.js | 129 +++++++++------ preload.js | 5 +- .../Silksong.mp4} | Bin renderer/index.html | 39 +++-- renderer/renderer.js | 55 ++++++- renderer/style.css | 147 ++++++++++-------- renderer/welcome.css | 6 +- renderer/welcome.html | 19 ++- renderer/welcome.js | 39 +++++ 9 files changed, 299 insertions(+), 140 deletions(-) rename renderer/assets/{background.mp4 => background/Silksong.mp4} (100%) diff --git a/main.js b/main.js index 152683b..46f9270 100644 --- a/main.js +++ b/main.js @@ -65,10 +65,10 @@ app.on('window-all-closed', () => { } }) +///////////////// SAVING AND LOADING ///////////////// ipcMain.handle('save-path', (event, path) => { saveSilksongPath(path) }); - function saveSilksongPath(path) { silksongPath = path; bepinexFolderPath = `${silksongPath}/BepInEx` @@ -84,19 +84,6 @@ ipcMain.handle('load-path', () => { return silksongPath; }); -ipcMain.handle('load-nexus-api', () => { - nexusAPI = store.get('nexus-api'); - if (nexusAPI == undefined) { - return ""; - } - return nexusAPI; -}); - -ipcMain.handle('save-nexus-api', (event, api) => { - nexusAPI = api; - createNexus() - store.set('nexus-api', nexusAPI); -}); function saveBepinexVersion(version) { bepinexVersion = version; @@ -107,6 +94,12 @@ function saveBepinexVersion(version) { store.set('bepinex-version', version); }; +ipcMain.handle('load-bepinex-version', () => { + bepinexVersion = store.get('bepinex-version'); + return bepinexVersion; +}); + + function saveBepinexBackupVersion(version) { bepinexBackupVersion = version; if (bepinexBackupVersion == undefined) { @@ -116,15 +109,40 @@ function saveBepinexBackupVersion(version) { store.set('bepinex-backup-version', version); }; -ipcMain.handle('load-bepinex-version', () => { - bepinexVersion = store.get('bepinex-version'); - return bepinexVersion; -}); - ipcMain.handle('load-bepinex-backup-version', () => { bepinexBackupVersion = store.get('bepinex-backup-version'); return bepinexBackupVersion; }); + +ipcMain.handle('save-nexus-api', (event, api) => { + nexusAPI = api; + createNexus() + store.set('nexus-api', nexusAPI); +}); + +ipcMain.handle('load-nexus-api', () => { + nexusAPI = store.get('nexus-api'); + if (nexusAPI == undefined) { + return ""; + } + return nexusAPI; +}); + + +ipcMain.handle('save-theme', (event, theme) => { + store.set('theme', theme); +}); + +ipcMain.handle('load-theme', () => { + theme = store.get('theme'); + if (theme == undefined) { + return "Silksong"; + } + return theme; +}); + +////////////////////////////////////////////////////// +/////////////////// DATA HANDLING //////////////////// async function fileExists(filePath) { try { @@ -135,15 +153,17 @@ async function fileExists(filePath) { } } -ipcMain.handle('file-exists', async (_, filePath) => { - return await fileExists(filePath); -}); - ipcMain.handle('delete-data', async () => { - await fs.unlink(dataPath) + if (await fileExists(dataPath)) { + await fs.unlink(dataPath) + } }); ipcMain.handle('export-data', async () => { + if (!await fileExists(dataPath)) { + return + } + const { canceled, filePath } = await dialog.showSaveDialog({ title: 'Export Data', defaultPath: 'config.json', @@ -173,31 +193,8 @@ ipcMain.handle('import-data', async () => { return true }) -ipcMain.handle('open-link', async (event, link) => { - await shell.openExternal(link) -}) - -ipcMain.handle('launch-game', async (event, mode) => { - const silksongExecutablePath = `${silksongPath}/Hollow Knight Silksong.exe` - if (mode === "modded"){ - if (await fileExists(bepinexFolderPath)) { - await shell.openExternal(silksongExecutablePath) - } - else { - await installBepinex() - await shell.openExternal(silksongExecutablePath) - } - } - if (mode === "vanilla"){ - if (await fileExists(bepinexFolderPath)) { - await backupBepinex() - await shell.openExternal(silksongExecutablePath) - } - else { - await shell.openExternal(silksongExecutablePath) - } - } -}) +////////////////////////////////////////////////////// +////////////////////// BEPINEX /////////////////////// async function installBepinex() { if (await fileExists(bepinexBackupPath)) { @@ -308,6 +305,9 @@ ipcMain.handle('delete-bepinex-backup', async () => { } }) +////////////////////////////////////////////////////// +/////////////////////// NEXUS //////////////////////// + async function createNexus() { if (nexusAPI == undefined) { return @@ -366,6 +366,9 @@ ipcMain.handle('download-mod', async (event, link) => { nexusWindow.loadURL(link) }) +////////////////////////////////////////////////////// +//////////////////// UNCATEGORIZE //////////////////// + ipcMain.handle('auto-detect-game-path', async () => { const defaultsSilksongPaths = [ ":/Program Files (x86)/Steam/steamapps/common/Hollow Knight Silksong", @@ -384,4 +387,30 @@ ipcMain.handle('auto-detect-game-path', async () => { ipcMain.handle('load-main-page', () => { mainWindow.loadFile("renderer/index.html") -}) \ No newline at end of file +}) + +ipcMain.handle('open-link', async (event, link) => { + await shell.openExternal(link) +}) + +ipcMain.handle('launch-game', async (event, mode) => { + const silksongExecutablePath = `${silksongPath}/Hollow Knight Silksong.exe` + if (mode === "modded"){ + if (await fileExists(bepinexFolderPath)) { + await shell.openExternal(silksongExecutablePath) + } + else { + await installBepinex() + await shell.openExternal(silksongExecutablePath) + } + } + if (mode === "vanilla"){ + if (await fileExists(bepinexFolderPath)) { + await backupBepinex() + await shell.openExternal(silksongExecutablePath) + } + else { + await shell.openExternal(silksongExecutablePath) + } + } +}) diff --git a/preload.js b/preload.js index 309c112..86667da 100644 --- a/preload.js +++ b/preload.js @@ -7,7 +7,6 @@ contextBridge.exposeInMainWorld('versions', { }); contextBridge.exposeInMainWorld('files', { - fileExists: (path) => ipcRenderer.invoke('file-exists', path), delete: () => ipcRenderer.invoke('delete-data'), export: () => ipcRenderer.invoke('export-data'), import: () => ipcRenderer.invoke('import-data'), @@ -18,7 +17,9 @@ contextBridge.exposeInMainWorld('files', { loadBepinexVersion: () => ipcRenderer.invoke('load-bepinex-version'), loadBepinexBackupVersion: () => ipcRenderer.invoke('load-bepinex-backup-version'), saveNexusAPI: (api) => ipcRenderer.invoke('save-nexus-api', api), - loadNexusAPI: () => ipcRenderer.invoke('load-nexus-api') + loadNexusAPI: () => ipcRenderer.invoke('load-nexus-api'), + saveTheme: (theme) => ipcRenderer.invoke('save-theme', theme), + loadTheme: () => ipcRenderer.invoke('load-theme') }); contextBridge.exposeInMainWorld('electronAPI', { diff --git a/renderer/assets/background.mp4 b/renderer/assets/background/Silksong.mp4 similarity index 100% rename from renderer/assets/background.mp4 rename to renderer/assets/background/Silksong.mp4 diff --git a/renderer/index.html b/renderer/index.html index 62fbd14..62effc7 100644 --- a/renderer/index.html +++ b/renderer/index.html @@ -9,42 +9,40 @@
- +
+
+ +
+
Silksong
+
+
  • Silksong
  • +
  • Citadel of song (WIP)
  • +
  • Cradle (WIP)
  • +
  • Abyss (WIP)
  • +
  • Greyroot (WIP)
  • +
  • Surface (WIP)
  • +
  • Steel (WIP)
  • +
    +
    +

    BepInEx

    diff --git a/renderer/renderer.js b/renderer/renderer.js index 39cd823..21c63e7 100644 --- a/renderer/renderer.js +++ b/renderer/renderer.js @@ -9,7 +9,12 @@ const modTemplate = document.getElementById("mod-template"); const versionText = HomeTemplate.content.getElementById("version-text"); -navigate("home") +on_startup() + +async function on_startup() { + changeTheme(await files.loadTheme()) + navigate("home") +} async function navigate(page) { view.replaceChildren() @@ -105,17 +110,18 @@ async function navigate(page) { silksongPathInput.value = await files.loadSilksongPath() silksongPathInput.addEventListener('input', async function(event) { let silksongPath = silksongPathInput.value - await files.saveSilksongPath(silksongPath) + files.saveSilksongPath(silksongPath) }); nexusAPIInput.value = await files.loadNexusAPI() nexusAPIInput.addEventListener('input', async function(event) { let nexusAPI = nexusAPIInput.value - await files.saveNexusAPI(nexusAPI) + files.saveNexusAPI(nexusAPI) }); view.appendChild(settingsTemplateCopy) setBepinexVersion() + setThemeButton() verifyNexusAPI() break; } @@ -135,6 +141,8 @@ async function autoDetectGamePath() { } async function deleteData() { + changeTheme("Silksong") + toggleThemesMenu() await files.delete() document.getElementById("silksong-path-input").value = await files.loadSilksongPath() document.getElementById("nexus-api-input").value = await files.loadNexusAPI() @@ -148,6 +156,8 @@ async function importData() { await files.import() document.getElementById("silksong-path-input").value = await files.loadSilksongPath() document.getElementById("nexus-api-input").value = await files.loadNexusAPI() + changeTheme(await files.loadTheme()) + toggleThemesMenu() } async function installBepinex() { @@ -205,4 +215,43 @@ async function verifyNexusAPI() { else { nexusCheckImage.src = "assets/cross.svg" } +} + +function toggleThemesMenu() { + const themesMenu = document.getElementById("themes-menu") + if (themesMenu) { + themesMenu.classList.toggle("show") + } +} + +async function setThemeButton() { + const themesButton = document.getElementById("themes-button") + if (themesButton) { + themesButton.textContent = await files.loadTheme() + } +} + +function changeTheme(theme) { + files.saveTheme(theme) + + setThemeButton() + + const themesColors = { + "var": ["--primary-color", "--secondary-color", "--background-color"], + "Silksong": ["rgba(255, 25, 0, 0.3)", "#ff6b6b", "rgba(255, 72, 0, 0.2)"], + "Citadel of song": ["rgba(160, 116, 89, 0.3)", "#d3ba91", "rgba(123, 102, 93, 0.2)"], + "Cradle": ["rgba(123, 136, 255, 0.3)", "#7c9fea", "rgba(61, 88, 150, 0.2)"], + "Abyss": ["rgba(255, 255, 255, 0.3)", "#ececec", "rgba(255, 255, 255, 0.2)"], + "Greyroot": ["rgba(181, 255, 180, 0.3)", "#c1ffcd", "rgba(90, 165, 130, 0.2)"], + "Surface": ["rgba(75, 120, 255, 0.3)", "#87c3ff", "rgba(42, 107, 203, 0.2)"], + "Steel": ["rgba(164, 164, 164, 0.3)", "#c5b9b9", "rgba(255, 255, 255, 0.2)"] + } + for(let i = 0; i < 3; i++) { + document.documentElement.style.setProperty(themesColors.var[i], themesColors[theme][i]) + } + + const backgroundVideo = document.getElementById("background-video") + backgroundVideo.src = `assets/background/${theme}.mp4` + + toggleThemesMenu() } \ No newline at end of file diff --git a/renderer/style.css b/renderer/style.css index e0ed64e..a615bde 100644 --- a/renderer/style.css +++ b/renderer/style.css @@ -1,11 +1,21 @@ * { margin: 0; - padding: 0; box-sizing: border-box; font-family: "Segoe UI", sans-serif; cursor: url("assets/cursor.png") 0 0, auto !important; } +:root { + --primary-color: rgba(255, 25, 0, 0.3); + --secondary-color: #ff6b6b; + --background-color: rgba(255, 72, 0, 0.2); + + --text-color: #eee; + --transparent-black: rgba(0, 0, 0, 0.4); + --darker-transparent-black: rgba(0, 0, 0, 0.8); + --transparent-grey: rgba(30, 30, 30, 0.8) +} + body { background: black; color: #eee; @@ -18,7 +28,7 @@ body { height: 100vh; } -.background_video { +.background-video { position: fixed; top: 0; left: 0; @@ -31,8 +41,8 @@ body { .sidebar { width: 280px; - background: rgba(0, 0, 0, 0.8); - border-right: 1px solid rgba(255, 0, 0, 0.15); + background: var(--darker-transparent-black); + border-right: 1px solid var(--background-color); display: flex; flex-direction: column; } @@ -43,18 +53,16 @@ body { align-items: center; justify-content: center; font-size: 32px; - cursor: pointer; - border-bottom: 1px solid rgba(255, 72, 0, 0.2); - transition: background 0.2s; + border-bottom: 1px solid var(--background-color); + transition: background 0.2s ease; } .logo:hover { - background: rgba(255, 0, 0, 0.08); + background: var(--background-color); } -.logo_img { +.logo-img { height: 50px; - width: auto; } .nav { @@ -70,11 +78,11 @@ body { font-size: 13px; text-transform: uppercase; letter-spacing: 1px; - color: #fff; + color: var(--text-color); margin-bottom: 10px; padding: 0 4px 4px; - border-bottom: 1px solid #ff6b6b; + border-bottom: 1px solid var(--secondary-color); } .nav button { @@ -82,17 +90,16 @@ body { padding: 10px 14px; margin-bottom: 8px; background: transparent; - border: 1px solid black; + border: 1px solid transparent; border-radius: 4px; - color: #eee; - cursor: pointer; + color: var(--text-color); text-align: left; transition: all 0.2s ease; } .nav button:hover { - background: rgba(255, 72, 0, 0.2); - border-color: rgba(255, 25, 0, 0.3); + background: var(--background-color); + border-color: var(--primary-color); } .content { @@ -103,7 +110,7 @@ body { .content h1 { font-size: 28px; margin-bottom: 20px; - color: #ffffff; + color: var(--text-color); display: flex; justify-content: center; } @@ -111,19 +118,18 @@ body { .content h2 { font-size: 24px; margin-bottom: 20px; - color: #ffffff; + color: var(--text-color); padding: 0 4px 4px; - border-bottom: 1px solid #ff6b6b; + border-bottom: 1px solid var(--secondary-color); } .view { - width: 100%; - background: rgba(0, 0, 0, 0.8); + background: var(--darker-transparent-black); border-radius: 12px; padding: 40px; position: relative; z-index: 0; - box-shadow: 0 0 50px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 50px var(--darker-transparent-black); overflow: auto; height: 90%; } @@ -139,35 +145,33 @@ body { flex: 1; height: 30px; padding: 0 12px; - background: rgba(0, 0, 0, 0.4); - border: 1px solid #ff6b6b; + background: var(--transparent-black); + border: 1px solid var(--secondary-color); border-radius: 4px; - color: #eee; + color: var(--text-color); font-size: 13px; outline: none; transition: all 0.2s ease; } .input:hover { - background: rgba(0, 0, 0, 0.55); - border-color: rgba(255, 25, 0, 0.3); + background: var(--darker-transparent-black); + border-color: var(--primary-color); } .input:focus { - background: rgba(0, 0, 0, 0.65); - border-color: rgba(255, 25, 0, 0.3); - box-shadow: 0 0 0 1px rgba(255, 25, 0, 0.2); + background: var(--darker-transparent-black); + border-color: var(--primary-color); + box-shadow: 0 0 0 1px var(--primary-color); } .default-button { width: 120px; height: 40px; - padding: 2px; - background: rgba(0, 0, 0, 0.4); - border: 1px solid #ff6b6b; + background: var(--transparent-black); + border: 1px solid var(--secondary-color); border-radius: 4px; - color: #eee; - cursor: pointer; + color: var(--text-color); font-size: 16px; transition: all 0.2s ease; display: flex; @@ -176,19 +180,17 @@ body { } .default-button:hover { - background: rgba(255, 72, 0, 0.2); - border-color: rgba(255, 25, 0, 0.3); + background: var(--background-color); + border-color: var(--primary-color); } .important-button { width: 120px; height: 40px; - padding: 2px; background: rgba(100, 0, 0, 0.4); border: 1px solid rgba(200, 25, 0); border-radius: 4px; - color: #eee; - cursor: pointer; + color: var(--text-color); font-size: 16px; transition: all 0.2s ease; display: flex; @@ -208,6 +210,10 @@ body { font-size: 32px; } +.longer-button { + width: 240px; +} + .search-container { position: absolute; left: 50%; @@ -221,7 +227,7 @@ body { border: none; border-radius: 50px; background-color: rgba(255, 255, 255, 0.15); - color: #fff; + color: var(--text-color); outline: none; transition: background 0.3s, width 0.3s; } @@ -238,20 +244,15 @@ body { transform: translateY(-50%); background: none; border: none; - color: #fff; + color: var(--text-color); font-size: 18px; cursor: pointer; } .mods-container { - width: 100%; height: 80%; transform: translateY(50px); - background: rgba(30, 30, 30, 0.8); - border-radius: 12px; padding: 20px; - position: relative; - box-shadow: 0 0 50px rgba(30, 30, 30, 0.15); overflow: auto; } @@ -262,12 +263,10 @@ body { display: flex; align-items: center; justify-content: space-between; - } .mod-container:not(:last-child) { - border-bottom: 1px solid rgba(150, 25, 0, 0.5); - + border-bottom: 1px solid var(--secondary-color); } .mod-text { @@ -275,17 +274,10 @@ body { flex-direction: column; } -.mod-actions { - margin-top: 12px; - display: flex; - gap: 20px; -} - .mod-icon { width: 128px; height: 128px; object-fit: contain; - opacity: 0.9; } ::-webkit-scrollbar { @@ -293,16 +285,17 @@ body { } ::-webkit-scrollbar-track { - background: #101010; + background: var(--transparent-grey); + border-radius: 5px; } ::-webkit-scrollbar-thumb { - background: rgb(120, 25, 0); - border-radius: 7px; + background: var(--primary-color); + border-radius: 5px; } ::-webkit-scrollbar-thumb:hover { - background: rgb(170, 25, 0); + background: var(--secondary-color); } .transparent-text { @@ -316,10 +309,36 @@ body { } .link { - color: #ffffff; + color: var(--text-color); transition: all 0.2s ease; } .link:hover { - color: #ff6b6b; + color: var(--secondary-color); +} + +.themes-div { + position: relative; +} + +.themes-menu { + display: none; + position: absolute; + background: var(--darker-transparent-black); + border: 1px solid var(--secondary-color); + border-radius: 4px; +} + +.themes-menu.show { + display: block; +} + +.themes-menu li { + padding: 6px; + display: flex; + justify-content: center; +} + +.themes-menu li:hover { + background: var(--background-color); } \ No newline at end of file diff --git a/renderer/welcome.css b/renderer/welcome.css index c6ce0df..e192f4e 100644 --- a/renderer/welcome.css +++ b/renderer/welcome.css @@ -1,17 +1,15 @@ .welcome-div { display: flex; flex-direction: column; - height: 100%; flex: 1; padding: 0 60px; } .title { display: flex; - flex: 1; font-size: 60px; margin-bottom: 60px; - color: #ffffff; + color: #eee; justify-content: center; } @@ -20,6 +18,4 @@ flex: 2; align-items: center; justify-content: space-between; - margin-top: 8px; - gap: 40px; } \ No newline at end of file diff --git a/renderer/welcome.html b/renderer/welcome.html index 6b36dc0..e31f174 100644 --- a/renderer/welcome.html +++ b/renderer/welcome.html @@ -8,9 +8,7 @@
    - +

    @@ -59,6 +57,21 @@