@@ -58,6 +58,44 @@ const InputControls = styled.div`
5858 align-items: flex-end;
5959` ;
6060
61+ const AttachButton = styled . button `
62+ width: 32px;
63+ height: 32px;
64+ flex-shrink: 0;
65+ border-radius: 4px;
66+ background: #3e3e42;
67+ color: #cccccc;
68+ border: none;
69+ cursor: pointer;
70+ display: none;
71+ align-items: center;
72+ justify-content: center;
73+ font-size: 18px;
74+ transition: background 0.2s;
75+
76+ /* Show only on mobile (viewport width <= 768px) */
77+ @media (max-width: 768px) {
78+ display: flex;
79+ }
80+
81+ &:hover {
82+ background: #505050;
83+ }
84+
85+ &:active {
86+ background: #5a5a5a;
87+ }
88+
89+ &:disabled {
90+ opacity: 0.5;
91+ cursor: not-allowed;
92+ }
93+ ` ;
94+
95+ const HiddenFileInput = styled . input `
96+ display: none;
97+ ` ;
98+
6199// Input now rendered by VimTextArea; styles moved there
62100
63101const ModeToggles = styled . div `
@@ -407,6 +445,28 @@ export const ChatInput: React.FC<ChatInputProps> = ({
407445 setImageAttachments ( ( prev ) => prev . filter ( ( img ) => img . id !== id ) ) ;
408446 } , [ ] ) ;
409447
448+ // Handle file selection from file input (for mobile)
449+ const fileInputRef = useRef < HTMLInputElement > ( null ) ;
450+
451+ const handleFileSelect = useCallback ( ( e : React . ChangeEvent < HTMLInputElement > ) => {
452+ const files = e . target . files ;
453+ if ( ! files || files . length === 0 ) return ;
454+
455+ const fileArray = Array . from ( files ) ;
456+ void processImageFiles ( fileArray ) . then ( ( attachments ) => {
457+ setImageAttachments ( ( prev ) => [ ...prev , ...attachments ] ) ;
458+ } ) ;
459+
460+ // Reset input so same file can be selected again
461+ if ( fileInputRef . current ) {
462+ fileInputRef . current . value = "" ;
463+ }
464+ } , [ ] ) ;
465+
466+ const handleAttachClick = useCallback ( ( ) => {
467+ fileInputRef . current ?. click ( ) ;
468+ } , [ ] ) ;
469+
410470 // Handle drag over to allow drop
411471 const handleDragOver = useCallback ( ( e : React . DragEvent < HTMLTextAreaElement > ) => {
412472 // Check if drag contains files
@@ -833,6 +893,21 @@ export const ChatInput: React.FC<ChatInputProps> = ({
833893 }
834894 aria-expanded = { showCommandSuggestions && commandSuggestions . length > 0 }
835895 />
896+ < HiddenFileInput
897+ ref = { fileInputRef }
898+ type = "file"
899+ accept = "image/*"
900+ multiple
901+ onChange = { handleFileSelect }
902+ />
903+ < AttachButton
904+ onClick = { handleAttachClick }
905+ disabled = { ! editingMessage && ( disabled || isSending || isCompacting ) }
906+ title = "Attach images"
907+ aria-label = "Attach images"
908+ >
909+ 📎
910+ </ AttachButton >
836911 </ InputControls >
837912 < ImageAttachments images = { imageAttachments } onRemove = { handleRemoveImage } />
838913 < ModeToggles data-component = "ChatModeToggles" >
0 commit comments