'use client' import { Fragment, useEffect, useState } from 'react' import { useTheme } from 'next-themes' import { Menu, RadioGroup, Transition } from '@headlessui/react' const Sun = () => ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="group:hover:text-gray-100 h-6 w-6" > <path fillRule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clipRule="evenodd" /> </svg> ) const Moon = () => ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="group:hover:text-gray-100 h-6 w-6" > <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" /> </svg> ) const Monitor = () => ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="group:hover:text-gray-100 h-6 w-6" > <rect x="3" y="3" width="14" height="10" rx="2" ry="2"></rect> <line x1="7" y1="17" x2="13" y2="17"></line> <line x1="10" y1="13" x2="10" y2="17"></line> </svg> ) const Blank = () => <svg className="h-6 w-6" /> const ThemeSwitch = () => { const [mounted, setMounted] = useState(false) const { theme, setTheme, resolvedTheme } = useTheme() // When mounted on client, now we can show the UI useEffect(() => setMounted(true), []) return ( <div className="mr-5 flex items-center"> <Menu as="div" className="relative inline-block text-left"> <div className="flex items-center justify-center hover:text-primary-500 dark:hover:text-primary-400"> <Menu.Button> {mounted ? resolvedTheme === 'dark' ? <Moon /> : <Sun /> : <Blank />} </Menu.Button> </div> <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" > <Menu.Items className="absolute right-0 z-50 mt-2 w-32 origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-800"> <RadioGroup value={theme} onChange={setTheme}> <div className="p-1"> <RadioGroup.Option value="light"> <Menu.Item> {({ active }) => ( <button className={`${ active ? 'bg-primary-600 text-white' : '' } group flex w-full items-center rounded-md px-2 py-2 text-sm`} > <div className="mr-2"> <Sun /> </div> Light </button> )} </Menu.Item> </RadioGroup.Option> <RadioGroup.Option value="dark"> <Menu.Item> {({ active }) => ( <button className={`${ active ? 'bg-primary-600 text-white' : '' } group flex w-full items-center rounded-md px-2 py-2 text-sm`} > <div className="mr-2"> <Moon /> </div> Dark </button> )} </Menu.Item> </RadioGroup.Option> <RadioGroup.Option value="system"> <Menu.Item> {({ active }) => ( <button className={`${ active ? 'bg-primary-600 text-white' : '' } group flex w-full items-center rounded-md px-2 py-2 text-sm`} > <div className="mr-2"> <Monitor /> </div> System </button> )} </Menu.Item> </RadioGroup.Option> </div> </RadioGroup> </Menu.Items> </Transition> </Menu> </div> ) } export default ThemeSwitch