syncova-policies/components/legal-page.tsx
Weapie 5aa8880190 Gebaerdensprach-Video ermoeglichen und Erklaerung anpassen
Ein DGS-Video liess sich bisher gar nicht einbinden: Der Markdown-
Prozessor laeuft mit Sanitizing, und remark reicht rohes HTML dann von
vornherein nicht durch - <video> kam als leeres <p> heraus. Eine
erweiterte Freigabeliste allein half deshalb nicht.

Statt rohes HTML fuer alle Textfelder zu oeffnen - auch fuer die 121
Erklaerungen - bekommt die Gebaerdensprach-Seite zwei eigene Felder fuer
Video- und Untertiteladresse. Ausgegeben wird ein natives <video
controls> mit <track kind="captions"> und Bildunterschrift.

Adressen werden zweimal geprueft, beim Speichern und vor der Ausgabe:
zugelassen sind nur der eigene Server und https. javascript:, data:,
protokollrelative und einfache http-Adressen werden abgewiesen. iframe
bleibt bewusst gesperrt - eine YouTube-Einbindung wuerde Besucherdaten
an Dritte uebertragen.

Erklaerung zur Barrierefreiheit entsprechend gekuerzt: Die beiden
Luecken nach § 4 BITV 2.0 entfallen, es bleibt die ungepruefte
Druckansicht.

Geprueft: Video wird mit Untertitelspur ausgeliefert und ist per Tastatur
erreichbar, axe-core meldet auf beiden neuen Seiten in hell und dunkel
keine Verstoesse, Adresspruefung weist alle acht Testfaelle korrekt zu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 16:18:09 +02:00

88 lines
3.0 KiB
TypeScript
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.

import { notFound } from "next/navigation"
import { PublicHeader } from "@/components/public-header"
import { SiteFooter } from "@/components/site-footer"
import { markdownToHtml } from "@/lib/markdown"
import { SITE_PAGE_META, SitePageKey, isSafeMediaUrl } from "@/lib/site-pages"
import { readSitePages } from "@/lib/site-pages.server"
/**
* Rendert eine der rechtlichen Seiten aus dem im Admin gepflegten Markdown.
*
* Serverseitig gerendert: Der Text steht ohne JavaScript im Dokument und ist
* damit auch für Screenreader, Suchmaschinen und Archivierung erreichbar.
* Ist nichts gepflegt, gibt es die Seite nicht – ein leeres Impressum wäre
* irreführender als ein 404.
*/
export async function LegalPage({ page }: { page: SitePageKey }) {
const pages = await readSitePages()
const content = pages[page].trim()
if (!content) notFound()
const html = await markdownToHtml(content)
const meta = SITE_PAGE_META[page]
// Zweite Prüfung vor der Ausgabe: Was in der Datenbank steht, könnte aus
// einer Zeit vor der Prüfung in der API stammen.
const video = isSafeMediaUrl(pages.signLanguageVideo)
? pages.signLanguageVideo.trim()
: ""
const captions = isSafeMediaUrl(pages.signLanguageCaptions)
? pages.signLanguageCaptions.trim()
: ""
return (
<div className="flex min-h-screen flex-col bg-background">
<PublicHeader subtitle={meta.title} />
<main id="inhalt" tabIndex={-1} className="mx-auto w-full max-w-3xl flex-1 px-4 py-6 sm:px-6 sm:py-8">
<h1 className="mb-6 text-2xl font-semibold tracking-tight">
{meta.title}
</h1>
{/* Erläuterungen in Deutscher Gebärdensprache nach § 4 BITV 2.0.
Der native Player ist mit der Tastatur bedienbar; Untertitel
werden eingebunden, sobald eine WebVTT-Datei hinterlegt ist. */}
{page === "signLanguage" && video && (
<figure className="mb-8">
<video
controls
preload="metadata"
className="w-full rounded-lg border bg-muted"
>
<source src={video} />
{captions && (
<track
src={captions}
kind="captions"
srcLang="de"
label="Deutsch"
default
/>
)}
Ihr Browser kann dieses Video nicht abspielen.{" "}
<a href={video}>Video herunterladen</a>
</video>
<figcaption className="mt-2 text-sm text-muted-foreground">
Erläuterungen zu diesem Portal in Deutscher Gebärdensprache
</figcaption>
</figure>
)}
<div
className="markdown-content"
dangerouslySetInnerHTML={{ __html: html }}
/>
</main>
<SiteFooter />
</div>
)
}
/** Seitentitel für den Browser-Tab. */
export function legalPageMetadata(page: SitePageKey) {
return { title: SITE_PAGE_META[page].title }
}