diff --git a/app/main.py b/app/main.py index 1b9dff2..86a8f0c 100644 --- a/app/main.py +++ b/app/main.py @@ -464,6 +464,17 @@ def _row_to_detail(row): ist_reg = wp.get("istRegierung", wp.get("ist_regierung")) if ist_reg is None: ist_reg = fraktion in regierung_set + # Zitate inline pro WP-/PP-Block (#177-Folge: Belege im Treue-Layout) + def _zitate_of(src: dict) -> list[dict]: + out = [] + for z in (src.get("zitate") or []): + out.append({ + "text": z.get("text", ""), + "source": z.get("quelle", ""), + "pdf_href": _build_pdf_href(z, bundesland), + }) + return out + fraktions_scores.append({ "fraktion": fraktion, "ist_antragsteller": ist_antrag, @@ -472,11 +483,13 @@ def _row_to_detail(row): "score": wp_src.get("score", 0), "begruendung": wp_src.get("begruendung", wp_src.get("begründung", "")), "hat_zitate": bool(wp_src.get("zitate")), + "zitate": _zitate_of(wp_src), }, "parteiprogramm": { "score": pp_src.get("score", 0), "begruendung": pp_src.get("begruendung", pp_src.get("begründung", "")), "hat_zitate": bool(pp_src.get("zitate")), + "zitate": _zitate_of(pp_src), }, }) diff --git a/app/static/v2/v2.css b/app/static/v2/v2.css index 4c10a5d..e55f199 100644 --- a/app/static/v2/v2.css +++ b/app/static/v2/v2.css @@ -938,25 +938,111 @@ body.v2 ul.v2-manual ul li::before { } .v2-fraktion-row { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - padding: 6px 8px; + display: block; + padding: 10px 12px; background: var(--paper); border: 1px solid var(--hairline); border-radius: 4px; font-size: 13px; } +.v2-fraktion-head { + display: flex; + align-items: baseline; + gap: 8px; + flex-wrap: wrap; + margin-bottom: 6px; +} + .v2-fraktion-label { font-family: var(--font-mono); - font-size: 12px; - font-weight: 600; + font-size: 13px; + font-weight: 700; + letter-spacing: 0.02em; +} + +/* Rolle-Pills (Antragsteller:in / Regierungsfraktion) */ +.v2-pill { + font-family: var(--font-mono); + font-size: 10px; + padding: 1px 6px; + border-radius: 3px; + text-transform: uppercase; + letter-spacing: 0.05em; +} +.v2-pill-antrag { + color: #bf6c10; + background: rgba(247, 148, 29, 0.15); +} +.v2-pill-reg { + color: #1e6a90; + background: rgba(0, 157, 165, 0.15); +} + +/* Aufklappbare Programm-Blöcke (Wahlprogramm/Parteiprogramm) */ +.v2-treue-block { + border-top: 1px solid var(--hairline); + margin: 0; +} +.v2-treue-block:first-of-type { + border-top: none; +} +.v2-treue-block > summary { display: flex; align-items: center; - gap: 4px; - min-width: 90px; + gap: 8px; + padding: 8px 0; + cursor: pointer; + list-style: none; + user-select: none; +} +.v2-treue-block > summary::-webkit-details-marker { + display: none; +} +.v2-treue-label { + font-family: var(--font-mono); + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.07em; + color: #0d6f76; + font-weight: 600; +} +.v2-treue-spacer { + flex: 1 1 auto; +} +.v2-treue-caret { + font-family: var(--font-mono); + font-size: 10px; + color: var(--ecg-dark); + opacity: 0.5; + transition: transform 0.15s ease; +} +.v2-treue-block[open] > summary .v2-treue-caret { + transform: rotate(180deg); +} +.v2-treue-body { + padding: 4px 0 10px; + font-size: 12.5px; + line-height: 1.5; +} +.v2-einschaetzung { + margin-bottom: 8px; +} +.v2-einschaetzung-label { + font-family: var(--font-mono); + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.07em; + color: var(--ecg-dark); + opacity: 0.6; + margin-bottom: 4px; +} +.v2-einschaetzung-text { + color: var(--ecg-dark); + line-height: 1.55; +} +.v2-belege { + margin-top: 6px; } .v2-fraktion-scores { diff --git a/app/templates/v2/screens/antrag_detail.html b/app/templates/v2/screens/antrag_detail.html index f523574..f09f96e 100644 --- a/app/templates/v2/screens/antrag_detail.html +++ b/app/templates/v2/screens/antrag_detail.html @@ -353,57 +353,76 @@ {{ matrix_mini(antrag.matrix) }} {% endif %} - {# Fraktions-Score-Tabelle: Score-Chips + ausgeschriebene Rolle + - sichtbare Begründung für jeden Score (#177). #} + {# Programm-Treue im BELEGE-Layout: pro Partei zwei aufklappbare Blöcke + (Wahlprogramm + Parteiprogramm). Summary zeigt Bewertung, expand + enthält Einschätzung + Belege. #} {% if antrag.fraktions_scores %}

