Pagination fixes, blog page chooser, Events & Projects redesign

Pagination
- Fix the broken mobile layout on News & Projects: page numbers on top,
  Previous / Next side-by-side below (shared .pagination component)
- Add a page chooser to the Blog: rewrite blog-filter.js to combine the
  topic filter with client-side pagination (page size 6), add the pager
  markup (all 3 languages) and .blog-pagination styles; it auto-hides
  when a topic has one page

Events & Projects — match the Blog/News design
- Hero: uppercase letter-spaced eyebrow, sentence-case bold title, lead
  subtitle, soft gradient; drop the redundant hero subscribe form and the
  placeholder copy (signup still available in the bottom newsletter CTA);
  align MK/SI titles to "Events & projects"
- Filters: News-style pills (dark active), left-aligned, with the thin
  separator line below; .filter-inner wrapper aligns pills/separator with
  the grid
- Spacing: reduce the gap under the header, add space below the filter so
  the separator / Events sub-filter no longer collide with "All our
  projects" (these hero/spacing tweaks also tidy the shared About/Get-to-know/
  Timeline heroes)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
popovskik 2026-08-01 20:30:47 +02:00
parent 9e8cbc5876
commit e1d596751a
9 changed files with 213 additions and 126 deletions

View File

@ -1,22 +1,91 @@
/* Blog topic filter: chips toggle which cards are shown. No dependencies. */ /* Blog: topic filter + client-side pagination (they work together).
Chips toggle the visible topic; the pager pages through the matches. */
(function () { (function () {
var list = document.querySelector('.blog-list'); var list = document.querySelector('.blog-list');
if (!list) return; if (!list) return;
var chips = list.querySelectorAll('.blog-chip'); var chips = [].slice.call(list.querySelectorAll('.blog-chip'));
var cards = list.querySelectorAll('.blog-card'); var cards = [].slice.call(list.querySelectorAll('.blog-card'));
var pager = list.querySelector('.blog-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) || 6) : 6;
function apply(topic) { var state = { topic: 'all', page: 1 };
cards.forEach(function (card) {
var show = topic === 'all' || card.getAttribute('data-topic') === topic; function matching() {
card.hidden = !show; return cards.filter(function (c) {
return state.topic === 'all' || c.getAttribute('data-topic') === state.topic;
}); });
} }
// 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) { chips.forEach(function (chip) {
chip.addEventListener('click', function () { chip.addEventListener('click', function () {
chips.forEach(function (c) { c.classList.remove('is-active'); }); chips.forEach(function (c) { c.classList.remove('is-active'); });
chip.classList.add('is-active'); chip.classList.add('is-active');
apply(chip.getAttribute('data-topic')); state.topic = chip.getAttribute('data-topic');
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);
})(); })();

View File

@ -176,3 +176,13 @@
.blog-hero h1 { font-size: 30px; } .blog-hero h1 { font-size: 30px; }
.blog-grid { columns: 1; } .blog-grid { columns: 1; }
} }
/* Pagination reuses the shared .pagination look; reset button chrome.
Topic filter + client-side paging are handled by blog-filter.js. */
.blog-pagination { margin-top: 40px; }
.blog-pagination .pagination-arrow,
.blog-pagination .page-number {
background: transparent;
border: none;
font-family: inherit;
}

View File

@ -19,8 +19,10 @@
} }
.page-header-section { .page-header-section {
padding: 96px 0; background: linear-gradient(180deg, #FFF7F2 0%, #FFFFFF 100%);
background: #FFFFFF; /* .page-content already offsets the fixed 80px header, so this top value
is the actual visible gap under the menu keep it small. */
padding: 40px 24px 44px;
text-align: center; text-align: center;
} }
@ -28,30 +30,34 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 24px; gap: 14px;
max-width: 960px; max-width: 760px;
} }
/* Eyebrow — uppercase, letter-spaced, like the News/Blog hero */
.page-subtitle { .page-subtitle {
font-weight: 600; display: inline-block;
font-size: 16px; font-weight: 700;
color: #FA7850; font-size: 14px;
letter-spacing: 0.06em;
text-transform: uppercase;
color: #E8833A;
} }
.page-header-section h1 { .page-header-section h1 {
font-weight: 600; font-weight: 700;
font-size: 48px; font-size: 42px;
line-height: 60px; line-height: 1.12;
letter-spacing: -0.02em;
color: #101828; color: #101828;
margin: 0; margin: 0;
max-width: 760px;
} }
.page-description { .page-description {
font-size: 20px; font-size: 18px;
line-height: 30px; line-height: 28px;
color: #667085; color: #475467;
max-width: 768px; max-width: 640px;
margin: 0; margin: 0;
} }
@ -107,67 +113,60 @@
/* 1b. Filter kategorij (pill navigacija + podfiltri) */ /* 1b. Filter kategorij (pill navigacija + podfiltri) */
/* Filter bar left-aligned pills with a thin separator, like the News hub.
.filter-inner mirrors the posts container so the pills/separator line up
with the grid below. */
.filter-section { .filter-section {
padding: 0 24px 44px; padding: 8px 80px 40px; /* bottom gap so the separator/sub-filter clears "All our projects" */
margin-top: -40px; }
.filter-inner {
max-width: 1280px;
margin: 0 auto;
padding: 0 32px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; gap: 16px;
gap: 20px;
} }
/* Zunanja "pill" navigacija (glavne kategorije) */
.filter-nav { .filter-nav {
display: flex; display: flex;
flex-wrap: wrap;
align-items: center; align-items: center;
gap: 4px; gap: 10px;
max-width: 100%; padding-bottom: 24px;
padding: 6px; border-bottom: 1px solid #EAECF0; /* thin, near-transparent separator */
background: #F9FAFB;
border-radius: 999px;
box-shadow: 0px 8px 30px rgba(16, 24, 40, 0.06);
overflow-x: auto;
scrollbar-width: none;
-ms-overflow-style: none;
} }
.filter-nav::-webkit-scrollbar { display: none; }
.filter-pill { .filter-pill {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
height: 40px;
padding: 0 20px;
border: none;
background: transparent;
border-radius: 999px;
font-family: inherit; font-family: inherit;
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
line-height: 1; line-height: 1;
color: #344054; color: #475467;
background: #F2F4F7;
border: 1px solid transparent;
border-radius: 999px;
padding: 9px 16px;
white-space: nowrap; white-space: nowrap;
cursor: pointer; cursor: pointer;
transition: color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease; transition: background 0.15s ease, color 0.15s ease;
} }
.filter-pill:hover { .filter-pill:hover {
color: #2D738C; background: #E4E7EC;
} }
.filter-pill.active { .filter-pill.active {
color: #2D738C; background: #101828;
background: #FFFFFF; color: #FFFFFF;
box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1), 0px 1px 2px rgba(16, 24, 40, 0.06);
} }
/* Notranja vrstica s podfiltri (npr. vrste dogodkov) */ /* Sub-filter row (e.g. event types) — sits under the pills, left aligned */
.filter-subnav { .filter-subnav {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: center; justify-content: flex-start;
gap: 12px; gap: 12px;
} }
.filter-subnav[hidden] { display: none; } .filter-subnav[hidden] { display: none; }
@ -321,12 +320,12 @@
} }
.page-header-section { .page-header-section {
padding: 64px 24px; padding: 32px 20px 28px;
} }
.page-header-section h1 { .page-header-section h1 {
font-size: 32px; font-size: 30px;
line-height: 40px; line-height: 1.15;
} }
.page-description { .page-description {
@ -344,16 +343,16 @@
} }
.filter-section { .filter-section {
padding: 0 16px 28px; padding: 8px 20px 32px;
margin-top: -24px; }
align-items: stretch; .filter-inner {
gap: 16px; padding: 0;
gap: 14px;
} }
/* Na mobilnem se glavna navigacija vodoravno pomika */
.filter-nav { .filter-nav {
justify-content: flex-start; justify-content: flex-start;
border-radius: 12px; padding-bottom: 20px;
} }
.filter-subnav { .filter-subnav {
@ -381,11 +380,14 @@
} }
.pagination { .pagination {
flex-direction: column; flex-wrap: wrap;
gap: 24px; gap: 20px;
} }
/* Numbers on their own row on top; Previous / Next share the row below */
.pagination-numbers { .pagination-numbers {
order: -1; order: -1;
flex-basis: 100%;
justify-content: center;
} }
} }

