From bfbeef726d9985bdaefe5dda0b4e15e10e1ac495 Mon Sep 17 00:00:00 2001 From: gaoziman <2942894660@qq.com> Date: Fri, 19 Dec 2025 22:36:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=BB=84=E4=BB=B6):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=80=9A=E7=94=A8UI=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 BrandIcon 品牌图标组件 - 添加 ThemeToggle 主题切换组件 - 添加 Toast 消息提示组件 --- src/components/ui/BrandIcon.tsx | 39 +++++++++++++++++++++ src/components/ui/ThemeToggle.tsx | 57 +++++++++++++++++++++++++++++++ src/components/ui/Toast.tsx | 30 ++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 src/components/ui/BrandIcon.tsx create mode 100644 src/components/ui/ThemeToggle.tsx create mode 100644 src/components/ui/Toast.tsx diff --git a/src/components/ui/BrandIcon.tsx b/src/components/ui/BrandIcon.tsx new file mode 100644 index 0000000..ba71386 --- /dev/null +++ b/src/components/ui/BrandIcon.tsx @@ -0,0 +1,39 @@ +'use client'; + +import { cn } from '@/lib/utils'; + +interface BrandIconProps { + size?: 'sm' | 'md' | 'lg' | 'xl'; + className?: string; +} + +const sizeMap = { + sm: 'w-6 h-6', + md: 'w-8 h-8', + lg: 'w-12 h-12', + xl: 'w-16 h-16', +}; + +export function BrandIcon({ size = 'md', className }: BrandIconProps) { + return ( + + {/* 八角星形图标 */} + + {/* 中心小星 */} + + + ); +} diff --git a/src/components/ui/ThemeToggle.tsx b/src/components/ui/ThemeToggle.tsx new file mode 100644 index 0000000..273d146 --- /dev/null +++ b/src/components/ui/ThemeToggle.tsx @@ -0,0 +1,57 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import { Moon, Sun } from 'lucide-react'; +import { cn } from '@/lib/utils'; + +interface ThemeToggleProps { + className?: string; +} + +export function ThemeToggle({ className }: ThemeToggleProps) { + const [isDark, setIsDark] = useState(false); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + // 从 localStorage 或 document 获取当前主题 + const currentTheme = document.documentElement.getAttribute('data-theme'); + const savedTheme = localStorage.getItem('theme'); + const theme = currentTheme || savedTheme || 'light'; + setIsDark(theme === 'dark'); + }, []); + + const toggleTheme = () => { + const newTheme = isDark ? 'light' : 'dark'; + setIsDark(!isDark); + document.documentElement.setAttribute('data-theme', newTheme); + localStorage.setItem('theme', newTheme); + }; + + // 避免服务端渲染不匹配 + if (!mounted) { + return ( + + ); + } + + return ( + + ); +} diff --git a/src/components/ui/Toast.tsx b/src/components/ui/Toast.tsx new file mode 100644 index 0000000..e80c54c --- /dev/null +++ b/src/components/ui/Toast.tsx @@ -0,0 +1,30 @@ +'use client'; + +import { Toaster as SonnerToaster } from 'sonner'; + +export function Toaster() { + return ( + + ); +} + +// 导出 toast 函数以便在组件中使用 +export { toast } from 'sonner';