mirror of
https://github.com/davegallant/rfd-fyi.git
synced 2026-03-03 17:46:35 +00:00
Add auto theme toggle
This commit is contained in:
65
src/App.vue
65
src/App.vue
@@ -17,7 +17,7 @@ export default {
|
|||||||
sortColumn: this.sortColumn,
|
sortColumn: this.sortColumn,
|
||||||
topics: [],
|
topics: [],
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
currentTheme: 'dark',
|
currentTheme: 'auto',
|
||||||
mediaQueryListener: null,
|
mediaQueryListener: null,
|
||||||
vuetifyTheme: null,
|
vuetifyTheme: null,
|
||||||
darkModeQuery: null,
|
darkModeQuery: null,
|
||||||
@@ -43,12 +43,11 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initializeTheme() {
|
initializeTheme() {
|
||||||
// If no saved preference, apply system preference now
|
// If no saved preference, default to auto
|
||||||
const savedTheme = localStorage.getItem('theme');
|
const savedTheme = localStorage.getItem('theme');
|
||||||
if (!savedTheme) {
|
if (!savedTheme) {
|
||||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
this.currentTheme = 'auto';
|
||||||
const theme = prefersDark ? 'dark' : 'light';
|
this.applyTheme('auto');
|
||||||
this.applyTheme(theme);
|
|
||||||
} else {
|
} else {
|
||||||
this.currentTheme = savedTheme;
|
this.currentTheme = savedTheme;
|
||||||
// Apply saved theme
|
// Apply saved theme
|
||||||
@@ -63,12 +62,12 @@ export default {
|
|||||||
|
|
||||||
// Use arrow function to preserve 'this' context
|
// Use arrow function to preserve 'this' context
|
||||||
const themeChangeHandler = (e) => {
|
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');
|
const savedTheme = localStorage.getItem('theme');
|
||||||
if (!savedTheme) {
|
if (savedTheme === 'auto' || !savedTheme) {
|
||||||
const newTheme = e.matches ? 'dark' : 'light';
|
const newTheme = e.matches ? 'dark' : 'light';
|
||||||
console.log('System theme changed to:', newTheme);
|
console.log('System theme changed to:', newTheme);
|
||||||
this.applyTheme(newTheme);
|
this.applyThemeActual(newTheme);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -77,15 +76,27 @@ export default {
|
|||||||
this.themeChangeHandler = themeChangeHandler;
|
this.themeChangeHandler = themeChangeHandler;
|
||||||
this.darkModeQuery = darkModeQuery;
|
this.darkModeQuery = darkModeQuery;
|
||||||
},
|
},
|
||||||
applyTheme(theme) {
|
applyTheme(theme, skipSave = false) {
|
||||||
this.currentTheme = theme;
|
this.currentTheme = theme;
|
||||||
|
if (!skipSave) {
|
||||||
localStorage.setItem('theme', theme);
|
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
|
// 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
|
// Update HTML class for theme-based CSS selectors
|
||||||
if (theme === 'dark') {
|
if (actualTheme === 'dark') {
|
||||||
document.documentElement.classList.add('dark-theme');
|
document.documentElement.classList.add('dark-theme');
|
||||||
document.documentElement.classList.remove('light-theme');
|
document.documentElement.classList.remove('light-theme');
|
||||||
} else {
|
} else {
|
||||||
@@ -94,7 +105,15 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleTheme() {
|
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);
|
this.applyTheme(newTheme);
|
||||||
},
|
},
|
||||||
detectMobile() {
|
detectMobile() {
|
||||||
@@ -186,6 +205,24 @@ export default {
|
|||||||
return dealerName.replace(re, (matchedText) => `<mark>${matchedText}</mark>`);
|
return dealerName.replace(re, (matchedText) => `<mark>${matchedText}</mark>`);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
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)';
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -205,8 +242,8 @@ export default {
|
|||||||
@keyup.esc="$refs.filter.blur()"
|
@keyup.esc="$refs.filter.blur()"
|
||||||
class="search-input"
|
class="search-input"
|
||||||
/>
|
/>
|
||||||
<button @click="toggleTheme" class="theme-toggle" :title="'Switch to ' + (currentTheme === 'dark' ? 'light' : 'dark') + ' theme'">
|
<button @click="toggleTheme" class="theme-toggle" :title="getThemeTitle">
|
||||||
<span class="material-symbols-outlined">{{ currentTheme === 'dark' ? 'light_mode' : 'dark_mode' }}</span>
|
<span class="material-symbols-outlined">{{ getThemeIcon }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ html.dark-theme .search-input:focus {
|
|||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-toggle:hover {
|
.theme-toggle:hover {
|
||||||
|
|||||||
Reference in New Issue
Block a user