Convert main.js to ESM and prettify code with Prettier

This commit is contained in:
2026-02-17 12:22:48 +01:00
parent 332c897c49
commit 2e54d5b222
8 changed files with 737 additions and 747 deletions

View File

@@ -0,0 +1 @@
<svg class="social-github" role="img" focusable="false" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14"><path d="m 7,1.1480539 c -3.313515,0 -6,2.68652 -6,6 0,2.65087 1.719175,4.9003701 4.103505,5.6933601 C 5.403301,12.897114 5.5,12.711544 5.5,12.552834 l 0,-1.11716 C 3.831039,11.798964 3.483359,10.728164 3.483359,10.728164 3.210913,10.034324 2.817388,9.8497439 2.817388,9.8497439 c -0.544456,-0.37205 0.04101,-0.36474 0.04101,-0.36474 0.602563,0.0425 0.919922,0.6186401 0.919922,0.6186401 0.535136,0.91698 1.403301,0.65187 1.746088,0.49855 0.05371,-0.38773 0.208951,-0.6523401 0.380854,-0.8022501 -1.333048,-0.15137 -2.733437,-0.66603 -2.733437,-2.96534 0,-0.65528 0.234379,-1.19045 0.618204,-1.61036 -0.0625,-0.15137 -0.267612,-0.76171 0.05764,-1.5879 0,0 0.503913,-0.16113 1.650349,0.61523 0.478981,-0.13282 0.992214,-0.19969 1.501981,-0.20214 0.509767,0.002 1.023903,0.0693 1.502913,0.20214 1.145534,-0.77636 1.648427,-0.61523 1.648427,-0.61523 0.326709,0.82616 0.121107,1.4365 0.0591,1.5879 0.384786,0.41991 0.61768,0.95508 0.61768,1.61036 0,2.30467 -1.403797,2.81199 -2.739729,2.96044 0.214806,0.18606 0.411641,0.5517401 0.411641,1.1113201 0,0.80274 0,1.44923 0,1.64647 0,0.15967 0.09615,0.34669 0.400369,0.28812 C 11.283214,12.046534 13,9.7984539 13,7.1480839 c 0,-3.31348 -2.686544,-6.00003 -6,-6.00003 z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,195 +1,197 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Silk Fly Launcher</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<head>
<meta charset="UTF-8" />
<title>Silk Fly Launcher</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="app">
<video autoplay muted loop class="background-video" id="background-video" src="assets/background/Silksong.mp4" type="video/mp4"></video>
<div class="app">
<video autoplay muted loop class="background-video" id="background-video" src="assets/background/Silksong.mp4" type="video/mp4"></video>
<!-- Sidebar -->
<aside class="sidebar">
<div class="logo" onclick="navigate('home')">
<img src="assets/logo.png" alt="Silk Fly Launcher Logo" class="logo-img"/>
<h5 class="logo-title">Silk Fly Launcher</h1>
</div>
<nav class="nav">
<div class="nav-section">
<span class="nav-title">Execute Silksong</span>
<button onclick="launch('vanilla')">
<img src="vanilla_launch_icon.png" class="button-icon"/>
Run Vanilla
<button onclick="launch('modded')">
<img src="modded_launch_icon.png" class="button-icon"/>
Run Modded
<!-- Sidebar -->
<aside class="sidebar">
<div class="logo" onclick="navigate('home')">
<img src="assets/logo.png" alt="Silk Fly Launcher Logo" class="logo-img" />
<h5 class="logo-title">Silk Fly Launcher</h5>
</div>
<div class="nav-section">
<span class="nav-title">Mods</span>
<button onclick="navigate('mods-installed')">
<img src="installed_mods_icon.png" class="button-icon"/>
Installed
<button onclick="navigate('mods-online')">
<img src="online_mods_icon.png" class="button-icon"/>
Online
</div>
<nav class="nav">
<div class="nav-section">
<span class="nav-title">Execute Silksong</span>
<button onclick="launch('vanilla')">
<img src="vanilla_launch_icon.png" class="button-icon" />
Run Vanilla
</button>
<button onclick="launch('modded')">
<img src="modded_launch_icon.png" class="button-icon" />
Run Modded
</button>
</div>
<div class="nav-section">
<span class="nav-title">Settings</span>
<button onclick="navigate('general-settings')">
<img src="general_settings_icon.png" class="button-icon"/>
General
</div>
</nav>
</aside>
<div class="nav-section">
<span class="nav-title">Mods</span>
<button onclick="navigate('mods-installed')">
<img src="installed_mods_icon.png" class="button-icon" />
Installed
</button>
<button onclick="navigate('mods-online')">
<img src="online_mods_icon.png" class="button-icon" />
Online
</button>
</div>
<!-- Main content -->
<main class="content">
<h1 id="title">Silk Fly Launcher</h1>
<div class="view" id="view">
</div>
</main>
</div>
<div class="nav-section">
<span class="nav-title">Settings</span>
<button onclick="navigate('general-settings')">
<img src="general_settings_icon.png" class="button-icon" />
General
</button>
</div>
</nav>
</aside>
<!-- Template -->
<template id="home-template">
<h2>About</h2>
<div class="horizontal-div separated-div">
<div class="horizontal-div">
<img src="assets/logo.png" alt="Silk Fly Launcher Logo" class="big-logo-img"/>
<div>
<h3>Silk Fly Launcher</h3>
<p class="transparent-text">v1.0.0</p>
</div>
</div>
<div class="horizontal-div">
<img onclick="electronAPI.openExternalLink('https://github.com/Gabi-Zar/Silk-Fly-Launcher')" src="data:image/svg+xml,%3csvg%20width='98'%20height='96'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20fill-rule='evenodd'%20clip-rule='evenodd'%20d='M48.854%200C21.839%200%200%2022%200%2049.217c0%2021.756%2013.993%2040.172%2033.405%2046.69%202.427.49%203.316-1.059%203.316-2.362%200-1.141-.08-5.052-.08-9.127-13.59%202.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015%204.934.326%207.523%205.052%207.523%205.052%204.367%207.496%2011.404%205.378%2014.235%204.074.404-3.178%201.699-5.378%203.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283%200-5.378%201.94-9.778%205.014-13.2-.485-1.222-2.184-6.275.486-13.038%200%200%204.125-1.304%2013.426%205.052a46.97%2046.97%200%200%201%2012.214-1.63c4.125%200%208.33.571%2012.213%201.63%209.302-6.356%2013.427-5.052%2013.427-5.052%202.67%206.763.97%2011.816.485%2013.038%203.155%203.422%205.015%207.822%205.015%2013.2%200%2018.905-11.404%2023.06-22.324%2024.283%201.78%201.548%203.316%204.481%203.316%209.126%200%206.6-.08%2011.897-.08%2013.526%200%201.304.89%202.853%203.316%202.364%2019.412-6.52%2033.405-24.935%2033.405-46.691C97.707%2022%2075.788%200%2048.854%200z'%20fill='%23fff'/%3e%3c/svg%3e" alt="Github logo" class="logo-img"/>
</div>
<!-- Main content -->
<main class="content">
<h1 id="title">Silk Fly Launcher</h1>
<div class="view" id="view"></div>
</main>
</div>
<br>
<ul>
<li>Silk Fly Launcher is a launcher and mod manager for Silksong mods from Nexus, built with Electron.</li>
<li>This product is licensed under the <a href="" class="link" onclick="electronAPI.openWindow('LICENSE')">GNU General Public License Version 3</a>.</li>
<li>This product uses third-party modules or assets under <a href="" class="link" onclick="electronAPI.openWindow('3RD-PARTY-LICENSES')">third-party licenses</a>.</li>
<li>Found a bug or have a feature request? Please <a href="" class="link" onclick="electronAPI.openExternalLink('https://github.com/Gabi-Zar/Silk-Fly-Launcher/issues')">create an issue on GitHub</a>.</li>
<li>Made with ♥ by <a href="" class="link" onclick="electronAPI.openExternalLink('https://github.com/Gabi-Zar')">GabiZar</a>.</li>
</ul>
<br>
</template>
<template id="installed-mods-template">
<h2>List Of Installed Mods</h2>
<form class="horizontal-div" id="search-form">
<input class="input" id="search-input" type="text" placeholder="Search For Mods...">
<button class="default-button" onclick="searchInstalledMods()">Search</button>
</form>
<div class="mods-container" id="mods-container">
</div>
</template>
<template id="online-mods-template">
<h2>List Of Nexus Mods</h2>
<form class="horizontal-div" id="search-form">
<input class="input" id="search-input" type="text" placeholder="Search For Mods...">
<button class="default-button" onclick="searchNexusMods()">Search</button>
</form>
<div class="mods-container" id="mods-container">
</div>
</template>
<template id="mod-template">
<div class="mod-container">
<div class="mod-text">
<div class="horizontal-div" >
<h3 id="mod-title">Unknown Title</h3>
<p id="mod-author">Unknown author</p>
<p id="mod-endorsements-number">? likes</p>
</div>
<p id="mod-description">No description provided</p>
<p class="transparent-text" id="mod-version">V1.0.0 last update on 01/01/2026</p>
<!-- Template -->
<template id="home-template">
<h2>About</h2>
<div class="horizontal-div separated-div">
<div class="horizontal-div">
<a href="www.nexusmods.com/hollowknightsilksong/mods" class="default-button" id="download-mod-button">Download</a>
<a href="www.nexusmods.com/hollowknightsilksong/mods" class="default-button" id="external-link">Website</a>
<img src="assets/logo.png" alt="Silk Fly Launcher Logo" class="big-logo-img" />
<div>
<h3>Silk Fly Launcher</h3>
<p class="transparent-text">v1.0.0</p>
</div>
</div>
<div class="horizontal-div">
<img onclick="electronAPI.openExternalLink('https://github.com/Gabi-Zar/Silk-Fly-Launcher')" src="assets/github.svg" alt="Github logo" class="logo-img invert-color" />
</div>
</div>
<img class="mod-icon" src="assets/placeholder_icon.png" alt="mod icon" id="mod-icon">
</div>
</template>
<template id="settings-template">
<h2>General settings</h2>
<div class="horizontal-div">
<label>Enter Silksong path: </label>
<input type="text" class="input" id="silksong-path-input" name="silksong-path-input">
<button class="default-button" onclick="autoDetectGamePath()">Auto Detect</button>
</div>
<div class="horizontal-div">
<label>Themes: </label>
<div class="themes-div">
<div class="default-button longer-button" id="themes-button" onclick="toggleThemesMenu()">Silksong</div>
<div class="themes-menu longer-button" id="themes-menu">
<li onclick="changeTheme('Silksong')">Silksong</li>
<li onclick="changeTheme('Citadel of song')">Citadel of song</li>
<li onclick="changeTheme('Cradle')">Cradle</li>
<li onclick="changeTheme('Abyss')">Abyss</li>
<li onclick="changeTheme('Greyroot')">Greyroot</li>
<li onclick="changeTheme('Surface')">Surface</li>
<li onclick="changeTheme('Steel')">Steel</li>
</div>
</div>
<label class="lace-pin-checkbox-container">
<input type="checkbox" name="lace-pin" id="lace-pin">
<span class="checkmark"></span>
Lace Pin
</label>
</div>
<br>
<h2>BepInEx</h2>
<p class="transparent-text" id="bepinex-version-text"></p>
<div class="horizontal-div">
<button class="default-button" onclick="installBepinex()">Install</button>
<button class="important-button" onclick="uninstallBepinex()">Uninstall</button>
<button class="default-button" onclick="backupBepinex()">Backup</button>
<button class="important-button" onclick="deleteBepinexBackup()">Delete Backup</button>
</div>
<br>
<h2>Nexus</h2>
<p class="transparent-text" id="bepinex-version-text"></p>
<div class="horizontal-div">
<label for="nexus-api-label">Enter your nexus api: </label>
<input type="text" class="input" id="nexus-api-input" name="nexus-api-input">
<img class="nexus-check-image" id="nexus-check-image" src="assets/cross.svg">
<button class="default-button" onclick="verifyNexusAPI()">Verify</button>
</div>
<br>
<h2>Import/Export</h2>
<div class="horizontal-div">
<button class="default-button" onclick="importData()">Import Data</button>
<button class="default-button" onclick="exportData()">Export Data</button>
<button class="important-button" onclick="deleteData()">Delete All Data</button>
</div>
<br>
<h2>Debugging</h2>
<div class="horizontal-div">
<h3>Versions: </h3>
<ul id="versions-list">
<li id="Silk-Fly-Launcher"></li>
<li id="Electron"></li>
<li id="Node"></li>
<li id="Chromium"></li>
<br />
<ul>
<li>Silk Fly Launcher is a launcher and mod manager for Silksong mods from Nexus, built with Electron.</li>
<li>This product is licensed under the <a href="" class="link" onclick="electronAPI.openWindow('LICENSE')">GNU General Public License Version 3</a>.</li>
<li>This product uses third-party modules or assets under <a href="" class="link" onclick="electronAPI.openWindow('3RD-PARTY-LICENSES')">third-party licenses</a>.</li>
<li>
Found a bug or have a feature request? Please
<a href="" class="link" onclick="electronAPI.openExternalLink('https://github.com/Gabi-Zar/Silk-Fly-Launcher/issues')">create an issue on GitHub</a>.
</li>
<li>Made with ♥ by <a href="" class="link" onclick="electronAPI.openExternalLink('https://github.com/Gabi-Zar')">GabiZar</a>.</li>
</ul>
<p id="version-text"></p>
</div>
</template>
<br />
</template>
<script src="renderer.js"></script>
<template id="installed-mods-template">
<h2>List Of Installed Mods</h2>
<form class="horizontal-div" id="search-form">
<input class="input" id="search-input" type="text" placeholder="Search For Mods..." />
<button class="default-button" onclick="searchInstalledMods()">Search</button>
</form>
<div class="mods-container" id="mods-container"></div>
</template>
</body>
</html>
<template id="online-mods-template">
<h2>List Of Nexus Mods</h2>
<form class="horizontal-div" id="search-form">
<input class="input" id="search-input" type="text" placeholder="Search For Mods..." />
<button class="default-button" onclick="searchNexusMods()">Search</button>
</form>
<div class="mods-container" id="mods-container"></div>
</template>
<template id="mod-template">
<div class="mod-container">
<div class="mod-text">
<div class="horizontal-div">
<h3 id="mod-title">Unknown Title</h3>
<p id="mod-author">Unknown author</p>
<p id="mod-endorsements-number">? likes</p>
</div>
<p id="mod-description">No description provided</p>
<p class="transparent-text" id="mod-version">V1.0.0 last update on 01/01/2026</p>
<div class="horizontal-div">
<a href="www.nexusmods.com/hollowknightsilksong/mods" class="default-button" id="download-mod-button">Download</a>
<a href="www.nexusmods.com/hollowknightsilksong/mods" class="default-button" id="external-link">Website</a>
</div>
</div>
<img class="mod-icon" src="assets/placeholder_icon.png" alt="mod icon" id="mod-icon" />
</div>
</template>
<template id="settings-template">
<h2>General settings</h2>
<div class="horizontal-div">
<label>Enter Silksong path: </label>
<input type="text" class="input" id="silksong-path-input" name="silksong-path-input" />
<button class="default-button" onclick="autoDetectGamePath()">Auto Detect</button>
</div>
<div class="horizontal-div">
<label>Themes: </label>
<div class="themes-div">
<div class="default-button longer-button" id="themes-button" onclick="toggleThemesMenu()">Silksong</div>
<div class="themes-menu longer-button" id="themes-menu">
<li onclick="changeTheme('Silksong')">Silksong</li>
<li onclick="changeTheme('Citadel of song')">Citadel of song</li>
<li onclick="changeTheme('Cradle')">Cradle</li>
<li onclick="changeTheme('Abyss')">Abyss</li>
<li onclick="changeTheme('Greyroot')">Greyroot</li>
<li onclick="changeTheme('Surface')">Surface</li>
<li onclick="changeTheme('Steel')">Steel</li>
</div>
</div>
<label class="lace-pin-checkbox-container">
<input type="checkbox" name="lace-pin" id="lace-pin" />
<span class="checkmark"></span>
Lace Pin
</label>
</div>
<br />
<h2>BepInEx</h2>
<p class="transparent-text" id="bepinex-version-text"></p>
<div class="horizontal-div">
<button class="default-button" onclick="installBepinex()">Install</button>
<button class="important-button" onclick="uninstallBepinex()">Uninstall</button>
<button class="default-button" onclick="backupBepinex()">Backup</button>
<button class="important-button" onclick="deleteBepinexBackup()">Delete Backup</button>
</div>
<br />
<h2>Nexus</h2>
<p class="transparent-text" id="bepinex-version-text"></p>
<div class="horizontal-div">
<label for="nexus-api-label">Enter your nexus api: </label>
<input type="text" class="input" id="nexus-api-input" name="nexus-api-input" />
<img class="nexus-check-image" id="nexus-check-image" src="assets/cross.svg" />
<button class="default-button" onclick="verifyNexusAPI()">Verify</button>
</div>
<br />
<h2>Import/Export</h2>
<div class="horizontal-div">
<button class="default-button" onclick="importData()">Import Data</button>
<button class="default-button" onclick="exportData()">Export Data</button>
<button class="important-button" onclick="deleteData()">Delete All Data</button>
</div>
<br />
<h2>Debugging</h2>
<div class="horizontal-div">
<h3>Versions:</h3>
<ul id="versions-list">
<li id="Silk-Fly-Launcher"></li>
<li id="Electron"></li>
<li id="Node"></li>
<li id="Chromium"></li>
</ul>
<p id="version-text"></p>
</div>
</template>
<script src="renderer.js"></script>
</body>
</html>

