* Ikke type="module" og ikke defer: da venter skriptet til HTML er lest, og * siden males lys før den blir mørk. Skriptet har ingen inline-kode, så det * virker under script-src 'self'. * * Skriver på : * data-theme="light|dark" temaet tokens.css bruker * data-tema-valg="auto|lys|mork" brukerens valg * style.colorScheme nettleserens egne felt og rullefelt følger temaet * * Gir window.sannTema (se tema.d.ts). Temabryteren (temabryter.js) bruker det. */ (() => { 'use strict'; if (window.sannTema) return; // Lastet to ganger: behold den første. const NØKKEL = 'sann-tema'; const VERDIER = ['auto', 'lys', 'mork']; const rot = document.documentElement; // 'screen and', som i kartet: ved utskrift skal ikke enhetens tema telle. const mørkEnhet = window.matchMedia ? window.matchMedia('screen and (prefers-color-scheme: dark)') : null; // Ukjente verdier gir auto, men skrives ikke over før brukeren velger. const les = () => { try { const v = window.localStorage.getItem(NØKKEL); return VERDIER.includes(v) ? v : 'auto'; } catch { return 'auto'; } }; let valg = les(); let lagringVirker = true; let skrives = false; // Mellom beforeprint og afterprint. const lyttere = new Set(); const enhetMørk = () => Boolean(mørkEnhet && mørkEnhet.matches); const tema = () => ((valg === 'auto' ? enhetMørk() : valg === 'mork') ? 'dark' : 'light'); const tilstand = () => ({ valg, tema: tema(), enhetMørk: enhetMørk(), lagringVirker }); const sett = (t) => { rot.setAttribute('data-theme', t); rot.style.colorScheme = t; }; const bruk = () => { rot.setAttribute('data-tema-valg', valg); if (!skrives) sett(tema()); }; const varsle = () => { const t = tilstand(); for (const fn of lyttere) { try { fn(t); } catch (e) { // En feil hos én lytter skal ikke stoppe de andre. setTimeout(() => { throw e; }); } } }; const oppdater = () => { bruk(); varsle(); }; const velg = (v) => { if (!VERDIER.includes(v)) throw new RangeError('sannTema.velg: ukjent verdi «' + v + '». Bruk auto, lys eller mork.'); valg = v; try { window.localStorage.setItem(NØKKEL, v); lagringVirker = true; } catch { // Valget gjelder likevel for siden som er åpen. lagringVirker = false; } oppdater(); return lagringVirker; }; const abonner = (fn) => { lyttere.add(fn); return () => lyttere.delete(fn); }; // Enheten bytter: bare Auto følger med. if (mørkEnhet) { const vedEndring = () => { if (valg === 'auto') oppdater(); }; if (mørkEnhet.addEventListener) mørkEnhet.addEventListener('change', vedEndring); else if (mørkEnhet.addListener) mørkEnhet.addListener(vedEndring); // Safari < 14 } // En annen fane på samme nettsted har valgt. key er null når lagringen tømmes. window.addEventListener('storage', (e) => { if (e.key !== NØKKEL && e.key !== null) return; valg = les(); oppdater(); }); // Utskrift er alltid lys. Etterpå gjelder valget igjen, ikke nettleseren. window.addEventListener('beforeprint', () => { skrives = true; sett('light'); }); window.addEventListener('afterprint', () => { skrives = false; bruk(); }); bruk(); window.sannTema = Object.freeze({ nøkkel: NØKKEL, verdier: Object.freeze(VERDIER.slice()), valg: () => valg, tema, enhetMørk, lagringVirker: () => lagringVirker, tilstand, velg, abonner, }); })();
STAGING7602576
SannSann

Et rolig verktøy
for urolige øyeblikk.

Sann er en felles arbeidsflate for arrangementer — der meldinger loggføres, saker eskaleres og beslutninger dokumenteres. Mens det skjer.

Logg inn

Fortsett til arrangementet ditt.