'YouTube', 'reddit' => 'Reddit', 'rt' => 'RT', default => ucfirst($source), }; } public static function sourceBadge(string $source): string { return match ($source) { 'youtube' => 'text-bg-danger', 'reddit' => 'text-bg-warning', 'rt' => 'text-bg-dark', default => 'text-bg-secondary', }; } public static function sourceColor(string $source): string { return match ($source) { 'youtube' => '#ff3b5c', 'reddit' => '#ff7a2f', 'rt' => '#1fcb93', default => '#f1f3f7', }; } public static function rangeLabel(string $range): string { return match ($range) { '1h' => '1 hour', '2h' => '2 hours', '6h' => '6 hours', '24h' => '24 hours', '7d' => '7 days', default => 'All time', }; } public static function render(string $template, array $data = []): string { $path = dirname(__DIR__) . '/templates/' . $template . '.php'; if (!is_file($path)) { throw new \RuntimeException(sprintf('Template "%s" not found.', $template)); } extract($data, EXTR_SKIP); ob_start(); include $path; return (string) ob_get_clean(); } public static function timeAgo(?string $iso): string { if ($iso === null || $iso === '') { return ''; } $timestamp = strtotime($iso); if ($timestamp === false) { return ''; } $diff = time() - $timestamp; if ($diff < 60) { return 'just now'; } $units = [ 31536000 => 'y', 2592000 => 'mo', 604800 => 'w', 86400 => 'd', 3600 => 'h', 60 => 'm', ]; foreach ($units as $seconds => $label) { if ($diff >= $seconds) { return floor($diff / $seconds) . $label . ' ago'; } } return 'just now'; } }