
Hab es mal als extra Thema hier neu gemacht.
Meine neuste Entwicklung
Hier die Codes die Ihr braucht:
HTML Block:
Code: Alles auswählen
<section data-bs-version="5.1" class="content-gallery" group="Content" mbr-style="{
'padding-top': paddingTop + 'rem',
'padding-bottom': paddingBottom + 'rem',
'background-color': bgColor,
'--btnColor': btnColor
}" data-thumbsize="{{thumbSize}}" data-perrow="{{perRow}}" data-maximages="{{maxImages}}">
<mbr-parameters>
<header>Abstände</header>
<input type="range" inline title="Abstand oben" name="paddingTop" min="0" max="10" step="1" value="6">
<input type="range" inline title="Abstand unten" name="paddingBottom" min="0" max="10" step="1" value="6">
<header>Galerie-Einstellungen</header>
<input type="range" title="Größe der Vorschaubilder (px)" name="thumbSize" min="80" max="240" step="10" value="210">
<input type="range" title="Bilder pro Reihe" name="perRow" min="2" max="10" step="1" value="5">
<input type="range" title="Bilder pro Seite" name="maxImages" min="1" max="50" step="1" value="10">
<header>Farben</header>
<input type="color" title="Hintergrundfarbe" name="bgColor" value="#000000">
<input type="color" title="Buttonfarbe (Ordner)" name="btnColor" value="#ffa600">
<header>Inhalt</header>
<input type="text" title="Titel" name="title" value="Unsere Foto-Galerien">
<textarea title="Beschreibung" name="text">Klicke auf ein Thema, um die Fotos anzuzeigen.</textarea>
</mbr-parameters>
<div class="container text-center">
<h3 class="mbr-section-title mbr-fonts-style mb-3" mbr-theme-style="display-5">Dynamische Bilder Galerie</h3>
<p class="mbr-text mbr-fonts-style mb-4" mbr-theme-style="display-7">Bilder werden einfach aus Ordnern eingelesen</p>
<div id="galleryButtons" class="mb-4 d-flex flex-wrap justify-content-center gap-2"></div>
<h5 id="currentGalleryTitle" class="text-center mb-4 text-muted"></h5>
<div id="galleryGrid" class="gallery-grid"></div>
<!-- Pagination -->
<div id="pagination" class="mt-4 d-flex justify-content-center flex-wrap gap-1">
<button id="prevPage" class="btn btn-outline-primary m-1">Zurück</button>
<div id="pageNumbers" class="d-flex flex-wrap justify-content-center"></div>
<button id="nextPage" class="btn btn-outline-primary m-1">Weiter</button>
</div>
</div>
<!-- Lightbox -->
<div id="lightbox-gallery" class="lightbox">
<span class="close" onclick="closeGallery()">×</span>
<div class="lightbox-content">
<img class="lightbox-image" id="lightbox-image" src alt>
<a class="prev" onclick="changeSlide(-1)">❮</a>
<a class="next" onclick="changeSlide(1)">❯</a>
</div>
</div>
<script>
let galleryImages = [], currentSlide = 0, currentPage = 1, totalPages = 1;
async function loadGalleries() {
const res = await fetch('galerien/');
const text = await res.text();
const doc = new DOMParser().parseFromString(text, 'text/html');
const folders = [...doc.querySelectorAll('a')]
.map(a => a.getAttribute('href'))
.filter(h => h && h.endsWith('/') && !h.includes('../') && !h.toLowerCase().includes('blogblock'))
.map(h => h.replace('/', ''));
const btns = document.getElementById('galleryButtons');
btns.innerHTML = '';
folders.forEach(f => {
const b = document.createElement('button');
b.className = 'btn m-1 gal-btn';
b.textContent = f.charAt(0).toUpperCase() + f.slice(1);
b.onclick = () => loadFolder(f);
btns.appendChild(b);
});
if (folders.length) loadFolder(folders[0]);
}
async function loadFolder(folder) {
const res = await fetch('galerien/' + folder + '/');
const text = await res.text();
const doc = new DOMParser().parseFromString(text, 'text/html');
galleryImages = [...doc.querySelectorAll('a')]
.map(a => a.getAttribute('href'))
.filter(h => h && h.match(/\.(jpg|jpeg|png|gif|webp)$/i))
.map(h => 'galerien/' + folder + '/' + h);
currentPage = 1;
renderGallery();
document.getElementById('currentGalleryTitle').textContent =
'Aktuelle Galerie: ' + folder.charAt(0).toUpperCase() + folder.slice(1);
}
function renderGallery() {
const section = document.querySelector('.content-gallery');
const perRow = parseInt(section.getAttribute('data-perRow')) || 4;
const thumb = parseInt(section.getAttribute('data-thumbSize')) || 150;
const perPage = parseInt(section.getAttribute('data-maxImages')) || 6;
const grid = document.getElementById('galleryGrid');
grid.innerHTML = '';
grid.style.gridTemplateColumns = `repeat(${perRow}, 1fr)`;
totalPages = Math.ceil(galleryImages.length / perPage);
const start = (currentPage - 1) * perPage;
const end = start + perPage;
galleryImages.slice(start, end).forEach((src, i) => {
const img = document.createElement('img');
img.src = src;
img.className = 'gallery-thumb-small';
img.style.width = thumb + 'px';
img.alt = 'Bild ' + (i + 1);
img.onclick = () => openGallery(start + i);
grid.appendChild(img);
});
updatePagination();
}
function updatePagination() {
const prevBtn = document.getElementById('prevPage');
const nextBtn = document.getElementById('nextPage');
const pageContainer = document.getElementById('pageNumbers');
prevBtn.disabled = currentPage === 1;
nextBtn.disabled = currentPage === totalPages;
pageContainer.innerHTML = '';
for (let i = 1; i <= totalPages; i++) {
const btn = document.createElement('button');
btn.className = 'btn btn-sm m-1 page-btn ' + (i === currentPage ? 'active' : '');
btn.textContent = i;
btn.onclick = () => { currentPage = i; renderGallery(); };
pageContainer.appendChild(btn);
}
prevBtn.onclick = () => {
if (currentPage > 1) { currentPage--; renderGallery(); }
};
nextBtn.onclick = () => {
if (currentPage < totalPages) { currentPage++; renderGallery(); }
};
}
function openGallery(i) {
currentSlide = i;
document.getElementById('lightbox-gallery').style.display = 'block';
showSlide(i);
}
function closeGallery() {
document.getElementById('lightbox-gallery').style.display = 'none';
}
function changeSlide(n) {
currentSlide = (currentSlide + n + galleryImages.length) % galleryImages.length;
showSlide(currentSlide);
}
function showSlide(i) {
document.getElementById('lightbox-image').src = galleryImages[i];
}
document.addEventListener('DOMContentLoaded', loadGalleries);
</script>
</section>
CSS Block:
Code: Alles auswählen
.content-gallery {
position: relative;
}
.gal-btn {
background-color: var(--btnColor, #007bff) !important;
border-color: var(--btnColor, #007bff) !important;
color: #fff !important;
border-radius: 6px;
transition: all 0.3s ease;
}
.gal-btn:hover {
opacity: 0.85;
}
.page-btn {
background-color: transparent;
color: var(--btnColor, #007bff);
border: 1px solid var(--btnColor, #007bff);
border-radius: 4px;
min-width: 40px;
transition: all 0.3s ease;
}
.page-btn.active, .page-btn:hover {
background-color: var(--btnColor, #007bff);
color: #fff;
}
.gallery-grid {
display: grid;
gap: 10px;
justify-items: center;
}
.gallery-thumb-small {
cursor: pointer;
border-radius: 8px;
transition: transform 0.3s ease, opacity 0.3s ease;
}
.gallery-thumb-small:hover {
transform: scale(1.05);
opacity: 0.8;
}
#pagination button {
min-width: 80px;
}
.lightbox {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.9);
z-index: 9999;
}
.lightbox-content {
position: relative;
margin: 60px auto;
max-width: 80%;
text-align: center;
}
.lightbox-image {
width: 100%;
max-height: 80vh;
object-fit: contain;
border-radius: 10px;
}
.close, .prev, .next {
color: #fff;
cursor: pointer;
font-size: 40px;
font-weight: bold;
user-select: none;
transition: color .3s;
}
.close:hover, .prev:hover, .next:hover {
color: #bbb;
}
.close {
position: absolute;
top: 15px;
right: 35px;
}
.prev, .next {
position: absolute;
top: 50%;
transform: translateY(-50%);
padding: 16px;
}
.prev {
left: 0;
}
.next {
right: 0;
}
P {
color: #ffffff;
}
H3 {
color: #ffffff;
}
Code: Alles auswählen
Options +Indexes
IndexOptions FancyIndexing NameWidth=*
AddType text/html .html .htm