mirror of
https://github.com/Xevion/rdap.git
synced 2025-12-05 23:15:58 -06:00
refactor: simplify ThemeToggle with config-driven approach
Replace imperative theme toggling logic with declarative THEME_CONFIG object for cleaner, more maintainable code. Add type safety with Theme type and isTheme type guard.
This commit is contained in:
@@ -17,6 +17,8 @@ export default [
|
|||||||
// Base configuration with ignores
|
// Base configuration with ignores
|
||||||
{
|
{
|
||||||
ignores: [
|
ignores: [
|
||||||
|
".media/**",
|
||||||
|
"coverage/**",
|
||||||
".next/**",
|
".next/**",
|
||||||
"node_modules/**",
|
"node_modules/**",
|
||||||
"out/**",
|
"out/**",
|
||||||
|
|||||||
@@ -3,7 +3,21 @@
|
|||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import { IconButton } from "@radix-ui/themes";
|
import { IconButton } from "@radix-ui/themes";
|
||||||
import { MoonIcon, SunIcon, DesktopIcon } from "@radix-ui/react-icons";
|
import { MoonIcon, SunIcon, DesktopIcon } from "@radix-ui/react-icons";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState, type ReactElement } from "react";
|
||||||
|
|
||||||
|
type Theme = "light" | "dark" | "system";
|
||||||
|
|
||||||
|
const ICON_SIZE = 22;
|
||||||
|
|
||||||
|
const THEME_CONFIG: Record<Theme, { icon: ReactElement; next: Theme }> = {
|
||||||
|
light: { icon: <SunIcon width={ICON_SIZE} height={ICON_SIZE} />, next: "dark" },
|
||||||
|
dark: { icon: <MoonIcon width={ICON_SIZE} height={ICON_SIZE} />, next: "system" },
|
||||||
|
system: { icon: <DesktopIcon width={ICON_SIZE} height={ICON_SIZE} />, next: "light" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const isTheme = (value: string | undefined): value is Theme => {
|
||||||
|
return value === "light" || value === "dark" || value === "system";
|
||||||
|
};
|
||||||
|
|
||||||
export const ThemeToggle = () => {
|
export const ThemeToggle = () => {
|
||||||
const { theme, setTheme } = useTheme();
|
const { theme, setTheme } = useTheme();
|
||||||
@@ -18,44 +32,16 @@ export const ThemeToggle = () => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentTheme: Theme = isTheme(theme) ? theme : "system";
|
||||||
|
const { icon, next } = THEME_CONFIG[currentTheme];
|
||||||
|
|
||||||
const toggleTheme = () => {
|
const toggleTheme = () => {
|
||||||
if (theme === "light") {
|
setTheme(next);
|
||||||
setTheme("dark");
|
|
||||||
} else if (theme === "dark") {
|
|
||||||
setTheme("system");
|
|
||||||
} else {
|
|
||||||
setTheme("light");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNextTheme = () => {
|
|
||||||
if (theme === "light") return "dark";
|
|
||||||
if (theme === "dark") return "system";
|
|
||||||
return "light";
|
|
||||||
};
|
|
||||||
|
|
||||||
const getIcon = () => {
|
|
||||||
if (theme === "light") {
|
|
||||||
return <SunIcon width="22" height="22" />;
|
|
||||||
} else if (theme === "dark") {
|
|
||||||
return <MoonIcon width="22" height="22" />;
|
|
||||||
} else {
|
|
||||||
return <DesktopIcon width="22" height="22" />;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const nextTheme = getNextTheme();
|
|
||||||
const themeLabel = theme === "system" ? "system" : theme === "light" ? "light" : "dark";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton size="3" variant="ghost" onClick={toggleTheme} aria-label="Toggle theme">
|
||||||
size="3"
|
{icon}
|
||||||
variant="ghost"
|
|
||||||
onClick={toggleTheme}
|
|
||||||
aria-label="Toggle theme"
|
|
||||||
title={`Current: ${themeLabel} mode. Click to switch to ${nextTheme} mode`}
|
|
||||||
>
|
|
||||||
{getIcon()}
|
|
||||||
</IconButton>
|
</IconButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user