Wiki pagination — 9 cards/page (3 rows), counter X/27, topic filter pills, prev/next

- wikiPerPage = 9 (3 masonry rows × 3 cols), wikiCurrentPage state
- wikiFilteredData holds sorted/filtered list; renderWikiPage slices it
- Topic filter pills below search bar, rendered from unique topics in data
- searchWiki now works with pagination/filters, resets to page 1
- Counter shows '9/27' style, pagination shows Zurück/Weiter with page info
- Language toggle re-renders wiki topics + page
- New CSS: .wiki-topics, .wiki-topic-filter (pill style), .wiki-footer, .wiki-page-btn
This commit is contained in:
Kato
2026-09-05 19:51:06 +00:00
parent 34d9b0b1e2
commit 113ca75502
3 changed files with 198 additions and 20 deletions
+79
View File
@@ -1054,6 +1054,85 @@ body[data-lang="en"] .hide-de { display: none !important; }
.rank-badge.rank-expert { background: #fff3e0; color: #e65100; }
.rank-badge.rank-legend { background: #fce4ec; color: #c62828; }
/* ========================================
WIKI TOPICS — filter pills
======================================== */
.wiki-topics {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin: 12px 0 20px;
}
.wiki-topic-filter {
background: #f0f2f5;
border: none;
border-radius: 999px;
padding: 5px 12px;
font-size: 13px;
font-weight: 500;
color: #1c1e21;
cursor: pointer;
transition: background 0.2s, color 0.2s;
white-space: nowrap;
}
.wiki-topic-filter:hover {
background: #e4e6eb;
}
.wiki-topic-filter.active {
background: #1877f2;
color: #fff;
}
.wiki-filter-count {
font-size: 11px;
opacity: 0.7;
margin-left: 2px;
}
/* ========================================
WIKI FOOTER — counter + pagination
======================================== */
.wiki-footer {
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
margin-top: 24px;
flex-wrap: wrap;
}
.wiki-counter {
font-size: 14px;
font-weight: 600;
color: #65676b;
}
.wiki-pagination {
display: flex;
align-items: center;
gap: 8px;
}
.wiki-page-btn {
background: #f0f2f5;
border: none;
border-radius: 8px;
padding: 6px 14px;
font-size: 13px;
font-weight: 500;
color: #1c1e21;
cursor: pointer;
transition: background 0.2s;
}
.wiki-page-btn:hover:not(:disabled) {
background: #e4e6eb;
}
.wiki-page-btn:disabled {
opacity: 0.4;
cursor: default;
}
.wiki-page-info {
font-size: 13px;
font-weight: 600;
color: #65676b;
}
/* ========================================
WIKI CARDS
======================================== */
+5
View File
@@ -436,12 +436,17 @@
<svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
<input type="text" id="wiki-search" class="search-input" placeholder="Wiki durchsuchen..." />
</div>
<div class="wiki-topics" id="wiki-topics"></div>
<div class="wiki-grid" id="wiki-grid">
<p class="loading-text">
<span class="hide-de">Lade Wiki...</span>
<span class="hide-en">Loading wiki...</span>
</p>
</div>
<div class="wiki-footer" id="wiki-footer">
<div class="wiki-counter" id="wiki-counter"></div>
<div class="wiki-pagination" id="wiki-pagination"></div>
</div>
</div>
</section>
+114 -20
View File
@@ -273,6 +273,10 @@ function setLanguage(lang) {
b.classList.toggle('active', b.dataset.lang === lang);
});
renderCalendar();
if (wikiData.length) {
renderWikiTopics();
renderWikiPage();
}
}
function isDE() {
@@ -730,6 +734,20 @@ function getTopicColor(topic) {
// ========================================
let wikiData = [];
let wikiCurrentPage = 1;
let wikiPerPage = 9;
let wikiFilteredData = [];
let wikiActiveTopic = '';
// Get unique topics with counts from the full wiki data
function getWikiTopics(data) {
const map = {};
data.forEach(item => {
const t = currentLang === 'en' && item.topic_en ? item.topic_en : (item.topic || 'Unknown');
map[t] = (map[t] || 0) + 1;
});
return Object.entries(map).sort();
}
async function loadWiki() {
try {
@@ -739,17 +757,94 @@ async function loadWiki() {
if (result.data && Array.isArray(result.data)) {
wikiData = result.data;
renderWikiCards(wikiData);
// Wiki count will be loaded from community webhook
wikiFilteredData = [...result.data].sort((a, b) => new Date(b.updatedAt || b.createdAt) - new Date(a.updatedAt || a.createdAt));
wikiCurrentPage = 1;
wikiActiveTopic = '';
renderWikiTopics();
renderWikiPage();
} else {
document.getElementById('wiki-grid').innerHTML = '<p class="loading-text">' + (isDE() ? 'Keine Wiki-Daten' : 'No wiki data') + '</p>';
const c = document.getElementById('wiki-counter'); if (c) c.innerHTML = '';
const p = document.getElementById('wiki-pagination'); if (p) p.innerHTML = '';
}
} catch (error) {
document.getElementById('wiki-grid').innerHTML = '<p class="loading-text">' + (isDE() ? 'Fehler beim Laden' : 'Error loading') + '</p>';
}
}
function renderWikiTopics() {
const container = document.getElementById('wiki-topics');
if (!container) return;
const topics = getWikiTopics(wikiData);
let html = '<button class="wiki-topic-filter' + (wikiActiveTopic === '' ? ' active' : '') + '" onclick="filterWikiByTopic(\'\')">' +
(isDE() ? 'Alle' : 'All') + ' <span class="wiki-filter-count">' + wikiData.length + '</span></button>';
topics.forEach(([topic, count]) => {
const esc = escapeHtml(topic).replace(/'/g, "\\'");
html += '<button class="wiki-topic-filter' + (topic === wikiActiveTopic ? ' active' : '') + '" onclick="filterWikiByTopic(\'' + esc + '\')">' +
escapeHtml(topic) + ' <span class="wiki-filter-count">' + count + '</span></button>';
});
container.innerHTML = html;
}
function filterWikiByTopic(topic) {
wikiActiveTopic = topic;
if (!topic) {
wikiFilteredData = [...wikiData].sort((a, b) => new Date(b.updatedAt || b.createdAt) - new Date(a.updatedAt || a.createdAt));
} else {
wikiFilteredData = [...wikiData].filter(item => {
const t = currentLang === 'en' && item.topic_en ? item.topic_en : (item.topic || '');
return t === topic;
}).sort((a, b) => new Date(b.updatedAt || b.createdAt) - new Date(a.updatedAt || a.createdAt));
}
wikiCurrentPage = 1;
renderWikiTopics();
renderWikiPage();
}
function renderWikiPage() {
const total = wikiFilteredData.length;
const totalPages = Math.max(1, Math.ceil(total / wikiPerPage));
if (wikiCurrentPage > totalPages) wikiCurrentPage = totalPages;
const start = (wikiCurrentPage - 1) * wikiPerPage;
const pageData = wikiFilteredData.slice(start, start + wikiPerPage);
renderWikiCards(pageData);
renderWikiCounter(start, total);
renderWikiPagination(totalPages);
}
function renderWikiCounter(start, total) {
const el = document.getElementById('wiki-counter');
if (!el) return;
if (total === 0 || start >= total) { el.innerHTML = ''; return; }
const shown = Math.min(wikiPerPage, total - start);
el.textContent = start + shown + '/' + total;
}
function renderWikiPagination(totalPages) {
const el = document.getElementById('wiki-pagination');
if (!el) return;
if (totalPages <= 1) { el.innerHTML = ''; return; }
el.innerHTML =
'<button class="wiki-page-btn" onclick="wikiGoPage(' + (wikiCurrentPage - 1) + ')"' + (wikiCurrentPage <= 1 ? ' disabled' : '') + '>' +
'<span class="hide-de">Zurück</span><span class="hide-en">Previous</span></button>' +
'<span class="wiki-page-info">' + wikiCurrentPage + '/' + totalPages + '</span>' +
'<button class="wiki-page-btn" onclick="wikiGoPage(' + (wikiCurrentPage + 1) + ')"' + (wikiCurrentPage >= totalPages ? ' disabled' : '') + '>' +
'<span class="hide-de">Weiter</span><span class="hide-en">Next</span></button>';
}
function wikiGoPage(page) {
const total = wikiFilteredData.length;
const totalPages = Math.max(1, Math.ceil(total / wikiPerPage));
if (page < 1 || page > totalPages) return;
wikiCurrentPage = page;
const start = (wikiCurrentPage - 1) * wikiPerPage;
renderWikiCards(wikiFilteredData.slice(start, start + wikiPerPage));
renderWikiCounter(start, total);
renderWikiPagination(totalPages);
const section = document.querySelector('#wiki');
if (section) section.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
function renderWikiCards(data) {
const grid = document.getElementById('wiki-grid');
grid.innerHTML = '';
@@ -759,9 +854,7 @@ function renderWikiCards(data) {
return;
}
const sorted = [...data].sort((a, b) => new Date(b.updatedAt || b.createdAt) - new Date(a.updatedAt || a.createdAt));
sorted.forEach((item, idx) => {
data.forEach((item, idx) => {
const card = document.createElement('div');
card.className = 'wiki-card-new stagger-' + (idx % 4 + 1);
card.setAttribute('role', 'button');
@@ -769,7 +862,6 @@ function renderWikiCards(data) {
const topic = currentLang === 'en' && item.topic_en ? item.topic_en : (item.topic || 'Unknown');
const topicColor = getTopicColor(topic);
// Feed topic accent into CSS custom properties (top bar + hover border)
card.style.setProperty('--topic-accent', topicColor.border);
const subtopic = currentLang === 'en' && item.subtopic_en ? item.subtopic_en : (item.subtopic || '');
@@ -839,20 +931,22 @@ function openWikiModalSingle(item) {
}
function searchWiki(term) {
if (!term.trim()) {
renderWikiCards(wikiData);
return;
const t = term.toLowerCase().trim();
if (!t) {
wikiActiveTopic = '';
wikiFilteredData = [...wikiData].sort((a, b) => new Date(b.updatedAt || b.createdAt) - new Date(a.updatedAt || a.createdAt));
} else {
wikiActiveTopic = '';
wikiFilteredData = wikiData.filter(item => {
const text = ((item.topic_en && currentLang === 'en') ? item.topic_en : (item.topic || '')) + ' ' +
((item.subtopic_en && currentLang === 'en') ? item.subtopic_en : (item.subtopic || '')) + ' ' +
((item.wiki_en && currentLang === 'en') ? item.wiki_en : (item.wiki || ''));
return text.toLowerCase().includes(t);
}).sort((a, b) => new Date(b.updatedAt || b.createdAt) - new Date(a.updatedAt || a.createdAt));
}
const t = term.toLowerCase();
const filtered = wikiData.filter(item => {
const topic = ((item.topic_en && currentLang === 'en') ? item.topic_en : (item.topic || '')) +
' ' + ((item.subtopic_en && currentLang === 'en') ? item.subtopic_en : (item.subtopic || '')) +
' ' + ((item.wiki_en && currentLang === 'en') ? item.wiki_en : (item.wiki || ''));
return topic.toLowerCase().includes(t);
});
renderWikiCards(filtered);
renderWikiTopics();
wikiCurrentPage = 1;
renderWikiPage();
}
function getTopicColor(topic) {