feat(sources): Quellenuebersicht der Lage nach Typ filterbar
Die Quellenuebersicht innerhalb einer Lage zeigt jetzt Filter-Chips (Alle / Web / Telegram / X) und blendet die Quellen-Boxen nach Quellentyp ein und aus. Die Chips erscheinen nur, wenn neben Web auch Telegram- oder X-Quellen vorkommen. - sources-summary-Endpoint liefert pro Quelle einen source_type, abgeleitet aus dem source-Praefix (X: / Telegram: / sonst Web) - Filter-Chips und data-type in renderSourceOverviewFromSummary - App.filterSourceOverview blendet die Boxen nach Typ - Chip-Styles in style.css Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -909,6 +909,26 @@ const App = {
|
||||
}
|
||||
},
|
||||
|
||||
/** Quellenuebersicht der Lage nach Quellentyp filtern (Web/Telegram/X). */
|
||||
filterSourceOverview(type, chipEl) {
|
||||
const content = document.getElementById('source-overview-content');
|
||||
if (!content) return;
|
||||
content.querySelectorAll('.source-type-filter-chip').forEach(c => c.classList.remove('active'));
|
||||
if (chipEl) chipEl.classList.add('active');
|
||||
// ein offenes Detail-Panel schliessen
|
||||
const det = content.querySelector('.source-overview-detail');
|
||||
if (det) det.remove();
|
||||
content.querySelectorAll('.source-overview-item.active').forEach(it => {
|
||||
it.classList.remove('active');
|
||||
it.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
// Quellen-Boxen nach Typ ein-/ausblenden
|
||||
content.querySelectorAll('.source-overview-item').forEach(it => {
|
||||
const t = it.dataset.type || 'web';
|
||||
it.style.display = (!type || t === type) ? '' : 'none';
|
||||
});
|
||||
},
|
||||
|
||||
/** Klick auf eine Quellen-Box: Liste der Artikel inline aufklappen (mutual-exclusive). */
|
||||
toggleSourceOverviewDetail(el) {
|
||||
if (!el) return;
|
||||
|
||||
@@ -1034,11 +1034,32 @@ const UI = {
|
||||
html += `<div class="source-lang-chips">${langChips}</div>`;
|
||||
html += `</div>`;
|
||||
|
||||
// Typ-Filter-Chips (nur zeigen, wenn neben Web auch Telegram/X vorkommt)
|
||||
const typeCounts = { web: 0, telegram: 0, x: 0 };
|
||||
data.sources.forEach(s => {
|
||||
const t = s.source_type || 'web';
|
||||
typeCounts[t] = (typeCounts[t] || 0) + 1;
|
||||
});
|
||||
if (typeCounts.telegram > 0 || typeCounts.x > 0) {
|
||||
const typeMeta = [
|
||||
{ key: '', label: 'Alle', count: data.sources.length },
|
||||
{ key: 'web', label: 'Web', count: typeCounts.web },
|
||||
{ key: 'telegram', label: 'Telegram', count: typeCounts.telegram },
|
||||
{ key: 'x', label: 'X', count: typeCounts.x },
|
||||
];
|
||||
const chips = typeMeta
|
||||
.filter(t => t.key === '' || t.count > 0)
|
||||
.map(t => `<button type="button" class="source-type-filter-chip${t.key === '' ? ' active' : ''}" data-type="${t.key}" onclick="App.filterSourceOverview('${t.key}', this)">${t.label} <strong>${t.count}</strong></button>`)
|
||||
.join('');
|
||||
html += `<div class="source-type-filter-chips">${chips}</div>`;
|
||||
}
|
||||
|
||||
html += '<div class="source-overview-grid">';
|
||||
data.sources.forEach(s => {
|
||||
const langs = (s.languages || ['de']).map(l => (l || 'de').toUpperCase()).join('/');
|
||||
const sourceName = this.escape(s.source || 'Unbekannt');
|
||||
html += `<div class="source-overview-item" data-source="${sourceName}" tabindex="0" role="button" aria-expanded="false" onclick="App.toggleSourceOverviewDetail(this)" onkeydown="if(event.key==='Enter'||event.key===' '){event.preventDefault();App.toggleSourceOverviewDetail(this);}">
|
||||
const sType = s.source_type || 'web';
|
||||
html += `<div class="source-overview-item" data-source="${sourceName}" data-type="${sType}" tabindex="0" role="button" aria-expanded="false" onclick="App.toggleSourceOverviewDetail(this)" onkeydown="if(event.key==='Enter'||event.key===' '){event.preventDefault();App.toggleSourceOverviewDetail(this);}">
|
||||
<span class="source-overview-name">${sourceName}</span>
|
||||
<span class="source-overview-lang">${langs}</span>
|
||||
<span class="source-overview-count">${s.article_count}</span>
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren