From 3955fbabc9ed05116be07c9f659cd550734f8593 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Mon, 9 Feb 2026 01:24:23 +0300 Subject: go FAST --- static/boot.js | 84 +++++++++++++++++++++++++++++++++++++++++++++ static/favicon.svg | 1 + static/giscus-loader.js | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 static/boot.js create mode 100644 static/favicon.svg create mode 100644 static/giscus-loader.js (limited to 'static') diff --git a/static/boot.js b/static/boot.js new file mode 100644 index 0000000..0bec294 --- /dev/null +++ b/static/boot.js @@ -0,0 +1,84 @@ +(() => { + if (window.__wsapBootInitialized) return; + window.__wsapBootInitialized = true; + + const getCurrentTheme = () => + document.documentElement.getAttribute("data-theme") === "dark" + ? "dark" + : "light"; + + const updateThemeToggleLabels = (theme) => { + const label = + theme === "dark" ? "Switch to light mode" : "Switch to dark mode"; + document.querySelectorAll(".theme-toggle").forEach((button) => { + if (button instanceof HTMLElement) { + button.setAttribute("aria-label", label); + button.setAttribute("title", label); + } + }); + }; + + const applyTheme = (theme, persist = true) => { + document.documentElement.setAttribute("data-theme", theme); + updateThemeToggleLabels(theme); + + if (!persist) return; + + try { + localStorage.setItem("theme", theme); + } catch { + // Ignore read/write failures in strict privacy modes. + } + }; + + const initThemeToggle = () => { + applyTheme(getCurrentTheme(), false); + + document.addEventListener("click", (event) => { + const eventTarget = event.target; + if (!(eventTarget instanceof Element)) return; + + const toggleButton = eventTarget.closest(".theme-toggle"); + if (!(toggleButton instanceof HTMLElement)) return; + + const currentTheme = getCurrentTheme(); + const nextTheme = currentTheme === "dark" ? "light" : "dark"; + applyTheme(nextTheme); + }); + }; + + const loadAnalytics = () => { + if (document.querySelector('script[data-goatcounter-script="true"]')) + return; + + const script = document.createElement("script"); + script.src = "https://stats.wsap.dev/count.js"; + script.async = true; + script.defer = true; + script.setAttribute("data-goatcounter", "https://stats.wsap.dev/count"); + script.setAttribute("data-goatcounter-script", "true"); + document.head.appendChild(script); + }; + + const scheduleAnalytics = () => { + if ("requestIdleCallback" in window) { + window.requestIdleCallback(loadAnalytics, { timeout: 3000 }); + return; + } + window.setTimeout(loadAnalytics, 1500); + }; + + const init = () => { + initThemeToggle(); + + if (document.readyState === "complete") scheduleAnalytics(); + else window.addEventListener("load", scheduleAnalytics, { once: true }); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init, { once: true }); + return; + } + + init(); +})(); diff --git a/static/favicon.svg b/static/favicon.svg new file mode 100644 index 0000000..cc5dc66 --- /dev/null +++ b/static/favicon.svg @@ -0,0 +1 @@ +svelte-logo \ No newline at end of file diff --git a/static/giscus-loader.js b/static/giscus-loader.js new file mode 100644 index 0000000..b671859 --- /dev/null +++ b/static/giscus-loader.js @@ -0,0 +1,90 @@ +(() => { + if (window.__wsapGiscusInitialized) return; + window.__wsapGiscusInitialized = true; + + const initContainer = (root) => { + if (!(root instanceof HTMLElement) || root.dataset.giscusInit === "1") + return; + root.dataset.giscusInit = "1"; + + const toggle = root.querySelector(".comments-toggle"); + const trigger = root.querySelector(".giscus-trigger"); + const slot = root.querySelector(".giscus-slot"); + + if ( + !(toggle instanceof HTMLButtonElement) || + !(slot instanceof HTMLElement) + ) { + return; + } + + let isLoading = false; + let hasLoaded = false; + let observer = null; + + const loadComments = () => { + if (isLoading || hasLoaded) return; + + isLoading = true; + toggle.disabled = true; + toggle.textContent = "Loading comments..."; + + const script = document.createElement("script"); + script.src = "https://giscus.app/client.js"; + script.setAttribute("data-repo", "wenekar/giscus"); + script.setAttribute("data-repo-id", "R_kgDOREZgEQ"); + script.setAttribute("data-category", "Announcements"); + script.setAttribute("data-category-id", "DIC_kwDOREZgEc4C1nRY"); + script.setAttribute("data-mapping", "pathname"); + script.setAttribute("data-strict", "0"); + script.setAttribute("data-reactions-enabled", "1"); + script.setAttribute("data-emit-metadata", "0"); + script.setAttribute("data-input-position", "top"); + script.setAttribute("data-theme", "preferred_color_scheme"); + script.setAttribute("data-lang", "en"); + script.setAttribute("data-loading", "lazy"); + script.crossOrigin = "anonymous"; + script.async = true; + + script.addEventListener("load", () => { + isLoading = false; + hasLoaded = true; + toggle.remove(); + }); + + script.addEventListener("error", () => { + isLoading = false; + hasLoaded = false; + toggle.disabled = false; + toggle.textContent = "Show comments"; + script.remove(); + }); + + slot.appendChild(script); + if (observer) observer.disconnect(); + }; + + toggle.addEventListener("click", loadComments); + + if ("IntersectionObserver" in window && trigger instanceof HTMLElement) { + observer = new IntersectionObserver( + (entries) => { + if (entries.some((entry) => entry.isIntersecting)) loadComments(); + }, + { rootMargin: "300px 0px" }, + ); + observer.observe(trigger); + } + }; + + const initAll = () => { + document.querySelectorAll("[data-giscus-root]").forEach(initContainer); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", initAll, { once: true }); + return; + } + + initAll(); +})(); -- cgit v1.2.3