| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- /**
- * 聊天输入组件 - 移动端优化
- */
- 'use client';
- import { useState, FormEvent, KeyboardEvent, useRef, useEffect } from 'react';
- interface ChatInputProps {
- onSend: (message: string) => void;
- isLoading: boolean;
- onAbort: () => void;
- }
- export default function ChatInput({ onSend, isLoading, onAbort }: ChatInputProps) {
- const [input, setInput] = useState('');
- const textareaRef = useRef<HTMLTextAreaElement>(null);
- // 自动调整 textarea 高度
- useEffect(() => {
- if (textareaRef.current) {
- textareaRef.current.style.height = 'auto';
- textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 150)}px`;
- }
- }, [input]);
- const handleSubmit = (e: FormEvent) => {
- e.preventDefault();
- if (input.trim() && !isLoading) {
- onSend(input.trim());
- setInput('');
- // 重置 textarea 高度
- if (textareaRef.current) {
- textareaRef.current.style.height = 'auto';
- }
- }
- };
- const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
- if (e.key === 'Enter' && !e.shiftKey) {
- e.preventDefault();
- handleSubmit(e);
- }
- };
- return (
- <form onSubmit={handleSubmit} className="flex items-end gap-2">
- <div className="flex-1 relative">
- <textarea
- ref={textareaRef}
- value={input}
- onChange={(e) => setInput(e.target.value)}
- onKeyDown={handleKeyDown}
- placeholder="输入消息... (Shift+Enter 换行)"
- disabled={isLoading}
- rows={1}
- className="w-full resize-none border border-gray-300 dark:border-gray-600 rounded-xl px-4 py-3 pr-12 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white text-[16px] leading-relaxed transition-all"
- style={{ minHeight: '48px', maxHeight: '150px' }}
- />
- {/* 字符计数 */}
- {input.length > 0 && (
- <span className="absolute bottom-2 right-3 text-xs text-gray-400">
- {input.length}
- </span>
- )}
- </div>
- {/* 移动端:图标按钮 */}
- {isLoading ? (
- <button
- type="button"
- onClick={onAbort}
- className="flex items-center justify-center w-12 h-12 min-w-[48px] bg-red-500 hover:bg-red-600 text-white rounded-xl transition-all active:scale-95 shadow-sm"
- aria-label="停止生成"
- >
- <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
- <rect x="6" y="6" width="12" height="12" rx="2" />
- </svg>
- </button>
- ) : (
- <button
- type="submit"
- disabled={!input.trim()}
- className="flex items-center justify-center w-12 h-12 min-w-[48px] bg-blue-500 hover:bg-blue-600 disabled:bg-gray-300 disabled:cursor-not-allowed text-white rounded-xl transition-all active:scale-95 shadow-sm disabled:active:scale-100"
- aria-label="发送消息"
- >
- <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
- </svg>
- </button>
- )}
- </form>
- );
- }
|