From d93f0d107da94a3faeefcba14da63793ab18d2a6 Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Tue, 4 Jan 2022 09:14:05 +0000 Subject: [PATCH] Allow using dark / light theme as indicated by prefers-color-scheme media feature --- changes/changelog.d/auto-darkmode.enhancement | 1 + front/src/App.vue | 33 ++++++++++++++++--- front/src/components/Footer.vue | 14 ++------ front/src/components/Sidebar.vue | 14 ++------ front/src/components/common/UserMenu.vue | 17 ++-------- front/src/components/common/UserModal.vue | 22 ++----------- front/src/components/mixins/Themes.vue | 25 ++++++++++++++ front/src/store/ui.js | 2 +- 8 files changed, 65 insertions(+), 63 deletions(-) create mode 100644 changes/changelog.d/auto-darkmode.enhancement create mode 100644 front/src/components/mixins/Themes.vue diff --git a/changes/changelog.d/auto-darkmode.enhancement b/changes/changelog.d/auto-darkmode.enhancement new file mode 100644 index 000000000..3e0b2c364 --- /dev/null +++ b/changes/changelog.d/auto-darkmode.enhancement @@ -0,0 +1 @@ +Allow using default browser dark mode and update UI dynamically on change \ No newline at end of file diff --git a/front/src/App.vue b/front/src/App.vue index 2db0fbc26..a94e6f030 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -129,6 +129,12 @@ export default { return this.$store.state.instance.frontSettings.additionalStylesheets || [] } return null + }, + matchDarkColorScheme () { + if (window.matchMedia) { + return window.matchMedia('(prefers-color-scheme: dark)') + } + return null } }, watch: { @@ -138,10 +144,21 @@ export default { }, '$store.state.ui.theme': { immediate: true, - handler (newValue, oldValue) { - const oldTheme = oldValue || 'light' - document.body.classList.remove(`theme-${oldTheme}`) - document.body.classList.add(`theme-${newValue}`) + handler (newValue) { + const matchesDark = this.matchDarkColorScheme + if (matchesDark) { + if (newValue === 'system') { + newValue = matchesDark.matches ? 'dark' : 'light' + matchesDark.addEventListener('change', this.handleThemeChange) + } else { + matchesDark.removeEventListener('change', this.handleThemeChange) + } + } else { + if (newValue === 'system') { + newValue = 'light' + } + } + this.setTheme(newValue) } }, '$store.state.auth.authenticated' (newValue) { @@ -451,6 +468,14 @@ export default { }, handleResize () { this.width = window.innerWidth + }, + handleThemeChange (event) { + this.setTheme(event.matches ? 'dark' : 'light') + }, + setTheme (theme) { + const oldTheme = (theme === 'light') ? 'dark' : 'light' + document.body.classList.remove(`theme-${oldTheme}`) + document.body.classList.add(`theme-${theme}`) } } } diff --git a/front/src/components/Footer.vue b/front/src/components/Footer.vue index f510e56ab..3f9641e18 100644 --- a/front/src/components/Footer.vue +++ b/front/src/components/Footer.vue @@ -212,9 +212,11 @@ diff --git a/front/src/store/ui.js b/front/src/store/ui.js index 174563f58..de77b8bba 100644 --- a/front/src/store/ui.js +++ b/front/src/store/ui.js @@ -13,7 +13,7 @@ export default { messageDisplayDuration: 5 * 1000, supportedExtensions: ['flac', 'ogg', 'mp3', 'opus', 'aac', 'm4a', 'aiff', 'aif'], messages: [], - theme: 'light', + theme: 'system', window: { height: 0, width: 0