diff --git a/AGENT.md b/CLAUDE.md similarity index 98% rename from AGENT.md rename to CLAUDE.md index 969c351..e637f37 100644 --- a/AGENT.md +++ b/CLAUDE.md @@ -28,6 +28,7 @@ - Custom templates override defaults (never modify defaults) - Custom templates live in `/app/custom/` - Default templates provide fallback behavior +- Docs get their own template variants for specialized presentation - Templates use PHP includes—simple and straightforward ### Content Conventions diff --git a/app/rendering.php b/app/rendering.php index 1ee87e1..f197a37 100644 --- a/app/rendering.php +++ b/app/rendering.php @@ -21,19 +21,21 @@ function renderContentFile(string $filePath, ?Context $ctx = null): string { require_once __DIR__ . '/vendor/ParsedownExtra.php'; } $html = '
' . (new ParsedownExtra())->text(file_get_contents($filePath)) . '
'; - + + // Add language prefix to internal links if ($langPrefix) { $html = preg_replace( - '/href="(\/[^"]*)"/', - 'href="' . $langPrefix . '$1"', + '/href="(\/[^"]*)"/', + 'href="' . $langPrefix . '$1"', $html ); } - + setCachedMarkdown($filePath, $html, $langPrefix); echo $html; } } elseif (in_array($ext, ['html', 'php'])) { + // Make template variables available to PHP content files if ($ctx !== null && $ext === 'php') { $templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [], $ctx); extract($templateVars); @@ -46,10 +48,12 @@ function renderContentFile(string $filePath, ?Context $ctx = null): string { function renderTemplate(Context $ctx, string $content, int $statusCode = 200): void { global $GLOBALS; + // Get basic template vars $navigation = $ctx->navigation; $homeLabel = $ctx->homeLabel; $pageTitle = null; + // Let plugins add template variables $templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [ 'content' => $content, 'navigation' => $navigation, @@ -78,6 +82,7 @@ function renderFile(Context $ctx, string $filePath): void { $pageDir = dirname($realPath); $pageMetadata = loadMetadata($pageDir); + // Load page-level plugins getPluginManager()->loadPagePlugins($pageMetadata); $navigation = $ctx->navigation; @@ -85,10 +90,12 @@ function renderFile(Context $ctx, string $filePath): void { $pageTitle = $pageMetadata['title'] ?? null; $metaDescription = extractMetaDescription($pageDir, $pageMetadata); + // Check for page-specific CSS $pageCss = findPageCss($pageDir, $ctx->contentDir); $pageCssUrl = $pageCss['url'] ?? null; $pageCssHash = $pageCss['hash'] ?? null; + // Check for cover image for social media $coverImage = findCoverImage($pageDir); $socialImageUrl = null; if ($coverImage) { @@ -97,6 +104,7 @@ function renderFile(Context $ctx, string $filePath): void { $socialImageUrl = '/' . ($relativePath ? $relativePath . '/' : '') . $coverImage; } + // Let plugins add template variables $templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [ 'content' => $content, 'navigation' => $navigation, @@ -110,6 +118,7 @@ function renderFile(Context $ctx, string $filePath): void { extract($templateVars); + // Wrap content with page template ob_start(); require $ctx->templates->page; $wrappedContent = ob_get_clean(); @@ -118,6 +127,7 @@ function renderFile(Context $ctx, string $filePath): void { exit; } + // Unknown type - 404 renderTemplate($ctx, "

404 - Not Found

The requested file could not be found.

", 404); } @@ -129,6 +139,7 @@ function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void $pageMetadata = loadMetadata($pageDir); + // Load page-level plugins getPluginManager()->loadPagePlugins($pageMetadata); $navigation = $ctx->navigation; @@ -136,10 +147,12 @@ function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void $pageTitle = $pageMetadata['title'] ?? null; $metaDescription = extractMetaDescription($pageDir, $pageMetadata); + // Check for page-specific CSS $pageCss = findPageCss($pageDir, $ctx->contentDir); $pageCssUrl = $pageCss['url'] ?? null; $pageCssHash = $pageCss['hash'] ?? null; + // Check for cover image $coverImage = findCoverImage($pageDir); $socialImageUrl = null; if ($coverImage) { @@ -148,6 +161,7 @@ function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void $socialImageUrl = '/' . ($relativePath ? $relativePath . '/' : '') . $coverImage; } + // Let plugins add template variables $templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [ 'content' => $content, 'navigation' => $navigation, @@ -161,6 +175,7 @@ function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void extract($templateVars); + // Wrap content with page template ob_start(); require $ctx->templates->page; $wrappedContent = ob_get_clean();