From fd32f4c59da13ec26b3c960d5cb5769ffd16f443 Mon Sep 17 00:00:00 2001 From: Julien Oculi Date: Tue, 13 Feb 2024 14:01:37 +0100 Subject: [PATCH] feat(ui): :sparkles: add theme picker --- components/Header.tsx | 2 ++ islands/ThemePicker.css | 29 ++++++++++++++++++ islands/ThemePicker.tsx | 55 ++++++++++++++++++++++++++++++++++ src/stylesheets/components.css | 1 + 4 files changed, 87 insertions(+) create mode 100644 islands/ThemePicker.css create mode 100644 islands/ThemePicker.tsx diff --git a/components/Header.tsx b/components/Header.tsx index 79e417a..b564973 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -1,4 +1,5 @@ import { asset } from '$fresh/runtime.ts' +import ThemePicker from '../islands/ThemePicker.tsx' export function Header() { return ( @@ -50,6 +51,7 @@ export function Header() { + ) diff --git a/islands/ThemePicker.css b/islands/ThemePicker.css new file mode 100644 index 0000000..cbf28ee --- /dev/null +++ b/islands/ThemePicker.css @@ -0,0 +1,29 @@ +.islands__theme_picker { + display: inline-flex; + align-items: center; + gap: var(--_gap-half); + height: fit-content; + margin: auto; + padding: var(--_gap-half); + + &:has(select:focus-visible) { + outline: currentColor solid var(--_border-size); + } + + & select { + border: none; + background-color: transparent; + outline: none; + color: currentColor; + } + + & option { + background-color: var(--_background-color); + } + + & span { + padding: 0; + font-weight: normal; + line-height: normal; + } +} diff --git a/islands/ThemePicker.tsx b/islands/ThemePicker.tsx new file mode 100644 index 0000000..0d445df --- /dev/null +++ b/islands/ThemePicker.tsx @@ -0,0 +1,55 @@ +import { useComputed, useSignal, useSignalEffect } from '@preact/signals' +import { IS_BROWSER } from '$fresh/runtime.ts' + +export default function ThemePicker() { + const colorSchemeQuery = '(prefers-color-scheme: dark)' + + const colorSchemeDark = useSignal( + IS_BROWSER ? matchMedia('(prefers-color-scheme: dark)').matches : false, + ) + + if (IS_BROWSER) { + matchMedia(colorSchemeQuery).addEventListener( + 'change', + (event) => colorSchemeDark.value = event.matches, + ) + } + + type Theme = 'system' | 'light' | 'dark' + const theme = useSignal( + localStorage.getItem('$cohabit.theme') as Theme ?? 'system', + ) + const themeIcon = useComputed(() => { + if (theme.value === 'light') { + return + } + if (theme.value === 'dark') { + return + } + //If not forced use system + if (colorSchemeDark.value) { + return + } + return + }) + + useSignalEffect(() => { + localStorage.setItem('$cohabit.theme', theme.value) + document.body.setAttribute('data-theme', theme.value) + }) + + return ( + + ) +} diff --git a/src/stylesheets/components.css b/src/stylesheets/components.css index 68309f3..f8cce73 100644 --- a/src/stylesheets/components.css +++ b/src/stylesheets/components.css @@ -1,3 +1,4 @@ @import url('../../components/Header.css'); @import url('../../components/Footer.css'); @import url('../../components/Heros.css'); +@import url('../../islands/ThemePicker.css');