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';