View File

@ -263,6 +263,11 @@
</div> </div>
</article> </article>
</div> </div>
<nav class="pagination blog-pagination" data-page-size="6" hidden>
<button type="button" class="pagination-arrow" data-nav="prev"><i class="fas fa-arrow-left" aria-hidden="true"></i> Previous</button>
<div class="pagination-numbers"></div>
<button type="button" class="pagination-arrow" data-nav="next">Next <i class="fas fa-arrow-right" aria-hidden="true"></i></button>
</nav>
</section> </section>
</main> </main>

View File

@ -148,31 +148,28 @@
<section class="page-header-section"> <section class="page-header-section">
<div class="container text-center"> <div class="container text-center">
<span class="page-subtitle">Our projects</span> <span class="page-subtitle">Our projects</span>
<h1>Events & Projects</h1> <h1>Events &amp; projects</h1>
<p class="page-description">Subscribe to learn about new product features, the latest in technology, solutions, and updates.</p> <p class="page-description">The events, projects and moments that bring the Macedonian student community in Slovenia together.</p>
<form class="subscribe-form">
<input type="email" placeholder="Enter your email">
<button type="submit" class="btn btn-primary-orange">Subscribe</button>
</form>
<p class="privacy-note">We care about your data in our <a href="../../en/privacy-policy/">privacy policy</a></p>
</div> </div>
</section> </section>
<!-- Category Filter --> <!-- Category Filter -->
<section class="filter-section"> <section class="filter-section">
<nav class="filter-nav" aria-label="Project categories"> <div class="filter-inner">
<button type="button" class="filter-pill active" data-filter="all" aria-pressed="true">All</button> <nav class="filter-nav" aria-label="Project categories">
<button type="button" class="filter-pill" data-filter="events" aria-pressed="false">Events</button> <button type="button" class="filter-pill active" data-filter="all" aria-pressed="true">All</button>
<button type="button" class="filter-pill" data-filter="student-life" aria-pressed="false">Student Life</button> <button type="button" class="filter-pill" data-filter="events" aria-pressed="false">Events</button>
<button type="button" class="filter-pill" data-filter="projects" aria-pressed="false">Projects</button> <button type="button" class="filter-pill" data-filter="student-life" aria-pressed="false">Student life</button>
<button type="button" class="filter-pill" data-filter="webinars" aria-pressed="false">Webinars</button> <button type="button" class="filter-pill" data-filter="projects" aria-pressed="false">Projects</button>
</nav> <button type="button" class="filter-pill" data-filter="webinars" aria-pressed="false">Webinars</button>
<div class="filter-subnav" data-parent="events" hidden> </nav>
<button type="button" class="filter-chip active" data-subfilter="all">All events</button> <div class="filter-subnav" data-parent="events" hidden>
<button type="button" class="filter-chip" data-subfilter="sports">Sports</button> <button type="button" class="filter-chip active" data-subfilter="all">All events</button>
<button type="button" class="filter-chip" data-subfilter="cultural">Cultural</button> <button type="button" class="filter-chip" data-subfilter="sports">Sports</button>
<button type="button" class="filter-chip" data-subfilter="entertainment">Entertainment</button> <button type="button" class="filter-chip" data-subfilter="cultural">Cultural</button>
<button type="button" class="filter-chip" data-subfilter="educational">Educational</button> <button type="button" class="filter-chip" data-subfilter="entertainment">Entertainment</button>
<button type="button" class="filter-chip" data-subfilter="educational">Educational</button>
</div>
</div> </div>
</section> </section>

