feat(quick-260916-dcz): CHANGELOG.md, Seite "Was ist neu" mit Kanalfilter, Versionszeile als Link, Bauzeit-Einbettung
- CHANGELOG.md (Wurzel): Unveroeffentlicht (bwo + dyv + diese Seite, 8 Punkte) und 1.0.0 – 2026-09-15 (11 Punkte aus den Handbuechern), Alltagssprache, echte Umlaute - next.config.ts liest CHANGELOG.md zur Bauzeit nach env.TESSERA_CHANGELOG_MD; .dockerignore-Ausnahme !CHANGELOG.md und COPY-Zeile im Web-Dockerfile - lib/changelog.ts: filterChangelogForChannel (live ohne Unveroeffentlicht, beta/dev mit "Noch nicht freigegeben (Beta)", leerer Abschnitt ausgeblendet), 10 Tests - Server-Seite /changelog (MDEditor.Markdown + rehype-sanitize, Hinweis auf Beta, Leer-Text), 3 Tests; Versionszeile ist Link mit aria-label, 2 Tests - de/en: sidebar.whatsNew und Namensraum changelog; Web-Suite 49/309, tsc 0 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import MDEditor from '@uiw/react-md-editor';
|
||||
import rehypeSanitize from 'rehype-sanitize';
|
||||
import { useTheme } from 'next-themes';
|
||||
|
||||
/**
|
||||
* Gerenderte Aenderungsliste fuer die Seite "Was ist neu" (quick-260916-dcz).
|
||||
*
|
||||
* Nutzt `MDEditor.Markdown` aus dem bereits installierten `@uiw/react-md-editor`
|
||||
* (wie die Vorschau des Notiz-Widgets) mit `rehype-sanitize` — kein neues
|
||||
* Paket, kein dangerouslySetInnerHTML. Der Farbmodus folgt `next-themes`
|
||||
* erst nach dem Mount (vorher 'light'), damit Server- und Client-Markup
|
||||
* uebereinstimmen (mounted-Guard wie in AppShell). Der Markdown-Text kommt
|
||||
* als Prop von der Server-Seite; dieses Modul importiert `@/lib/changelog`
|
||||
* bewusst NICHT, damit der Text nicht in Client-Chunks landet.
|
||||
*/
|
||||
export function ChangelogView({ markdown }: { markdown: string }) {
|
||||
const { resolvedTheme } = useTheme();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const mode: 'light' | 'dark' = mounted && resolvedTheme === 'dark' ? 'dark' : 'light';
|
||||
|
||||
return (
|
||||
<div data-testid="changelog-markdown" className="rounded-md border border-border bg-card p-4">
|
||||
<MDEditor.Markdown
|
||||
source={markdown}
|
||||
rehypePlugins={[[rehypeSanitize]]}
|
||||
wrapperElement={{ 'data-color-mode': mode }}
|
||||
style={{ background: 'transparent' }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user