import { Panel } from './Panel'; import { t } from '@/services/i18n'; import { joinSafeHtml, safeHtml, safeUrlAttr, type SafeHtml } from '@/utils/sanitize'; import { getHydratedData } from '@/services/bootstrap'; import { createLazyClient, getRpcBaseUrl, rpcFetch } from '@/services/rpc-client'; import type { ListClimateNewsResponse, ClimateNewsItem } from '@/generated/client/worldmonitor/climate/v1/service_client'; import { ClimateServiceClient } from '@/services/generated-rpc-clients'; const getClimateClient = createLazyClient(() => new ClimateServiceClient(getRpcBaseUrl(), { fetch: rpcFetch })); function formatTimeAgo(epochMs: number): string { const diffMs = Date.now() - epochMs; const minutes = Math.floor(diffMs / 60_000); if (minutes < 1) return 'just now'; if (minutes < 60) return `${minutes}m ago`; const hours = Math.floor(minutes / 60); if (hours < 24) return `${hours}h ago`; const days = Math.floor(hours / 24); if (days === 1) return '1d ago'; return `${days}d ago`; } function truncateSummary(text: string, maxLen = 120): string { if (!text || text.length <= maxLen) return text || ''; return text.slice(0, maxLen).replace(/\s+\S*$/, '') + '...'; } function renderNewsCard(item: ClimateNewsItem): SafeHtml { const timeAgo = item.publishedAt ? formatTimeAgo(item.publishedAt) : ''; const summary = truncateSummary(item.summary); const safeUrl = safeUrlAttr(item.url); const inner = safeHtml`