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
+377
-34
No files matched your search
@@ -4095,3 +4095,204 @@ h3.contact-title {
|
|||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.mi, .mi [pathLength] { animation: none !important; }
|
.mi, .mi [pathLength] { animation: none !important; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ══════════════════════════════════════════════════════════════════════════
|
||||||
|
Galeria — masonry + lightbox (site/includes/gallery.php)
|
||||||
|
Without JS: a plain CSS grid (photos cropped to equal tiles). With JS
|
||||||
|
(.is-masonry): main.js positions every tile absolutely — shortest column
|
||||||
|
first, true aspect ratio, some tiles two columns wide — and sets the list's
|
||||||
|
height. 4 columns on desktop, 3 on tablets, 2 on phones.
|
||||||
|
══════════════════════════════════════════════════════════════════════════ */
|
||||||
|
.gal-masonry {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0 0 70px;
|
||||||
|
padding: 0;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
grid-auto-rows: 170px;
|
||||||
|
grid-auto-flow: dense;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-tile { position: relative; margin: 0; }
|
||||||
|
.gal-w { grid-column: span 2; }
|
||||||
|
|
||||||
|
/* JS masonry: absolute tiles, sized and placed by main.js. */
|
||||||
|
.gal-masonry.is-masonry {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-masonry.is-masonry .gal-tile {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
transition: transform .5s cubic-bezier(.2, .8, .2, 1), width .5s cubic-bezier(.2, .8, .2, 1), height .5s cubic-bezier(.2, .8, .2, 1), opacity .6s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Entrance: tiles rise in one after another when the gallery comes into view
|
||||||
|
(main.js adds .is-in with a per-tile delay). */
|
||||||
|
.gal-masonry.is-masonry .gal-tile:not(.is-in) {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-masonry.is-masonry .gal-tile .gal-link {
|
||||||
|
transition: transform .6s cubic-bezier(.2, .8, .2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-masonry.is-masonry .gal-tile:not(.is-in) .gal-link {
|
||||||
|
transform: translateY(24px) scale(.97);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-link {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 6px;
|
||||||
|
position: relative;
|
||||||
|
background: var(--fitme-surface-2);
|
||||||
|
cursor: zoom-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-link img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
display: block;
|
||||||
|
transition: transform .6s cubic-bezier(.2, .8, .2, 1), filter .4s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accent frame + slow zoom on hover / focus. */
|
||||||
|
.gal-link::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
box-shadow: inset 0 0 0 0 var(--fitme-accent);
|
||||||
|
transition: box-shadow .3s ease;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-link:hover img,
|
||||||
|
.gal-link:focus-visible img {
|
||||||
|
transform: scale(1.06);
|
||||||
|
filter: brightness(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-link:hover::after,
|
||||||
|
.gal-link:focus-visible::after {
|
||||||
|
box-shadow: inset 0 0 0 3px var(--fitme-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991px) {
|
||||||
|
.gal-masonry { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: 150px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
.gal-masonry { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 120px; gap: 8px; margin-bottom: 48px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lightbox */
|
||||||
|
.gal-lightbox {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
max-width: none;
|
||||||
|
max-height: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-lightbox[open] {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-lightbox::backdrop {
|
||||||
|
background: rgba(11, 11, 13, .92);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-lb-figure {
|
||||||
|
margin: 0;
|
||||||
|
max-width: calc(100vw - 140px);
|
||||||
|
max-height: calc(100vh - 80px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-lb-figure img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: calc(100vh - 110px);
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 20px 60px rgba(0, 0, 0, .5);
|
||||||
|
animation: gal-in .35s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes gal-in {
|
||||||
|
from { opacity: 0; transform: scale(.97); }
|
||||||
|
to { opacity: 1; transform: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-lb-count {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: .85rem;
|
||||||
|
color: var(--fitme-ash);
|
||||||
|
letter-spacing: .08em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-lb-close,
|
||||||
|
.gal-lb-nav {
|
||||||
|
position: absolute;
|
||||||
|
border: 0;
|
||||||
|
background: rgba(255, 255, 255, .08);
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background var(--fitme-transition), color var(--fitme-transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-lb-close:hover,
|
||||||
|
.gal-lb-nav:hover {
|
||||||
|
background: var(--fitme-accent);
|
||||||
|
color: var(--fitme-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-lb-close {
|
||||||
|
top: 16px;
|
||||||
|
right: 16px;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 50%;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-lb-nav {
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gal-lb-prev { left: 20px; }
|
||||||
|
.gal-lb-next { right: 20px; }
|
||||||
|
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
.gal-lb-figure { max-width: calc(100vw - 24px); }
|
||||||
|
.gal-lb-nav { top: auto; bottom: 18px; transform: none; }
|
||||||
|
.gal-lb-prev { left: calc(50% - 60px); }
|
||||||
|
.gal-lb-next { right: calc(50% - 60px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.gal-link img, .gal-lb-figure img { transition: none; animation: none; }
|
||||||
|
.gal-masonry.is-masonry .gal-tile,
|
||||||
|
.gal-masonry.is-masonry .gal-tile .gal-link { transition: none; }
|
||||||
|
}
|
||||||
@@ -695,3 +695,144 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
btn.addEventListener('click', function () { select.value = btn.getAttribute('data-membership'); });
|
btn.addEventListener('click', function () { select.value = btn.getAttribute('data-membership'); });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* ── Galeria: lightbox ───────────────────────────────────────────────────────
|
||||||
|
Tiles are plain links to the full image (works without JS). With JS a click
|
||||||
|
opens the <dialog> instead: prev / next buttons, ← → keys, Esc, swipe on
|
||||||
|
touch, and a click on the dark backdrop closes it. */
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
document.querySelectorAll('.gal-masonry').forEach(function (grid) {
|
||||||
|
var box = grid.parentElement.nextElementSibling;
|
||||||
|
if (!box || !box.classList.contains('gal-lightbox') || typeof box.showModal !== 'function') return;
|
||||||
|
var links = Array.prototype.slice.call(grid.querySelectorAll('.gal-link'));
|
||||||
|
var img = box.querySelector('.gal-lb-figure img');
|
||||||
|
var count = box.querySelector('.gal-lb-count');
|
||||||
|
var current = 0;
|
||||||
|
|
||||||
|
function show(i) {
|
||||||
|
current = (i + links.length) % links.length;
|
||||||
|
var src = links[current].querySelector('img');
|
||||||
|
img.src = links[current].getAttribute('href');
|
||||||
|
img.alt = src ? src.alt : '';
|
||||||
|
// Restart the fade-in for each photo.
|
||||||
|
img.style.animation = 'none'; void img.offsetWidth; img.style.animation = '';
|
||||||
|
count.textContent = (current + 1) + ' / ' + links.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
links.forEach(function (a, i) {
|
||||||
|
a.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
show(i);
|
||||||
|
box.showModal();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
box.querySelector('.gal-lb-prev').addEventListener('click', function () { show(current - 1); });
|
||||||
|
box.querySelector('.gal-lb-next').addEventListener('click', function () { show(current + 1); });
|
||||||
|
box.querySelector('.gal-lb-close').addEventListener('click', function () { box.close(); });
|
||||||
|
// Clicks that land on the dialog itself (not the photo or a button) are the backdrop.
|
||||||
|
box.addEventListener('click', function (e) { if (e.target === box) box.close(); });
|
||||||
|
box.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'ArrowLeft') show(current - 1);
|
||||||
|
else if (e.key === 'ArrowRight') show(current + 1);
|
||||||
|
});
|
||||||
|
box.addEventListener('close', function () { links[current].focus(); });
|
||||||
|
|
||||||
|
var x0 = null;
|
||||||
|
box.addEventListener('touchstart', function (e) { x0 = e.touches[0].clientX; }, { passive: true });
|
||||||
|
box.addEventListener('touchend', function (e) {
|
||||||
|
if (x0 === null) return;
|
||||||
|
var dx = e.changedTouches[0].clientX - x0;
|
||||||
|
if (Math.abs(dx) > 40) show(current + (dx < 0 ? 1 : -1));
|
||||||
|
x0 = null;
|
||||||
|
}, { passive: true });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ── Galeria: masonry layout ─────────────────────────────────────────────────
|
||||||
|
A small hand-rolled masonry (no library): the grid is split into columns
|
||||||
|
(4 / 3 / 2 by width), and each tile — at its photo's true aspect ratio, from
|
||||||
|
the width/height attributes the PHP writes — is dropped into the shortest
|
||||||
|
column; tiles marked .gal-w take two adjacent columns (the pair whose taller
|
||||||
|
one is lowest), which is what staggers the rows. Tiles are absolutely
|
||||||
|
positioned with transforms, so a relayout on resize glides into place.
|
||||||
|
The first time the gallery scrolls into view the tiles rise in one by one. */
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
document.querySelectorAll('.gal-masonry').forEach(function (grid) {
|
||||||
|
var tiles = Array.prototype.slice.call(grid.querySelectorAll('.gal-tile'));
|
||||||
|
if (!tiles.length) return;
|
||||||
|
grid.classList.add('is-masonry');
|
||||||
|
|
||||||
|
function ratio(tile) {
|
||||||
|
var img = tile.querySelector('img');
|
||||||
|
var w = +img.getAttribute('width') || img.naturalWidth || 4;
|
||||||
|
var h = +img.getAttribute('height') || img.naturalHeight || 3;
|
||||||
|
return h / w;
|
||||||
|
}
|
||||||
|
function layout() {
|
||||||
|
var width = grid.clientWidth;
|
||||||
|
var cols = width >= 900 ? 4 : width >= 520 ? 3 : 2;
|
||||||
|
var gap = width >= 520 ? 12 : 8;
|
||||||
|
var colW = (width - gap * (cols - 1)) / cols;
|
||||||
|
var heights = [];
|
||||||
|
for (var c = 0; c < cols; c++) heights.push(0);
|
||||||
|
|
||||||
|
tiles.forEach(function (tile) {
|
||||||
|
var span = (tile.classList.contains('gal-w') && cols > 1) ? 2 : 1;
|
||||||
|
// Best column (or pair of columns) = lowest top edge.
|
||||||
|
var pick = function (span) {
|
||||||
|
var best = 0, bestTop = Infinity, waste = 0;
|
||||||
|
for (var i = 0; i <= cols - span; i++) {
|
||||||
|
var cells = heights.slice(i, i + span);
|
||||||
|
var top = Math.max.apply(null, cells);
|
||||||
|
if (top < bestTop - 0.5) { bestTop = top; best = i; waste = top - Math.min.apply(null, cells); }
|
||||||
|
}
|
||||||
|
return [best, bestTop, waste];
|
||||||
|
};
|
||||||
|
var p = pick(span);
|
||||||
|
// A wide tile whose two columns end at different heights would
|
||||||
|
// leave a hole under the shorter one — use a single column then.
|
||||||
|
if (span === 2 && p[2] > 60) { span = 1; p = pick(1); }
|
||||||
|
var best = p[0], bestTop = p[1];
|
||||||
|
var w = colW * span + gap * (span - 1);
|
||||||
|
var h = Math.round(w * ratio(tile));
|
||||||
|
tile.style.width = w + 'px';
|
||||||
|
tile.style.height = h + 'px';
|
||||||
|
tile.style.transform = 'translate(' + (best * (colW + gap)) + 'px,' + bestTop + 'px)';
|
||||||
|
for (var j = best; j < best + span; j++) heights[j] = bestTop + h + gap;
|
||||||
|
});
|
||||||
|
grid.style.height = Math.max(0, Math.max.apply(null, heights) - gap) + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
layout();
|
||||||
|
// Re-lay out whenever the grid's own width changes (window resize, but
|
||||||
|
// also a gallery that was laid out while hidden / zero-width).
|
||||||
|
var t, lastW = grid.clientWidth;
|
||||||
|
var relayout = function () {
|
||||||
|
if (grid.clientWidth === lastW) return;
|
||||||
|
lastW = grid.clientWidth;
|
||||||
|
clearTimeout(t); t = setTimeout(layout, 80);
|
||||||
|
};
|
||||||
|
if ('ResizeObserver' in window) new ResizeObserver(relayout).observe(grid);
|
||||||
|
window.addEventListener('resize', relayout, { passive: true }); // belt and braces; relayout() is idempotent
|
||||||
|
// Re-run once images report their size, in case an attribute was missing.
|
||||||
|
tiles.forEach(function (tile) {
|
||||||
|
var img = tile.querySelector('img');
|
||||||
|
if (!img.getAttribute('width')) img.addEventListener('load', layout, { once: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Staggered entrance.
|
||||||
|
var enter = function () {
|
||||||
|
tiles.forEach(function (tile, i) {
|
||||||
|
setTimeout(function () { tile.classList.add('is-in'); }, Math.min(i, 12) * 70);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if ('IntersectionObserver' in window) {
|
||||||
|
var io = new IntersectionObserver(function (entries) {
|
||||||
|
if (entries.some(function (e) { return e.isIntersecting; })) { enter(); io.disconnect(); }
|
||||||
|
}, { rootMargin: '0px 0px -80px 0px' });
|
||||||
|
io.observe(grid);
|
||||||
|
} else {
|
||||||
|
enter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -36,7 +36,6 @@
|
|||||||
<!-- Scripts: jQuery first (Bootstrap navbar/alerts depend on it), then plugins -->
|
<!-- Scripts: jQuery first (Bootstrap navbar/alerts depend on it), then plugins -->
|
||||||
<?= script_tag('site/assets/js/jquery-3.7.1.min.js') ?>
|
<?= script_tag('site/assets/js/jquery-3.7.1.min.js') ?>
|
||||||
<?= script_tag('assets/vendor/bootstrap/js/bootstrap.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') ?>
|
<?= script_tag('site/assets/js/main.js') ?>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+35
-30
@@ -1,9 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
// Gallery partial — Splide CSS/JS is loaded centrally by include.php / footer.php.
|
// Gallery partial — masonry (home "instalações" and the CrossFit page).
|
||||||
// Slides use Splide's native lazy loading (data-splide-lazy + cover), so only
|
// main.js lays the tiles out itself: each photo keeps its own aspect ratio (no
|
||||||
// the visible/nearby images are downloaded instead of the whole gallery.
|
// 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');
|
$files = glob(rtrim($gallery_path, '/') . '/*.jpg');
|
||||||
if (!$files || !is_array($files)) $files = [];
|
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="row justify-content-md-center" style="margin-top: 58px">
|
||||||
<div class="col-lg-8">
|
<div class="col-lg-8">
|
||||||
@@ -14,33 +21,31 @@ if (!$files || !is_array($files)) $files = [];
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="primary-slider" class="splide" style="padding:0;">
|
<?php if ($files): ?>
|
||||||
<div class="splide__track">
|
<div class="container">
|
||||||
<ul class="splide__list">
|
<ul class="gal-masonry">
|
||||||
<?php foreach($files as $gi => $f): /* distinct alt per photo — identical alts read as one image */ ?>
|
<?php foreach ($files as $gi => $f):
|
||||||
<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>
|
$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; ?>
|
<?php endforeach; ?>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<dialog class="gal-lightbox" aria-label="<?= htmlspecialchars($gal_label) ?>">
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
<button type="button" class="gal-lb-close" aria-label="Fechar">×</button>
|
||||||
var isMobile = window.innerWidth < 768;
|
<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>
|
||||||
// Single auto-playing slider (no thumbnail strip). Real <img src> + cover
|
<figure class="gal-lb-figure">
|
||||||
// paints the first big image on mount; autoplay cross-fades through the
|
<img src="" alt="">
|
||||||
// rest and rewinds at the end. Pauses on hover/focus for accessibility.
|
<figcaption class="gal-lb-count"></figcaption>
|
||||||
new Splide('#primary-slider', {
|
</figure>
|
||||||
type: 'fade',
|
<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>
|
||||||
rewind: true,
|
</dialog>
|
||||||
heightRatio: isMobile ? 0.7 : 0.5,
|
<?php endif; ?>
|
||||||
cover: true,
|
|
||||||
arrows: !isMobile,
|
|
||||||
pagination: true,
|
|
||||||
autoplay: true,
|
|
||||||
interval: 4500,
|
|
||||||
speed: 800,
|
|
||||||
pauseOnHover: true,
|
|
||||||
pauseOnFocus: true
|
|
||||||
}).mount();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -46,9 +46,6 @@ $canonical = $GLOBALS['_canonical_override'] ?? base_url($page !== '' ? 'home/'
|
|||||||
<!-- Vendor: Font Awesome 5 -->
|
<!-- Vendor: Font Awesome 5 -->
|
||||||
<?= link_tag('site/assets/fonts/fontawesome/css/all.css') ?>
|
<?= 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) -->
|
<!-- App styles (Bootstrap overrides) -->
|
||||||
<?= link_tag('site/assets/css/style.css') ?>
|
<?= link_tag('site/assets/css/style.css') ?>
|
||||||
|
|||||||
Reference in new issue
Block a user