aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/ThemeToggle.astro
blob: f7b09269f97e093fc77d7d70d4830c09d9fa4bcc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
---
import { Button } from '@/components/ui/button'
import { Icon } from 'astro-icon/components'
---

<Button
  id="theme-toggle"
  variant="ghost"
  size="icon"
  title="Toggle theme"
  className="-my-2 -me-2 size-8"
>
  <Icon name="lucide:sun" class="size-4 dark:hidden" />
  <Icon name="lucide:moon" class="absolute hidden size-4 dark:block" />
  <span class="sr-only">Toggle theme</span>
</Button>

<script is:inline data-astro-rerun>
  ;(() => {
    const theme = (() => {
      const stored = localStorage?.getItem('theme') ?? ''
      if (['dark', 'light'].includes(stored)) return stored
      return window.matchMedia('(prefers-color-scheme: dark)').matches
        ? 'dark'
        : 'light'
    })()

    document.documentElement.setAttribute('data-theme', theme)
    window.localStorage.setItem('theme', theme)
  })()
</script>

<script>
  function handleToggleClick() {
    const element = document.documentElement
    const currentTheme = element.getAttribute('data-theme')
    const newTheme = currentTheme === 'dark' ? 'light' : 'dark'

    element.classList.add('[&_*]:transition-none')
    element.setAttribute('data-theme', newTheme)
    window.getComputedStyle(element).getPropertyValue('opacity')

    requestAnimationFrame(() => {
      element.classList.remove('[&_*]:transition-none')
    })

    localStorage.setItem('theme', newTheme)
  }

  function initThemeToggle() {
    document
      .getElementById('theme-toggle')
      ?.addEventListener('click', handleToggleClick)
  }

  initThemeToggle()

  document.addEventListener('astro:after-swap', () => {
    const storedTheme = localStorage.getItem('theme') || 'light'
    const element = document.documentElement

    element.classList.add('[&_*]:transition-none')
    window.getComputedStyle(element).getPropertyValue('opacity')
    element.setAttribute('data-theme', storedTheme)

    requestAnimationFrame(() => {
      element.classList.remove('[&_*]:transition-none')
    })

    initThemeToggle()
  })
</script>