108 lines
3.6 KiB
TypeScript
108 lines
3.6 KiB
TypeScript
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)
|
||
}
|
||
}
|
||
})
|