From 3ef3c2eed1549953665e383aff1a97e1ed6dd59f Mon Sep 17 00:00:00 2001 From: kevinwong Date: Sun, 30 Jun 2024 15:50:21 +0800 Subject: [PATCH] feat: add theme toggle transition --- src/components/ThemeToggle.vue | 40 +++++++++++++++++++++++++++++++++- src/styles/global.css | 21 ++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/components/ThemeToggle.vue b/src/components/ThemeToggle.vue index b69f035..31b6442 100644 --- a/src/components/ThemeToggle.vue +++ b/src/components/ThemeToggle.vue @@ -4,8 +4,46 @@ import { useDark, useToggle } from '@vueuse/core' const isDark = useDark() const toggleDark = useToggle(isDark) + +function toggleTheme(event: MouseEvent) { + 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 + if (!document.startViewTransition) { + toggleDark() + return + } + + // @ts-expect-error: Transition API + const transition = document.startViewTransition(async () => { + toggleDark() + }) + + transition.ready.then(() => { + const clipPath = [ + `circle(0px at ${x}px ${y}px)`, + `circle(${endRadius}px at ${x}px ${y}px)`, + ] + document.documentElement.animate( + { + clipPath: isDark.value ? [...clipPath].reverse() : clipPath, + }, + { + duration: 400, + easing: 'ease-in', + pseudoElement: isDark.value + ? '::view-transition-old(root)' + : '::view-transition-new(root)', + }, + ) + }) +} diff --git a/src/styles/global.css b/src/styles/global.css index 430d7c5..ca8892c 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -41,3 +41,24 @@ article { .prose-link i { --at-apply: text-sm mr-1; } + +::view-transition-old(root), +::view-transition-new(root) { + animation: none; + mix-blend-mode: normal; +} + +::view-transition-old(root) { + z-index: 1; +} + +::view-transition-new(root) { + z-index: 2147483646; +} + +html.dark::view-transition-old(root) { + z-index: 2147483646; +} +html.dark::view-transition-new(root) { + z-index: 1; +}