Skip to content

Commit

Permalink
feat: add dark/light mode switch transition (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed May 10, 2023
1 parent f7d11ee commit 782e0da
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 7 deletions.
18 changes: 18 additions & 0 deletions packages/devtools-ui-kit/src/assets/styles.css
Expand Up @@ -15,3 +15,21 @@ html.dark {
::selection {
background: #8884;
}

::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;
}
.dark::view-transition-old(root) {
z-index: 2147483646;
}
.dark::view-transition-new(root) {
z-index: 1;
}
52 changes: 49 additions & 3 deletions packages/devtools-ui-kit/src/components/NDarkToggle.vue
@@ -1,6 +1,5 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useToggle } from '@vueuse/core'
import { computed, nextTick } from 'vue'
// @ts-expect-error auto imported from @nuxtjs/color-mode
import { useColorMode } from '#imports'
Expand All @@ -14,7 +13,54 @@ const isDark = computed<boolean>({
mode.preference = isDark.value ? 'light' : 'dark'
},
})
const toggle = useToggle(isDark)
// @ts-expect-error: Transition API
const isAppearanceTransition = document.startViewTransition
&& !window.matchMedia('(prefers-reduced-motion: reduce)').matches
/**
* Credit to [@hooray](https://github.com/hooray)
* @see https://github.com/vuejs/vitepress/pull/2347
*/
function toggle(event?: MouseEvent) {
if (!isAppearanceTransition || !event) {
isDark.value = !isDark.value
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 () => {
isDark.value = !isDark.value
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: isDark.value
? [...clipPath].reverse()
: clipPath,
},
{
duration: 400,
easing: 'ease-in',
pseudoElement: isDark.value
? '::view-transition-old(root)'
: '::view-transition-new(root)',
},
)
})
}
const context = {
mode,
isDark,
Expand Down
2 changes: 1 addition & 1 deletion packages/devtools/client/components/DockingPanel.vue
Expand Up @@ -48,7 +48,7 @@ function refreshPage() {
</div>
<div px3 py2 border="b base" flex="~ gap-2">
<NDarkToggle v-slot="{ toggle, isDark }">
<NButton n="sm primary" @click="toggle()">
<NButton n="sm primary" @click="toggle">
<div carbon-sun dark:carbon-moon translate-y--1px /> {{ isDark.value ? 'Dark' : 'Light' }}
</NButton>
</NDarkToggle>
Expand Down
2 changes: 1 addition & 1 deletion packages/devtools/client/pages/settings.vue
Expand Up @@ -88,7 +88,7 @@ function toggleTabCategory(name: string, v: boolean) {
</h3>
<div>
<NDarkToggle v-slot="{ toggle, isDark }">
<NButton n="primary" @click="toggle()">
<NButton n="primary" @click="toggle">
<div carbon-sun dark:carbon-moon translate-y--1px /> {{ isDark.value ? 'Dark' : 'Light' }}
</NButton>
</NDarkToggle>
Expand Down
2 changes: 1 addition & 1 deletion packages/devtools/src/runtime/plugins/view/Container.vue
Expand Up @@ -76,7 +76,7 @@ function getToggleButtonPosition() {
background: #0C0C0C;
border: 1px solid rgba(125,125,125,0.2);
box-shadow: 3px 5px 10px rgba(0,0,0,0.1);
z-index: 2147483647;
z-index: 2147483645;
cursor: pointer;
opacity: 0.8;
padding: 0;
Expand Down
2 changes: 1 addition & 1 deletion packages/devtools/src/runtime/plugins/view/Frame.vue
Expand Up @@ -255,7 +255,7 @@ declare global {
<style scoped>
.nuxt-devtools-frame {
position: fixed;
z-index: 2147483646;
z-index: 2147483645;
}
.nuxt-devtools-frame iframe {
Expand Down

0 comments on commit 782e0da

Please sign in to comment.