gwoe-antragspruefer/app/templates/v3/screens/antrag_detail.html

303 lines
13 KiB
HTML
Raw Normal View History

{# ─────────────────────────────────────────────────────────────────────
v3/screens/antrag_detail.html — Bürger:innen-Modus
Override-Strategie: extendet v2-Screen, ersetzt nur die Sub-Blocks,
die in v3 vereinfacht werden. Block-Liste:
- antrag_id_section — entschärfte Drucksache-Sprache mit Glossar
- score_hero_section — Wort-Etikett groß, Zahl klein darunter
- matrix_section — 5 Werte default + <details> für 5×5
- verbesserungen_section — default kollabiert
- aktions_section — JSON-Export raus, nur PDF + Permalink
- comments_section — default kollabiert
───────────────────────────────────────────────────────────────────── #}
{% extends "v2/screens/antrag_detail.html" %}
{% block head_extra %}
{{ super() }}
<link rel="stylesheet" href="/static/v3/v3.css?v={{ app_version|default('1') }}">
{% endblock %}
{# ─── 1. Drucksache-ID: weniger Behörden-Sprache, Glossar-Hinweise ─── #}
{% block antrag_id_section %}
<div class="v2-antrag-id v3-antrag-id">
Antrag im
{% if antrag.bundesland == "BU" %}Bundestag
{% elif antrag.bundesland %}Landtag {{ antrag.bundesland }}
{% else %}Parlament{% endif %}
{% if antrag.drucksache %}
· <span class="v3-glossar" data-glossar="drucksache" tabindex="0" role="button"
aria-label="Glossar: Drucksache">Drucksache</span>
{{ antrag.drucksache }}
{% endif %}
{% if antrag.datum %} · eingebracht {{ antrag.datum }}{% endif %}
</div>
{% endblock %}
{# ─── 2. Score-Hero: Wort-Etikett groß, Zahl klein ──────────────────── #}
{% block score_hero_section %}
{% set s = (antrag.score | default(0)) | float %}
{% if s >= 7 %}
{% set v3_label = antrag.verdict_title or "Stark gemeinwohlfördernd" %}
{% set v3_class = "good" %}
{% elif s >= 4 %}
{% set v3_label = antrag.verdict_title or "Gemischt" %}
{% set v3_class = "mid" %}
{% else %}
{% set v3_label = antrag.verdict_title or "Widerspricht dem Gemeinwohl" %}
{% set v3_class = "low" %}
{% endif %}
<div class="v3-score-hero {{ v3_class }}"
role="region" aria-label="Bewertung: {{ v3_label }} ({{ '%.1f'|format(s) }} von 10)">
<div class="v3-score-label">{{ v3_label }}</div>
{% if antrag.verdict_body %}
<div class="v3-score-body">{{ antrag.verdict_body }}</div>
{% endif %}
<div class="v3-score-meta">
<span class="v3-glossar" data-glossar="gwoe-score" tabindex="0" role="button"
aria-label="Glossar: GWÖ-Score">Gemeinwohl-Score</span>:
<strong>{{ "%.1f"|format(s) }} von 10</strong>
</div>
</div>
{% endblock %}
{# ─── 3. Matrix: 5 Werte default, volle 5×5 in <details> ─────────────── #}
{% block matrix_section %}
{% if antrag.matrix %}
<h3 class="v2-h3">Beitrag zu den 5 Gemeinwohl-Werten</h3>
{# Pro Wert (Spalte 1..5) Durchschnitt aus den 5 Berührungsgruppen-Zellen.
Skala bleibt -5..+5 wie in der DB. #}
{% set v3_werte = [
("1", "Menschenwürde"),
("2", "Solidarität"),
("3", "Ökologische Nachhaltigkeit"),
("4", "Soziale Gerechtigkeit"),
("5", "Transparenz & Demokratie"),
] %}
<div class="v3-werte-list">
{% for col, label in v3_werte %}
{% set ns = namespace(sum=0, cnt=0) %}
{% for row in ["A","B","C","D","E"] %}
{% set cell = antrag.matrix[row ~ col] | default(none) %}
{% if cell %}
{% set ns.sum = ns.sum + (cell.rating | int) %}
{% set ns.cnt = ns.cnt + 1 %}
{% endif %}
{% endfor %}
{% set avg = (ns.sum / ns.cnt) if ns.cnt else 0 %}
{% set pct = ((avg + 5) / 10 * 100) %}
<div class="v3-wert-row">
<div class="v3-wert-label">{{ label }}</div>
<div class="v3-wert-bar" aria-hidden="true">
<div class="v3-wert-track">
<div class="v3-wert-mid"></div>
<div class="v3-wert-fill {% if avg >= 1 %}pos{% elif avg <= -1 %}neg{% else %}neu{% endif %}"
style="left: {{ 'calc(50% - ' ~ ((-avg / 5 * 50)) ~ '%)' if avg < 0 else '50%' }};
width: {{ ((avg if avg > 0 else -avg) / 5 * 50) }}%;"></div>
</div>
</div>
<div class="v3-wert-num"
title="Durchschnitt der 5 Berührungsgruppen — Skala 5 bis +5">
{% if avg > 0 %}+{% endif %}{{ "%.1f"|format(avg) }}
</div>
</div>
{% endfor %}
</div>
<details class="v3-matrix-details">
<summary>
Volle <span class="v3-glossar" data-glossar="gwoe-matrix" tabindex="0" role="button"
aria-label="Glossar: GWÖ-Matrix">GWÖ-Matrix 2.0</span>
· 25 Felder (5 Werte × 5 Berührungsgruppen)
</summary>
<div style="margin-top:8px;">
{% from "v2/components/matrix_mini.html" import matrix_mini %}
{{ matrix_mini(antrag.matrix) }}
</div>
</details>
{% endif %}
{% endblock %}
{# ─── 4. Verbesserungsvorschläge: default kollabiert ──────────────────── #}
{% block verbesserungen_section %}
{% if antrag.verbesserungen %}
<details class="v3-collapsible">
<summary>
<h3 class="v2-h3">Verbesserungsvorschläge</h3>
<span class="v3-collapsible-hint">{{ antrag.verbesserungen | length }} Vorschlag{{ "" if antrag.verbesserungen | length == 1 else "e" }} · klicken zum Aufklappen</span>
</summary>
<div style="margin-top:12px;">
{% for v in antrag.verbesserungen %}
<div style="margin-bottom:16px;">
{% if antrag.verbesserungen | length > 1 %}
<div style="font-family:var(--font-mono);font-size:11px;color:var(--ecg-dark);opacity:0.65;margin-bottom:4px;">
Vorschlag {{ loop.index }} von {{ antrag.verbesserungen | length }}
</div>
{% endif %}
{% from "v2/components/redline.html" import redline %}
{% 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 style="font-size:12px;color:var(--ecg-dark);opacity:0.75;margin:4px 0 0;font-family:var(--font-mono);">
{{ v.begruendung }}
</p>
{% endif %}
</div>
{% endfor %}
</div>
</details>
{% endif %}
{% endblock %}
{# ─── 5. Aktions-Links: nur PDF + Permalink ──────────────────────────── #}
{% block aktions_section %}
<div class="v3-aktions">
<a href="/api/assessment/pdf?drucksache={{ antrag.drucksache | urlencode }}">
PDF-Bericht
</a>
<a href="/antrag/{{ antrag.drucksache }}">
Permalink
</a>
</div>
{% endblock %}
{# ─── 6. Kommentare: default kollabiert ──────────────────────────────── #}
{% block comments_section %}
<details class="v3-collapsible v3-comments">
<summary>
<h3 class="v2-h3">Kommentare</h3>
<span class="v3-collapsible-hint">klicken zum Aufklappen · Anmeldung erforderlich</span>
</summary>
<div style="margin-top:16px;">
<div id="v2-comments-list" style="margin-bottom:20px;">
<span style="font-family:var(--font-mono);font-size:12px;color:var(--ecg-dark);opacity:0.5;">Lade…</span>
</div>
<div id="v2-comment-form" style="display:none;">
<div style="font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:0.07em;color:var(--ecg-dark);opacity:0.6;margin-bottom:8px;">Kommentar hinzufügen</div>
<textarea id="v2-comment-input"
rows="3"
placeholder="Kommentar…"
style="width:100%;box-sizing:border-box;padding:8px 10px;border:1px solid var(--hairline);border-radius:4px;font-family:var(--font-sans);font-size:13px;background:var(--surface);color:var(--ecg-dark);resize:vertical;margin-bottom:8px;outline:none;"></textarea>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
<select id="v2-comment-visibility"
style="padding:5px 8px;border:1px solid var(--hairline);border-radius:4px;font-family:var(--font-mono);font-size:11px;background:var(--surface);color:var(--ecg-dark);">
<option value="all">Öffentlich</option>
<option value="authenticated">Nur Angemeldete</option>
<option value="private">Nur ich</option>
</select>
<button onclick="v2DetailAddComment('{{ antrag.drucksache | e }}')"
style="padding:5px 14px;border:none;border-radius:4px;background:var(--ecg-blue);color:#fff;cursor:pointer;font-family:var(--font-mono);font-size:11px;font-weight:700;">
Absenden
</button>
</div>
</div>
<div id="v2-comment-login-hint" style="display:none;">
<button onclick="v2AuthModalOpen()"
style="padding:5px 12px;border:1px solid var(--hairline);border-radius:4px;background:none;cursor:pointer;font-family:var(--font-mono);font-size:11px;color:var(--ecg-blue);">
Anmelden um zu kommentieren
</button>
</div>
</div>
</details>
{% endblock %}
{# ─── Topbar-Pill + Toggle + Glossar-Tooltips (JS) ───────────────────── #}
{% block body_scripts %}
{{ super() }}
<script>
/* Topbar: Beta-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 für Erst-Leser:innen.';
var toggle = document.createElement('a');
toggle.className = 'v3-modus-toggle';
toggle.href = '/antrag/' + encodeURIComponent({{ antrag.drucksache | tojson }});
toggle.textContent = '→ Profi-Modus';
toggle.title = 'Volle GWÖ-Detailansicht (v2) öffnen';
bar.appendChild(pill);
bar.appendChild(toggle);
})();
/* Glossar-Tooltips: Klick/Focus öffnet Pop-up mit Alltags-Definition. */
window._v3Glossar = {
"drucksache": {
titel: "Drucksache",
text: "Eine Drucksache ist die offizielle Nummer eines Antrags im Parlament. Format: <Wahlperiode>/<laufende Nummer>. Beispiel: '18/18246' = 18. Wahlperiode, Nummer 18246. Über diese Nummer findest du den Antrag in den Parlamentsakten."
},
"fraktion": {
titel: "Fraktion",
text: "Eine Fraktion ist die Gruppe der Abgeordneten einer Partei im Parlament. Sie ist nicht dasselbe wie die Partei selbst — die Partei ist die Organisation außerhalb, die Fraktion sind die gewählten Abgeordneten innerhalb."
},
"gwoe-score": {
titel: "Gemeinwohl-Score (010)",
text: "Der GWÖ-Score bewertet, wie stark der Antrag dem Gemeinwohl dient — auf einer Skala von 0 bis 10. Höher = besser für die Allgemeinheit. Der Wert ist ein gewichteter Durchschnitt aus 25 Bewertungs-Feldern (5 Werte × 5 Berührungsgruppen). Mehr unter /methodik."
},
"gwoe-matrix": {
titel: "GWÖ-Matrix 2.0",
text: "Die Gemeinwohl-Matrix ist ein Bewertungsraster mit 25 Feldern: 5 Werte (Menschenwürde, Solidarität, Nachhaltigkeit, Gerechtigkeit, Transparenz) × 5 Berührungsgruppen (Lieferant:innen, Finanzen, Verwaltung, Bürger:innen, Gesellschaft & Natur). Jedes Feld bekommt eine Bewertung von 5 (stark widersprechend) bis +5 (stark fördernd)."
},
"heuchelei": {
titel: "Heuchelei-Marker (⚠)",
text: "Wird angezeigt, wenn eine Fraktion mit Nein gestimmt hat, obwohl der Antrag inhaltlich gut zu ihrem eigenen Wahlprogramm passt (Wahlprogramm-Score ≥ 7 von 10). Der Marker macht die Lücke zwischen Wahlversprechen und Abstimmungsverhalten sichtbar."
},
"opportunismus": {
titel: "Opportunismus-Marker (!)",
text: "Wird angezeigt, wenn eine Fraktion mit Ja gestimmt hat, obwohl der Antrag schlecht zum eigenen Wahlprogramm passt (Wahlprogramm-Score < 3 von 10). Mögliches Anzeichen für taktisches Stimmverhalten."
}
};
window.v3OpenGlossar = function (key) {
var data = window._v3Glossar[key];
if (!data) return;
var modal = document.getElementById('v3-glossar-modal');
if (!modal) return;
document.getElementById('v3-glossar-title').textContent = data.titel;
document.getElementById('v3-glossar-body').textContent = data.text;
modal.style.display = 'flex';
};
document.addEventListener('click', function (e) {
var t = e.target.closest('.v3-glossar');
if (t) {
e.preventDefault();
window.v3OpenGlossar(t.dataset.glossar);
}
});
document.addEventListener('keydown', function (e) {
if ((e.key === 'Enter' || e.key === ' ') && document.activeElement && document.activeElement.classList.contains('v3-glossar')) {
e.preventDefault();
window.v3OpenGlossar(document.activeElement.dataset.glossar);
}
if (e.key === 'Escape') {
var m = document.getElementById('v3-glossar-modal');
if (m && m.style.display === 'flex') { m.style.display = 'none'; }
}
});
</script>
{# Glossar-Modal #}
<div id="v3-glossar-modal" class="v3-glossar-modal" role="dialog" aria-modal="true"
aria-labelledby="v3-glossar-title"
onclick="if(event.target===this)this.style.display='none'">
<div class="v3-glossar-card">
<div class="v3-glossar-head">
<strong id="v3-glossar-title"></strong>
<button class="v3-glossar-close"
onclick="document.getElementById('v3-glossar-modal').style.display='none'"
aria-label="Schließen">×</button>
</div>
<p id="v3-glossar-body"></p>
</div>
</div>
{% endblock %}