system theme support + as default
This commit is contained in:
parent
2b1c357603
commit
22361db2a9
1 changed files with 61 additions and 8 deletions
|
@ -3,20 +3,39 @@ import { computed, onMounted, ref } from 'vue'
|
||||||
|
|
||||||
import PrimeVueSelect from 'primevue/select'
|
import PrimeVueSelect from 'primevue/select'
|
||||||
|
|
||||||
import type { SiteTheme } from '@goldenwere/mackenzii-types'
|
import type { SiteTheme, SiteThemeType } from '@goldenwere/mackenzii-types'
|
||||||
import { injectStylesheet } from 'src/utilities/dom'
|
import { injectStylesheet } from 'src/utilities/dom'
|
||||||
import { storage } from 'src/utilities/fetch'
|
import { storage } from 'src/utilities/fetch'
|
||||||
import { useRouteStore } from 'src/routes'
|
import { useRouteStore } from 'src/routes'
|
||||||
|
|
||||||
|
type Theme = SiteTheme & { id: string }
|
||||||
|
const systemTheme = {
|
||||||
|
id: 'SYSTEM',
|
||||||
|
displayName: 'System',
|
||||||
|
type: null as any,
|
||||||
|
url: null as any,
|
||||||
|
}
|
||||||
|
|
||||||
const routeStore = useRouteStore()
|
const routeStore = useRouteStore()
|
||||||
const globalConfig = routeStore._globals
|
const globalConfig = routeStore._globals
|
||||||
const options = ref(globalConfig.themes)
|
const options = ref(globalConfig.themes)
|
||||||
const optionsArray = computed(() => Object.keys(options.value).map(key => ({...options.value[key], id: key})))
|
const optionsArray = computed<Theme[]>(() => {
|
||||||
|
const val = Object.keys(options.value).map(key => ({...options.value[key], id: key}))
|
||||||
|
if (val.find(other => other.type === 'dark') && val.find(other => other.type === 'light')) {
|
||||||
|
val.push(systemTheme)
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
})
|
||||||
const currentTheme = ref<SiteTheme & { id: string }>(null as any)
|
const currentTheme = ref<SiteTheme & { id: string }>(null as any)
|
||||||
|
const currentSystem = ref<SiteThemeType>(null as any)
|
||||||
let node: HTMLLinkElement
|
let node: HTMLLinkElement
|
||||||
|
|
||||||
const setModeClass = () => {
|
const setModeClass = () => {
|
||||||
switch (currentTheme.value.type) {
|
const type = currentTheme.value.id === 'SYSTEM'
|
||||||
|
? currentSystem.value
|
||||||
|
: currentTheme.value.type
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
case 'dark':
|
case 'dark':
|
||||||
document.body.parentElement!.classList.add('app-dark')
|
document.body.parentElement!.classList.add('app-dark')
|
||||||
document.body.parentElement!.classList.remove('app-dark-hc')
|
document.body.parentElement!.classList.remove('app-dark-hc')
|
||||||
|
@ -50,29 +69,63 @@ const setModeClass = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onThemeChosen = (event: Event) => {
|
const getUrlOfTheme = (id: string) => {
|
||||||
|
if (id === 'SYSTEM') {
|
||||||
|
return optionsArray.value.find(other => other.type === currentSystem.value)!.url
|
||||||
|
} else {
|
||||||
|
return globalConfig.themes[id].url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onThemeChosen = (event?: Event) => {
|
||||||
const themeId = currentTheme.value.id
|
const themeId = currentTheme.value.id
|
||||||
storage.write(`${globalConfig.id}::currentTheme`, themeId)
|
storage.write(`${globalConfig.id}::currentTheme`, themeId)
|
||||||
node.setAttribute('href', globalConfig.themes[themeId].url)
|
node.setAttribute('href', getUrlOfTheme(themeId))
|
||||||
setModeClass()
|
setModeClass()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onSystemThemeChanged = (query: MediaQueryListEvent | MediaQueryList) => {
|
||||||
|
if (query.matches) {
|
||||||
|
currentSystem.value = 'dark'
|
||||||
|
} else {
|
||||||
|
currentSystem.value = 'light'
|
||||||
|
}
|
||||||
|
onThemeChosen()
|
||||||
|
}
|
||||||
|
|
||||||
|
const setupSystemThemeListener = () => {
|
||||||
|
const themeListener = window.matchMedia('(prefers-color-scheme: dark)')
|
||||||
|
onSystemThemeChanged(themeListener)
|
||||||
|
themeListener.addEventListener('change', onSystemThemeChanged)
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadThemeFromStorage = () => {
|
||||||
|
const themeId = storage.read<string>(`${globalConfig.id}::currentTheme`) || (
|
||||||
|
!!optionsArray.value.find(other => other.id === 'SYSTEM') ? 'SYSTEM' : Object.keys(globalConfig.themes)[0]
|
||||||
|
)
|
||||||
|
currentTheme.value = themeId === 'SYSTEM' ? systemTheme : { ...options.value[themeId], id: themeId }
|
||||||
|
node = injectStylesheet(getUrlOfTheme(themeId), 'theme-stylesheet')
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const themeId = storage.read<string>(`${globalConfig.id}::currentTheme`) || Object.keys(globalConfig.themes)[0]
|
loadThemeFromStorage()
|
||||||
currentTheme.value = { ...options.value[themeId], id: themeId }
|
setupSystemThemeListener()
|
||||||
node = injectStylesheet(globalConfig.themes[themeId].url, 'theme-stylesheet')
|
|
||||||
setModeClass()
|
setModeClass()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.theme-picker
|
.theme-picker
|
||||||
|
label(
|
||||||
|
for='site theme'
|
||||||
|
) Theme
|
||||||
PrimeVueSelect(
|
PrimeVueSelect(
|
||||||
v-model='currentTheme'
|
v-model='currentTheme'
|
||||||
:options='optionsArray'
|
:options='optionsArray'
|
||||||
@change='onThemeChosen($event)'
|
@change='onThemeChosen($event)'
|
||||||
optionLabel='displayName'
|
optionLabel='displayName'
|
||||||
placeholder='theme'
|
placeholder='theme'
|
||||||
|
name='site theme'
|
||||||
)
|
)
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue