| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Artistry Gallery | Your Personal Digital Art Space</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .gallery-item { |
| transition: all 0.3s ease; |
| transform: scale(1); |
| } |
| .gallery-item:hover { |
| transform: scale(1.03); |
| box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); |
| z-index: 10; |
| } |
| .modal-overlay { |
| background-color: rgba(0, 0, 0, 0.9); |
| } |
| .modal-content { |
| animation: fadeIn 0.3s ease-out; |
| } |
| @keyframes fadeIn { |
| from { opacity: 0; transform: scale(0.9); } |
| to { opacity: 1; transform: scale(1); } |
| } |
| .upload-area { |
| border: 2px dashed #cbd5e0; |
| transition: all 0.3s ease; |
| } |
| .upload-area:hover { |
| border-color: #667eea; |
| background-color: rgba(102, 126, 234, 0.05); |
| } |
| .upload-area.dragover { |
| border-color: #667eea; |
| background-color: rgba(102, 126, 234, 0.1); |
| } |
| .category-btn.active { |
| background-color: #667eea; |
| color: white; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-50 font-sans"> |
| |
| <nav class="bg-white shadow-lg"> |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> |
| <div class="flex justify-between h-16"> |
| <div class="flex items-center"> |
| <div class="flex-shrink-0 flex items-center"> |
| <i class="fas fa-palette text-indigo-600 text-2xl mr-2"></i> |
| <span class="text-xl font-bold text-gray-900">Artistry Gallery</span> |
| </div> |
| </div> |
| <div class="flex items-center"> |
| <button id="uploadBtn" class="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 transition flex items-center"> |
| <i class="fas fa-upload mr-2"></i> Upload Art |
| </button> |
| </div> |
| </div> |
| </div> |
| </nav> |
|
|
| |
| <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"> |
| |
| <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-8"> |
| <h1 class="text-3xl font-bold text-gray-900 mb-4 sm:mb-0">Your Personal Art Collection</h1> |
| |
| <div class="flex space-x-2 overflow-x-auto pb-2 w-full sm:w-auto"> |
| <button class="category-btn active px-4 py-2 rounded-full bg-indigo-600 text-white text-sm" data-category="all">All</button> |
| <button class="category-btn px-4 py-2 rounded-full bg-gray-200 text-gray-700 hover:bg-gray-300 text-sm" data-category="painting">Paintings</button> |
| <button class="category-btn px-4 py-2 rounded-full bg-gray-200 text-gray-700 hover:bg-gray-300 text-sm" data-category="photography">Photography</button> |
| <button class="category-btn px-4 py-2 rounded-full bg-gray-200 text-gray-700 hover:bg-gray-300 text-sm" data-category="digital">Digital Art</button> |
| <button class="category-btn px-4 py-2 rounded-full bg-gray-200 text-gray-700 hover:bg-gray-300 text-sm" data-category="sketch">Sketches</button> |
| </div> |
| </div> |
|
|
| |
| <div id="galleryGrid" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6"> |
| |
| <div class="text-center py-12 text-gray-500" id="emptyState"> |
| <i class="fas fa-images text-4xl mb-4 text-gray-300"></i> |
| <p class="text-lg">Your gallery is empty</p> |
| <p class="text-sm mt-2">Upload your first artwork to get started</p> |
| </div> |
| </div> |
| </main> |
|
|
| |
| <div id="uploadModal" class="fixed inset-0 z-50 hidden"> |
| <div class="modal-overlay absolute inset-0"></div> |
| <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> |
| <div class="modal-content inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"> |
| <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |
| <div class="sm:flex sm:items-start"> |
| <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left w-full"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-lg leading-6 font-medium text-gray-900">Upload Artwork</h3> |
| <button id="closeModal" class="text-gray-400 hover:text-gray-500"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <div class="mt-2"> |
| <div id="uploadArea" class="upload-area rounded-lg p-8 text-center cursor-pointer mb-4"> |
| <i class="fas fa-cloud-upload-alt text-4xl text-indigo-500 mb-3"></i> |
| <p class="text-gray-600">Drag & drop your artwork here</p> |
| <p class="text-gray-400 text-sm mt-1">or click to browse files</p> |
| <input type="file" id="fileInput" class="hidden" accept="image/*" multiple> |
| </div> |
| |
| <div class="mb-4"> |
| <label for="artTitle" class="block text-sm font-medium text-gray-700 mb-1">Title</label> |
| <input type="text" id="artTitle" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"> |
| </div> |
| |
| <div class="mb-4"> |
| <label for="artCategory" class="block text-sm font-medium text-gray-700 mb-1">Category</label> |
| <select id="artCategory" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"> |
| <option value="painting">Painting</option> |
| <option value="photography">Photography</option> |
| <option value="digital">Digital Art</option> |
| <option value="sketch">Sketch</option> |
| <option value="other">Other</option> |
| </select> |
| </div> |
| |
| <div class="mb-4"> |
| <label for="artDescription" class="block text-sm font-medium text-gray-700 mb-1">Description (optional)</label> |
| <textarea id="artDescription" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"></textarea> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |
| <button id="submitUpload" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:ml-3 sm:w-auto sm:text-sm"> |
| Upload Artwork |
| </button> |
| <button id="cancelUpload" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> |
| Cancel |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="imageViewer" class="fixed inset-0 z-50 hidden"> |
| <div class="modal-overlay absolute inset-0"></div> |
| <div class="flex items-center justify-center min-h-screen"> |
| <div class="relative max-w-4xl w-full mx-4"> |
| <button id="closeViewer" class="absolute top-4 right-4 text-white text-3xl z-10 hover:text-gray-300"> |
| <i class="fas fa-times"></i> |
| </button> |
| <button id="prevImage" class="absolute left-4 top-1/2 transform -translate-y-1/2 text-white text-3xl z-10 hover:text-gray-300"> |
| <i class="fas fa-chevron-left"></i> |
| </button> |
| <button id="nextImage" class="absolute right-4 top-1/2 transform -translate-y-1/2 text-white text-3xl z-10 hover:text-gray-300"> |
| <i class="fas fa-chevron-right"></i> |
| </button> |
| |
| <div class="bg-white rounded-lg overflow-hidden"> |
| <img id="viewerImage" src="" alt="" class="w-full max-h-screen-80 object-contain"> |
| <div class="p-4 bg-white"> |
| <h3 id="viewerTitle" class="text-xl font-bold text-gray-900"></h3> |
| <div class="flex items-center mt-1 mb-2"> |
| <span id="viewerCategory" class="px-2 py-1 text-xs rounded-full bg-indigo-100 text-indigo-800"></span> |
| <span class="text-gray-500 text-sm ml-auto" id="viewerDate"></span> |
| </div> |
| <p id="viewerDescription" class="text-gray-700 mt-2"></p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| |
| let galleryData = JSON.parse(localStorage.getItem('artGallery')) || []; |
| let currentCategory = 'all'; |
| let currentViewerIndex = 0; |
| |
| |
| const uploadBtn = document.getElementById('uploadBtn'); |
| const uploadModal = document.getElementById('uploadModal'); |
| const closeModal = document.getElementById('closeModal'); |
| const cancelUpload = document.getElementById('cancelUpload'); |
| const uploadArea = document.getElementById('uploadArea'); |
| const fileInput = document.getElementById('fileInput'); |
| const submitUpload = document.getElementById('submitUpload'); |
| const galleryGrid = document.getElementById('galleryGrid'); |
| const emptyState = document.getElementById('emptyState'); |
| const categoryBtns = document.querySelectorAll('.category-btn'); |
| const imageViewer = document.getElementById('imageViewer'); |
| const closeViewer = document.getElementById('closeViewer'); |
| const prevImage = document.getElementById('prevImage'); |
| const nextImage = document.getElementById('nextImage'); |
| const viewerImage = document.getElementById('viewerImage'); |
| const viewerTitle = document.getElementById('viewerTitle'); |
| const viewerCategory = document.getElementById('viewerCategory'); |
| const viewerDescription = document.getElementById('viewerDescription'); |
| const viewerDate = document.getElementById('viewerDate'); |
| |
| |
| uploadBtn.addEventListener('click', () => uploadModal.classList.remove('hidden')); |
| closeModal.addEventListener('click', () => uploadModal.classList.add('hidden')); |
| cancelUpload.addEventListener('click', () => uploadModal.classList.add('hidden')); |
| closeViewer.addEventListener('click', () => imageViewer.classList.add('hidden')); |
| |
| uploadArea.addEventListener('click', () => fileInput.click()); |
| |
| fileInput.addEventListener('change', (e) => { |
| if (e.target.files.length > 0) { |
| |
| } |
| }); |
| |
| |
| uploadArea.addEventListener('dragover', (e) => { |
| e.preventDefault(); |
| uploadArea.classList.add('dragover'); |
| }); |
| |
| uploadArea.addEventListener('dragleave', () => { |
| uploadArea.classList.remove('dragover'); |
| }); |
| |
| uploadArea.addEventListener('drop', (e) => { |
| e.preventDefault(); |
| uploadArea.classList.remove('dragover'); |
| fileInput.files = e.dataTransfer.files; |
| }); |
| |
| |
| submitUpload.addEventListener('click', () => { |
| const title = document.getElementById('artTitle').value.trim(); |
| const category = document.getElementById('artCategory').value; |
| const description = document.getElementById('artDescription').value.trim(); |
| |
| if (!title) { |
| alert('Please enter a title for your artwork'); |
| return; |
| } |
| |
| if (fileInput.files.length === 0) { |
| alert('Please select an image file'); |
| return; |
| } |
| |
| const file = fileInput.files[0]; |
| const reader = new FileReader(); |
| |
| reader.onload = function(e) { |
| const newArtwork = { |
| id: Date.now(), |
| title: title, |
| category: category, |
| description: description, |
| image: e.target.result, |
| date: new Date().toLocaleDateString() |
| }; |
| |
| galleryData.push(newArtwork); |
| saveGalleryData(); |
| renderGallery(); |
| uploadModal.classList.add('hidden'); |
| |
| |
| document.getElementById('artTitle').value = ''; |
| document.getElementById('artDescription').value = ''; |
| fileInput.value = ''; |
| }; |
| |
| reader.readAsDataURL(file); |
| }); |
| |
| |
| categoryBtns.forEach(btn => { |
| btn.addEventListener('click', () => { |
| categoryBtns.forEach(b => b.classList.remove('active')); |
| btn.classList.add('active'); |
| currentCategory = btn.dataset.category; |
| renderGallery(); |
| }); |
| }); |
| |
| |
| prevImage.addEventListener('click', () => { |
| if (currentViewerIndex > 0) { |
| currentViewerIndex--; |
| updateViewer(); |
| } |
| }); |
| |
| nextImage.addEventListener('click', () => { |
| if (currentViewerIndex < getFilteredGallery().length - 1) { |
| currentViewerIndex++; |
| updateViewer(); |
| } |
| }); |
| |
| |
| function saveGalleryData() { |
| localStorage.setItem('artGallery', JSON.stringify(galleryData)); |
| } |
| |
| function getFilteredGallery() { |
| if (currentCategory === 'all') return galleryData; |
| return galleryData.filter(item => item.category === currentCategory); |
| } |
| |
| function renderGallery() { |
| const filteredGallery = getFilteredGallery(); |
| |
| if (filteredGallery.length === 0) { |
| emptyState.classList.remove('hidden'); |
| galleryGrid.innerHTML = ''; |
| galleryGrid.appendChild(emptyState); |
| return; |
| } |
| |
| emptyState.classList.add('hidden'); |
| galleryGrid.innerHTML = ''; |
| |
| filteredGallery.forEach((item, index) => { |
| const galleryItem = document.createElement('div'); |
| galleryItem.className = 'gallery-item bg-white rounded-lg overflow-hidden shadow-md cursor-pointer'; |
| galleryItem.dataset.index = index; |
| |
| galleryItem.innerHTML = ` |
| <div class="relative pb-3/4 h-48 overflow-hidden"> |
| <img src="${item.image}" alt="${item.title}" class="absolute h-full w-full object-cover"> |
| </div> |
| <div class="p-4"> |
| <h3 class="font-medium text-gray-900 truncate">${item.title}</h3> |
| <div class="flex items-center mt-1"> |
| <span class="px-2 py-1 text-xs rounded-full ${getCategoryClass(item.category)}">${formatCategory(item.category)}</span> |
| </div> |
| </div> |
| `; |
| |
| galleryItem.addEventListener('click', () => { |
| currentViewerIndex = index; |
| updateViewer(); |
| imageViewer.classList.remove('hidden'); |
| }); |
| |
| galleryGrid.appendChild(galleryItem); |
| }); |
| } |
| |
| function updateViewer() { |
| const artwork = getFilteredGallery()[currentViewerIndex]; |
| viewerImage.src = artwork.image; |
| viewerImage.alt = artwork.title; |
| viewerTitle.textContent = artwork.title; |
| viewerCategory.textContent = formatCategory(artwork.category); |
| viewerCategory.className = `px-2 py-1 text-xs rounded-full ${getCategoryClass(artwork.category)}`; |
| viewerDescription.textContent = artwork.description || 'No description provided'; |
| viewerDate.textContent = artwork.date; |
| |
| |
| prevImage.style.display = currentViewerIndex === 0 ? 'none' : 'block'; |
| nextImage.style.display = currentViewerIndex === getFilteredGallery().length - 1 ? 'none' : 'block'; |
| } |
| |
| function formatCategory(category) { |
| return category.charAt(0).toUpperCase() + category.slice(1); |
| } |
| |
| function getCategoryClass(category) { |
| const classes = { |
| painting: 'bg-red-100 text-red-800', |
| photography: 'bg-blue-100 text-blue-800', |
| digital: 'bg-purple-100 text-purple-800', |
| sketch: 'bg-yellow-100 text-yellow-800', |
| other: 'bg-gray-100 text-gray-800' |
| }; |
| return classes[category] || 'bg-gray-100 text-gray-800'; |
| } |
| |
| |
| renderGallery(); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Fate17/flashes" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |