The Alpine.js state was reading from localStorage instead of the actual
class on the html element, causing the icon to be out of sync with the
actual theme. Now we initialize the Alpine state by checking the current
html classList, which is set by the page-load script in baseof.html.
Co-Authored-By: Claude Haiku 4.5 <redacted>
<!-- Theme toggle button -->
<button
id="theme-toggle"
- x-data="{ theme: localStorage.getItem('theme') || 'dark' }"
- @click="theme = theme === 'dark' ? 'light' : 'dark'; document.documentElement.className = 'theme-' + theme; localStorage.setItem('theme', theme)"
+ x-data="{
+ theme: document.documentElement.classList.contains('theme-light') ? 'light' : 'dark',
+ toggle() {
+ this.theme = this.theme === 'dark' ? 'light' : 'dark';
+ document.documentElement.className = 'theme-' + this.theme;
+ localStorage.setItem('theme', this.theme);
+ }
+ }"
+ @click="toggle()"
aria-label="{{ i18n "toggleTheme" }}"
class="p-2 rounded hover:bg-surface transition-colors"
>