--- import Layout from '../../layouts/Layout.astro'; import { marked } from 'marked'; const { slug } = Astro.params; const API_URL = (typeof process !== 'undefined' ? process.env.PUBLIC_API_URL : import.meta.env.PUBLIC_API_URL) || 'http://localhost:3000'; interface PostDetail { slug: string; content: string; } let post: PostDetail | null = null; let html = ''; let error = ''; // Custom citation pre-processor (Regex-Free!) function processCitations(text: string) { let result = text; // Keep looking for citation tags until there are none left while (result.includes('', startIndex)) { // Safety check: if there's no closing bracket, stop to prevent infinite loops if (endIndex === -1) break; // Extract the exact string to replace (e.g., "") const fullMatch = result.substring(startIndex, endIndex + 1); // Extract just the numbers/IDs (e.g., "1, 2") const citations = result.substring(startIndex + 6, endIndex).trim(); // Build the HTML links const links = citations.split(',').map((c: string) => { const id = c.trim(); return `${id}`; }).join(', '); // Build the superscript wrapper const replacement = `[${links}]`; // Replace the first occurrence we found, then the loop will handle the rest result = result.replace(fullMatch, replacement); } return result; } try { const response = await fetch(`${API_URL}/api/posts/${slug}`); if (response.ok) { post = await response.json(); if (post) { // 1. Process citations first const processedContent = processCitations(post.content); // 2. Then parse the rest of the markdown html = await marked.parse(processedContent); } } else { error = 'Post not found'; } } catch (e) { const cause = (e as any)?.cause; error = `Could not connect to backend at ${API_URL}: ${e instanceof Error ? e.message : String(e)}${cause ? ' (Cause: ' + (cause.message || cause.code || JSON.stringify(cause)) + ')' : ''}`; console.error(error); } function formatSlug(slug: string) { if (!slug) return ''; return slug .split('-') .map(word => word.charAt(0).toUpperCase() + word.slice(1)) .join(' '); } ---
Back to list {post && (

{formatSlug(post.slug)}

)}
{error && (

{error}

Return home
)} {post && (
)}