feat(stage-web): theme for settings

This commit is contained in:
Neko Ayaka
2025-07-07 23:41:55 +08:00
parent 61ef007cc5
commit 907daf0d43
3 changed files with 59 additions and 23 deletions
@@ -0,0 +1,46 @@
import Color from 'colorjs.io'
import { withRetry } from '@moeru/std'
import { useDark } from '@vueuse/core'
export function themeColorFromPropertyOf(colorFromClass: string, property: string): () => Promise<string> {
return async () => {
const fetchUntilWidgetMounted = withRetry(() => {
const widgets = document.querySelector(colorFromClass) as HTMLDivElement | undefined
if (!widgets)
throw new Error('Widgets element not found')
return widgets
}, { retry: 10, retryDelay: 1000 })
const widgets = await fetchUntilWidgetMounted()
return window.getComputedStyle(widgets).getPropertyValue(property)
}
}
export function themeColorFromValue(value: string | { light: string, dark: string }): () => Promise<string> {
return async () => {
if (typeof value === 'string') {
return value
}
else {
const dark = useDark()
return dark.value ? value.dark : value.light
}
}
}
export function useThemeColor(colorFrom: () => string | Promise<string>) {
async function updateThemeColor() {
if (!('document' in globalThis && globalThis.document != null))
return
if (!('window' in globalThis && globalThis.window != null))
return
document.querySelector('meta[name="theme-color"]')?.setAttribute('content', new Color(await colorFrom()).to('srgb').toString({ format: 'hex' }))
}
return {
updateThemeColor,
}
}
+10 -1
View File
@@ -1,14 +1,18 @@
<script setup lang="ts">
import { PageHeader } from '@proj-airi/stage-ui/components'
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
import { useDark } from '@vueuse/core'
import { storeToRefs } from 'pinia'
import { computed } from 'vue'
import { computed, onMounted, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { RouterView, useRoute } from 'vue-router'
import HeaderLink from '../components/Layouts/HeaderLink.vue'
import { themeColorFromValue, useThemeColor } from '../composables/theme-color'
const route = useRoute()
const dark = useDark()
const { t } = useI18n()
const providersStore = useProvidersStore()
const { allProvidersMetadata } = storeToRefs(providersStore)
@@ -108,6 +112,11 @@ const routeHeaderMetadataMap = computed(() => {
// const activeSettingsTutorial = ref('default')
const routeHeaderMetadata = computed(() => routeHeaderMetadataMap.value[route.path])
const { updateThemeColor } = useThemeColor(themeColorFromValue({ light: 'rgb(255 255 255)', dark: 'rgb(18 18 18)' }))
watch(dark, () => updateThemeColor(), { immediate: true })
watch(route, () => updateThemeColor(), { immediate: true })
onMounted(() => updateThemeColor())
</script>
<template>
+3 -22
View File
@@ -1,7 +1,4 @@
<script setup lang="ts">
import Color from 'colorjs.io'
import { withRetry } from '@moeru/std'
import { WidgetStage } from '@proj-airi/stage-ui/components/scenes'
import { breakpointsTailwind, useBreakpoints, useDark, useMouse } from '@vueuse/core'
import { onMounted, ref, watch } from 'vue'
@@ -12,6 +9,8 @@ import InteractiveArea from '../components/Layouts/InteractiveArea.vue'
import MobileInteractiveArea from '../components/Layouts/MobileInteractiveArea.vue'
import AnimatedWave from '../components/Widgets/AnimatedWave.vue'
import { themeColorFromPropertyOf, useThemeColor } from '../composables/theme-color'
const dark = useDark()
const paused = ref(false)
@@ -23,25 +22,7 @@ const positionCursor = useMouse()
const breakpoints = useBreakpoints(breakpointsTailwind)
const isMobile = breakpoints.smaller('md')
async function updateThemeColor() {
if (!('document' in globalThis && globalThis.document != null))
return
if (!('window' in globalThis && globalThis.window != null))
return
const fetchUntilWidgetMounted = withRetry(() => {
const widgets = document.querySelector('.widgets.top-widgets .colored-area') as HTMLDivElement | undefined
if (!widgets)
throw new Error('Widgets element not found')
return widgets
}, { retry: 10, retryDelay: 1000 })
const widgets = await fetchUntilWidgetMounted()
const backgroundColor = window.getComputedStyle(widgets).getPropertyValue('background-color')
document.querySelector('meta[name="theme-color"]')?.setAttribute('content', new Color(backgroundColor).to('srgb').toString({ format: 'hex' }))
}
const { updateThemeColor } = useThemeColor(themeColorFromPropertyOf('.widgets.top-widgets .colored-area', 'background-color'))
watch(dark, () => updateThemeColor(), { immediate: true })
onMounted(() => updateThemeColor())
</script>