-
-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathDarkMode.astro
89 lines (78 loc) · 3.21 KB
/
DarkMode.astro
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
---
interface Props {
initialMode?: 'light' | 'dark' | 'auto'
}
const { initialMode = 'auto' } = Astro.props
---
<button
class="darkmode-toggle"
aria-pressed="false"
aria-label="Toggle Dark Mode"
data-initial-mode={initialMode}
transition:persist
>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="32" height="32" viewBox="0 0 24 24"
><path
fill="currentColor"
d="M9.353 3C5.849 4.408 3 7.463 3 11.47A9.53 9.53 0 0 0 12.53 21c4.007 0 7.062-2.849 8.47-6.353C8.17 17.065 8.14 8.14 9.353 3z"
></path></svg
>
</button>
<script is:inline define:vars={{ initialMode }}>
// variables
let darkMode = localStorage.getItem('darkMode')
const darkModeToggle = document.querySelector('.darkmode-toggle')
const root = document.documentElement
// functions
const enableDarkMode = (store = true) => {
root.classList.add('darkmode')
root.style.colorScheme = 'dark'
darkModeToggle.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="32" height="32" viewBox="0 0 24 24"><path fill-rule="evenodd" clip-rule="evenodd" d="M13 3a1 1 0 1 0-2 0v1a1 1 0 1 0 2 0V3zM5.707 4.293a1 1 0 0 0-1.414 1.414l1 1a1 1 0 0 0 1.414-1.414l-1-1zm14 0a1 1 0 0 0-1.414 0l-1 1a1 1 0 0 0 1.414 1.414l1-1a1 1 0 0 0 0-1.414zM12 7a5 5 0 1 0 0 10 5 5 0 0 0 0-10zm-9 4a1 1 0 1 0 0 2h1a1 1 0 1 0 0-2H3zm17 0a1 1 0 1 0 0 2h1a1 1 0 1 0 0-2h-1zM6.707 18.707a1 1 0 1 0-1.414-1.414l-1 1a1 1 0 1 0 1.414 1.414l1-1zm12-1.414a1 1 0 0 0-1.414 1.414l1 1a1 1 0 0 0 1.414-1.414l-1-1zM13 20a1 1 0 1 0-2 0v1a1 1 0 1 0 2 0v-1z" fill="currentColor"/></svg>`
darkModeToggle.setAttribute('aria-pressed', 'true')
if (store) localStorage.setItem('darkMode', 'enabled')
}
const disableDarkMode = (store = true) => {
root.classList.remove('darkmode')
root.style.colorScheme = 'light'
darkModeToggle.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M9.353 3C5.849 4.408 3 7.463 3 11.47A9.53 9.53 0 0 0 12.53 21c4.007 0 7.062-2.849 8.47-6.353C8.17 17.065 8.14 8.14 9.353 3z"/></svg>`
darkModeToggle.setAttribute('aria-pressed', 'false')
if (store) localStorage.setItem('darkMode', 'disabled')
}
const checkPreference = () => {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
enableDarkMode(false)
} else {
disableDarkMode(false)
}
}
// Initial setup based on props
const initializeDarkMode = () => {
if (darkMode) {
// If user has a preference, respect that first
darkMode === 'enabled' ? enableDarkMode() : disableDarkMode()
return
}
// Handle initial mode
switch (initialMode) {
case 'dark':
enableDarkMode()
break
case 'light':
disableDarkMode()
break
default: // 'auto'
checkPreference()
}
}
// execution
initializeDarkMode()
darkModeToggle.addEventListener('click', () => {
darkMode = root.classList.contains('darkmode')
!darkMode ? enableDarkMode() : disableDarkMode()
})
// Listen for view transitions
document.addEventListener('astro:after-swap', () => {
darkMode = localStorage.getItem('darkMode')
initializeDarkMode()
})
</script>