Fork of Chiri for Astro for my blog
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at d53cf66a7c485bc65a203dfd645442c65b48b58e 122 lines 3.8 kB view raw
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>