LoongPanel-Asp/web/utils.ts

72 lines
2.5 KiB
TypeScript

export function deepEqual(obj1: any, obj2: any) {
if (obj1 === obj2) return true;
if (typeof obj1 !== "object" || obj1 === null || typeof obj2 !== "object" || obj2 === null) {
return false;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (let key of keys1) {
if (!keys2.includes(key)) return false;
if (!deepEqual(obj1[key], obj2[key])) return false;
}
return true;
}
export function useBeep() {
const audioContext = ref(new (window.AudioContext)());
const playBeep = (frequency = 440, duration = 0.1) => {
const oscillator = audioContext.value.createOscillator();
const gainNode = audioContext.value.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.value.destination);
gainNode.gain.setValueAtTime(0, audioContext.value.currentTime);
gainNode.gain.linearRampToValueAtTime(1, audioContext.value.currentTime + 0.01);
gainNode.gain.linearRampToValueAtTime(0, audioContext.value.currentTime + duration);
oscillator.frequency.value = frequency;
oscillator.start(audioContext.value.currentTime);
oscillator.stop(audioContext.value.currentTime + duration);
};
return {playBeep};
}
export function toggleDark(event: MouseEvent) {
const isAppearanceTransition = document.startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches
if (!isAppearanceTransition) {
useColorMode().preference = useColorMode().value == 'dark' ? 'light' : 'dark'
return
}
const x = event.clientX
const y = event.clientY
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y),)
// @ts-expect-error: Transition API
const transition = document.startViewTransition(async () => {
useColorMode().preference = useColorMode().value == 'dark' ? 'light' : 'dark'
await nextTick()
})
transition.ready
.then(() => {
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`,]
document.documentElement.animate({
clipPath: useColorMode().value == 'dark' ? [...clipPath].reverse() : clipPath,
}, {
duration: 400,
easing: 'ease-out',
pseudoElement: useColorMode().value == 'dark' ? '::view-transition-old(root)' : '::view-transition-new(root)',
},)
})
}