1 ---
2 import { SITE } from '@/config'
3 ---
4
5 {
6 SITE.themeToggle && (
7 <button id="theme-toggle" class="theme-toggle" aria-label="Toggle theme">
8 <div class="theme-icon hollow-circle" />
9 <div class="theme-icon solid-circle" />
10 </button>
11 )
12 }
13
14 <script is:inline>
15 window.addEventListener('DOMContentLoaded', function () {
16 const htmlElement = document.documentElement
17
18 // Get system theme preference
19 function getSystemTheme() {
20 const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
21 return isDark ? 'dark' : 'light'
22 }
23
24 // Get current actual theme state
25 function getCurrentTheme() {
26 const hasLight = htmlElement.classList.contains('light')
27 const hasDark = htmlElement.classList.contains('dark')
28
29 if (hasLight) {
30 return 'light'
31 }
32 if (hasDark) {
33 return 'dark'
34 }
35
36 const systemTheme = getSystemTheme()
37 return systemTheme
38 }
39
40 // Apply theme
41 function applyTheme(theme) {
42 htmlElement.classList.remove('light', 'dark')
43
44 if (theme === 'dark') {
45 htmlElement.classList.add('dark')
46 } else {
47 htmlElement.classList.add('light')
48 }
49 }
50
51 // Initialize theme - ensure explicit classes are always present
52 function initTheme() {
53 const systemTheme = getSystemTheme()
54 applyTheme(systemTheme)
55 }
56
57 // Listen for system theme changes
58 const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
59 mediaQuery.addEventListener('change', function (e) {
60 const newTheme = e.matches ? 'dark' : 'light'
61 applyTheme(newTheme)
62 })
63
64 // Get theme toggle button (only if it exists)
65 const themeToggle = document.getElementById('theme-toggle')
66 if (themeToggle) {
67 // Toggle theme function
68 function toggleTheme() {
69 const currentTheme = getCurrentTheme()
70 const newTheme = currentTheme === 'dark' ? 'light' : 'dark'
71 applyTheme(newTheme)
72 }
73
74 themeToggle.addEventListener('click', function (e) {
75 e.preventDefault()
76 e.stopPropagation()
77 toggleTheme()
78 })
79 }
80
81 initTheme()
82 })
83 </script>
84
85 <style>
86 .theme-toggle {
87 background: none;
88 border: none;
89 cursor: pointer;
90 display: flex;
91 align-items: center;
92 height: 1.5rem;
93 gap: 0.325rem;
94 color: var(--text-primary);
95 transition: opacity 0.2s ease;
96 padding: 0;
97 position: relative;
98 }
99
100 .theme-toggle:hover {
101 opacity: 0.7;
102 }
103
104 .theme-toggle:active {
105 opacity: 0.5;
106 }
107
108 .theme-icon {
109 width: 0.5625rem;
110 height: 0.5625rem;
111 transition: all 0.2s ease;
112 }
113
114 .hollow-circle {
115 border: none;
116 border-radius: 50%;
117 box-shadow: inset 0 0 0 1.5px var(--text-primary);
118 }
119
120 .solid-circle {
121 background-color: var(--text-primary);
122 border-radius: 50%;
123 }
124 </style>