It adds a new main navigation menu on the website and in the documentation, offering more choices and simpler access to different parts of the content for the visitor. Co-authored-by: Benjamin Cabanes <3447705+bcabanes@users.noreply.github.com>
97 lines
3.2 KiB
TypeScript
97 lines
3.2 KiB
TypeScript
import { Listbox, Transition } from '@headlessui/react';
|
|
import {
|
|
ComputerDesktopIcon,
|
|
MoonIcon,
|
|
SunIcon,
|
|
} from '@heroicons/react/24/outline';
|
|
import cx from 'classnames';
|
|
import { ElementType, Fragment } from 'react';
|
|
import { Theme, useTheme } from './theme.provider';
|
|
|
|
export function ThemeSwitcher(): JSX.Element {
|
|
const [theme, setTheme] = useTheme();
|
|
const themeMap = {
|
|
dark: {
|
|
className: 'group-hover:text-white',
|
|
icon: <MoonIcon className="h-4 w-4" />,
|
|
},
|
|
light: {
|
|
className: 'group-hover:text-yellow-500',
|
|
icon: <SunIcon className="h-4 w-4" />,
|
|
},
|
|
system: {
|
|
className: 'group-hover:text-blue-500',
|
|
icon: <ComputerDesktopIcon className="h-4 w-4" />,
|
|
},
|
|
};
|
|
const availableThemes: { label: string; value: Theme; icon: ElementType }[] =
|
|
[
|
|
{
|
|
label: 'Light',
|
|
value: 'light',
|
|
icon: SunIcon,
|
|
},
|
|
{
|
|
label: 'Dark',
|
|
value: 'dark',
|
|
icon: MoonIcon,
|
|
},
|
|
{
|
|
label: 'System',
|
|
value: 'system',
|
|
icon: ComputerDesktopIcon,
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div className="inline-block">
|
|
<div className="group relative flex h-full w-full items-center px-1">
|
|
<Listbox value={theme} onChange={setTheme}>
|
|
<Listbox.Label className="sr-only">Theme</Listbox.Label>
|
|
<Listbox.Button
|
|
type="button"
|
|
className={cx(
|
|
'inline-flex p-2 text-sm font-medium opacity-60 transition-opacity group-hover:opacity-100',
|
|
themeMap[theme].className
|
|
)}
|
|
>
|
|
{themeMap[theme].icon}
|
|
</Listbox.Button>
|
|
|
|
<Transition
|
|
as={Fragment}
|
|
enter="transition ease-out duration-100"
|
|
enterFrom="transform opacity-0 scale-95"
|
|
enterTo="transform opacity-100 scale-100"
|
|
leave="transition ease-in duration-75"
|
|
leaveFrom="transform opacity-100 scale-100"
|
|
leaveTo="transform opacity-0 scale-95"
|
|
>
|
|
<Listbox.Options className="absolute top-full -right-10 z-50 mt-2 w-36 origin-top-right divide-y divide-slate-100 rounded-md bg-white shadow-lg ring-1 ring-black/5 focus:outline-none dark:divide-slate-800 dark:bg-slate-900 dark:ring-white/5">
|
|
{availableThemes.map((t) => (
|
|
<Listbox.Option key={t.value} value={t.value} as={Fragment}>
|
|
{({ active, selected }) => (
|
|
<li
|
|
className={cx(
|
|
'flex cursor-pointer items-center gap-2 px-4 py-2 text-sm',
|
|
{
|
|
'bg-slate-100 dark:bg-slate-800/60': active,
|
|
'text-blue-500 dark:text-sky-500': active || selected,
|
|
'text-slate-700 dark:text-slate-400': !active,
|
|
}
|
|
)}
|
|
>
|
|
<t.icon aria-hidden="true" className="h-4 w-4 shrink-0" />
|
|
{t.label}
|
|
</li>
|
|
)}
|
|
</Listbox.Option>
|
|
))}
|
|
</Listbox.Options>
|
|
</Transition>
|
|
</Listbox>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|