Explicação do código:
Esse componente ModeToggle
permite que o usuário alterne entre os temas "light", "dark" e "system" (que segue a configuração do sistema do usuário). Ele usa a biblioteca next-themes
para lidar com a troca de temas.
Como o componente funciona:
-
Uso de
useTheme
donext-themes
: O hookuseTheme
é utilizado para acessar e modificar o tema da aplicação. Ele possui o métodosetTheme
que define o tema desejado. -
Modo de operação diferente para a sidebar e navbar: Dependendo do contexto (passado como props), o componente renderiza de maneira diferente:
- Sidebar: Usando um
DropdownMenu
com botões para alternar os temas. - Navbar: Um botão de alternância com ícones de Sol (☀️) e Lua (🌙) que muda de acordo com o tema atual.
- Sidebar: Usando um
Detalhamento do código:
-
Importações:
- O componente importa ícones (
Moon
,Sun
) da bibliotecalucide-react
. - O
useTheme
donext-themes
para gerenciar os temas. - Componentes de UI como
Button
,DropdownMenu
,SidebarMenuItem
, e outros para a estrutura visual.
- O componente importa ícones (
-
Condicional de Contexto:
- Se o contexto for
"sidebar"
, o componente renderiza oDropdownMenu
dentro de um item da sidebar. - Se o contexto for diferente (como na navbar), ele renderiza apenas um botão de alternância de tema.
- Se o contexto for
-
Mudança de Tema:
- O botão de alternância chama a função
setTheme
com o tema desejado ('light'
,'dark'
,'system'
). - Ícones de Sol e Lua são animados para indicar o tema atual e para um efeito visual ao alternar entre os temas.
- O botão de alternância chama a função
Código completo:
'use client'
import * as React from 'react'
import { Moon, Sun } from 'lucide-react'
import { useTheme } from 'next-themes'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { SidebarMenuItem, SidebarMenuButton } from '@/components/ui/sidebar'
export function ModeToggle({ context = 'navbar' }) {
const { setTheme } = useTheme()
if (context === 'sidebar') {
// Estilo para sidebar com DropdownMenu
return (
<SidebarMenuItem className="list-none">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuButton size="sm">
<div className="flex items-center">
<div className="h-[1.2rem] w-[1.2rem] flex items-center justify-center">
<Sun className="transition-all dark:rotate-90 dark:scale-0" />
<Moon className="absolute transition-all scale-0 dark:scale-100 dark:rotate-0" />
</div>
<span className="ml-3">Toggle theme</span>
</div>
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem onClick={() => setTheme('light')}>Light</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme('dark')}>Dark</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme('system')}>System</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
)
}
// Estilo para a navbar
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme('light')}>Light</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme('dark')}>Dark</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme('system')}>System</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
Emojis:
- ☀️ para o Sol (modo claro)
- 🌙 para a Lua (modo escuro)