portfolio/src/components/ThemeSwitch/index.tsx

58 lines
1.7 KiB
TypeScript
Raw Normal View History

'use client'
2023-01-29 04:58:06 +01:00
import { useEffect, useState } from 'react'
2023-01-29 04:02:05 +01:00
import * as Select from '@radix-ui/react-select'
2023-01-28 02:27:49 +01:00
import { useTheme } from 'next-themes'
2023-01-29 04:58:06 +01:00
import Icon from '../Icon'
2023-01-29 04:02:05 +01:00
import { Item } from './Item'
2023-01-29 04:58:06 +01:00
import styles from './index.module.css'
2023-01-28 02:27:49 +01:00
2023-01-29 04:02:05 +01:00
export function getIconName(theme: string) {
2023-02-01 17:11:29 +01:00
return theme === 'light' ? 'Sun' : theme === 'dark' ? 'Moon' : 'Contrast'
2023-01-28 02:27:49 +01:00
}
export default function ThemeSwitch() {
2023-01-28 02:27:49 +01:00
const { theme, themes, resolvedTheme, setTheme } = useTheme()
const iconName = getIconName(resolvedTheme || '')
2023-01-28 02:27:49 +01:00
// hydration errors workaround
const [mounted, setMounted] = useState(false)
2023-01-28 02:27:49 +01:00
useEffect(() => setMounted(true), [])
return (
<aside className={styles.themeSwitch}>
{mounted ? (
<Select.Root
defaultValue={theme}
value={theme}
onValueChange={(value) => setTheme(value)}
>
<Select.Trigger className={styles.trigger} aria-label="Theme Switch">
<Select.Value>
<Icon name={iconName} />
</Select.Value>
<Select.Icon className={styles.chevron}>
<Icon name="ChevronDown" />
</Select.Icon>
</Select.Trigger>
2023-01-28 02:27:49 +01:00
<Select.Portal>
<Select.Content
className={styles.content}
position="popper"
align="end"
2023-01-28 02:27:49 +01:00
>
<Select.Arrow className={styles.arrow} width={14} height={7} />
<Select.Viewport className={styles.viewport}>
{themes
.map((theme) => <Item key={theme} theme={theme}></Item>)
.reverse()}
</Select.Viewport>
</Select.Content>
</Select.Portal>
</Select.Root>
) : null}
</aside>
)
}