import { defineStore } from 'pinia' import { setCookie, getCookie, getLocalStorage, setLocalStorage } from 'vue3-common/utils/storageUtil' import { useDark, useToggle } from '@vueuse/core' import { calcDarken, calcLighten } from '@/utils/element/elColor.ts' export const useAppStore = defineStore('ipp', { state: () => ({ appName: 'Sweet Hut', sidebar: { // !!:转为布尔值 // 保存当前菜单栏显示和隐藏的状态 opened: getCookie('sidebarStatus') ? !!getCookie('sidebarStatus') : true as boolean, withoutAnimation: false as boolean }, device: 'desktop' as string, homeTitle: '', isLoading: false, isLogin: false, isShowMobileBack: false, isShowSetting: false, themeColor: '', isDark: false, isWebSocket: false, serverIp: '14.103.235.151', version: 'v1.0.0.2025042901' }), actions: { // 控制菜单栏显示和隐藏的切换 toggleSideBar() { this.sidebar.opened = !this.sidebar.opened this.sidebar.withoutAnimation = false if (this.sidebar.opened) { setCookie('sidebarStatus', String(1)) } else { setCookie('sidebarStatus', String(0)) } }, initApp() { this.setThemeColor(this.getThemeColor()) this.setDartModel() }, setDartModel() { const dark = useDark({ selector: 'html', attribute: 'class', valueDark: 'dark', valueLight: '' }) this.isDark = dark.value }, toggleDark(e: MouseEvent) { const toggleDark = useToggle(useDark()) if (!document.startViewTransition) { toggleDark() this.isDark = !this.isDark return } const transition = document.startViewTransition(() => { toggleDark() // 实际切换主题 }) transition.ready.then(() => { const x = e.clientX const y = e.clientY // 从点击点到窗口最远边缘的距离,这个距离即为圆的半径,用于确定一个圆形裁剪路径 (clip path) 的最大尺寸,以便覆盖整个视窗。 // 勾股定理:a² + b² = c² const a = Math.max(x, window.innerWidth - x) const b = Math.max(y, window.innerHeight - y) const radius = Math.sqrt((a ** 2) + (b ** 2)) const clipPath = [`circle(0 at ${x}px ${y}px)`, `circle(${radius}px at ${x}px ${y}px)`] // 实现过渡的过程 circle document.documentElement.animate( { clipPath: this.isDark ? clipPath.reverse() : clipPath }, { duration: 500, easing: 'ease-in', pseudoElement: this.isDark ? '::view-transition-old(root)' : '::view-transition-new(root)' } ) }) this.isDark = !this.isDark }, getThemeColor(): string { return getLocalStorage('theme-color') as string || '#009FA8' }, setThemeColor(value: string) { const root = document.documentElement root.style.setProperty('--el-color-primary', value) root.style.setProperty('--el-color-primary-light-3', calcLighten(value, 30)) root.style.setProperty('--el-color-primary-light-5', calcLighten(value, 50)) root.style.setProperty('--el-color-primary-light-7', calcLighten(value, 70)) root.style.setProperty('--el-color-primary-light-8', calcLighten(value, 80)) root.style.setProperty('--el-color-primary-light-9', calcLighten(value, 90)) root.style.setProperty('--el-color-primary-dark-2', calcDarken(value, 20)) root.style.setProperty('--van-primary-color', value) setLocalStorage('theme-color', value) } } })