forked from 77media/video-flow
142 lines
5.0 KiB
TypeScript
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>
|
|
);
|
|
}
|