Files
app/wei-ai-demo/pages/Library.tsx
2026-01-28 19:10:19 +08:00

120 lines
5.7 KiB
TypeScript

import React, { useState } from 'react';
import { Play, Lock, Activity, Zap } from 'lucide-react';
import { MOCK_SCENARIOS } from '../constants';
import { Scenario } from '../types';
interface LibraryProps {
onPlay: (scenario: Scenario) => void;
}
const Library: React.FC<LibraryProps> = ({ onPlay }) => {
const categories = ['全部', '职场', '邻家', '科幻', 'ASMR'];
const [activeCategory, setActiveCategory] = useState('全部');
const filtered = activeCategory === '全部'
? MOCK_SCENARIOS
: MOCK_SCENARIOS.filter(s => s.category === activeCategory || s.tags.includes(activeCategory));
const getIntensityColor = (intensity: string) => {
switch(intensity) {
case 'Low': return 'text-[#34D399]';
case 'Medium': return 'text-[#60A5FA]';
case 'High': return 'text-[#FBBF24]';
case 'Extreme': return 'text-[#F472B6]';
default: return 'text-white/50';
}
};
return (
<div className="pb-24 px-4 min-h-full">
{/* Filter Bar */}
<div className="sticky top-0 z-20 pt-2 pb-2 -mx-4 mb-4">
<div className="relative">
<div className="flex items-center px-6 gap-3 overflow-x-auto no-scrollbar pr-12">
{categories.map(cat => {
const isActive = activeCategory === cat;
return (
<button
key={cat}
onClick={() => setActiveCategory(cat)}
className={`relative px-4 py-1.5 rounded-full border transition-all duration-300 shrink-0 ${
isActive
? 'bg-gradient-to-r from-[#C084FC] to-[#F472B6] text-white font-bold border-transparent shadow-[0_0_15px_rgba(192,132,252,0.4)]'
: 'bg-white/5 text-white/70 border-white/10 hover:bg-white/10 backdrop-blur-md'
}`}
>
<span className="text-sm">{cat}</span>
</button>
);
})}
</div>
<div className="absolute top-0 right-0 h-full w-12 bg-gradient-to-l from-[#4c1d95]/0 to-transparent pointer-events-none"></div>
</div>
</div>
{/* List Layout */}
<div className="flex flex-col gap-3">
{filtered.map(scenario => (
<div
key={scenario.id}
onClick={() => onPlay(scenario)}
className="group relative flex items-center p-3 rounded-2xl bg-[#4c1d95]/20 border border-white/10 overflow-hidden active:scale-[0.98] transition-all duration-300 backdrop-blur-md hover:border-[#C084FC]/40 hover:bg-[#4c1d95]/40 hover:shadow-[0_4px_20px_rgba(0,0,0,0.2)]"
>
{/* Left: Thumbnail */}
<div className="relative w-20 h-20 rounded-xl overflow-hidden shrink-0 shadow-lg border border-white/10">
<img src={scenario.cover} alt={scenario.title} className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500" />
{scenario.isLocked && (
<div className="absolute inset-0 bg-[#2e1065]/60 flex items-center justify-center backdrop-blur-[2px]">
<Lock size={16} className="text-white/90" />
</div>
)}
</div>
{/* Center: Info */}
<div className="flex-1 ml-4 flex flex-col justify-center min-w-0">
<div className="flex items-center gap-2 mb-1">
<span className="text-[10px] text-white/90 font-mono uppercase tracking-wider bg-white/10 px-1.5 rounded border border-white/10 backdrop-blur-md">
{scenario.category}
</span>
<div className="flex items-center gap-1">
<Zap size={10} className={getIntensityColor(scenario.intensity)} fill="currentColor" />
<span className={`text-[9px] font-bold ${getIntensityColor(scenario.intensity)}`}>{scenario.intensity}</span>
</div>
</div>
<h3 className="text-sm font-bold text-white mb-1.5 truncate pr-2 group-hover:text-[#F472B6] transition-colors drop-shadow-sm">{scenario.title}</h3>
{/* Tags */}
<div className="flex flex-wrap gap-1.5">
{scenario.tags.slice(0, 3).map((tag, i) => (
<span key={i} className="text-[10px] text-[#E2E8F0] bg-white/5 px-1.5 py-0.5 rounded-sm border border-white/5">#{tag}</span>
))}
</div>
</div>
{/* Right: Action Button */}
<div className="shrink-0 mr-1">
<div className={`w-10 h-10 rounded-full flex items-center justify-center transition-all duration-300 ${
scenario.isLocked
? 'bg-white/5 text-white/30'
: 'bg-[#C084FC]/20 text-[#C084FC] group-hover:bg-gradient-to-r group-hover:from-[#C084FC] group-hover:to-[#F472B6] group-hover:text-white group-hover:shadow-[0_0_15px_rgba(192,132,252,0.5)]'
}`}>
{scenario.isLocked ? <Lock size={16} /> : <Play size={18} fill="currentColor" className="ml-0.5" />}
</div>
</div>
</div>
))}
</div>
{/* Empty State */}
{filtered.length === 0 && (
<div className="flex flex-col items-center justify-center py-12 opacity-50">
<Activity size={32} className="text-white mb-2" />
<p className="text-xs text-white"></p>
</div>
)}
</div>
);
};
export default Library;