summaryrefslogtreecommitdiff
path: root/site/themes/sine/static/js
diff options
context:
space:
mode:
Diffstat (limited to 'site/themes/sine/static/js')
-rw-r--r--site/themes/sine/static/js/background.js82
-rw-r--r--site/themes/sine/static/js/switch-theme.js88
2 files changed, 170 insertions, 0 deletions
diff --git a/site/themes/sine/static/js/background.js b/site/themes/sine/static/js/background.js
new file mode 100644
index 0000000..e9b61a2
--- /dev/null
+++ b/site/themes/sine/static/js/background.js
@@ -0,0 +1,82 @@
+document.addEventListener("DOMContentLoaded", () => {
+ const canvas = document.getElementById("background");
+ if (!canvas) return;
+ const ctx = canvas.getContext("2d");
+
+ // Grab config from the embedded <script>
+ const configEl = document.getElementById("background-config");
+ const config = configEl ? JSON.parse(configEl.textContent) : {};
+
+ // Use config values with defaults as fallback
+ const spacing = config.spacing ?? 24;
+ const maxRadius = config.maxRadius ?? 8;
+ const baseOffset = config.baseOffset ?? 120;
+ const freq = config.freq ?? 0.008;
+ const speed = config.speed ?? 0.02;
+
+ const baseAmp = config.baseAmp ?? 100;
+ const env1Freq = config.envelope1Freq ?? 0.002;
+ const env1Amp = config.envelope1Amp ?? 120;
+ const env2Freq = config.envelope2Freq ?? 0.0005;
+ const env2Amp = config.envelope2Amp ?? 200;
+
+ let t = parseFloat(localStorage.getItem("waveProgress")) || 0;
+ let widthCss = window.innerWidth;
+ let heightCss = window.innerHeight;
+ let pixelRatio = window.devicePixelRatio || 1;
+
+ function resize() {
+ widthCss = window.innerWidth;
+ heightCss = window.innerHeight;
+ pixelRatio = window.devicePixelRatio || 1;
+
+ canvas.width = Math.floor(widthCss * pixelRatio);
+ canvas.height = Math.floor(heightCss * pixelRatio);
+ canvas.style.width = widthCss + "px";
+ canvas.style.height = heightCss + "px";
+ ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
+ }
+ window.addEventListener("resize", resize);
+ resize();
+
+ function draw() {
+ const styles = getComputedStyle(document.documentElement);
+ const fg = styles.getPropertyValue("--fg").trim();
+
+ ctx.clearRect(0, 0, widthCss, heightCss);
+ ctx.fillStyle = fg;
+
+ for (let x = 0; x <= widthCss + spacing; x += spacing) {
+ // envelope: controls crest variance
+ const envelope =
+ baseAmp
+ + Math.sin(x * env1Freq + t * 0.1) * env1Amp
+ + Math.sin(x * env2Freq + t * 0.05) * env2Amp;
+
+ const waveY = heightCss - (Math.sin(x * freq + t) * envelope + baseOffset);
+ // const waveY = Math.max(heightCss - 50, heightCss - (Math.sin(x * freq + t) * envelope + baseOffset));
+
+ for (let y = heightCss; y >= 0; y -= spacing) {
+ const dist = Math.max(0, y - waveY);
+ const radius = Math.min(maxRadius, dist / 40);
+ if (radius > 0.2) {
+ ctx.beginPath();
+ // ctx.arc(x + spacing / 2, y - spacing / 2, radius, 0, Math.PI * 2);
+ ctx.fillRect(
+ x + spacing / 2 - radius,
+ y - spacing / 2 - radius,
+ radius * 2,
+ radius * 2
+ );
+ ctx.fill();
+ }
+ }
+ }
+
+ t += speed;
+ localStorage.setItem("waveProgress", t);
+ requestAnimationFrame(draw);
+ }
+
+ draw();
+});
diff --git a/site/themes/sine/static/js/switch-theme.js b/site/themes/sine/static/js/switch-theme.js
new file mode 100644
index 0000000..5052f39
--- /dev/null
+++ b/site/themes/sine/static/js/switch-theme.js
@@ -0,0 +1,88 @@
+// const root = document.documentElement; // <html>, not <body>
+// const btn = document.getElementById("toggleTheme");
+//
+// const savedTheme = localStorage.getItem("theme") || "light";
+// root.className = savedTheme;
+// btn.innerHTML = savedTheme === "dark" ? "✧" : "☾";
+//
+// btn.addEventListener("click", () => {
+// const newTheme = root.classList.contains("light") ? "dark" : "light";
+// root.className = newTheme;
+// localStorage.setItem("theme", newTheme);
+// btn.innerHTML = newTheme === "dark" ? "✧" : "☾";
+// });
+
+/**
+* Utility function to calculate the current theme setting.
+* Look for a local storage value.
+* Fall back to system setting.
+* Fall back to light mode.
+*/
+function calculateSettingAsThemeString({ localStorageTheme, systemSettingDark }) {
+ if (localStorageTheme !== null) {
+ return localStorageTheme;
+ }
+
+ if (systemSettingDark.matches) {
+ return "dark";
+ }
+
+ return "light";
+}
+
+/**
+* Utility function to update the button text and aria-label.
+*/
+function updateButton({ buttonEl, isDark }) {
+ const newCta = isDark ? "Change to light theme" : "Change to dark theme";
+
+ const newInnerText = isDark ? "✧" : "☾";
+ // use an aria-label if you are omitting text on the button
+ // and using a sun/moon icon, for example
+ buttonEl.setAttribute("aria-label", newCta);
+ buttonEl.innerText = newInnerText;
+}
+
+/**
+* Utility function to update the theme setting on the html tag
+*/
+function updateThemeOnHtmlEl({ theme }) {
+ document.querySelector("html").setAttribute("data-theme", theme);
+}
+
+
+/**
+* On page load:
+*/
+
+/**
+* 1. Grab what we need from the DOM and system settings on page load
+*/
+const button = document.querySelector("[data-theme-toggle]");
+const localStorageTheme = localStorage.getItem("theme");
+const systemSettingDark = window.matchMedia("(prefers-color-scheme: dark)");
+
+/**
+* 2. Work out the current site settings
+*/
+let currentThemeSetting = calculateSettingAsThemeString({ localStorageTheme, systemSettingDark });
+
+/**
+* 3. Update the theme setting and button text accoridng to current settings
+*/
+updateButton({ buttonEl: button, isDark: currentThemeSetting === "dark" });
+updateThemeOnHtmlEl({ theme: currentThemeSetting });
+
+/**
+* 4. Add an event listener to toggle the theme
+*/
+button.addEventListener("click", (event) => {
+ const newTheme = currentThemeSetting === "dark" ? "light" : "dark";
+
+ localStorage.setItem("theme", newTheme);
+ updateButton({ buttonEl: button, isDark: newTheme === "dark" });
+ updateThemeOnHtmlEl({ theme: newTheme });
+
+ currentThemeSetting = newTheme;
+});
+