Skip to content

Commit

Permalink
fix: support Astro's built-in view transitions (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
ocavue authored Oct 8, 2024
1 parent bdd2d8f commit bdc0ef0
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 24 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,14 @@ npm install astro-theme-toggle
</button>
<script>
import { handleToggleClick } from 'astro-theme-toggle';
document.getElementById('theme-toggle')?.addEventListener('click', handleToggleClick);
import { handleToggleClick } from 'astro-theme-toggle'
const addListener = () => {
document
.getElementById('theme-toggle')
?.addEventListener('click', handleToggleClick)
}
addListener()
document.addEventListener('astro:after-swap', addListener)
</script>
<style is:global>
Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cd $(dirname $0)
export PATH=$PATH:$PWD/node_modules/.bin

esbuild --minify --bundle --outdir=temp lib/theme-script.ts
cp lib/theme-style.astro lib/theme-script.astro
echo "" > lib/theme-script.astro
echo "<script is:inline>" >> lib/theme-script.astro
cat temp/theme-script.js >> lib/theme-script.astro
echo "</script>" >> lib/theme-script.astro
Expand Down
27 changes: 25 additions & 2 deletions lib/handle-toggle-click.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
import { toggleTheme } from './theme'

const STYLE_ID = 'astro-theme-toggle-temporary-styles'
const STYLE_CONTENT =
'::view-transition-old(root), ::view-transition-new(root) { animation: none; mix-blend-mode: normal; }'

function removeTemporaryStyles() {
const style = document.getElementById(STYLE_ID)
style?.remove()
}

function injectTemporaryStyles() {
removeTemporaryStyles()
const style = document.createElement('style')
style.id = STYLE_ID
style.textContent = STYLE_CONTENT
document.head.appendChild(style)
}

async function startCircleAnimation(
callback: () => void,
x: number,
Expand All @@ -8,6 +25,7 @@ async function startCircleAnimation(
const doc = document as unknown as {
startViewTransition?: (updateCallback?: () => unknown) => {
ready?: Promise<void>
finished?: Promise<void>
}
}

Expand All @@ -16,9 +34,14 @@ async function startCircleAnimation(
return
}

await doc.startViewTransition(() => {
injectTemporaryStyles()

const transition = doc.startViewTransition(() => {
callback()
})?.ready
})

await transition?.ready
void transition?.finished?.then(removeTemporaryStyles)

const gradientOffset = 0.7
const maskSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8"><defs><radialGradient id="toggle-theme-gradient"><stop offset="${gradientOffset}"/><stop offset="1" stop-opacity="0"/></radialGradient></defs><circle cx="4" cy="4" r="4" fill="url(#toggle-theme-gradient)"/></svg>`
Expand Down
10 changes: 2 additions & 8 deletions lib/theme-script.astro
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
<style is:global>
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
mix-blend-mode: normal;
}
</style>

<script is:inline>
"use strict";(()=>{(()=>{let t="theme-toggle";function o(){return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function l(){let e=localStorage.getItem(t);return e==="dark"||e==="light"?e:null}function n(){return l()||o()}function c(e){e===o()?localStorage.removeItem(t):localStorage.setItem(t,e)}function s(e){let m=document.documentElement;m.classList.toggle("dark",e==="dark"),m.style.colorScheme=e}function r(e){c(e),s(e)}r(n()),window.astroThemeToggle={setTheme:r,getTheme:n}})();})();
"use strict";(()=>{(()=>{let t="theme-toggle";function o(){return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function c(){let e=localStorage.getItem(t);return e==="dark"||e==="light"?e:null}function n(){return c()||o()}function l(e){e===o()?localStorage.removeItem(t):localStorage.setItem(t,e)}function a(e){let s=document.documentElement;s.classList.toggle("dark",e==="dark"),s.style.colorScheme=e}function r(e){l(e),a(e)}function m(){r(n())}m(),document.addEventListener("astro:after-swap",m),window.astroThemeToggle={setTheme:r,getTheme:n}})();})();
</script>
9 changes: 8 additions & 1 deletion lib/theme-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,15 @@
setStyle(theme)
}

function setupTheme() {
setTheme(getTheme())
}

// Set the theme on load
setTheme(getTheme())
setupTheme()

// Set the theme after a page swap
document.addEventListener('astro:after-swap', setupTheme)

window.astroThemeToggle = { setTheme, getTheme }
})()
7 changes: 0 additions & 7 deletions lib/theme-style.astro

This file was deleted.

2 changes: 2 additions & 0 deletions website/components/head.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
---
import { ThemeScript } from 'astro-theme-toggle'
import { ViewTransitions } from 'astro:transitions'
---

<head>
<title>astro-theme-toggle</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<ViewTransitions />
<ThemeScript />
</head>
10 changes: 7 additions & 3 deletions website/components/theme-toggle-button.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import IconMoonSvg from './icon-moon-svg.astro'

<script>
import { handleToggleClick } from 'astro-theme-toggle'
document
.getElementById('theme-toggle')
?.addEventListener('click', handleToggleClick)
const addListener = () => {
document
.getElementById('theme-toggle')
?.addEventListener('click', handleToggleClick)
}
addListener()
document.addEventListener('astro:after-swap', addListener)
</script>

0 comments on commit bdc0ef0

Please sign in to comment.