feat(chat): support pasting images directly into the chat box

This commit is contained in:
2026-07-06 13:38:02 +00:00
parent 88e7faaafb
commit 0c26e2402b
+53
View File
@@ -437,6 +437,58 @@ export function ChatArea() {
return () => clearInterval(t); return () => clearInterval(t);
}, [slowmodeRemaining]); }, [slowmodeRemaining]);
const handlePaste = async (e: React.ClipboardEvent<HTMLInputElement>) => {
const items = e.clipboardData.items;
let imageFile: File | null = null;
for (let i = 0; i < items.length; i++) {
if (items[i].type.startsWith('image/')) {
imageFile = items[i].getAsFile();
break;
}
}
if (imageFile) {
e.preventDefault();
const formData = new FormData();
formData.append('file', imageFile);
try {
const res = await fetch('/api/v1/upload', {
method: 'POST',
body: formData,
credentials: 'include'
});
if (!res.ok) throw new Error('Upload failed');
const data = await res.json();
const imageUrl = data.url;
// Insert into input
const imgMarkdown = `![image](${imageUrl})`;
const inputEl = inputRef.current;
if (inputEl) {
const start = inputEl.selectionStart || 0;
const end = inputEl.selectionEnd || 0;
const newValue = input.slice(0, start) + imgMarkdown + input.slice(end);
setInput(newValue);
setTimeout(() => {
inputEl.focus();
inputEl.setSelectionRange(start + imgMarkdown.length, start + imgMarkdown.length);
}, 0);
} else {
setInput(prev => prev + (prev.length > 0 && !prev.endsWith(' ') ? ' ' : '') + imgMarkdown);
}
} catch (err) {
console.error('Failed to upload image:', err);
}
}
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value; const value = e.target.value;
const cursor = e.target.selectionStart ?? value.length; const cursor = e.target.selectionStart ?? value.length;
@@ -851,6 +903,7 @@ export function ChatArea() {
type="text" type="text"
value={input} value={input}
onChange={handleInputChange} onChange={handleInputChange}
onPaste={handlePaste}
placeholder="type a message..." placeholder="type a message..."
className="terminal-input w-full" className="terminal-input w-full"
disabled={!activeChannelId || slowmodeRemaining > 0} disabled={!activeChannelId || slowmodeRemaining > 0}