diff --git a/css/pages/_news.css b/css/pages/_news.css
index da7c7990..c3a60baf 100644
--- a/css/pages/_news.css
+++ b/css/pages/_news.css
@@ -94,6 +94,15 @@
.newshub-card h3 a:hover { color: #2D738C; }
.newshub-excerpt { margin: 0; font-size: 14px; line-height: 22px; color: #667085; }
+/* Pagination reuses the shared .pagination look; reset button chrome */
+.newshub-pagination { margin-top: 44px; }
+.newshub-pagination .pagination-arrow,
+.newshub-pagination .page-number {
+ background: transparent;
+ border: none;
+ font-family: inherit;
+}
+
@media (max-width: 768px) {
.newshub-hero { padding: 92px 20px 32px; }
.newshub-hero h1 { font-size: 30px; }
diff --git a/en/index.html b/en/index.html
index a3a04316..59cf7f3f 100644
--- a/en/index.html
+++ b/en/index.html
@@ -258,7 +258,7 @@
-
+
diff --git a/mk/index.html b/mk/index.html
index 0302a72d..c4c598d3 100644
--- a/mk/index.html
+++ b/mk/index.html
@@ -261,7 +261,7 @@
-
+
diff --git a/news-filter.js b/news-filter.js
index 6493eab4..78a51501 100644
--- a/news-filter.js
+++ b/news-filter.js
@@ -1,19 +1,90 @@
-/* News hub type filter: chips toggle which cards are shown. No dependencies. */
+/* News hub: type filter + client-side pagination (they work together). */
(function () {
var list = document.querySelector('.newshub-list');
if (!list) return;
- var chips = list.querySelectorAll('.newshub-chip');
- var cards = list.querySelectorAll('.newshub-card');
- function apply(type) {
- cards.forEach(function (card) {
- card.hidden = !(type === 'all' || card.getAttribute('data-type') === type);
+ var chips = [].slice.call(list.querySelectorAll('.newshub-chip'));
+ var cards = [].slice.call(list.querySelectorAll('.newshub-card'));
+ var pager = list.querySelector('.newshub-pagination');
+ var numbers = pager ? pager.querySelector('.pagination-numbers') : null;
+ var prevBtn = pager ? pager.querySelector('[data-nav="prev"]') : null;
+ var nextBtn = pager ? pager.querySelector('[data-nav="next"]') : null;
+ var pageSize = pager ? (parseInt(pager.getAttribute('data-page-size'), 10) || 9) : 9;
+
+ var state = { type: 'all', page: 1 };
+
+ function matching() {
+ return cards.filter(function (c) {
+ return state.type === 'all' || c.getAttribute('data-type') === state.type;
});
}
+
+ // Build the compact list of page tokens: numbers and 'dots'.
+ function tokens(total, cur) {
+ if (total <= 7) {
+ var all = [];
+ for (var i = 1; i <= total; i++) all.push(i);
+ return all;
+ }
+ var set = { 1: 1, 2: 1 };
+ set[total] = 1; set[total - 1] = 1;
+ set[cur] = 1; set[cur - 1] = 1; set[cur + 1] = 1;
+ var pages = Object.keys(set).map(Number).filter(function (n) { return n >= 1 && n <= total; }).sort(function (a, b) { return a - b; });
+ var out = [];
+ for (var j = 0; j < pages.length; j++) {
+ if (j > 0 && pages[j] - pages[j - 1] > 1) out.push('dots');
+ out.push(pages[j]);
+ }
+ return out;
+ }
+
+ function buildPager(total) {
+ if (!pager) return;
+ if (total <= 1) { pager.hidden = true; return; }
+ pager.hidden = false;
+ numbers.innerHTML = '';
+ tokens(total, state.page).forEach(function (t) {
+ if (t === 'dots') {
+ var s = document.createElement('span');
+ s.className = 'page-dots';
+ s.textContent = '...';
+ numbers.appendChild(s);
+ return;
+ }
+ var b = document.createElement('button');
+ b.type = 'button';
+ b.className = 'page-number' + (t === state.page ? ' active' : '');
+ b.textContent = t;
+ b.addEventListener('click', function () { state.page = t; render(true); });
+ numbers.appendChild(b);
+ });
+ prevBtn.classList.toggle('disabled', state.page <= 1);
+ nextBtn.classList.toggle('disabled', state.page >= total);
+ }
+
+ function render(scroll) {
+ var m = matching();
+ var total = Math.max(1, Math.ceil(m.length / pageSize));
+ if (state.page > total) state.page = total;
+ if (state.page < 1) state.page = 1;
+ var start = (state.page - 1) * pageSize;
+ var end = start + pageSize;
+ cards.forEach(function (c) { c.hidden = true; });
+ m.slice(start, end).forEach(function (c) { c.hidden = false; });
+ buildPager(total);
+ if (scroll) list.scrollIntoView({ behavior: 'smooth', block: 'start' });
+ }
+
chips.forEach(function (chip) {
chip.addEventListener('click', function () {
chips.forEach(function (c) { c.classList.remove('is-active'); });
chip.classList.add('is-active');
- apply(chip.getAttribute('data-type'));
+ state.type = chip.getAttribute('data-type');
+ state.page = 1;
+ render(false);
});
});
+ if (prevBtn) prevBtn.addEventListener('click', function () { if (state.page > 1) { state.page--; render(true); } });
+ if (nextBtn) nextBtn.addEventListener('click', function () { state.page++; render(true); });
+
+ render(false);
})();
diff --git a/si/index.html b/si/index.html
index 0883d783..46d9d5e1 100644
--- a/si/index.html
+++ b/si/index.html
@@ -261,7 +261,7 @@
-