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
|
|
|
{% from "v2/components/icon.html" import icon %}
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="de" data-theme="auto">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
<title>{% block title %}GWÖ-Antragsprüfer{% endblock %}</title>
|
|
|
|
|
<link rel="alternate" type="application/atom+xml" title="GWÖ-Antragsprüfer — Neue Bewertungen" href="/api/feed.xml">
|
|
|
|
|
|
|
|
|
|
{# Design-System: Tokens zuerst, dann Fonts, dann Base-Styles #}
|
2026-04-28 00:33:18 +02:00
|
|
|
<link rel="stylesheet" href="/static/v2/tokens.css?v={{ app_version|default('1') }}">
|
|
|
|
|
<link rel="stylesheet" href="/static/v2/fonts.css?v={{ app_version|default('1') }}">
|
|
|
|
|
<link rel="stylesheet" href="/static/v2/v2.css?v={{ app_version|default('1') }}">
|
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
|
|
|
|
|
|
|
|
{% block head_extra %}{% endblock %}
|
|
|
|
|
</head>
|
|
|
|
|
<body class="v2">
|
|
|
|
|
|
|
|
|
|
{% block body %}
|
|
|
|
|
{# AppShell inline, damit {% block main %} aus Screen-Templates rendert.
|
|
|
|
|
include propagiert Blocks nicht (Jinja2-Limitierung), darum direkt hier. #}
|
|
|
|
|
|
|
|
|
|
<div id="v2-overlay" class="v2-overlay"></div>
|
|
|
|
|
|
|
|
|
|
<div class="v2-shell">
|
|
|
|
|
|
|
|
|
|
<aside id="v2-sidebar" class="v2-sidebar">
|
|
|
|
|
<div class="v2-brand">
|
|
|
|
|
GWÖ-<span class="grn">ANTRAGS</span><span class="blu">PRÜFER</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="v2-brand-sub">Matrix 2.0 · Gemeinden</div>
|
|
|
|
|
|
|
|
|
|
<nav aria-label="Hauptnavigation">
|
|
|
|
|
<div class="v2-nav-group">
|
|
|
|
|
<div class="v2-nav-label">— Lesen</div>
|
|
|
|
|
<a href="/" class="v2-nav-item {% if v2_active_nav == 'durchsuchen' %}active{% endif %}"
|
|
|
|
|
aria-current="{% if v2_active_nav == 'durchsuchen' %}page{% endif %}">
|
|
|
|
|
{{ icon("magnifying-glass", 14) }} Durchsuchen
|
|
|
|
|
{% if assessment_count is defined and assessment_count %}
|
|
|
|
|
<span class="v2-nav-count">{{ assessment_count }}</span>
|
|
|
|
|
{% endif %}
|
|
|
|
|
</a>
|
2026-04-25 21:50:36 +02:00
|
|
|
{% if is_authenticated %}<a href="/v2/merkliste" class="v2-nav-item {% if v2_active_nav == 'merkliste' %}active{% endif %}">{{ icon("bookmark-simple", 14) }} Merkliste</a>{% endif %}
|
|
|
|
|
<a href="/v2/tags" class="v2-nav-item {% if v2_active_nav == 'tags' %}active{% endif %}">{{ icon("tag", 14) }} Tags</a>
|
|
|
|
|
{% if is_admin %}<a href="/v2/cluster" class="v2-nav-item {% if v2_active_nav == 'cluster' %}active{% endif %}">{{ icon("graph", 14) }} Cluster</a>{% endif %}
|
|
|
|
|
{% if is_authenticated %}<a href="/v2/landtag-suche" class="v2-nav-item {% if v2_active_nav == 'landtag_suche' %}active{% endif %}">{{ icon("magnifying-glass-plus", 14) }} Landtag-Suche</a>{% endif %}
|
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>
|
|
|
|
|
|
2026-04-25 22:18:58 +02:00
|
|
|
{% if is_authenticated %}
|
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-nav-group">
|
|
|
|
|
<div class="v2-nav-label">— Prüfen</div>
|
2026-04-25 22:18:58 +02:00
|
|
|
<a href="/v2/neu" class="v2-nav-item {% if v2_active_nav == 'neu' %}active{% endif %}">{{ icon("file-plus", 14) }} Neuer Antrag</a>
|
2026-04-25 21:50:36 +02:00
|
|
|
{% if is_admin %}<a href="/v2/batch" class="v2-nav-item {% if v2_active_nav == 'batch' %}active{% endif %}">{{ icon("stack", 14) }} Batch-Analyse</a>{% endif %}
|
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>
|
|
|
|
|
|
|
|
|
|
<div class="v2-nav-group">
|
|
|
|
|
<div class="v2-nav-label">— Daten</div>
|
2026-04-25 22:18:58 +02:00
|
|
|
<a href="/auswertungen" class="v2-nav-item {% if v2_active_nav == 'auswertungen' %}active{% endif %}">{{ icon("chart-bar", 14) }} Auswertungen</a>
|
|
|
|
|
<a href="/api/auswertungen/export.csv" class="v2-nav-item">{{ icon("file-csv", 14) }} Export · API</a>
|
2026-04-25 22:34:55 +02:00
|
|
|
<a href="/v2/feed" class="v2-nav-item {% if v2_active_nav == 'feed' %}active{% endif %}">{{ icon("rss", 14) }} Atom-Feed</a>
|
|
|
|
|
<a href="/v2/abos" class="v2-nav-item {% if v2_active_nav == 'abos' %}active{% endif %}">{{ icon("envelope-simple", 14) }} Meine Abos</a>
|
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>
|
2026-04-25 22:18:58 +02:00
|
|
|
{% endif %}
|
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
|
|
|
|
2026-04-25 21:50:36 +02:00
|
|
|
{% if is_admin %}
|
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-nav-group">
|
|
|
|
|
<div class="v2-nav-label">— Administration</div>
|
|
|
|
|
<a href="/v2/admin/freischaltungen" class="v2-nav-item">{{ icon("user-check", 14) }} Freischaltungen</a>
|
|
|
|
|
<a href="/v2/admin/queue" class="v2-nav-item">{{ icon("list-checks", 14) }} Queue</a>
|
|
|
|
|
<a href="/v2/admin/abos" class="v2-nav-item">{{ icon("envelope-simple", 14) }} Abos</a>
|
|
|
|
|
</div>
|
|
|
|
|
{% endif %}
|
|
|
|
|
</nav>
|
|
|
|
|
</aside>
|
|
|
|
|
|
|
|
|
|
<header class="v2-topbar">
|
|
|
|
|
<button id="v2-menu-toggle" class="v2-menu-toggle" aria-label="Navigation öffnen">☰</button>
|
|
|
|
|
<span class="v2-topbar-spacer"></span>
|
|
|
|
|
<a href="/classic" class="v2-back-link">{{ icon("arrow-square-out", 13) }} Klassische Ansicht</a>
|
|
|
|
|
<a href="/methodik">{{ icon("info", 13) }} Methodik</a>
|
|
|
|
|
<a href="/quellen">{{ icon("book-open", 13) }} Quellen</a>
|
|
|
|
|
|
2026-04-25 21:50:36 +02:00
|
|
|
{# ── Globaler Bundesland-Selector ─────────────────────────────────── #}
|
|
|
|
|
<select id="v2-global-bl"
|
|
|
|
|
onchange="v2SetGlobalBl(this.value)"
|
|
|
|
|
aria-label="Bundesland wählen"
|
|
|
|
|
style="font-family:var(--font-mono);font-size:11px;padding:3px 6px;border:1px solid var(--ecg-light, var(--ecg-border));background:var(--ecg-card-bg);color:var(--ecg-dark);text-transform:uppercase;border-radius:3px;cursor:pointer;">
|
|
|
|
|
<option value="ALL">Bundesweit</option>
|
|
|
|
|
{% for bl in v2_bundeslaender %}<option value="{{ bl.code }}">{{ bl.code }}</option>{% endfor %}
|
|
|
|
|
</select>
|
|
|
|
|
|
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
|
|
|
{# ── Auth-Control — wird per JS nach /api/auth/me-Aufruf umgeschaltet ── #}
|
|
|
|
|
<div id="v2-auth-control" style="display:inline-flex;align-items:center;">
|
|
|
|
|
{# Platzhalter, bis initV2Auth() den Zustand kennt — unsichtbar #}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button id="v2-theme-toggle"
|
|
|
|
|
onclick="window.__v2CycleTheme && window.__v2CycleTheme()"
|
|
|
|
|
aria-label="Farbschema wechseln"
|
|
|
|
|
style="background:none;border:none;cursor:pointer;font-family:var(--font-mono);font-size:11px;color:var(--ecg-dark);letter-spacing:0.06em;text-transform:uppercase;opacity:0.75;padding:0;display:inline-flex;align-items:center;gap:4px;">
|
|
|
|
|
<span id="v2-theme-icon">{{ icon("circle-half", 14) }}</span><span id="v2-theme-label">Auto</span>
|
|
|
|
|
</button>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<main class="v2-main" id="v2-main">
|
|
|
|
|
{% block main %}{% endblock %}
|
|
|
|
|
</main>
|
|
|
|
|
|
|
|
|
|
<footer class="v2-footer">
|
|
|
|
|
<span>GWÖ-Antragsprüfer · Matrix 2.0 · CC BY 4.0</span>
|
|
|
|
|
<a href="/methodik">Methodik</a>
|
|
|
|
|
<a href="/quellen">Quellen</a>
|
|
|
|
|
<a href="/impressum">Impressum</a>
|
|
|
|
|
<a href="/datenschutz">Datenschutz</a>
|
|
|
|
|
<a href="https://repo.toppyr.de/tobias/gwoe-antragspruefer">Quellcode</a>
|
|
|
|
|
<span class="v2-topbar-spacer"></span>
|
|
|
|
|
<a href="/classic" style="color:var(--ecg-green);opacity:1;">Zurück zur klassischen Ansicht</a>
|
|
|
|
|
</footer>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
{% endblock %}
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
/* ── Dark-Mode Toggle ────────────────────────────────────────────── */
|
|
|
|
|
(function () {
|
|
|
|
|
const STORAGE_KEY = 'gwoe.theme';
|
|
|
|
|
const PREF_KEY = 'gwoe.ui';
|
|
|
|
|
const root = document.documentElement;
|
|
|
|
|
|
|
|
|
|
function applyTheme(theme) {
|
|
|
|
|
root.setAttribute('data-theme', theme);
|
|
|
|
|
localStorage.setItem(STORAGE_KEY, theme);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function cycleTheme() {
|
|
|
|
|
const current = localStorage.getItem(STORAGE_KEY) || 'auto';
|
|
|
|
|
const next = { auto: 'light', light: 'dark', dark: 'auto' }[current] || 'auto';
|
|
|
|
|
applyTheme(next);
|
|
|
|
|
updateToggleLabel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateToggleLabel() {
|
|
|
|
|
const labelEl = document.getElementById('v2-theme-label');
|
|
|
|
|
const iconEl = document.getElementById('v2-theme-icon');
|
|
|
|
|
if (!labelEl) return;
|
|
|
|
|
const current = localStorage.getItem(STORAGE_KEY) || 'auto';
|
|
|
|
|
const labels = { auto: 'Auto', light: 'Hell', dark: 'Dunkel' };
|
|
|
|
|
const icons = {
|
|
|
|
|
auto: 'circle-half',
|
|
|
|
|
light: 'sun',
|
|
|
|
|
dark: 'moon'
|
|
|
|
|
};
|
|
|
|
|
labelEl.textContent = labels[current] || 'Auto';
|
|
|
|
|
if (iconEl) {
|
|
|
|
|
const iconName = icons[current] || 'circle-half';
|
|
|
|
|
iconEl.dataset.icon = iconName;
|
|
|
|
|
// Replace icon SVG dynamically via fetch (icons are static files)
|
|
|
|
|
fetch('/static/v2/icons/phosphor/' + iconName + '.svg')
|
|
|
|
|
.then(r => r.text())
|
|
|
|
|
.then(svg => { iconEl.innerHTML = svg; })
|
|
|
|
|
.catch(() => {});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Restore stored theme
|
|
|
|
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
|
|
|
if (stored) applyTheme(stored);
|
|
|
|
|
|
|
|
|
|
window.__v2CycleTheme = cycleTheme;
|
|
|
|
|
document.addEventListener('DOMContentLoaded', updateToggleLabel);
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
/* ── UI Preference (v2 = Default) ───────────────────────────────── */
|
|
|
|
|
/* AUTO-REDIRECT DEAKTIVIERT — er verursacht Loop mit aggressivem classic-localStorage-Set.
|
|
|
|
|
Umschalter via Topbar-Link „Klassische Ansicht" reicht als Opt-Out. */
|
|
|
|
|
(function () {
|
|
|
|
|
// Alte Preference-Spuren löschen, damit niemand festklebt
|
|
|
|
|
localStorage.removeItem('gwoe.ui');
|
|
|
|
|
return;
|
|
|
|
|
// dead code weiter unten, bewusst belassen für Nachvollziehbarkeit
|
|
|
|
|
// Wenn Nutzer:in zuvor explizit "classic" gewählt hat, zu /classic weiterleiten.
|
|
|
|
|
// gwoe.ui='classic' wird von index.html gesetzt, wenn man /classic besucht.
|
|
|
|
|
// Nach Rückkehr via "Zum neuen Design"-Link überschreibt v2 das localStorage,
|
|
|
|
|
// damit die Präferenz für den nächsten Tab-Start korrekt ist.
|
|
|
|
|
var pref = localStorage.getItem('gwoe.ui');
|
|
|
|
|
if (pref === 'classic') {
|
|
|
|
|
// Einmal weiterleiten; danach bleibt Nutzer:in auf v2 (kein Loop)
|
|
|
|
|
localStorage.removeItem('gwoe.ui');
|
|
|
|
|
window.location.replace('/classic');
|
|
|
|
|
} else {
|
|
|
|
|
localStorage.setItem('gwoe.ui', 'v2');
|
|
|
|
|
}
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
/* ── Mobile Sidebar Toggle ───────────────────────────────────────── */
|
|
|
|
|
(function () {
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
|
|
const toggle = document.getElementById('v2-menu-toggle');
|
|
|
|
|
const sidebar = document.getElementById('v2-sidebar');
|
|
|
|
|
const overlay = document.getElementById('v2-overlay');
|
|
|
|
|
|
|
|
|
|
if (!toggle || !sidebar || !overlay) return;
|
|
|
|
|
|
|
|
|
|
toggle.addEventListener('click', function () {
|
|
|
|
|
sidebar.classList.toggle('open');
|
|
|
|
|
overlay.classList.toggle('open');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
overlay.addEventListener('click', function () {
|
|
|
|
|
sidebar.classList.remove('open');
|
|
|
|
|
overlay.classList.remove('open');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
})();
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
{% block body_scripts %}{% endblock %}
|
|
|
|
|
|
2026-04-25 21:50:36 +02:00
|
|
|
{# ── Globaler BL-Selector — Persistenz + Event ───────────────────────────── #}
|
|
|
|
|
<script>
|
|
|
|
|
(function () {
|
|
|
|
|
var BL_KEY = 'gwoe.bl';
|
|
|
|
|
|
|
|
|
|
window.v2SetGlobalBl = function (code) {
|
|
|
|
|
try { localStorage.setItem(BL_KEY, code); } catch (_) {}
|
|
|
|
|
window.dispatchEvent(new CustomEvent('v2-bl-changed', { detail: { bl: code } }));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
window.v2GetGlobalBl = function () {
|
|
|
|
|
try { return localStorage.getItem(BL_KEY) || 'ALL'; } catch (_) { return 'ALL'; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
|
|
var sel = document.getElementById('v2-global-bl');
|
|
|
|
|
if (sel) sel.value = window.v2GetGlobalBl();
|
|
|
|
|
});
|
|
|
|
|
})();
|
|
|
|
|
</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
|
|
|
{# ── Auth Modal (global, einmal pro Seite) ────────────────────────────── #}
|
|
|
|
|
{% include "v2/components/auth_modal.html" %}
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
/* ── v2 Auth-State — Topbar-Control ─────────────────────────────────── */
|
|
|
|
|
(function () {
|
|
|
|
|
|
|
|
|
|
var TOPBAR_CONTROL_ID = 'v2-auth-control';
|
|
|
|
|
|
|
|
|
|
var BTN_BASE = [
|
|
|
|
|
'background:none',
|
|
|
|
|
'border:none',
|
|
|
|
|
'cursor:pointer',
|
|
|
|
|
'font-family:var(--font-sans)',
|
|
|
|
|
'font-size:11px',
|
|
|
|
|
'color:var(--ecg-dark)',
|
|
|
|
|
'letter-spacing:0.06em',
|
|
|
|
|
'text-transform:uppercase',
|
|
|
|
|
'opacity:0.75',
|
|
|
|
|
'padding:0',
|
|
|
|
|
'display:inline-flex',
|
|
|
|
|
'align-items:center',
|
|
|
|
|
'gap:4px'
|
|
|
|
|
].join(';');
|
|
|
|
|
|
|
|
|
|
function renderUnauthenticated(container) {
|
|
|
|
|
container.innerHTML =
|
|
|
|
|
'<button style="' + BTN_BASE + '" onclick="v2AuthModalOpen()" aria-label="Anmelden">' +
|
|
|
|
|
'{{ icon("key", 13) | replace("\"", "\'") }} Anmelden' +
|
|
|
|
|
'</button>';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function renderAuthenticated(container, user) {
|
|
|
|
|
var name = user.preferred_username || user.name || user.sub || 'Konto';
|
|
|
|
|
container.innerHTML =
|
|
|
|
|
'<span style="' + BTN_BASE + ';cursor:default;gap:4px;">' +
|
|
|
|
|
'{{ icon("user", 13) | replace("\"", "\'") }} ' +
|
|
|
|
|
'<span style="max-width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="' + name + '">' + name + '</span>' +
|
|
|
|
|
'</span>' +
|
|
|
|
|
' ' +
|
|
|
|
|
'<button style="' + BTN_BASE + '" onclick="v2AuthLogout()" aria-label="Abmelden">' +
|
|
|
|
|
'{{ icon("sign-out", 13) | replace("\"", "\'") }} Abmelden' +
|
|
|
|
|
'</button>';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function initV2Auth() {
|
|
|
|
|
var container = document.getElementById(TOPBAR_CONTROL_ID);
|
|
|
|
|
if (!container) return;
|
|
|
|
|
try {
|
|
|
|
|
var resp = await fetch('/api/auth/me');
|
|
|
|
|
var data = await resp.json();
|
|
|
|
|
if (data && data.authenticated) {
|
|
|
|
|
renderAuthenticated(container, data);
|
|
|
|
|
} else {
|
|
|
|
|
renderUnauthenticated(container);
|
|
|
|
|
}
|
|
|
|
|
} catch (_) {
|
|
|
|
|
renderUnauthenticated(container);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function logout() {
|
|
|
|
|
// Server-seitig Cookies löschen (HttpOnly → client-side nicht möglich)
|
|
|
|
|
try {
|
|
|
|
|
await fetch('/api/auth/logout', { method: 'POST', credentials: 'same-origin' });
|
|
|
|
|
} catch (e) { /* ignore, reload trotzdem */ }
|
|
|
|
|
location.reload();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.v2AuthLogout = logout;
|
|
|
|
|
document.addEventListener('DOMContentLoaded', initV2Auth);
|
|
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
</script>
|
2026-04-25 21:50:36 +02:00
|
|
|
|
feat(v2): Feedback-Widget mit Audit-Trail + Screenshot + direkter Gitea-Anbindung
- Component v2/components/feedback_widget.html: Button unten links oberhalb der
Queue, Klick oeffnet Modal mit vorausgefuellten Kontext-Feldern (URL,
Drucksache, Viewport, User-Agent, letzte 15 Klicks, letzte 10 Console-Errors,
letzte 5 Page-Loads). Eingaben: Titel, Beschreibung, optional Screenshot
- Audit-Trail-Sammler in localStorage (Ringbuffer 30 Klicks, 10 Errors)
- Screenshot via self-hosted html2canvas 1.4.1 (194 KB unter app/static/v2/lib/)
- Backend POST /api/feedback (rate-limit 5/h):
- validiert + html-strippt Inputs
- erstellt Gitea-Issue per API mit Label 'feedback' (Label wird idempotent angelegt)
- laedt Screenshot als Issue-Asset hoch (Gitea Issue-Attachment-API)
- 4 neue Settings: gitea_token, gitea_api_url, gitea_repo_owner, gitea_repo_name
- Server .env um GITEA_TOKEN ergaenzt
- 10 neue Unit-Tests (mit gemocktem httpx)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 01:00:44 +02:00
|
|
|
{# Feedback/Bug-Report-Widget — öffnet Gitea-Issues direkt aus dem Browser #}
|
|
|
|
|
{% include "v2/components/feedback_widget.html" %}
|
|
|
|
|
|
2026-04-25 21:50:36 +02:00
|
|
|
{# Queue-Statusbar mit Hover-Tooltip — analog zu classic-UI (#149) #}
|
|
|
|
|
{% include "v2/components/queue_widget.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
|
|
|
</body>
|
|
|
|
|
</html>
|