Skip to content

Commit 5d9e8ed

Browse files
committed
Add pagination dots to talk carousel
Make it clear at a glance that a meetup has multiple talks, addressing review feedback that the carousel did not signal there were several. Dots are generated in JS (one per talk, shown only when total > 1), sync with the counter and the active slide, and are clickable to jump to a talk.
1 parent 83d1831 commit 5d9e8ed

2 files changed

Lines changed: 76 additions & 9 deletions

File tree

_sass/view.scss

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,40 @@ $vm-pad-x: 4rem;
745745
right: 8px;
746746
}
747747

748+
.carousel__dots {
749+
align-items: center;
750+
display: flex;
751+
flex-wrap: wrap;
752+
gap: 0.5rem;
753+
justify-content: center;
754+
margin-top: 1.125rem;
755+
}
756+
757+
.carousel__dot {
758+
background: rgba($vm-blue, 0.28);
759+
border: 0;
760+
border-radius: 999px;
761+
cursor: pointer;
762+
height: 8px;
763+
padding: 0;
764+
transition: background 0.2s ease, width 0.2s ease;
765+
width: 8px;
766+
767+
&:hover {
768+
background: rgba($vm-blue, 0.55);
769+
}
770+
771+
&.is-active {
772+
background: $vm-blue;
773+
width: 26px;
774+
}
775+
776+
&:focus-visible {
777+
outline: 2px solid $vm-blue;
778+
outline-offset: 2px;
779+
}
780+
}
781+
748782
@media (max-width: 640px) {
749783
.carousel__btn--prev {
750784
left: 4px;

assets/js/meetup_carousel.js

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,38 @@
1818

1919
var total = slides.length;
2020
var current = 0;
21+
var dots = [];
2122

22-
function updateCounter() {
23+
function scrollToIndex(index) {
24+
var target = slides[index];
25+
if (!target) return;
26+
target.scrollIntoView({ inline: 'start', behavior: 'smooth', block: 'nearest' });
27+
}
28+
29+
// Build pagination dots so it is obvious at a glance that there are multiple talks.
30+
if (total > 1) {
31+
var dotsNav = document.createElement('div');
32+
dotsNav.className = 'carousel__dots';
33+
dotsNav.setAttribute('role', 'tablist');
34+
dotsNav.setAttribute('aria-label', 'Charlas de la meetup');
35+
for (var i = 0; i < total; i++) {
36+
(function (index) {
37+
var dot = document.createElement('button');
38+
dot.type = 'button';
39+
dot.className = 'carousel__dot';
40+
dot.setAttribute('role', 'tab');
41+
dot.setAttribute('aria-label', 'Ir a la charla ' + (index + 1) + ' de ' + total);
42+
dot.addEventListener('click', function () {
43+
scrollToIndex(index);
44+
});
45+
dotsNav.appendChild(dot);
46+
dots.push(dot);
47+
})(i);
48+
}
49+
root.appendChild(dotsNav);
50+
}
51+
52+
function updateUI() {
2353
if (counter) {
2454
counter.textContent = pad2(current + 1) + ' / ' + pad2(total);
2555
}
@@ -29,12 +59,15 @@
2959
if (nextBtn) {
3060
nextBtn.disabled = current === total - 1;
3161
}
32-
}
33-
34-
function scrollToIndex(index) {
35-
var target = slides[index];
36-
if (!target) return;
37-
target.scrollIntoView({ inline: 'start', behavior: 'smooth', block: 'nearest' });
62+
dots.forEach(function (dot, index) {
63+
var active = index === current;
64+
dot.classList.toggle('is-active', active);
65+
if (active) {
66+
dot.setAttribute('aria-current', 'true');
67+
} else {
68+
dot.removeAttribute('aria-current');
69+
}
70+
});
3871
}
3972

4073
if (prevBtn) {
@@ -57,7 +90,7 @@
5790
var idx = Array.prototype.indexOf.call(slides, entry.target);
5891
if (idx !== -1 && idx !== current) {
5992
current = idx;
60-
updateCounter();
93+
updateUI();
6194
}
6295
}
6396
});
@@ -69,7 +102,7 @@
69102
});
70103
}
71104

72-
updateCounter();
105+
updateUI();
73106
}
74107

75108
function init() {

0 commit comments

Comments
 (0)