@@ -159,22 +159,41 @@ def _safe_json(obj) -> str:
159159 >
160160 </div>
161161
162- <button
163- @click="darkMode = !darkMode; localStorage.setItem('darkMode', darkMode)"
164- class="p-2 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-lg transition"
165- :aria-label="darkMode ? 'Light mode' : 'Dark mode'"
166- >
167- <template x-if="darkMode">
168- <svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">
162+ <div class="flex items-center gap-1 bg-gray-200 dark:bg-gray-700 rounded-lg p-1" role="group" aria-label="Theme">
163+ <button
164+ @click="setTheme('light')"
165+ :class="theme === 'light' ? 'bg-white dark:bg-gray-900 text-red-600 shadow-sm' : 'text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'"
166+ class="p-1.5 rounded-md transition"
167+ aria-label="Light theme"
168+ :aria-pressed="theme === 'light'"
169+ >
170+ <svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">
169171 <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z"/>
170172 </svg>
171- </template>
172- <template x-if="!darkMode">
173- <svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">
173+ </button>
174+ <button
175+ @click="setTheme('system')"
176+ :class="theme === 'system' ? 'bg-white dark:bg-gray-900 text-red-600 shadow-sm' : 'text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'"
177+ class="p-1.5 rounded-md transition"
178+ aria-label="Use system theme"
179+ :aria-pressed="theme === 'system'"
180+ >
181+ <svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">
182+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 0 1-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0 1 15 18.257V17.25m6-12V15a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 15V5.25m18 0A2.25 2.25 0 0 0 18.75 3H5.25A2.25 2.25 0 0 0 3 5.25m18 0V12a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 12V5.25"/>
183+ </svg>
184+ </button>
185+ <button
186+ @click="setTheme('dark')"
187+ :class="theme === 'dark' ? 'bg-white dark:bg-gray-900 text-red-600 shadow-sm' : 'text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'"
188+ class="p-1.5 rounded-md transition"
189+ aria-label="Dark theme"
190+ :aria-pressed="theme === 'dark'"
191+ >
192+ <svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">
174193 <path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z"/>
175194 </svg>
176- </template >
177- </button >
195+ </button >
196+ </div >
178197 </div>
179198 </header>
180199
@@ -428,7 +447,21 @@ def _safe_json(obj) -> str:
428447 search: '',
429448 activeCategory: null,
430449 activeTags: [],
431- darkMode: localStorage.getItem('darkMode') === 'true',
450+ theme: localStorage.getItem('theme') || 'system',
451+ osDark: window.matchMedia('(prefers-color-scheme: dark)').matches,
452+
453+ get darkMode() {
454+ return this.theme === 'system' ? this.osDark : this.theme === 'dark';
455+ },
456+
457+ setTheme(t) {
458+ this.theme = t;
459+ if (t === 'system') {
460+ localStorage.removeItem('theme');
461+ } else {
462+ localStorage.setItem('theme', t);
463+ }
464+ },
432465
433466 get filtered() {
434467 return this.scripts.filter(script => {
@@ -470,6 +503,11 @@ def _safe_json(obj) -> str:
470503 },
471504
472505 init() {
506+ // Follow OS theme changes live while no explicit choice overrides it
507+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
508+ this.osDark = e.matches;
509+ });
510+
473511 // Listen for filter-tag events from tag chips
474512 window.addEventListener('filter-tag', (e) => {
475513 this.toggleTag(e.detail.tag);
0 commit comments