diff --git a/app/page.tsx b/app/page.tsx index d36eafc..3dae286 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -11,6 +11,7 @@ import RankingPanel from '@/components/RankingPanel' import AIChatWidget from '@/components/AIChatWidget' import ChangePasswordModal from '@/components/ChangePasswordModal' import MaterialPreviewModal from '@/components/MaterialPreviewModal' +import Tag from '@/components/ui/Tag' import { useThemeStyles } from '@/lib/ui-styles' import { useDialog } from '@/components/ui/DialogProvider' @@ -513,8 +514,8 @@ export default function Home() { if (status === 'loading' || loading) { return ( -
-
加载中...
+
+
加载中...
) } @@ -524,7 +525,7 @@ export default function Home() { } return ( -
+
{/* 内网切换提示 */} @@ -594,7 +595,7 @@ export default function Home() { className={`${styles.inputStyles.base} pl-12 pr-4`} /> setSearchKeyword('')} - className="absolute right-4 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" + className="absolute right-4 top-1/2 transform -translate-y-1/2 text-slate-400 hover:text-slate-600 dark:hover:text-slate-300" > @@ -640,9 +641,9 @@ export default function Home() { <>
-

类型分页

+

类型分页

{selectedMaterialType && ( - + {materials.length} 个素材 )} @@ -653,7 +654,7 @@ export default function Home() { className={`px-4 py-2 rounded-full text-sm font-medium transition-all ${ selectedMaterialType === '' ? 'text-white' - : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700' + : 'bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700' }`} style={selectedMaterialType === '' ? { backgroundColor: themeColor } : {}} > @@ -666,7 +667,7 @@ export default function Home() { className={`px-4 py-2 rounded-full text-sm font-medium transition-all ${ selectedMaterialType === type.value ? 'text-white' - : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700' + : 'bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700' }`} style={selectedMaterialType === type.value ? { backgroundColor: themeColor } : {}} > @@ -679,9 +680,9 @@ export default function Home() { {/* Category Filter (使用店铺) */}
-

使用店铺

+

使用店铺

{selectedCategory && ( - + {materials.length} 个素材 )} @@ -692,15 +693,15 @@ export default function Home() { className={`px-4 py-2 rounded-full text-sm font-medium transition-all ${ selectedCategory === '' ? 'text-white' - : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700' + : 'bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700' }`} style={selectedCategory === '' ? { backgroundColor: themeColor } : {}} > 全部 ({totalMaterialsCount}) @@ -712,15 +713,15 @@ export default function Home() { className={`px-4 py-2 rounded-full text-sm font-medium transition-all ${ selectedCategory === category.name ? 'text-white' - : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700' + : 'bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700' }`} style={selectedCategory === category.name ? { backgroundColor: themeColor } : {}} > {category.name} ({category.count || 0}) @@ -732,9 +733,9 @@ export default function Home() { {/* Scene Filter (场景类别) */}
-

场景类别

+

场景类别

{selectedScene && ( - + {materials.length} 个素材 )} @@ -745,15 +746,15 @@ export default function Home() { className={`px-4 py-2 rounded-full text-sm font-medium transition-all ${ selectedScene === '' ? 'text-white' - : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700' + : 'bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700' }`} style={selectedScene === '' ? { backgroundColor: themeColor } : {}} > 全部 ({totalMaterialsCount}) @@ -765,15 +766,15 @@ export default function Home() { className={`px-4 py-2 rounded-full text-sm font-medium transition-all ${ selectedScene === scene.name ? 'text-white' - : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700' + : 'bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700' }`} style={selectedScene === scene.name ? { backgroundColor: themeColor } : {}} > {scene.name} ({scene.count || 0}) @@ -786,9 +787,9 @@ export default function Home() { {platforms.length > 0 && (
-

平台分类

+

平台分类

{selectedPlatform && ( - + {materials.length} 个素材 )} @@ -799,15 +800,15 @@ export default function Home() { className={`px-4 py-2 rounded-full text-sm font-medium transition-all ${ selectedPlatform === '' ? 'text-white' - : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700' + : 'bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700' }`} style={selectedPlatform === '' ? { backgroundColor: themeColor } : {}} > 全部 ({totalMaterialsCount}) @@ -819,15 +820,15 @@ export default function Home() { className={`px-4 py-2 rounded-full text-sm font-medium transition-all ${ selectedPlatform === platform.name ? 'text-white' - : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700' + : 'bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700' }`} style={selectedPlatform === platform.name ? { backgroundColor: themeColor } : {}} > {platform.name} ({platform.count || 0}) @@ -840,7 +841,7 @@ export default function Home() { {/* Month Filter (上传月份) */}
-

上传月份

+

上传月份

)} {selectedCategory && ( - + 店铺: {selectedCategory} )} {selectedScene && ( - + 场景类别: {selectedScene} )} {selectedMaterialType && ( - + 素材类型: {selectedMaterialType} )} {selectedPlatform && ( - + 平台分类: {selectedPlatform} )} {selectedMonth && ( - + 月份: {months.find(m => m.value === selectedMonth)?.label || selectedMonth} @@ -1004,7 +1005,7 @@ export default function Home() { 清除所有筛选
-
+
💡 提示:可以组合使用多个筛选条件,找到更精确的素材
@@ -1014,11 +1015,11 @@ export default function Home() { {/* Materials Grid */} {loading ? (
-

加载中...

+

加载中...

) : materials.length === 0 ? (
-

+

{searchKeyword || selectedCategory || selectedScene || selectedMaterialType || selectedPlatform ? '没有找到匹配的素材' : '还没有素材,快来上传第一个吧!'}

@@ -1064,24 +1065,16 @@ export default function Home() {
{/* 店铺、场景、素材类型和渲染器 */}
- - {material.categoryName} - - - {material.sceneName} - - - {material.materialType} - + {material.categoryName} + {material.sceneName} + {material.materialType} {material.materialType === '3DMAX' && ( - - {material.renderer} - + {material.renderer} )}
{/* 作者和时间 */} -
+

作者: {material.authorName} @@ -1094,13 +1087,13 @@ export default function Home() { 大小: {formatFileSize(material.zipFileSize)}

-

+

{format(new Date(material.createdAt), 'yyyy-MM-dd HH:mm')}

{/* 统计数据 */} -
+
@@ -1135,7 +1128,7 @@ export default function Home() { )} @@ -1201,7 +1194,7 @@ export default function Home() { window.scrollTo({ top: 0, behavior: 'smooth' }) }} disabled={currentPage === 1} - className="px-4 py-2 rounded-lg bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all" + className={`${styles.buttonStyles.secondary} ${styles.buttonModifiers.compact} disabled:opacity-50 disabled:cursor-not-allowed`} > @@ -1232,7 +1225,7 @@ export default function Home() { className={`px-4 py-2 rounded-lg transition-all ${ currentPage === pageNum ? 'text-white font-medium' - : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700' + : 'bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700' }`} style={currentPage === pageNum ? { backgroundColor: themeColor } : {}} > @@ -1249,7 +1242,7 @@ export default function Home() { window.scrollTo({ top: 0, behavior: 'smooth' }) }} disabled={currentPage === totalPages} - className="px-4 py-2 rounded-lg bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all" + className={`${styles.buttonStyles.secondary} ${styles.buttonModifiers.compact} disabled:opacity-50 disabled:cursor-not-allowed`} > @@ -1263,7 +1256,7 @@ export default function Home() { window.scrollTo({ top: 0, behavior: 'smooth' }) }} disabled={currentPage === totalPages} - className="px-4 py-2 rounded-lg bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all" + className={`${styles.buttonStyles.secondary} ${styles.buttonModifiers.compact} disabled:opacity-50 disabled:cursor-not-allowed`} > 末页 @@ -1271,11 +1264,11 @@ export default function Home() { {/* 页码跳转和信息 */}
- + 第 {currentPage} / {totalPages} 页,共 {totalMaterialsCount} 条
- 跳至 + 跳至 - 页 + 页 @@ -1567,11 +1560,11 @@ export default function Home() { onClick={() => setShowShareModal(false)} >
e.stopPropagation()} > -

分享链接

-
+

分享链接

+
{shareUrl}
@@ -1584,7 +1577,7 @@ export default function Home() { diff --git a/components/ui/Badge.tsx b/components/ui/Badge.tsx new file mode 100644 index 0000000..9c8553a --- /dev/null +++ b/components/ui/Badge.tsx @@ -0,0 +1,40 @@ +'use client' + +import { ReactNode } from 'react' +import { useThemeStyles, cn } from '@/lib/ui-styles' + +interface BadgeProps { + children: ReactNode + variant?: 'primary' | 'success' | 'warning' | 'danger' + size?: 'sm' | 'md' | 'lg' + className?: string +} + +export default function Badge({ + children, + variant = 'primary', + size = 'md', + className = '', +}: BadgeProps) { + const styles = useThemeStyles() + + const sizeClasses = { + sm: 'px-2 py-0.5 text-xs', + md: 'px-2 py-1 text-xs', + lg: 'px-3 py-1.5 text-sm', + } + + return ( + + {children} + + ) +} + diff --git a/components/ui/Button.tsx b/components/ui/Button.tsx new file mode 100644 index 0000000..c77a67d --- /dev/null +++ b/components/ui/Button.tsx @@ -0,0 +1,86 @@ +'use client' + +import { ButtonHTMLAttributes, ReactNode, forwardRef } from 'react' +import { useThemeStyles, cn } from '@/lib/ui-styles' + +interface ButtonProps extends ButtonHTMLAttributes { + children: ReactNode + variant?: 'primary' | 'secondary' | 'ghost' | 'danger' | 'success' + size?: 'sm' | 'md' | 'lg' + fullWidth?: boolean + loading?: boolean +} + +const Button = forwardRef( + ( + { + children, + variant = 'primary', + size = 'md', + fullWidth = false, + loading = false, + disabled, + className = '', + ...props + }, + ref + ) => { + const styles = useThemeStyles() + + const sizeClasses = { + sm: styles.buttonModifiers.compactXs, + md: '', + lg: 'px-8 py-4 text-base', + } + + const variantClass = styles.buttonStyles[variant] + + return ( + + ) + } +) + +Button.displayName = 'Button' + +export default Button + diff --git a/components/ui/Input.tsx b/components/ui/Input.tsx new file mode 100644 index 0000000..ec2ac97 --- /dev/null +++ b/components/ui/Input.tsx @@ -0,0 +1,51 @@ +'use client' + +import { InputHTMLAttributes, forwardRef } from 'react' +import { useThemeStyles, cn } from '@/lib/ui-styles' + +interface InputProps extends InputHTMLAttributes { + error?: boolean + size?: 'sm' | 'md' | 'lg' + fullWidth?: boolean +} + +const Input = forwardRef( + ( + { + error = false, + size = 'md', + fullWidth = true, + className = '', + ...props + }, + ref + ) => { + const styles = useThemeStyles() + + const sizeClasses = { + sm: styles.inputModifiers.compactXs, + md: '', + lg: 'px-5 py-4 text-base', + } + + const inputClass = error ? styles.inputStyles.error : styles.inputStyles.base + + return ( + + ) + } +) + +Input.displayName = 'Input' + +export default Input + diff --git a/components/ui/Tag.tsx b/components/ui/Tag.tsx new file mode 100644 index 0000000..3455b8f --- /dev/null +++ b/components/ui/Tag.tsx @@ -0,0 +1,56 @@ +'use client' + +import { ReactNode } from 'react' +import { useThemeStyles, cn } from '@/lib/ui-styles' + +interface TagProps { + children: ReactNode + color?: 'blue' | 'green' | 'orange' | 'purple' | 'indigo' | 'pink' | 'cyan' + size?: 'sm' | 'md' | 'lg' + className?: string + onClick?: () => void +} + +export default function Tag({ + children, + color = 'blue', + size = 'md', + className = '', + onClick, +}: TagProps) { + const styles = useThemeStyles() + + const colorClasses = { + blue: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300', + green: 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300', + orange: 'bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-300', + purple: 'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300', + indigo: 'bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300', + pink: 'bg-pink-100 dark:bg-pink-900/30 text-pink-700 dark:text-pink-300', + cyan: 'bg-cyan-100 dark:bg-cyan-900/30 text-cyan-700 dark:text-cyan-300', + } + + const sizeClasses = { + sm: 'px-2 py-0.5 text-xs', + md: 'px-2 py-1 text-xs', + lg: 'px-3 py-1.5 text-sm', + } + + const baseClasses = 'inline-flex items-center font-medium rounded transition-colors' + + return ( + + {children} + + ) +} +