Files
dating/assets/theme-switch.js
tiennm99 bc499368a5 feat: add connect, photo slot, playlist link, freshness stamp, OS theme
- closing scene: Facebook + Instagram connect buttons (placeholder handles)
- Canh 2: portrait slot with placeholder and real-photo swap-in comment
- Canh 2: playlist link on the music claim (placeholder URL)
- closing: runtime freshness stamp from the GitHub commit date; hidden if the fetch fails
- theme: follow the OS light/dark on first visit, stored choice still wins, persist only on toggle
- commented scaffolds for owner-written vulnerability and concrete-texture beats
2026-07-25 02:29:14 +07:00

66 lines
2.4 KiB
JavaScript

// Theme toggle. The pre-paint bootstrap inline in each page head sets
// documentElement.dataset.theme before first paint (stored choice, else OS
// preference, else light); this script wires the buttons and syncs button state.
// Keep the storage key and accepted values in sync with that bootstrap script.
(() => {
const storageKey = 'dating-theme';
const buttons = document.querySelectorAll('[data-theme-option]');
/** Reflect a theme in the DOM + button state. `persist` writes the choice to
* localStorage; it is true ONLY for an explicit user toggle. The initial sync
* and OS-follow updates pass false so an implicit default is never frozen into
* a stored preference — that is what lets a first visit keep tracking the OS
* until the visitor actually picks a theme.
* @param {'light' | 'dark'} theme */
function applyTheme(theme, persist) {
document.documentElement.dataset.theme = theme;
document.documentElement.style.colorScheme = theme;
if (persist) {
try {
localStorage.setItem(storageKey, theme);
} catch {
// Keep the in-memory preference even when persistence is blocked.
}
}
for (const button of buttons) {
const active = button.dataset.themeOption === theme;
button.classList.toggle('active', active);
button.setAttribute('aria-pressed', String(active));
}
}
for (const button of buttons) {
button.addEventListener('click', () => {
applyTheme(button.dataset.themeOption === 'dark' ? 'dark' : 'light', true);
});
}
// Sync button state with the theme chosen by the pre-paint bootstrap (no persist).
applyTheme(document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light', false);
// While no explicit choice is stored, keep following live OS light/dark changes.
// A stored choice (set on toggle) suppresses this, matching "stored choice wins".
if (window.matchMedia) {
const osDark = window.matchMedia('(prefers-color-scheme: dark)');
const onOsChange = (event) => {
let stored = null;
try {
stored = localStorage.getItem(storageKey);
} catch {
// Treat unreadable storage as "no choice" and follow the OS.
}
if (stored !== 'light' && stored !== 'dark') {
applyTheme(event.matches ? 'dark' : 'light', false);
}
};
if (typeof osDark.addEventListener === 'function') {
osDark.addEventListener('change', onOsChange);
} else if (typeof osDark.addListener === 'function') {
// Older Safari fallback.
osDark.addListener(onOsChange);
}
}
})();