WFDASH-WEBAPP/public/pos/theme.js
Dave 78f357de69 chore(pos): copy WFSALES POS mockup into public/pos/ (unwired)
pb-config.js deliberately not copied — it hardcoded a PocketBase
superuser email/password in client-shipped JS.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-31 01:41:54 +02:00

91 lines
3.5 KiB
JavaScript

// Shared dark-mode toggle.
// Usage: <script src="theme.js"></script> at the end of <body>.
// Set <html data-theme="light|dark|auto">. Default = light.
//
// Self-contained: the toggle works even if this file fails to load,
// because the button's inline onclick uses WFTheme.cycle() which is
// defined here AND duplicated as a fallback. We also listen for
// storage events so the theme stays in sync across tabs.
(function(){
const KEY = 'wfsales.theme';
const html = document.documentElement;
function systemPref(){
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
function apply(){
const saved = localStorage.getItem(KEY) || 'light';
const v = saved === 'auto' ? systemPref() : saved;
html.setAttribute('data-theme', v);
document.querySelectorAll('[data-theme-toggle]').forEach(btn => {
btn.setAttribute('data-current', saved);
btn.setAttribute('aria-pressed', saved === 'dark' ? 'true' : 'false');
});
}
// API
function setTheme(v){
if(!['light','dark','auto'].includes(v)) v = 'light';
try{ localStorage.setItem(KEY, v); }catch(_){}
apply();
}
function currentTheme(){
try{ return localStorage.getItem(KEY) || 'light'; }catch(_){ return 'light'; }
}
function cycleTheme(){
const cur = currentTheme();
setTheme(cur === 'light' ? 'dark' : cur === 'dark' ? 'auto' : 'light');
}
// Expose as early as possible so the button's inline onclick (which
// guards on window.WFTheme) never sees undefined.
window.WFTheme = { set: setTheme, current: currentTheme, cycle: cycleTheme };
// Also: install a global fallback so clicking the button works even
// if this script never executes (network blocked, SW serving a stale
// version, etc.). The button's inline onclick calls
// (WFTheme && WFTheme.cycle || fallback)() — we register a global
// __wfCycle function so the click always works.
window.__wfCycle = cycleTheme;
function onThemeTap(e){
let el = e.target;
while(el && el !== document){
if(el.matches && el.matches('[data-theme-toggle]')){
e.preventDefault();
e.stopPropagation();
cycleTheme();
return;
}
el = el.parentNode;
}
}
// Capture phase + both click and pointerup so the handler runs even
// if a deeper listener calls stopPropagation(), and so the toggle
// works on touch devices where the SVG is the actual target.
document.addEventListener('click', onThemeTap, true);
document.addEventListener('pointerup', onThemeTap, true);
// Also bind directly to any current or future theme buttons
function bindAll(){
document.querySelectorAll('[data-theme-toggle]').forEach(btn=>{
if(btn.__wfBound) return;
btn.__wfBound = true;
btn.addEventListener('click', e=>{
e.preventDefault(); e.stopPropagation();
cycleTheme();
});
});
}
bindAll();
// Watch for new buttons (e.g. drawer-injected HTML) and bind them
try{ new MutationObserver(bindAll).observe(document.body, {childList:true, subtree:true}); }catch(_){}
// React to system change when in auto mode
if(window.matchMedia){
try{ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ()=>{
if((currentTheme()) === 'auto') apply();
}); }catch(_){}
}
// Apply the saved theme on load
apply();
// Cross-tab sync: if the user toggles in one tab, other tabs update
window.addEventListener('storage', e=>{
if(e.key === KEY) apply();
});
})();