forked from
quillmatiq.com/augment
Fork of Chiri for Astro for my blog
1<script is:inline>
2 // Global Theme Manager
3 ;(function () {
4 // Prevent duplicate initialization
5 if (window.ThemeManager && window.ThemeManager.initialized) {
6 return
7 }
8
9 window.ThemeManager = {
10 STORAGE_KEY: 'chiri-theme',
11 initialized: false,
12
13 getSystemTheme() {
14 return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
15 },
16
17 getStoredTheme() {
18 try {
19 return localStorage.getItem(this.STORAGE_KEY)
20 } catch {
21 return null
22 }
23 },
24
25 setStoredTheme(theme) {
26 try {
27 if (theme === 'system') {
28 localStorage.removeItem(this.STORAGE_KEY)
29 } else {
30 localStorage.setItem(this.STORAGE_KEY, theme)
31 }
32 } catch (e) {
33 console.warn('Failed to store theme preference:', e)
34 }
35 },
36
37 getEffectiveTheme() {
38 const stored = this.getStoredTheme()
39 return stored || this.getSystemTheme()
40 },
41
42 isUsingSystemTheme() {
43 return this.getStoredTheme() === null
44 },
45
46 applyTheme(theme) {
47 document.documentElement.classList.remove('light', 'dark')
48 document.documentElement.classList.add(theme)
49
50 // Dispatch event for other components
51 document.dispatchEvent(
52 new CustomEvent('themechange', {
53 detail: {
54 theme,
55 isUserChoice: !this.isUsingSystemTheme(),
56 isSystemTheme: this.isUsingSystemTheme()
57 }
58 })
59 )
60 },
61
62 toggle() {
63 const currentTheme = this.getEffectiveTheme()
64 // Simply toggle between light and dark
65 const newTheme = currentTheme === 'dark' ? 'light' : 'dark'
66
67 this.setStoredTheme(newTheme)
68 this.applyTheme(newTheme)
69 },
70
71 init() {
72 if (this.initialized) return
73
74 // Set initial theme (maintain current theme when refreshing page)
75 this.applyTheme(this.getEffectiveTheme())
76
77 // Listen for system theme changes
78 window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
79 const newSystemTheme = e.matches ? 'dark' : 'light'
80
81 // Always follow system theme changes and update stored theme preference
82 this.setStoredTheme(newSystemTheme)
83 this.applyTheme(newSystemTheme)
84 })
85
86 this.initialized = true
87 }
88 }
89
90 // Initialize theme manager
91 window.ThemeManager.init()
92
93 // Listen for Astro page transition events, but delay execution to avoid conflicts with transition animations
94 document.addEventListener('astro:page-load', () => {
95 if (window.ThemeManager) {
96 // Use requestAnimationFrame to ensure execution in the next frame, avoiding conflicts with transition animations
97 requestAnimationFrame(() => {
98 const currentTheme = window.ThemeManager.getEffectiveTheme()
99 const appliedTheme = document.documentElement.classList.contains('dark')
100 ? 'dark'
101 : 'light'
102
103 // Only reapply theme when there's a mismatch to avoid unnecessary flickering
104 if (currentTheme !== appliedTheme) {
105 window.ThemeManager.applyTheme(currentTheme)
106 }
107 })
108 }
109 })
110
111 // Listen for page transition start event to ensure theme is ready before transition
112 document.addEventListener('astro:before-preparation', () => {
113 if (window.ThemeManager) {
114 const theme = window.ThemeManager.getEffectiveTheme()
115 // Ensure theme class is applied before transition starts
116 if (!document.documentElement.classList.contains(theme)) {
117 document.documentElement.classList.add(theme)
118 }
119 }
120 })
121 })()
122</script>