From 9d05d0074a65d48599fecf718ce111757ec48591 Mon Sep 17 00:00:00 2001 From: jiwangyihao Date: Wed, 4 Jun 2025 00:52:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=9A=97=E9=BB=91?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E6=94=AF=E6=8C=81=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E5=92=8C=E8=83=8C=E6=99=AF=E5=9B=BE=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sylvanysc Co-authored-by: xudeyu444 Co-authored-by: 奕 --- app.vue | 152 +++++++++++++++++++--- assets/css/main.css | 104 ++++++++++++++- assets/images/index/figure-dark.avif | Bin 0 -> 327782 bytes assets/images/index/figure-dark.png | Bin 0 -> 2595749 bytes assets/images/index/figure-dark.webp | Bin 0 -> 687424 bytes nuxt.config.ts | 3 + pages/index.vue | 188 +++++++++++++++------------ 7 files changed, 344 insertions(+), 103 deletions(-) create mode 100644 assets/images/index/figure-dark.avif create mode 100644 assets/images/index/figure-dark.png create mode 100644 assets/images/index/figure-dark.webp diff --git a/app.vue b/app.vue index d54806f..c46456e 100644 --- a/app.vue +++ b/app.vue @@ -70,6 +70,87 @@ onMounted(() => { qrWidth.value = qrEl.getBoundingClientRect().height; } }); + +const sDarkConfig = ref("auto"); + +const isDarkMode = ref(false); + +const sDark = computed(() => { + return sDarkConfig.value === "auto" + ? isDarkMode.value + ? true + : false + : sDarkConfig.value === "dark" + ? true + : false; +}); + +provide("sDark", sDark); + +const enableTransitions = () => + "startViewTransition" in document && + window.matchMedia("(prefers-reduced-motion: no-preference)").matches; + +const mouseX = ref(0); +const mouseY = ref(0); + +const toggleDarkMode = async ({ clientX: x, clientY: y }: MouseEvent) => { + if (sDarkConfig.value === "auto") { + sDarkConfig.value = isDarkMode.value ? "light" : "dark"; + } else if (sDarkConfig.value === "dark" && isDarkMode.value) { + sDarkConfig.value = "auto"; + } else if (sDarkConfig.value === "light" && !isDarkMode.value) { + sDarkConfig.value = "auto"; + } else { + sDarkConfig.value = isDarkMode.value ? "dark" : "light"; + } + localStorage.setItem("darkMode", sDarkConfig.value); + + mouseX.value = x; + mouseY.value = y; +}; + +onMounted(() => { + const schemeQuery = window.matchMedia("(prefers-color-scheme: dark)"); + isDarkMode.value = schemeQuery.matches; + schemeQuery.addEventListener("change", (e) => { + isDarkMode.value = e.matches; + }); + const savedDarkMode = localStorage.getItem("darkMode"); + if (savedDarkMode) { + sDarkConfig.value = savedDarkMode; + } + watchEffect(async () => { + const sDarkValue = sDark.value; + + if (!enableTransitions()) { + document.documentElement.classList.toggle("s-dark", sDarkValue); + return; + } + + const clipPath = [ + `circle(0px at ${mouseX.value}px ${mouseY.value}px)`, + `circle(${Math.hypot( + Math.max(mouseX.value, innerWidth - mouseX.value), + Math.max(mouseY.value, innerHeight - mouseY.value) + )}px at ${mouseX.value}px ${mouseY.value}px)`, + ]; + + await document.startViewTransition(async () => { + document.documentElement.classList.toggle("s-dark", sDarkValue); + await nextTick(); + }).ready; + + document.documentElement.animate( + { clipPath: sDarkValue ? clipPath.reverse() : clipPath }, + { + duration: 300, + easing: "ease-in", + pseudoElement: `::view-transition-${sDarkValue ? "old" : "new"}(root)`, + } + ); + }); +});