video-flow-b/components/ai-suggestion-bar.tsx
2025-06-26 20:12:55 +08:00

142 lines
5.0 KiB
TypeScript

import { useState, useRef, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Sparkles, Send, X, Lightbulb } from 'lucide-react';
interface AISuggestionBarProps {
suggestions: string[];
onSuggestionClick: (suggestion: string) => void;
onSubmit: (text: string) => void;
placeholder?: string;
}
export function AISuggestionBar({
suggestions,
onSuggestionClick,
onSubmit,
placeholder = "输入你的想法,或点击预设词条获取 AI 建议..."
}: AISuggestionBarProps) {
const [inputText, setInputText] = useState('');
const [isFocused, setIsFocused] = useState(false);
const [showSuggestions, setShowSuggestions] = useState(false);
const inputRef = useRef<HTMLTextAreaElement>(null);
// 自动调整输入框高度
useEffect(() => {
if (inputRef.current) {
inputRef.current.style.height = 'auto';
inputRef.current.style.height = `${inputRef.current.scrollHeight}px`;
}
}, [inputText]);
// 处理提交
const handleSubmit = () => {
if (inputText.trim()) {
onSubmit(inputText.trim());
setInputText('');
if (inputRef.current) {
inputRef.current.style.height = 'auto';
}
}
};
// 处理回车提交
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSubmit();
}
};
return (
<motion.div
initial={{ y: 100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
className="fixed bottom-0 left-0 right-0 z-50 bg-gradient-to-t from-[#0C0E11] via-[#0C0E11] to-transparent pb-8"
>
<div className="max-w-5xl mx-auto px-6">
{/* 智能预设词条 */}
<AnimatePresence>
{showSuggestions && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: 'auto', opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
className="mb-4 overflow-hidden bg-black/30"
>
<div className="flex items-center gap-3 mb-3">
<Lightbulb className="w-4 h-4 text-yellow-500" />
<span className="text-sm text-white/60"></span>
</div>
<div className="flex flex-wrap gap-2">
{suggestions.map((suggestion, index) => (
<motion.button
key={suggestion}
initial={{ opacity: 0, scale: 0.8 }}
animate={{
opacity: 1,
scale: 1,
transition: { delay: index * 0.1 }
}}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
className="px-3 py-1.5 rounded-full bg-white/5 hover:bg-white/10 backdrop-blur-sm
text-sm text-white/70 hover:text-white transition-colors flex items-center gap-2"
onClick={() => onSuggestionClick(suggestion)}
>
<Sparkles className="w-3 h-3" />
{suggestion}
</motion.button>
))}
</div>
</motion.div>
)}
</AnimatePresence>
{/* 输入区域 */}
<div className={`
relative rounded-xl bg-white/5 backdrop-blur-sm transition-all duration-300
${isFocused ? 'ring-2 ring-blue-500/50 bg-white/10' : 'hover:bg-white/[0.07]'}
`}>
<textarea
ref={inputRef}
value={inputText}
onChange={(e) => setInputText(e.target.value)}
onKeyDown={handleKeyDown}
onFocus={() => {
setIsFocused(true);
setShowSuggestions(true);
}}
onBlur={() => { setIsFocused(false); setShowSuggestions(false) }}
placeholder={placeholder}
className="w-full resize-none bg-transparent border-none px-4 py-3 text-white placeholder:text-white/40
focus:outline-none min-h-[52px] max-h-[150px] pr-[100px]"
rows={1}
/>
{/* 操作按钮 */}
<div className="absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-2">
<button
className={`
p-2 rounded-lg transition-colors
${showSuggestions ? 'bg-white/10 text-white' : 'text-white/40 hover:text-white/60'}
`}
onClick={() => setShowSuggestions(!showSuggestions)}
>
{showSuggestions ? <X className="w-5 h-5" /> : <Sparkles className="w-5 h-5" />}
</button>
<button
className={`
p-2 rounded-lg transition-colors
${inputText.trim() ? 'bg-blue-500 text-white' : 'bg-white/5 text-white/20'}
`}
onClick={handleSubmit}
disabled={!inputText.trim()}
>
<Send className="w-5 h-5" />
</button>
</div>
</div>
</div>
</motion.div>
);
}