import React from 'react' import Link from 'next/link' interface RenderState { currentList: string[] inCodeBlock: boolean codeBlockContent: string[] } export function renderMarkdown(markdown: string): JSX.Element[] { const lines = markdown.split('\n') const elements: JSX.Element[] = [] const state: RenderState = { currentList: [], inCodeBlock: false, codeBlockContent: [], } lines.forEach((line, index) => { if (line.startsWith('```')) { handleCodeBlock(line, index, state, elements) return } if (state.inCodeBlock) { state.codeBlockContent.push(line) return } closeListIfNeeded(line, index, state, elements) if (line.startsWith('# ')) { elements.push(

{line.substring(2)}

) } else if (line.startsWith('## ')) { elements.push(

{line.substring(3)}

) } else if (line.startsWith('### ')) { elements.push(

{line.substring(4)}

) } else if (line.startsWith('#### ')) { elements.push(

{line.substring(5)}

) } else if (line.startsWith('- ') || line.startsWith('* ')) { state.currentList.push(line) } else if (line.includes('[') && line.includes('](')) { renderLink(line, index, elements) } else if (line.includes('**') || line.includes('`')) { renderBoldAndCode(line, index, elements) } else if (line.trim() !== '') { elements.push(

{line}

) } else if (elements.length > 0 && elements[elements.length - 1].type !== 'br') { elements.push(
) } }) closeListIfNeeded('', lines.length, state, elements) return elements } function handleCodeBlock( line: string, index: number, state: RenderState, elements: JSX.Element[] ): void { if (state.inCodeBlock) { elements.push(
        {state.codeBlockContent.join('\n')}
      
) state.codeBlockContent = [] state.inCodeBlock = false } else { state.inCodeBlock = true } } function closeListIfNeeded( line: string, index: number, state: RenderState, elements: JSX.Element[] ): void { if (state.currentList.length > 0 && !line.startsWith('- ') && !line.startsWith('* ') && line.trim() !== '') { elements.push( ) state.currentList = [] } } function createLinkElement( text: string, href: string, key: string, isExternal: boolean ): JSX.Element { const className = 'text-blue-600 hover:text-blue-800 underline' if (isExternal) { return ( {text} ) } return ( {text} ) } function renderLink(line: string, index: number, elements: JSX.Element[]): void { const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g let lastIndex = 0 const parts: (string | JSX.Element)[] = [] let match while ((match = linkRegex.exec(line)) !== null) { if (match.index > lastIndex) { parts.push(line.substring(lastIndex, match.index)) } const href = match[2] const isExternal = href.startsWith('http') parts.push(createLinkElement(match[1], href, `link-${index}-${match.index}`, isExternal)) lastIndex = match.index + match[0].length } if (lastIndex < line.length) { parts.push(line.substring(lastIndex)) } elements.push(

{parts}

) } function renderBoldAndCode(line: string, index: number, elements: JSX.Element[]): void { const parts: (string | JSX.Element)[] = [] const codeRegex = /`([^`]+)`/g let codeMatch let lastIndex = 0 while ((codeMatch = codeRegex.exec(line)) !== null) { if (codeMatch.index > lastIndex) { const beforeCode = line.substring(lastIndex, codeMatch.index) processBold(beforeCode, parts) } parts.push( {codeMatch[1]} ) lastIndex = codeMatch.index + codeMatch[0].length } if (lastIndex < line.length) { const remaining = line.substring(lastIndex) processBold(remaining, parts) } elements.push(

{parts.length > 0 ? parts : line}

) } function processBold(text: string, parts: (string | JSX.Element)[]): void { const boldParts = text.split(/(\*\*[^*]+\*\*)/g) boldParts.forEach((part, i) => { if (part.startsWith('**') && part.endsWith('**')) { parts.push({part.slice(2, -2)}) } else if (part) { parts.push(part) } }) }