* * * * Available sizes: * - 'small': Horizontal scrolling row of compact cards (cover, title, date) * - 'medium': Responsive wrapping grid (cover, title, date) * - 'large': Responsive wrapping grid with summary (cover, title, date, summary) */ function newsPreviewT(string $key): string { $ctx = $GLOBALS['ctx'] ?? null; $translations = $ctx?->get('translations', []) ?? []; $fallbacks = [ 'heading' => 'Siste nytt', 'read_more' => 'Les mer', 'see_all' => 'Se alle nyheter', ]; return $translations["news_preview.$key"] ?? $fallbacks[$key] ?? $key; } function newsPreviewBuildItems(int $count): array { $ctx = $GLOBALS['ctx'] ?? null; if (!$ctx) return []; $newsDir = $ctx->contentDir . '/nyheter'; if (!is_dir($newsDir)) return []; $langPrefix = $ctx->get('langPrefix', ''); $subdirs = getSubdirectories($newsDir); $items = []; foreach ($subdirs as $dir) { $itemPath = "$newsDir/$dir"; $metadata = loadMetadata($itemPath); $title = $metadata['title'] ?? extractTitle($itemPath) ?? $dir; $rawDate = $metadata['date'] ?? extractRawDateFromFolder($dir); $date = $rawDate ? Hooks::apply(Hook::PROCESS_CONTENT, $rawDate, 'date_format') : null; $cover = findCoverImage($itemPath); $slug = $metadata['slug'] ?? $dir; $items[] = [ 'title' => $title, 'url' => $langPrefix . '/nyheter/' . urlencode($slug) . '/', 'date' => $date, 'rawDate' => $rawDate, 'summary' => $metadata['summary'] ?? extractMetaDescription($itemPath, $metadata), 'cover' => $cover ? $langPrefix . '/nyheter/' . urlencode($dir) . '/' . $cover : null, ]; } usort($items, fn($a, $b) => strcmp($b['rawDate'] ?? '', $a['rawDate'] ?? '')); return array_slice($items, 0, $count); } function newsPreviewRenderSmall(array $items, string $langPrefix): string { $heading = htmlspecialchars(newsPreviewT('heading')); $seeAll = htmlspecialchars(newsPreviewT('see_all')); $seeAllUrl = htmlspecialchars($langPrefix . '/nyheter/'); $cards = ''; foreach ($items as $item) { $title = htmlspecialchars($item['title']); $url = htmlspecialchars($item['url']); $date = $item['date'] ? '

' . htmlspecialchars($item['date']) . '

' : ''; $cover = $item['cover'] ? '' . $title . '' : ''; $cards .= << {$cover}

{$title}

{$date}
HTML; } return <<

{$heading}

{$seeAll}
{$cards}
HTML; } function newsPreviewRenderMedium(array $items, string $langPrefix): string { $heading = htmlspecialchars(newsPreviewT('heading')); $seeAll = htmlspecialchars(newsPreviewT('see_all')); $seeAllUrl = htmlspecialchars($langPrefix . '/nyheter/'); $cards = ''; foreach ($items as $item) { $title = htmlspecialchars($item['title']); $url = htmlspecialchars($item['url']); $date = $item['date'] ? '

' . htmlspecialchars($item['date']) . '

' : ''; $cover = $item['cover'] ? '' . $title . '' : ''; $cards .= << {$cover}

{$title}

{$date} HTML; } return <<

{$heading}

{$seeAll}
{$cards}
HTML; } function newsPreviewRenderLarge(array $items, string $langPrefix): string { $heading = htmlspecialchars(newsPreviewT('heading')); $readMore = htmlspecialchars(newsPreviewT('read_more')); $seeAll = htmlspecialchars(newsPreviewT('see_all')); $seeAllUrl = htmlspecialchars($langPrefix . '/nyheter/'); $cards = ''; foreach ($items as $item) { $title = htmlspecialchars($item['title']); $url = htmlspecialchars($item['url']); $date = $item['date'] ? '

' . htmlspecialchars($item['date']) . '

' : ''; $cover = $item['cover'] ? '' . $title . '' : ''; $summary = $item['summary'] ? '

' . htmlspecialchars($item['summary']) . '

' : ''; $cards .= << {$cover}

{$title}

{$date} {$summary} {$readMore} HTML; } return <<

{$heading}

{$seeAll}
{$cards}
HTML; } function newsPreviewGetStyles(): string { static $included = false; if ($included) return ''; $included = true; return <<<'STYLES' STYLES; } /** * Render a news preview section. * * @param int $count Number of news items to show (default: 3) * @param string $size Display size: 'small', 'medium', or 'large' (default: 'medium') * @return string The complete HTML for the news preview section */ function news_preview(int $count = 3, string $size = 'medium'): string { $ctx = $GLOBALS['ctx'] ?? null; if (!$ctx) return ''; $items = newsPreviewBuildItems($count); if (empty($items)) return ''; $langPrefix = $ctx->get('langPrefix', ''); $html = newsPreviewGetStyles(); $html .= match ($size) { 'small' => newsPreviewRenderSmall($items, $langPrefix), 'large' => newsPreviewRenderLarge($items, $langPrefix), default => newsPreviewRenderMedium($items, $langPrefix), }; return $html; }