diff options
Diffstat (limited to 'examples/portfolio/src/components/ThemeToggle.astro')
-rw-r--r-- | examples/portfolio/src/components/ThemeToggle.astro | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/examples/portfolio/src/components/ThemeToggle.astro b/examples/portfolio/src/components/ThemeToggle.astro new file mode 100644 index 000000000..88f7bf67c --- /dev/null +++ b/examples/portfolio/src/components/ThemeToggle.astro @@ -0,0 +1,95 @@ +--- +import Icon from './Icon.astro'; +--- + +<theme-toggle> + <button> + <span class="sr-only">Dark theme</span> + <span class="icon light"><Icon icon="sun" /></span> + <span class="icon dark"><Icon icon="moon-stars" /></span> + </button> +</theme-toggle> + +<style> + button { + display: flex; + border: 0; + border-radius: 999rem; + padding: 0; + background-color: var(--gray-999); + box-shadow: inset 0 0 0 1px var(--accent-overlay); + cursor: pointer; + } + + .icon { + z-index: 1; + position: relative; + display: flex; + padding: 0.5rem; + width: 2rem; + height: 2rem; + font-size: 1rem; + color: var(--accent-overlay); + } + + .icon.light::before { + content: ''; + z-index: -1; + position: absolute; + inset: 0; + background-color: var(--accent-regular); + border-radius: 999rem; + } + + :global(.theme-dark) .icon.light::before { + transform: translateX(100%); + } + + :global(.theme-dark) .icon.dark, + :global(html:not(.theme-dark)) .icon.light, + button[aria-pressed='false'] .icon.light { + color: var(--accent-text-over); + } + + @media (prefers-reduced-motion: no-preference) { + .icon, + .icon.light::before { + transition: + transform var(--theme-transition), + color var(--theme-transition); + } + } + + @media (forced-colors: active) { + .icon.light::before { + background-color: SelectedItem; + } + } +</style> + +<script> + class ThemeToggle extends HTMLElement { + constructor() { + super(); + + const button = this.querySelector('button')!; + + /** Set the theme to dark/light mode. */ + const setTheme = (dark: boolean) => { + document.documentElement.classList[dark ? 'add' : 'remove']('theme-dark'); + button.setAttribute('aria-pressed', String(dark)); + }; + + // Toggle the theme when a user clicks the button. + button.addEventListener('click', () => setTheme(!this.isDark())); + + // Initialize button state to reflect current theme. + setTheme(this.isDark()); + } + + isDark() { + return document.documentElement.classList.contains('theme-dark'); + } + } + customElements.define('theme-toggle', ThemeToggle); +</script> |