document.addEventListener('DOMContentLoaded', () => { const uploadInput = document.getElementById('image-upload'); const uploadButton = document.getElementById('upload-button'); const uploadDropzone = document.getElementById('upload-dropzone'); const uploadedPreviews = document.getElementById('uploaded-previews'); const imageSpots = Array.from(document.querySelectorAll('.image-spot')); const textPrompt = document.getElementById('text-prompt'); const remixButton = document.getElementById('remix-button'); const statusMessage = document.getElementById('status-message'); const remixResult = document.getElementById('remix-result'); const resultImage = document.getElementById('result-image'); const resultPlaceholder = document.getElementById('result-placeholder'); // Store base64 data for images in spots const imageSpotData = Array(3).fill(null); // Store original draggable elements created from uploaded images const draggableImages = new Map(); // Map let uploadedImageCounter = 0; // --- Utility Functions --- const showStatus = (message, type = 'loading') => { statusMessage.textContent = message; statusMessage.className = `status-message ${type}`; statusMessage.style.display = 'block'; }; const hideStatus = () => { statusMessage.style.display = 'none'; statusMessage.textContent = ''; }; const clearResult = () => { resultImage.style.display = 'none'; resultImage.src = ''; resultPlaceholder.style.display = 'block'; }; // --- File Upload Logic --- uploadButton.addEventListener('click', () => uploadInput.click()); uploadInput.addEventListener('change', (event) => { handleFiles(event.target.files); }); uploadDropzone.addEventListener('dragover', (event) => { event.preventDefault(); uploadDropzone.classList.add('drag-over'); }); uploadDropzone.addEventListener('dragleave', () => { uploadDropzone.classList.remove('drag-over'); }); uploadDropzone.addEventListener('drop', (event) => { event.preventDefault(); uploadDropzone.classList.remove('drag-over'); handleFiles(event.dataTransfer.files); }); function handleFiles(files) { if (files.length === 0) return; Array.from(files).forEach(file => { if (!file.type.startsWith('image/')) return; const reader = new FileReader(); reader.onload = (e) => { const imgId = `uploaded-img-${uploadedImageCounter++}`; createDraggableImage(e.target.result, imgId); }; reader.readAsDataURL(file); }); } function createDraggableImage(src, id) { const wrapper = document.createElement('div'); wrapper.className = 'uploaded-image-wrapper'; wrapper.draggable = true; wrapper.id = id; const img = document.createElement('img'); img.src = src; img.alt = `Uploaded image ${id}`; const removeBtn = document.createElement('button'); removeBtn.className = 'remove-image'; removeBtn.textContent = 'x'; removeBtn.title = 'Remove image'; removeBtn.addEventListener('click', (e) => { e.stopPropagation(); // Prevent drag event from firing wrapper.remove(); draggableImages.delete(id); // Also check if this image was in any spot and remove it for (let i = 0; i < imageSpotData.length; i++) { if (imageSpotData[i] && imageSpotData[i].id === id) { clearImageSpot(imageSpots[i], i); } } }); wrapper.appendChild(img); wrapper.appendChild(removeBtn); uploadedPreviews.appendChild(wrapper); draggableImages.set(id, { element: wrapper, src: src }); wrapper.addEventListener('dragstart', (e) => { e.dataTransfer.setData('text/plain', id); e.dataTransfer.effectAllowed = 'copyMove'; // Optional: add a class to the original to make it transparent or similar // e.target.classList.add('dragging'); }); // wrapper.addEventListener('dragend', (e) => { // e.target.classList.remove('dragging'); // }); } // --- Image Spot Drag & Drop Logic --- imageSpots.forEach((spot) => { spot.addEventListener('dragover', (event) => { event.preventDefault(); spot.classList.add('drag-over'); event.dataTransfer.dropEffect = 'copy'; }); spot.addEventListener('dragleave', () => { spot.classList.remove('drag-over'); }); spot.addEventListener('drop', (event) => { event.preventDefault(); spot.classList.remove('drag-over'); const draggedId = event.dataTransfer.getData('text/plain'); const draggedImageData = draggableImages.get(draggedId); if (draggedImageData) { const spotIndex = parseInt(spot.dataset.index); renderImageInSpot(spot, draggedImageData.src); imageSpotData[spotIndex] = { src: draggedImageData.src, id: draggedId }; } }); }); function renderImageInSpot(spotElement, imgSrc) { const imgElement = spotElement.querySelector('.spot-image'); imgElement.src = imgSrc; spotElement.classList.add('has-image'); imgElement.alt = `Image in spot ${spotElement.dataset.index + 1}`; // Remove old image's alt if it exists and wasn't placeholder. } function clearImageSpot(spotElement, spotIndex) { const imgElement = spotElement.querySelector('.spot-image'); imgElement.src = 'assets/img/placeholder.png'; // Reset to placeholder spotElement.classList.remove('has-image'); imgElement.alt = `Image spot ${spotIndex + 1}`; imageSpotData[spotIndex] = null; } // --- Remix Logic --- remixButton.addEventListener('click', remixImages); async function remixImages() { hideStatus(); clearResult(); const images = imageSpotData.filter(data => data !== null); const prompt = textPrompt.value.trim(); const selectedModel = document.querySelector('input[name="ai-model"]:checked').value; if (images.length === 0) { showStatus('Please drag at least one image into a spot.', 'error'); return; } if (!prompt) { showStatus('Please enter a text prompt.', 'error'); return; } showStatus(`Remixing with ${selectedModel}... This is a simulation.`, 'loading'); try { // Simulate API call await new Promise(resolve => setTimeout(resolve, 3000)); // Simulate network delay // In a real application, you would send `images` (base64 or URLs), `prompt`, and `selectedModel` // to a backend API that integrates with Gemini-2 or GPT Image-1. // The backend would then return the generated image's URL or base64. // For simulation, we'll use a placeholder image based on the model const placeholderResult = selectedModel === 'gemini-2' ? 'https://picsum.photos/seed/gemini/800/600?grayscale' // A bit more abstract : 'https://picsum.photos/seed/gpt/800/600'; // Standard realistic resultImage.src = placeholderResult; resultImage.style.display = 'block'; resultPlaceholder.style.display = 'none'; showStatus('Remix successful! (Simulated)', 'success'); statusMessage.style.backgroundColor = '#d4edda'; // Light green for success statusMessage.style.color = '#155724'; statusMessage.style.borderColor = '#28a745'; } catch (error) { console.error('Remix error (simulated):', error); showStatus('Failed to remix images. Please try again. (Simulated Error)', 'error'); } } }); // Initial state for result section document.addEventListener('DOMContentLoaded', () => { const resultImage = document.getElementById('result-image'); const resultPlaceholder = document.getElementById('result-placeholder'); resultImage.style.display = 'none'; resultPlaceholder.style.display = 'block'; });