mirror of
https://github.com/Gabi-Zar/Silk-Fly-Launcher.git
synced 2026-04-17 05:26:04 +02:00
Convert main.js to ESM and prettify code with Prettier
This commit is contained in:
426
main.js
426
main.js
@@ -1,144 +1,141 @@
|
|||||||
const { app, BrowserWindow , ipcMain, dialog, shell} = require('electron/main');
|
import { app, BrowserWindow, ipcMain, dialog, shell } from "electron";
|
||||||
const path = require('node:path');
|
import path from "path";
|
||||||
const Store = require('electron-store').default;
|
import { fileURLToPath } from "url";
|
||||||
const fs = require('fs/promises');
|
import Store from "electron-store";
|
||||||
const { createWriteStream } = require('fs');
|
import fs from "fs/promises";
|
||||||
const { pipeline } = require('stream/promises');
|
import { createWriteStream } from "fs";
|
||||||
const extract = require('extract-zip');
|
import { pipeline } from "stream/promises";
|
||||||
const Nexus = require('@nexusmods/nexus-api').default;
|
import extract from "extract-zip";
|
||||||
|
import NexusModule from "@nexusmods/nexus-api";
|
||||||
|
const Nexus = NexusModule.default;
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
const store = new Store();
|
const store = new Store();
|
||||||
const userSavePath = app.getPath('userData')
|
const userSavePath = app.getPath("userData");
|
||||||
const dataPath = `${userSavePath}\\config.json`
|
const dataPath = `${userSavePath}\\config.json`;
|
||||||
let silksongPath = store.get('silksong-path')
|
let silksongPath = store.get("silksong-path");
|
||||||
|
|
||||||
let nexusAPI = store.get('nexus-api')
|
let nexusAPI = store.get("nexus-api");
|
||||||
let nexus = undefined
|
let nexus = undefined;
|
||||||
createNexus()
|
createNexus();
|
||||||
|
|
||||||
let bepinexFolderPath = `${silksongPath}/BepInEx`
|
let bepinexFolderPath = `${silksongPath}/BepInEx`;
|
||||||
let bepinexBackupPath = `${silksongPath}/BepInEx-Backup`
|
let bepinexBackupPath = `${silksongPath}/BepInEx-Backup`;
|
||||||
const bepinexFiles = [
|
const bepinexFiles = [".doorstop_version", "changelog.txt", "doorstop_config.ini", "winhttp.dll"];
|
||||||
".doorstop_version",
|
|
||||||
"changelog.txt",
|
|
||||||
"doorstop_config.ini",
|
|
||||||
"winhttp.dll"
|
|
||||||
]
|
|
||||||
|
|
||||||
let bepinexVersion
|
let bepinexVersion;
|
||||||
let bepinexBackupVersion
|
let bepinexBackupVersion;
|
||||||
const bepinexStore = new Store({cwd: 'bepinex-version'});
|
const bepinexStore = new Store({ cwd: "bepinex-version" });
|
||||||
|
|
||||||
let mainWindow
|
let mainWindow;
|
||||||
let htmlFile
|
let htmlFile;
|
||||||
|
|
||||||
async function createWindow() {
|
async function createWindow() {
|
||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
width: 1280,
|
width: 1280,
|
||||||
height: 720,
|
height: 720,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: path.join(__dirname, 'preload.js')
|
preload: path.join(__dirname, "preload.js"),
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
if(await fileExists(dataPath)) {
|
if (await fileExists(dataPath)) {
|
||||||
htmlFile = "index.html"
|
htmlFile = "index.html";
|
||||||
}
|
} else {
|
||||||
else {
|
htmlFile = "welcome.html";
|
||||||
htmlFile = "welcome.html"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mainWindow.loadFile(`renderer/${htmlFile}`)
|
mainWindow.loadFile(`renderer/${htmlFile}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
createWindow()
|
createWindow();
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on("activate", () => {
|
||||||
if (BrowserWindow.getAllWindows().length === 0) {
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
createWindow()
|
createWindow();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
app.on("window-all-closed", () => {
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== "darwin") {
|
||||||
app.quit()
|
app.quit();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
///////////////// SAVING AND LOADING /////////////////
|
///////////////// SAVING AND LOADING /////////////////
|
||||||
ipcMain.handle('save-path', (event, path) => {
|
ipcMain.handle("save-path", (event, path) => {
|
||||||
saveSilksongPath(path)
|
saveSilksongPath(path);
|
||||||
});
|
});
|
||||||
function saveSilksongPath(path) {
|
function saveSilksongPath(path) {
|
||||||
silksongPath = path;
|
silksongPath = path;
|
||||||
bepinexFolderPath = `${silksongPath}/BepInEx`
|
bepinexFolderPath = `${silksongPath}/BepInEx`;
|
||||||
bepinexBackupPath = `${silksongPath}/BepInEx-Backup`
|
bepinexBackupPath = `${silksongPath}/BepInEx-Backup`;
|
||||||
store.set('silksong-path', silksongPath);
|
store.set("silksong-path", silksongPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('load-path', () => {
|
ipcMain.handle("load-path", () => {
|
||||||
silksongPath = store.get('silksong-path');
|
silksongPath = store.get("silksong-path");
|
||||||
if (silksongPath == undefined) {
|
if (silksongPath == undefined) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return silksongPath;
|
return silksongPath;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function saveBepinexVersion(version) {
|
function saveBepinexVersion(version) {
|
||||||
bepinexVersion = version;
|
bepinexVersion = version;
|
||||||
if (bepinexVersion == undefined) {
|
if (bepinexVersion == undefined) {
|
||||||
bepinexStore.delete('bepinex-version');
|
bepinexStore.delete("bepinex-version");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bepinexStore.set('bepinex-version', version);
|
bepinexStore.set("bepinex-version", version);
|
||||||
};
|
}
|
||||||
|
|
||||||
ipcMain.handle('load-bepinex-version', () => {
|
ipcMain.handle("load-bepinex-version", () => {
|
||||||
bepinexVersion = bepinexStore.get('bepinex-version');
|
bepinexVersion = bepinexStore.get("bepinex-version");
|
||||||
return bepinexVersion;
|
return bepinexVersion;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function saveBepinexBackupVersion(version) {
|
function saveBepinexBackupVersion(version) {
|
||||||
bepinexBackupVersion = version;
|
bepinexBackupVersion = version;
|
||||||
if (bepinexBackupVersion == undefined) {
|
if (bepinexBackupVersion == undefined) {
|
||||||
bepinexStore.delete('bepinex-backup-version');
|
bepinexStore.delete("bepinex-backup-version");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bepinexStore.set('bepinex-backup-version', version);
|
bepinexStore.set("bepinex-backup-version", version);
|
||||||
};
|
}
|
||||||
|
|
||||||
ipcMain.handle('load-bepinex-backup-version', () => {
|
ipcMain.handle("load-bepinex-backup-version", () => {
|
||||||
bepinexBackupVersion = bepinexStore.get('bepinex-backup-version');
|
bepinexBackupVersion = bepinexStore.get("bepinex-backup-version");
|
||||||
return bepinexBackupVersion;
|
return bepinexBackupVersion;
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('save-nexus-api', (event, api) => {
|
ipcMain.handle("save-nexus-api", (event, api) => {
|
||||||
nexusAPI = api;
|
nexusAPI = api;
|
||||||
createNexus()
|
createNexus();
|
||||||
store.set('nexus-api', nexusAPI);
|
store.set("nexus-api", nexusAPI);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('load-nexus-api', () => {
|
ipcMain.handle("load-nexus-api", () => {
|
||||||
nexusAPI = store.get('nexus-api');
|
nexusAPI = store.get("nexus-api");
|
||||||
if (nexusAPI == undefined) {
|
if (nexusAPI == undefined) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return nexusAPI;
|
return nexusAPI;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle("save-theme", (event, theme, lacePinState) => {
|
||||||
ipcMain.handle('save-theme', (event, theme, lacePinState) => {
|
store.set("theme.theme", theme);
|
||||||
store.set('theme.theme', theme);
|
store.set("theme.lacePinState", lacePinState);
|
||||||
store.set('theme.lacePinState', lacePinState);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('load-theme', () => {
|
ipcMain.handle("load-theme", () => {
|
||||||
theme = [store.get('theme.theme'), store.get('theme.lacePinState')];
|
const theme = [store.get("theme.theme"), store.get("theme.lacePinState")];
|
||||||
if (theme[0] == undefined) {
|
if (theme[0] == undefined) {
|
||||||
return ["Silksong", false];
|
return ["Silksong", false];
|
||||||
}
|
}
|
||||||
return theme;
|
return theme;
|
||||||
@@ -156,45 +153,43 @@ async function fileExists(filePath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('delete-data', async () => {
|
ipcMain.handle("delete-data", async () => {
|
||||||
if (await fileExists(dataPath)) {
|
if (await fileExists(dataPath)) {
|
||||||
await fs.unlink(dataPath)
|
await fs.unlink(dataPath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('export-data', async () => {
|
ipcMain.handle("export-data", async () => {
|
||||||
if (!await fileExists(dataPath)) {
|
if (!(await fileExists(dataPath))) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { canceled, filePath } = await dialog.showSaveDialog({
|
const { canceled, filePath } = await dialog.showSaveDialog({
|
||||||
title: 'Export Data',
|
title: "Export Data",
|
||||||
defaultPath: 'config.json',
|
defaultPath: "config.json",
|
||||||
filters: [
|
filters: [{ name: "JSON", extensions: ["json"] }],
|
||||||
{ name: 'JSON', extensions: ['json'] }
|
});
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
if (canceled || !filePath) return
|
if (canceled || !filePath) return;
|
||||||
|
|
||||||
await fs.copyFile(dataPath, filePath)
|
await fs.copyFile(dataPath, filePath);
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMain.handle('import-data', async () => {
|
ipcMain.handle("import-data", async () => {
|
||||||
const { canceled, filePaths } = await dialog.showOpenDialog({
|
const { canceled, filePaths } = await dialog.showOpenDialog({
|
||||||
title: 'Import Data',
|
title: "Import Data",
|
||||||
properties: ['openFile'],
|
properties: ["openFile"],
|
||||||
filters: [{ name: 'JSON', extensions: ['json'] }]
|
filters: [{ name: "JSON", extensions: ["json"] }],
|
||||||
})
|
});
|
||||||
|
|
||||||
if (canceled || !filePaths) return false
|
if (canceled || !filePaths) return false;
|
||||||
|
|
||||||
if(await fileExists(dataPath)) {
|
if (await fileExists(dataPath)) {
|
||||||
await fs.unlink(dataPath)
|
await fs.unlink(dataPath);
|
||||||
}
|
}
|
||||||
await fs.copyFile(filePaths[0], dataPath,fs.constants.COPYFILE_EXCL)
|
await fs.copyFile(filePaths[0], dataPath, fs.constants.COPYFILE_EXCL);
|
||||||
return true
|
return true;
|
||||||
})
|
});
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
////////////////////// BEPINEX ///////////////////////
|
////////////////////// BEPINEX ///////////////////////
|
||||||
@@ -202,157 +197,151 @@ ipcMain.handle('import-data', async () => {
|
|||||||
async function installBepinex() {
|
async function installBepinex() {
|
||||||
if (await fileExists(bepinexBackupPath)) {
|
if (await fileExists(bepinexBackupPath)) {
|
||||||
if (await fileExists(`${bepinexBackupPath}/BepInEx`)) {
|
if (await fileExists(`${bepinexBackupPath}/BepInEx`)) {
|
||||||
await fs.cp(`${bepinexBackupPath}/BepInEx`, bepinexFolderPath, { recursive: true })
|
await fs.cp(`${bepinexBackupPath}/BepInEx`, bepinexFolderPath, {
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const file of bepinexFiles) {
|
for (const file of bepinexFiles) {
|
||||||
const filePath = `${silksongPath}/${file}`
|
const filePath = `${silksongPath}/${file}`;
|
||||||
if (await fileExists(`${bepinexBackupPath}/${file}`)) {
|
if (await fileExists(`${bepinexBackupPath}/${file}`)) {
|
||||||
await fs.copyFile(`${bepinexBackupPath}/${file}`, filePath)
|
await fs.copyFile(`${bepinexBackupPath}/${file}`, filePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await fs.rm(bepinexBackupPath, { recursive: true })
|
await fs.rm(bepinexBackupPath, { recursive: true });
|
||||||
|
|
||||||
bepinexBackupVersion = bepinexStore.get('bepinex-backup-version')
|
bepinexBackupVersion = bepinexStore.get("bepinex-backup-version");
|
||||||
saveBepinexVersion(bepinexBackupVersion)
|
saveBepinexVersion(bepinexBackupVersion);
|
||||||
saveBepinexBackupVersion(undefined)
|
saveBepinexBackupVersion(undefined);
|
||||||
}
|
} else {
|
||||||
else {
|
const GITHUB_URL = "https://api.github.com/repos/bepinex/bepinex/releases/latest";
|
||||||
const GITHUB_URL = "https://api.github.com/repos/bepinex/bepinex/releases/latest"
|
|
||||||
|
|
||||||
const res = await fetch(GITHUB_URL, {
|
const res = await fetch(GITHUB_URL, {
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": "SilkFlyLauncher/1.0.0",
|
"User-Agent": "SilkFlyLauncher/1.0.0",
|
||||||
"Accept": "application/vnd.github+json",
|
Accept: "application/vnd.github+json",
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(`GitHub API error: ${res.status}`)
|
throw new Error(`GitHub API error: ${res.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const release = await res.json();
|
const release = await res.json();
|
||||||
|
|
||||||
const asset = release.assets.find(
|
const asset = release.assets.find((a) => a.name.endsWith(".zip") && a.name.toLowerCase().includes("win_x64"));
|
||||||
a => a.name.endsWith(".zip") && a.name.toLowerCase().includes("win_x64")
|
|
||||||
);
|
|
||||||
|
|
||||||
const download = await fetch(asset.browser_download_url)
|
const download = await fetch(asset.browser_download_url);
|
||||||
if (!download.ok) {
|
if (!download.ok) {
|
||||||
throw new Error("Download error");
|
throw new Error("Download error");
|
||||||
}
|
}
|
||||||
const filePath = `${userSavePath}\\bepinex.zip`
|
const filePath = `${userSavePath}\\bepinex.zip`;
|
||||||
|
|
||||||
await pipeline(
|
await pipeline(download.body, createWriteStream(filePath));
|
||||||
download.body,
|
|
||||||
createWriteStream(filePath)
|
|
||||||
)
|
|
||||||
|
|
||||||
await extract(filePath, { dir: silksongPath})
|
await extract(filePath, { dir: silksongPath });
|
||||||
await fs.unlink(filePath)
|
await fs.unlink(filePath);
|
||||||
|
|
||||||
saveBepinexVersion(release.tag_name)
|
saveBepinexVersion(release.tag_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('install-bepinex', async () => {
|
ipcMain.handle("install-bepinex", async () => {
|
||||||
await installBepinex()
|
await installBepinex();
|
||||||
})
|
});
|
||||||
|
|
||||||
async function uninstallBepinex() {
|
async function uninstallBepinex() {
|
||||||
if (await fileExists(bepinexFolderPath)) {
|
if (await fileExists(bepinexFolderPath)) {
|
||||||
await fs.rm(bepinexFolderPath, { recursive: true })
|
await fs.rm(bepinexFolderPath, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const file of bepinexFiles) {
|
for (const file of bepinexFiles) {
|
||||||
const filePath = `${silksongPath}/${file}`
|
const filePath = `${silksongPath}/${file}`;
|
||||||
if (await fileExists(filePath)) {
|
if (await fileExists(filePath)) {
|
||||||
await fs.unlink(filePath)
|
await fs.unlink(filePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
saveBepinexVersion(undefined)
|
saveBepinexVersion(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('uninstall-bepinex', async () => {
|
ipcMain.handle("uninstall-bepinex", async () => {
|
||||||
await uninstallBepinex()
|
await uninstallBepinex();
|
||||||
})
|
});
|
||||||
|
|
||||||
async function backupBepinex() {
|
async function backupBepinex() {
|
||||||
if (await fileExists(bepinexBackupPath) == false) {
|
if ((await fileExists(bepinexBackupPath)) == false) {
|
||||||
await fs.mkdir(bepinexBackupPath)
|
await fs.mkdir(bepinexBackupPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await fileExists(bepinexFolderPath)) {
|
if (await fileExists(bepinexFolderPath)) {
|
||||||
await fs.cp(bepinexFolderPath, `${bepinexBackupPath}/BepInEx`, { recursive: true })
|
await fs.cp(bepinexFolderPath, `${bepinexBackupPath}/BepInEx`, {
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const file of bepinexFiles) {
|
for (const file of bepinexFiles) {
|
||||||
const filePath = `${silksongPath}/${file}`
|
const filePath = `${silksongPath}/${file}`;
|
||||||
if (await fileExists(filePath)) {
|
if (await fileExists(filePath)) {
|
||||||
await fs.copyFile(filePath, `${bepinexBackupPath}/${file}`)
|
await fs.copyFile(filePath, `${bepinexBackupPath}/${file}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveBepinexBackupVersion(bepinexVersion)
|
saveBepinexBackupVersion(bepinexVersion);
|
||||||
await uninstallBepinex()
|
await uninstallBepinex();
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('backup-bepinex', async () => {
|
ipcMain.handle("backup-bepinex", async () => {
|
||||||
await backupBepinex()
|
await backupBepinex();
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMain.handle('delete-bepinex-backup', async () => {
|
ipcMain.handle("delete-bepinex-backup", async () => {
|
||||||
if (await fileExists(bepinexBackupPath)) {
|
if (await fileExists(bepinexBackupPath)) {
|
||||||
await fs.rm(bepinexBackupPath, { recursive: true })
|
await fs.rm(bepinexBackupPath, { recursive: true });
|
||||||
saveBepinexBackupVersion(undefined)
|
saveBepinexBackupVersion(undefined);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
/////////////////////// NEXUS ////////////////////////
|
/////////////////////// NEXUS ////////////////////////
|
||||||
|
|
||||||
async function createNexus() {
|
async function createNexus() {
|
||||||
if (nexusAPI == undefined) {
|
if (nexusAPI == undefined) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
nexus = await Nexus.create(
|
nexus = await Nexus.create(nexusAPI, "silk-fly-launcher", "1.0.0", "hollowknightsilksong");
|
||||||
nexusAPI,
|
|
||||||
'silk-fly-launcher',
|
|
||||||
'1.0.0',
|
|
||||||
'hollowknightsilksong'
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
nexus = undefined
|
console.log(error);
|
||||||
|
nexus = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('verify-nexus-api', async () => {
|
ipcMain.handle("verify-nexus-api", async () => {
|
||||||
return await verifyNexusAPI()
|
return await verifyNexusAPI();
|
||||||
})
|
});
|
||||||
|
|
||||||
async function verifyNexusAPI() {
|
async function verifyNexusAPI() {
|
||||||
if (nexus == undefined) {
|
if (nexus == undefined) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
if (await nexus.getValidationResult()) {
|
if (await nexus.getValidationResult()) {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('get-latest-mods', async () => {
|
ipcMain.handle("get-latest-mods", async () => {
|
||||||
if (nexus == undefined) {
|
if (nexus == undefined) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mods = await nexus.getLatestAdded()
|
const mods = await nexus.getLatestAdded();
|
||||||
return mods
|
return mods;
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMain.handle('download-mod', async (event, link) => {
|
ipcMain.handle("download-mod", async (event, link) => {
|
||||||
if (nexus == undefined) {
|
if (nexus == undefined) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nexusWindow = new BrowserWindow({
|
const nexusWindow = new BrowserWindow({
|
||||||
@@ -362,46 +351,43 @@ ipcMain.handle('download-mod', async (event, link) => {
|
|||||||
parent: mainWindow,
|
parent: mainWindow,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
contextIsolation: true
|
contextIsolation: true,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
nexusWindow.loadURL(link)
|
nexusWindow.loadURL(link);
|
||||||
})
|
});
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
//////////////////// UNCATEGORIZE ////////////////////
|
//////////////////// UNCATEGORIZE ////////////////////
|
||||||
|
|
||||||
ipcMain.handle('auto-detect-game-path', async () => {
|
ipcMain.handle("auto-detect-game-path", async () => {
|
||||||
const defaultsSilksongPaths = [
|
const defaultsSilksongPaths = [":/Program Files (x86)/Steam/steamapps/common/Hollow Knight Silksong", ":/SteamLibrary/steamapps/common/Hollow Knight Silksong"];
|
||||||
":/Program Files (x86)/Steam/steamapps/common/Hollow Knight Silksong",
|
|
||||||
":/SteamLibrary/steamapps/common/Hollow Knight Silksong"
|
|
||||||
]
|
|
||||||
for (const path of defaultsSilksongPaths) {
|
for (const path of defaultsSilksongPaths) {
|
||||||
for (let i = 'A'.charCodeAt(0); i <= 'Z'.charCodeAt(0); i++) {
|
for (let i = "A".charCodeAt(0); i <= "Z".charCodeAt(0); i++) {
|
||||||
const fullPath = `${String.fromCharCode(i)}${path}`
|
const fullPath = `${String.fromCharCode(i)}${path}`;
|
||||||
if (await fileExists(fullPath)) {
|
if (await fileExists(fullPath)) {
|
||||||
saveSilksongPath(fullPath)
|
saveSilksongPath(fullPath);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMain.handle('load-main-page', () => {
|
ipcMain.handle("load-main-page", () => {
|
||||||
htmlFile = "index.html"
|
htmlFile = "index.html";
|
||||||
mainWindow.loadFile(`renderer/${htmlFile}`)
|
mainWindow.loadFile(`renderer/${htmlFile}`);
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMain.handle('get-page', () => {
|
ipcMain.handle("get-page", () => {
|
||||||
return htmlFile
|
return htmlFile;
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMain.handle('open-link', async (event, link) => {
|
ipcMain.handle("open-link", async (event, link) => {
|
||||||
await shell.openExternal(link)
|
await shell.openExternal(link);
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMain.handle('open-window', async (event, file) => {
|
ipcMain.handle("open-window", async (event, file) => {
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
width: 600,
|
width: 600,
|
||||||
height: 720,
|
height: 720,
|
||||||
@@ -409,32 +395,30 @@ ipcMain.handle('open-window', async (event, file) => {
|
|||||||
parent: mainWindow,
|
parent: mainWindow,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
contextIsolation: true
|
contextIsolation: true,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
win.title = file
|
win.title = file;
|
||||||
win.loadFile(file)
|
win.loadFile(file);
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMain.handle('launch-game', async (event, mode) => {
|
ipcMain.handle("launch-game", async (event, mode) => {
|
||||||
const silksongExecutablePath = `${silksongPath}/Hollow Knight Silksong.exe`
|
const silksongExecutablePath = `${silksongPath}/Hollow Knight Silksong.exe`;
|
||||||
if (mode === "modded"){
|
if (mode === "modded") {
|
||||||
if (await fileExists(bepinexFolderPath)) {
|
if (await fileExists(bepinexFolderPath)) {
|
||||||
await shell.openExternal(silksongExecutablePath)
|
await shell.openExternal(silksongExecutablePath);
|
||||||
}
|
} else {
|
||||||
else {
|
await installBepinex();
|
||||||
await installBepinex()
|
await shell.openExternal(silksongExecutablePath);
|
||||||
await shell.openExternal(silksongExecutablePath)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mode === "vanilla"){
|
if (mode === "vanilla") {
|
||||||
if (await fileExists(bepinexFolderPath)) {
|
if (await fileExists(bepinexFolderPath)) {
|
||||||
await backupBepinex()
|
await backupBepinex();
|
||||||
await shell.openExternal(silksongExecutablePath)
|
await shell.openExternal(silksongExecutablePath);
|
||||||
}
|
} else {
|
||||||
else {
|
await shell.openExternal(silksongExecutablePath);
|
||||||
await shell.openExternal(silksongExecutablePath)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|||||||
37
package.json
37
package.json
@@ -1,20 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "silkflylauncher",
|
"name": "silkflylauncher",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "A launcher and manager for silksong bepinex mods written in javascript",
|
"description": "A launcher and manager for silksong bepinex mods written in javascript",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"type": "module",
|
||||||
"start": "electron .",
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"start": "electron .",
|
||||||
},
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
"author": "GabiZar",
|
},
|
||||||
"license": "SEE LICENSE IN LICENSE",
|
"author": "GabiZar",
|
||||||
"devDependencies": {
|
"license": "GPL-3.0",
|
||||||
"electron": "^39.2.7"
|
"devDependencies": {
|
||||||
},
|
"electron": "^39.2.7"
|
||||||
"dependencies": {
|
},
|
||||||
"@nexusmods/nexus-api": "^1.1.5",
|
"dependencies": {
|
||||||
"electron-store": "^11.0.2",
|
"@nexusmods/nexus-api": "^1.1.5",
|
||||||
"extract-zip": "^2.0.1"
|
"electron-store": "^11.0.2",
|
||||||
}
|
"extract-zip": "^2.0.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
68
preload.js
68
preload.js
@@ -1,47 +1,47 @@
|
|||||||
const { contextBridge, ipcRenderer } = require('electron')
|
const { contextBridge, ipcRenderer } = require("electron");
|
||||||
|
|
||||||
const VERSION = "1.0.0"
|
const VERSION = "1.0.0";
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('versions', {
|
contextBridge.exposeInMainWorld("versions", {
|
||||||
silkFlyLauncher: () => VERSION,
|
silkFlyLauncher: () => VERSION,
|
||||||
node: () => process.versions.node,
|
node: () => process.versions.node,
|
||||||
chromium: () => process.versions.chrome,
|
chromium: () => process.versions.chrome,
|
||||||
electron: () => process.versions.electron
|
electron: () => process.versions.electron,
|
||||||
});
|
});
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('files', {
|
contextBridge.exposeInMainWorld("files", {
|
||||||
delete: () => ipcRenderer.invoke('delete-data'),
|
delete: () => ipcRenderer.invoke("delete-data"),
|
||||||
export: () => ipcRenderer.invoke('export-data'),
|
export: () => ipcRenderer.invoke("export-data"),
|
||||||
import: () => ipcRenderer.invoke('import-data'),
|
import: () => ipcRenderer.invoke("import-data"),
|
||||||
|
|
||||||
autoDetectGamePath: () => ipcRenderer.invoke('auto-detect-game-path'),
|
autoDetectGamePath: () => ipcRenderer.invoke("auto-detect-game-path"),
|
||||||
saveSilksongPath: (path) => ipcRenderer.invoke('save-path', path),
|
saveSilksongPath: (path) => ipcRenderer.invoke("save-path", path),
|
||||||
loadSilksongPath: () => ipcRenderer.invoke('load-path'),
|
loadSilksongPath: () => ipcRenderer.invoke("load-path"),
|
||||||
loadBepinexVersion: () => ipcRenderer.invoke('load-bepinex-version'),
|
loadBepinexVersion: () => ipcRenderer.invoke("load-bepinex-version"),
|
||||||
loadBepinexBackupVersion: () => ipcRenderer.invoke('load-bepinex-backup-version'),
|
loadBepinexBackupVersion: () => ipcRenderer.invoke("load-bepinex-backup-version"),
|
||||||
saveNexusAPI: (api) => ipcRenderer.invoke('save-nexus-api', api),
|
saveNexusAPI: (api) => ipcRenderer.invoke("save-nexus-api", api),
|
||||||
loadNexusAPI: () => ipcRenderer.invoke('load-nexus-api'),
|
loadNexusAPI: () => ipcRenderer.invoke("load-nexus-api"),
|
||||||
saveTheme: (theme, lacePinState) => ipcRenderer.invoke('save-theme', theme, lacePinState),
|
saveTheme: (theme, lacePinState) => ipcRenderer.invoke("save-theme", theme, lacePinState),
|
||||||
loadTheme: () => ipcRenderer.invoke('load-theme')
|
loadTheme: () => ipcRenderer.invoke("load-theme"),
|
||||||
});
|
});
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electronAPI', {
|
contextBridge.exposeInMainWorld("electronAPI", {
|
||||||
openExternalLink: (url) => ipcRenderer.invoke('open-link', url),
|
openExternalLink: (url) => ipcRenderer.invoke("open-link", url),
|
||||||
openWindow: (file) => ipcRenderer.invoke('open-window', file),
|
openWindow: (file) => ipcRenderer.invoke("open-window", file),
|
||||||
launchGame: (mode) => ipcRenderer.invoke('launch-game', mode),
|
launchGame: (mode) => ipcRenderer.invoke("launch-game", mode),
|
||||||
loadMainPage: () => ipcRenderer.invoke('load-main-page'),
|
loadMainPage: () => ipcRenderer.invoke("load-main-page"),
|
||||||
getPage: () => ipcRenderer.invoke('get-page')
|
getPage: () => ipcRenderer.invoke("get-page"),
|
||||||
});
|
});
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('bepinex', {
|
contextBridge.exposeInMainWorld("bepinex", {
|
||||||
install: () => ipcRenderer.invoke('install-bepinex'),
|
install: () => ipcRenderer.invoke("install-bepinex"),
|
||||||
uninstall: () => ipcRenderer.invoke('uninstall-bepinex'),
|
uninstall: () => ipcRenderer.invoke("uninstall-bepinex"),
|
||||||
backup: () => ipcRenderer.invoke('backup-bepinex'),
|
backup: () => ipcRenderer.invoke("backup-bepinex"),
|
||||||
deleteBackup: () => ipcRenderer.invoke('delete-bepinex-backup')
|
deleteBackup: () => ipcRenderer.invoke("delete-bepinex-backup"),
|
||||||
})
|
});
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('nexus', {
|
contextBridge.exposeInMainWorld("nexus", {
|
||||||
verifyAPI: () => ipcRenderer.invoke('verify-nexus-api'),
|
verifyAPI: () => ipcRenderer.invoke("verify-nexus-api"),
|
||||||
getLatestMods: () => ipcRenderer.invoke('get-latest-mods'),
|
getLatestMods: () => ipcRenderer.invoke("get-latest-mods"),
|
||||||
download: (link) => ipcRenderer.invoke('download-mod', link)
|
download: (link) => ipcRenderer.invoke("download-mod", link),
|
||||||
})
|
});
|
||||||
|
|||||||
1
renderer/assets/github.svg
Normal file
1
renderer/assets/github.svg
Normal 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 |
@@ -1,195 +1,197 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>Silk Fly Launcher</title>
|
<title>Silk Fly Launcher</title>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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">
|
<!-- Sidebar -->
|
||||||
|
<aside class="sidebar">
|
||||||
<video autoplay muted loop class="background-video" id="background-video" src="assets/background/Silksong.mp4" type="video/mp4"></video>
|
<div class="logo" onclick="navigate('home')">
|
||||||
|
<img src="assets/logo.png" alt="Silk Fly Launcher Logo" class="logo-img" />
|
||||||
<!-- Sidebar -->
|
<h5 class="logo-title">Silk Fly Launcher</h5>
|
||||||
<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
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-section">
|
<nav class="nav">
|
||||||
<span class="nav-title">Mods</span>
|
<div class="nav-section">
|
||||||
<button onclick="navigate('mods-installed')">
|
<span class="nav-title">Execute Silksong</span>
|
||||||
<img src="installed_mods_icon.png" class="button-icon"/>
|
<button onclick="launch('vanilla')">
|
||||||
Installed
|
<img src="vanilla_launch_icon.png" class="button-icon" />
|
||||||
<button onclick="navigate('mods-online')">
|
Run Vanilla
|
||||||
<img src="online_mods_icon.png" class="button-icon"/>
|
</button>
|
||||||
Online
|
<button onclick="launch('modded')">
|
||||||
</div>
|
<img src="modded_launch_icon.png" class="button-icon" />
|
||||||
|
Run Modded
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="nav-section">
|
<div class="nav-section">
|
||||||
<span class="nav-title">Settings</span>
|
<span class="nav-title">Mods</span>
|
||||||
<button onclick="navigate('general-settings')">
|
<button onclick="navigate('mods-installed')">
|
||||||
<img src="general_settings_icon.png" class="button-icon"/>
|
<img src="installed_mods_icon.png" class="button-icon" />
|
||||||
General
|
Installed
|
||||||
</div>
|
</button>
|
||||||
</nav>
|
<button onclick="navigate('mods-online')">
|
||||||
</aside>
|
<img src="online_mods_icon.png" class="button-icon" />
|
||||||
|
Online
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Main content -->
|
<div class="nav-section">
|
||||||
<main class="content">
|
<span class="nav-title">Settings</span>
|
||||||
<h1 id="title">Silk Fly Launcher</h1>
|
<button onclick="navigate('general-settings')">
|
||||||
<div class="view" id="view">
|
<img src="general_settings_icon.png" class="button-icon" />
|
||||||
</div>
|
General
|
||||||
</main>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
|
||||||
<!-- Template -->
|
<!-- Main content -->
|
||||||
<template id="home-template">
|
<main class="content">
|
||||||
<h2>About</h2>
|
<h1 id="title">Silk Fly Launcher</h1>
|
||||||
<div class="horizontal-div separated-div">
|
<div class="view" id="view"></div>
|
||||||
<div class="horizontal-div">
|
</main>
|
||||||
<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>
|
|
||||||
</div>
|
</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">
|
<div class="horizontal-div">
|
||||||
<a href="www.nexusmods.com/hollowknightsilksong/mods" class="default-button" id="download-mod-button">Download</a>
|
<img src="assets/logo.png" alt="Silk Fly Launcher Logo" class="big-logo-img" />
|
||||||
<a href="www.nexusmods.com/hollowknightsilksong/mods" class="default-button" id="external-link">Website</a>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
<br />
|
||||||
<img class="mod-icon" src="assets/placeholder_icon.png" alt="mod icon" id="mod-icon">
|
<ul>
|
||||||
</div>
|
<li>Silk Fly Launcher is a launcher and mod manager for Silksong mods from Nexus, built with Electron.</li>
|
||||||
</template>
|
<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>
|
||||||
<template id="settings-template">
|
<li>
|
||||||
<h2>General settings</h2>
|
Found a bug or have a feature request? Please
|
||||||
<div class="horizontal-div">
|
<a href="" class="link" onclick="electronAPI.openExternalLink('https://github.com/Gabi-Zar/Silk-Fly-Launcher/issues')">create an issue on GitHub</a>.
|
||||||
<label>Enter Silksong path: </label>
|
</li>
|
||||||
<input type="text" class="input" id="silksong-path-input" name="silksong-path-input">
|
<li>Made with ♥ by <a href="" class="link" onclick="electronAPI.openExternalLink('https://github.com/Gabi-Zar')">GabiZar</a>.</li>
|
||||||
<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>
|
</ul>
|
||||||
<p id="version-text"></p>
|
<br />
|
||||||
</div>
|
</template>
|
||||||
</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>
|
<template id="online-mods-template">
|
||||||
</html>
|
<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>
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ const onlineModsTemplate = document.getElementById("online-mods-template");
|
|||||||
const settingsTemplate = document.getElementById("settings-template");
|
const settingsTemplate = document.getElementById("settings-template");
|
||||||
const modTemplate = document.getElementById("mod-template");
|
const modTemplate = document.getElementById("mod-template");
|
||||||
|
|
||||||
let oldPage
|
let oldPage;
|
||||||
let actualTheme = []
|
let actualTheme = [];
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
///////////////// CONST FOR WELCOME //////////////////
|
///////////////// CONST FOR WELCOME //////////////////
|
||||||
|
|
||||||
let actualPage = 0
|
let actualPage = 0;
|
||||||
|
|
||||||
const pageDiv = document.getElementById("page");
|
const pageDiv = document.getElementById("page");
|
||||||
const buttonDiv = document.getElementById("button-div");
|
const buttonDiv = document.getElementById("button-div");
|
||||||
@@ -31,16 +31,15 @@ const tutorialTemplate = document.getElementById("tutorial-template");
|
|||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
////////////////////// STARTUP ///////////////////////
|
////////////////////// STARTUP ///////////////////////
|
||||||
|
|
||||||
on_startup()
|
on_startup();
|
||||||
|
|
||||||
async function on_startup() {
|
async function on_startup() {
|
||||||
if (await electronAPI.getPage() == "index.html") {
|
if ((await electronAPI.getPage()) == "index.html") {
|
||||||
const theme = await files.loadTheme()
|
const theme = await files.loadTheme();
|
||||||
changeTheme(theme[0], theme[1])
|
changeTheme(theme[0], theme[1]);
|
||||||
navigate("home")
|
navigate("home");
|
||||||
}
|
} else if ((await electronAPI.getPage()) == "welcome.html") {
|
||||||
else if (await electronAPI.getPage() == "welcome.html") {
|
welcomeNavigate();
|
||||||
welcomeNavigate()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,223 +48,220 @@ async function on_startup() {
|
|||||||
|
|
||||||
async function navigate(page) {
|
async function navigate(page) {
|
||||||
if (oldPage == page) {
|
if (oldPage == page) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
oldPage = page
|
oldPage = page;
|
||||||
|
|
||||||
view.replaceChildren()
|
view.replaceChildren();
|
||||||
switch (page) {
|
switch (page) {
|
||||||
case "home":
|
case "home":
|
||||||
title.innerText = "Silk Fly Launcher";
|
title.innerText = "Silk Fly Launcher";
|
||||||
const HomeTemplateCopy = HomeTemplate.content.cloneNode(true)
|
const HomeTemplateCopy = HomeTemplate.content.cloneNode(true);
|
||||||
view.appendChild(HomeTemplateCopy)
|
view.appendChild(HomeTemplateCopy);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "mods-installed":
|
case "mods-installed":
|
||||||
title.innerText = "Installed Mods";
|
title.innerText = "Installed Mods";
|
||||||
const installedModsTemplateCopy = installedModsTemplate.content.cloneNode(true)
|
const installedModsTemplateCopy = installedModsTemplate.content.cloneNode(true);
|
||||||
const searchFormInstalled = installedModsTemplateCopy.getElementById("search-form")
|
const searchFormInstalled = installedModsTemplateCopy.getElementById("search-form");
|
||||||
|
|
||||||
searchFormInstalled.addEventListener('submit', async function(event) {
|
|
||||||
event.preventDefault()
|
|
||||||
})
|
|
||||||
|
|
||||||
view.appendChild(installedModsTemplateCopy)
|
searchFormInstalled.addEventListener("submit", async function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
view.appendChild(installedModsTemplateCopy);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "mods-online":
|
case "mods-online":
|
||||||
title.innerText = "Online Mods";
|
title.innerText = "Online Mods";
|
||||||
const onlineModsTemplateCopy = onlineModsTemplate.content.cloneNode(true)
|
const onlineModsTemplateCopy = onlineModsTemplate.content.cloneNode(true);
|
||||||
const ModsContainer = onlineModsTemplateCopy.getElementById("mods-container")
|
const ModsContainer = onlineModsTemplateCopy.getElementById("mods-container");
|
||||||
const searchFormNexus = onlineModsTemplateCopy.getElementById("search-form")
|
const searchFormNexus = onlineModsTemplateCopy.getElementById("search-form");
|
||||||
|
|
||||||
searchFormNexus.addEventListener('submit', async function(event) {
|
|
||||||
event.preventDefault()
|
|
||||||
})
|
|
||||||
|
|
||||||
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) {
|
if (mods == undefined) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for(const mod of mods) {
|
for (const mod of mods) {
|
||||||
if (mod.name == undefined) {
|
if (mod.name == undefined) {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
const modTemplateCopy = modTemplate.content.cloneNode(true)
|
const modTemplateCopy = modTemplate.content.cloneNode(true);
|
||||||
if (mod.name) {
|
if (mod.name) {
|
||||||
const modTitleText = modTemplateCopy.getElementById("mod-title")
|
const modTitleText = modTemplateCopy.getElementById("mod-title");
|
||||||
modTitleText.innerText = mod.name
|
modTitleText.innerText = mod.name;
|
||||||
}
|
}
|
||||||
if (mod.author) {
|
if (mod.author) {
|
||||||
const modAuthorText = modTemplateCopy.getElementById("mod-author")
|
const modAuthorText = modTemplateCopy.getElementById("mod-author");
|
||||||
modAuthorText.innerText = `by ${mod.author}`
|
modAuthorText.innerText = `by ${mod.author}`;
|
||||||
}
|
}
|
||||||
if (mod.endorsement_count) {
|
if (mod.endorsement_count) {
|
||||||
const modEndorsementsNumber = modTemplateCopy.getElementById("mod-endorsements-number")
|
const modEndorsementsNumber = modTemplateCopy.getElementById("mod-endorsements-number");
|
||||||
if (mod.endorsement_count > 1) {
|
if (mod.endorsement_count > 1) {
|
||||||
modEndorsementsNumber.innerText = `${mod.endorsement_count} likes`
|
modEndorsementsNumber.innerText = `${mod.endorsement_count} likes`;
|
||||||
}
|
} else {
|
||||||
else {
|
modEndorsementsNumber.innerText = `${mod.endorsement_count} like`;
|
||||||
modEndorsementsNumber.innerText = `${mod.endorsement_count} like`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mod.summary) {
|
if (mod.summary) {
|
||||||
const modDescriptionText = modTemplateCopy.getElementById("mod-description")
|
const modDescriptionText = modTemplateCopy.getElementById("mod-description");
|
||||||
modDescriptionText.innerText = mod.summary
|
modDescriptionText.innerText = mod.summary;
|
||||||
}
|
}
|
||||||
if (mod.picture_url) {
|
if (mod.picture_url) {
|
||||||
const modPicture = modTemplateCopy.getElementById("mod-icon")
|
const modPicture = modTemplateCopy.getElementById("mod-icon");
|
||||||
modPicture.src = mod.picture_url
|
modPicture.src = mod.picture_url;
|
||||||
}
|
}
|
||||||
if (mod.version && mod.updated_timestamp) {
|
if (mod.version && mod.updated_timestamp) {
|
||||||
const modVersionText = modTemplateCopy.getElementById("mod-version")
|
const modVersionText = modTemplateCopy.getElementById("mod-version");
|
||||||
modVersionText.innerText = `V${mod.version} last updated on ${mod.updated_time.slice(0, 10)}`
|
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")
|
const modLinkButton = modTemplateCopy.getElementById("external-link");
|
||||||
modLinkButton.href = modUrl
|
modLinkButton.href = modUrl;
|
||||||
modLinkButton.addEventListener('click', function(event) {
|
modLinkButton.addEventListener("click", function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
const modLink = modLinkButton.href
|
const modLink = modLinkButton.href;
|
||||||
electronAPI.openExternalLink(modLink)
|
electronAPI.openExternalLink(modLink);
|
||||||
})
|
});
|
||||||
|
|
||||||
modDownloadButton = modTemplateCopy.getElementById("download-mod-button")
|
modDownloadButton = modTemplateCopy.getElementById("download-mod-button");
|
||||||
modDownloadButton.addEventListener('click', function(event) {
|
modDownloadButton.addEventListener("click", function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
const modDownloadLink = `${modUrl}?tab=files`
|
const modDownloadLink = `${modUrl}?tab=files`;
|
||||||
nexus.download(modDownloadLink)
|
nexus.download(modDownloadLink);
|
||||||
})
|
});
|
||||||
|
|
||||||
ModsContainer.appendChild(modTemplateCopy)
|
ModsContainer.appendChild(modTemplateCopy);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "general-settings":
|
case "general-settings":
|
||||||
title.innerText = "Settings";
|
title.innerText = "Settings";
|
||||||
const settingsTemplateCopy = settingsTemplate.content.cloneNode(true)
|
const settingsTemplateCopy = settingsTemplate.content.cloneNode(true);
|
||||||
const silksongPathInput = settingsTemplateCopy.getElementById("silksong-path-input")
|
const silksongPathInput = settingsTemplateCopy.getElementById("silksong-path-input");
|
||||||
const nexusAPIInput = settingsTemplateCopy.getElementById("nexus-api-input")
|
const nexusAPIInput = settingsTemplateCopy.getElementById("nexus-api-input");
|
||||||
const versionsList = settingsTemplateCopy.getElementById("versions-list")
|
const versionsList = settingsTemplateCopy.getElementById("versions-list");
|
||||||
const versionsDictionnary = {
|
const versionsDictionnary = {
|
||||||
"Silk-Fly-Launcher": `Silk Fly Launcher: v${versions.silkFlyLauncher()}`,
|
"Silk-Fly-Launcher": `Silk Fly Launcher: v${versions.silkFlyLauncher()}`,
|
||||||
"Electron": `Electron: v${versions.electron()}`,
|
Electron: `Electron: v${versions.electron()}`,
|
||||||
"Node": `Node.js: v${versions.node()}`,
|
Node: `Node.js: v${versions.node()}`,
|
||||||
"Chromium": `Chromium: v${versions.chromium()}`,
|
Chromium: `Chromium: v${versions.chromium()}`,
|
||||||
}
|
};
|
||||||
const lacePinCheckbox = settingsTemplateCopy.getElementById('lace-pin');
|
const lacePinCheckbox = settingsTemplateCopy.getElementById("lace-pin");
|
||||||
|
|
||||||
silksongPathInput.value = await files.loadSilksongPath()
|
silksongPathInput.value = await files.loadSilksongPath();
|
||||||
silksongPathInput.addEventListener('input', async function(event) {
|
silksongPathInput.addEventListener("input", async function (event) {
|
||||||
let silksongPath = silksongPathInput.value
|
let silksongPath = silksongPathInput.value;
|
||||||
files.saveSilksongPath(silksongPath)
|
files.saveSilksongPath(silksongPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
nexusAPIInput.value = await files.loadNexusAPI()
|
nexusAPIInput.value = await files.loadNexusAPI();
|
||||||
nexusAPIInput.addEventListener('input', async function(event) {
|
nexusAPIInput.addEventListener("input", async function (event) {
|
||||||
let nexusAPI = nexusAPIInput.value
|
let nexusAPI = nexusAPIInput.value;
|
||||||
files.saveNexusAPI(nexusAPI)
|
files.saveNexusAPI(nexusAPI);
|
||||||
});
|
});
|
||||||
|
|
||||||
for(const element of versionsList.children) {
|
for (const element of versionsList.children) {
|
||||||
element.innerText = versionsDictionnary[element.id]
|
element.innerText = versionsDictionnary[element.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
const theme = await files.loadTheme()
|
const theme = await files.loadTheme();
|
||||||
lacePinCheckbox.checked = theme[1]
|
lacePinCheckbox.checked = theme[1];
|
||||||
|
|
||||||
lacePinCheckbox.addEventListener('change', async function() {
|
lacePinCheckbox.addEventListener("change", async function () {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
const theme = await files.loadTheme();
|
const theme = await files.loadTheme();
|
||||||
changeTheme(theme[0], true);
|
changeTheme(theme[0], true);
|
||||||
toggleThemesMenu()
|
toggleThemesMenu();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
const theme = await files.loadTheme();
|
const theme = await files.loadTheme();
|
||||||
changeTheme(theme[0], false);
|
changeTheme(theme[0], false);
|
||||||
toggleThemesMenu()
|
toggleThemesMenu();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
view.appendChild(settingsTemplateCopy)
|
view.appendChild(settingsTemplateCopy);
|
||||||
setBepinexVersion()
|
setBepinexVersion();
|
||||||
setThemeButton()
|
setThemeButton();
|
||||||
verifyNexusAPI()
|
verifyNexusAPI();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function welcomeNavigate() {
|
async function welcomeNavigate() {
|
||||||
pageDiv.replaceChildren()
|
pageDiv.replaceChildren();
|
||||||
switch (actualPage) {
|
switch (actualPage) {
|
||||||
case 0:
|
case 0:
|
||||||
pageDiv.appendChild(welcomeTemplate.content.cloneNode(true))
|
pageDiv.appendChild(welcomeTemplate.content.cloneNode(true));
|
||||||
buttonDiv.replaceChildren()
|
buttonDiv.replaceChildren();
|
||||||
buttonDiv.appendChild(oneButtonTemplate.content.cloneNode(true))
|
buttonDiv.appendChild(oneButtonTemplate.content.cloneNode(true));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
pageDiv.appendChild(silksongPathTemplate.content.cloneNode(true))
|
pageDiv.appendChild(silksongPathTemplate.content.cloneNode(true));
|
||||||
buttonDiv.replaceChildren()
|
buttonDiv.replaceChildren();
|
||||||
buttonDiv.appendChild(twoButtonTemplate.content.cloneNode(true))
|
buttonDiv.appendChild(twoButtonTemplate.content.cloneNode(true));
|
||||||
|
|
||||||
const silksongPathInput = document.getElementById("silksong-path-input")
|
const silksongPathInput = document.getElementById("silksong-path-input");
|
||||||
if (await files.loadSilksongPath() == "") {
|
if ((await files.loadSilksongPath()) == "") {
|
||||||
autoDetectGamePath()
|
autoDetectGamePath();
|
||||||
}
|
} else {
|
||||||
else {
|
document.getElementById("silksong-path-input").value = await files.loadSilksongPath();
|
||||||
document.getElementById("silksong-path-input").value = await files.loadSilksongPath()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
silksongPathInput.addEventListener('input', async function(event) {
|
silksongPathInput.addEventListener("input", async function (event) {
|
||||||
let silksongPath = silksongPathInput.value
|
let silksongPath = silksongPathInput.value;
|
||||||
await files.saveSilksongPath(silksongPath)
|
await files.saveSilksongPath(silksongPath);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
pageDiv.appendChild(nexusTemplate.content.cloneNode(true))
|
pageDiv.appendChild(nexusTemplate.content.cloneNode(true));
|
||||||
const nexusLink = document.getElementById("external-link")
|
const nexusLink = document.getElementById("external-link");
|
||||||
nexusLink.addEventListener('click', function(event) {
|
nexusLink.addEventListener("click", function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
const url = nexusLink.href
|
const url = nexusLink.href;
|
||||||
electronAPI.openExternalLink(url)
|
electronAPI.openExternalLink(url);
|
||||||
})
|
});
|
||||||
|
|
||||||
const nexusAPIInput = document.getElementById("nexus-api-input")
|
const nexusAPIInput = document.getElementById("nexus-api-input");
|
||||||
nexusAPIInput.value = await files.loadNexusAPI()
|
nexusAPIInput.value = await files.loadNexusAPI();
|
||||||
nexusAPIInput.addEventListener('input', async function(event) {
|
nexusAPIInput.addEventListener("input", async function (event) {
|
||||||
let nexusAPI = nexusAPIInput.value
|
let nexusAPI = nexusAPIInput.value;
|
||||||
await files.saveNexusAPI(nexusAPI)
|
await files.saveNexusAPI(nexusAPI);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
pageDiv.appendChild(styleTemplate.content.cloneNode(true))
|
pageDiv.appendChild(styleTemplate.content.cloneNode(true));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
pageDiv.appendChild(tutorialTemplate.content.cloneNode(true))
|
pageDiv.appendChild(tutorialTemplate.content.cloneNode(true));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
electronAPI.loadMainPage()
|
electronAPI.loadMainPage();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function next() {
|
function next() {
|
||||||
actualPage++
|
actualPage++;
|
||||||
welcomeNavigate()
|
welcomeNavigate();
|
||||||
}
|
}
|
||||||
|
|
||||||
function back() {
|
function back() {
|
||||||
actualPage--
|
actualPage--;
|
||||||
welcomeNavigate()
|
welcomeNavigate();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
@@ -273,149 +269,145 @@ function back() {
|
|||||||
|
|
||||||
async function initialImportData() {
|
async function initialImportData() {
|
||||||
if (await files.import()) {
|
if (await files.import()) {
|
||||||
electronAPI.loadMainPage()
|
electronAPI.loadMainPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function importData() {
|
async function importData() {
|
||||||
await files.import()
|
await files.import();
|
||||||
document.getElementById("silksong-path-input").value = await files.loadSilksongPath()
|
document.getElementById("silksong-path-input").value = await files.loadSilksongPath();
|
||||||
document.getElementById("nexus-api-input").value = await files.loadNexusAPI()
|
document.getElementById("nexus-api-input").value = await files.loadNexusAPI();
|
||||||
const lacePinCheckbox = document.getElementById('lace-pin')
|
const lacePinCheckbox = document.getElementById("lace-pin");
|
||||||
const theme = await files.loadTheme()
|
const theme = await files.loadTheme();
|
||||||
lacePinCheckbox.checked = theme[1]
|
lacePinCheckbox.checked = theme[1];
|
||||||
changeTheme(theme[0])
|
changeTheme(theme[0]);
|
||||||
toggleThemesMenu()
|
toggleThemesMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function exportData() {
|
async function exportData() {
|
||||||
await files.export()
|
await files.export();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteData() {
|
async function deleteData() {
|
||||||
const lacePinCheckbox = document.getElementById('lace-pin')
|
const lacePinCheckbox = document.getElementById("lace-pin");
|
||||||
lacePinCheckbox.checked = false
|
lacePinCheckbox.checked = false;
|
||||||
changeTheme("Silksong")
|
changeTheme("Silksong");
|
||||||
toggleThemesMenu()
|
toggleThemesMenu();
|
||||||
await files.delete()
|
await files.delete();
|
||||||
document.getElementById("silksong-path-input").value = await files.loadSilksongPath()
|
document.getElementById("silksong-path-input").value = await files.loadSilksongPath();
|
||||||
document.getElementById("nexus-api-input").value = await files.loadNexusAPI()
|
document.getElementById("nexus-api-input").value = await files.loadNexusAPI();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
////////////////////// BEPINEX ///////////////////////
|
////////////////////// BEPINEX ///////////////////////
|
||||||
|
|
||||||
async function installBepinex() {
|
async function installBepinex() {
|
||||||
await bepinex.install()
|
await bepinex.install();
|
||||||
setBepinexVersion()
|
setBepinexVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uninstallBepinex() {
|
async function uninstallBepinex() {
|
||||||
await bepinex.uninstall()
|
await bepinex.uninstall();
|
||||||
setBepinexVersion()
|
setBepinexVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function backupBepinex() {
|
async function backupBepinex() {
|
||||||
await bepinex.backup()
|
await bepinex.backup();
|
||||||
setBepinexVersion()
|
setBepinexVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteBepinexBackup() {
|
async function deleteBepinexBackup() {
|
||||||
await bepinex.deleteBackup()
|
await bepinex.deleteBackup();
|
||||||
setBepinexVersion()
|
setBepinexVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setBepinexVersion() {
|
async function setBepinexVersion() {
|
||||||
const bepinexVersionText = document.getElementById("bepinex-version-text")
|
const bepinexVersionText = document.getElementById("bepinex-version-text");
|
||||||
if (bepinexVersionText == undefined) {
|
if (bepinexVersionText == undefined) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bepinexVersion = await files.loadBepinexVersion()
|
const bepinexVersion = await files.loadBepinexVersion();
|
||||||
const bepinexBackupVersion = await files.loadBepinexBackupVersion()
|
const bepinexBackupVersion = await files.loadBepinexBackupVersion();
|
||||||
if(bepinexVersion == undefined) {
|
if (bepinexVersion == undefined) {
|
||||||
if(bepinexBackupVersion == undefined) {
|
if (bepinexBackupVersion == undefined) {
|
||||||
bepinexVersionText.innerText = "BepInEx is not installed"
|
bepinexVersionText.innerText = "BepInEx is not installed";
|
||||||
|
} else {
|
||||||
|
bepinexVersionText.innerText = `BepInEx ${bepinexBackupVersion} is backed up`;
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
bepinexVersionText.innerText = `BepInEx ${bepinexBackupVersion} is backed up`
|
bepinexVersionText.innerText = `BepInEx ${bepinexVersion} is installed`;
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bepinexVersionText.innerText = `BepInEx ${bepinexVersion} is installed`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function searchInstalledMods() {
|
async function searchInstalledMods() {
|
||||||
const searchInput = document.getElementById("search-input")
|
const searchInput = document.getElementById("search-input");
|
||||||
console.log(searchInput.value)
|
console.log(searchInput.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
/////////////////////// NEXUS ////////////////////////
|
/////////////////////// NEXUS ////////////////////////
|
||||||
|
|
||||||
async function verifyNexusAPI() {
|
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) {
|
if (nexusCheckImage == undefined) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response) {
|
if (response) {
|
||||||
nexusCheckImage.src = "assets/check.svg"
|
nexusCheckImage.src = "assets/check.svg";
|
||||||
}
|
} else {
|
||||||
else {
|
nexusCheckImage.src = "assets/cross.svg";
|
||||||
nexusCheckImage.src = "assets/cross.svg"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function searchNexusMods() {
|
async function searchNexusMods() {
|
||||||
const searchInput = document.getElementById("search-input")
|
const searchInput = document.getElementById("search-input");
|
||||||
console.log(searchInput.value)
|
console.log(searchInput.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
/////////////////////// THEMES ///////////////////////
|
/////////////////////// THEMES ///////////////////////
|
||||||
|
|
||||||
function toggleThemesMenu() {
|
function toggleThemesMenu() {
|
||||||
const themesMenu = document.getElementById("themes-menu")
|
const themesMenu = document.getElementById("themes-menu");
|
||||||
if (themesMenu) {
|
if (themesMenu) {
|
||||||
themesMenu.classList.toggle("show")
|
themesMenu.classList.toggle("show");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setThemeButton() {
|
async function setThemeButton() {
|
||||||
const themesButton = document.getElementById("themes-button")
|
const themesButton = document.getElementById("themes-button");
|
||||||
if (themesButton) {
|
if (themesButton) {
|
||||||
const theme = await files.loadTheme()
|
const theme = await files.loadTheme();
|
||||||
themesButton.textContent = theme[0]
|
themesButton.textContent = theme[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeTheme(theme, state) {
|
function changeTheme(theme, state) {
|
||||||
toggleThemesMenu()
|
toggleThemesMenu();
|
||||||
|
|
||||||
const lacePinCheckbox = document.getElementById('lace-pin');
|
const lacePinCheckbox = document.getElementById("lace-pin");
|
||||||
if (lacePinCheckbox) {
|
if (lacePinCheckbox) {
|
||||||
lacePinState = lacePinCheckbox.checked;
|
lacePinState = lacePinCheckbox.checked;
|
||||||
}
|
} else if (state) {
|
||||||
else if (state) {
|
lacePinState = state;
|
||||||
lacePinState = state
|
} else {
|
||||||
}
|
lacePinState = false;
|
||||||
else {
|
|
||||||
lacePinState = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actualTheme[0] == theme && actualTheme[1] == lacePinState) {
|
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 = {
|
const themesColors = {
|
||||||
"var": ["--primary-color", "--secondary-color", "--background-color"],
|
"var": ["--primary-color", "--secondary-color", "--background-color"],
|
||||||
"Silksong": ["rgba(255, 25, 0, 0.3)", "#ff6b6b", "rgba(255, 72, 0, 0.2)"],
|
"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)"],
|
"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)"]
|
"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")
|
const backgroundVideo = document.getElementById("background-video");
|
||||||
let backgroundVideoPath = `assets/background/${theme}.mp4`
|
let backgroundVideoPath = `assets/background/${theme}.mp4`;
|
||||||
if (lacePinState) {
|
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) {
|
async function launch(mode) {
|
||||||
await electronAPI.launchGame(mode);
|
await electronAPI.launchGame(mode);
|
||||||
setBepinexVersion()
|
setBepinexVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function autoDetectGamePath() {
|
async function autoDetectGamePath() {
|
||||||
await files.autoDetectGamePath()
|
await files.autoDetectGamePath();
|
||||||
if (document.getElementById("silksong-path-input")) {
|
if (document.getElementById("silksong-path-input")) {
|
||||||
document.getElementById("silksong-path-input").value = await files.loadSilksongPath()
|
document.getElementById("silksong-path-input").value = await files.loadSilksongPath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
font-family: "Segoe UI", sans-serif;
|
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 {
|
:root {
|
||||||
@@ -13,7 +15,7 @@
|
|||||||
--text-color: #eee;
|
--text-color: #eee;
|
||||||
--transparent-black: rgba(0, 0, 0, 0.4);
|
--transparent-black: rgba(0, 0, 0, 0.4);
|
||||||
--darker-transparent-black: rgba(0, 0, 0, 0.8);
|
--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 {
|
body {
|
||||||
@@ -69,6 +71,10 @@ body {
|
|||||||
height: 100px;
|
height: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.invert-color {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
@@ -86,7 +92,7 @@ body {
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
padding: 0 4px 4px;
|
padding: 0 4px 4px;
|
||||||
border-bottom: 1px solid var(--secondary-color);
|
border-bottom: 1px solid var(--secondary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav button {
|
.nav button {
|
||||||
@@ -124,7 +130,7 @@ body {
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
padding: 0 4px 4px;
|
padding: 0 4px 4px;
|
||||||
border-bottom: 1px solid var(--secondary-color);
|
border-bottom: 1px solid var(--secondary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.view {
|
.view {
|
||||||
@@ -135,7 +141,7 @@ body {
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
box-shadow: 0 0 50px var(--darker-transparent-black);
|
box-shadow: 0 0 50px var(--darker-transparent-black);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
height: 90%;
|
height: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.horizontal-div {
|
.horizontal-div {
|
||||||
@@ -371,4 +377,4 @@ body {
|
|||||||
border: solid var(--text-color);
|
border: solid var(--text-color);
|
||||||
border-width: 0 2px 2px 0;
|
border-width: 0 2px 2px 0;
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,84 +1,87 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<title>Welcome to Silk Fly Launcher</title>
|
<title>Welcome to Silk Fly Launcher</title>
|
||||||
<link rel="stylesheet" href="welcome.css" />
|
<link rel="stylesheet" href="welcome.css" />
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="app">
|
<div class="app">
|
||||||
<video autoplay muted loop class="background-video" id="background-video" src="assets/background/Silksong.mp4" type="video/mp4"></video>
|
<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">
|
<div class="welcome-div" id="main-div">
|
||||||
<br>
|
<br />
|
||||||
<div id="page"></div>
|
<div id="page"></div>
|
||||||
<div class="button-div" id="button-div"></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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
|
||||||
|
|
||||||
<template id="tutorial-template">
|
<template id="welcome-template">
|
||||||
<h1 class="title">Tutorial to download mod from nexus</h1>
|
<h1 class="title">Welcome to Silk Fly Launcher</h1>
|
||||||
</template>
|
<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>
|
<template id="one-button-template">
|
||||||
</body>
|
<button class="default-button bigger-button" onclick="initialImportData()">Import Data</button>
|
||||||
</html>
|
<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>
|
||||||
|
|||||||
Reference in New Issue
Block a user