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 type { SiteTheme } from '@goldenwere/mackenzii-types'
|
||||
import type { SiteTheme, SiteThemeType } from '@goldenwere/mackenzii-types'
|
||||
import { injectStylesheet } from 'src/utilities/dom'
|
||||
import { storage } from 'src/utilities/fetch'
|
||||
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 globalConfig = routeStore._globals
|
||||
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 currentSystem = ref<SiteThemeType>(null as any)
|
||||
let node: HTMLLinkElement
|
||||
|
||||
const setModeClass = () => {
|
||||
switch (currentTheme.value.type) {
|
||||
const type = currentTheme.value.id === 'SYSTEM'
|
||||
? currentSystem.value
|
||||
: currentTheme.value.type
|
||||
|
||||
switch (type) {
|
||||
case 'dark':
|
||||
document.body.parentElement!.classList.add('app-dark')
|
||||
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
|
||||
storage.write(`${globalConfig.id}::currentTheme`, themeId)
|
||||
node.setAttribute('href', globalConfig.themes[themeId].url)
|
||||
node.setAttribute('href', getUrlOfTheme(themeId))
|
||||
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 () => {
|
||||
const themeId = storage.read<string>(`${globalConfig.id}::currentTheme`) || Object.keys(globalConfig.themes)[0]
|
||||
currentTheme.value = { ...options.value[themeId], id: themeId }
|
||||
node = injectStylesheet(globalConfig.themes[themeId].url, 'theme-stylesheet')
|
||||
loadThemeFromStorage()
|
||||
setupSystemThemeListener()
|
||||
setModeClass()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template lang="pug">
|
||||
.theme-picker
|
||||
label(
|
||||
for='site theme'
|
||||
) Theme
|
||||
PrimeVueSelect(
|
||||
v-model='currentTheme'
|
||||
:options='optionsArray'
|
||||
@change='onThemeChosen($event)'
|
||||
optionLabel='displayName'
|
||||
placeholder='theme'
|
||||
name='site theme'
|
||||
)
|
||||
</template>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue