import { marked } from "marked"; import katex from "katex"; marked.use({ breaks: true, gfm: true, }); function renderMath(html: string): string { // Display math: $$...$$ html = html.replace(/\$\$([\s\S]+?)\$\$/g, (_, tex) => { try { return katex.renderToString(tex.trim(), { displayMode: true, throwOnError: false }); } catch { return `${tex}`; } }); // Inline math: $...$ (but not inside code blocks or pre) html = html.replace(/(?]*>)\$([^$\n]+?)\$(?![^<]*<\/code>)/g, (_, tex) => { try { return katex.renderToString(tex.trim(), { displayMode: false, throwOnError: false }); } catch { return `${tex}`; } }); return html; } export function renderMarkdown(md: string): string { const html = marked.parse(md) as string; return renderMath(html); } export interface PageData { position: number; markdown: string; image_key: string; } export interface DocumentData { id: string; title: string; date: string; pages: PageData[]; } export function renderDocument(doc: DocumentData): string { const pages = doc.pages.map((page, i) => { const header = i === 0 ? `

${escapeHtml(doc.date)}

${escapeHtml(doc.title)}

` : ""; const content = renderMarkdown(page.markdown); const imageUrl = `/i/${page.image_key}`; const ext = page.image_key?.split(".").pop()?.toUpperCase() || "Image"; return `
${header} ${content}
`; }).join(""); return pages; } function escapeHtml(s: string): string { return s .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); }