' . inline_markdown(trim($paragraph)) . "
\n"; $paragraph = ''; } }; $close_list = function () use (&$html, &$in_list, &$in_ol) { if ($in_list) { $html .= "\n"; $in_list = false; } if ($in_ol) { $html .= "\n"; $in_ol = false; } }; foreach ($lines as $line) { // Fenced code blocks if (preg_match('/^```(\w*)/', $line, $m)) { $flush_paragraph(); $close_list(); if (!$in_code) { $lang = $m[1] ? ' class="language-' . e($m[1]) . '"' : ''; $html .= "";
$in_code = true;
} else {
$html .= "\n";
$in_code = false;
}
continue;
}
if ($in_code) {
$html .= e($line) . "\n";
continue;
}
// Blank line
if (trim($line) === '') {
$flush_paragraph();
$close_list();
if ($in_blockquote) { $html .= "\n"; $in_blockquote = false; }
continue;
}
// Headings
if (preg_match('/^(#{1,6})\s+(.+)/', $line, $m)) {
$flush_paragraph(); $close_list();
$level = strlen($m[1]);
$id = slugify($m[2]);
$html .= "\n"; $in_blockquote = true; } $html .= '\n"; return $html; } /** * Process inline markdown: bold, italic, code, links, images. */ function inline_markdown(string $text): string { // Images:  $text = preg_replace('/!\[([^\]]*)\]\(([^)]+)\)/', '' . inline_markdown($m[1]) . "
\n"; continue; } // Unordered list if (preg_match('/^[\-\*]\s+(.+)/', $line, $m)) { $flush_paragraph(); if ($in_ol) { $html .= "\n"; $in_ol = false; } if (!$in_list) { $html .= "\n"; $in_list = true; } $html .= '
\n"; $in_list = false; } if (!$in_ol) { $html .= "- ' . inline_markdown($m[1]) . "
\n"; continue; } // Ordered list if (preg_match('/^\d+\.\s+(.+)/', $line, $m)) { $flush_paragraph(); if ($in_list) { $html .= "\n"; $in_ol = true; } $html .= '
- ' . inline_markdown($m[1]) . "
\n"; continue; } // Paragraph text $paragraph .= $line . "\n"; } $flush_paragraph(); $close_list(); if ($in_code) $html .= "\n"; if ($in_blockquote) $html .= "
$1', $text);
return $text;
}
/**
* HTML-escape shorthand.
*/
function e(string $s): string {
return htmlspecialchars($s, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
/**
* Generate a URL-friendly slug from text.
*/
function slugify(string $text): string {
$text = strtolower(strip_tags($text));
$text = preg_replace('/[^a-z0-9\s-]/', '', $text);
return preg_replace('/[\s-]+/', '-', trim($text));
}
/**
* Load and render a markdown content file. Returns HTML or null.
*/
function load_content(string $slug): ?string {
global $CONTENT_MAP;
$file = $CONTENT_MAP[$slug] ?? null;
if (!$file) return null;
$path = CONTENT_DIR . $file;
if (!file_exists($path)) return null;
return markdown_to_html(file_get_contents($path));
}
/**
* Check if current page matches slug (for nav highlighting).
*/
function is_active(string $slug, string $current): string {
return ($slug === $current) ? ' class="active"' : '';
}
/**
* Get the URL for a page slug.
*/
function page_url(string $slug): string {
if ($slug === 'home') return SITE_BASE_URL;
return SITE_BASE_URL . $slug;
}