From 879d7c585851cb3d07d4014da5712821f16c6122 Mon Sep 17 00:00:00 2001 From: patrickzerhusen Date: Mon, 27 Apr 2026 15:30:33 +0200 Subject: [PATCH] photos section in moderation portal with slider --- public/admin.php | 64 ++++++++++++++++++++++++++++++++++++++++++++--- public/styles.css | 56 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 4 deletions(-) diff --git a/public/admin.php b/public/admin.php index 7a17530..c599583 100644 --- a/public/admin.php +++ b/public/admin.php @@ -99,7 +99,7 @@ $categories = get_categories(); // Loads all Contributions for Municipality $stmt = $pdo->prepare(" - SELECT contribution_id, title, category, description, author_name, + SELECT contribution_id, title, category, description, author_name, photo_path, geom_type, status, likes_count, dislikes_count, created_at, updated_at FROM contributions WHERE municipality_id = :mid @@ -275,9 +275,28 @@ $counts['total'] = count($all_contributions);
- -
+ +
+ +
+
+
+
+ + + + + + +
@@ -295,6 +314,10 @@ $counts['total'] = count($all_contributions); · + · + + +
@@ -537,6 +560,39 @@ $counts['total'] = count($all_contributions); } + // ============================================================= + // Detail Slider for Maps and Photos + // ============================================================= + + function slideDetail(contributionId, direction) { + const slider = document.getElementById('slider-' + contributionId); + if (!slider) return; + + const slides = slider.querySelectorAll('.detail-slide'); + let activeIndex = -1; + + // Finds currently active Slide + slides.forEach(function (slide, i) { + if (slide.style.display !== 'none') activeIndex = i; + }); + + // Calculates next Slide Index (wraps around) + const nextIndex = (activeIndex + direction + slides.length) % slides.length; + + // Switches Slides + slides.forEach(function (slide) { slide.style.display = 'none'; }); + slides[nextIndex].style.display = 'block'; + + // Loads Map if switching to Map Slide and not yet loaded + if (slides[nextIndex].dataset.slide === 'map') { + const mapDiv = slides[nextIndex].querySelector('.detail-map'); + if (mapDiv && !mapDiv.dataset.loaded) { + loadMapPreview(mapDiv); + } + } + } + + // ============================================================= // Map Preview (Leaflet Mini Map per Contribution) // ============================================================= diff --git a/public/styles.css b/public/styles.css index c65704b..4ec85bc 100644 --- a/public/styles.css +++ b/public/styles.css @@ -1036,6 +1036,60 @@ select.form-input { cursor: pointer; } .back-link a { color: var(--color-text-secondary); } +/* ----------------------------------------------------------------- + 5.8 Detail Slider (Map/Photo in Admin) + ----------------------------------------------------------------- */ +.detail-slider { + width: 220px; + height: 170px; + flex-shrink: 0; + position: relative; + border-radius: 6px; + overflow: hidden; + border: 1px solid var(--color-border); + background: #f0f0f0; +} + +.detail-slide { width: 100%; height: 100%; } + +.detail-slide-photo { + width: 100%; + height: 100%; + object-fit: cover; + cursor: pointer; +} + +.detail-slider .detail-map { + width: 100%; + height: 100%; + border: none; + border-radius: 0; +} + +.slider-arrow { + position: absolute; + top: 50%; + transform: translateY(-50%); + background: rgba(0, 0, 0, 0.5); + color: white; + border: none; + width: 28px; + height: 28px; + border-radius: 50%; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.7rem; + z-index: 1000; + transition: background var(--transition-fast); +} + +.slider-arrow:hover { background: rgba(0, 0, 0, 0.7); } +.slider-arrow-left { left: 4px; } +.slider-arrow-right { right: 4px; } + + /* ================================================================= SECTION 6: Responsive Overrides ================================================================= */ @@ -1075,6 +1129,8 @@ select.form-input { cursor: pointer; } .action-buttons .btn { justify-content: center; } .filter-tabs { overflow-x: auto; } .page-tabs { overflow-x: auto; } + .detail-slider { width: 100%; height: 200px; } + /* Legal */ .page-content-box { padding: 20px; }