gwoe-antragspruefer/app/templates/v3/screens/antrag_detail.html
Dotty Dotter 4de2df9cea feat(v3): single-column Restructure — neue Reihenfolge, CD-konforme Radien
User-Spec: 1a (single column überall), CD-Rundungen subtil 2-4 px,
keine 8px-Pills, keine Kreise. v3 wird nach Reife der neue Default.

Reihenfolge:
1. Metadaten/Titel
2. Zusammenfassung
3. Bewertung — Score xl + Empfehlung daneben + verdict_body voll breit
4. Merken + Bewertung treffend
5. Matrix 5×5 (volle Profi-Variante mit Klick-Modal)
6. Programm-Treue — pro Partei: WP-Zeile + PP-Zeile (default closed),
   Klick auf die Zeile expandiert Begründung + Belege. Score-Chip
   rechtsbündig.
7. Verbesserungsvorschläge — volle Breite, kein max-width
8. Abstimmungsergebnis — Plenum + namentliche Abstimmung
9. Rest — PDF/Teilen/Re-analyze/Historie + Stärken/Schwächen +
   Konsistenz-Hinweis + Marker-Legende + News-Box + Kommentare

v2-Templates unangetastet (Sub-Blocks vom letzten Commit beibehalten,
nur main-Block wird in v3 komplett überschrieben). v2-JS-Handler
bleiben funktionsfähig — gleiche DOM-IDs (v2-merkliste-btn, v2-vote-up,
v2-comments-list, v2-matrix-field-modal, …) im neuen Layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:51:33 +02:00

