This commit is contained in:
2026-04-12 01:02:14 +08:00
parent 509487f155
commit 9b053e302b
14085 changed files with 2680009 additions and 12 deletions

View File

@@ -0,0 +1,131 @@
"use client";
import { useRef, useState, type KeyboardEvent } from "react";
interface ChatInputProps {
onSend: (text: string, refImage: File | null) => void;
disabled: boolean;
}
export function ChatInput({ onSend, disabled }: ChatInputProps) {
const [text, setText] = useState("");
const [refImage, setRefImage] = useState<File | null>(null);
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
const handleSubmit = () => {
const trimmed = text.trim();
if (!trimmed || disabled) return;
onSend(trimmed, refImage);
setText("");
setRefImage(null);
setPreviewUrl(null);
};
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
handleSubmit();
}
};
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
setRefImage(file);
setPreviewUrl(URL.createObjectURL(file));
};
const removeRefImage = () => {
setRefImage(null);
if (previewUrl) URL.revokeObjectURL(previewUrl);
setPreviewUrl(null);
if (fileInputRef.current) fileInputRef.current.value = "";
};
return (
<div className="border-t border-[var(--border)] bg-[var(--bg-secondary)] px-4 py-3">
{/* 参考图预览 */}
{previewUrl && (
<div className="mb-3 flex items-start gap-2">
<div className="relative">
<img
src={previewUrl}
alt="参考图"
className="w-16 h-16 rounded-lg object-cover border border-[var(--border)]"
/>
<button
onClick={removeRefImage}
className="absolute -top-1.5 -right-1.5 w-5 h-5 rounded-full
bg-red-500 text-white text-xs flex items-center justify-center
hover:bg-red-600 cursor-pointer"
>
×
</button>
</div>
<span className="text-xs text-[var(--text-secondary)] mt-1"></span>
</div>
)}
<div className="flex items-end gap-2">
{/* 上传参考图按钮 */}
<button
onClick={() => fileInputRef.current?.click()}
disabled={disabled}
className="flex-shrink-0 w-10 h-10 rounded-lg border border-[var(--border)]
bg-[var(--bg-tertiary)] text-[var(--text-secondary)]
hover:text-[var(--text-primary)] hover:border-[var(--accent)]
flex items-center justify-center transition-colors
disabled:opacity-50 cursor-pointer"
title="上传参考图"
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
<circle cx="8.5" cy="8.5" r="1.5" />
<polyline points="21 15 16 10 5 21" />
</svg>
</button>
<input
ref={fileInputRef}
type="file"
accept="image/*"
onChange={handleFileChange}
className="hidden"
/>
{/* 文字输入框 */}
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="描述你想要的美术资源..."
disabled={disabled}
rows={1}
className="flex-1 resize-none rounded-lg border border-[var(--border)]
bg-[var(--bg-tertiary)] text-[var(--text-primary)]
placeholder:text-[var(--text-secondary)]
px-4 py-2.5 text-sm leading-relaxed
focus:outline-none focus:border-[var(--accent)]
disabled:opacity-50 transition-colors
min-h-[42px] max-h-[120px]"
style={{ fieldSizing: "content" } as React.CSSProperties}
/>
{/* 发送按钮 */}
<button
onClick={handleSubmit}
disabled={disabled || !text.trim()}
className="flex-shrink-0 w-10 h-10 rounded-lg
bg-[var(--accent)] text-white
hover:bg-[var(--accent-hover)]
flex items-center justify-center transition-colors
disabled:opacity-50 cursor-pointer"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
</svg>
</button>
</div>
</div>
);
}