diff --git a/src/App.vue b/src/App.vue index 85a6e04..78ac2a6 100644 --- a/src/App.vue +++ b/src/App.vue @@ -17,7 +17,7 @@ export default { sortColumn: this.sortColumn, topics: [], isMobile: false, - currentTheme: 'dark', + currentTheme: 'auto', mediaQueryListener: null, vuetifyTheme: null, darkModeQuery: null, @@ -43,12 +43,11 @@ export default { }, methods: { initializeTheme() { - // If no saved preference, apply system preference now + // If no saved preference, default to auto const savedTheme = localStorage.getItem('theme'); if (!savedTheme) { - const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; - const theme = prefersDark ? 'dark' : 'light'; - this.applyTheme(theme); + this.currentTheme = 'auto'; + this.applyTheme('auto'); } else { this.currentTheme = savedTheme; // Apply saved theme @@ -63,12 +62,12 @@ export default { // Use arrow function to preserve 'this' context const themeChangeHandler = (e) => { - // Only auto-update theme if user hasn't set a preference manually + // Only auto-update theme if set to 'auto' const savedTheme = localStorage.getItem('theme'); - if (!savedTheme) { + if (savedTheme === 'auto' || !savedTheme) { const newTheme = e.matches ? 'dark' : 'light'; console.log('System theme changed to:', newTheme); - this.applyTheme(newTheme); + this.applyThemeActual(newTheme); } }; @@ -77,15 +76,27 @@ export default { this.themeChangeHandler = themeChangeHandler; this.darkModeQuery = darkModeQuery; }, - applyTheme(theme) { + applyTheme(theme, skipSave = false) { this.currentTheme = theme; - localStorage.setItem('theme', theme); + if (!skipSave) { + localStorage.setItem('theme', theme); + } + // Determine actual theme to apply + let actualTheme = theme; + if (theme === 'auto') { + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + actualTheme = prefersDark ? 'dark' : 'light'; + } + + this.applyThemeActual(actualTheme); + }, + applyThemeActual(actualTheme) { // Update data-bs-theme attribute for CSS variables to work - document.documentElement.setAttribute('data-bs-theme', theme === 'dark' ? 'dark' : 'light'); + document.documentElement.setAttribute('data-bs-theme', actualTheme === 'dark' ? 'dark' : 'light'); // Update HTML class for theme-based CSS selectors - if (theme === 'dark') { + if (actualTheme === 'dark') { document.documentElement.classList.add('dark-theme'); document.documentElement.classList.remove('light-theme'); } else { @@ -94,7 +105,15 @@ export default { } }, toggleTheme() { - const newTheme = this.currentTheme === 'dark' ? 'light' : 'dark'; + // Cycle through: auto -> light -> dark -> auto + let newTheme; + if (this.currentTheme === 'auto') { + newTheme = 'light'; + } else if (this.currentTheme === 'light') { + newTheme = 'dark'; + } else { + newTheme = 'auto'; + } this.applyTheme(newTheme); }, detectMobile() { @@ -186,6 +205,24 @@ export default { return dealerName.replace(re, (matchedText) => `${matchedText}`); }; }, + getThemeIcon() { + if (this.currentTheme === 'auto') { + return 'brightness_auto'; + } else if (this.currentTheme === 'dark') { + return 'light_mode'; + } else { + return 'dark_mode'; + } + }, + getThemeTitle() { + if (this.currentTheme === 'auto') { + return 'Theme: Auto (click for Light)'; + } else if (this.currentTheme === 'light') { + return 'Theme: Light (click for Dark)'; + } else { + return 'Theme: Dark (click for Auto)'; + } + }, }, }; @@ -205,8 +242,8 @@ export default { @keyup.esc="$refs.filter.blur()" class="search-input" /> - diff --git a/src/theme.css b/src/theme.css index 8681804..33b7b93 100644 --- a/src/theme.css +++ b/src/theme.css @@ -169,6 +169,7 @@ html.dark-theme .search-input:focus { transition: all 0.2s ease; font-size: 18px; padding: 0; + flex-shrink: 0; } .theme-toggle:hover {