diff --git a/VERSION b/VERSION index 10bf840..50aea0e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.0.1 \ No newline at end of file +2.1.0 \ No newline at end of file diff --git a/src/webui/gallery-editor/index.html b/src/webui/gallery-editor/index.html index 329a65c..6c3efd8 100644 --- a/src/webui/gallery-editor/index.html +++ b/src/webui/gallery-editor/index.html @@ -18,7 +18,16 @@ +
+ +${galleryImages.length} photos
`; + } + + // Update gallery count (bottom) + const galleryCountBottom = document.getElementById('gallery-count-bottom'); + if (galleryCountBottom) { + galleryCountBottom.innerHTML = `${galleryImages.length} photos
`; + } + + // Show/hide Remove All button (top) const removeAllBtn = document.getElementById('remove-all-gallery'); if (removeAllBtn) { removeAllBtn.style.display = galleryImages.length > 0 ? 'inline-block' : 'none'; } + + // Show/hide bottom upload row + const bottomGalleryUpload = document.getElementById('bottom-gallery-upload'); + if (bottomGalleryUpload) { + bottomGalleryUpload.style.display = galleryImages.length > 0 ? 'flex' : 'none'; + } + + // Show/hide Remove All button (bottom) + const removeAllBtnBottom = document.getElementById('remove-all-gallery-bottom'); + if (removeAllBtnBottom) { + removeAllBtnBottom.style.display = galleryImages.length > 0 ? 'inline-block' : 'none'; + } } // --- Render tags for a single image --- @@ -244,11 +268,35 @@ function renderHero() { container.appendChild(div); }); - // Show/hide Remove All button + // Update hero count (top) + const heroCount = document.getElementById('hero-count'); + if (heroCount) { + heroCount.innerHTML = `${heroImages.length} photos
`; + } + + // Update hero count (bottom) + const heroCountBottom = document.getElementById('hero-count-bottom'); + if (heroCountBottom) { + heroCountBottom.innerHTML = `${heroImages.length} photos
`; + } + + // Show/hide Remove All button (top) const removeAllBtn = document.getElementById('remove-all-hero'); if (removeAllBtn) { removeAllBtn.style.display = heroImages.length > 0 ? 'inline-block' : 'none'; } + + // Show/hide bottom upload row + const bottomHeroUpload = document.getElementById('bottom-hero-upload'); + if (bottomHeroUpload) { + bottomHeroUpload.style.display = heroImages.length > 0 ? 'flex' : 'none'; + } + + // Show/hide Remove All button (bottom) + const removeAllBtnBottom = document.getElementById('remove-all-hero-bottom'); + if (removeAllBtnBottom) { + removeAllBtnBottom.style.display = heroImages.length > 0 ? 'inline-block' : 'none'; + } } // --- Save gallery to server --- @@ -429,9 +477,13 @@ document.addEventListener('DOMContentLoaded', () => { // Bulk delete buttons const removeAllGalleryBtn = document.getElementById('remove-all-gallery'); + const removeAllGalleryBtnBottom = document.getElementById('remove-all-gallery-bottom'); const removeAllHeroBtn = document.getElementById('remove-all-hero'); + const removeAllHeroBtnBottom = document.getElementById('remove-all-hero-bottom'); if (removeAllGalleryBtn) removeAllGalleryBtn.onclick = () => showDeleteModal('gallery-all'); + if (removeAllGalleryBtnBottom) removeAllGalleryBtnBottom.onclick = () => showDeleteModal('gallery-all'); if (removeAllHeroBtn) removeAllHeroBtn.onclick = () => showDeleteModal('hero-all'); + if (removeAllHeroBtnBottom) removeAllHeroBtnBottom.onclick = () => showDeleteModal('hero-all'); }); // --- Initialize --- diff --git a/src/webui/js/upload.js b/src/webui/js/upload.js index d2a45f1..8316b6e 100644 --- a/src/webui/js/upload.js +++ b/src/webui/js/upload.js @@ -11,6 +11,7 @@ function hideLoader() { if (loader) loader.classList.remove("active"); } + // --- Upload gallery images --- const galleryInput = document.getElementById('upload-gallery'); if (galleryInput) { @@ -47,6 +48,58 @@ if (heroInput) { const formData = new FormData(); for (const file of files) formData.append('files', file); + try { + const res = await fetch('/api/hero/upload', { method: 'POST', body: formData }); + const data = await res.json(); + hideLoader(); + if (res.ok) { + showToast(`✅ ${data.uploaded.length} hero image(s) uploaded!`, "success"); + if (typeof refreshHero === "function") refreshHero(); + } else showToast('Error: ' + data.error, "error"); + } catch(err) { + hideLoader(); + console.error(err); + showToast('Server error!', "error"); + } finally { e.target.value = ''; } + }); +} + +// --- Upload gallery images (bottom button) --- +const galleryInputBottom = document.getElementById('upload-gallery-bottom'); +if (galleryInputBottom) { + galleryInputBottom.addEventListener('change', async (e) => { + const files = e.target.files; + if (!files.length) return; + showLoader("Uploading photos..."); + const formData = new FormData(); + for (const file of files) formData.append('files', file); + + try { + const res = await fetch('/api/gallery/upload', { method: 'POST', body: formData }); + const data = await res.json(); + hideLoader(); + if (res.ok) { + showToast(`✅ ${data.uploaded.length} gallery image(s) uploaded!`, "success"); + if (typeof refreshGallery === "function") refreshGallery(); + } else showToast('Error: ' + data.error, "error"); + } catch(err) { + hideLoader(); + console.error(err); + showToast('Server error!', "error"); + } finally { e.target.value = ''; } + }); +} + +// --- Upload hero images (bottom button) --- +const heroInputBottom = document.getElementById('upload-hero-bottom'); +if (heroInputBottom) { + heroInputBottom.addEventListener('change', async (e) => { + const files = e.target.files; + if (!files.length) return; + showLoader("Uploading hero photos..."); + const formData = new FormData(); + for (const file of files) formData.append('files', file); + try { const res = await fetch('/api/hero/upload', { method: 'POST', body: formData }); const data = await res.json(); diff --git a/src/webui/style/style.css b/src/webui/style/style.css index c75c539..c397faa 100644 --- a/src/webui/style/style.css +++ b/src/webui/style/style.css @@ -241,7 +241,7 @@ h2 { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 15px; - margin-top: 30px; + margin: 30px 0 0 0; } /* --- Photo Card --- */ @@ -521,18 +521,23 @@ h2 { align-items: center; gap: 16px; margin-bottom: 10px; + flex-wrap: wrap; } /* --- Remove All Buttons --- */ -#remove-all-hero, #remove-all-gallery { +#remove-all-hero, #remove-all-gallery, .bottom-remove-btn { background: #2d2d2d; color: white; display: none; margin-bottom: 6px; } +.bottom-remove-btn { + display: inherit; +} + #remove-all-gallery:hover, -#remove-all-hero:hover { +#remove-all-hero:hover, .bottom-remove-btn:hover { background: rgb(121, 26, 19); } @@ -541,6 +546,7 @@ h2 { flex-direction: column; align-items: stretch; gap: 8px; + flex-wrap: wrap; } } @@ -1036,4 +1042,12 @@ justify-content: center; position: relative; flex-wrap: nowrap; } +} + +#hero-count-bottom, #gallery-count-bottom { + flex-basis: 100%; +} + +.bottom-action-row { + margin-top: 30px; } \ No newline at end of file