Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions src/components/ChatInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,44 @@ const InputControls = styled.div`
align-items: flex-end;
`;

const AttachButton = styled.button`
width: 32px;
height: 32px;
flex-shrink: 0;
border-radius: 4px;
background: #3e3e42;
color: #cccccc;
border: none;
cursor: pointer;
display: none;
align-items: center;
justify-content: center;
font-size: 18px;
transition: background 0.2s;

/* Show only on mobile (viewport width <= 768px) */
@media (max-width: 768px) {
display: flex;
}

&:hover {
background: #505050;
}

&:active {
background: #5a5a5a;
}

&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
`;

const HiddenFileInput = styled.input`
display: none;
`;

// Input now rendered by VimTextArea; styles moved there

const ModeToggles = styled.div`
Expand Down Expand Up @@ -407,6 +445,28 @@ export const ChatInput: React.FC<ChatInputProps> = ({
setImageAttachments((prev) => prev.filter((img) => img.id !== id));
}, []);

// Handle file selection from file input (for mobile)
const fileInputRef = useRef<HTMLInputElement>(null);

const handleFileSelect = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
if (!files || files.length === 0) return;

const fileArray = Array.from(files);
void processImageFiles(fileArray).then((attachments) => {
setImageAttachments((prev) => [...prev, ...attachments]);
});

// Reset input so same file can be selected again
if (fileInputRef.current) {
fileInputRef.current.value = "";
}
}, []);

const handleAttachClick = useCallback(() => {
fileInputRef.current?.click();
}, []);

// Handle drag over to allow drop
const handleDragOver = useCallback((e: React.DragEvent<HTMLTextAreaElement>) => {
// Check if drag contains files
Expand Down Expand Up @@ -833,6 +893,21 @@ export const ChatInput: React.FC<ChatInputProps> = ({
}
aria-expanded={showCommandSuggestions && commandSuggestions.length > 0}
/>
<HiddenFileInput
ref={fileInputRef}
type="file"
accept="image/*"
multiple
onChange={handleFileSelect}
/>
<AttachButton
onClick={handleAttachClick}
disabled={!editingMessage && (disabled || isSending || isCompacting)}
title="Attach images"
aria-label="Attach images"
>
📎
</AttachButton>
</InputControls>
<ImageAttachments images={imageAttachments} onRemove={handleRemoveImage} />
<ModeToggles data-component="ChatModeToggles">
Expand Down