// #16/#100/#127: theme preset resolution. Runs in (blocking) so the // correct data-preset is set before first paint. The server default dark flag // arrives via the script tag's data-default-dark attribute so no inline script is needed. // #130: shared line wrap preference (localStorage 'palette-wrap', default off). // preset hook (#16): ?theme= wins; else persisted choice (#100). // #127: theme pairs - each base theme has a light and dark variant; // palette-theme stores the base id, palette-dark the dark flag. (function () { var PAIRS = { 'midnight': { light: 'midnight-light', dark: 'midnight' }, 'smooth': { light: 'smooth', dark: 'smooth-dark' }, 'pastel-lavender': { light: 'pastel-lavender', dark: 'pastel-lavender-dark' }, 'pastel-peach': { light: 'pastel-peach', dark: 'pastel-peach-dark' }, 'pastel-cloud': { light: 'pastel-cloud', dark: 'pastel-cloud-dark' } }; function resolve(t, dark) { for (var base in PAIRS) { if (t === PAIRS[base].light || t === PAIRS[base].dark) return t; if (t === base) return dark ? PAIRS[base].dark : PAIRS[base].light; } return null; } var t = new URLSearchParams(location.search).get('theme'); // precedence: URL ?theme= > stored pair+dark prefs > server default dark > dark on var dark = (document.currentScript && document.currentScript.getAttribute('data-default-dark')) === '1'; try { var stored = localStorage.getItem('palette-dark'); if (stored !== null) dark = stored !== 'false'; } catch (e) {} if (t) { // URL ?theme= wins and accepts both base and variant ids; a variant id // also sets the dark flag and normalizes t back to its base pair id. var found = false; for (var base in PAIRS) { if (t === PAIRS[base].dark) { dark = true; t = base; found = true; break; } if (t === PAIRS[base].light) { dark = false; t = base; found = true; break; } if (t === base) { found = true; break; } } if (!found) t = null; } if (!t) { try { t = localStorage.getItem('palette-theme'); } catch (e) {} } if (!PAIRS[t]) t = 'midnight'; // do not persist anything here: URL theme is a one-off override document.documentElement.dataset.preset = dark ? PAIRS[t].dark : PAIRS[t].light; })(); // #130: shared line wrap preference (localStorage 'palette-wrap', default off) (function () { function wrapOn() { try { return localStorage.getItem('palette-wrap') === '1'; } catch (e) { return false; } } function wrapApply(on) { if (on) document.documentElement.setAttribute('data-wrap', '1'); else document.documentElement.removeAttribute('data-wrap'); document.querySelectorAll('.wrap-toggle').forEach(function (b) { b.setAttribute('aria-pressed', on ? 'true' : 'false'); }); var s = document.getElementById('wrap-setting'); if (s) s.checked = on; } window.paletteWrapToggle = function () { var on = !wrapOn(); try { localStorage.setItem('palette-wrap', on ? '1' : '0'); } catch (e) {} wrapApply(on); return on; }; document.addEventListener('DOMContentLoaded', function () { wrapApply(wrapOn()); document.querySelectorAll('.wrap-toggle').forEach(function (b) { b.addEventListener('click', function () { window.paletteWrapToggle(); }); }); var s = document.getElementById('wrap-setting'); if (s) s.addEventListener('change', function () { if (s.checked !== wrapOn()) window.paletteWrapToggle(); }); }); })();