View File

@ -263,6 +263,11 @@
</div> </div>
</article> </article>
</div> </div>
<nav class="pagination blog-pagination" data-page-size="6" hidden>
<button type="button" class="pagination-arrow" data-nav="prev"><i class="fas fa-arrow-left" aria-hidden="true"></i> Претходна</button>
<div class="pagination-numbers"></div>
<button type="button" class="pagination-arrow" data-nav="next">Следна <i class="fas fa-arrow-right" aria-hidden="true"></i></button>
</nav>
</section> </section>
</main> </main>

View File

@ -148,31 +148,28 @@
<section class="page-header-section"> <section class="page-header-section">
<div class="container text-center"> <div class="container text-center">
<span class="page-subtitle">Наши проекти</span> <span class="page-subtitle">Наши проекти</span>
<h1>Проекти</h1> <h1>Настани и проекти</h1>
<p class="page-description">Претплатете се за да дознаете за новите функции на производите, најновите технологии, решенија и ажурирања.</p> <p class="page-description">Настаните, проектите и моментите што ја зближуваат македонската студентска заедница во Словенија.</p>
<form class="subscribe-form">
<input type="email" placeholder="Внесете ја вашата е-пошта">
<button type="submit" class="btn btn-primary-orange">Претплати се</button>
</form>
<p class="privacy-note">Ние се грижиме за вашите податоци во нашата <a href="../../mk/privacy-policy/">политика за приватност</a></p>
</div> </div>
</section> </section>
<!-- Филтер по категории --> <!-- Филтер по категории -->
<section class="filter-section"> <section class="filter-section">
<nav class="filter-nav" aria-label="Категории на проекти"> <div class="filter-inner">
<button type="button" class="filter-pill active" data-filter="all" aria-pressed="true">Сите</button> <nav class="filter-nav" aria-label="Категории на проекти">
<button type="button" class="filter-pill" data-filter="events" aria-pressed="false">Настани</button> <button type="button" class="filter-pill active" data-filter="all" aria-pressed="true">Сите</button>
<button type="button" class="filter-pill" data-filter="student-life" aria-pressed="false">Студентски живот</button> <button type="button" class="filter-pill" data-filter="events" aria-pressed="false">Настани</button>
<button type="button" class="filter-pill" data-filter="projects" aria-pressed="false">Проекти</button> <button type="button" class="filter-pill" data-filter="student-life" aria-pressed="false">Студентски живот</button>
<button type="button" class="filter-pill" data-filter="webinars" aria-pressed="false">Вебинари</button> <button type="button" class="filter-pill" data-filter="projects" aria-pressed="false">Проекти</button>
</nav> <button type="button" class="filter-pill" data-filter="webinars" aria-pressed="false">Вебинари</button>
<div class="filter-subnav" data-parent="events" hidden> </nav>
<button type="button" class="filter-chip active" data-subfilter="all">Сите настани</button> <div class="filter-subnav" data-parent="events" hidden>
<button type="button" class="filter-chip" data-subfilter="sports">Спорт</button> <button type="button" class="filter-chip active" data-subfilter="all">Сите настани</button>
<button type="button" class="filter-chip" data-subfilter="cultural">Културни</button> <button type="button" class="filter-chip" data-subfilter="sports">Спорт</button>
<button type="button" class="filter-chip" data-subfilter="entertainment">Забава</button> <button type="button" class="filter-chip" data-subfilter="cultural">Културни</button>
<button type="button" class="filter-chip" data-subfilter="educational">Едукативни</button> <button type="button" class="filter-chip" data-subfilter="entertainment">Забава</button>
<button type="button" class="filter-chip" data-subfilter="educational">Едукативни</button>
</div>
</div> </div>
</section> </section>

