import { Suspense } from 'react'; import Link from 'next/link'; import { Hero } from '@/components/home/hero'; import { IndexTape } from '@/components/market/index-strip'; import { AssetRail, LatestTransactions, LotsRail, MarketInsights, RadarRail, SalesRail } from '@/components/home/sections'; import { CategoryGrid } from '@/components/market/category-grid'; import { attachGuidePrices, getCategoryThumbnails, getLatestObservationsFeed } from '@/lib/queries/assets'; import { fmtNum } from '@/lib/format'; import { Skeleton } from '@/components/ui/primitives'; import { getLatestSales, getSiteStats } from '@/lib/queries/site'; import { listIndices } from '@/lib/queries/indices'; import { rankedAssets } from '@/lib/queries/assets'; import { getMarketRows } from '@/lib/queries/markets'; import { getTopSales, listLots, listRadar } from '@/lib/queries/market-lists'; import { LineChart } from '@/components/charts/line-chart'; import { getIndexSeries } from '@/lib/queries/indices'; export const revalidate = 120; export default async function HomePage() { const [stats, indices] = await Promise.all([getSiteStats(), listIndices()]); return (
}> {Array.from({ length: 6 }).map((_, i) => )}
}> }>
); } async function FlagshipPanel() { const indices = await listIndices(); const rare = indices.find((i) => i.isFlagship); const subs = indices.filter((i) => !i.isFlagship && i.latest); const series = rare ? await getIndexSeries(rare.id, 365) : []; return (

RARE · RareIndex Global Collectibles Index

Chain-linked, equal-weighted across subindices · base 1,000 on 2024-01-01

Index detail →
({ x: p.date, y: p.value })) }]} emptyLabel={rare ? `Index building — publishes once ${rare.minConstituents} priced constituents exist (${rare.pricedAssets} today)` : 'Index not configured'} />

Subindices

Daily change · latest published value

{subs.length ? ( ) : (

No subindex has reached its minimum constituent count yet.
See build progress

)}
); } async function Discovery() { const [trending, movers, losers, records, radar, lots, watched, newest, markets, opportunities, newestPriced, documented, withSales] = await Promise.all([ rankedAssets('trending', { limit: 8 }), rankedAssets('gainers', { limit: 8, window: '7d' }), rankedAssets('losers', { limit: 8, window: '7d' }), getTopSales(8), listRadar({ limit: 8 }), listLots({ endingWithinHours: 72, status: null, limit: 8 }), rankedAssets('watched', { limit: 8 }), rankedAssets('newest', { limit: 8 }), getMarketRows(), rankedAssets('opportunity', { limit: 8 }), rankedAssets('newest_priced', { limit: 8 }), rankedAssets('documented', { limit: 8 }), rankedAssets('with_sales', { limit: 8 }), ]); await Promise.all([attachGuidePrices(newest), attachGuidePrices(documented)]); const families = markets.filter((r) => r.counts.assets > 0); const thumbs = await getCategoryThumbnails(markets.map((r) => r.node.slug)); // Honest fallbacks while valuations are still being computed: each rail states what it shows. const trendingRail = trending.length ? { title: 'Trending Now', subtitle: 'Price × volume × listing momentum', items: trending, metric: 'trending' as const, href: '/trending' } : newestPriced.length ? { title: 'Recently valued', subtitle: 'Newest RareIndex Valuations (trending needs momentum history)', items: newestPriced, metric: 'riv' as const, href: '/explore?has=valuation&sort=riv' } : { title: 'Best-documented assets', subtitle: 'Images plus sales or guide prices — trending publishes once momentum history exists', items: documented, metric: 'guide' as const, href: '/explore?has=observations' }; const moversItems = movers.length ? movers : losers; const moversRail = moversItems.length ? { title: 'Biggest Movers', subtitle: '7-day change in RareIndex Valuation', items: moversItems, metric: 'change7d' as const, href: '/explore?sort=change7d' } : withSales.length ? { title: 'Latest sold assets', subtitle: 'Most recent verified sale per asset — movers need a 7-day valuation history', items: withSales, metric: 'riv' as const, href: '/sales' } : null; return ( <>

Browse by category

{fmtNum(families.length)} families with data ·{' '} all {fmtNum(markets.length)} →
{moversRail ? : null} {watched.length ? : null} {opportunities.length ? : null}
); } async function Latest() { const items = await getLatestSales(12); const observations = items.length ? [] : await getLatestObservationsFeed(12); return (
); }