diff --git a/apps/studio/src/routes/editor/EditPanel/StylesTab/single/ColorInput/ImagePicker.tsx b/apps/studio/src/routes/editor/EditPanel/StylesTab/single/ColorInput/ImagePicker.tsx index 81761f951b..81129c6f1d 100644 --- a/apps/studio/src/routes/editor/EditPanel/StylesTab/single/ColorInput/ImagePicker.tsx +++ b/apps/studio/src/routes/editor/EditPanel/StylesTab/single/ColorInput/ImagePicker.tsx @@ -9,6 +9,8 @@ import { } from '@onlook/ui/dropdown-menu'; import { Icons } from '@onlook/ui/icons'; import { memo, useCallback, useState } from 'react'; +import ImageSelectionModal from './ImageSelection'; +import type { ImageContentData } from '@onlook/models'; enum ImageFit { FILL = 'fill', @@ -60,6 +62,8 @@ const ImagePickerContent: React.FC<{ backgroundImage?: string; compoundStyle?: C }) => { const editorEngine = useEditorEngine(); const [isDragging, setIsDragging] = useState(false); + const [isImageSelectionOpen, setIsImageSelectionOpen] = useState(false); + const getDefaultImageData = () => { const selectedStyle = editorEngine.style.selectedStyle?.styles; const url = backgroundImage; @@ -96,6 +100,18 @@ const ImagePickerContent: React.FC<{ backgroundImage?: string; compoundStyle?: C mimeType: '', }; }; + + const handleImageSelection = (selectedImage: ImageContentData) => { + const newImageData: ImageData = { + url: selectedImage.content, + base64: selectedImage.content, + mimeType: selectedImage.mimeType, + fit: imageData?.fit || ImageFit.FILL, + }; + setImageData(newImageData); + editorEngine.image.insert(selectedImage.content, selectedImage.mimeType); + }; + const [imageData, setImageData] = useState(getDefaultImageData()); const handleDragOver = useCallback((e: React.DragEvent) => { @@ -175,14 +191,23 @@ const ImagePickerContent: React.FC<{ backgroundImage?: string; compoundStyle?: C onDragLeave={handleDragLeave} onDrop={handleDrop} > - - +
+ + + setIsImageSelectionOpen(true)} /> + + setIsImageSelectionOpen(false)} + onSelect={handleImageSelection} + /> +
@@ -220,6 +245,22 @@ const UploadButton: React.FC<{ onButtonClick: (e: React.MouseEvent) => void }> = ), ); +const SelectImageButton: React.FC<{ onButtonClick: (e: React.MouseEvent) => void }> = memo( + ({ onButtonClick }) => ( + + ), +); + +SelectImageButton.displayName = 'SelectImageButton'; + UploadButton.displayName = 'UploadButton'; export default memo(ImagePickerContent); diff --git a/apps/studio/src/routes/editor/EditPanel/StylesTab/single/ColorInput/ImageSelection.tsx b/apps/studio/src/routes/editor/EditPanel/StylesTab/single/ColorInput/ImageSelection.tsx new file mode 100644 index 0000000000..9d5a6eb1b1 --- /dev/null +++ b/apps/studio/src/routes/editor/EditPanel/StylesTab/single/ColorInput/ImageSelection.tsx @@ -0,0 +1,58 @@ +import { useEditorEngine } from '@/components/Context'; +import type { ImageContentData } from '@onlook/models'; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@onlook/ui/dialog'; +import { Input } from '@onlook/ui/input'; +import React, { useState } from 'react'; + +interface ImageSelectionModalProps { + isOpen: boolean; + onClose: () => void; + onSelect: (image: ImageContentData) => void; +} + +const ImageSelectionModal: React.FC = ({ isOpen, onClose, onSelect }) => { + const editorEngine = useEditorEngine(); + const [search, setSearch] = useState(''); + + const filteredImages = editorEngine.image.assets.filter( + (image) => !search || image.fileName.toLowerCase().includes(search.toLowerCase()), + ); + + return ( + onClose()}> + + + Select Image + +
+ setSearch(e.target.value)} + className="h-8 text-xs" + /> +
+ {filteredImages.map((image) => ( +
{ + onSelect(image); + onClose(); + }} + > + {image.fileName} +
+ ))} +
+
+
+
+ ); +}; + +export default ImageSelectionModal;