Allow using dark / light theme as indicated by prefers-color-scheme media feature

This commit is contained in:
Philipp Wolfer 2022-01-04 09:14:05 +00:00 committed by Georg Krause
parent 742f843c98
commit d93f0d107d
8 changed files with 65 additions and 63 deletions

View File

@ -0,0 +1 @@
Allow using default browser dark mode and update UI dynamically on change

View File

@ -129,6 +129,12 @@ export default {
return this.$store.state.instance.frontSettings.additionalStylesheets || [] return this.$store.state.instance.frontSettings.additionalStylesheets || []
} }
return null return null
},
matchDarkColorScheme () {
if (window.matchMedia) {
return window.matchMedia('(prefers-color-scheme: dark)')
}
return null
} }
}, },
watch: { watch: {
@ -138,10 +144,21 @@ export default {
}, },
'$store.state.ui.theme': { '$store.state.ui.theme': {
immediate: true, immediate: true,
handler (newValue, oldValue) { handler (newValue) {
const oldTheme = oldValue || 'light' const matchesDark = this.matchDarkColorScheme
document.body.classList.remove(`theme-${oldTheme}`) if (matchesDark) {
document.body.classList.add(`theme-${newValue}`) 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) { '$store.state.auth.authenticated' (newValue) {
@ -451,6 +468,14 @@ export default {
}, },
handleResize () { handleResize () {
this.width = window.innerWidth 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}`)
} }
} }
} }

View File

@ -212,9 +212,11 @@
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import ThemesMixin from '@/components/mixins/Themes'
import _ from '@/lodash' import _ from '@/lodash'
export default { export default {
mixins: [ThemesMixin],
props: { version: { type: String, required: true } }, props: { version: { type: String, required: true } },
computed: { computed: {
...mapState({ ...mapState({
@ -229,18 +231,6 @@ export default {
const parser = document.createElement('a') const parser = document.createElement('a')
parser.href = url parser.href = url
return parser.hostname return parser.hostname
},
themes () {
return [
{
name: this.$pgettext('Footer/Settings/Dropdown.Label/Theme name', 'Light'),
key: 'light'
},
{
name: this.$pgettext('Footer/Settings/Dropdown.Label/Theme name', 'Dark'),
key: 'dark'
}
]
} }
} }
} }

View File

@ -475,6 +475,7 @@ import { mapState, mapActions, mapGetters } from 'vuex'
import UserModal from '@/components/common/UserModal' import UserModal from '@/components/common/UserModal'
import Logo from '@/components/Logo' import Logo from '@/components/Logo'
import SearchBar from '@/components/audio/SearchBar' import SearchBar from '@/components/audio/SearchBar'
import ThemesMixin from '@/components/mixins/Themes'
import UserMenu from '@/components/common/UserMenu' import UserMenu from '@/components/common/UserMenu'
import Modal from '@/components/semantic/Modal' import Modal from '@/components/semantic/Modal'
@ -489,6 +490,7 @@ export default {
UserModal, UserModal,
Modal Modal
}, },
mixins: [ThemesMixin],
props: { props: {
width: { type: Number, required: true } width: { type: Number, required: true }
}, },
@ -589,18 +591,6 @@ export default {
}, },
production () { production () {
return process.env.NODE_ENV === 'production' return process.env.NODE_ENV === 'production'
},
themes () {
return [
{
name: this.$pgettext('Sidebar/Settings/Dropdown.Label/Theme name', 'Light'),
key: 'light'
},
{
name: this.$pgettext('Sidebar/Settings/Dropdown.Label/Theme name', 'Dark'),
key: 'dark'
}
]
} }
}, },
watch: { watch: {

View File

@ -155,7 +155,10 @@
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import ThemesMixin from '@/components/mixins/Themes'
export default { export default {
mixins: [ThemesMixin],
computed: { computed: {
labels () { labels () {
return { return {
@ -176,20 +179,6 @@ export default {
notifications: this.$pgettext('*/Notifications/*', 'Notifications') notifications: this.$pgettext('*/Notifications/*', 'Notifications')
} }
}, },
themes () {
return [
{
icon: 'sun icon',
name: this.$pgettext('Footer/Settings/Dropdown.Label/Theme name', 'Light'),
key: 'light'
},
{
icon: 'moon icon',
name: this.$pgettext('Footer/Settings/Dropdown.Label/Theme name', 'Dark'),
key: 'dark'
}
]
},
...mapGetters({ ...mapGetters({
additionalNotifications: 'ui/additionalNotifications' additionalNotifications: 'ui/additionalNotifications'
}) })

View File

@ -175,12 +175,14 @@
<script> <script>
import Modal from '@/components/semantic/Modal' import Modal from '@/components/semantic/Modal'
import ThemesMixin from '@/components/mixins/Themes'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
export default { export default {
components: { components: {
Modal Modal
}, },
mixins: [ThemesMixin],
props: { props: {
show: { type: Boolean, required: true } show: { type: Boolean, required: true }
}, },
@ -216,26 +218,6 @@ export default {
) )
} }
}, },
themes () {
return [
{
icon: 'sun icon',
name: this.$pgettext(
'Footer/Settings/Dropdown.Label/Theme name',
'Light'
),
key: 'light'
},
{
icon: 'moon icon',
name: this.$pgettext(
'Footer/Settings/Dropdown.Label/Theme name',
'Dark'
),
key: 'dark'
}
]
},
...mapGetters({ ...mapGetters({
additionalNotifications: 'ui/additionalNotifications' additionalNotifications: 'ui/additionalNotifications'
}) })

View File

@ -0,0 +1,25 @@
<script>
export default {
computed: {
themes () {
return [
{
icon: 'palette icon',
name: this.$pgettext('*/Settings/Dropdown.Label/Theme name', 'Browser default'),
key: 'system'
},
{
icon: 'sun icon',
name: this.$pgettext('*/Settings/Dropdown.Label/Theme name', 'Light'),
key: 'light'
},
{
icon: 'moon icon',
name: this.$pgettext('*/Settings/Dropdown.Label/Theme name', 'Dark'),
key: 'dark'
}
]
}
}
}
</script>

View File

@ -13,7 +13,7 @@ export default {
messageDisplayDuration: 5 * 1000, messageDisplayDuration: 5 * 1000,
supportedExtensions: ['flac', 'ogg', 'mp3', 'opus', 'aac', 'm4a', 'aiff', 'aif'], supportedExtensions: ['flac', 'ogg', 'mp3', 'opus', 'aac', 'm4a', 'aiff', 'aif'],
messages: [], messages: [],
theme: 'light', theme: 'system',
window: { window: {
height: 0, height: 0,
width: 0 width: 0