diff mrjunejune/src/index.js @ 256:30c2196d03d4

[site] Integrate Zenbu themes and components Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Tue, 04 Aug 2026 16:49:01 -0700
parents bcc76a156aea
children 60a876c4587a
line wrap: on
line diff
--- a/mrjunejune/src/index.js	Tue Aug 04 15:12:18 2026 -0700
+++ b/mrjunejune/src/index.js	Tue Aug 04 16:49:01 2026 -0700
@@ -1,50 +1,74 @@
 const THEME_STORAGE_KEY = 'theme-preference';
-// Get stored preference or detect system preference
-function getThemePreference()
-{
-  const stored = localStorage.getItem(THEME_STORAGE_KEY);
-  if (stored) {
-    return stored;
-  }
-  return 'auto';
+const THEMES = ['auto', 'paper', 'ink', 'playful'];
+const THEME_LABELS = {
+  auto: 'Auto',
+  paper: 'Paper',
+  ink: 'Ink',
+  playful: 'Playful',
+};
+
+function normalizeTheme(value) {
+  if (value === 'light') return 'paper';
+  if (value === 'dark') return 'ink';
+  return THEMES.includes(value) ? value : 'auto';
+}
+
+function getThemePreference() {
+  return normalizeTheme(localStorage.getItem(THEME_STORAGE_KEY));
+}
+
+function updateThemeColor() {
+  const probe = document.createElement('span');
+  probe.style.background = 'var(--zen-color-canvas)';
+  document.body.append(probe);
+  const color = getComputedStyle(probe).backgroundColor;
+  probe.remove();
+  document.querySelector('meta[name="theme-color"]')
+    ?.setAttribute('content', color);
 }
 
-function applyTheme(preference)
-{
-  const root = document.documentElement;
-
-  if (preference === 'light') {
-    root.classList.remove('dark', 'auto');
-    root.classList.add('light-mode');
-  } else if (preference === 'dark') {
-    root.classList.remove('light-mode', 'auto');
-    root.classList.add('dark');
-  } else {
-    // Auto - remove manual overrides and let CSS media query handle it
-    root.classList.remove('light-mode', 'dark');
-    root.classList.add('auto');
-  }
+function updateThemeControl(preference) {
+  const toggle = document.querySelector('#themeToggle');
+  const label = document.querySelector('#themeName');
+  if (label) label.textContent = THEME_LABELS[preference];
+  toggle?.setAttribute(
+    'aria-label',
+    `Change site theme. Current theme: ${THEME_LABELS[preference]}`,
+  );
 }
 
-(function() {
-  const currentPreference = getThemePreference();
-  applyTheme(currentPreference);
-})();
-
-/* Toggle lights auto and dark */
-const toggle = document.querySelector('#themeToggle');
-toggle.addEventListener('click', function() {
-  let preference = getThemePreference();
+function applyTheme(value, persist = false) {
+  const preference = normalizeTheme(value);
+  const root = document.documentElement;
+  root.classList.remove('light-mode', 'dark', 'auto');
+  if (preference === 'auto') delete root.dataset.zenTheme;
+  else root.dataset.zenTheme = preference;
+  if (persist) localStorage.setItem(THEME_STORAGE_KEY, preference);
+  updateThemeControl(preference);
+  requestAnimationFrame(updateThemeColor);
+  document.dispatchEvent(new CustomEvent('zen-theme-change', {
+    detail: { theme: preference },
+  }));
+  return preference;
+}
 
-  // Cycle through: auto -> light -> dark -> auto
-  if (preference === 'auto') {
-    preference = 'light';
-  } else if (preference === 'light') {
-    preference = 'dark';
-  } else {
-    preference = 'auto';
-  }
+const currentPreference = applyTheme(getThemePreference());
+if (localStorage.getItem(THEME_STORAGE_KEY) !== currentPreference) {
+  localStorage.setItem(THEME_STORAGE_KEY, currentPreference);
+}
 
-  localStorage.setItem(THEME_STORAGE_KEY, preference);
-  applyTheme(preference);
+document.querySelector('#themeToggle')?.addEventListener('click', () => {
+  const current = getThemePreference();
+  const next = THEMES[(THEMES.indexOf(current) + 1) % THEMES.length];
+  applyTheme(next, true);
 });
+
+matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
+  if (getThemePreference() === 'auto') updateThemeColor();
+});
+
+window.MrJuneJuneTheme = Object.freeze({
+  apply: theme => applyTheme(theme, true),
+  current: getThemePreference,
+  themes: [...THEMES],
+});