From c8dfd00317eecc55b140b4896c24ee9b81bf6838 Mon Sep 17 00:00:00 2001 From: xintaofei Date: Sat, 11 Apr 2026 16:01:09 +0800 Subject: [PATCH] feat(appearance): add theme color picker, zoom level selector, reset button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 外观设置页新增三个 UI 单元:12 个 shadcn 主题预设的色盘按钮网格、6 档窗口缩放 下拉选择器、以及只重置主题色和缩放(不动主题模式)的恢复默认按钮。 i18n 键在上一个 Task 中已预备好,本提交后整个外观设置功能即可在浏览器中端到端使用。 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../settings/appearance-settings.tsx | 132 +++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/src/components/settings/appearance-settings.tsx b/src/components/settings/appearance-settings.tsx index 22c18e1..8c7b51f 100644 --- a/src/components/settings/appearance-settings.tsx +++ b/src/components/settings/appearance-settings.tsx @@ -1,8 +1,9 @@ "use client" -import { Monitor, Moon, Sun } from "lucide-react" +import { Monitor, Moon, RotateCcw, Sun, Type } from "lucide-react" import { useTranslations } from "next-intl" import { useTheme } from "next-themes" +import { Button } from "@/components/ui/button" import { Select, SelectContent, @@ -10,12 +11,26 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select" +import { useThemeColor, useZoomLevel } from "@/hooks/use-appearance" +import { cn } from "@/lib/utils" +import { + DEFAULT_THEME_COLOR, + DEFAULT_ZOOM_LEVEL, + THEME_COLOR_PREVIEW, + THEME_COLORS, + ZOOM_LEVELS, + type ThemeColor, + type ZoomLevel, +} from "@/lib/theme-presets" type ThemeMode = "system" | "light" | "dark" export function AppearanceSettings() { const t = useTranslations("AppearanceSettings") const { theme, resolvedTheme, setTheme } = useTheme() + const { themeColor, setThemeColor } = useThemeColor() + const { zoomLevel, setZoomLevel } = useZoomLevel() + const resolvedThemeLabel = resolvedTheme === "dark" ? t("resolvedTheme.dark") @@ -23,9 +38,18 @@ export function AppearanceSettings() { ? t("resolvedTheme.light") : t("resolvedTheme.unknown") + const isAtDefaults = + themeColor === DEFAULT_THEME_COLOR && zoomLevel === DEFAULT_ZOOM_LEVEL + + const handleResetToDefaults = () => { + setThemeColor(DEFAULT_THEME_COLOR) + setZoomLevel(DEFAULT_ZOOM_LEVEL) + } + return (
+ {/* ===== Theme Mode (existing) ===== */}
@@ -76,6 +100,112 @@ export function AppearanceSettings() {

+ + {/* ===== Theme Color (new) ===== */} +
+
+ +

+ {t("themeColor.sectionTitle")} +

+
+ +

+ {t("themeColor.sectionDescription")} +

+ +
+ {THEME_COLORS.map((color) => { + const isActive = themeColor === color + return ( + + ) + })} +
+ +

+ {t("themeColor.current", { + color: t(`themeColor.options.${themeColor}`), + })} +

+
+ + {/* ===== Zoom Level (new) ===== */} +
+
+ +

+ {t("zoomLevel.sectionTitle")} +

+
+ +

+ {t("zoomLevel.sectionDescription")} +

+ +
+ +

+ {t("zoomLevel.current", { zoom: zoomLevel })} +

+
+
+ + {/* ===== Reset to defaults (new) ===== */} +
+ +
)