120 lines
3.8 KiB
TypeScript
120 lines
3.8 KiB
TypeScript
import React from 'react';
|
|
import { Link, useLocation } from 'react-router-dom';
|
|
import {
|
|
FolderIcon,
|
|
UserGroupIcon,
|
|
CpuChipIcon,
|
|
DocumentDuplicateIcon,
|
|
LinkIcon,
|
|
WrenchScrewdriverIcon,
|
|
SparklesIcon,
|
|
} from '@heroicons/react/24/outline';
|
|
|
|
const Navigation: React.FC = () => {
|
|
const location = useLocation();
|
|
|
|
const navItems = [
|
|
{
|
|
name: '项目',
|
|
href: '/',
|
|
icon: FolderIcon,
|
|
description: '管理项目和素材'
|
|
},
|
|
{
|
|
name: '模特',
|
|
href: '/models',
|
|
icon: UserGroupIcon,
|
|
description: '管理模特信息'
|
|
},
|
|
{
|
|
name: '模板',
|
|
href: '/templates',
|
|
icon: DocumentDuplicateIcon,
|
|
description: '管理剪映模板'
|
|
},
|
|
{
|
|
name: '素材',
|
|
href: '/material-model-binding',
|
|
icon: LinkIcon,
|
|
description: '管理素材与模特的绑定关系'
|
|
},
|
|
{
|
|
name: '分类',
|
|
href: '/ai-classification-settings',
|
|
icon: CpuChipIcon,
|
|
description: '管理AI视频分类规则'
|
|
},
|
|
{
|
|
name: '穿搭',
|
|
href: '/fashion-chat',
|
|
icon: SparklesIcon,
|
|
description: 'AI智能服装搭配推荐'
|
|
},
|
|
{
|
|
name: '工具',
|
|
href: '/tools',
|
|
icon: WrenchScrewdriverIcon,
|
|
description: 'AI检索图片/数据清洗工具'
|
|
}
|
|
];
|
|
|
|
const isActive = (href: string) => {
|
|
if (href === '/') {
|
|
return location.pathname === '/';
|
|
}
|
|
return location.pathname.startsWith(href);
|
|
};
|
|
|
|
return (
|
|
<nav className="bg-white/95 backdrop-blur-sm shadow-sm border-b border-gray-200/50 sticky top-0 z-50 flex-shrink-0">
|
|
<div className="px-4 sm:px-2 lg:px-4">
|
|
<div className="flex items-center justify-between h-16">
|
|
{/* 增强的 Logo */}
|
|
<div className="flex items-center">
|
|
<div className="flex-shrink-0">
|
|
<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>
|
|
|
|
<div>
|
|
<div className="ml-4 flex items-baseline space-x-2">
|
|
{navItems.map((item) => {
|
|
const Icon = item.icon;
|
|
const active = isActive(item.href);
|
|
|
|
return (
|
|
<Link
|
|
key={item.name}
|
|
to={item.href}
|
|
className={`group flex items-center px-2 py-2 rounded-lg text-sm font-medium transition-all duration-200 relative overflow-hidden ${
|
|
active
|
|
? '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}
|
|
>
|
|
{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'
|
|
}`} />
|
|
<span className="relative z-10">{item.name}</span>
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
);
|
|
};
|
|
|
|
export default Navigation;
|