feat(geschichten): add stripHtml util and GeschichtenCard component
stripHtml() strips tags via DOMParser (browser) with a regex fallback for SSR. plainExcerpt() truncates at a word boundary with an ellipsis. Both covered by Vitest specs. GeschichtenCard renders the top 3 published stories about a person on /persons/[id], with an editorial excerpt, publication date, author, and a "+ Geschichte schreiben" link visible only to BLOG_WRITERs. Footer link to /geschichten?personId=... appears once geschichten.length >= 3. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
23
frontend/src/lib/utils/stripHtml.ts
Normal file
23
frontend/src/lib/utils/stripHtml.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Strip HTML tags from a string and return the plain text.
|
||||
* Uses DOMParser in the browser, falls back to a regex strip on the server
|
||||
* (where DOMParser is not available without isomorphic-dompurify's JSDOM).
|
||||
*/
|
||||
export function stripHtml(html: string | null | undefined): string {
|
||||
if (!html) return '';
|
||||
if (typeof DOMParser === 'function') {
|
||||
const doc = new DOMParser().parseFromString(html, 'text/html');
|
||||
return (doc.body.textContent ?? '').trim();
|
||||
}
|
||||
return html.replace(/<[^>]*>/g, '').trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip HTML and truncate to a maximum length, appending an ellipsis when
|
||||
* the source exceeds it. Used for editorial story excerpts.
|
||||
*/
|
||||
export function plainExcerpt(html: string | null | undefined, max = 80): string {
|
||||
const text = stripHtml(html);
|
||||
if (text.length <= max) return text;
|
||||
return text.slice(0, max).replace(/\s+\S*$/, '') + '…';
|
||||
}
|
||||
Reference in New Issue
Block a user