-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy paththeme.ts
More file actions
74 lines (60 loc) · 2.14 KB
/
theme.ts
File metadata and controls
74 lines (60 loc) · 2.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
export type ThemePreference = 'light' | 'dark'
export const SYSTEM_PREFERENCE_DARK = '(prefers-color-scheme: dark)'
export const SESSION_STORAGE_NAME = 'preferred-theme'
export const THEME_CHANGE_EVENT = 'theme-change'
export const COLORS = {
light: '#e7eef4',
dark: '#1d2224'
}
// Assumes a theme has already been applied by a script
// before this module is loaded. We do this in `<head>`.
let currentTheme: ThemePreference = getDocumentTheme()
export function getDocumentTheme(): ThemePreference {
return document.documentElement.getAttribute('data-theme') === 'dark'
? 'dark'
: 'light'
}
export function applyTheme(theme: ThemePreference): void {
const color = COLORS[theme]
const htmlEl = document.documentElement
const metaThemeColor = document.querySelector('meta[name=theme-color]')
htmlEl.setAttribute('data-theme', theme)
htmlEl.setAttribute('data-theme-color', color)
metaThemeColor?.setAttribute('content', color)
}
export function saveTheme(theme: ThemePreference): void {
sessionStorage.setItem(SESSION_STORAGE_NAME, theme)
}
function broadcastTheme(theme: ThemePreference): void {
applyTheme(theme)
document.dispatchEvent(
new CustomEvent<ThemePreference>(THEME_CHANGE_EVENT, { detail: theme })
)
}
export function setTheme(theme: ThemePreference, shouldPersist = true): void {
const themeChanged = currentTheme !== theme
if (themeChanged) {
currentTheme = theme
if (shouldPersist) saveTheme(theme)
}
broadcastTheme(theme)
}
let listenersAdded = false
export function addThemeListeners(): void {
if (listenersAdded) return
listenersAdded = true
const systemPreference = window.matchMedia(SYSTEM_PREFERENCE_DARK)
systemPreference.addEventListener('change', (event) => {
setTheme(event.matches ? 'dark' : 'light', false)
})
document.addEventListener(THEME_CHANGE_EVENT, (event) => {
const customEvent = event as CustomEvent<ThemePreference | undefined>
if (customEvent.detail && customEvent.detail !== currentTheme) {
setTheme(customEvent.detail, true)
}
})
}
// For testing: reset the listeners flag
export function __resetListeners(): void {
listenersAdded = false
}