feat: Enhance Guest Frontend with new features and UI improvements

This commit is contained in:
2025-09-09 21:22:44 +02:00
parent e3423a7da5
commit 81958899a6
5 changed files with 141 additions and 23 deletions

View File

@@ -4,10 +4,47 @@ import { useParams } from 'react-router-dom';
export default function LegalPage() {
const { page } = useParams();
const [loading, setLoading] = React.useState(true);
const [title, setTitle] = React.useState('');
const [body, setBody] = React.useState('');
React.useEffect(() => {
async function load() {
setLoading(true);
const res = await fetch(`/api/v1/legal/${encodeURIComponent(page || '')}?lang=de`, { headers: { 'Cache-Control': 'no-store' }});
if (res.ok) {
const j = await res.json();
setTitle(j.title || '');
setBody(j.body_markdown || '');
}
setLoading(false);
}
if (page) load();
}, [page]);
return (
<Page title={`Rechtliches: ${page}`}>
<p>Impressum / Datenschutz / AGB</p>
<Page title={title || `Rechtliches: ${page}` }>
{loading ? <p>Lädt</p> : <Markdown md={body} />}
</Page>
);
}
function Markdown({ md }: { md: string }) {
// Tiny, safe Markdown: paragraphs + basic bold/italic + links; no external dependency
const html = React.useMemo(() => {
let s = md
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
// bold **text**
s = s.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
// italic *text*
s = s.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, '<em>$1</em>');
// links [text](url)
s = s.replace(/\[(.+?)\]\((https?:[^\s)]+)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1<\/a>');
// paragraphs
s = s.split(/\n{2,}/).map(p => `<p>${p.replace(/\n/g, '<br/>')}<\/p>`).join('\n');
return s;
}, [md]);
return <div className="prose prose-sm dark:prose-invert" dangerouslySetInnerHTML={{ __html: html }} />;
}