Banner-Slider: Vor-/Zurück-Steuerung
Prev/Next-Navigationsbuttons für den Banner-Slider (carousel.js, generisch über [data-carousel-prev/next]), zugehörige ad-banner-Steuerungs-Styles und Chevron- Icons. Ohne JS bleiben die Controls ausgeblendet (progressive enhancement). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HGzc6GhWhmLJt1jC2q1SRZ
This commit is contained in:
@@ -26,14 +26,7 @@ $total = count($banners);
|
|||||||
?>
|
?>
|
||||||
<section class="section ad-banner" id="anzeigen" aria-roledescription="Karussell" aria-label="Anzeigen unserer Sponsoren und Partner" data-carousel>
|
<section class="section ad-banner" id="anzeigen" aria-roledescription="Karussell" aria-label="Anzeigen unserer Sponsoren und Partner" data-carousel>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<?php if ($heading !== null): ?>
|
|
||||||
<h2><?= e($heading) ?></h2>
|
|
||||||
<?php else: ?>
|
|
||||||
<h2 class="visually-hidden">Anzeigen unserer Sponsoren & Partner</h2>
|
<h2 class="visually-hidden">Anzeigen unserer Sponsoren & Partner</h2>
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($subline !== null): ?>
|
|
||||||
<p class="text-muted ad-banner__subline"><?= e($subline) ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
<ul class="ad-banner__track" id="ad-banner-track" data-carousel-track aria-live="off">
|
<ul class="ad-banner__track" id="ad-banner-track" data-carousel-track aria-live="off">
|
||||||
<?php foreach ($banners as $i => $banner): ?>
|
<?php foreach ($banners as $i => $banner): ?>
|
||||||
<?php
|
<?php
|
||||||
@@ -98,23 +91,34 @@ $total = count($banners);
|
|||||||
</li>
|
</li>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</ul>
|
</ul>
|
||||||
<?php if ($total > 1): ?>
|
<div class="ad-banner__meta">
|
||||||
<?php /* Ohne JS verborgen (Steuerung wäre funktionslos); carousel.js blendet sie ein. */ ?>
|
<?php if ($heading !== null): ?>
|
||||||
<div class="ad-banner__controls" data-carousel-controls hidden>
|
<p class="ad-banner__meta-label"><?= e($heading) ?></p>
|
||||||
<?php /* Explizite Pause/Play-Taste — WCAG 2.2.2. Nur bei aktiver Auto-Rotation sichtbar. */ ?>
|
|
||||||
<button class="ad-banner__toggle" type="button" data-carousel-toggle aria-pressed="false" aria-controls="ad-banner-track" hidden>
|
|
||||||
<?= icon('pause-fill', 'ad-banner__toggle-icon ad-banner__toggle-icon--pause') ?>
|
|
||||||
<?= icon('play-fill', 'ad-banner__toggle-icon ad-banner__toggle-icon--play') ?>
|
|
||||||
<span class="visually-hidden" data-carousel-toggle-label>Automatischen Wechsel pausieren</span>
|
|
||||||
</button>
|
|
||||||
<div class="ad-banner__indicators" role="group" aria-label="Anzeige wählen">
|
|
||||||
<?php foreach ($banners as $i => $banner): ?>
|
|
||||||
<button class="ad-banner__dot" type="button" data-carousel-dot aria-controls="ad-banner-track" aria-label="Anzeige <?= ($i + 1) ?> von <?= $total ?>: <?= e($banner['company'] ?? $banner['title']) ?>">
|
|
||||||
<span class="ad-banner__progress" data-carousel-progress aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<?php if ($total > 1): ?>
|
||||||
|
<?php /* Ohne JS verborgen (Steuerung wäre funktionslos); carousel.js blendet sie ein. */ ?>
|
||||||
|
<div class="ad-banner__controls" data-carousel-controls hidden>
|
||||||
|
<button class="ad-banner__nav-btn" type="button" data-carousel-prev aria-label="Vorherige Anzeige">
|
||||||
|
<?= icon('chevron-left') ?>
|
||||||
|
</button>
|
||||||
|
<div class="ad-banner__indicators" role="group" aria-label="Anzeige wählen">
|
||||||
|
<?php foreach ($banners as $i => $banner): ?>
|
||||||
|
<button class="ad-banner__dot" type="button" data-carousel-dot aria-controls="ad-banner-track" aria-label="Anzeige <?= ($i + 1) ?> von <?= $total ?>: <?= e($banner['company'] ?? $banner['title']) ?>">
|
||||||
|
<span class="ad-banner__progress" data-carousel-progress aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<button class="ad-banner__nav-btn" type="button" data-carousel-next aria-label="Nächste Anzeige">
|
||||||
|
<?= icon('chevron-right') ?>
|
||||||
|
</button>
|
||||||
|
<?php /* Pause/Play — WCAG 2.2.2. Nur bei aktiver Auto-Rotation sichtbar. */ ?>
|
||||||
|
<button class="ad-banner__toggle" type="button" data-carousel-toggle aria-pressed="false" aria-controls="ad-banner-track" hidden>
|
||||||
|
<?= icon('pause-fill', 'ad-banner__toggle-icon ad-banner__toggle-icon--pause') ?>
|
||||||
|
<?= icon('play-fill', 'ad-banner__toggle-icon ad-banner__toggle-icon--play') ?>
|
||||||
|
<span class="visually-hidden" data-carousel-toggle-label>Automatischen Wechsel pausieren</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"heading": "Werbepartner werden",
|
"heading": "Präsentieren Sie sich als Werbepartner des TSV 08 Kulmbach.",
|
||||||
"subline": "Präsentieren Sie Ihr Unternehmen auf der Startseite des TSV 08 Kulmbach – sichtbar für die ganze Region.",
|
"subline": "Präsentieren Sie Ihr Unternehmen auf der Startseite des TSV 08 Kulmbach – sichtbar für die ganze Region.",
|
||||||
"banners": [
|
"banners": [
|
||||||
{
|
{
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"text": "Werden Sie Werbepartner des TSV 08 Kulmbach und zeigen Sie Ihr Unternehmen genau hier – sichtbar für tausende sportbegeisterte Menschen aus Kulmbach und dem Katzbachtal.",
|
"text": "Werden Sie Werbepartner des TSV 08 Kulmbach und zeigen Sie Ihr Unternehmen genau hier – sichtbar für tausende sportbegeisterte Menschen aus Kulmbach und dem Katzbachtal.",
|
||||||
"logo": "img/logo.svg",
|
"logo": "img/logo.svg",
|
||||||
"background": "img/pages/fussball-hero-1600.jpg",
|
"background": "img/pages/fussball-hero-1600.jpg",
|
||||||
"cta": { "label": "Werbepartner werden", "url": "#kontakt", "internal": true }
|
"cta": { "label": "Werbepartner werden", "url": "/partner-werden", "internal": true }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "Breadcrumb Solutions GmbH",
|
"company": "Breadcrumb Solutions GmbH",
|
||||||
|
|||||||
@@ -1369,25 +1369,28 @@
|
|||||||
--banner-interval: 6s;
|
--banner-interval: 6s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sektions-Kopf zentriert (einheitlich mit partners/persons/…) */
|
|
||||||
.ad-banner > .container > h2,
|
|
||||||
.ad-banner__subline {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ad-banner__subline {
|
|
||||||
margin-top: 0.75rem;
|
|
||||||
/* Volle Breite, damit der Dank in einer Zeile steht; auf Mobil bricht er natürlich um. */
|
|
||||||
max-width: none;
|
|
||||||
text-wrap: balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ad-banner__track {
|
.ad-banner__track {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 2rem 0 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Meta-Zeile unter dem Slider: Label links, Controls rechts */
|
||||||
|
.ad-banner__meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
min-height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ad-banner__meta-label {
|
||||||
|
font-size: var(--fs-400);
|
||||||
|
color: var(--clr-text-muted);
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
.ad-banner__slide[hidden] {
|
.ad-banner__slide[hidden] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -1613,13 +1616,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Steuerung: Pause/Play-Taste + Indikatorleiste. */
|
/* Steuerung: Pause/Play-Taste + Indikatorleiste — sitzt rechts in .ad-banner__meta. */
|
||||||
.ad-banner__controls {
|
.ad-banner__controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
gap: 0.75rem;
|
||||||
gap: 1rem;
|
flex-shrink: 0;
|
||||||
margin-top: 1.75rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ad-banner__controls[hidden] {
|
.ad-banner__controls[hidden] {
|
||||||
@@ -1644,6 +1646,30 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ad-banner__nav-btn {
|
||||||
|
display: inline-grid;
|
||||||
|
place-items: center;
|
||||||
|
width: 2.25rem;
|
||||||
|
height: 2.25rem;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--clr-text);
|
||||||
|
background: var(--clr-glass-bg);
|
||||||
|
border: 1px solid var(--clr-glass-border);
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ad-banner__nav-btn:hover {
|
||||||
|
background: rgb(255 255 255 / 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ad-banner__nav-btn:focus-visible {
|
||||||
|
outline: 2px solid var(--clr-text);
|
||||||
|
outline-offset: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.ad-banner__toggle:hover {
|
.ad-banner__toggle:hover {
|
||||||
background: rgb(255 255 255 / 0.2);
|
background: rgb(255 255 255 / 0.2);
|
||||||
}
|
}
|
||||||
@@ -1654,7 +1680,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ad-banner__toggle-icon {
|
.ad-banner__toggle-icon {
|
||||||
font-size: 1.15rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pause-Icon im Abspiel-Zustand, Play-Icon wenn pausiert. */
|
/* Pause-Icon im Abspiel-Zustand, Play-Icon wenn pausiert. */
|
||||||
|
|||||||
1
public/assets/icons/chevron-left.svg
Normal file
1
public/assets/icons/chevron-left.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0"/></svg>
|
||||||
|
After Width: | Height: | Size: 215 B |
1
public/assets/icons/chevron-right.svg
Normal file
1
public/assets/icons/chevron-right.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708"/></svg>
|
||||||
|
After Width: | Height: | Size: 216 B |
@@ -29,6 +29,8 @@
|
|||||||
var controls = root.querySelector('[data-carousel-controls]');
|
var controls = root.querySelector('[data-carousel-controls]');
|
||||||
var toggle = root.querySelector('[data-carousel-toggle]');
|
var toggle = root.querySelector('[data-carousel-toggle]');
|
||||||
var toggleLabel = root.querySelector('[data-carousel-toggle-label]');
|
var toggleLabel = root.querySelector('[data-carousel-toggle-label]');
|
||||||
|
var prevBtn = root.querySelector('[data-carousel-prev]');
|
||||||
|
var nextBtn = root.querySelector('[data-carousel-next]');
|
||||||
if (slides.length <= 1) {
|
if (slides.length <= 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -96,6 +98,13 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (prevBtn) {
|
||||||
|
prevBtn.addEventListener('click', function () { activate(index - 1); });
|
||||||
|
}
|
||||||
|
if (nextBtn) {
|
||||||
|
nextBtn.addEventListener('click', function () { activate(index + 1); });
|
||||||
|
}
|
||||||
|
|
||||||
// Steuerung einblenden (ohne JS bleibt sie verborgen, da funktionslos).
|
// Steuerung einblenden (ohne JS bleibt sie verborgen, da funktionslos).
|
||||||
if (controls) {
|
if (controls) {
|
||||||
controls.hidden = false;
|
controls.hidden = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user