/* eslint-disable security/detect-unsafe-regex */ "use client"; import React from "react"; interface WikiLinkRendererProps { /** HTML content with wiki-links to parse */ html: string; /** Additional CSS classes */ className?: string; } /** * WikiLinkRenderer - Parses and renders wiki-links in HTML content * * Converts: * - [[slug]] → clickable link to /knowledge/slug * - [[slug|display text]] → clickable link with custom text * * Features: * - Distinct styling for wiki-links (blue color, underline) * - Graceful handling of broken links (gray out) * - Preserves all other HTML formatting */ export function WikiLinkRenderer({ html, className = "", }: WikiLinkRendererProps): React.ReactElement { const processedHtml = React.useMemo(() => { return parseWikiLinks(html); }, [html]); return (
); } /** * Parse wiki-links in HTML and convert to anchor tags * * Supports: * - [[slug]] - basic link * - [[slug|display text]] - link with custom display text */ function parseWikiLinks(html: string): string { // Match [[...]] patterns // Group 1: target slug // Group 2: optional display text after | const wikiLinkRegex = /\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g; return html.replace(wikiLinkRegex, (match, slug: string, displayText?: string) => { const trimmedSlug = slug.trim(); const text = displayText?.trim() ?? trimmedSlug; // Validate slug contains only safe characters if (!/^[a-zA-Z0-9\-_./]+$/.test(trimmedSlug)) { // Invalid slug - return original text without creating a link return escapeHtml(match); } // Create a styled link // Using data-wiki-link attribute for styling and click handling return `${escapeHtml(text)}`; }); } /** * Handle wiki-link clicks * Intercepts clicks on wiki-links to use Next.js navigation */ function handleWikiLinkClick(e: React.MouseEvent