View File

@ -263,6 +263,11 @@
</div> </div>
</article> </article>
</div> </div>
<nav class="pagination blog-pagination" data-page-size="6" hidden>
<button type="button" class="pagination-arrow" data-nav="prev"><i class="fas fa-arrow-left" aria-hidden="true"></i> Prejšnja</button>
<div class="pagination-numbers"></div>
<button type="button" class="pagination-arrow" data-nav="next">Naslednja <i class="fas fa-arrow-right" aria-hidden="true"></i></button>
</nav>
</section> </section>
</main> </main>

View File

@ -148,31 +148,28 @@
<section class="page-header-section"> <section class="page-header-section">
<div class="container text-center"> <div class="container text-center">
<span class="page-subtitle">Naši projekti</span> <span class="page-subtitle">Naši projekti</span>
<h1>Projekti</h1> <h1>Dogodki in projekti</h1>
<p class="page-description">Naročite se in bodite na tekočem z novimi funkcijami, najnovejšimi tehnologijami, rešitvami in posodobitvami.</p> <p class="page-description">Dogodki, projekti in trenutki, ki povezujejo makedonsko študentsko skupnost v Sloveniji.</p>
<form class="subscribe-form">
<input type="email" placeholder="Vnesite svoj e-mail">
<button type="submit" class="btn btn-primary-orange">Naroči se</button>
</form>
<p class="privacy-note">Skrbimo za vaše podatke v naši <a href="../../si/privacy-policy/">politiki zasebnosti</a>.</p>
</div> </div>
</section> </section>
<!-- Filter kategorij --> <!-- Filter kategorij -->
<section class="filter-section"> <section class="filter-section">
<nav class="filter-nav" aria-label="Kategorije projektov"> <div class="filter-inner">
<button type="button" class="filter-pill active" data-filter="all" aria-pressed="true">Vse</button> <nav class="filter-nav" aria-label="Kategorije projektov">
<button type="button" class="filter-pill" data-filter="events" aria-pressed="false">Dogodki</button> <button type="button" class="filter-pill active" data-filter="all" aria-pressed="true">Vse</button>
<button type="button" class="filter-pill" data-filter="student-life" aria-pressed="false">Študentsko življenje</button> <button type="button" class="filter-pill" data-filter="events" aria-pressed="false">Dogodki</button>
<button type="button" class="filter-pill" data-filter="projects" aria-pressed="false">Projekti</button> <button type="button" class="filter-pill" data-filter="student-life" aria-pressed="false">Študentsko življenje</button>
<button type="button" class="filter-pill" data-filter="webinars" aria-pressed="false">Webinarji</button> <button type="button" class="filter-pill" data-filter="projects" aria-pressed="false">Projekti</button>
</nav> <button type="button" class="filter-pill" data-filter="webinars" aria-pressed="false">Webinarji</button>
<div class="filter-subnav" data-parent="events" hidden> </nav>
<button type="button" class="filter-chip active" data-subfilter="all">Vsi dogodki</button> <div class="filter-subnav" data-parent="events" hidden>
<button type="button" class="filter-chip" data-subfilter="sports">Šport</button> <button type="button" class="filter-chip active" data-subfilter="all">Vsi dogodki</button>
<button type="button" class="filter-chip" data-subfilter="cultural">Kulturni</button> <button type="button" class="filter-chip" data-subfilter="sports">Šport</button>
<button type="button" class="filter-chip" data-subfilter="entertainment">Zabava</button> <button type="button" class="filter-chip" data-subfilter="cultural">Kulturni</button>
<button type="button" class="filter-chip" data-subfilter="educational">Izobraževalni</button> <button type="button" class="filter-chip" data-subfilter="entertainment">Zabava</button>
<button type="button" class="filter-chip" data-subfilter="educational">Izobraževalni</button>
</div>
</div> </div>
</section> </section>