feat(galeria): masonry em JS com lightbox, em vez do slider
- «Conhece as nossas instalações» (e a galeria do CrossFit) passa de slider Splide a masonry: layout próprio em JS (sem biblioteca), fotos com a proporção original, coluna mais baixa primeiro e algumas a ocupar duas colunas (só quando não deixam buraco). Reorganiza ao mudar de largura (ResizeObserver + resize) e as fotos entram em cascata ao aparecer. Sem JS fica uma grelha CSS. - Clicar abre a foto num <dialog>: anterior/seguinte, setas, Esc, deslizar. - O Splide deixa de ser carregado (CSS e JS). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cb0e4540f2
commit
d70f13aea0
5 files changed
+379
-36
No files matched your search
@@ -36,7 +36,6 @@
|
||||
<!-- Scripts: jQuery first (Bootstrap navbar/alerts depend on it), then plugins -->
|
||||
<?= script_tag('site/assets/js/jquery-3.7.1.min.js') ?>
|
||||
<?= script_tag('assets/vendor/bootstrap/js/bootstrap.min.js') ?>
|
||||
<?= script_tag('site/assets/js/splide/dist/js/splide.min.js') ?>
|
||||
<?= script_tag('site/assets/js/main.js') ?>
|
||||
</body>
|
||||
</html>
|
||||
+37
-32
@@ -1,9 +1,16 @@
|
||||
<?php
|
||||
// Gallery partial — Splide CSS/JS is loaded centrally by include.php / footer.php.
|
||||
// Slides use Splide's native lazy loading (data-splide-lazy + cover), so only
|
||||
// the visible/nearby images are downloaded instead of the whole gallery.
|
||||
// Gallery partial — masonry (home "instalações" and the CrossFit page).
|
||||
// main.js lays the tiles out itself: each photo keeps its own aspect ratio (no
|
||||
// cropping) and drops into the shortest column; every few tiles one spans two
|
||||
// columns, which is what staggers the heights — the photos are all landscape,
|
||||
// so equal-width tiles alone would just form a grid. Without JS the list falls
|
||||
// back to a plain CSS grid. Clicking a tile opens it full size in a <dialog>
|
||||
// lightbox with prev / next, arrow keys, Esc and swipe (main.js).
|
||||
$files = glob(rtrim($gallery_path, '/') . '/*.jpg');
|
||||
if (!$files || !is_array($files)) $files = [];
|
||||
// Column span per tile, cycled: w = two columns, s = one.
|
||||
$gal_shapes = ['w', 's', 's', 's', 's', 'w', 's', 's', 's', 's', 's'];
|
||||
$gal_label = $gallery_h2 ?? 'Instalações';
|
||||
?>
|
||||
<div class="row justify-content-md-center" style="margin-top: 58px">
|
||||
<div class="col-lg-8">
|
||||
@@ -14,33 +21,31 @@ if (!$files || !is_array($files)) $files = [];
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="primary-slider" class="splide" style="padding:0;">
|
||||
<div class="splide__track">
|
||||
<ul class="splide__list">
|
||||
<?php foreach($files as $gi => $f): /* distinct alt per photo — identical alts read as one image */ ?>
|
||||
<li class="splide__slide"><img src="<?= base_url($f) ?>" alt="<?= htmlspecialchars(($gallery_h2 ?? 'Instalações') . ' — FitMe 3070, foto ' . ($gi + 1)) ?>"<?= $gi > 0 ? ' loading="lazy"' : '' ?>></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php if ($files): ?>
|
||||
<div class="container">
|
||||
<ul class="gal-masonry">
|
||||
<?php foreach ($files as $gi => $f):
|
||||
$src = base_url($f);
|
||||
$alt = $gal_label . ' — FitMe 3070, foto ' . ($gi + 1); // distinct alt per photo
|
||||
$dim = @getimagesize($f) ?: [0, 0];
|
||||
?>
|
||||
<li class="gal-tile gal-<?= $gal_shapes[$gi % count($gal_shapes)] ?>">
|
||||
<a href="<?= htmlspecialchars($src) ?>" class="gal-link" data-index="<?= $gi ?>" aria-label="Ampliar: <?= htmlspecialchars($alt) ?>">
|
||||
<img src="<?= htmlspecialchars($src) ?>" alt="<?= htmlspecialchars($alt) ?>"
|
||||
<?= $dim[0] ? 'width="' . (int) $dim[0] . '" height="' . (int) $dim[1] . '"' : '' ?>
|
||||
<?= $gi > 1 ? 'loading="lazy"' : '' ?> decoding="async">
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var isMobile = window.innerWidth < 768;
|
||||
// Single auto-playing slider (no thumbnail strip). Real <img src> + cover
|
||||
// paints the first big image on mount; autoplay cross-fades through the
|
||||
// rest and rewinds at the end. Pauses on hover/focus for accessibility.
|
||||
new Splide('#primary-slider', {
|
||||
type: 'fade',
|
||||
rewind: true,
|
||||
heightRatio: isMobile ? 0.7 : 0.5,
|
||||
cover: true,
|
||||
arrows: !isMobile,
|
||||
pagination: true,
|
||||
autoplay: true,
|
||||
interval: 4500,
|
||||
speed: 800,
|
||||
pauseOnHover: true,
|
||||
pauseOnFocus: true
|
||||
}).mount();
|
||||
});
|
||||
</script>
|
||||
<dialog class="gal-lightbox" aria-label="<?= htmlspecialchars($gal_label) ?>">
|
||||
<button type="button" class="gal-lb-close" aria-label="Fechar">×</button>
|
||||
<button type="button" class="gal-lb-nav gal-lb-prev" aria-label="Foto anterior"><i class="fas fa-chevron-left" aria-hidden="true"></i></button>
|
||||
<figure class="gal-lb-figure">
|
||||
<img src="" alt="">
|
||||
<figcaption class="gal-lb-count"></figcaption>
|
||||
</figure>
|
||||
<button type="button" class="gal-lb-nav gal-lb-next" aria-label="Foto seguinte"><i class="fas fa-chevron-right" aria-hidden="true"></i></button>
|
||||
</dialog>
|
||||
<?php endif; ?>
|
||||
@@ -46,9 +46,6 @@ $canonical = $GLOBALS['_canonical_override'] ?? base_url($page !== '' ? 'home/'
|
||||
<!-- Vendor: Font Awesome 5 -->
|
||||
<?= link_tag('site/assets/fonts/fontawesome/css/all.css') ?>
|
||||
|
||||
<!-- Vendor: Splide (gallery slider) — load BEFORE app styles so style.css wins -->
|
||||
<link rel="stylesheet" href="<?= base_url('site/assets/js/splide/dist/css/splide.min.css') ?>">
|
||||
<link rel="stylesheet" href="<?= base_url('site/assets/js/splide/dist/css/themes/splide-sea-green.min.css') ?>">
|
||||
|
||||
<!-- App styles (Bootstrap overrides) -->
|
||||
<?= link_tag('site/assets/css/style.css') ?>
|
||||
|
||||
Reference in new issue
Block a user