← back to Ventura Corridor
public/theme.js
53 lines
/**
* Theme toggle — sun/moon, persists via localStorage.
*
* Inverts the noir-on-metal palette: --noir↔--ink, --noir-rise↔--noir-rise (compute), etc.
* Applied via a single body class `light` that swaps CSS vars at the :root level.
*
* Anti-flash: this script runs synchronously inline in <head>, so the class is set
* before first paint.
*
* Usage: drop <script src="/theme.js" defer></script> in <head> AFTER an inline
* antiflash snippet, then call attachThemeToggle(parentEl) from page JS.
*/
(function() {
const KEY = 'vc-theme';
const stored = (function () { try { return localStorage.getItem(KEY); } catch { return null; } })();
const initial = stored === 'light' || stored === 'dark' ? stored : 'dark';
document.documentElement.dataset.theme = initial;
function setTheme(t) {
document.documentElement.dataset.theme = t;
try { localStorage.setItem(KEY, t); } catch {}
document.querySelectorAll('.theme-toggle').forEach(btn => {
btn.textContent = t === 'light' ? '☾' : '☀';
btn.title = t === 'light' ? 'Switch to dark' : 'Switch to light';
});
}
window.toggleTheme = function() {
const cur = document.documentElement.dataset.theme || 'dark';
setTheme(cur === 'dark' ? 'light' : 'dark');
};
window.attachThemeToggle = function(parent) {
if (!parent) return;
if (parent.querySelector('.theme-toggle')) return;
const btn = document.createElement('button');
btn.className = 'theme-toggle';
btn.type = 'button';
btn.setAttribute('aria-label', 'Toggle dark / light theme');
btn.style.cssText = 'background:transparent;border:1px solid var(--rule);color:var(--ink-mute);font-size:13px;padding:4px 10px;cursor:pointer;letter-spacing:.1em;font-family:inherit;line-height:1.2;height:28px;';
btn.addEventListener('click', toggleTheme);
btn.addEventListener('mouseenter', () => { btn.style.borderColor = 'var(--metal)'; btn.style.color = 'var(--metal)'; });
btn.addEventListener('mouseleave', () => { btn.style.borderColor = 'var(--rule)'; btn.style.color = 'var(--ink-mute)'; });
parent.appendChild(btn);
setTheme(document.documentElement.dataset.theme || 'dark');
};
// Auto-attach to any element with class "theme-toggle-host"
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.theme-toggle-host').forEach(host => attachThemeToggle(host));
});
})();