aboutsummaryrefslogtreecommitdiff
path: root/examples/portfolio/src/components/ThemeToggle.astro
diff options
context:
space:
mode:
Diffstat (limited to 'examples/portfolio/src/components/ThemeToggle.astro')
-rw-r--r--examples/portfolio/src/components/ThemeToggle.astro95
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>