feat: FAKTEN + Bewertungskarte als HTML/CSS statt Grafiken

- .bsn-fakten: 3-Spalten-Grid, mobile-first (1 Spalte auf Handy)
- .bsn-rating-card: dunkelblauer Header, MECHANISMEN/PRO/KONTRA-Spalten, Footer mit Wertung
- CSS in bsn-review.css — ins Joomla-Template einzubinden
- Discord-Modul entfernt, Gallery mit einfachen Klammern
- Alle Stile: mobile-first, globale CSS-Klassen
This commit is contained in:
Hermes Agent
2026-07-13 23:10:03 +02:00
parent 3a26e03510
commit db707f650a
2 changed files with 224 additions and 64 deletions
+48 -64
View File
@@ -2126,64 +2126,42 @@ document.getElementById('publishBtn').addEventListener('click',function(){{submi
autor_name = author_info["name"] autor_name = author_info["name"]
autor_banner = author_info["banner"] autor_banner = author_info["banner"]
# Infobox-Tabelle # FAKTEN ZUM SPIEL — 3-Spalten-Grid (CSS: .bsn-fakten)
fakten_rows = [] fakten_items = []
if autoren: fakten_rows.append(f'<tr><td><strong>Autor:innen</strong></td><td>{autoren}</td></tr>') if autoren: fakten_items.append(('Autor:innen', autoren))
if illustratoren: fakten_rows.append(f'<tr><td><strong>Illustrator:innen</strong></td><td>{illustratoren}</td></tr>') if illustratoren: fakten_items.append(('Illustrator:innen', illustratoren))
if verlag: fakten_rows.append(f'<tr><td><strong>Verlag</strong></td><td>{verlag}</td></tr>') if verlag: fakten_items.append(('Verlag/Vertrieb', verlag))
if personen: fakten_rows.append(f'<tr><td><strong>Personenzahl</strong></td><td>{personen}</td></tr>') if personen: fakten_items.append(('Personenzahl', personen))
if spielzeit: fakten_rows.append(f'<tr><td><strong>Spielzeit</strong></td><td>{spielzeit}</td></tr>') if spielzeit: fakten_items.append(('Spielzeit', spielzeit))
if jahr: fakten_rows.append(f'<tr><td><strong>Erscheinungsjahr</strong></td><td>{jahr}</td></tr>') if jahr: fakten_items.append(('Erscheinungsjahr', jahr))
if preis: fakten_rows.append(f'<tr><td><strong>Preis</strong></td><td>{preis}</td></tr>') if preis: fakten_items.append(('ungefährer Preis', preis))
if app: fakten_rows.append(f'<tr><td><strong>App</strong></td><td>{app}</td></tr>') if app: fakten_items.append(('App', app))
if alter: fakten_rows.append(f'<tr><td><strong>Alter</strong></td><td>{alter}</td></tr>') if alter: fakten_items.append(('empfohlenes Alter', alter))
fakten_html = "" fakten_html = ""
if fakten_rows: if fakten_items:
fakten_html = '<table class="bsn-table"><tbody>' + "".join(fakten_rows) + '</tbody></table>' items = "".join(f'<div class="bsn-fakten-item"><span class="bsn-fakten-val">{v}</span><span class="bsn-fakten-lbl">{k}</span></div>' for k, v in fakten_items)
fakten_html = f'<div class="bsn-fakten"><h3>FAKTEN ZUM SPIEL</h3><div class="bsn-fakten-grid">{items}</div></div>'
# Pro/Kontra # BEWERTUNGSKARTE — dunkelblauer Header + 3 Spalten + Footer (CSS: .bsn-rating-card)
pro_html = "" mech_items = "".join(f'<span class="bsn-rc-mech">{m}</span>' for m in mech) if mech else ""
if pros: pro_items = "".join(f'<span class="bsn-rc-pro">{p}</span>' for p in pros) if pros else ""
pro_html = '<div><h3>👍 PRO</h3><ul>' + "".join(f"<li>{p}</li>" for p in pros) + '</ul></div>' kontra_items = "".join(f'<span class="bsn-rc-kontra">{k}</span>' for k in kontras) if kontras else ""
kontra_html = "" rating_html = ""
if kontras:
kontra_html = '<div><h3>👎 KONTRA</h3><ul>' + "".join(f"<li>{k}</li>" for k in kontras) + '</ul></div>'
# Mechanismen
mech_html = ""
if mech:
mech_html = '<p><strong>Mechanismen:</strong> ' + ", ".join(mech) + '</p>'
# Bewertung
wertung_html = ""
if wertung: if wertung:
wertung_html = f'<div class="bsn-rating"><span class="bsn-rating-score">{wertung}</span><span class="bsn-rating-label">/ 100</span></div>' rating_html = f"""<div class="bsn-rating-card">
<div class="bsn-rc-header"><span class="bsn-rc-title">{spielname}</span><span class="bsn-rc-meta">Komplexität: {komplex or ''}</span><span class="bsn-rc-meta">Sprachen: {sprache}</span></div>
<div class="bsn-rc-body"><div class="bsn-rc-col"><h4>MECHANISMEN</h4>{mech_items or '<span class="bsn-rc-empty">—</span>'}</div>
<div class="bsn-rc-col"><h4>PRO</h4>{pro_items or '<span class="bsn-rc-empty">—</span>'}</div>
<div class="bsn-rc-col"><h4>KONTRA</h4>{kontra_items or '<span class="bsn-rc-empty">—</span>'}</div></div>
<div class="bsn-rc-footer"><span class="bsn-rc-author">Bewertung von: {autor_name}</span><span class="bsn-rc-score">MEINE WERTUNG {wertung} / 100</span></div>
</div>"""
disc_html = "" # Artikeltext aus Word splitten
if disclosure_text:
disc_html = f'<p style="text-align:center;"><em>{disclosure_text}<br>Dies hat keinen Einfluss auf unsere Bewertung!</em></p>'
aff_html = ""
if fantasywelt_url:
aff_html += f'<p><a href="{fantasywelt_url}" target="_blank" rel="noopener"><img style="margin:10px auto;display:block;" src="images/banners/fantasywelt/banner_fantasywelt-jetzt-kaufen.jpg" alt="Bei Fantasywelt kaufen"></a></p>\n'
if so_url:
aff_html += f'<p><a href="{so_url}" target="_blank" rel="noopener"><img style="margin:10px auto;display:block;" src="images/banners/fantasywelt/SO_kaufen_button.jpg" alt="Bei Spiele-Offensive kaufen"></a></p>\n'
if amazon_url:
aff_html += f'<p><a href="{amazon_url}" target="_blank" rel="noopener"><img style="margin:10px auto;display:block;" src="images/banners/amazon/amazon-kaufen-button.jpg" alt="Bei Amazon kaufen"></a></p>\n'
if allgames4you_url:
aff_html += f'<p><a href="{allgames4you_url}" target="_blank" rel="noopener"><img style="margin:10px auto;display:block;" src="images/banners/allgames4you/allgames4you-kaufen-button.jpg" alt="Bei AllGames4You kaufen"></a></p>\n'
gal_path = f"01/{erster}/{ordner}"
tags_str = ", ".join(tags) if tags else f"{spielname}, Brettspiel, Review, Bewertung, {autor_name}"
title_full = f"{spielname} {zusatz}".strip()
# Artikeltext aus Word in Spielerklärung + Fazit splitten
erklarung_html = "" erklarung_html = ""
fazit_html = "" fazit_html = ""
if word_text: if word_text:
# Suche "Fazit"-Überschrift als Trenner
import re as re2 import re as re2
split_marker = re2.search(r'(?i)^Fazit\s*$|^{2,}Fazit\s*$', word_text, re2.MULTILINE) split_marker = re2.search(r'(?i)^Fazit\s*$', word_text, re2.MULTILINE)
if split_marker: if split_marker:
erkl = word_text[:split_marker.start()].strip() erkl = word_text[:split_marker.start()].strip()
faz = word_text[split_marker.end():].strip() faz = word_text[split_marker.end():].strip()
@@ -2194,7 +2172,6 @@ document.getElementById('publishBtn').addEventListener('click',function(){{submi
else: else:
erkl = word_text erkl = word_text
faz = "" faz = ""
# In HTML umwandeln falls Plaintext
if erkl and "<" not in erkl[:100]: if erkl and "<" not in erkl[:100]:
erkl = f"<p>{erkl.replace(chr(10)+chr(10), '</p><p>')}</p>" erkl = f"<p>{erkl.replace(chr(10)+chr(10), '</p><p>')}</p>"
if faz and "<" not in faz[:100]: if faz and "<" not in faz[:100]:
@@ -2202,30 +2179,37 @@ document.getElementById('publishBtn').addEventListener('click',function(){{submi
erklarung_html = erkl erklarung_html = erkl
fazit_html = faz fazit_html = faz
# Verlag/Autor Fallback disc_html = ""
if disclosure_text:
disc_html = f'<p class="bsn-disclosure"><em>{disclosure_text}<br>Dies hat keinen Einfluss auf unsere Bewertung!</em></p>'
aff_html = ""
if fantasywelt_url:
aff_html += f'<p class="bsn-affiliate"><a href="{fantasywelt_url}" target="_blank" rel="noopener"><img src="images/banners/fantasywelt/banner_fantasywelt-jetzt-kaufen.jpg" alt="Bei Fantasywelt kaufen"></a></p>\n'
if so_url:
aff_html += f'<p class="bsn-affiliate"><a href="{so_url}" target="_blank" rel="noopener"><img src="images/banners/fantasywelt/SO_kaufen_button.jpg" alt="Bei Spiele-Offensive kaufen"></a></p>\n'
if amazon_url:
aff_html += f'<p class="bsn-affiliate"><a href="{amazon_url}" target="_blank" rel="noopener"><img src="images/banners/amazon/amazon-kaufen-button.jpg" alt="Bei Amazon kaufen"></a></p>\n'
if allgames4you_url:
aff_html += f'<p class="bsn-affiliate"><a href="{allgames4you_url}" target="_blank" rel="noopener"><img src="images/banners/allgames4you/allgames4you-kaufen-button.jpg" alt="Bei AllGames4You kaufen"></a></p>\n'
gal_path = f"01/{erster}/{ordner}"
tags_str = ", ".join(tags) if tags else f"{spielname}, Brettspiel, Review, Bewertung, {autor_name}"
title_full = f"{spielname} {zusatz}".strip()
display_autor = autoren or verlag or meta.get("verlag", "").strip() or "unbekannt" display_autor = autoren or verlag or meta.get("verlag", "").strip() or "unbekannt"
body = f"""<p>{spielname}{komplex or 'Brettspiel'} von {display_autor}</p> body = f"""<p class="bsn-dachzeile">{spielname}{komplex or 'Brettspiel'} von {display_autor}</p>
<hr id="system-readmore"> <hr id="system-readmore">
<p>&nbsp;</p>
<p><img style="margin:10px auto;display:block;" src="{base_img}/wertung/info.png" alt="Fakten zum Spiel"></p>
{fakten_html} {fakten_html}
{disc_html} {disc_html}
{mech_html}
{erklarung_html} {erklarung_html}
<h2><img src="images/banners/redaktion/{autor_banner}" alt="Meine Meinung"></h2> <h2><img src="images/banners/redaktion/{autor_banner}" alt="Meine Meinung"></h2>
{fazit_html} {fazit_html}
{pro_html} {rating_html}
{kontra_html}
{wertung_html}
<p>&nbsp;</p>
<p style="text-align:center;">{{{{module Discord-Hinweis Tests}}}}</p>
<p>&nbsp;</p> <p>&nbsp;</p>
{aff_html} {aff_html}
<p>&nbsp;</p>
<h2>Bilder vom Spiel</h2> <h2>Bilder vom Spiel</h2>
<p>{{{{gallery}}}}{gal_path}{{{{/gallery}}}}</p> <p>{{gallery}}{gal_path}{{/gallery}}</p>"""
<p>{{{{module Aktuelle Texte fur Content}}}}</p>"""
datei = datetime.now().strftime("%Y-%m-%d") datei = datetime.now().strftime("%Y-%m-%d")
safe = spielname.lower().replace(" ", "-").replace(":", "").replace("/", "-") safe = spielname.lower().replace(" ", "-").replace(":", "").replace("/", "-")
+176
View File
@@ -0,0 +1,176 @@
/* ═══════════════════════════════════════════════════════════════════════
BSN FAKTEN ZUM SPIEL — 3-Spalten-Grid, mobile-first
═══════════════════════════════════════════════════════════════════════ */
.bsn-fakten {
margin: 24px 0;
border: 1px solid #e0e0e0;
border-radius: 8px;
overflow: hidden;
}
.bsn-fakten h3 {
background: #fff;
margin: 0;
padding: 12px 16px;
font-size: 0.95em;
font-weight: 700;
letter-spacing: 0.05em;
border-bottom: 1px solid #000;
}
.bsn-fakten-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0;
background: #fff;
}
.bsn-fakten-item {
padding: 14px 12px;
border-right: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 4px;
}
.bsn-fakten-item:nth-child(3n) { border-right: none; }
.bsn-fakten-val {
font-weight: 600;
font-size: 0.9em;
color: #1a1a1a;
}
.bsn-fakten-lbl {
font-size: 0.75em;
color: #999;
}
@media (max-width: 600px) {
.bsn-fakten-grid {
grid-template-columns: repeat(2, 1fr);
}
.bsn-fakten-item:nth-child(3n) { border-right: 1px solid #f0f0f0; }
.bsn-fakten-item:nth-child(2n) { border-right: none; }
}
@media (max-width: 380px) {
.bsn-fakten-grid { grid-template-columns: 1fr; }
.bsn-fakten-item { border-right: none; }
}
/* ═══════════════════════════════════════════════════════════════════════
BSN BEWERTUNGSKARTE — dunkelblauer Header, 3 Spalten, Footer
═══════════════════════════════════════════════════════════════════════ */
.bsn-rating-card {
margin: 32px 0;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
font-family: system-ui, -apple-system, sans-serif;
}
.bsn-rc-header {
background: #20228a;
color: #fff;
padding: 16px 20px;
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 16px;
}
.bsn-rc-title {
font-size: 1.3em;
font-weight: 700;
letter-spacing: 0.02em;
}
.bsn-rc-meta {
font-size: 0.8em;
opacity: 0.85;
}
.bsn-rc-body {
background: #fff;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0;
}
.bsn-rc-col {
padding: 16px 14px;
border-right: 1px solid #eee;
}
.bsn-rc-col:last-child { border-right: none; }
.bsn-rc-col h4 {
font-size: 0.75em;
font-weight: 700;
letter-spacing: 0.06em;
color: #20228a;
margin: 0 0 10px;
}
.bsn-rc-mech,
.bsn-rc-pro,
.bsn-rc-kontra {
display: block;
font-size: 0.88em;
padding: 4px 0;
border-bottom: 1px dotted #ddd;
color: #333;
}
.bsn-rc-empty {
display: block;
font-size: 0.85em;
color: #bbb;
padding: 4px 0;
}
.bsn-rc-footer {
background: #20228a;
color: #fff;
padding: 14px 20px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 8px;
}
.bsn-rc-author {
font-size: 0.85em;
font-style: italic;
opacity: 0.9;
}
.bsn-rc-score {
font-size: 1.2em;
font-weight: 700;
letter-spacing: 0.03em;
}
@media (max-width: 600px) {
.bsn-rc-body { grid-template-columns: 1fr; }
.bsn-rc-col { border-right: none; border-bottom: 1px solid #eee; }
.bsn-rc-col:last-child { border-bottom: none; }
.bsn-rc-header { flex-direction: column; gap: 4px; }
.bsn-rc-footer { flex-direction: column; text-align: center; }
}
/* ═══════════════════════════════════════════════════════════════════════
BSN Allgemeine Artikel-Elemente
═══════════════════════════════════════════════════════════════════════ */
.bsn-dachzeile {
color: #20228a;
font-weight: 600;
border-bottom: 2px solid #20228a;
padding-bottom: 8px;
margin-bottom: 16px;
}
.bsn-disclosure {
text-align: center;
font-size: 0.9em;
color: #666;
margin: 12px 0;
}
.bsn-affiliate {
text-align: center;
margin: 8px 0;
}
.bsn-affiliate img {
max-width: 100%;
height: auto;
border-radius: 6px;
}