import Decimal from "decimal.js"; import Link from "next/link"; import { AlertCircleIcon, ArrowUpRightIcon, Clock3Icon, InfoIcon, LightbulbIcon, TriangleAlertIcon, } from "lucide-react"; import type { z } from "zod"; import { ComparisonChart } from "@/components/public/comparison-chart"; import { MediaImage } from "@/components/public/media-image"; import { TermDetail } from "@/components/public/term-detail"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@/components/ui/accordion"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Badge } from "@/components/ui/badge"; import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, } from "@/components/ui/carousel"; import { Separator } from "@/components/ui/separator"; import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { blockSchemas, resolveBlock } from "@/lib/blocks"; import { prepareComparisonChart } from "@/lib/charts/comparison"; import { evaluateDataSource } from "@/lib/content/data-source"; import type { DataSourceSnapshot, PageBlockSnapshot, PageSnapshot, } from "@/lib/content/types"; import { cn } from "@/lib/utils"; type Config = z.output< (typeof blockSchemas)[Type] >; const widthClasses = { content: "mx-auto max-w-3xl", wide: "mx-auto max-w-6xl", full: "w-full", } as const; function evaluatedSource( source: DataSourceSnapshot | undefined, ): ReturnType | null { if (!source) return null; try { return evaluateDataSource(source); } catch { return null; } } function displayCell( evaluated: ReturnType, rowId: string, field: string, ): string { const cell = evaluated.rows.find((row) => row.id === rowId)?.cells[field]; return cell && !cell.error && cell.display != null ? cell.display : "—"; } export function collectGuideSections( blocks: PageBlockSnapshot[], ): Array<{ id: string; label: string }> { return blocks.flatMap((serialized) => { const resolution = resolveBlock(serialized); if (resolution.kind !== "ready") return []; if (resolution.block.type === "section") { const config = blockSchemas.section.parse(resolution.block.config); return [{ id: config.anchor ?? `section-${serialized.id}`, label: config.title }]; } if (resolution.block.type === "heading") { const config = blockSchemas.heading.parse(resolution.block.config); return [{ id: config.anchor ?? `section-${serialized.id}`, label: config.text }]; } return []; }); } export function PublicBlockRenderer({ snapshot }: { snapshot: PageSnapshot }) { return (
{snapshot.blocks.map((serialized) => { const resolution = resolveBlock(serialized); if (resolution.kind !== "ready") { return (
); } const layout = resolution.block.responsiveLayout as { width: keyof typeof widthClasses; hideOnMobile: boolean; }; return (
); })}
); } function ReadyBlock({ block, dataSources, }: { block: ReturnType extends infer Resolution ? Resolution extends { kind: "ready"; block: infer Ready } ? Ready : never : never; dataSources: PageSnapshot["dataSources"]; }) { switch (block.type) { case "profile": return ; case "rich-text": return ; case "heading": { const config = blockSchemas.heading.parse(block.config); const id = config.anchor ?? `section-${block.id}`; const Heading = `h${config.level}` as "h2" | "h3" | "h4"; return ( {config.text} ); } case "callout": return ; case "stat-cards": return ; case "key-value": return ; case "ranking": return ( ).dataSourceId]} /> ); case "team-composition": return ( ).dataSourceId]} /> ); case "rotation": return ; case "table": return ( ).dataSourceId]} /> ); case "comparison-chart": { const config = blockSchemas["comparison-chart"].parse(block.config); return ; } case "image": { const config = blockSchemas.image.parse(block.config); return (
{config.caption ? (
{config.caption}
) : null}
); } case "gallery": return ; case "tabs": return ; case "accordion": return ; case "section": { const config = blockSchemas.section.parse(block.config); return (

{config.title}

{config.description ?

{config.description}

: null}
); } case "columns": { const config = blockSchemas.columns.parse(block.config); return ( ); } case "links": return ; case "separator": { const config = blockSchemas.separator.parse(block.config); return (
{config.label ? {config.label} : null} {config.label ? : null}
); } } } function ProfileBlock({ config }: { config: Config<"profile"> }) { return (
{config.eyebrow ? (

{config.eyebrow}

) : null}

{config.title}

{config.subtitle ?

{config.subtitle}

: null}
{config.summary ?

{config.summary}

: null}
{config.badges.map((badge) => ( {badge.label}{badge.value ? ` · ${badge.value}` : ""} ))}
); } function RichTextBlock({ config }: { config: Config<"rich-text"> }) { return (
{config.content.map((node, index) => { if (node.type === "paragraph") return

{node.text}

; if (node.type === "quote") { return
{node.text}
; } const List = node.type === "numbered-list" ? "ol" : "ul"; return ( {node.items.map((item, itemIndex) =>
  • {item}
  • )}
    ); })}
    ); } function CalloutBlock({ config }: { config: Config<"callout"> }) { const icon = { info: