Allow using dark / light theme as indicated by prefers-color-scheme media feature
This commit is contained in:
parent
742f843c98
commit
d93f0d107d
|
@ -0,0 +1 @@
|
||||||
|
Allow using default browser dark mode and update UI dynamically on change
|
|
@ -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}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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'
|
||||||
})
|
})
|
||||||
|
|
|
@ -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'
|
||||||
})
|
})
|
||||||
|
|
|
@ -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>
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue