Skip to content

Commit a5f2eac

Browse files
brc-ddhooray
andcommittedAug 25, 2023
feat(theme): allow providing custom toggle-appearance function (#2844)
Co-authored-by: Hooray Hu <304327508@qq.com>
1 parent e477cdf commit a5f2eac

File tree

3 files changed

+106
-1
lines changed

3 files changed

+106
-1
lines changed
 

‎docs/guide/extending-default-theme.md

+100
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
---
2+
outline: deep
3+
---
4+
15
# Extending the Default Theme
26

37
VitePress' default theme is optimized for documentation, and can be customized. Consult the [Default Theme Config Overview](../reference/default-theme-config) for a comprehensive list of options.
@@ -195,6 +199,102 @@ Full list of slots available in the default theme layout:
195199
- `nav-screen-content-before`
196200
- `nav-screen-content-after`
197201

202+
## Using View Transitions API
203+
204+
### On Appearance Toggle
205+
206+
You can extend the default theme to provide a custom transition when the color mode is toggled. An example:
207+
208+
```vue
209+
<!-- .vitepress/theme/Layout.vue -->
210+
211+
<script setup lang="ts">
212+
import { useData } from 'vitepress'
213+
import DefaultTheme from 'vitepress/theme'
214+
import { nextTick, provide } from 'vue'
215+
216+
const { isDark } = useData()
217+
218+
const enableTransitions = () =>
219+
'startViewTransition' in document &&
220+
window.matchMedia('(prefers-reduced-motion: no-preference)').matches
221+
222+
provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
223+
if (!enableTransitions()) {
224+
isDark.value = !isDark.value
225+
return
226+
}
227+
228+
const clipPath = [
229+
`circle(0px at ${x}px ${y}px)`,
230+
`circle(${Math.hypot(
231+
Math.max(x, innerWidth - x),
232+
Math.max(y, innerHeight - y)
233+
)}px at ${x}px ${y}px)`
234+
]
235+
236+
await document.startViewTransition(async () => {
237+
isDark.value = !isDark.value
238+
await nextTick()
239+
}).ready
240+
241+
document.documentElement.animate(
242+
{ clipPath: isDark.value ? clipPath.reverse() : clipPath },
243+
{
244+
duration: 300,
245+
easing: 'ease-in',
246+
pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`
247+
}
248+
)
249+
})
250+
</script>
251+
252+
<template>
253+
<DefaultTheme.Layout />
254+
</template>
255+
256+
<style>
257+
::view-transition-old(root),
258+
::view-transition-new(root) {
259+
animation: none;
260+
mix-blend-mode: normal;
261+
}
262+
263+
::view-transition-old(root),
264+
.dark::view-transition-new(root) {
265+
z-index: 1;
266+
}
267+
268+
::view-transition-new(root),
269+
.dark::view-transition-old(root) {
270+
z-index: 9999;
271+
}
272+
273+
.VPSwitchAppearance {
274+
width: 22px !important;
275+
}
276+
277+
.VPSwitchAppearance .check {
278+
transform: none !important;
279+
}
280+
</style>
281+
```
282+
283+
Result (**warning!**: flashing colors, sudden movements, bright lights):
284+
285+
<details>
286+
<summary>Demo</summary>
287+
288+
![Appearance Toggle Transition Demo](/appearance-toggle-transition.webp)
289+
290+
</details>
291+
292+
Refer [Chrome Docs](https://developer.chrome.com/docs/web-platform/view-transitions/) from more details on view transitions.
293+
294+
### On Route Change
295+
296+
Coming soon.
297+
198298
## Overriding Internal Components
199299

200300
You can use Vite's [aliases](https://vitejs.dev/config/shared-options.html#resolve-alias) to replace default theme components with your custom ones:
93.8 KB
Binary file not shown.

‎src/client/theme-default/components/VPSwitchAppearance.vue

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
<script lang="ts" setup>
2+
import { inject } from 'vue'
23
import { useData } from '../composables/data'
34
import VPSwitch from './VPSwitch.vue'
45
import VPIconMoon from './icons/VPIconMoon.vue'
56
import VPIconSun from './icons/VPIconSun.vue'
67
78
const { isDark } = useData()
9+
10+
const toggleAppearance = inject('toggle-appearance', () => {
11+
isDark.value = !isDark.value
12+
})
813
</script>
914

1015
<template>
1116
<VPSwitch
1217
title="toggle dark mode"
1318
class="VPSwitchAppearance"
1419
:aria-checked="isDark"
15-
@click="isDark = !isDark"
20+
@click="toggleAppearance"
1621
>
1722
<VPIconSun class="sun" />
1823
<VPIconMoon class="moon" />

0 commit comments

Comments
 (0)
Please sign in to comment.