3de59ccaaf
Build & Push Docker Image / build (push) Successful in 2m33s
- translate remaining pages/components (admin, analytics, redundancy, trash, compare, browse, watchlist, admin tools tab, category combobox, theme toggle, tool preview card, tool-new/edit) to t() calls - locales: 453 keys each, parity verified - docs: bilingual handbook + release notes via *.en.md variants, language-aware docs.tsx (markdown paths, nav titles, search index), LanguageSwitcher in docs header - generate-docs: emit per-locale handbook/release/search output, localized index.json fields (fileEn/titleEn), en-aware snapshots
70 lines
2.4 KiB
TypeScript
70 lines
2.4 KiB
TypeScript
import { ChevronDown, Lightbulb, LightbulbOff, Monitor, Moon, Sun } from "lucide-react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuTrigger,
|
|
DropdownMenuContent,
|
|
DropdownMenuLabel,
|
|
DropdownMenuRadioGroup,
|
|
DropdownMenuRadioItem,
|
|
} from "@/components/ui/dropdown-menu";
|
|
import { useTheme, type Theme } from "@/hooks/use-theme";
|
|
|
|
export function ThemeToggle() {
|
|
const { t } = useTranslation();
|
|
const { theme, setTheme, resolvedTheme } = useTheme();
|
|
const isDark = resolvedTheme === "dark";
|
|
|
|
function quickToggle() {
|
|
setTheme(isDark ? "light" : "dark");
|
|
}
|
|
|
|
return (
|
|
<div className="flex items-center gap-0.5" data-testid="theme-toggle">
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="h-9 w-9"
|
|
onClick={quickToggle}
|
|
title={isDark ? t("theme.switchLight") : t("theme.switchDark")}
|
|
aria-label={isDark ? t("theme.switchLight") : t("theme.switchDark")}
|
|
data-testid="button-theme-quick-toggle"
|
|
>
|
|
{isDark ? <Lightbulb className="w-4 h-4" /> : <LightbulbOff className="w-4 h-4" />}
|
|
</Button>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="h-9 w-9"
|
|
aria-label={t("theme.chooseTitle")}
|
|
title={t("theme.chooseTitle")}
|
|
data-testid="button-theme-menu"
|
|
>
|
|
<ChevronDown className="w-4 h-4" />
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" sideOffset={6}>
|
|
<DropdownMenuLabel>{t("theme.title")}</DropdownMenuLabel>
|
|
<DropdownMenuRadioGroup value={theme} onValueChange={(v) => setTheme(v as Theme)}>
|
|
<DropdownMenuRadioItem value="light">
|
|
<Sun className="w-4 h-4 mr-2" />
|
|
{t("theme.light")}
|
|
</DropdownMenuRadioItem>
|
|
<DropdownMenuRadioItem value="dark">
|
|
<Moon className="w-4 h-4 mr-2" />
|
|
{t("theme.dark")}
|
|
</DropdownMenuRadioItem>
|
|
<DropdownMenuRadioItem value="system">
|
|
<Monitor className="w-4 h-4 mr-2" />
|
|
{t("theme.system")}
|
|
</DropdownMenuRadioItem>
|
|
</DropdownMenuRadioGroup>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
);
|
|
}
|