Programm-Treue pro Fraktion

{% for fs in antrag.fraktions_scores %} {% set wp_score = fs.wahlprogramm.score | float %} {% set pp_score = fs.parteiprogramm.score | float %} -
-
- {{ fs.fraktion }} - {% if fs.ist_antragsteller %}Antragsteller:in{% endif %} - {% if fs.ist_regierung %}Regierungsfraktion{% endif %} - - - WP {{ "%.0f"|format(wp_score) }}/10 - - - PP {{ "%.0f"|format(pp_score) }}/10 - - +
+
+ {{ fs.fraktion }} + {% if fs.ist_antragsteller %}Antragsteller:in{% endif %} + {% if fs.ist_regierung %}Regierungsfraktion{% endif %}
- {% if fs.wahlprogramm.begruendung %} -
- Wahlprogramm - — {{ fs.wahlprogramm.begruendung }} -
- {% endif %} - {% if fs.parteiprogramm.begruendung %} -
- Parteiprogramm - — {{ fs.parteiprogramm.begruendung }} -
- {% endif %} + +
+ + Wahlprogramm + + {{ "%.0f"|format(wp_score) }}/10 + + +
+ {% if fs.wahlprogramm.begruendung %} +
+
Einschätzung
+
{{ fs.wahlprogramm.begruendung }}
+
+ {% endif %} + {% if fs.wahlprogramm.zitate %} +
+
Belege
+ {% for z in fs.wahlprogramm.zitate %} + {{ quote_card(z.text, z.source, True, False, z.pdf_href) }} + {% endfor %} +
+ {% endif %} +
+
+ +
+ + Parteiprogramm + + {{ "%.0f"|format(pp_score) }}/10 + + +
+ {% if fs.parteiprogramm.begruendung %} +
+
Einschätzung
+
{{ fs.parteiprogramm.begruendung }}
+
+ {% endif %} + {% if fs.parteiprogramm.zitate %} +
+
Belege
+ {% for z in fs.parteiprogramm.zitate %} + {{ quote_card(z.text, z.source, True, False, z.pdf_href) }} + {% endfor %} +
+ {% endif %} +
+
{% endfor %}
{% endif %} - {# Zitate nach Partei gruppiert; Fraktion ohne Zitate erhält Hinweis via fraktions_scores-Block oben #} - {% if antrag.zitate %} - {% set current_partei = namespace(value="") %} - {% for z in antrag.zitate %} - {% if z.partei != current_partei.value %} - {% set current_partei.value = z.partei %} -

Belege — {{ z.partei }}

- {% endif %} - {{ quote_card(z.text, z.source, z.verified | default(True), z.contra | default(False), z.pdf_href | default("")) }} - {% endfor %} - {% endif %} - {# ── News-Match-Box: aktuelle News passend zu diesem Antrag (#170) ── #}