feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
{% extends "v2/base.html" %}
{% from "v2/components/result_row.html" import result_row %}
{% from "v2/components/chip.html" import chip %}
{% block title %}Durchsuchen — GWÖ-Antragsprüfer{% endblock %}
{% set v2_active_nav = "durchsuchen" %}
{% block main %}
2026-05-09 02:47:04 +02:00
{# ── Welcome-Banner: Tour-Einstieg für Erst-Besucher:innen (#185) ── #}
2026-05-09 03:31:09 +02:00
< aside id = "gwoe-welcome-banner" class = "gwoe-welcome-banner" hidden role = "region"
aria-label="Willkommen — Tour-Einstieg">
< span aria-hidden = "true" class = "gwoe-welcome-icon" > 🧭< / span >
2026-05-09 02:47:04 +02:00
< div class = "gwoe-welcome-text" >
< strong > Du bist neu hier?< / strong >
2026-05-09 03:31:09 +02:00
Soll ich dir die Seite kurz erklären? Geführte Tour mit Sprachausgabe — jederzeit abbrechbar.
2026-05-09 02:47:04 +02:00
< / div >
< div class = "gwoe-welcome-actions" >
< button type = "button" onclick = "gwoeTourStart()" class = "v2-chip primary"
2026-05-09 03:31:09 +02:00
id="gwoe-welcome-start">Tour starten< / button >
< button type = "button" onclick = "gwoeWelcomeDismiss()" class = "gwoe-welcome-skip"
id="gwoe-welcome-dismiss" aria-label="Banner schließen">Später< / button >
2026-05-09 02:47:04 +02:00
< / div >
2026-05-09 03:31:09 +02:00
< / aside >
2026-05-09 02:47:04 +02:00
2026-04-25 21:50:36 +02:00
{# ── Toolbar: Suche ──────────────────────────────────────────────── #}
{# BL-Filter läuft jetzt über den globalen Selector in der Topbar. #}
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
< div class = "v2-toolbar" id = "v2-toolbar" role = "toolbar" aria-label = "Filter und Suche" >
< input class = "v2-search"
type="search"
placeholder="Anträge durchsuchen …"
aria-label="Anträge durchsuchen"
id="v2-search-input">
< / div >
{# ── Score-Filter + Sortierung ───────────────────────────────────── #}
< div class = "v2-toolbar" role = "toolbar" aria-label = "Score-Filter und Sortierung" style = "border:0;padding:4px 0;margin:0 0 8px;position:static;" >
< button class = "v2-chip active" data-band = "ALL" onclick = "v2SetBand(this,'ALL')" > Alle Scores< / button >
< button class = "v2-chip" data-band = "HIGH" onclick = "v2SetBand(this,'HIGH')" > Score 8– 10< / button >
< button class = "v2-chip" data-band = "MID" onclick = "v2SetBand(this,'MID')" > 5– 7< / button >
< button class = "v2-chip" data-band = "LOW" onclick = "v2SetBand(this,'LOW')" > 0– 4< / button >
< span class = "v2-toolbar-sep" > < / span >
< select id = "v2-sort"
aria-label="Sortierung"
onchange="v2ApplySort(this.value)"
style="padding:4px 8px;border:1px solid var(--hairline);border-radius:4px;
font-family:var(--font-mono);font-size:11px;background:var(--surface);
color:var(--ecg-dark);cursor:pointer;">
< option value = "score-desc" > Score ↓< / option >
< option value = "score-asc" > Score ↑< / option >
< option value = "date-desc" > Datum ↓< / option >
< option value = "date-asc" > Datum ↑< / option >
< option value = "drucksache-desc" > Drs.-Nr. ↓< / option >
< option value = "drucksache-asc" > Drs.-Nr. ↑< / option >
< option value = "title-asc" > Titel A– Z< / option >
< option value = "title-desc" > Titel Z– A< / option >
< / select >
< / div >
{# ── Ergebnisliste ───────────────────────────────────────────────── #}
< div id = "v2-results" role = "list" >
{% if assessments %}
{% for a in assessments %}
{{ result_row(a) }}
{% endfor %}
{% else %}
< p style = "font-family:var(--font-mono);font-size:13px;color:var(--ecg-dark);opacity:0.6;margin-top:32px;" >
Noch keine Bewertungen in der Datenbank.
< / p >
{% endif %}
< / div > {# #v2-results #}
{# ── Empty-State ─────────────────────────────────────────────────── #}
< div id = "v2-empty-state" class = "v2-kasten outline-green" style = "display:none;margin-top:32px;" >
< h4 > Keine Ergebnisse< / h4 >
< p > Die aktuelle Filterauswahl liefert keine Treffer.
< button onclick = "v2ResetFilters()"
style="background:none;border:none;color:var(--ecg-green);cursor:pointer;font-weight:900;text-decoration:underline;font-size:inherit;font-family:inherit;">
Filter zurücksetzen
< / button >
< / p >
< / div >
2026-05-09 02:47:04 +02:00
{# ── Tour-Stationen für die Startseite + Engine-Include ──────────── #}
< script >
window.GWOE_TOUR_STEPS = [
{ selector: '.v2-brand-link, .v2-brand',
title: 'Willkommen beim GWÖ-Antragsprüfer',
text: 'Diese Seite bewertet Anträge aus deutschen Parlamenten nach der Gemeinwohl-Matrix. Was sie auszeichnet: Sie schaut nicht nur, ob ein Antrag „gut klingt", sondern wie sehr er fünf Werten dient — Würde, Solidarität, Nachhaltigkeit, Gerechtigkeit und Demokratie.' },
{ selector: '#v2-search-input',
title: 'Anträge durchsuchen',
text: 'Hier findest du Anträge nach Stichwort, Drucksachen-Nummer oder Antragstellerin. Die Liste filtert sich beim Tippen mit.' },
{ selector: '.v2-toolbar:nth-of-type(2), [data-band]',
title: 'Filter nach Note',
text: 'Mit diesen Knöpfen filterst du nach Gemeinwohl-Note. Acht bis Zehn sind vorbildlich, fünf bis sieben durchwachsen, null bis vier problematisch. Daneben kannst du nach Datum, Score oder Titel sortieren.' },
{ selector: '#v2-results .v2-result-row, #v2-results',
title: 'Die Antrags-Liste',
text: 'Jede Karte zeigt einen Antrag mit seiner Note. Klick auf eine Karte öffnet die ausführliche Bewertung — dort wirst du dort dann auch noch eine eigene Tour finden, die das Detail erklärt.' },
{ selector: '.v2-nav-group, #v2-sidebar nav',
title: 'Navigation links',
text: 'Links findest du weitere Sichten. „Auswertungen" zeigt Aggregate über alle Anträge, „Stimmverhalten" die Konsistenz jeder Fraktion zwischen Wahlprogramm und tatsächlicher Stimme, „Quellen" alle indizierten Wahl- und Grundsatzprogramme — semantisch durchsuchbar.' },
];
< / script >
{% include "v3/components/tour.html" %}
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
{% endblock %}
{% block body_scripts %}
< script >
/* ── v2 Listenfilter ─────────────────────────────────────────────── */
(function () {
var activeBl = 'ALL';
var activeBand = 'ALL';
function getRows() {
return document.querySelectorAll('#v2-results .v2-result-row');
}
function getScore(row) {
var cell = row.querySelector('.v2-score-cell');
return cell ? parseFloat(cell.textContent) || 0 : 0;
}
function getBl(row) {
var state = row.querySelector('.v2-r-state');
return state ? state.textContent.trim().split('·')[0].trim() : '';
}
function applyFilters() {
var q = (document.getElementById('v2-search-input').value || '').toLowerCase().trim();
var rows = getRows();
var visible = 0;
rows.forEach(function (row) {
var score = getScore(row);
var bl = getBl(row);
var text = row.textContent.toLowerCase();
var blOk = (activeBl === 'ALL') || (bl === activeBl);
var bandOk = (activeBand === 'ALL') ||
(activeBand === 'HIGH' & & score >= 8) ||
(activeBand === 'MID' & & score >= 5 & & score < 8 ) | |
(activeBand === 'LOW' & & score < 5 ) ;
var qOk = !q || text.includes(q);
var show = blOk & & bandOk & & qOk;
row.style.display = show ? '' : 'none';
if (show) visible++;
});
var empty = document.getElementById('v2-empty-state');
if (empty) empty.style.display = (visible === 0) ? 'block' : 'none';
}
2026-04-25 21:50:36 +02:00
/* BL-Filter: globaler Selector in der Topbar */
window.addEventListener('v2-bl-changed', function (e) {
activeBl = (e.detail & & e.detail.bl) ? e.detail.bl : 'ALL';
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
applyFilters();
2026-04-25 21:50:36 +02:00
});
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
window.v2SetBand = function (btn, band) {
activeBand = band;
document.querySelectorAll('[data-band]').forEach(function (b) {
b.classList.toggle('active', b.dataset.band === band);
});
applyFilters();
};
window.v2ResetFilters = function () {
document.getElementById('v2-search-input').value = '';
2026-04-25 21:50:36 +02:00
// BL auf ALL zurücksetzen: globalen Selector aktualisieren
var sel = document.getElementById('v2-global-bl');
if (sel) sel.value = 'ALL';
window.v2SetGlobalBl & & window.v2SetGlobalBl('ALL');
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
v2SetBand(null, 'ALL');
};
document.addEventListener('DOMContentLoaded', function () {
var input = document.getElementById('v2-search-input');
if (input) input.addEventListener('input', applyFilters);
2026-04-25 21:50:36 +02:00
// Gespeicherten BL-Wert beim Laden anwenden
activeBl = (window.v2GetGlobalBl & & window.v2GetGlobalBl()) || 'ALL';
applyFilters();
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
});
})();
/* ── Sort ────────────────────────────────────────────────────────── */
(function () {
var SORT_KEY = 'gwoe.v2-sort';
function getRowVal(row, field) {
if (field === 'score') {
var cell = row.querySelector('.v2-score-cell');
return cell ? parseFloat(cell.textContent) || 0 : 0;
}
if (field === 'title') {
var titleEl = row.querySelector('.v2-r-title');
return titleEl ? titleEl.textContent.trim().toLowerCase() : '';
}
if (field === 'date') {
var dateEl = row.querySelector('.v2-r-date');
return dateEl ? dateEl.textContent.trim() : '';
}
if (field === 'drucksache') {
var stateEl = row.querySelector('.v2-r-state');
return stateEl ? stateEl.textContent.trim() : '';
}
return '';
}
function sortRows(sortVal) {
var parts = sortVal.split('-');
var field = parts.slice(0, -1).join('-');
var dir = parts[parts.length - 1]; // 'asc' or 'desc'
var container = document.getElementById('v2-results');
if (!container) return;
var rows = Array.from(container.querySelectorAll('.v2-result-row'));
rows.sort(function(a, b) {
var va = getRowVal(a, field);
var vb = getRowVal(b, field);
var cmp;
if (typeof va === 'number' & & typeof vb === 'number') {
cmp = va - vb;
} else {
cmp = String(va).localeCompare(String(vb), 'de');
}
return dir === 'asc' ? cmp : -cmp;
});
rows.forEach(function(row) { container.appendChild(row); });
}
window.v2ApplySort = function(val) {
try { localStorage.setItem(SORT_KEY, val); } catch (_) {}
sortRows(val);
};
document.addEventListener('DOMContentLoaded', function() {
var savedSort;
try { savedSort = localStorage.getItem(SORT_KEY); } catch (_) {}
var sortSelect = document.getElementById('v2-sort');
if (savedSort & & sortSelect) {
sortSelect.value = savedSort;
sortRows(savedSort);
}
});
})();
/* ── Keyboard Shortcuts (#116 port to v2) ────────────────────────── */
(function () {
document.addEventListener('keydown', function (e) {
// Nicht in Input-Feldern auslösen
if (e.target.matches('input, textarea, select')) return;
var rows = Array.from(document.querySelectorAll('#v2-results .v2-result-row'));
var active = document.querySelector('#v2-results .v2-result-row.v2-kb-active');
var idx = active ? rows.indexOf(active) : -1;
switch (e.key) {
case 'j': // nächster Eintrag
e.preventDefault();
if (!rows.length) break;
idx = Math.min(idx + 1, rows.length - 1);
if (active) active.classList.remove('v2-kb-active');
rows[idx].classList.add('v2-kb-active');
rows[idx].scrollIntoView({ block: 'nearest' });
break;
case 'k': // vorheriger Eintrag
e.preventDefault();
if (!rows.length) break;
idx = Math.max(idx - 1, 0);
if (active) active.classList.remove('v2-kb-active');
rows[idx].classList.add('v2-kb-active');
rows[idx].scrollIntoView({ block: 'nearest' });
break;
case 'Enter': // Eintrag öffnen
if (active) {
e.preventDefault();
var href = active.getAttribute('href');
if (href) window.location.href = href;
}
break;
case '/': // Suche fokussieren
e.preventDefault();
var searchInput = document.getElementById('v2-search-input');
if (searchInput) searchInput.focus();
break;
case '?': // Shortcuts-Hilfe
e.preventDefault();
var modal = document.getElementById('v2-kb-help-modal');
if (modal) {
modal.style.display = modal.style.display === 'flex' ? 'none' : 'flex';
}
break;
case 'Escape': // Hilfe-Modal schließen (auf Detailseiten: history.back() — dort eigener Handler)
var helpModal = document.getElementById('v2-kb-help-modal');
if (helpModal & & helpModal.style.display === 'flex') {
e.preventDefault();
helpModal.style.display = 'none';
}
break;
}
});
})();
< / script >
{# ── Keyboard-Hilfe-Modal ───────────────────────────────────────── #}
< div id = "v2-kb-help-modal"
role="dialog" aria-modal="true" aria-label="Tastenkürzel"
style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.45);
z-index:9000;align-items:center;justify-content:center;"
onclick="if(event.target===this)this.style.display='none'">
< div style = "background:var(--ecg-card-bg);border:1px solid var ( --ecg-border ) ;
border-radius:8px;padding:28px 32px;min-width:280px;max-width:400px;
font-family:var(--font-mono);font-size:13px;color:var(--ecg-dark);">
< div style = "font-family:var(--font-display);font-size:15px;font-weight:900;
color:var(--ecg-teal);margin-bottom:16px;letter-spacing:0.03em;">
Tastenkürzel
< / div >
< table style = "width:100%;border-collapse:collapse;line-height:1.9;" >
< tr > < td style = "width:50px;" > < kbd > j< / kbd > < / td > < td > Nächster Antrag< / td > < / tr >
< tr > < td > < kbd > k< / kbd > < / td > < td > Vorheriger Antrag< / td > < / tr >
< tr > < td > < kbd > Enter< / kbd > < / td > < td > Antrag öffnen< / td > < / tr >
< tr > < td > < kbd > Esc< / kbd > < / td > < td > Detail schließen / zurück< / td > < / tr >
< tr > < td > < kbd > /< / kbd > < / td > < td > Suche fokussieren< / td > < / tr >
< tr > < td > < kbd > ?< / kbd > < / td > < td > Diese Hilfe< / td > < / tr >
< / table >
< button onclick = "document.getElementById('v2-kb-help-modal').style.display='none'"
style="margin-top:18px;font-family:var(--font-mono);font-size:11px;
background:none;border:1px solid var(--ecg-border);border-radius:4px;
padding:5px 14px;cursor:pointer;color:var(--ecg-dark);">
Schließen
< / button >
< / div >
< / div >
< style >
.v2-kb-active {
outline: 2px solid var(--ecg-teal);
outline-offset: -2px;
border-radius: 4px;
}
kbd {
display: inline-block;
font-family: var(--font-mono);
font-size: 11px;
background: var(--ecg-border);
border: 1px solid color-mix(in srgb, var(--ecg-border) 60%, #000);
border-radius: 3px;
padding: 1px 5px;
color: var(--ecg-dark);
}
2026-05-09 02:47:04 +02:00
.gwoe-welcome-banner {
display: flex;
align-items: center;
2026-05-09 03:31:09 +02:00
gap: 14px;
2026-05-09 02:47:04 +02:00
flex-wrap: wrap;
2026-05-09 03:31:09 +02:00
margin-bottom: 14px;
padding: 14px 18px;
border-radius: 12px;
/* dezent-warmer Hint statt scharfes Outline-Kasten */
background: linear-gradient(
135deg,
color-mix(in srgb, var(--ecg-teal) 6%, var(--surface)) 0%,
color-mix(in srgb, var(--ecg-blue) 4%, var(--surface)) 100%
);
border: 1px solid color-mix(in srgb, var(--ecg-teal) 22%, transparent);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
2026-05-09 02:47:04 +02:00
}
.gwoe-welcome-banner[hidden] { display: none !important; }
2026-05-09 03:31:09 +02:00
.gwoe-welcome-icon {
font-size: 22px;
flex-shrink: 0;
filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.08));
}
2026-05-09 02:47:04 +02:00
.gwoe-welcome-text {
flex: 1 1 320px;
2026-05-09 03:31:09 +02:00
font-size: 14px;
line-height: 1.55;
2026-05-09 02:47:04 +02:00
color: var(--ecg-dark);
}
2026-05-09 03:31:09 +02:00
.gwoe-welcome-text strong {
font-weight: 700;
color: var(--ecg-teal);
}
2026-05-09 02:47:04 +02:00
.gwoe-welcome-actions {
display: flex;
2026-05-09 03:31:09 +02:00
gap: 4px;
2026-05-09 02:47:04 +02:00
align-items: center;
}
2026-05-09 03:31:09 +02:00
.gwoe-welcome-skip {
background: none;
border: none;
color: var(--ecg-dark);
font-size: 12px;
font-family: var(--font-mono);
letter-spacing: 0.04em;
opacity: 0.55;
padding: 6px 10px;
cursor: pointer;
border-radius: 999px;
transition: opacity 0.15s ease, background 0.15s ease;
}
.gwoe-welcome-skip:hover {
opacity: 0.9;
background: color-mix(in srgb, var(--ecg-dark) 6%, transparent);
2026-05-09 02:47:04 +02:00
}
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
< / style >
2026-05-09 02:47:04 +02:00
< script >
/* Welcome-Banner sichtbar bis Tour gestartet oder „Nein, danke".
localStorage: 'gwoe_welcome_dismissed' = '1' merkt den Schließ-Klick. */
(function () {
var KEY = 'gwoe_welcome_dismissed';
var banner = document.getElementById('gwoe-welcome-banner');
if (!banner) return;
if (localStorage.getItem(KEY) !== '1') {
banner.hidden = false;
}
window.gwoeWelcomeDismiss = function () {
try { localStorage.setItem(KEY, '1'); } catch (_) {}
banner.hidden = true;
};
// Wenn Tour gestartet wird, Banner auch wegblenden + dismissed merken.
var origStart = window.gwoeTourStart;
if (typeof origStart === 'function') {
window.gwoeTourStart = function () {
try { localStorage.setItem(KEY, '1'); } catch (_) {}
banner.hidden = true;
return origStart.apply(this, arguments);
};
}
})();
< / script >
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
{% endblock %}