@@ -19,7 +19,6 @@ import { FilePicker } from "./FilePicker";
1919import { ImagePreview } from "./ImagePreview" ;
2020import { type FileEntry } from "@/lib/api" ;
2121import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow" ;
22- import { invoke } from "@tauri-apps/api/core" ;
2322
2423interface FloatingPromptInputProps {
2524 /**
@@ -220,33 +219,39 @@ const FloatingPromptInputInner = (
220219
221220 // Helper function to check if a file is an image
222221 const isImageFile = ( path : string ) : boolean => {
222+ // Check if it's a data URL
223+ if ( path . startsWith ( 'data:image/' ) ) {
224+ return true ;
225+ }
226+ // Otherwise check file extension
223227 const ext = path . split ( '.' ) . pop ( ) ?. toLowerCase ( ) ;
224228 return [ 'png' , 'jpg' , 'jpeg' , 'gif' , 'svg' , 'webp' , 'ico' , 'bmp' ] . includes ( ext || '' ) ;
225229 } ;
226230
227231 // Extract image paths from prompt text
228232 const extractImagePaths = ( text : string ) : string [ ] => {
229- console . log ( '[extractImagePaths] Input text:' , text ) ;
233+ console . log ( '[extractImagePaths] Input text length :' , text . length ) ;
230234
231235 // Updated regex to handle both quoted and unquoted paths
232- // Pattern 1: @"path with spaces" - quoted paths
236+ // Pattern 1: @"path with spaces or data URLs " - quoted paths
233237 // Pattern 2: @path - unquoted paths (continues until @ or end)
234238 const quotedRegex = / @ " ( [ ^ " ] + ) " / g;
235239 const unquotedRegex = / @ ( [ ^ @ \n \s ] + ) / g;
236240
237241 const pathsSet = new Set < string > ( ) ; // Use Set to ensure uniqueness
238242
239- // First, extract quoted paths
243+ // First, extract quoted paths (including data URLs)
240244 let matches = Array . from ( text . matchAll ( quotedRegex ) ) ;
241- console . log ( '[extractImagePaths] Quoted matches:' , matches . map ( m => m [ 0 ] ) ) ;
245+ console . log ( '[extractImagePaths] Quoted matches:' , matches . length ) ;
242246
243247 for ( const match of matches ) {
244248 const path = match [ 1 ] ; // No need to trim, quotes preserve exact path
245- console . log ( '[extractImagePaths] Processing quoted path:' , path ) ;
249+ console . log ( '[extractImagePaths] Processing quoted path:' , path . startsWith ( 'data:' ) ? 'data URL' : path ) ;
246250
247- // Convert relative path to absolute if needed
248- const fullPath = path . startsWith ( '/' ) ? path : ( projectPath ? `${ projectPath } /${ path } ` : path ) ;
249- console . log ( '[extractImagePaths] Full path:' , fullPath , 'Is image:' , isImageFile ( fullPath ) ) ;
251+ // For data URLs, use as-is; for file paths, convert to absolute
252+ const fullPath = path . startsWith ( 'data:' )
253+ ? path
254+ : ( path . startsWith ( '/' ) ? path : ( projectPath ? `${ projectPath } /${ path } ` : path ) ) ;
250255
251256 if ( isImageFile ( fullPath ) ) {
252257 pathsSet . add ( fullPath ) ;
@@ -256,25 +261,27 @@ const FloatingPromptInputInner = (
256261 // Remove quoted mentions from text to avoid double-matching
257262 let textWithoutQuoted = text . replace ( quotedRegex , '' ) ;
258263
259- // Then extract unquoted paths
264+ // Then extract unquoted paths (typically file paths)
260265 matches = Array . from ( textWithoutQuoted . matchAll ( unquotedRegex ) ) ;
261- console . log ( '[extractImagePaths] Unquoted matches:' , matches . map ( m => m [ 0 ] ) ) ;
266+ console . log ( '[extractImagePaths] Unquoted matches:' , matches . length ) ;
262267
263268 for ( const match of matches ) {
264269 const path = match [ 1 ] . trim ( ) ;
270+ // Skip if it looks like a data URL fragment (shouldn't happen with proper quoting)
271+ if ( path . includes ( 'data:' ) ) continue ;
272+
265273 console . log ( '[extractImagePaths] Processing unquoted path:' , path ) ;
266274
267275 // Convert relative path to absolute if needed
268276 const fullPath = path . startsWith ( '/' ) ? path : ( projectPath ? `${ projectPath } /${ path } ` : path ) ;
269- console . log ( '[extractImagePaths] Full path:' , fullPath , 'Is image:' , isImageFile ( fullPath ) ) ;
270277
271278 if ( isImageFile ( fullPath ) ) {
272279 pathsSet . add ( fullPath ) ;
273280 }
274281 }
275282
276- const uniquePaths = Array . from ( pathsSet ) ; // Convert Set back to Array
277- console . log ( '[extractImagePaths] Final extracted paths (unique):' , uniquePaths ) ;
283+ const uniquePaths = Array . from ( pathsSet ) ;
284+ console . log ( '[extractImagePaths] Final extracted paths (unique):' , uniquePaths . length ) ;
278285 return uniquePaths ;
279286 } ;
280287
@@ -479,7 +486,7 @@ const FloatingPromptInputInner = (
479486
480487 const handlePaste = async ( e : React . ClipboardEvent ) => {
481488 const items = e . clipboardData ?. items ;
482- if ( ! items || ! projectPath ) return ;
489+ if ( ! items ) return ;
483490
484491 for ( const item of items ) {
485492 if ( item . type . startsWith ( 'image/' ) ) {
@@ -492,24 +499,13 @@ const FloatingPromptInputInner = (
492499 try {
493500 // Convert blob to base64
494501 const reader = new FileReader ( ) ;
495- reader . onload = async ( ) => {
502+ reader . onload = ( ) => {
496503 const base64Data = reader . result as string ;
497504
498- // Generate a session-specific ID for the image
499- const sessionId = `paste-${ Date . now ( ) } ` ;
500-
501- // Save the image via Tauri command
502- const imagePath = await invoke < string > ( 'save_clipboard_image' , {
503- projectPath,
504- sessionId,
505- imageData : base64Data ,
506- mimeType : item . type
507- } ) ;
508-
509- // Add the image path as a mention to the prompt
505+ // Add the base64 data URL directly to the prompt
510506 setPrompt ( currentPrompt => {
511- // Wrap path in quotes if it contains spaces
512- const mention = imagePath . includes ( ' ' ) ? `@"${ imagePath } "` : `@ ${ imagePath } `;
507+ // Use the data URL directly as the image reference
508+ const mention = `@"${ base64Data } " ` ;
513509 const newPrompt = currentPrompt + ( currentPrompt . endsWith ( ' ' ) || currentPrompt === '' ? '' : ' ' ) + mention + ' ' ;
514510
515511 // Focus the textarea and move cursor to end
@@ -548,6 +544,17 @@ const FloatingPromptInputInner = (
548544 const handleRemoveImage = ( index : number ) => {
549545 // Remove the corresponding @mention from the prompt
550546 const imagePath = embeddedImages [ index ] ;
547+
548+ // For data URLs, we need to handle them specially since they're always quoted
549+ if ( imagePath . startsWith ( 'data:' ) ) {
550+ // Simply remove the exact quoted data URL
551+ const quotedPath = `@"${ imagePath } "` ;
552+ const newPrompt = prompt . replace ( quotedPath , '' ) . trim ( ) ;
553+ setPrompt ( newPrompt ) ;
554+ return ;
555+ }
556+
557+ // For file paths, use the original logic
551558 const escapedPath = imagePath . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) ;
552559 const escapedRelativePath = imagePath . replace ( projectPath + '/' , '' ) . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) ;
553560
0 commit comments