From c11f4adf589ff1184185ab8499770e632630d36a Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Tue, 18 Aug 2026 16:46:33 +0200 Subject: [PATCH 01/14] feat: migrate unattend to ts --- .../assets/js/{unattend.js => unattend.ts} | 47 ++++++++++--------- app/src/layouts/Layout.astro | 2 +- 2 files changed, 27 insertions(+), 22 deletions(-) rename app/src/assets/js/{unattend.js => unattend.ts} (89%) diff --git a/app/src/assets/js/unattend.js b/app/src/assets/js/unattend.ts similarity index 89% rename from app/src/assets/js/unattend.js rename to app/src/assets/js/unattend.ts index 80b57651..1f89e081 100644 --- a/app/src/assets/js/unattend.js +++ b/app/src/assets/js/unattend.ts @@ -2,12 +2,16 @@ import { save } from "@tauri-apps/plugin-dialog"; import { writeTextFile } from "@tauri-apps/plugin-fs"; const autoattendBtn = document.getElementById("autounattendBtn"); -autoattendBtn.addEventListener("click", async () => { - let script = document.getElementById("code").innerText; - script = script.replace(/\n/g, "\r\n"); - script = script.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); +if (autoattendBtn) { + autoattendBtn.addEventListener("click", async () => { + const code = document.getElementById("code"); + if (!code) return; - const autoattendScript = ` + let script = code.innerText; + script = script.replace(/\n/g, "\r\n"); + script = script.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); + + const autoattendScript = ` @@ -157,21 +161,22 @@ $scripts = @( `; - try { - const filePath = await save({ - defaultPath: "autounattend.xml", - filters: [ - { - name: "XML", - extensions: ["xml"], - }, - ], - }); + try { + const filePath = await save({ + defaultPath: "autounattend.xml", + filters: [ + { + name: "XML", + extensions: ["xml"], + }, + ], + }); - if (filePath) { - await writeTextFile(filePath, autoattendScript); + if (filePath) { + await writeTextFile(filePath, autoattendScript); + } + } catch (error) { + console.error("Error saving autoattend:", error); } - } catch (error) { - console.error("Error saving autoattend:", error); - } -}); + }); +} diff --git a/app/src/layouts/Layout.astro b/app/src/layouts/Layout.astro index e2276321..53d6c00a 100644 --- a/app/src/layouts/Layout.astro +++ b/app/src/layouts/Layout.astro @@ -24,7 +24,7 @@ const { locale = "en" } = Astro.props; - + - + - + From d06cefef64289274991620c88cdbdc9187599e04 Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 14:03:35 +0200 Subject: [PATCH 04/14] feat: rename main to ts --- app/src/assets/js/{main.js => main.ts} | 0 app/src/layouts/Layout.astro | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename app/src/assets/js/{main.js => main.ts} (100%) diff --git a/app/src/assets/js/main.js b/app/src/assets/js/main.ts similarity index 100% rename from app/src/assets/js/main.js rename to app/src/assets/js/main.ts diff --git a/app/src/layouts/Layout.astro b/app/src/layouts/Layout.astro index 1388a901..04972c7c 100644 --- a/app/src/layouts/Layout.astro +++ b/app/src/layouts/Layout.astro @@ -21,7 +21,7 @@ const { locale = "en" } = Astro.props; - + From 3db1c6c3881246675dbfc9538315c0fa18b43ba9 Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 15:26:44 +0200 Subject: [PATCH 05/14] feat: migrate main to ts --- app/src/assets/js/main.ts | 272 ++++++++++++++++++++------------------ 1 file changed, 143 insertions(+), 129 deletions(-) diff --git a/app/src/assets/js/main.ts b/app/src/assets/js/main.ts index 52085e7e..276fac5b 100644 --- a/app/src/assets/js/main.ts +++ b/app/src/assets/js/main.ts @@ -1,9 +1,9 @@ -import { writeTextFile, readTextFile, mkdir, remove, exists } from "@tauri-apps/plugin-fs"; -import { tempDir, join, dirname } from "@tauri-apps/api/path"; +import { writeTextFile, readTextFile, mkdir } from "@tauri-apps/plugin-fs"; +import { tempDir, join } from "@tauri-apps/api/path"; import { Command } from "@tauri-apps/plugin-shell"; import { app } from "@tauri-apps/api"; import { version, locale as getOsLocale } from "@tauri-apps/plugin-os"; -import { getCurrentWindow } from "@tauri-apps/api/window"; +import { Effect, getCurrentWindow } from "@tauri-apps/api/window"; import { ask, save, open } from "@tauri-apps/plugin-dialog"; import { check } from "@tauri-apps/plugin-updater"; import { relaunch } from "@tauri-apps/plugin-process"; @@ -13,15 +13,19 @@ import { getMatches } from "@tauri-apps/plugin-cli"; async function loadConfig() { const matches = await getMatches(); if (matches.args.import) { - const path = matches.args.import.value; + const path = matches.args.import.value?.toString(); if (!path) { return; } try { - const checkboxes = document.querySelectorAll('input[type="checkbox"]'); - const radios = document.querySelectorAll('input[type="radio"]'); + const checkboxes = document.querySelectorAll( + 'input[type="checkbox"]', + ) as NodeListOf; + const radios = document.querySelectorAll( + 'input[type="radio"]', + ) as NodeListOf; const contents = await readTextFile(path); const settings = JSON.parse(contents); @@ -115,7 +119,7 @@ async function checkForUpdates() { cancelLabel: "Later", }); - if (updateAsk === true) { + if (update && updateAsk === true) { await update.downloadAndInstall(); await relaunch(); } else { @@ -129,9 +133,9 @@ async function checkForUpdates() { async function isInstalled() { const update = await check(); + if (!update) return; - if (update) { - const script = ` + const script = ` $processExists = [bool](Get-Process winscript-portable -ErrorAction SilentlyContinue) $parentPath = (Get-Process -Id (Get-CimInstance Win32_Process -Filter "ProcessId=$PID").ParentProcessId).Path $uninstallPath = Join-Path (Split-Path $parentPath) "uninstall.exe" @@ -139,29 +143,26 @@ async function isInstalled() { @{ isPortable = $processExists; uninstallExists = $uninstallExists } | ConvertTo-Json -Compress `; - const shell = new Command("powershell", [ - "-NoProfile", - "-WindowStyle", - "Hidden", - "-Command", - script, - ]); + const shell = Command.create("powershell", [ + "-NoProfile", + "-WindowStyle", + "Hidden", + "-Command", + script, + ]); - const result = await shell.execute(); - const { isPortable, uninstallExists } = JSON.parse(result.stdout); + const result = await shell.execute(); + const { isPortable, uninstallExists } = JSON.parse(result.stdout); - if (isPortable) { - alertForUpdates(); - return; - } + if (isPortable) { + alertForUpdates(); + return; + } - if (uninstallExists) { - checkForUpdates(); - } else { - alertForUpdates(); - } + if (uninstallExists) { + checkForUpdates(); } else { - return; + alertForUpdates(); } } @@ -177,7 +178,7 @@ function isWindows11() { function applyMica() { try { if (isWindows11()) { - getCurrentWindow().setEffects({ effects: ["mica"] }); + getCurrentWindow().setEffects({ effects: [Effect.Mica] }); } else { document.body.style.backgroundColor = "var(--background)"; } @@ -189,7 +190,7 @@ function applyMica() { async function hasWindowsTerminal() { try { - const check = new Command("where", ["wt"]); + const check = Command.create("where", ["wt"]); const output = await check.execute(); return output.code === 0; } catch (error) { @@ -213,21 +214,26 @@ document.addEventListener("DOMContentLoaded", () => { }); async function displayVersion() { + const versionElement = document.getElementById("version"); + if (!versionElement) return; try { const version = await app.getVersion(); - document.getElementById("version").textContent = `${version}`; + versionElement.textContent = `${version}`; } catch (error) { - document.getElementById("version").textContent = ``; + versionElement.textContent = ``; console.error("Failed to get app version:", error); } } displayVersion(); -document.querySelector(".nav-icon").addEventListener("click", () => { +document.querySelector(".nav-icon")?.addEventListener("click", () => { const navbar = document.getElementById("sidebar"); const content = document.querySelector(".content"); - const paragraphs = document.querySelectorAll(".content-entry:not(.about) p"); + const paragraphs = document.querySelectorAll( + ".content-entry:not(.about) p", + ) as NodeListOf; + if (!navbar || !content) return; if (!navbar.classList.contains("responsive")) { navbar.classList.add("responsive"); @@ -249,7 +255,7 @@ document.querySelector(".nav-icon").addEventListener("click", () => { } }); -const tabs = document.querySelectorAll(".sidebar-entry"); +const tabs = document.querySelectorAll(".sidebar-entry") as NodeListOf; const contents = document.querySelectorAll(".tab-content"); const title = document.getElementById("content-header"); // Select the header element for updating @@ -257,11 +263,13 @@ const title = document.getElementById("content-header"); // Select the header el if (tabs.length > 0 && contents.length > 0) { tabs[0].classList.add("active"); contents[0].classList.add("active"); - title.textContent = tabs[0].textContent || "WinScript"; // Update header with the first tab's text + if (title) { + title.textContent = tabs[0].textContent || "WinScript"; + } } // Titlebar button goes to languages tab -document.querySelector('button[data-tab="localizations-tab"]').addEventListener("click", () => { +document.querySelector('button[data-tab="localizations-tab"]')?.addEventListener("click", () => { tabs[9].click(); }); @@ -281,18 +289,22 @@ tabs.forEach((tab, index) => { tab.classList.add("active"); contents[index].classList.add("active"); - title.textContent = tab.textContent; + if (title) { + title.textContent = tab.textContent; + } }); }); // Import & Export const importBtn = document.getElementById("importBtn"); const exportBtn = document.getElementById("exportBtn"); -const checkboxes = document.querySelectorAll('input[type="checkbox"]'); -const radios = document.querySelectorAll('input[type="radio"]'); +const checkboxes = document.querySelectorAll( + 'input[type="checkbox"]', +) as NodeListOf; +const radios = document.querySelectorAll('input[type="radio"]') as NodeListOf; -exportBtn.addEventListener("click", async () => { - let settings = {}; +exportBtn?.addEventListener("click", async () => { + let settings: Record = {}; checkboxes.forEach((checkbox) => { settings[checkbox.id] = checkbox.checked; }); @@ -319,7 +331,7 @@ exportBtn.addEventListener("click", async () => { } }); -importBtn.addEventListener("click", async () => { +importBtn?.addEventListener("click", async () => { try { const filePath = await open({ filters: [ @@ -357,41 +369,43 @@ const visualEffects = document.getElementById("openVisualEffects"); const pageFile = document.getElementById("openPageFile"); const msConfig = document.getElementById("openMSConfig"); -windowsSettings.addEventListener("click", () => { - new Command("cmd", ["/c", "start", "ms-settings:"]).execute(); +windowsSettings?.addEventListener("click", () => { + Command.create("cmd", ["/c", "start", "ms-settings:"]).execute(); }); -deviceManager.addEventListener("click", () => { - new Command("cmd", ["/c", "start", "devmgmt.msc"]).execute(); +deviceManager?.addEventListener("click", () => { + Command.create("cmd", ["/c", "start", "devmgmt.msc"]).execute(); }); -controlPanel.addEventListener("click", () => { - new Command("cmd", ["/c", "start", "control"]).execute(); +controlPanel?.addEventListener("click", () => { + Command.create("cmd", ["/c", "start", "control"]).execute(); }); -visualEffects.addEventListener("click", () => { - new Command("cmd", ["/c", "start", "SystemPropertiesPerformance"]).execute(); +visualEffects?.addEventListener("click", () => { + Command.create("cmd", ["/c", "start", "SystemPropertiesPerformance"]).execute(); }); -pageFile.addEventListener("click", () => { - new Command("cmd", ["/c", "SystemPropertiesPerformance /pagefile"]).execute(); +pageFile?.addEventListener("click", () => { + Command.create("cmd", ["/c", "SystemPropertiesPerformance /pagefile"]).execute(); }); -msConfig.addEventListener("click", () => { - new Command("cmd", ["/c", "start", "msconfig"]).execute(); +msConfig?.addEventListener("click", () => { + Command.create("cmd", ["/c", "start", "msconfig"]).execute(); }); // MAS Checkbox const masCheckbox = document.getElementById("installmas"); -masCheckbox.addEventListener("change", () => { - if (masCheckbox.checked) { - document.querySelector(".mas-container").style.display = "block"; - } else { - document.querySelector(".mas-container").style.display = "none"; - } -}); +const masContainer = document.querySelector(".mas-container"); + +if (masCheckbox instanceof HTMLInputElement && masContainer instanceof HTMLDivElement) { + masCheckbox.addEventListener("change", () => { + masContainer.style.display = masCheckbox.checked ? "block" : "none"; + }); +} // OneDrive Checkbox const onedriveCheckbox = document.getElementById("onedrive"); let onedriveChanging = false; -onedriveCheckbox.addEventListener("click", async (e) => { +onedriveCheckbox?.addEventListener("click", async (e) => { + if (!(onedriveCheckbox instanceof HTMLInputElement)) return; + if (onedriveChanging) { onedriveChanging = false; return; @@ -404,7 +418,6 @@ onedriveCheckbox.addEventListener("click", async (e) => { "Uninstalling OneDrive will delete all of your OneDrive files, make sure to backup if you wish to proceed. Do you want to continue?", { title: "Uninstall OneDrive", - type: "question", }, ); @@ -417,44 +430,44 @@ onedriveCheckbox.addEventListener("click", async (e) => { }); // Restore Point Checkbox -const restoreCheckbox = document.getElementById("restorepoint"); -restoreCheckbox.addEventListener("change", () => { - if (restoreCheckbox.checked) { - document.querySelector(".restore-container").style.display = "block"; - } else { - document.querySelector(".restore-container").style.display = "none"; - } +const restoreCheckbox = document.getElementById("restorepoint") as HTMLInputElement; +const restoreContainer = document.querySelector(".restore-container") as HTMLDivElement; +restoreCheckbox?.addEventListener("change", () => { + restoreContainer.style.display = restoreCheckbox.checked ? "block" : "none"; }); // App Search Bar -document.getElementById("searchBar").addEventListener("input", () => { - const searchValue = document.getElementById("searchBar").value.toLowerCase(); - const detailsElements = document.querySelectorAll("#install-tab details"); - - detailsElements.forEach((details) => { - const entries = [...details.querySelectorAll(".content-entry")]; - const summary = details.querySelector("summary"); - - let hasMatch = false; +const searchBar = document.getElementById("searchBar"); +if (searchBar instanceof HTMLInputElement) { + searchBar?.addEventListener("input", () => { + const searchValue = searchBar.value.toLowerCase(); + const detailsElements = document.querySelectorAll("#install-tab details"); + + detailsElements.forEach((details) => { + const entries = [...details.querySelectorAll(".content-entry")]; + const summary = details.querySelector("summary"); + + let hasMatch = false; + + entries.forEach((entry) => { + if (!entry.isSameNode(summary)) { + const isMatch = entry.textContent.toLowerCase().includes(searchValue); + entry.style.display = isMatch ? "" : "none"; + hasMatch ||= isMatch; + } + }); - entries.forEach((entry) => { - if (!entry.isSameNode(summary)) { - const isMatch = entry.textContent.toLowerCase().includes(searchValue); - entry.style.display = isMatch ? "" : "none"; - hasMatch ||= isMatch; + if (!searchValue) { + details.style.display = ""; + details.open = false; + entries.forEach((entry) => (entry.style.display = "")); + } else { + details.style.display = hasMatch ? "" : "none"; + details.open = hasMatch; } }); - - if (!searchValue) { - details.style.display = ""; - details.open = false; - entries.forEach((entry) => (entry.style.display = "")); - } else { - details.style.display = hasMatch ? "" : "none"; - details.open = hasMatch; - } }); -}); +} // Update apps button const updateBtn = document.getElementById("updateBtn"); @@ -463,7 +476,7 @@ const chocoUpdateCommand = "choco upgrade all -y"; const wingetUpdateCommand = "winget upgrade --all --include-unknown --silent --accept-source-agreements --accept-package-agreements"; -async function updateApps(packageUpdateCommand) { +async function updateApps(packageUpdateCommand: string) { const hasWt = await hasWindowsTerminal(); const args = ["/c", "start"]; if (hasWt) args.push("wt"); @@ -477,22 +490,25 @@ async function updateApps(packageUpdateCommand) { packageUpdateCommand, ); - new Command("cmd", args).execute(); + Command.create("cmd", args).execute(); } -updateBtn.addEventListener("click", () => { - if (packageManager.value === "chocolatey") { - updateApps(chocoUpdateCommand); - } else if (packageManager.value === "winget") { - updateApps(wingetUpdateCommand); - } -}); +if (packageManager instanceof HTMLInputElement) { + updateBtn?.addEventListener("click", () => { + if (packageManager.value === "chocolatey") { + updateApps(chocoUpdateCommand); + } else if (packageManager.value === "winget") { + updateApps(wingetUpdateCommand); + } + }); +} // Copy to clipboard button -document.getElementById("copyBtn").addEventListener("click", function () { - var textContent = document.getElementById("code").innerText; +document.getElementById("copyBtn")?.addEventListener("click", async function () { + var textContent = document.getElementById("code")?.innerText; + if (!textContent) return; try { - navigator.clipboard.writeText(textContent); + await navigator.clipboard.writeText(textContent); } catch (error) { console.error("Error copying to clipboard:", error); } @@ -504,7 +520,7 @@ document.querySelectorAll(".checkbox-wrapper").forEach((wrapper) => { const radio = wrapper.querySelector('input[type="radio"]'); const indicator = wrapper.querySelector(".indicator"); - if (checkbox) { + if (checkbox && checkbox instanceof HTMLInputElement) { checkbox.addEventListener("change", () => { if (indicator) { indicator.textContent = checkbox.checked @@ -517,36 +533,33 @@ document.querySelectorAll(".checkbox-wrapper").forEach((wrapper) => { if (radio) { radio.addEventListener("change", () => { const radioName = radio.getAttribute("name"); - document.querySelectorAll(`input[type="radio"][name="${radioName}"]`).forEach((r) => { - const parentWrapper = r.closest(".checkbox-wrapper"); - if (parentWrapper) { - const ind = parentWrapper.querySelector(".indicator"); - if (ind) { - ind.textContent = r.checked - ? ind.getAttribute("data-on") || "On" - : ind.getAttribute("data-off") || "Off"; - } - } - }); + document + .querySelectorAll(`input[type="radio"][name="${radioName}"]`) + .forEach((r) => { + const parentWrapper = r.closest(".checkbox-wrapper"); + const ind = parentWrapper?.querySelector(".indicator"); + if (!ind) return; + ind.textContent = r.checked + ? ind.getAttribute("data-on") || "On" + : ind.getAttribute("data-off") || "Off"; + }); }); } }); // Run Button -document.getElementById("runBtn").addEventListener("click", async function () { +document.getElementById("runBtn")?.addEventListener("click", async function () { if (!restoreCheckbox.checked) { let restoreAsk = await ask("Do you want to create a restore point?", { title: "Restore Point", }); - if (restoreAsk === true) { - document.querySelector(".restore-container").style.display = "block"; - } else { - document.querySelector(".restore-container").style.display = "none"; - } + if (!restoreContainer) return; + restoreContainer.style.display = restoreAsk ? "block" : "none"; } - let textContent = document.getElementById("code").innerText; + let textContent = document.getElementById("code")?.innerText; + if (!textContent) return; // Convert LF to CRLF textContent = textContent.replace(/\n/g, "\r\n"); @@ -587,7 +600,7 @@ document.getElementById("runBtn").addEventListener("click", async function () { filePath, ]; - const command = new Command("cmd", args); + const command = Command.create("cmd", args); command .spawn() @@ -601,9 +614,10 @@ document.getElementById("runBtn").addEventListener("click", async function () { // Language switching document.querySelectorAll(".localization-entry").forEach((entry) => { const useBtn = entry.querySelector(".use-lang-btn"); - const locale = useBtn.getAttribute("data-locale"); + const locale = useBtn?.getAttribute("data-locale"); - useBtn.addEventListener("click", (e) => { + useBtn?.addEventListener("click", (e) => { + if (!locale) return; e.stopPropagation(); // Redirect to /[locale] // If locale is en, we could go to / but /en is safer/more consistent From 19f780bb1abc278427cbeb4a9f423ca6f995a54f Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 15:34:44 +0200 Subject: [PATCH 06/14] refactor: cleaning some functions --- app/src/components/Titlebar.astro | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/app/src/components/Titlebar.astro b/app/src/components/Titlebar.astro index 2ec54723..cdf6641f 100644 --- a/app/src/components/Titlebar.astro +++ b/app/src/components/Titlebar.astro @@ -120,12 +120,9 @@ const appWindow = getCurrentWindow(); const title = document.getElementById("title"); - function updateTitle(isFocused) { - if (isFocused) { - title!.style.color = "var(--text)"; - } else { - title!.style.color = "var(--muted)"; - } + function updateTitle(isFocused: boolean) { + if (!title) return; + title.style.color = isFocused ? "var(--text)" : "var(--muted)"; } appWindow.isFocused().then((focused) => { @@ -165,11 +162,7 @@ } askCheckbox?.addEventListener("change", () => { - if (askCheckbox.checked) { - localStorage.setItem("askPreference", "false"); - } else { - localStorage.setItem("askPreference", "true"); - } + localStorage.setItem("askPreference", askCheckbox.checked ? "false" : "true") }); coffeeButton?.addEventListener("click", async () => { From 8b5f40c06733e69c8c44e17b2fe21ed0a1584667 Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 15:35:22 +0200 Subject: [PATCH 07/14] feat: rename website files --- website/src/assets/js/{appinstall.js => appinstall.ts} | 0 website/src/assets/js/{main.js => main.ts} | 0 website/src/assets/js/{scripts.js => scripts.ts} | 0 website/src/assets/js/{unattend.js => unattend.ts} | 0 website/src/layouts/Layout.astro | 8 ++++---- 5 files changed, 4 insertions(+), 4 deletions(-) rename website/src/assets/js/{appinstall.js => appinstall.ts} (100%) rename website/src/assets/js/{main.js => main.ts} (100%) rename website/src/assets/js/{scripts.js => scripts.ts} (100%) rename website/src/assets/js/{unattend.js => unattend.ts} (100%) diff --git a/website/src/assets/js/appinstall.js b/website/src/assets/js/appinstall.ts similarity index 100% rename from website/src/assets/js/appinstall.js rename to website/src/assets/js/appinstall.ts diff --git a/website/src/assets/js/main.js b/website/src/assets/js/main.ts similarity index 100% rename from website/src/assets/js/main.js rename to website/src/assets/js/main.ts diff --git a/website/src/assets/js/scripts.js b/website/src/assets/js/scripts.ts similarity index 100% rename from website/src/assets/js/scripts.js rename to website/src/assets/js/scripts.ts diff --git a/website/src/assets/js/unattend.js b/website/src/assets/js/unattend.ts similarity index 100% rename from website/src/assets/js/unattend.js rename to website/src/assets/js/unattend.ts diff --git a/website/src/layouts/Layout.astro b/website/src/layouts/Layout.astro index 561dc9ea..d16a56d6 100644 --- a/website/src/layouts/Layout.astro +++ b/website/src/layouts/Layout.astro @@ -39,8 +39,8 @@ const { locale = "en" } = Astro.props; hljs.highlightAll(); - - - - + + + + From 8d7e7cdae2988dcc391f59e0304fa48db957b702 Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 15:38:23 +0200 Subject: [PATCH 08/14] feat: migrate website appinstall to ts --- website/src/assets/js/appinstall.ts | 114 ++++++++++++++++++---------- website/src/assets/js/global.d.ts | 7 ++ 2 files changed, 81 insertions(+), 40 deletions(-) create mode 100644 website/src/assets/js/global.d.ts diff --git a/website/src/assets/js/appinstall.ts b/website/src/assets/js/appinstall.ts index f9d00fe3..2e6c89c0 100644 --- a/website/src/assets/js/appinstall.ts +++ b/website/src/assets/js/appinstall.ts @@ -235,7 +235,7 @@ function appsInstallChocolatey() { function getCheckedUrls() { return appListChocolatey .filter((app) => { - const element = document.getElementById(app.id); + const element = document.getElementById(app.id) as HTMLInputElement; return element && element.checked; }) .map((app) => app.url); @@ -244,7 +244,7 @@ function appsInstallChocolatey() { // Function to update the command display function updateCommandDisplay() { const checkedUrls = getCheckedUrls(); - const allUrls = [...checkedUrls, ...window.manualURLs]; + const allUrls = [...checkedUrls, ...(window.manualURLs ?? [])]; const finalURL = allUrls .filter((url) => url && url.trim() !== "") .map((url) => `\\"${url}\\"`) @@ -261,19 +261,29 @@ function appsInstallChocolatey() { : ""; // Display the final URL in the div - document.querySelector(".div-install").style.display = allUrls.length > 0 ? "block" : "none"; - document.querySelector(".winget-container").style.display = "none"; - document.querySelector(".chocolatey-container").style.display = - allUrls.length > 0 ? "block" : "none"; - + const divInstall = document.querySelector(".div-install") as HTMLDivElement; + const wingetContainer = document.querySelector(".winget-container") as HTMLDivElement; + const chocolateyContainer = document.querySelector(".chocolatey-container") as HTMLDivElement; const commandDisplay = document.querySelector(".commandDisplay"); - commandDisplay.textContent = command; - const installingApps = document.querySelector(".installingApps"); + if ( + !divInstall || + !wingetContainer || + !chocolateyContainer || + !commandDisplay || + !installingApps + ) + return; + + divInstall.style.display = allUrls.length > 0 ? "block" : "none"; + wingetContainer.style.display = "none"; + chocolateyContainer.style.display = allUrls.length > 0 ? "block" : "none"; + + commandDisplay.textContent = command; installingApps.textContent = allUrls.join(", "); const manualList = document.getElementById("manualList"); - if (window.manualURLs.length > 0) { + if (manualList && window.manualURLs && window.manualURLs.length > 0) { manualList.innerHTML = "Manual packages added: " + window.manualURLs.join(" | "); } } @@ -523,7 +533,7 @@ function appsInstallWinget() { function getCheckedUrls() { return appListWinget .filter((app) => { - const element = document.getElementById(app.id); + const element = document.getElementById(app.id) as HTMLInputElement; return element && element.checked; }) .map((app) => app.url); @@ -532,7 +542,7 @@ function appsInstallWinget() { // Function to update the command display function updateCommandDisplay() { const checkedUrls = getCheckedUrls(); - const allUrls = [...checkedUrls, ...window.manualURLs]; + const allUrls = [...checkedUrls, ...(window.manualURLs ?? [])]; const finalURL = allUrls .filter((url) => url && url.trim() !== "") .map((url) => `\\"${url}\\"`) @@ -546,22 +556,33 @@ function appsInstallWinget() { : ""; // Display the final URL in the div - document.querySelector(".div-install").style.display = allUrls.length > 0 ? "block" : "none"; - document.querySelector(".chocolatey-container").style.display = "none"; - document.querySelector(".winget-container").style.display = - allUrls.length > 0 ? "block" : "none"; - + const divInstall = document.querySelector(".div-install") as HTMLDivElement; + const wingetContainer = document.querySelector(".winget-container") as HTMLDivElement; + const chocolateyContainer = document.querySelector(".chocolatey-container") as HTMLDivElement; const commandDisplay = document.querySelector(".commandDisplay"); - commandDisplay.textContent = command; - const installingApps = document.querySelector(".installingApps"); + const wingetUpgrade = document.getElementById("wingetUpgrade"); + if ( + !divInstall || + !wingetContainer || + !chocolateyContainer || + !commandDisplay || + !installingApps || + !wingetUpgrade + ) + return; + + divInstall.style.display = allUrls.length > 0 ? "block" : "none"; + chocolateyContainer.style.display = "none"; + wingetContainer.style.display = allUrls.length > 0 ? "block" : "none"; + + commandDisplay.textContent = command; installingApps.textContent = allUrls.join(", "); - const wingetUpgrade = document.getElementById("wingetUpgrade"); wingetUpgrade.textContent = `$v = winget -v; if ([version]($v.TrimStart('v')) -lt [version]'1.7.0') { Write-Output '-- Old Winget version detected, upgrading.'; Set-Location $env:USERPROFILE; Invoke-WebRequest -Uri 'https://aka.ms/getwinget' -OutFile 'winget.msixbundle'; Add-AppPackage -ForceApplicationShutdown .\\winget.msixbundle; Remove-Item .\\winget.msixbundle } else { Write-Output 'Winget is already up to date, skipping upgrade.' }`; const manualList = document.getElementById("manualList"); - if (window.manualURLs.length > 0) { + if (manualList && window.manualURLs && window.manualURLs.length > 0) { manualList.innerHTML = "Manual packages added: " + window.manualURLs.join(" | "); } } @@ -572,45 +593,58 @@ function appsInstallWinget() { appsInstallWinget(); appsInstallChocolatey(); -const selectedPackageManager = document.getElementById("packageManager"); -selectedPackageManager.addEventListener("change", () => { - if (selectedPackageManager.value === "chocolatey") { - appsInstallChocolatey(); - } else if (selectedPackageManager.value === "winget") { - appsInstallWinget(); - } -}); +const selectedPackageManager = document.getElementById("packageManager") as HTMLInputElement; +if (selectedPackageManager) { + selectedPackageManager.addEventListener("change", () => { + if (selectedPackageManager.value === "chocolatey") { + appsInstallChocolatey(); + } else if (selectedPackageManager.value === "winget") { + appsInstallWinget(); + } + }); +} // Check manual IDs -function isValidManualId(manualId) { +function isValidManualId(manualId: string) { return /^[A-Za-z0-9._+\-]+$/.test(manualId); } // Manual IDs button listener const addButton = document.getElementById("addApp"); -addButton.addEventListener("click", () => { - const manualInput = document.getElementById("manualInput").value.trim(); - if (manualInput) { - if (!isValidManualId(manualInput)) { - const manualList = document.getElementById("manualList"); +if (addButton) { + addButton.addEventListener("click", () => { + const manualInput = document.getElementById("manualInput") as HTMLInputElement; + const manualList = document.getElementById("manualList"); + const inputValue = manualInput.value.trim(); + if (!manualInput || !manualList) return; + + if (!isValidManualId(inputValue)) { manualList.innerHTML = "Please enter a valid package ID."; return; } - window.manualURLs.push(manualInput); - document.getElementById("manualInput").value = ""; // Clear input + + if (window.manualURLs) { + window.manualURLs.push(inputValue); + } + + manualInput.value = ""; // Clear input if (selectedPackageManager.value === "chocolatey") { appsInstallChocolatey(); } else if (selectedPackageManager.value === "winget") { appsInstallWinget(); } - } -}); + }); +} // Checkboxes event listeners const apps = document.querySelectorAll('[js-target="install"]'); document.addEventListener("DOMContentLoaded", () => { document.body.addEventListener("change", (event) => { - if (event.target.matches("[js-target=install]")) { + if ( + event.target && + event.target instanceof Element && + event.target.matches("[js-target=install]") + ) { if (selectedPackageManager.value === "chocolatey") { appsInstallChocolatey(); } else if (selectedPackageManager.value === "winget") { diff --git a/website/src/assets/js/global.d.ts b/website/src/assets/js/global.d.ts new file mode 100644 index 00000000..78a054a6 --- /dev/null +++ b/website/src/assets/js/global.d.ts @@ -0,0 +1,7 @@ +declare global { + interface Window { + manualURLs?: string[]; + } +} + +export {}; From c2d7968cbdc4c3f2b84f462a3fb6132292e580b3 Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 15:39:58 +0200 Subject: [PATCH 09/14] feat: migrate website scripts to ts --- website/src/assets/js/scripts.ts | 53 ++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/website/src/assets/js/scripts.ts b/website/src/assets/js/scripts.ts index 0de2dc14..47df64d0 100644 --- a/website/src/assets/js/scripts.ts +++ b/website/src/assets/js/scripts.ts @@ -1,7 +1,8 @@ document.addEventListener("DOMContentLoaded", function () { const parentDiv = document.querySelector(".allScripts"); - function addScript(className, scriptContent) { + function addScript(className: string, scriptContent: string) { + if (!parentDiv) return; const newDiv = document.createElement("div"); const codeElement = document.createElement("code"); @@ -11,14 +12,15 @@ document.addEventListener("DOMContentLoaded", function () { newDiv.appendChild(codeElement); parentDiv.appendChild(newDiv); - hljs.highlightElement(codeElement); + (window as any).hljs.highlightElement(codeElement); } - function removeScripts(className) { + function removeScripts(className: string) { + if (!parentDiv) return; parentDiv.querySelectorAll(`.${className}`).forEach((el) => el.remove()); } - const scripts = { + const scripts: Record = { microsoftstore: [ "Write-Host '-- Uninstalling Microsoft Store' -ForegroundColor Green", 'Get-AppxPackage "*Microsoft.WindowsStore*" | Remove-AppxPackage', @@ -1020,11 +1022,13 @@ document.addEventListener("DOMContentLoaded", function () { checkboxItems.forEach((id) => { const checkbox = document.getElementById(id); - if (checkbox) { + if (checkbox instanceof HTMLInputElement) { checkbox.addEventListener("change", () => { - checkbox.checked - ? scripts[id]?.forEach((script) => addScript(id, script)) - : removeScripts(id); + if (checkbox.checked) { + scripts[id]?.forEach((script) => addScript(id, script)); + } else { + removeScripts(id); + } }); } }); @@ -1032,7 +1036,7 @@ document.addEventListener("DOMContentLoaded", function () { const radios = document.querySelectorAll('input[type="radio"]'); radios.forEach((radio) => { radio.addEventListener("change", () => { - if (radio.checked) { + if (radio instanceof HTMLInputElement && radio.checked) { const groupName = radio.name; document @@ -1050,19 +1054,23 @@ function uncheckAll() { const checkboxes = document.querySelectorAll('input[type="checkbox"]'); const radios = document.querySelectorAll('input[type="radio"]'); const indicator = document.querySelectorAll(".indicator"); + const manualList = document.getElementById("manualList"); window.manualURLs = []; - document.getElementById("manualList").innerHTML = ""; + + if (manualList) { + manualList.innerHTML = ""; + } checkboxes.forEach((checkbox) => { - if (checkbox.checked) { + if (checkbox instanceof HTMLInputElement && checkbox.checked) { checkbox.checked = false; checkbox.dispatchEvent(new Event("change")); } }); radios.forEach((radio) => { - if (radio.checked) { + if (radio instanceof HTMLInputElement && radio.checked) { radio.checked = false; radio.dispatchEvent(new Event("change")); } @@ -1072,15 +1080,20 @@ function uncheckAll() { indicator.textContent = indicator.getAttribute("data-off") || "Off"; }); - document.querySelector(".chocolatey-container").style.display = "none"; - document.querySelector(".winget-container").style.display = "none"; - document.querySelector(".div-install").style.display = "none"; + const chocolateyContainer = document.querySelector(".chocolatey-container") as HTMLDivElement; + const wingetContainer = document.querySelector(".winget-container") as HTMLDivElement; + const divInstall = document.querySelector(".div-install") as HTMLDivElement; + if (!chocolateyContainer || !wingetContainer || !divInstall) return; + + chocolateyContainer.style.display = "none"; + wingetContainer.style.display = "none"; + divInstall.style.display = "none"; } -document.getElementById("uncheckAll").addEventListener("click", uncheckAll); +document.getElementById("uncheckAll")?.addEventListener("click", uncheckAll); // Presets -const presets = { +const presets: Record = { basic: [ "cleanmgr", "cleantemp", @@ -1253,11 +1266,11 @@ const presets = { ], }; -const applyPreset = (ids) => { +const applyPreset = (ids: string[]) => { uncheckAll(); ids.forEach((id) => { const checkbox = document.getElementById(id); - if (checkbox) { + if (checkbox instanceof HTMLInputElement) { checkbox.checked = true; checkbox.dispatchEvent(new Event("change")); } @@ -1267,5 +1280,5 @@ const applyPreset = (ids) => { ["basic", "strict", "extreme"].forEach((preset) => document .getElementById(`${preset}Preset`) - .addEventListener("click", () => applyPreset(presets[preset])), + ?.addEventListener("click", () => applyPreset(presets[preset])), ); From 8367944de05e14bfdd16f4ece33c4a9f0422f3a6 Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 15:42:19 +0200 Subject: [PATCH 10/14] feat: migrate website unattend to ts --- app/src/assets/js/unattend.ts | 48 +++++++++++++++---------------- website/src/assets/js/unattend.ts | 7 +++-- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/app/src/assets/js/unattend.ts b/app/src/assets/js/unattend.ts index 1f89e081..e8c5f55a 100644 --- a/app/src/assets/js/unattend.ts +++ b/app/src/assets/js/unattend.ts @@ -2,16 +2,15 @@ import { save } from "@tauri-apps/plugin-dialog"; import { writeTextFile } from "@tauri-apps/plugin-fs"; const autoattendBtn = document.getElementById("autounattendBtn"); -if (autoattendBtn) { - autoattendBtn.addEventListener("click", async () => { - const code = document.getElementById("code"); - if (!code) return; +autoattendBtn?.addEventListener("click", async () => { + const code = document.getElementById("code"); + if (!code) return; - let script = code.innerText; - script = script.replace(/\n/g, "\r\n"); - script = script.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); + let script = code.innerText; + script = script.replace(/\n/g, "\r\n"); + script = script.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); - const autoattendScript = ` + const autoattendScript = ` @@ -161,22 +160,21 @@ $scripts = @( `; - try { - const filePath = await save({ - defaultPath: "autounattend.xml", - filters: [ - { - name: "XML", - extensions: ["xml"], - }, - ], - }); + try { + const filePath = await save({ + defaultPath: "autounattend.xml", + filters: [ + { + name: "XML", + extensions: ["xml"], + }, + ], + }); - if (filePath) { - await writeTextFile(filePath, autoattendScript); - } - } catch (error) { - console.error("Error saving autoattend:", error); + if (filePath) { + await writeTextFile(filePath, autoattendScript); } - }); -} + } catch (error) { + console.error("Error saving autoattend:", error); + } +}); diff --git a/website/src/assets/js/unattend.ts b/website/src/assets/js/unattend.ts index e314b505..9fdd55af 100644 --- a/website/src/assets/js/unattend.ts +++ b/website/src/assets/js/unattend.ts @@ -1,6 +1,9 @@ const autoattendBtn = document.getElementById("autounattendBtn"); -autoattendBtn.addEventListener("click", async () => { - let script = document.getElementById("code").innerText; +autoattendBtn?.addEventListener("click", async () => { + const code = document.getElementById("code"); + if (!code) return; + + let script = code.innerText; script = script.replace(/\n/g, "\r\n"); script = script.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); From d304f04873f5873cc0d0835f787ed2a11fc5b9b4 Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:03:01 +0200 Subject: [PATCH 11/14] feat: migrate website main to ts --- website/src/assets/js/main.ts | 161 +++++++++++++++++++--------------- 1 file changed, 90 insertions(+), 71 deletions(-) diff --git a/website/src/assets/js/main.ts b/website/src/assets/js/main.ts index 06b3f45d..217d0d7a 100644 --- a/website/src/assets/js/main.ts +++ b/website/src/assets/js/main.ts @@ -45,8 +45,10 @@ function loadLocale() { document.querySelectorAll(".fa-solid").forEach((icon) => { icon.addEventListener("click", () => { const navbar = document.getElementById("sidebar"); - const menuIcon = document.querySelector(".fa-solid.fa-bars-staggered"); - const markIcon = document.querySelector(".fa-solid.fa-xmark"); + const menuIcon = document.querySelector(".fa-solid.fa-bars-staggered") as HTMLElement; + const markIcon = document.querySelector(".fa-solid.fa-xmark") as HTMLElement; + + if (!navbar || !menuIcon || !markIcon) return; if (!navbar.classList.contains("responsive")) { navbar.classList.add("responsive"); @@ -72,7 +74,9 @@ const title = document.getElementById("content-header"); if (tabs.length > 0 && contents.length > 0) { tabs[0].classList.add("active"); contents[0].classList.add("active"); - title.textContent = tabs[0].textContent || "WinScript"; // Update header with the first tab's text + if (title) { + title.textContent = tabs[0].textContent || "WinScript"; + } } // Remove 'active' from all other content divs @@ -91,67 +95,69 @@ tabs.forEach((tab, index) => { tab.classList.add("active"); contents[index].classList.add("active"); - title.textContent = tab.textContent; + if (title) { + title.textContent = tab.textContent; + } }); }); // MAS Checkbox const masCheckbox = document.getElementById("installmas"); -masCheckbox.addEventListener("change", () => { - if (masCheckbox.checked) { - document.querySelector(".mas-container").style.display = "block"; - } else { - document.querySelector(".mas-container").style.display = "none"; - } -}); +const masContainer = document.querySelector(".mas-container"); + +if (masCheckbox instanceof HTMLInputElement && masContainer instanceof HTMLDivElement) { + masCheckbox.addEventListener("change", () => { + masContainer.style.display = masCheckbox.checked ? "block" : "none"; + }); +} // Restore Point Checkbox -const restoreCheckbox = document.getElementById("restorepoint"); -restoreCheckbox.addEventListener("change", () => { - if (restoreCheckbox.checked) { - document.querySelector(".restore-container").style.display = "block"; - } else { - document.querySelector(".restore-container").style.display = "none"; - } +const restoreCheckbox = document.getElementById("restorepoint") as HTMLInputElement; +const restoreContainer = document.querySelector(".restore-container") as HTMLDivElement; +restoreCheckbox?.addEventListener("change", () => { + restoreContainer.style.display = restoreCheckbox.checked ? "block" : "none"; }); // App Search Bar -document.getElementById("searchBar").addEventListener("input", () => { - const searchValue = document.getElementById("searchBar").value.toLowerCase(); - const detailsElements = document.querySelectorAll("#install-tab details"); - - detailsElements.forEach((details) => { - const entries = [...details.querySelectorAll(".content-entry")]; - const summary = details.querySelector("summary"); - - let hasMatch = false; +const searchBar = document.getElementById("searchBar"); +if (searchBar instanceof HTMLInputElement) { + searchBar?.addEventListener("input", () => { + const searchValue = searchBar.value.toLowerCase(); + const detailsElements = document.querySelectorAll("#install-tab details"); + + detailsElements.forEach((details) => { + const entries = [...details.querySelectorAll(".content-entry")]; + const summary = details.querySelector("summary"); + + let hasMatch = false; + + entries.forEach((entry) => { + if (!entry.isSameNode(summary)) { + const isMatch = entry.textContent.toLowerCase().includes(searchValue); + entry.style.display = isMatch ? "" : "none"; + hasMatch ||= isMatch; + } + }); - entries.forEach((entry) => { - if (!entry.isSameNode(summary)) { - const isMatch = entry.textContent.toLowerCase().includes(searchValue); - entry.style.display = isMatch ? "" : "none"; - hasMatch ||= isMatch; + if (!searchValue) { + details.style.display = ""; + details.open = false; + entries.forEach((entry) => (entry.style.display = "")); + } else { + details.style.display = hasMatch ? "" : "none"; + details.open = hasMatch; } }); - - if (!searchValue) { - details.style.display = ""; - details.open = false; - entries.forEach((entry) => (entry.style.display = "")); - } else { - details.style.display = hasMatch ? "" : "none"; - details.open = hasMatch; - } }); -}); +} const importBtn = document.getElementById("importBtn"); const exportBtn = document.getElementById("exportBtn"); -const checkboxes = document.querySelectorAll('input[type="checkbox"]'); -const radios = document.querySelectorAll('input[type="radio"]'); +const checkboxes = document.querySelectorAll('input[type="checkbox"]'); +const radios = document.querySelectorAll('input[type="radio"]'); -exportBtn.addEventListener("click", () => { - let settings = {}; +exportBtn?.addEventListener("click", () => { + let settings: Record = {}; checkboxes.forEach((checkbox) => { settings[checkbox.id] = checkbox.checked; }); @@ -176,19 +182,21 @@ exportBtn.addEventListener("click", () => { console.log("File saved successfully"); }); -importBtn.addEventListener("click", () => { +importBtn?.addEventListener("click", () => { const fileInput = document.createElement("input"); fileInput.type = "file"; fileInput.accept = ".json"; fileInput.addEventListener("change", (event) => { - const file = event.target.files[0]; + const file = (event.target as HTMLInputElement)?.files?.[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { try { - const settings = JSON.parse(e.target.result); + const result = (e.target as FileReader)?.result; + if (typeof result !== "string") return; + const settings = JSON.parse(result); checkboxes.forEach((checkbox) => { checkbox.checked = settings[checkbox.id]; checkbox.dispatchEvent(new Event("change")); @@ -209,9 +217,14 @@ importBtn.addEventListener("click", () => { }); // Copy to clipboard button -document.getElementById("copyBtn").addEventListener("click", function () { - var textContent = document.getElementById("code").innerText; - navigator.clipboard.writeText(textContent); +document.getElementById("copyBtn")?.addEventListener("click", async function () { + var textContent = document.getElementById("code")?.innerText; + if (!textContent) return; + try { + await navigator.clipboard.writeText(textContent); + } catch (error) { + console.error("Error copying to clipboard:", error); + } }); // Update the indicator text @@ -220,7 +233,7 @@ document.querySelectorAll(".checkbox-wrapper").forEach((wrapper) => { const radio = wrapper.querySelector('input[type="radio"]'); const indicator = wrapper.querySelector(".indicator"); - if (checkbox) { + if (checkbox && checkbox instanceof HTMLInputElement) { checkbox.addEventListener("change", () => { if (indicator) { indicator.textContent = checkbox.checked @@ -233,26 +246,29 @@ document.querySelectorAll(".checkbox-wrapper").forEach((wrapper) => { if (radio) { radio.addEventListener("change", () => { const radioName = radio.getAttribute("name"); - document.querySelectorAll(`input[type="radio"][name="${radioName}"]`).forEach((r) => { - const parentWrapper = r.closest(".checkbox-wrapper"); - if (parentWrapper) { - const ind = parentWrapper.querySelector(".indicator"); - if (ind) { - ind.textContent = r.checked - ? ind.getAttribute("data-on") || "On" - : ind.getAttribute("data-off") || "Off"; + document + .querySelectorAll(`input[type="radio"][name="${radioName}"]`) + .forEach((r) => { + const parentWrapper = r.closest(".checkbox-wrapper"); + if (parentWrapper) { + const ind = parentWrapper.querySelector(".indicator"); + if (ind) { + ind.textContent = r.checked + ? ind.getAttribute("data-on") || "On" + : ind.getAttribute("data-off") || "Off"; + } } - } - }); + }); }); } }); -document.getElementById("downloadBtn").addEventListener("click", function () { +document.getElementById("downloadBtn")?.addEventListener("click", function () { const supportDialog = document.getElementById("supportDialog"); const closeSupportDialog = document.getElementById("closeSupportDialog"); - var textContent = document.getElementById("code").innerText; + var textContent = document.getElementById("code")?.innerText; + if (!textContent) return; // Convert LF to CRLF textContent = textContent.replace(/\n/g, "\r\n"); @@ -266,19 +282,22 @@ document.getElementById("downloadBtn").addEventListener("click", function () { link.click(); document.body.removeChild(link); - supportDialog.showModal(); + if (supportDialog instanceof HTMLDialogElement && closeSupportDialog instanceof SVGElement) { + supportDialog?.showModal(); - closeSupportDialog.addEventListener("click", () => { - supportDialog.close(); - }); + closeSupportDialog?.addEventListener("click", () => { + supportDialog?.close(); + }); + } }); // Language switching document.querySelectorAll(".localization-entry").forEach((entry) => { const useBtn = entry.querySelector(".use-lang-btn"); - const locale = useBtn.getAttribute("data-locale"); + const locale = useBtn?.getAttribute("data-locale"); - useBtn.addEventListener("click", (e) => { + useBtn?.addEventListener("click", (e) => { + if (!locale) return; e.stopPropagation(); localStorage.setItem("locale", locale); // Redirect to /[locale] From c98ff33a8662caab81f8d46f69ed32b1445d54e8 Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:03:25 +0200 Subject: [PATCH 12/14] refactor: remove type assertion --- app/src/assets/js/main.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/assets/js/main.ts b/app/src/assets/js/main.ts index 276fac5b..07f88f67 100644 --- a/app/src/assets/js/main.ts +++ b/app/src/assets/js/main.ts @@ -298,10 +298,8 @@ tabs.forEach((tab, index) => { // Import & Export const importBtn = document.getElementById("importBtn"); const exportBtn = document.getElementById("exportBtn"); -const checkboxes = document.querySelectorAll( - 'input[type="checkbox"]', -) as NodeListOf; -const radios = document.querySelectorAll('input[type="radio"]') as NodeListOf; +const checkboxes = document.querySelectorAll('input[type="checkbox"]'); +const radios = document.querySelectorAll('input[type="radio"]'); exportBtn?.addEventListener("click", async () => { let settings: Record = {}; From 558346da8d077dfb84c0b1f6919231acc9e47ac8 Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:06:22 +0200 Subject: [PATCH 13/14] fix: change workflow to compare .ts files --- .github/workflows/compare.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/compare.yml b/.github/workflows/compare.yml index fca387c9..03d6978b 100644 --- a/.github/workflows/compare.yml +++ b/.github/workflows/compare.yml @@ -71,8 +71,8 @@ jobs: } } - $appInstallApp = "app/src/assets/js/appinstall.js" - $appInstallWeb = "website/src/assets/js/appinstall.js" + $appInstallApp = "app/src/assets/js/appinstall.ts" + $appInstallWeb = "website/src/assets/js/appinstall.ts" if ((Test-Path $appInstallApp) -and (Test-Path $appInstallWeb)) { if ((Get-FileHash $appInstallApp).Hash -ne (Get-FileHash $appInstallWeb).Hash) { @@ -81,8 +81,8 @@ jobs: } } - $scriptsApp = "app/src/assets/js/scripts.js" - $scriptsWeb = "website/src/assets/js/scripts.js" + $scriptsApp = "app/src/assets/js/scripts.ts" + $scriptsWeb = "website/src/assets/js/scripts.ts" if ((Test-Path $scriptsApp) -and (Test-Path $scriptsWeb)) { if ((Get-FileHash $scriptsApp).Hash -ne (Get-FileHash $scriptsWeb).Hash) { From f9298a7fd377ea27416752a65fc06d8298263297 Mon Sep 17 00:00:00 2001 From: flick9000 <137506210+flick9000@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:21:09 +0200 Subject: [PATCH 14/14] refactor: change type syntax --- app/src/assets/js/main.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/app/src/assets/js/main.ts b/app/src/assets/js/main.ts index 07f88f67..c534ca23 100644 --- a/app/src/assets/js/main.ts +++ b/app/src/assets/js/main.ts @@ -20,12 +20,8 @@ async function loadConfig() { } try { - const checkboxes = document.querySelectorAll( - 'input[type="checkbox"]', - ) as NodeListOf; - const radios = document.querySelectorAll( - 'input[type="radio"]', - ) as NodeListOf; + const checkboxes = document.querySelectorAll('input[type="checkbox"]'); + const radios = document.querySelectorAll('input[type="radio"]'); const contents = await readTextFile(path); const settings = JSON.parse(contents); @@ -230,9 +226,9 @@ displayVersion(); document.querySelector(".nav-icon")?.addEventListener("click", () => { const navbar = document.getElementById("sidebar"); const content = document.querySelector(".content"); - const paragraphs = document.querySelectorAll( + const paragraphs = document.querySelectorAll( ".content-entry:not(.about) p", - ) as NodeListOf; + ); if (!navbar || !content) return; if (!navbar.classList.contains("responsive")) { @@ -255,7 +251,7 @@ document.querySelector(".nav-icon")?.addEventListener("click", () => { } }); -const tabs = document.querySelectorAll(".sidebar-entry") as NodeListOf; +const tabs = document.querySelectorAll(".sidebar-entry"); const contents = document.querySelectorAll(".tab-content"); const title = document.getElementById("content-header"); // Select the header element for updating