458 lines
20 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{# ─────────────────────────────────────────────────────────────────────
v3/screens/antrag_detail.html — Bürger:innen-Modus, single column
Override-Strategie: extendet v2/screens/antrag_detail.html und
ersetzt nur `block main` komplett. body_scripts erbt via super(), so
dass alle v2-JS-Handler (vote, merkliste, share, comments, history,
matrix-modal) ohne Code-Duplikation weiterlaufen — sie hängen sich an
DOM-IDs (v2-vote-up, v2-merkliste-btn, v2-comments-list, …), die wir
in der neuen Layout-Reihenfolge wiederverwenden.
Reihenfolge (single column):
1. Metadaten/Titel
2. Zusammenfassung
3. Bewertung (Score xl + Empfehlung daneben + Begründung darunter)
4. Merken / Bewertung treffend
5. Matrix 5×5
6. Programm-Treue (default-closed Klappmechanismus pro Programm)
7. Verbesserungsvorschläge (volle Breite, nicht kollabiert)
8. Abstimmungsergebnis
9. Rest: PDF/Teilen/Neu/Historie + Stärken/Schwächen + Konsistenz +
Marker-Legende + News + Kommentare
───────────────────────────────────────────────────────────────────── #}
{% extends "v2/screens/antrag_detail.html" %}
{% from "v2/components/score_hero.html" import score_hero %}
{% from "v2/components/matrix_mini.html" import matrix_mini %}
{% from "v2/components/quote_card.html" import quote_card %}
{% from "v2/components/redline.html" import redline %}
{% block head_extra %}
{{ super() }}
<link rel="stylesheet" href="/static/v3/v3.css?v={{ app_version|default('1') }}">
{% endblock %}
{% block main %}
{% if error is defined and error %}
<div class="v2-kasten" style="border-color:var(--redline-contra);margin-top:32px;">
<h3 style="color:var(--redline-contra);">Antrag nicht gefunden</h3>
<p>{{ error }}</p>
<p><a href="/">← Zurück zur Übersicht</a></p>
</div>
{% elif antrag is defined and antrag %}
<div class="v3-page">
<p class="v3-back">
<a href="/">← Zurück zur Übersicht</a>
</p>
{# 1 ── Metadaten + Titel ─────────────────────────────────────────── #}
<section class="v3-section v3-meta">
<div class="v3-antrag-id">
{{ antrag.bundesland | default("") }}
{% if antrag.drucksache %} · Drs. {{ antrag.drucksache }}{% endif %}
{% if antrag.typ %} · {{ antrag.typ }}{% endif %}
{% if antrag.datum %} · eingebracht {{ antrag.datum }}{% endif %}
</div>
<h1 class="v3-title">{{ antrag.title | default("Antrag") }}</h1>
{% if antrag.parteien or antrag.analysiert %}
<div class="v3-byline">
{% if antrag.parteien %}Eingebracht von {{ antrag.parteien | join(", ") }}{% endif %}
{% if antrag.analysiert %} — Analyse {{ antrag.analysiert }}{% endif %}
{% if antrag.modell %}, {{ antrag.modell }}{% endif %}
{% if antrag.zitate_count %} · {{ antrag.zitate_count }} Zitat{{ "e" if antrag.zitate_count != 1 else "" }} verifiziert{% endif %}
</div>
{% endif %}
</section>
{# 2 ── Zusammenfassung ───────────────────────────────────────────── #}
{% if antrag.zusammenfassung %}
<section class="v3-section">
<h3 class="v3-h3">Zusammenfassung</h3>
<p class="v3-prose">{{ antrag.zusammenfassung }}</p>
</section>
{% endif %}
{# 3 ── Bewertung ─────────────────────────────────────────────────── #}
<section class="v3-section v3-bewertung">
{% set s = (antrag.score | default(0)) | float %}
<div class="v3-bewertung-head">
<div class="v3-score-num">
{{ "%.1f"|format(s) }}<span class="v3-score-slash">/10</span>
</div>
{% if antrag.verdict_title %}
<div class="v3-empfehlung
{% if s >= 7 %}good{% elif s >= 4 %}mid{% else %}low{% endif %}">
{{ antrag.verdict_title }}
</div>
{% endif %}
</div>
{% if antrag.verdict_body %}
<p class="v3-bewertung-body">{{ antrag.verdict_body }}</p>
{% endif %}
</section>
{# 4 ── Merken + Bewertung treffend (User-Aktionen) ──────────────── #}
<section class="v3-section v3-userrow">
<button id="v2-merkliste-btn" onclick="v2DetailMerklisteToggle()" class="v3-action-btn">
<span id="v2-merkliste-star"></span>
<span id="v2-merkliste-label">Merken</span>
</button>
<div class="v3-userrow-vote">
<span class="v3-userrow-label">Bewertung treffend?</span>
<div id="v2-vote-overall" class="v3-vote-buttons">
<button id="v2-vote-up" onclick="v2DetailCastVote('{{ antrag.drucksache | e }}','up')" class="v3-action-btn">
👍 <span id="v2-vote-up-count">0</span>
</button>
<button id="v2-vote-down" onclick="v2DetailCastVote('{{ antrag.drucksache | e }}','down')" class="v3-action-btn">
👎 <span id="v2-vote-down-count">0</span>
</button>
</div>
</div>
</section>
{# 5 ── Matrix 5×5 (volle Profi-Variante, mit Klick-Modal) ────────── #}
{% if antrag.matrix %}
<section class="v3-section">
<h3 class="v3-h3">Matrix 2.0 · 25 Felder</h3>
{{ matrix_mini(antrag.matrix) }}
</section>
{% endif %}
{# 6 ── Programm-Treue ─────────────────────────────────────────────── #}
{% if antrag.fraktions_scores %}
<section class="v3-section">
<h3 class="v3-h3">Programm-Treue pro Fraktion</h3>
<div class="v3-fraktionen">
{% for fs in antrag.fraktions_scores %}
<div class="v3-fraktion">
<div class="v3-fraktion-head">
<span class="v3-fraktion-name">{{ fs.fraktion }}</span>
{% if fs.ist_antragsteller %}<span class="v3-pill v3-pill-antrag">Antragsteller:in</span>{% endif %}
{% if fs.ist_regierung %}<span class="v3-pill v3-pill-reg">Regierungsfraktion</span>{% endif %}
</div>
{% for prog_key, prog_label in [("wahlprogramm","Wahlprogramm"),("parteiprogramm","Parteiprogramm")] %}
{% set p = fs[prog_key] %}
{% set p_score = p.score | float %}
<details class="v3-prog">
<summary class="v3-prog-row">
<span class="v3-prog-label">{{ prog_label }}</span>
<span class="v3-prog-spacer"></span>
<span class="v3-prog-score
{% if p_score >= 7 %}good{% elif p_score >= 4 %}mid{% else %}low{% endif %}">{{ "%.0f"|format(p_score) }}/10</span>
</summary>
<div class="v3-prog-body">
{% if p.begruendung %}<p class="v3-prog-text">{{ p.begruendung }}</p>{% endif %}
{% if p.zitate %}
<div class="v3-prog-zitate">
{% for z in p.zitate %}
{{ quote_card(z.text, z.source, True, False, z.pdf_href) }}
{% endfor %}
</div>
{% endif %}
</div>
</details>
{% endfor %}
</div>
{% endfor %}
</div>
</section>
{% endif %}
{# 7 ── Verbesserungsvorschläge — volle Breite, nicht kollabiert ───── #}
{% if antrag.verbesserungen %}
<section class="v3-section v3-verbesserungen">
<h3 class="v3-h3">Verbesserungsvorschläge</h3>
{% for v in antrag.verbesserungen %}
<div class="v3-verbesserung">
{% if antrag.verbesserungen | length > 1 %}
<div class="v3-verbesserung-num">Vorschlag {{ loop.index }} von {{ antrag.verbesserungen | length }}</div>
{% endif %}
{% if v.segments %}
{{ redline(original=v.original | default(""), segments=v.segments) }}
{% else %}
{{ redline(original=v.original | default(""), vorschlag=v.vorschlag | default("")) }}
{% endif %}
{% if v.begruendung %}
<p class="v3-verbesserung-begr">{{ v.begruendung }}</p>
{% endif %}
</div>
{% endfor %}
</section>
{% elif antrag.redline and antrag.redline.segments %}
<section class="v3-section v3-verbesserungen">
<h3 class="v3-h3">Verbesserungsvorschlag</h3>
{{ redline(segments=antrag.redline.segments) }}
</section>
{% endif %}
{# 8 ── Abstimmungsergebnis (Plenum + namentlich) ──────────────────── #}
{% if antrag.plenum_votes %}
<section class="v3-section v3-vote-section">
<h3 class="v3-h3">Abstimmungsergebnis</h3>
{% set ergebnis_color = {
"angenommen":"#2da44e","abgelehnt":"#cf222e","überwiesen":"#0969da",
"zurückgezogen":"#8250df","bestätigt":"#2da44e","sammel":"#0969da",
} %}
{% for v in antrag.plenum_votes %}
<div class="v3-vote-card">
<div class="v3-vote-card-head">
<span class="v3-vote-ergebnis" style="color:{{ ergebnis_color.get(v.ergebnis, '#6e7781') }};">
{{ v.ergebnis | capitalize }}{% if v.einstimmig %} · einstimmig{% endif %}
</span>
{% if v.quelle_url %}
<a href="{{ v.quelle_url }}" target="_blank" rel="noopener" class="v3-vote-quelle"
title="Plenarprotokoll im neuen Tab öffnen">
{{ v.quelle_protokoll }} ↗
</a>
{% else %}
<span class="v3-vote-quelle">{{ v.quelle_protokoll }}</span>
{% endif %}
</div>
{% if v.fraktionen_ja or v.fraktionen_nein or v.fraktionen_enthaltung %}
{% set _n_ja = v.fraktionen_ja | length %}
{% set _n_nein = v.fraktionen_nein | length %}
{% set _n_enth = v.fraktionen_enthaltung | length %}
{% set _n_total = _n_ja + _n_nein + _n_enth %}
{% if _n_total > 0 %}
<div class="v3-vote-bar"
title="Fraktions-Mehrheit: {{ _n_ja }} Ja · {{ _n_nein }} Nein · {{ _n_enth }} Enth.">
{% if _n_ja %}<div class="v3-vote-bar-ja" style="width:{{ (100 * _n_ja / _n_total) }}%;"></div>{% endif %}
{% if _n_enth %}<div class="v3-vote-bar-enth" style="width:{{ (100 * _n_enth / _n_total) }}%;"></div>{% endif %}
{% if _n_nein %}<div class="v3-vote-bar-nein" style="width:{{ (100 * _n_nein / _n_total) }}%;"></div>{% endif %}
</div>
<div class="v3-vote-bar-caption">
{{ _n_ja }}/{{ _n_total }} Fraktionen Ja · {{ _n_nein }} Nein · {{ _n_enth }} Enth.
</div>
{% endif %}
<div class="v3-vote-pills">
{% if v.fraktionen_ja %}
<div><span class="v3-vote-side ja">Ja:</span>
{% for f in v.fraktionen_ja %}
{% set _opp = opportunismus_score(f, antrag.fraktions_scores) %}
<span class="v3-vote-pill ja">{{ f }}{% if _opp is not none %}<span class="v3-marker opp" tabindex="0" role="button" title="Opportunismus-Marker — Ja trotz schwacher Wahlprogramm-Übereinstimmung (WP-Score {{ '%.0f' | format(_opp) }}/10).">!</span>{% endif %}</span>
{% endfor %}
</div>
{% endif %}
{% if v.fraktionen_nein %}
<div><span class="v3-vote-side nein">Nein:</span>
{% for f in v.fraktionen_nein %}
{% set _wp = heuchelei_score(f, antrag.fraktions_scores) %}
<span class="v3-vote-pill nein">{{ f }}{% if _wp is not none %}<span class="v3-marker heuchelei" tabindex="0" role="button" title="Heuchelei-Marker — Nein trotz hoher Wahlprogramm-Übereinstimmung (WP-Score {{ '%.0f' | format(_wp) }}/10)."></span>{% endif %}</span>
{% endfor %}
</div>
{% endif %}
{% if v.fraktionen_enthaltung %}
<div><span class="v3-vote-side enth">Enth.:</span>
{% for f in v.fraktionen_enthaltung %}<span class="v3-vote-pill enth">{{ f }}</span>{% endfor %}
</div>
{% endif %}
</div>
{% endif %}
</div>
{% endfor %}
<div class="v3-vote-source">Quelle: Plenarprotokoll · automatisch extrahiert</div>
</section>
{% endif %}
{% if antrag.abstimmungsverhalten %}
{% set aw = antrag.abstimmungsverhalten %}
<section class="v3-section">
<h3 class="v3-h3">Namentliche Abstimmung</h3>
<div class="v3-namentlich">
<div>{{ aw.protokoll | default("") }}{% if aw.datum %} · {{ aw.datum }}{% endif %}</div>
{% if aw.abstimmung %}
<div>{{ aw.abstimmung.ja | default(0) }} Ja · {{ aw.abstimmung.nein | default(0) }} Nein · {{ aw.abstimmung.enthaltung | default(0) }} Enthaltung</div>
{% endif %}
</div>
</section>
{% endif %}
{# ════════════════ 9 ── REST-Block ════════════════════════════════════ #}
<section class="v3-rest">
{# 9a Aktions-Links #}
<div class="v3-rest-aktions">
<a href="/api/assessment/pdf?drucksache={{ antrag.drucksache | urlencode }}">PDF-Bericht</a>
<a href="/api/assessment?drucksache={{ antrag.drucksache | urlencode }}">JSON-Export</a>
<a href="/antrag/{{ antrag.drucksache }}">Permalink</a>
</div>
{# 9b Teilen #}
<div class="v3-rest-block">
<h3 class="v3-h3">Teilen</h3>
<div class="v3-share-buttons">
<button onclick="v2DetailShareCopy()" class="v3-action-btn">📋 Kopieren</button>
<button onclick="v2DetailShare('threads')" class="v3-action-btn">Threads</button>
<button onclick="v2DetailShareMastodon()" class="v3-action-btn">Mastodon</button>
<button onclick="v2DetailShare('linkedin')" class="v3-action-btn">LinkedIn</button>
<button onclick="v2DetailShareEmail()" class="v3-action-btn">📧 E-Mail</button>
<button onclick="v2DetailShareImage()" class="v3-action-btn">🖼 Bild</button>
</div>
</div>
{# 9c Neu analysieren #}
<div class="v3-rest-block">
<button id="v2-reanalyze-btn" onclick="v2DetailReAnalyze(this)" class="v3-action-btn v3-action-muted">
Neu analysieren
</button>
</div>
{# 9d Bewertungs-Historie #}
<div class="v3-rest-block">
<h3 class="v3-h3">Bewertungs-Historie</h3>
<div id="v2-history-list">
<span class="v3-loading">Lade…</span>
</div>
</div>
{# 9e Stärken / Schwächen #}
{% if antrag.staerkster_wert and antrag.staerkster_wert.text %}
<div class="v2-kasten outline-green">
<h4>Stärkster Wert{% if antrag.staerkster_wert.titel %} — {{ antrag.staerkster_wert.titel }}{% endif %}</h4>
<p>{{ antrag.staerkster_wert.text }}</p>
</div>
{% elif antrag.staerken %}
<div class="v2-kasten outline-green">
<h4>Stärken</h4>
<ul>
{% for s in antrag.staerken %}<li>{{ s }}</li>{% endfor %}
</ul>
</div>
{% endif %}
{% if antrag.schwaechster_wert and antrag.schwaechster_wert.text %}
<div class="v2-kasten outline-blue">
<h4>Schwächster Wert{% if antrag.schwaechster_wert.titel %} — {{ antrag.schwaechster_wert.titel }}{% endif %}</h4>
<p>{{ antrag.schwaechster_wert.text }}</p>
</div>
{% elif antrag.schwaechen %}
<div class="v2-kasten outline-blue">
<h4>Schwächen</h4>
<ul>
{% for s in antrag.schwaechen %}<li>{{ s }}</li>{% endfor %}
</ul>
</div>
{% endif %}
{# 9f Konsistenz-Hinweis #}
{% if antrag.plenum_votes %}
{% set _state = consistency_state(antrag.verdict_title, antrag.plenum_votes) %}
{% set _decisive = decisive_outcome(antrag.plenum_votes) %}
{% if _state %}
<div class="v3-konsistenz {{ _state }}">
<strong>{% if _state == 'conflict' %}Mehrheit kontra GWÖ-Empfehlung{% else %}Mehrheit deckt sich mit GWÖ-Empfehlung{% endif %}</strong>
— Empfohlen: <em>{{ antrag.verdict_title }}</em>; Beschluss: <em>{{ _decisive | capitalize }}</em>.
</div>
{% endif %}
{% endif %}
{# 9g Marker-Legende — nur wenn ⚠ oder ! im Vote-Block vorkam #}
{% set _legende = namespace(heuchelei=false, opp=false) %}
{% for vv in (antrag.plenum_votes or []) %}
{% for f in (vv.fraktionen_nein or []) %}
{% if heuchelei_score(f, antrag.fraktions_scores) is not none %}{% set _legende.heuchelei = true %}{% endif %}
{% endfor %}
{% for f in (vv.fraktionen_ja or []) %}
{% if opportunismus_score(f, antrag.fraktions_scores) is not none %}{% set _legende.opp = true %}{% endif %}
{% endfor %}
{% endfor %}
{% if _legende.heuchelei or _legende.opp %}
<div class="v3-marker-legend">
{% if _legende.heuchelei %}
<div><span class="v3-marker heuchelei"></span> <strong>Heuchelei:</strong> Nein trotz hoher Wahlprogramm-Übereinstimmung (WP&nbsp;&nbsp;7/10).</div>
{% endif %}
{% if _legende.opp %}
<div><span class="v3-marker opp">!</span> <strong>Opportunismus:</strong> Ja trotz schwacher Wahlprogramm-Übereinstimmung (WP&nbsp;&lt;&nbsp;3/10).</div>
{% endif %}
</div>
{% endif %}
{# 9h News-Box (per JS gefuellt) #}
<div id="ad-news-box" class="v3-news-box" style="display:none;">
<h3 class="v3-h3">Aktuelle News passend zu diesem Antrag</h3>
<p class="v3-news-meta">Embedding-Match aus den letzten 90 Tagen. Quelle: Tagesschau-API + Bundestag-RSS.</p>
<div id="ad-news-list">
<div class="v3-loading">Lade …</div>
</div>
</div>
{# 9i Kommentare #}
<div class="v3-rest-block v3-comments">
<h3 class="v3-h3">Kommentare</h3>
<div id="v2-comments-list">
<span class="v3-loading">Lade…</span>
</div>
<div id="v2-comment-form" style="display:none;">
<div class="v3-comment-label">Kommentar hinzufügen</div>
<textarea id="v2-comment-input" rows="3" placeholder="Kommentar…" class="v3-comment-textarea"></textarea>
<div class="v3-comment-controls">
<select id="v2-comment-visibility" class="v3-comment-vis">
<option value="all">Öffentlich</option>
<option value="authenticated">Nur Angemeldete</option>
<option value="private">Nur ich</option>
</select>
<button onclick="v2DetailAddComment('{{ antrag.drucksache | e }}')" class="v3-action-btn primary">Absenden</button>
</div>
</div>
<div id="v2-comment-login-hint" style="display:none;">
<button onclick="v2AuthModalOpen()" class="v3-action-btn">Anmelden um zu kommentieren</button>
</div>
</div>
</section>{# v3-rest #}
{# ════════════════ Modals ═════════════════════════════════════════════ #}
{# Matrix-Feld-Info-Modal — gleiche IDs wie v2, JS aus super() greift #}
<div id="v2-matrix-field-modal"
role="dialog" aria-modal="true" aria-label="Matrix-Feld Erklärung"
class="v3-modal"
onclick="if(event.target===this)this.style.display='none'">
<div class="v3-modal-card">
<div class="v3-modal-head">
<strong id="v2-matrix-field-title" class="v3-modal-title"></strong>
<span id="v2-matrix-field-rating" class="v3-modal-rating"></span>
<button onclick="document.getElementById('v2-matrix-field-modal').style.display='none'"
class="v3-modal-close" aria-label="Schließen">×</button>
</div>
<div id="v2-matrix-field-antrag" class="v3-modal-section" style="display:none;">
<div class="v3-modal-sublabel">Bewertung in diesem Antrag</div>
<div id="v2-matrix-field-label" class="v3-modal-itemlabel"></div>
<div id="v2-matrix-field-aspect" class="v3-modal-itemtext"></div>
</div>
<div class="v3-modal-section v3-modal-section--bordered">
<div class="v3-modal-sublabel">Was misst dieses Feld?</div>
<p id="v2-matrix-field-text" class="v3-modal-itemtext"></p>
</div>
</div>
</div>
</div>{# .v3-page #}
{% endif %}{# antrag #}
{% endblock %}
{% block body_scripts %}
{{ super() }}
<script>
/* v3-Topbar-Pill + Toggle zurueck zu Profi-Modus */
(function () {
var bar = document.querySelector('.v2-topbar');
if (!bar) return;
var pill = document.createElement('span');
pill.className = 'v3-beta-badge';
pill.textContent = 'Bürger:innen-Modus · Beta';
pill.title = 'Vereinfachte Ansicht. v3 ist eine frühe Vorschau.';
var toggle = document.createElement('a');
toggle.className = 'v3-modus-toggle';
toggle.href = '/antrag/' + encodeURIComponent({{ antrag.drucksache | tojson if antrag is defined and antrag else '""' | safe }});
toggle.textContent = '→ Profi-Modus';
toggle.title = 'Volle GWÖ-Detailansicht (v2) öffnen';
bar.appendChild(pill);
bar.appendChild(toggle);
})();
</script>
{% endblock %}