UNPKG

use-vibes

Version:

Transform any DOM element into an AI-powered micro-app

181 lines 8.63 kB
import * as React from 'react'; import { useFireproof, ImgFile } from 'use-fireproof'; import { ImgGenFileDrop } from '../ImgGenUtils/ImgGenFileDrop'; import { combineClasses } from '../../utils/style-utils'; import '../ImgGen.css'; /** * Component for displaying uploaded images and allowing users to: * 1. Upload more images to the same document * 2. Enter a prompt to start generation */ export function ImgGenUploadWaiting({ document, className, classes, debug, database, onFilesAdded, onDocumentCreated, onPromptSubmit, }) { const { database: db } = useFireproof(database || 'ImgGen'); const [prompt, setPrompt] = React.useState(''); const [inputFiles, setInputFiles] = React.useState([]); // Get all input files from the document React.useEffect(() => { if (document?._files) { const inFiles = Object.keys(document._files) .filter((key) => key.startsWith('in')) .sort(); setInputFiles(inFiles); if (debug) { console.log('[ImgGenUploadWaiting] Found input files:', inFiles); } } }, [document, debug]); // Clean up any created object URLs when unmounting React.useEffect(() => { const objectUrls = []; return () => { // Clean up any created object URLs objectUrls.forEach((url) => URL.revokeObjectURL(url)); }; }, []); // Handle files being uploaded - two paths: add to existing doc or create new doc const handleFilesUploaded = async (files) => { if (!files.length) return; // If we already have a document, add files to it if (document && document._id) { await addFilesToExistingDocument(files); } // Otherwise create a new document else { await createNewDocumentWithFiles(files); } }; // Create a new document with the uploaded files const createNewDocumentWithFiles = async (files) => { try { // Create new document to hold the uploaded files const newDoc = { type: 'image', createdAt: new Date().toISOString(), _files: {}, }; // Add files to the document with input file keys files.forEach((file, index) => { // Input files are prefixed with 'in' followed by a number // These are files uploaded by the user, not generated by AI newDoc._files[`in${index + 1}`] = file; }); // Save the document to get an ID const result = await db.put(newDoc); if (debug) { console.log('[ImgGenUploadWaiting] Created document for uploads:', result.id); } // Notify parent component that files were uploaded and document created if (onDocumentCreated && result.id) { onDocumentCreated(result.id); } } catch (error) { console.error('[ImgGenUploadWaiting] Error creating document for uploads:', error); } }; // Add files to an existing document const addFilesToExistingDocument = async (files) => { if (!document || !document._id) return; try { // Load existing document const doc = await db.get(document._id); if (!doc) { console.error('[ImgGenUploadWaiting] Document not found:', document._id); return; } // Find highest current input file number let maxInputNum = 0; if (doc._files) { Object.keys(doc._files).forEach((key) => { if (key.startsWith('in')) { const num = parseInt(key.substring(2), 10); if (!isNaN(num) && num > maxInputNum) { maxInputNum = num; } } }); } // Add new files with incremented keys const updatedDoc = { ...doc }; if (!updatedDoc._files) updatedDoc._files = {}; for (let i = 0; i < files.length; i++) { const file = files[i]; const fileKey = `in${maxInputNum + i + 1}`; // Add file to document updatedDoc._files[fileKey] = file; if (debug) { console.log(`[ImgGenUploadWaiting] Adding file to document: ${fileKey}`, file.name); } } // Save updated document const result = await db.put(updatedDoc); if (debug) { console.log('[ImgGenUploadWaiting] Document updated with new files:', result.id); } // Refresh the document to get the latest version with new files const refreshedDoc = await db.get(result.id); if (refreshedDoc) { // Update input files state with the new files const inFiles = Object.keys(refreshedDoc._files || {}) .filter((key) => key.startsWith('in')) .sort(); setInputFiles(inFiles); if (debug) { console.log('[ImgGenUploadWaiting] Refreshed input files:', inFiles); } } // Notify parent about files added if (onFilesAdded) { onFilesAdded(); } } catch (error) { console.error('[ImgGenUploadWaiting] Error updating document with new files:', error); } }; // Handle prompt submission const handleSubmit = (e) => { e.preventDefault(); if (prompt.trim()) { // Pass both the prompt and document ID to the parent component if we have a document if (document && document._id) { if (debug) { console.log('[ImgGenUploadWaiting] Submitting prompt with document ID:', document._id); } onPromptSubmit(prompt.trim(), document._id); } else { // Submit just the prompt if no document is available if (debug) { console.log('[ImgGenUploadWaiting] Submitting prompt with no document'); } onPromptSubmit(prompt.trim()); } } }; // We no longer need this function since we're using ImgFile component // which handles all the file display logic for us return (React.createElement("div", { className: combineClasses('imggen-upload-waiting', className || '', classes?.uploadWaiting || '') }, React.createElement("div", { className: "imggen-placeholder-content", style: { textAlign: 'center' } }, React.createElement("h3", { style: { margin: '0 0 0.5rem 0', color: '#333' } }, "Image Generator")), React.createElement("form", { onSubmit: handleSubmit, className: "imggen-prompt-form" }, React.createElement("input", { type: "text", value: prompt, onChange: (e) => setPrompt(e.target.value), placeholder: "Enter a prompt...", className: "imggen-prompt-input" }), React.createElement("button", { type: "submit", disabled: !prompt.trim(), className: "imggen-prompt-submit" }, "Generate")), inputFiles.length > 0 && (React.createElement("div", { className: "imggen-uploaded-previews" }, React.createElement("div", { className: "imggen-upload-count" }, inputFiles.length, " ", inputFiles.length === 1 ? 'image' : 'images', " uploaded"), React.createElement("div", { className: "imggen-thumbnails" }, inputFiles.slice(0, 4).map((fileKey) => (React.createElement("div", { key: fileKey, className: "imggen-thumbnail" }, document?._files && document._files[fileKey] && (React.createElement(ImgFile, { file: document._files[fileKey], alt: `Upload ${fileKey}`, className: "imggen-thumbnail-img" }))))), inputFiles.length > 4 && (React.createElement("div", { className: "imggen-more-count" }, "+", inputFiles.length - 4, " more"))))), React.createElement(ImgGenFileDrop, { className: classes?.dropZone || '', onFilesDropped: handleFilesUploaded, isActive: true, maxFiles: 10, debug: debug, addFilesMessage: "Drop images or click to upload (optional)" }))); } //# sourceMappingURL=ImgGenUploadWaiting.js.map