fix: UI 样式优化
This commit is contained in:
@@ -242,14 +242,16 @@ const ModelCard: React.FC<ModelCardProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
// 网格视图 - 现代化设计
|
||||
// 网格视图 - 增强的现代化设计
|
||||
return (
|
||||
<div
|
||||
className="group relative bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden hover:shadow-xl hover:border-primary-200 transition-all duration-300 hover:-translate-y-1 hover-lift animate-scale-in"
|
||||
className="group relative bg-gradient-to-br from-white to-gray-50/50 hover:from-white hover:to-primary-50/30 rounded-2xl shadow-sm border border-gray-100/50 overflow-hidden hover:shadow-xl hover:border-primary-200 transition-all duration-500 hover:-translate-y-2 hover:scale-[1.02] animate-scale-in"
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
onClick={onSelect}
|
||||
>
|
||||
{/* 装饰性背景 */}
|
||||
<div className="absolute top-0 right-0 w-20 h-20 bg-gradient-to-br from-primary-100/30 to-primary-200/30 rounded-full -translate-y-10 translate-x-10 opacity-0 group-hover:opacity-100 transition-all duration-500"></div>
|
||||
{/* 封面图片容器 */}
|
||||
<div className="relative aspect-[4/5] bg-gradient-to-br from-gray-50 to-gray-100 overflow-hidden">
|
||||
{/* 图片 */}
|
||||
|
||||
@@ -250,12 +250,13 @@ const ModelList: React.FC<ModelListProps> = ({ onModelSelect }) => {
|
||||
|
||||
return (
|
||||
<div className="space-y-8 animate-fade-in">
|
||||
{/* 头部工具栏 */}
|
||||
<div className="bg-white rounded-xl shadow-sm border border-gray-100 p-4">
|
||||
<div className="flex flex-col lg:flex-row justify-between items-start lg:items-center gap-4">
|
||||
{/* 美观的头部工具栏 */}
|
||||
<div className="bg-gradient-to-r from-white via-primary-50/30 to-white rounded-xl shadow-sm border border-gray-200/50 p-6 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-primary-100/30 to-primary-200/30 rounded-full -translate-y-16 translate-x-16 opacity-50"></div>
|
||||
<div className="flex flex-col lg:flex-row justify-between items-start lg:items-center gap-4 relative z-10">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 bg-gradient-to-br from-primary-500 to-primary-600 rounded-lg flex items-center justify-center">
|
||||
<SparklesIcon className="h-5 w-5 text-white" />
|
||||
<div className="w-12 h-12 bg-gradient-to-br from-primary-500 to-primary-600 rounded-xl flex items-center justify-center shadow-sm">
|
||||
<SparklesIcon className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-gray-900 mb-0.5">模特管理</h1>
|
||||
|
||||
@@ -52,13 +52,18 @@ const Navigation: React.FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<nav className="bg-white shadow-sm border-b border-gray-200">
|
||||
<nav className="bg-white/95 backdrop-blur-sm shadow-sm border-b border-gray-200/50 sticky top-0 z-50">
|
||||
<div className="px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex items-center justify-between h-16">
|
||||
{/* Logo */}
|
||||
{/* 增强的 Logo */}
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0">
|
||||
<h1 className="text-xl font-bold text-gray-900">MixVideo</h1>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8 bg-gradient-to-br from-primary-500 to-primary-600 rounded-lg flex items-center justify-center shadow-sm">
|
||||
<span className="text-white font-bold text-sm">M</span>
|
||||
</div>
|
||||
<h1 className="text-xl font-bold bg-gradient-to-r from-gray-900 to-gray-700 bg-clip-text text-transparent">MixVideo</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -73,17 +78,20 @@ const Navigation: React.FC = () => {
|
||||
<Link
|
||||
key={item.name}
|
||||
to={item.href}
|
||||
className={`group flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||
className={`group flex items-center px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200 relative overflow-hidden ${
|
||||
active
|
||||
? 'bg-blue-100 text-blue-700'
|
||||
: 'text-gray-600 hover:text-gray-900 hover:bg-gray-50'
|
||||
? 'bg-gradient-to-r from-primary-100 to-primary-200 text-primary-700 shadow-sm'
|
||||
: 'text-gray-600 hover:text-gray-900 hover:bg-gradient-to-r hover:from-gray-50 hover:to-gray-100'
|
||||
}`}
|
||||
title={item.description}
|
||||
>
|
||||
<Icon className={`mr-2 h-5 w-5 ${
|
||||
active ? 'text-blue-600' : 'text-gray-400 group-hover:text-gray-600'
|
||||
{active && (
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-primary-500/10 to-primary-600/10"></div>
|
||||
)}
|
||||
<Icon className={`mr-2 h-5 w-5 relative z-10 transition-all duration-200 ${
|
||||
active ? 'text-primary-600' : 'text-gray-400 group-hover:text-gray-600 group-hover:scale-110'
|
||||
}`} />
|
||||
{item.name}
|
||||
<span className="relative z-10">{item.name}</span>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -139,16 +139,20 @@ export const ProjectCard: React.FC<ProjectCardProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card card-interactive group cursor-pointer animate-fade-in-up relative overflow-hidden">
|
||||
{/* 背景装饰 */}
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-primary-100 to-blue-100 rounded-full -translate-y-16 translate-x-16 opacity-50 group-hover:opacity-70 transition-opacity duration-300"></div>
|
||||
<div className="card card-interactive group cursor-pointer animate-fade-in-up relative overflow-hidden bg-gradient-to-br from-white to-gray-50/50 hover:from-white hover:to-primary-50/30 transition-all duration-500">
|
||||
{/* 增强的背景装饰 */}
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-primary-100 to-primary-200 rounded-full -translate-y-16 translate-x-16 opacity-40 group-hover:opacity-60 transition-all duration-500 group-hover:scale-110"></div>
|
||||
|
||||
{/* 光晕效果 */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-transparent via-transparent to-primary-50/20 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
||||
|
||||
{/* 卡片头部 */}
|
||||
<div className="relative p-6 pb-4">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-3 bg-primary-100 text-primary-600 rounded-xl group-hover:bg-primary-200 group-hover:scale-110 transition-all duration-300">
|
||||
<Folder size={20} />
|
||||
<div className="p-3 bg-gradient-to-br from-primary-100 to-primary-200 text-primary-600 rounded-xl group-hover:from-primary-200 group-hover:to-primary-300 group-hover:scale-110 group-hover:shadow-lg transition-all duration-300 relative overflow-hidden">
|
||||
<div className="absolute inset-0 bg-white opacity-0 group-hover:opacity-20 transition-opacity duration-300"></div>
|
||||
<Folder size={20} className="relative z-10" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 line-clamp-1 group-hover:text-primary-700 transition-colors duration-200">
|
||||
@@ -238,14 +242,15 @@ export const ProjectCard: React.FC<ProjectCardProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
) : stats && (
|
||||
<div className="bg-gradient-to-r from-primary-50 to-blue-50 rounded-xl p-4 mb-4 border border-primary-100">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="bg-gradient-to-r from-primary-50 via-blue-50 to-indigo-50 rounded-xl p-4 mb-4 border border-primary-200/50 shadow-sm hover:shadow-md transition-all duration-300 relative overflow-hidden">
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-white/40 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||
<div className="flex items-center justify-between mb-3 relative z-10">
|
||||
<div className="flex items-center space-x-2 text-primary-700 font-semibold text-sm">
|
||||
<BarChart3 className="w-4 h-4" />
|
||||
<BarChart3 className="w-4 h-4 text-primary-600" />
|
||||
<span>项目统计</span>
|
||||
</div>
|
||||
{stats.total_materials > 0 && (
|
||||
<div className="badge badge-primary">
|
||||
<div className="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-primary-100 text-primary-800 border border-primary-200">
|
||||
{stats.total_materials} 个素材
|
||||
</div>
|
||||
)}
|
||||
@@ -308,28 +313,28 @@ export const ProjectCard: React.FC<ProjectCardProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 卡片底部操作区 */}
|
||||
{/* 增强的底部操作区 */}
|
||||
<div className="relative px-6 pb-6">
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
className="btn btn-ghost btn-sm p-2"
|
||||
className="p-2.5 rounded-lg text-gray-500 hover:text-primary-600 hover:bg-primary-50 transition-all duration-200 hover:scale-105"
|
||||
onClick={handleOpenFolder}
|
||||
title="打开项目文件夹"
|
||||
>
|
||||
<FolderOpen size={16} />
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-secondary btn-sm flex-1"
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-2.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-all duration-200 hover:scale-105 font-medium text-sm"
|
||||
onClick={() => onEdit(project)}
|
||||
>
|
||||
<Edit3 size={16} />
|
||||
<Edit3 size={14} />
|
||||
编辑
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-primary btn-sm flex-1 shadow-glow"
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-2.5 bg-gradient-to-r from-primary-600 to-primary-700 hover:from-primary-700 hover:to-primary-800 text-white rounded-lg transition-all duration-200 hover:scale-105 hover:shadow-lg font-medium text-sm"
|
||||
onClick={() => onOpen(project)}
|
||||
>
|
||||
<ExternalLink size={16} />
|
||||
<ExternalLink size={14} />
|
||||
打开
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -257,13 +257,13 @@ export const ProjectList: React.FC = () => {
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-6">
|
||||
{/* 项目网格 */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
{/* 优化的项目网格 - 更好的响应式布局 */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-5">
|
||||
{projects.map((project, index) => (
|
||||
<div
|
||||
key={project.id}
|
||||
className="animate-fade-in-up"
|
||||
style={{ animationDelay: `${index * 0.1}s` }}
|
||||
style={{ animationDelay: `${index * 0.08}s` }}
|
||||
>
|
||||
<ProjectCard
|
||||
project={project}
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
ArrowUpIcon,
|
||||
ArrowDownIcon,
|
||||
CheckIcon,
|
||||
XMarkIcon
|
||||
XMarkIcon,
|
||||
CpuChipIcon
|
||||
} from '@heroicons/react/24/outline';
|
||||
import { AiClassificationService } from '../services/aiClassificationService';
|
||||
import {
|
||||
@@ -282,31 +283,41 @@ const AiClassificationSettings: React.FC = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50/30">
|
||||
<div className="max-w-6xl mx-auto px-4 py-6">
|
||||
{/* 页面标题和操作栏 - 优化布局和视觉层次 */}
|
||||
<div className="mb-8">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-1">
|
||||
<h1 className="text-xl font-semibold text-gray-900 tracking-tight">AI分类设置</h1>
|
||||
<p className="text-sm text-gray-500">管理视频AI分类规则和提示词</p>
|
||||
{/* 美观的页面头部 */}
|
||||
<div className="mb-6">
|
||||
<div className="bg-gradient-to-r from-white via-purple-50/30 to-white rounded-xl shadow-sm border border-gray-200/50 p-6 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-purple-100/30 to-pink-100/30 rounded-full -translate-y-16 translate-x-16 opacity-50"></div>
|
||||
|
||||
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4 relative z-10">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-12 h-12 bg-gradient-to-br from-purple-500 to-pink-500 rounded-xl flex items-center justify-center shadow-sm">
|
||||
<CpuChipIcon className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-gray-900 mb-1">AI分类设置</h1>
|
||||
<p className="text-sm text-gray-600">管理视频AI分类规则和提示词</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={openPreviewDialog}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-gray-600 bg-white border border-gray-200 rounded-lg hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-300 transition-all duration-200"
|
||||
className="inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium text-gray-700 bg-white border border-gray-200 rounded-lg hover:bg-gray-50 hover:border-gray-300 transition-all duration-200 hover:scale-105"
|
||||
>
|
||||
<EyeIcon className="h-3.5 w-3.5" />
|
||||
<EyeIcon className="h-4 w-4" />
|
||||
预览提示词
|
||||
</button>
|
||||
<button
|
||||
onClick={openCreateDialog}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-white bg-blue-600 border border-blue-600 rounded-lg hover:bg-blue-700 hover:border-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-300 transition-all duration-200 shadow-sm"
|
||||
className="inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium text-white bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 rounded-lg transition-all duration-200 hover:scale-105 shadow-sm hover:shadow-md"
|
||||
>
|
||||
<PlusIcon className="h-3.5 w-3.5" />
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
添加分类
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 分类列表 - 优化卡片设计和布局 */}
|
||||
{classifications.length === 0 ? (
|
||||
@@ -325,28 +336,30 @@ const AiClassificationSettings: React.FC = () => {
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* 分类卡片网格 */}
|
||||
<div className="grid gap-3">
|
||||
{/* 美观的分类卡片网格 */}
|
||||
<div className="grid gap-4">
|
||||
{classifications.map((classification, index) => (
|
||||
<div
|
||||
key={classification.id}
|
||||
className="group relative bg-white border border-gray-200 rounded-xl p-4 hover:border-gray-300 hover:shadow-sm transition-all duration-200"
|
||||
className="group relative bg-gradient-to-br from-white to-gray-50/30 border border-gray-200/50 rounded-xl p-5 hover:border-purple-200 hover:shadow-md hover:-translate-y-1 transition-all duration-300 overflow-hidden"
|
||||
>
|
||||
{/* 卡片头部 */}
|
||||
<div className="flex items-start justify-between mb-3">
|
||||
{/* 装饰性背景 */}
|
||||
<div className="absolute top-0 right-0 w-20 h-20 bg-gradient-to-br from-purple-100/20 to-pink-100/20 rounded-full -translate-y-10 translate-x-10 opacity-0 group-hover:opacity-100 transition-all duration-300"></div>
|
||||
{/* 美观的卡片头部 */}
|
||||
<div className="flex items-start justify-between mb-4 relative z-10">
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<h3 className="text-sm font-medium text-gray-900 truncate">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<h3 className="text-base font-semibold text-gray-900 truncate">
|
||||
{classification.name}
|
||||
</h3>
|
||||
<span className={`inline-flex items-center px-1.5 py-0.5 rounded-md text-xs font-medium ${
|
||||
<span className={`inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium ${
|
||||
classification.is_active
|
||||
? 'bg-emerald-50 text-emerald-700 border border-emerald-200'
|
||||
: 'bg-gray-50 text-gray-600 border border-gray-200'
|
||||
? 'bg-gradient-to-r from-emerald-50 to-emerald-100 text-emerald-700 border border-emerald-200'
|
||||
: 'bg-gradient-to-r from-gray-50 to-gray-100 text-gray-600 border border-gray-200'
|
||||
}`}>
|
||||
{classification.is_active ? '激活' : '禁用'}
|
||||
</span>
|
||||
<span className="text-xs text-gray-400 bg-gray-50 px-1.5 py-0.5 rounded">
|
||||
<span className="text-xs text-purple-600 bg-purple-50 px-2 py-1 rounded-full border border-purple-200">
|
||||
#{classification.sort_order}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { ArrowLeft, FolderOpen, Upload, FileVideo, FileAudio, FileImage, HardDrive, Brain, Loader2, Link, Layers } from 'lucide-react';
|
||||
import { ArrowLeft, FolderOpen, Upload, FileVideo, FileAudio, FileImage, HardDrive, Brain, Loader2, Link, Layers, Calendar, MapPin } from 'lucide-react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { useProjectStore } from '../store/projectStore';
|
||||
import { useMaterialStore } from '../store/materialStore';
|
||||
@@ -29,6 +29,27 @@ import {
|
||||
import { MaterialMatchingService } from '../services/materialMatchingService';
|
||||
import { MaterialMatchingResult, MaterialMatchingRequest } from '../types/materialMatching';
|
||||
import { MaterialSegmentView } from '../components/MaterialSegmentView';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { zhCN } from 'date-fns/locale';
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (dateString: string) => {
|
||||
try {
|
||||
const date = new Date(dateString);
|
||||
return formatDistanceToNow(date, {
|
||||
addSuffix: true,
|
||||
locale: zhCN
|
||||
});
|
||||
} catch {
|
||||
return '未知时间';
|
||||
}
|
||||
};
|
||||
|
||||
// 获取项目目录名
|
||||
const getDirectoryName = (path: string) => {
|
||||
const parts = path.split(/[/\\]/);
|
||||
return parts[parts.length - 1] || path;
|
||||
};
|
||||
|
||||
/**
|
||||
* 项目详情页面组件
|
||||
@@ -427,111 +448,146 @@ export const ProjectDetails: React.FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto">
|
||||
{/* 页面头部 */}
|
||||
<div className="mb-8">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between space-y-4 sm:space-y-0 mb-4">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* 美观的页面头部 */}
|
||||
<div className="mb-6">
|
||||
{/* 面包屑导航 */}
|
||||
<div className="mb-4">
|
||||
<button
|
||||
onClick={handleBack}
|
||||
className="inline-flex items-center text-gray-600 hover:text-gray-900 transition-colors self-start"
|
||||
className="inline-flex items-center text-gray-500 hover:text-primary-600 transition-all duration-200 hover:scale-105"
|
||||
>
|
||||
<ArrowLeft className="w-5 h-5 mr-2" />
|
||||
<span className="hidden sm:inline">返回项目列表</span>
|
||||
<span className="sm:hidden">返回</span>
|
||||
<ArrowLeft className="w-4 h-4 mr-1.5" />
|
||||
<span className="text-sm font-medium">返回项目列表</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2 sm:gap-3">
|
||||
{/* 项目标题和操作区 */}
|
||||
<div className="bg-gradient-to-r from-white via-primary-50/30 to-white rounded-2xl border border-gray-200/50 p-6 shadow-sm hover:shadow-md transition-all duration-300 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-primary-100/50 to-primary-200/50 rounded-full -translate-y-16 translate-x-16 opacity-50"></div>
|
||||
|
||||
<div className="relative z-10">
|
||||
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4">
|
||||
<div className="flex-1 min-w-0">
|
||||
<h1 className="text-2xl lg:text-3xl font-bold text-gray-900 mb-2 truncate">
|
||||
{project.name}
|
||||
</h1>
|
||||
{project.description && (
|
||||
<p className="text-gray-600 text-sm lg:text-base mb-3 line-clamp-2">
|
||||
{project.description}
|
||||
</p>
|
||||
)}
|
||||
<div className="flex items-center gap-4 text-sm text-gray-500">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Calendar className="w-4 h-4" />
|
||||
<span>更新于 {formatTime(project.updated_at)}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<MapPin className="w-4 h-4" />
|
||||
<span className="truncate max-w-xs" title={project.path}>
|
||||
{getDirectoryName(project.path)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
onClick={handleOpenFolder}
|
||||
className="inline-flex items-center px-3 sm:px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors text-sm"
|
||||
className="inline-flex items-center px-4 py-2.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-all duration-200 hover:scale-105 text-sm font-medium"
|
||||
>
|
||||
<FolderOpen className="w-4 h-4" />
|
||||
<span className="hidden sm:inline ml-2">打开文件夹</span>
|
||||
<FolderOpen className="w-4 h-4 mr-2" />
|
||||
打开文件夹
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleMaterialImport}
|
||||
className="inline-flex items-center px-3 sm:px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm"
|
||||
className="inline-flex items-center px-4 py-2.5 bg-gradient-to-r from-primary-600 to-primary-700 hover:from-primary-700 hover:to-primary-800 text-white rounded-lg transition-all duration-200 hover:scale-105 shadow-sm hover:shadow-md text-sm font-medium"
|
||||
>
|
||||
<Upload className="w-4 h-4" />
|
||||
<span className="hidden sm:inline ml-2">导入素材</span>
|
||||
<Upload className="w-4 h-4 mr-2" />
|
||||
导入素材
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleBatchClassification}
|
||||
disabled={classificationLoading}
|
||||
className="inline-flex items-center px-3 sm:px-4 py-2 bg-gradient-to-r from-purple-500 to-pink-500 text-white rounded-lg hover:from-purple-600 hover:to-pink-600 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 shadow-sm hover:shadow-md text-sm"
|
||||
className="inline-flex items-center px-4 py-2.5 bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 disabled:opacity-50 disabled:cursor-not-allowed text-white rounded-lg transition-all duration-200 hover:scale-105 shadow-sm hover:shadow-md text-sm font-medium"
|
||||
>
|
||||
{classificationLoading ? (
|
||||
<Loader2 className="w-4 h-4 animate-spin" />
|
||||
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
||||
) : (
|
||||
<Brain className="w-4 h-4" />
|
||||
<Brain className="w-4 h-4 mr-2" />
|
||||
)}
|
||||
<span className="hidden sm:inline ml-2">
|
||||
{classificationLoading ? '分类中...' : '一键AI分类'}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 项目统计概览 */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-5 gap-4 md:gap-6 mb-6">
|
||||
{/* 美观的项目统计概览 */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-5 gap-3 md:gap-4 mb-6">
|
||||
{/* 总素材数 */}
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 md:p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="bg-gradient-to-br from-white to-primary-50/30 rounded-xl shadow-sm border border-gray-200/50 p-4 md:p-5 hover:shadow-md transition-all duration-300 hover:-translate-y-1 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-16 h-16 bg-gradient-to-br from-primary-100/50 to-primary-200/50 rounded-full -translate-y-8 translate-x-8 opacity-50"></div>
|
||||
<div className="flex items-center justify-between relative z-10">
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-xs md:text-sm font-medium text-gray-600 truncate">总素材数</p>
|
||||
<p className="text-xl md:text-2xl font-bold text-gray-900">{stats?.total_materials || 0}</p>
|
||||
</div>
|
||||
<div className="w-10 h-10 md:w-12 md:h-12 bg-blue-100 rounded-lg flex items-center justify-center ml-2">
|
||||
<FolderOpen className="w-5 h-5 md:w-6 md:h-6 text-blue-600" />
|
||||
<div className="w-10 h-10 md:w-12 md:h-12 bg-gradient-to-br from-primary-100 to-primary-200 rounded-xl flex items-center justify-center ml-2 shadow-sm">
|
||||
<FolderOpen className="w-5 h-5 md:w-6 md:h-6 text-primary-600" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 视频文件 */}
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 md:p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="bg-gradient-to-br from-white to-green-50/30 rounded-xl shadow-sm border border-gray-200/50 p-4 md:p-5 hover:shadow-md transition-all duration-300 hover:-translate-y-1 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-16 h-16 bg-gradient-to-br from-green-100/50 to-green-200/50 rounded-full -translate-y-8 translate-x-8 opacity-50"></div>
|
||||
<div className="flex items-center justify-between relative z-10">
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-xs md:text-sm font-medium text-gray-600 truncate">视频文件</p>
|
||||
<p className="text-xl md:text-2xl font-bold text-gray-900">{stats?.video_count || 0}</p>
|
||||
</div>
|
||||
<div className="w-10 h-10 md:w-12 md:h-12 bg-green-100 rounded-lg flex items-center justify-center ml-2">
|
||||
<div className="w-10 h-10 md:w-12 md:h-12 bg-gradient-to-br from-green-100 to-green-200 rounded-xl flex items-center justify-center ml-2 shadow-sm">
|
||||
<FileVideo className="w-5 h-5 md:w-6 md:h-6 text-green-600" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 音频文件 */}
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 md:p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="bg-gradient-to-br from-white to-purple-50/30 rounded-xl shadow-sm border border-gray-200/50 p-4 md:p-5 hover:shadow-md transition-all duration-300 hover:-translate-y-1 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-16 h-16 bg-gradient-to-br from-purple-100/50 to-purple-200/50 rounded-full -translate-y-8 translate-x-8 opacity-50"></div>
|
||||
<div className="flex items-center justify-between relative z-10">
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-xs md:text-sm font-medium text-gray-600 truncate">音频文件</p>
|
||||
<p className="text-xl md:text-2xl font-bold text-gray-900">{stats?.audio_count || 0}</p>
|
||||
</div>
|
||||
<div className="w-10 h-10 md:w-12 md:h-12 bg-purple-100 rounded-lg flex items-center justify-center ml-2">
|
||||
<div className="w-10 h-10 md:w-12 md:h-12 bg-gradient-to-br from-purple-100 to-purple-200 rounded-xl flex items-center justify-center ml-2 shadow-sm">
|
||||
<FileAudio className="w-5 h-5 md:w-6 md:h-6 text-purple-600" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 图片文件 */}
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 md:p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="bg-gradient-to-br from-white to-orange-50/30 rounded-xl shadow-sm border border-gray-200/50 p-4 md:p-5 hover:shadow-md transition-all duration-300 hover:-translate-y-1 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-16 h-16 bg-gradient-to-br from-orange-100/50 to-orange-200/50 rounded-full -translate-y-8 translate-x-8 opacity-50"></div>
|
||||
<div className="flex items-center justify-between relative z-10">
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-xs md:text-sm font-medium text-gray-600 truncate">图片文件</p>
|
||||
<p className="text-xl md:text-2xl font-bold text-gray-900">{stats?.image_count || 0}</p>
|
||||
</div>
|
||||
<div className="w-10 h-10 md:w-12 md:h-12 bg-orange-100 rounded-lg flex items-center justify-center ml-2">
|
||||
<div className="w-10 h-10 md:w-12 md:h-12 bg-gradient-to-br from-orange-100 to-orange-200 rounded-xl flex items-center justify-center ml-2 shadow-sm">
|
||||
<FileImage className="w-5 h-5 md:w-6 md:h-6 text-orange-600" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI分类状态 */}
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 md:p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="bg-gradient-to-br from-white to-purple-50/30 rounded-xl shadow-sm border border-gray-200/50 p-4 md:p-5 hover:shadow-md transition-all duration-300 hover:-translate-y-1 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-16 h-16 bg-gradient-to-br from-purple-100/50 to-pink-100/50 rounded-full -translate-y-8 translate-x-8 opacity-50"></div>
|
||||
<div className="flex items-center justify-between relative z-10">
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-xs md:text-sm font-medium text-gray-600 truncate">AI分类队列</p>
|
||||
<div className="flex items-center space-x-1">
|
||||
@@ -541,12 +597,12 @@ export const ProjectDetails: React.FC = () => {
|
||||
<span className="text-xs text-gray-500">待处理</span>
|
||||
</div>
|
||||
{queueStats?.processing_tasks && queueStats.processing_tasks > 0 && (
|
||||
<p className="text-xs text-blue-600 mt-1">
|
||||
<p className="text-xs text-purple-600 mt-1 font-medium">
|
||||
{queueStats.processing_tasks} 个正在处理
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="w-10 h-10 md:w-12 md:h-12 bg-gradient-to-br from-purple-100 to-pink-100 rounded-lg flex items-center justify-center ml-2">
|
||||
<div className="w-10 h-10 md:w-12 md:h-12 bg-gradient-to-br from-purple-100 to-pink-100 rounded-xl flex items-center justify-center ml-2 shadow-sm">
|
||||
<Brain className="w-5 h-5 md:w-6 md:h-6 text-purple-600" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -555,16 +611,16 @@ export const ProjectDetails: React.FC = () => {
|
||||
|
||||
{/* 主要内容区域 */}
|
||||
<div className="space-y-6">
|
||||
{/* 选项卡导航 */}
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200">
|
||||
<div className="border-b border-gray-200">
|
||||
<nav className="flex space-x-4 md:space-x-8 px-4 md:px-6 overflow-x-auto" aria-label="Tabs">
|
||||
{/* 美观的选项卡导航 */}
|
||||
<div className="bg-white rounded-xl shadow-sm border border-gray-200/50 overflow-hidden">
|
||||
<div className="border-b border-gray-100">
|
||||
<nav className="flex space-x-1 px-4 md:px-6 overflow-x-auto" aria-label="Tabs">
|
||||
<button
|
||||
onClick={() => setActiveTab('materials')}
|
||||
className={`py-4 px-1 border-b-2 font-medium text-sm transition-colors whitespace-nowrap ${
|
||||
className={`py-3 px-4 font-medium text-sm transition-all duration-200 whitespace-nowrap rounded-t-lg relative ${
|
||||
activeTab === 'materials'
|
||||
? 'border-blue-500 text-blue-600'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
|
||||
? 'text-primary-600 bg-primary-50 border-b-2 border-primary-500'
|
||||
: 'text-gray-500 hover:text-gray-700 hover:bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
@@ -575,10 +631,10 @@ export const ProjectDetails: React.FC = () => {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('segments')}
|
||||
className={`py-4 px-1 border-b-2 font-medium text-sm transition-colors whitespace-nowrap ${
|
||||
className={`py-3 px-4 font-medium text-sm transition-all duration-200 whitespace-nowrap rounded-t-lg relative ${
|
||||
activeTab === 'segments'
|
||||
? 'border-blue-500 text-blue-600'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
|
||||
? 'text-primary-600 bg-primary-50 border-b-2 border-primary-500'
|
||||
: 'text-gray-500 hover:text-gray-700 hover:bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
@@ -589,10 +645,10 @@ export const ProjectDetails: React.FC = () => {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('templates')}
|
||||
className={`py-4 px-1 border-b-2 font-medium text-sm transition-colors whitespace-nowrap ${
|
||||
className={`py-3 px-4 font-medium text-sm transition-all duration-200 whitespace-nowrap rounded-t-lg relative ${
|
||||
activeTab === 'templates'
|
||||
? 'border-blue-500 text-blue-600'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
|
||||
? 'text-primary-600 bg-primary-50 border-b-2 border-primary-500'
|
||||
: 'text-gray-500 hover:text-gray-700 hover:bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
@@ -603,10 +659,10 @@ export const ProjectDetails: React.FC = () => {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('ai-logs')}
|
||||
className={`py-4 px-1 border-b-2 font-medium text-sm transition-colors whitespace-nowrap ${
|
||||
className={`py-3 px-4 font-medium text-sm transition-all duration-200 whitespace-nowrap rounded-t-lg relative ${
|
||||
activeTab === 'ai-logs'
|
||||
? 'border-blue-500 text-blue-600'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
|
||||
? 'text-primary-600 bg-primary-50 border-b-2 border-primary-500'
|
||||
: 'text-gray-500 hover:text-gray-700 hover:bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
|
||||
@@ -186,54 +186,66 @@ const TemplateManagement: React.FC = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 p-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* 页面标题和操作栏 */}
|
||||
<div className="mb-8">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
{/* 美观的页面头部 */}
|
||||
<div className="mb-6">
|
||||
<div className="bg-gradient-to-r from-white via-indigo-50/30 to-white rounded-xl shadow-sm border border-gray-200/50 p-6 mb-6 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-indigo-100/30 to-purple-100/30 rounded-full -translate-y-16 translate-x-16 opacity-50"></div>
|
||||
|
||||
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4 relative z-10">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-500 rounded-xl flex items-center justify-center shadow-sm">
|
||||
<FileText className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-gray-900">模板管理</h1>
|
||||
<p className="text-gray-600 mt-2">管理剪映模板,支持导入、编辑和组织</p>
|
||||
<h1 className="text-2xl font-bold text-gray-900 mb-1">模板管理</h1>
|
||||
<p className="text-sm text-gray-600">管理剪映模板,支持导入、编辑和组织</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => setShowImportModal(true)}
|
||||
className="flex items-center gap-1.5 px-4 py-2 bg-gradient-to-r from-primary-500 to-primary-600 text-white rounded-lg hover:from-primary-600 hover:to-primary-700 transition-all duration-200 shadow-sm hover:shadow-md text-sm font-medium"
|
||||
className="inline-flex items-center gap-2 px-4 py-2.5 bg-gradient-to-r from-primary-600 to-primary-700 hover:from-primary-700 hover:to-primary-800 text-white rounded-lg transition-all duration-200 hover:scale-105 shadow-sm hover:shadow-md text-sm font-medium"
|
||||
>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
<Plus className="w-4 h-4" />
|
||||
导入模板
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setShowBatchImportModal(true)}
|
||||
className="inline-flex items-center px-3 sm:px-4 py-2 bg-gradient-to-r from-purple-500 to-pink-500 text-white rounded-lg hover:from-purple-600 hover:to-pink-600 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 shadow-sm hover:shadow-md text-sm"
|
||||
className="inline-flex items-center gap-2 px-4 py-2.5 bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white rounded-lg transition-all duration-200 hover:scale-105 shadow-sm hover:shadow-md text-sm font-medium"
|
||||
>
|
||||
<Upload className="w-4 h-4 mr-2" />
|
||||
<Upload className="w-4 h-4" />
|
||||
批量导入
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 搜索和筛选栏 */}
|
||||
<div className="flex items-center space-x-4 bg-white p-4 rounded-lg shadow-sm">
|
||||
{/* 美观的搜索和筛选栏 */}
|
||||
<div className="flex items-center space-x-4 bg-white p-5 rounded-xl shadow-sm border border-gray-200/50">
|
||||
<div className="flex-1 relative">
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
|
||||
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="搜索模板名称..."
|
||||
value={searchKeyword}
|
||||
onChange={(e) => handleSearch(e.target.value)}
|
||||
className="w-full pl-10 pr-3 py-2 border border-gray-200 rounded-lg bg-white focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200 placeholder-gray-400 text-sm text-gray-900 hover:border-gray-300"
|
||||
className="w-full pl-11 pr-4 py-3 border border-gray-200 rounded-xl bg-white focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200 placeholder-gray-400 text-sm text-gray-900 hover:border-gray-300 shadow-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<Filter className="w-4 h-4 text-gray-500" />
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="flex items-center gap-2 text-gray-500">
|
||||
<Filter className="w-4 h-4" />
|
||||
<span className="text-sm font-medium">筛选</span>
|
||||
</div>
|
||||
<CustomSelect
|
||||
value={statusFilter}
|
||||
onChange={handleStatusFilter}
|
||||
options={statusOptions}
|
||||
placeholder="筛选状态"
|
||||
className="w-40"
|
||||
className="w-44"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,11 +3,23 @@
|
||||
* 遵循前端开发规范的动画设计原则
|
||||
*/
|
||||
|
||||
/* 淡入动画 */
|
||||
/* 增强的淡入动画 */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
transform: translateY(20px) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 优雅的淡入上升动画 */
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
@@ -117,7 +129,25 @@
|
||||
|
||||
/* 动画类 */
|
||||
.animate-fade-in {
|
||||
animation: fadeIn 0.3s ease-out forwards;
|
||||
animation: fadeInUp 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||||
}
|
||||
|
||||
/* 优雅的悬停效果 */
|
||||
.hover-glow {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.hover-glow:hover {
|
||||
box-shadow: 0 10px 25px -5px rgba(59, 130, 246, 0.1), 0 10px 10px -5px rgba(59, 130, 246, 0.04);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* 渐变文字效果 */
|
||||
.text-gradient-primary {
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.animate-fade-out {
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
/* 设计令牌 - 颜色系统 */
|
||||
:root {
|
||||
/* 主色调 - 优雅的紫色系 */
|
||||
--primary-50: #faf5ff;
|
||||
--primary-100: #f3e8ff;
|
||||
--primary-200: #e9d5ff;
|
||||
--primary-300: #d8b4fe;
|
||||
--primary-400: #c084fc;
|
||||
--primary-500: #a855f7;
|
||||
--primary-600: #9333ea;
|
||||
--primary-700: #7c3aed;
|
||||
--primary-800: #6b21a8;
|
||||
--primary-900: #581c87;
|
||||
/* 主色调 - 现代蓝色系(与Tailwind配置一致) */
|
||||
--primary-50: #eff6ff;
|
||||
--primary-100: #dbeafe;
|
||||
--primary-200: #bfdbfe;
|
||||
--primary-300: #93c5fd;
|
||||
--primary-400: #60a5fa;
|
||||
--primary-500: #3b82f6;
|
||||
--primary-600: #2563eb;
|
||||
--primary-700: #1d4ed8;
|
||||
--primary-800: #1e40af;
|
||||
--primary-900: #1e3a8a;
|
||||
|
||||
/* 中性色 */
|
||||
--gray-50: #f9fafb;
|
||||
|
||||
Reference in New Issue
Block a user