Getrennter Titel fuer Suchergebnisse je Seite und Beitrag (Migration 20260913000100): auf der Seite steht "Leistungen", im Suchergebnis darf der lange Titel stehen. Leer heisst weiterhin: der Titel der Seite. Schriften kommen jetzt vom eigenen Server. Ein Knopf im Designbereich oder cms:fonts:fetch holt die gewaehlten Google-Schnitte als WOFF2 nach public/assets/fonts. Das spart zwei fremde Verbindungen nacheinander (gemessen 820 ms) und die IP-Weitergabe an Google. Ohne Dateien bleibt es beim bisherigen Verweis - eine Seite ohne Schrift waere schlimmer. Ein Stylesheet statt vier, mit Pruefsumme im Namen und ohne Kommentare, dazu eine .htaccess mit Kompression, Cache und Schutz interner Dateien. Der Entwicklungsserver sendet dieselben Kopfzeilen, sonst misst man lokal etwas, das es im Betrieb nicht gibt. Bilder in der Groesse, in der sie erscheinen: ein nur fuer Desktop gesetztes Hintergrundbild gilt auf dem Telefon in Telefongroesse (189 KB -> 40 KB), img nennt seine feste Breite oder sizes="auto", und fetchpriority liegt auf dem ersten Bild des Inhalts statt auf dem Logo. Neu: npm run test:links prueft jeden internen Verweis auf seine Antwort. Lighthouse gegen den Nachbau: Barrierefreiheit, Best Practices und SEO 100 auf allen vier geprueften Adressen, Performance 100 ausser auf der bilderreichen Startseite (98 mobil, 96 Desktop). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
72 lines
4.8 KiB
Twig
72 lines
4.8 KiB
Twig
<!doctype html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{{ heading }}{% if result.page > 1 %} · Seite {{ result.page }}{% endif %} · Beiträge</title>
|
|
<meta name="description" content="{{ term ? 'Beiträge zu ' ~ term.name : 'Alle Beiträge' }}.">
|
|
<link rel="canonical" href="{{ canonical }}">
|
|
{# Auch ein geteiltes Archiv soll einen Namen haben statt einer nackten Adresse. #}
|
|
<meta property="og:title" content="{{ heading }}{% if result.page > 1 %} · Seite {{ result.page }}{% endif %}">
|
|
<meta property="og:description" content="{{ term ? 'Beiträge zu ' ~ term.name : 'Alle Beiträge' }}.">
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:url" content="{{ canonical }}">
|
|
<meta name="twitter:card" content="summary">
|
|
{% if result.page > 1 %}<link rel="prev" href="{{ base }}{{ result.page > 2 ? '?seite=' ~ (result.page - 1) : '' }}">{% endif %}
|
|
{% if result.page < result.pages %}<link rel="next" href="{{ base }}?seite={{ result.page + 1 }}">{% endif %}
|
|
<link rel="alternate" type="application/rss+xml" title="Beiträge" href="/feed.xml">
|
|
{% include 'favicon.html.twig' %}
|
|
<link rel="stylesheet" href="/assets/site.css?v={{ kant_version() }}">
|
|
<link rel="stylesheet" href="/assets/design.css?v={{ kant_version() }}">
|
|
</head>
|
|
{% set consentOpen = not editing|default(false) and consentGate.needsBanner(app.request) %}
|
|
<body class="kant{{ consentOpen ? ' consent-open' : '' }}">
|
|
<a class="skip-link" href="#main">Zum Inhalt springen</a>
|
|
{% if areas.header|default(null) %}
|
|
<header class="site-header{{ siteSettings.load().stickyHeader ? ' is-sticky' : '' }}">
|
|
{% for block in areas.header.blocks %}{% include 'blocks/block.html.twig' with {block: block, postLists: {}, forms: {}, breadcrumbs: [], navigation: navigation|default({}), sections: sections|default({}), richText: true, richHeadings: areas.header.schemaVersion|default(1) >= 17, eagerImage: null} only %}{% endfor %}
|
|
</header>
|
|
{% endif %}
|
|
<main id="main" tabindex="-1">
|
|
<section class="block-section tone-mint width-normal">
|
|
<div class="shell section-inner">
|
|
{% if term %}<p class="post-terms-label">{{ term.kind == 'category' ? 'Kategorie' : 'Schlagwort' }}</p>{% endif %}
|
|
<h1>{{ heading }}</h1>
|
|
<p class="block-text">{{ result.total }} {{ result.total == 1 ? 'Beitrag' : 'Beiträge' }}{% if result.pages > 1 %} · Seite {{ result.page }} von {{ result.pages }}{% endif %}</p>
|
|
</div>
|
|
</section>
|
|
<section class="block-section tone-paper width-normal">
|
|
<div class="shell section-inner">
|
|
{% include 'blocks/post-list.html.twig' with {posts: result.posts} only %}
|
|
{% if result.pages > 1 %}
|
|
<nav class="pagination" aria-label="Seiten">
|
|
{% if result.page > 1 %}<a rel="prev" href="{{ base }}{{ result.page > 2 ? '?seite=' ~ (result.page - 1) : '' }}">← Neuere</a>{% endif %}
|
|
<span>Seite {{ result.page }} von {{ result.pages }}</span>
|
|
{% if result.page < result.pages %}<a rel="next" href="{{ base }}?seite={{ result.page + 1 }}">Ältere →</a>{% endif %}
|
|
</nav>
|
|
{% endif %}
|
|
</div>
|
|
</section>
|
|
</main>
|
|
{% if areas.footer|default(null) %}
|
|
<footer class="site-footer">
|
|
{% for block in areas.footer.blocks %}{% include 'blocks/block.html.twig' with {block: block, postLists: {}, forms: {}, breadcrumbs: [], navigation: navigation|default({}), sections: sections|default({}), richText: true, richHeadings: areas.footer.schemaVersion|default(1) >= 17, eagerImage: null} only %}{% endfor %}
|
|
</footer>
|
|
{% endif %}
|
|
{# Privacy statement, imprint and the way back to the consent decision. All three have to be
|
|
reachable from every page, so they are part of the template and not of the footer area,
|
|
which someone could delete. One labelled landmark, so they are not loose text either. #}
|
|
{% set legal = consentGate.legalLinks() %}
|
|
{% set revocable = not editing|default(false) and consentGate.askedGroups is not empty and not consentGate.needsBanner(app.request) %}
|
|
{% if legal is not empty or revocable %}
|
|
<nav class="legal-bar" aria-label="Rechtliches">
|
|
{% for path, label in legal %}{% if not loop.first %} · {% endif %}<a href="/{{ path }}">{{ label }}</a>{% endfor %}
|
|
{% if revocable %}{% if legal is not empty %} · {% endif %}<a href="/einwilligung">Einwilligung ändern</a>{% endif %}
|
|
</nav>
|
|
{% endif %}
|
|
{% if not editing|default(false) and consentGate.needsBanner(app.request) %}
|
|
{% include 'consent-banner.html.twig' with {consent: consentGate.state(app.request), back: app.request.pathInfo} only %}
|
|
{% endif %}
|
|
</body>
|
|
</html>
|