system theme support + as default

This commit is contained in:
lightling 2025-04-20 15:19:17 -04:00
parent 2b1c357603
commit 22361db2a9
Signed by: lightling
GPG key ID: F1F29650D537C773

View file

@ -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>