"use client";
type MarkdownRendererProps = {
content: string;
};
export function MarkdownRenderer({ content }: MarkdownRendererProps) {
const renderMarkdown = (md: string): string => {
const lines = md.split("\n");
const result: string[] = [];
let inCodeBlock = false;
let codeBlockLang = "";
let codeBlockContent: string[] = [];
let inList = false;
let listType: "ul" | "ol" | null = null;
const escapeHtml = (text: string): string => {
return text
.replace(/&/g, "&")
.replace(//g, ">");
};
const processInline = (text: string): string => {
let processed = text;
// Inline code (avant les autres pour éviter les conflits)
processed = processed.replace(
/`([^`]+)`/g,
'$1'
);
// Bold
processed = processed.replace(
/\*\*([^*]+)\*\*/g,
'$1'
);
// Italic
processed = processed.replace(
/\*([^*]+)\*/g,
'$1'
);
// Links
processed = processed.replace(
/\[([^\]]+)\]\(([^)]+)\)/g,
'$1'
);
// Images
processed = processed.replace(
/!\[([^\]]*)\]\(([^)]+)\)/g,
''
);
return processed;
};
const closeList = () => {
if (inList && listType) {
result.push(listType === "ul" ? "" : "");
inList = false;
listType = null;
}
};
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Code block start/end
if (line.trim().startsWith("```")) {
if (!inCodeBlock) {
closeList();
inCodeBlock = true;
codeBlockLang = line.trim().slice(3).trim() || "text";
codeBlockContent = [];
} else {
// End code block
const code = escapeHtml(codeBlockContent.join("\n"));
result.push(`
${code}
${processInline( escapeHtml(trimmedLine.slice(2)) )}` ); continue; } // Unordered list if (trimmedLine.startsWith("- ") || trimmedLine.startsWith("* ")) { if (!inList || listType !== "ul") { closeList(); result.push('
${processInline( escapeHtml(trimmedLine) )}
` ); } // Close any remaining list closeList(); // Close any unclosed code block if (inCodeBlock && codeBlockContent.length > 0) { const code = escapeHtml(codeBlockContent.join("\n")); result.push(`${code}