View File

@@ -8,13 +8,13 @@ const onlineModsTemplate = document.getElementById("online-mods-template");
const settingsTemplate = document.getElementById("settings-template");
const modTemplate = document.getElementById("mod-template");
let oldPage
let actualTheme = []
let oldPage;
let actualTheme = [];
//////////////////////////////////////////////////////
///////////////// CONST FOR WELCOME //////////////////
let actualPage = 0
let actualPage = 0;
const pageDiv = document.getElementById("page");
const buttonDiv = document.getElementById("button-div");
@@ -31,16 +31,15 @@ const tutorialTemplate = document.getElementById("tutorial-template");
//////////////////////////////////////////////////////
////////////////////// STARTUP ///////////////////////
on_startup()
on_startup();
async function on_startup() {
if (await electronAPI.getPage() == "index.html") {
const theme = await files.loadTheme()
changeTheme(theme[0], theme[1])
navigate("home")
}
else if (await electronAPI.getPage() == "welcome.html") {
welcomeNavigate()
if ((await electronAPI.getPage()) == "index.html") {
const theme = await files.loadTheme();
changeTheme(theme[0], theme[1]);
navigate("home");
} else if ((await electronAPI.getPage()) == "welcome.html") {
welcomeNavigate();
}
}
@@ -49,223 +48,220 @@ async function on_startup() {
async function navigate(page) {
if (oldPage == page) {
return
return;
}
oldPage = page
oldPage = page;
view.replaceChildren()
view.replaceChildren();
switch (page) {
case "home":
title.innerText = "Silk Fly Launcher";
const HomeTemplateCopy = HomeTemplate.content.cloneNode(true)
view.appendChild(HomeTemplateCopy)
const HomeTemplateCopy = HomeTemplate.content.cloneNode(true);
view.appendChild(HomeTemplateCopy);
break;
case "mods-installed":
title.innerText = "Installed Mods";
const installedModsTemplateCopy = installedModsTemplate.content.cloneNode(true)
const searchFormInstalled = installedModsTemplateCopy.getElementById("search-form")
searchFormInstalled.addEventListener('submit', async function(event) {
event.preventDefault()
})
const installedModsTemplateCopy = installedModsTemplate.content.cloneNode(true);
const searchFormInstalled = installedModsTemplateCopy.getElementById("search-form");
view.appendChild(installedModsTemplateCopy)
searchFormInstalled.addEventListener("submit", async function (event) {
event.preventDefault();
});
view.appendChild(installedModsTemplateCopy);
break;
case "mods-online":
title.innerText = "Online Mods";
const onlineModsTemplateCopy = onlineModsTemplate.content.cloneNode(true)
const ModsContainer = onlineModsTemplateCopy.getElementById("mods-container")
const searchFormNexus = onlineModsTemplateCopy.getElementById("search-form")
searchFormNexus.addEventListener('submit', async function(event) {
event.preventDefault()
})
const onlineModsTemplateCopy = onlineModsTemplate.content.cloneNode(true);
const ModsContainer = onlineModsTemplateCopy.getElementById("mods-container");
const searchFormNexus = onlineModsTemplateCopy.getElementById("search-form");
view.appendChild(onlineModsTemplateCopy)
searchFormNexus.addEventListener("submit", async function (event) {
event.preventDefault();
});
mods = await nexus.getLatestMods()
view.appendChild(onlineModsTemplateCopy);
mods = await nexus.getLatestMods();
if (mods == undefined) {
break;
}
for(const mod of mods) {
for (const mod of mods) {
if (mod.name == undefined) {
continue
continue;
}
const modTemplateCopy = modTemplate.content.cloneNode(true)
const modTemplateCopy = modTemplate.content.cloneNode(true);
if (mod.name) {
const modTitleText = modTemplateCopy.getElementById("mod-title")
modTitleText.innerText = mod.name
const modTitleText = modTemplateCopy.getElementById("mod-title");
modTitleText.innerText = mod.name;
}
if (mod.author) {
const modAuthorText = modTemplateCopy.getElementById("mod-author")
modAuthorText.innerText = `by ${mod.author}`
const modAuthorText = modTemplateCopy.getElementById("mod-author");
modAuthorText.innerText = `by ${mod.author}`;
}
if (mod.endorsement_count) {
const modEndorsementsNumber = modTemplateCopy.getElementById("mod-endorsements-number")
const modEndorsementsNumber = modTemplateCopy.getElementById("mod-endorsements-number");
if (mod.endorsement_count > 1) {
modEndorsementsNumber.innerText = `${mod.endorsement_count} likes`
}
else {
modEndorsementsNumber.innerText = `${mod.endorsement_count} like`
modEndorsementsNumber.innerText = `${mod.endorsement_count} likes`;
} else {
modEndorsementsNumber.innerText = `${mod.endorsement_count} like`;
}
}
if (mod.summary) {
const modDescriptionText = modTemplateCopy.getElementById("mod-description")
modDescriptionText.innerText = mod.summary
const modDescriptionText = modTemplateCopy.getElementById("mod-description");
modDescriptionText.innerText = mod.summary;
}
if (mod.picture_url) {
const modPicture = modTemplateCopy.getElementById("mod-icon")
modPicture.src = mod.picture_url
const modPicture = modTemplateCopy.getElementById("mod-icon");
modPicture.src = mod.picture_url;
}
if (mod.version && mod.updated_timestamp) {
const modVersionText = modTemplateCopy.getElementById("mod-version")
modVersionText.innerText = `V${mod.version} last updated on ${mod.updated_time.slice(0, 10)}`
const modVersionText = modTemplateCopy.getElementById("mod-version");
modVersionText.innerText = `V${mod.version} last updated on ${mod.updated_time.slice(0, 10)}`;
}
const modUrl = `https://www.nexusmods.com/hollowknightsilksong/mods/${mod.mod_id}`
const modUrl = `https://www.nexusmods.com/hollowknightsilksong/mods/${mod.mod_id}`;
const modLinkButton = modTemplateCopy.getElementById("external-link")
modLinkButton.href = modUrl
modLinkButton.addEventListener('click', function(event) {
event.preventDefault()
const modLink = modLinkButton.href
electronAPI.openExternalLink(modLink)
})
const modLinkButton = modTemplateCopy.getElementById("external-link");
modLinkButton.href = modUrl;
modLinkButton.addEventListener("click", function (event) {
event.preventDefault();
const modLink = modLinkButton.href;
electronAPI.openExternalLink(modLink);
});
modDownloadButton = modTemplateCopy.getElementById("download-mod-button")
modDownloadButton.addEventListener('click', function(event) {
event.preventDefault()
const modDownloadLink = `${modUrl}?tab=files`
nexus.download(modDownloadLink)
})
modDownloadButton = modTemplateCopy.getElementById("download-mod-button");
modDownloadButton.addEventListener("click", function (event) {
event.preventDefault();
const modDownloadLink = `${modUrl}?tab=files`;
nexus.download(modDownloadLink);
});
ModsContainer.appendChild(modTemplateCopy)
ModsContainer.appendChild(modTemplateCopy);
}
break;
case "general-settings":
title.innerText = "Settings";
const settingsTemplateCopy = settingsTemplate.content.cloneNode(true)
const silksongPathInput = settingsTemplateCopy.getElementById("silksong-path-input")
const nexusAPIInput = settingsTemplateCopy.getElementById("nexus-api-input")
const versionsList = settingsTemplateCopy.getElementById("versions-list")
const settingsTemplateCopy = settingsTemplate.content.cloneNode(true);
const silksongPathInput = settingsTemplateCopy.getElementById("silksong-path-input");
const nexusAPIInput = settingsTemplateCopy.getElementById("nexus-api-input");
const versionsList = settingsTemplateCopy.getElementById("versions-list");
const versionsDictionnary = {
"Silk-Fly-Launcher": `Silk Fly Launcher: v${versions.silkFlyLauncher()}`,
"Electron": `Electron: v${versions.electron()}`,
"Node": `Node.js: v${versions.node()}`,
"Chromium": `Chromium: v${versions.chromium()}`,
}
const lacePinCheckbox = settingsTemplateCopy.getElementById('lace-pin');
"Silk-Fly-Launcher": `Silk Fly Launcher: v${versions.silkFlyLauncher()}`,
Electron: `Electron: v${versions.electron()}`,
Node: `Node.js: v${versions.node()}`,
Chromium: `Chromium: v${versions.chromium()}`,
};
const lacePinCheckbox = settingsTemplateCopy.getElementById("lace-pin");
silksongPathInput.value = await files.loadSilksongPath()
silksongPathInput.addEventListener('input', async function(event) {
let silksongPath = silksongPathInput.value
files.saveSilksongPath(silksongPath)
silksongPathInput.value = await files.loadSilksongPath();
silksongPathInput.addEventListener("input", async function (event) {
let silksongPath = silksongPathInput.value;
files.saveSilksongPath(silksongPath);
});
nexusAPIInput.value = await files.loadNexusAPI()
nexusAPIInput.addEventListener('input', async function(event) {
let nexusAPI = nexusAPIInput.value
files.saveNexusAPI(nexusAPI)
nexusAPIInput.value = await files.loadNexusAPI();
nexusAPIInput.addEventListener("input", async function (event) {
let nexusAPI = nexusAPIInput.value;
files.saveNexusAPI(nexusAPI);
});
for(const element of versionsList.children) {
element.innerText = versionsDictionnary[element.id]
for (const element of versionsList.children) {
element.innerText = versionsDictionnary[element.id];
}
const theme = await files.loadTheme()
lacePinCheckbox.checked = theme[1]
const theme = await files.loadTheme();
lacePinCheckbox.checked = theme[1];
lacePinCheckbox.addEventListener('change', async function() {
lacePinCheckbox.addEventListener("change", async function () {
if (this.checked) {
const theme = await files.loadTheme();
changeTheme(theme[0], true);
toggleThemesMenu()
}
else {
toggleThemesMenu();
} else {
const theme = await files.loadTheme();
changeTheme(theme[0], false);
toggleThemesMenu()
toggleThemesMenu();
}
});
view.appendChild(settingsTemplateCopy)
setBepinexVersion()
setThemeButton()
verifyNexusAPI()
view.appendChild(settingsTemplateCopy);
setBepinexVersion();
setThemeButton();
verifyNexusAPI();
break;
}
}
async function welcomeNavigate() {
pageDiv.replaceChildren()
pageDiv.replaceChildren();
switch (actualPage) {
case 0:
pageDiv.appendChild(welcomeTemplate.content.cloneNode(true))
buttonDiv.replaceChildren()
buttonDiv.appendChild(oneButtonTemplate.content.cloneNode(true))
pageDiv.appendChild(welcomeTemplate.content.cloneNode(true));
buttonDiv.replaceChildren();
buttonDiv.appendChild(oneButtonTemplate.content.cloneNode(true));
break;
case 1:
pageDiv.appendChild(silksongPathTemplate.content.cloneNode(true))
buttonDiv.replaceChildren()
buttonDiv.appendChild(twoButtonTemplate.content.cloneNode(true))
pageDiv.appendChild(silksongPathTemplate.content.cloneNode(true));
buttonDiv.replaceChildren();
buttonDiv.appendChild(twoButtonTemplate.content.cloneNode(true));
const silksongPathInput = document.getElementById("silksong-path-input")
if (await files.loadSilksongPath() == "") {
autoDetectGamePath()
}
else {
document.getElementById("silksong-path-input").value = await files.loadSilksongPath()
const silksongPathInput = document.getElementById("silksong-path-input");
if ((await files.loadSilksongPath()) == "") {
autoDetectGamePath();
} else {
document.getElementById("silksong-path-input").value = await files.loadSilksongPath();
}
silksongPathInput.addEventListener('input', async function(event) {
let silksongPath = silksongPathInput.value
await files.saveSilksongPath(silksongPath)
silksongPathInput.addEventListener("input", async function (event) {
let silksongPath = silksongPathInput.value;
await files.saveSilksongPath(silksongPath);
});
break;
case 2:
pageDiv.appendChild(nexusTemplate.content.cloneNode(true))
const nexusLink = document.getElementById("external-link")
nexusLink.addEventListener('click', function(event) {
event.preventDefault()
const url = nexusLink.href
electronAPI.openExternalLink(url)
})
pageDiv.appendChild(nexusTemplate.content.cloneNode(true));
const nexusLink = document.getElementById("external-link");
nexusLink.addEventListener("click", function (event) {
event.preventDefault();
const url = nexusLink.href;
electronAPI.openExternalLink(url);
});
const nexusAPIInput = document.getElementById("nexus-api-input")
nexusAPIInput.value = await files.loadNexusAPI()
nexusAPIInput.addEventListener('input', async function(event) {
let nexusAPI = nexusAPIInput.value
await files.saveNexusAPI(nexusAPI)
const nexusAPIInput = document.getElementById("nexus-api-input");
nexusAPIInput.value = await files.loadNexusAPI();
nexusAPIInput.addEventListener("input", async function (event) {
let nexusAPI = nexusAPIInput.value;
await files.saveNexusAPI(nexusAPI);
});
break;
case 3:
pageDiv.appendChild(styleTemplate.content.cloneNode(true))
pageDiv.appendChild(styleTemplate.content.cloneNode(true));
break;
case 4:
pageDiv.appendChild(tutorialTemplate.content.cloneNode(true))
pageDiv.appendChild(tutorialTemplate.content.cloneNode(true));
break;
case 5:
electronAPI.loadMainPage()
electronAPI.loadMainPage();
break;
}
}
function next() {
actualPage++
welcomeNavigate()
actualPage++;
welcomeNavigate();
}
function back() {
actualPage--
welcomeNavigate()
actualPage--;
welcomeNavigate();
}
//////////////////////////////////////////////////////
@@ -273,149 +269,145 @@ function back() {
async function initialImportData() {
if (await files.import()) {
electronAPI.loadMainPage()
electronAPI.loadMainPage();
}
}
async function importData() {
await files.import()
document.getElementById("silksong-path-input").value = await files.loadSilksongPath()
document.getElementById("nexus-api-input").value = await files.loadNexusAPI()
const lacePinCheckbox = document.getElementById('lace-pin')
const theme = await files.loadTheme()
lacePinCheckbox.checked = theme[1]
changeTheme(theme[0])
toggleThemesMenu()
await files.import();
document.getElementById("silksong-path-input").value = await files.loadSilksongPath();
document.getElementById("nexus-api-input").value = await files.loadNexusAPI();
const lacePinCheckbox = document.getElementById("lace-pin");
const theme = await files.loadTheme();
lacePinCheckbox.checked = theme[1];
changeTheme(theme[0]);
toggleThemesMenu();
}
async function exportData() {
await files.export()
await files.export();
}
async function deleteData() {
const lacePinCheckbox = document.getElementById('lace-pin')
lacePinCheckbox.checked = false
changeTheme("Silksong")
toggleThemesMenu()
await files.delete()
document.getElementById("silksong-path-input").value = await files.loadSilksongPath()
document.getElementById("nexus-api-input").value = await files.loadNexusAPI()
const lacePinCheckbox = document.getElementById("lace-pin");
lacePinCheckbox.checked = false;
changeTheme("Silksong");
toggleThemesMenu();
await files.delete();
document.getElementById("silksong-path-input").value = await files.loadSilksongPath();
document.getElementById("nexus-api-input").value = await files.loadNexusAPI();
}
//////////////////////////////////////////////////////
////////////////////// BEPINEX ///////////////////////
async function installBepinex() {
await bepinex.install()
setBepinexVersion()
await bepinex.install();
setBepinexVersion();
}
async function uninstallBepinex() {
await bepinex.uninstall()
setBepinexVersion()
await bepinex.uninstall();
setBepinexVersion();
}
async function backupBepinex() {
await bepinex.backup()
setBepinexVersion()
await bepinex.backup();
setBepinexVersion();
}
async function deleteBepinexBackup() {
await bepinex.deleteBackup()
setBepinexVersion()
await bepinex.deleteBackup();
setBepinexVersion();
}
async function setBepinexVersion() {
const bepinexVersionText = document.getElementById("bepinex-version-text")
const bepinexVersionText = document.getElementById("bepinex-version-text");
if (bepinexVersionText == undefined) {
return
return;
}
const bepinexVersion = await files.loadBepinexVersion()
const bepinexBackupVersion = await files.loadBepinexBackupVersion()
if(bepinexVersion == undefined) {
if(bepinexBackupVersion == undefined) {
bepinexVersionText.innerText = "BepInEx is not installed"
const bepinexVersion = await files.loadBepinexVersion();
const bepinexBackupVersion = await files.loadBepinexBackupVersion();
if (bepinexVersion == undefined) {
if (bepinexBackupVersion == undefined) {
bepinexVersionText.innerText = "BepInEx is not installed";
} else {
bepinexVersionText.innerText = `BepInEx ${bepinexBackupVersion} is backed up`;
}
else {
bepinexVersionText.innerText = `BepInEx ${bepinexBackupVersion} is backed up`
}
}
else {
bepinexVersionText.innerText = `BepInEx ${bepinexVersion} is installed`
} else {
bepinexVersionText.innerText = `BepInEx ${bepinexVersion} is installed`;
}
}
async function searchInstalledMods() {
const searchInput = document.getElementById("search-input")
console.log(searchInput.value)
const searchInput = document.getElementById("search-input");
console.log(searchInput.value);
}
//////////////////////////////////////////////////////
/////////////////////// NEXUS ////////////////////////
async function verifyNexusAPI() {
response = await nexus.verifyAPI()
response = await nexus.verifyAPI();
const nexusCheckImage = document.getElementById("nexus-check-image")
const nexusCheckImage = document.getElementById("nexus-check-image");
if (nexusCheckImage == undefined) {
return
return;
}
if (response) {
nexusCheckImage.src = "assets/check.svg"
}
else {
nexusCheckImage.src = "assets/cross.svg"
nexusCheckImage.src = "assets/check.svg";
} else {
nexusCheckImage.src = "assets/cross.svg";
}
}
async function searchNexusMods() {
const searchInput = document.getElementById("search-input")
console.log(searchInput.value)
const searchInput = document.getElementById("search-input");
console.log(searchInput.value);
}
//////////////////////////////////////////////////////
/////////////////////// THEMES ///////////////////////
function toggleThemesMenu() {
const themesMenu = document.getElementById("themes-menu")
const themesMenu = document.getElementById("themes-menu");
if (themesMenu) {
themesMenu.classList.toggle("show")
themesMenu.classList.toggle("show");
}
}
async function setThemeButton() {
const themesButton = document.getElementById("themes-button")
const themesButton = document.getElementById("themes-button");
if (themesButton) {
const theme = await files.loadTheme()
themesButton.textContent = theme[0]
const theme = await files.loadTheme();
themesButton.textContent = theme[0];
}
}
function changeTheme(theme, state) {
toggleThemesMenu()
toggleThemesMenu();
const lacePinCheckbox = document.getElementById('lace-pin');
const lacePinCheckbox = document.getElementById("lace-pin");
if (lacePinCheckbox) {
lacePinState = lacePinCheckbox.checked;
}
else if (state) {
lacePinState = state
}
else {
lacePinState = false
} else if (state) {
lacePinState = state;
} else {
lacePinState = false;
}
if (actualTheme[0] == theme && actualTheme[1] == lacePinState) {
return
return;
}
actualTheme = [theme, lacePinState]
actualTheme = [theme, lacePinState];
files.saveTheme(theme, lacePinState)
files.saveTheme(theme, lacePinState);
setThemeButton()
setThemeButton();
// prettier-ignore
const themesColors = {
"var": ["--primary-color", "--secondary-color", "--background-color"],
"Silksong": ["rgba(255, 25, 0, 0.3)", "#ff6b6b", "rgba(255, 72, 0, 0.2)"],
@@ -426,17 +418,18 @@ function changeTheme(theme, state) {
"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])
for (let i = 0; i < 3; i++) {
document.documentElement.style.setProperty(themesColors.var[i], themesColors[theme][i]);
}
const backgroundVideo = document.getElementById("background-video")
let backgroundVideoPath = `assets/background/${theme}.mp4`
const backgroundVideo = document.getElementById("background-video");
let backgroundVideoPath = `assets/background/${theme}.mp4`;
if (lacePinState) {
backgroundVideoPath = `assets/background/${theme} Lace Pin.mp4`
backgroundVideoPath = `assets/background/${theme} Lace Pin.mp4`;
}
backgroundVideo.src = backgroundVideoPath
backgroundVideo.src = backgroundVideoPath;
}
//////////////////////////////////////////////////////
@@ -444,12 +437,12 @@ function changeTheme(theme, state) {
async function launch(mode) {
await electronAPI.launchGame(mode);
setBepinexVersion()
setBepinexVersion();
}
async function autoDetectGamePath() {
await files.autoDetectGamePath()
await files.autoDetectGamePath();
if (document.getElementById("silksong-path-input")) {
document.getElementById("silksong-path-input").value = await files.loadSilksongPath()
document.getElementById("silksong-path-input").value = await files.loadSilksongPath();
}
}
}

View File

@@ -2,7 +2,9 @@
margin: 0;
box-sizing: border-box;
font-family: "Segoe UI", sans-serif;
cursor: url("assets/cursor.png") 0 0, auto !important;
cursor:
url("assets/cursor.png") 0 0,
auto !important;
}
:root {
@@ -13,7 +15,7 @@
--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)
--transparent-grey: rgba(30, 30, 30, 0.8);
}
body {
@@ -69,6 +71,10 @@ body {
height: 100px;
}
.invert-color {
filter: invert(1);
}
.nav {
padding: 20px;
}
@@ -86,7 +92,7 @@ body {
margin-bottom: 10px;
padding: 0 4px 4px;
border-bottom: 1px solid var(--secondary-color);
border-bottom: 1px solid var(--secondary-color);
}
.nav button {
@@ -124,7 +130,7 @@ body {
margin-bottom: 20px;
color: var(--text-color);
padding: 0 4px 4px;
border-bottom: 1px solid var(--secondary-color);
border-bottom: 1px solid var(--secondary-color);
}
.view {
@@ -135,7 +141,7 @@ body {
z-index: 0;
box-shadow: 0 0 50px var(--darker-transparent-black);
overflow: auto;
height: 90%;
height: 90%;
}
.horizontal-div {
@@ -371,4 +377,4 @@ body {
border: solid var(--text-color);
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
}

View File

@@ -1,84 +1,87 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Welcome to Silk Fly Launcher</title>
<link rel="stylesheet" href="welcome.css" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="app">
<video autoplay muted loop class="background-video" id="background-video" src="assets/background/Silksong.mp4" type="video/mp4"></video>
<head>
<meta charset="UTF-8" />
<title>Welcome to Silk Fly Launcher</title>
<link rel="stylesheet" href="welcome.css" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="app">
<video autoplay muted loop class="background-video" id="background-video" src="assets/background/Silksong.mp4" type="video/mp4"></video>
<div class="welcome-div" id="main-div">
<br>
<div id="page"></div>
<div class="button-div" id="button-div"></div>
</div>
</div>
<template id="welcome-template">
<h1 class="title">Welcome to Silk Fly Launcher</h1>
<div class="horizontal-div welcome-div">
<p>Silk Fly Launcher is a launcher and mod manager for Silksong mods from Nexus, built with Electron.</p>
<p>Made with ♥ by <a href="" class="link" onclick="electronAPI.openExternalLink('https://github.com/Gabi-Zar')">GabiZar</a>.</p>
</div>
</template>
<template id="one-button-template">
<button class="default-button bigger-button" onclick="initialImportData()">Import Data</button>
<button class="default-button bigger-button" onclick="next()">Next →</button>
</template>
<template id="two-button-template">
<button class="default-button bigger-button" onclick="back()">← Back</button>
<button class="default-button bigger-button" onclick="next()">Next →</button>
</template>
<template id="path-template">
<h1 class="title">Enter Hollow Knight: Silksong path</h1>
<p>Please verify the path to your game and edit it if the auto detection didn't work</p>
<div class="horizontal-div">
<label>Enter Silksong path: </label>
<input type="text" class="input" id="silksong-path-input" name="silksong-path-input">
<button class="default-button" onclick="autoDetectGamePath()">Auto Detect</button>
</div>
</template>
<template id="nexus-template">
<h1 class="title">Enter your nexus API key</h1>
<p>Please enter your nexus API key. To get your API key go to <a href="https://www.nexusmods.com/settings/api-keys" class="link" id="external-link">https://www.nexusmods.com/settings/api-keys</a> and click on new personnal API key</p>
<div class="horizontal-div">
<label for="nexus-api-label">Enter your nexus api: </label>
<input type="text" class="input" id="nexus-api-input" name="nexus-api-input">
<img class="nexus-check-image" id="nexus-check-image" src="assets/cross.svg">
<button class="default-button" onclick="verifyNexusAPI()">Verify</button>
</div>
</template>
<template id="style-template">
<h1 class="title">Chose the theme of the app</h1>
<div class="horizontal-div welcome-div">
<label>Themes: </label>
<div class="themes-div">
<div class="default-button longer-button" id="themes-button" onclick="toggleThemesMenu()">Silksong</div>
<div class="themes-menu longer-button" id="themes-menu">
<li onclick="changeTheme('Silksong')">Silksong</li>
<li onclick="changeTheme('Citadel of song')">Citadel of song</li>
<li onclick="changeTheme('Cradle')">Cradle</li>
<li onclick="changeTheme('Abyss')">Abyss</li>
<li onclick="changeTheme('Greyroot')">Greyroot</li>
<li onclick="changeTheme('Surface')">Surface</li>
<li onclick="changeTheme('Steel')">Steel</li>
</div>
<div class="welcome-div" id="main-div">
<br />
<div id="page"></div>
<div class="button-div" id="button-div"></div>
</div>
</div>
</template>
<template id="tutorial-template">
<h1 class="title">Tutorial to download mod from nexus</h1>
</template>
<template id="welcome-template">
<h1 class="title">Welcome to Silk Fly Launcher</h1>
<div class="horizontal-div welcome-div">
<p>Silk Fly Launcher is a launcher and mod manager for Silksong mods from Nexus, built with Electron.</p>
<p>Made with ♥ by <a href="" class="link" onclick="electronAPI.openExternalLink('https://github.com/Gabi-Zar')">GabiZar</a>.</p>
</div>
</template>
<script src="renderer.js"></script>
</body>
</html>
<template id="one-button-template">
<button class="default-button bigger-button" onclick="initialImportData()">Import Data</button>
<button class="default-button bigger-button" onclick="next()">Next →</button>
</template>
<template id="two-button-template">
<button class="default-button bigger-button" onclick="back()">← Back</button>
<button class="default-button bigger-button" onclick="next()">Next →</button>
</template>
<template id="path-template">
<h1 class="title">Enter Hollow Knight: Silksong path</h1>
<p>Please verify the path to your game and edit it if the auto detection didn't work</p>
<div class="horizontal-div">
<label>Enter Silksong path: </label>
<input type="text" class="input" id="silksong-path-input" name="silksong-path-input" />
<button class="default-button" onclick="autoDetectGamePath()">Auto Detect</button>
</div>
</template>
<template id="nexus-template">
<h1 class="title">Enter your nexus API key</h1>
<p>
Please enter your nexus API key. To get your API key go to
<a href="https://www.nexusmods.com/settings/api-keys" class="link" id="external-link">https://www.nexusmods.com/settings/api-keys</a> and click on new personnal API key
</p>
<div class="horizontal-div">
<label for="nexus-api-label">Enter your nexus api: </label>
<input type="text" class="input" id="nexus-api-input" name="nexus-api-input" />
<img class="nexus-check-image" id="nexus-check-image" src="assets/cross.svg" />
<button class="default-button" onclick="verifyNexusAPI()">Verify</button>
</div>
</template>
<template id="style-template">
<h1 class="title">Chose the theme of the app</h1>
<div class="horizontal-div welcome-div">
<label>Themes: </label>
<div class="themes-div">
<div class="default-button longer-button" id="themes-button" onclick="toggleThemesMenu()">Silksong</div>
<div class="themes-menu longer-button" id="themes-menu">
<li onclick="changeTheme('Silksong')">Silksong</li>
<li onclick="changeTheme('Citadel of song')">Citadel of song</li>
<li onclick="changeTheme('Cradle')">Cradle</li>
<li onclick="changeTheme('Abyss')">Abyss</li>
<li onclick="changeTheme('Greyroot')">Greyroot</li>
<li onclick="changeTheme('Surface')">Surface</li>
<li onclick="changeTheme('Steel')">Steel</li>
</div>
</div>
</div>
</template>
<template id="tutorial-template">
<h1 class="title">Tutorial to download mod from nexus</h1>
</template>
<script src="renderer.js"></script>
</body>
</html>