Skip to content

Commit d2086a4

Browse files
committed
Add theme switch animation.
1 parent 51ea3be commit d2086a4

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<script setup>
2+
import { useData } from "vitepress";
3+
import DefaultTheme from "vitepress/theme";
4+
import { nextTick, provide } from "vue";
5+
6+
const { isDark } = useData();
7+
8+
const enableTransitions = () =>
9+
"startViewTransition" in document &&
10+
window.matchMedia("(prefers-reduced-motion: no-preference)").matches;
11+
12+
provide("toggle-appearance", async () => {
13+
if (!enableTransitions()) {
14+
isDark.value = !isDark.value;
15+
return;
16+
}
17+
18+
const clipPath = [
19+
`polygon(0 0, 100vw 0, 100vw 100vh, 100vw 100vh, 100vw 66vh, 100vw 66vh, 100vw 33vh, 100vw 33vh, 100vw 0)`,
20+
`polygon(0 0, 100vw 0, 100vw 100vh, 80vw 100vh, 80vw 66vh, 100vw 66vh, 100vw 33vh, 100vw 33vh, 100vw 0)`,
21+
`polygon(0 0, 100vw 0, 100vw 100vh, 60vw 100vh, 60vw 66vh, 100vw 66vh, 100vw 33vh, 100vw 33vh, 100vw 0)`,
22+
`polygon(0 0, 100vw 0, 100vw 100vh, 40vw 100vh, 40vw 66vh, 80vw 66vh, 80vw 33vh, 100vw 33vh, 100vw 0)`,
23+
`polygon(0 0, 100vw 0, 100vw 100vh, 20vw 100vh, 20vw 66vh, 60vw 66vh, 60vw 33vh, 100vw 33vh, 100vw 0)`,
24+
`polygon(0 0, 100vw 0, 100vw 100vh, 0 100vh, 0 66vh, 40vw 66vh, 40vw 33vh, 80vw 33vh, 80vw 0)`,
25+
`polygon(0 0, 100vw 0, 100vw 100vh, 0 100vh, 0 66vh, 20vw 66vh, 20vw 33vh, 60vw 33vh, 60vw 0)`,
26+
`polygon(0 0, 100vw 0, 100vw 100vh, 0 100vh, 0 66vh, 0 66vh, 0 33vh, 40vw 33vh, 40vw 0)`,
27+
`polygon(0 0, 100vw 0, 100vw 100vh, 0 100vh, 0 66vh, 0 66vh, 0 33vh, 20vw 33vh, 20vw 0)`,
28+
`polygon(0 0, 100vw 0, 100vw 100vh, 0 100vh, 0 66vh, 0 66vh, 0 33vh, 0 33vh, 0 0)`,
29+
];
30+
31+
await document.startViewTransition(async () => {
32+
isDark.value = !isDark.value;
33+
await nextTick();
34+
}).ready;
35+
36+
document.documentElement.animate(
37+
{ clipPath: isDark.value ? clipPath.reverse() : clipPath },
38+
{
39+
duration: 300,
40+
easing: "ease-in",
41+
pseudoElement: `::view-transition-${isDark.value ? "old" : "new"}(root)`,
42+
},
43+
);
44+
});
45+
</script>
46+
47+
<template>
48+
<DefaultTheme.Layout />
49+
</template>
50+
51+
<style>
52+
::view-transition-old(root),
53+
::view-transition-new(root) {
54+
animation: none;
55+
mix-blend-mode: normal;
56+
}
57+
58+
::view-transition-old(root),
59+
.dark::view-transition-new(root) {
60+
z-index: 1;
61+
}
62+
63+
::view-transition-new(root),
64+
.dark::view-transition-old(root) {
65+
z-index: 9999;
66+
}
67+
</style>

.vitepress/theme/index.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import "./style.css";
33
import PageInfo from "./components/PageInfo.vue";
44
import PageTitle from "./components/PageTitle.vue";
55
import FutureStar from "./components/FutureStar.vue";
6+
import CustomLayout from "./components/CustomLayout.vue";
67

78
/**
89
* @typedef {import('vitepress').EnhanceAppContext} EnhanceAppContext
910
*/
1011
export default {
11-
...DefaultTheme,
12+
extends: DefaultTheme,
13+
Layout: CustomLayout,
1214
/**
1315
* @param {EnhanceAppContext} ctx context
1416
* @returns {void}

0 commit comments

Comments
 (0)