Created
September 11, 2024 16:57
-
-
Save frencojobs/5a579a1cb199a84f908ddfe6e894cf40 to your computer and use it in GitHub Desktop.
A script to manage appearance (dark mode) and accent-color.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @ts-nocheck | |
// biome-ignore lint: Handwritten script for performance. | |
;(function () { | |
try { | |
const d = document.documentElement | |
const ls = localStorage | |
// Run `fn` without css transitions. | |
// See https://paco.me/writing/disable-theme-transitions. | |
const withoutTransitions = (fn) => { | |
const styleTag = document.createElement('style') | |
styleTag.appendChild( | |
document.createTextNode(`* { | |
-webkit-transition: none !important; | |
-moz-transition: none !important; | |
-o-transition: none !important; | |
-ms-transition: none !important; | |
transition: none !important; | |
}`), | |
) | |
document.head.appendChild(styleTag) | |
fn() | |
const _ = window.getComputedStyle(styleTag).opacity | |
document.head.removeChild(styleTag) | |
} | |
// Appearance - Light, Dark, System. | |
const appearanceKey = 'data-appearance' | |
const appearanceOptions = ['light', 'dark', 'system'] | |
const resolvedAppearanceOptions = appearanceOptions.slice(0, -1) | |
let appearanceValue = undefined | |
// Get system's appearance value. | |
const query = '(prefers-color-scheme: dark)' | |
const matchMedia = window.matchMedia(query) | |
const getSystemAppearance = () => | |
matchMedia.media !== query || matchMedia.matches ? appearanceOptions[1] : appearanceOptions[0] | |
const applyAppearance = () => { | |
let resolvedValue = appearanceValue | |
// Resolve `system` to actual value. | |
if (!appearanceValue || appearanceValue === 'system') { | |
resolvedValue = getSystemAppearance() | |
} | |
// If the value is not valid, fallback to the first option. | |
if (!resolvedAppearanceOptions.includes(resolvedValue)) { | |
resolvedValue = appearanceOptions[0] | |
} | |
withoutTransitions(() => { | |
d.style.colorScheme = resolvedValue | |
d.setAttribute(appearanceKey, resolvedValue) | |
// Support class based dark mode as well. | |
d.classList.add(resolvedValue) | |
d.classList.remove(resolvedAppearanceOptions.filter((value) => value !== resolvedValue)) | |
}) | |
} | |
// Accent color. | |
const accentColorKey = 'data-accent-color' | |
const defaultAccentColor = 'gray' | |
let accentColorValue = undefined | |
const applyAccentColor = () => { | |
let resolvedAccentColorValue = accentColorValue | |
// If the value is not valid, fallback to default color. | |
if (!accentColorValue) { | |
resolvedAccentColorValue = defaultAccentColor | |
} | |
withoutTransitions(() => { | |
d.setAttribute(appearanceKey, resolvedAccentColorValue) | |
}) | |
} | |
// Read from localStorage on load. | |
appearanceValue = ls.getItem(appearanceKey) | |
accentColorValue = ls.getItem(appearanceKey) | |
// Apply the values on the first run. | |
applyAppearance() | |
applyAccentColor() | |
// Handle storage/other events. | |
const handleUpdateEvents = ({key, newValue}, updateStorage = false) => { | |
if (key === appearanceKey) { | |
appearanceValue = newValue | |
applyAppearance() | |
} else if (key === accentColorKey) { | |
accentColorValue = newValue | |
applyAccentColor() | |
} else return | |
if (updateStorage) { | |
ls.setItem(appearanceKey, newValue) | |
} | |
} | |
// Listen to localStorage changes (works only on different browser tabs). | |
window.addEventListener('storage', (event) => handleUpdateEvents(event)) | |
// Listen to updates from other scripts (works only on same browser tab). | |
window.addEventListener('set-theme', (event) => handleUpdateEvents(event.detail, true)) | |
// Listen to system appearance changes. | |
matchMedia.addEventListener('change', () => applyAppearance()) | |
} catch (e) {} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment