diff --git a/src/components/CCIP/Landing/ccip-landing.astro b/src/components/CCIP/Landing/ccip-landing.astro index f65de34c258..910cfafdbe6 100644 --- a/src/components/CCIP/Landing/ccip-landing.astro +++ b/src/components/CCIP/Landing/ccip-landing.astro @@ -15,7 +15,6 @@ import { getTokenIconUrl } from "~/features/utils" import LazyNetworkGrid from "./LazyNetworkGrid" import LazyTokenGrid from "../TokenGrid/LazyTokenGrid" import LazyVerifierGrid from "../VerifierGrid/LazyVerifierGrid" -import StructuredData from "~/components/StructuredData.astro" import { generateDirectoryStructuredData } from "~/utils/ccipStructuredData" import { DOCS_BASE_URL } from "~/utils/structuredData" import AddButton from "~/components/CCIP/AddButton/AddButton.astro" @@ -25,37 +24,119 @@ export type Props = { } const { environment } = Astro.props as Props -const entry = await getEntry("ccip", "index") -if (!entry) { - throw new Error('No "ccip/index" doc found! Please make sure it exists in src/content/ccip/index.mdx or .md.') +// ---------------------- +// Featured ranking (exact canonical names) +// ---------------------- + +const FEATURED_NETWORK_RANK: Record = { + Ethereum: 1, + Plasma: 2, + Solana: 3, + "BNB Chain": 4, + Base: 5, + "Arbitrum One": 6, + Avalanche: 7, + Monad: 8, +} + +const FEATURED_TOKEN_RANK: Record = { + LINK: 1, + USDC: 2, + USDT: 3, + WETH: 4, + syrupUSDC: 5, + syrupUSDT: 6, + GHO: 7, + cbBTC: 8, } +// ---------------------- + +const entry = await getEntry("ccip", "index") +if (!entry) throw new Error('No "ccip/index" doc found!') + const { headings } = await render(entry) -const networks = getAllNetworks({ filter: environment }) +// ---------------------- +// Networks (exact match) +// ---------------------- + +const networksRaw = getAllNetworks({ filter: environment }) + +const networks = networksRaw.map((n) => ({ + ...n, + featuredRank: FEATURED_NETWORK_RANK[n.name], +})) + +const featuredNetworkCount = networks.filter((n) => n.featuredRank !== undefined).length +if (featuredNetworkCount !== 8) { + console.warn(`Expected 8 featured networks, got ${featuredNetworkCount}`) +} + +// ---------------------- +// Tokens (exact match) +// ---------------------- + const supportedTokens = getAllSupportedTokens({ environment, version: Version.V1_2_0, }) + const tokens = Object.keys(supportedTokens).sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" })) + const allTokens = tokens.map((token) => { const logo = getTokenIconUrl(token) || "" return { id: token, logo, totalNetworks: getChainsOfToken({ token, filter: environment }).length, + featuredRank: FEATURED_TOKEN_RANK[token], } }) + +const featuredTokenCount = allTokens.filter((t) => t.featuredRank !== undefined).length +if (featuredTokenCount !== 8) { + console.warn(`Expected 8 featured tokens, got ${featuredTokenCount}`) +} + +// ---------------------- +// Split + order +// ---------------------- + +function splitFeatured(items) { + const featured = items.filter((i) => i.featuredRank !== undefined).sort((a, b) => a.featuredRank - b.featuredRank) + + const rest = items + .filter((i) => i.featuredRank === undefined) + .sort((a, b) => { + const aKey = a.name || a.id + const bKey = b.name || b.id + return aKey.localeCompare(bKey, undefined, { sensitivity: "base" }) + }) + + return { featured, rest } +} + +const { featured: featuredNetworks, rest: restNetworks } = splitFeatured(networks) +const { featured: featuredTokens, rest: restTokens } = splitFeatured(allTokens) + +const orderedNetworks = [...featuredNetworks, ...restNetworks] +const orderedTokens = [...featuredTokens, ...restTokens] + +// ---------------------- +// Other data +// ---------------------- + const allVerifiers = getAllUniqueVerifiers({ environment, version: Version.V1_2_0, }) + const searchLanes = getSearchLanes({ environment }) -// Generate directory-level structured data (DataCatalog/Dataset) -// Use production base for canonical JSON-LD URLs (avoid local IPv6/port) const currentPath = new URL(Astro.request.url).pathname const canonicalForJsonLd = `${DOCS_BASE_URL}${currentPath}` + const directoryStructuredData = generateDirectoryStructuredData(environment, networks, tokens, canonicalForJsonLd) --- @@ -67,33 +148,36 @@ const directoryStructuredData = generateDirectoryStructuredData(environment, net pageTitleOverride={`CCIP Directory - ${environment === Environment.Mainnet ? "Mainnet" : "Testnet"}`} metadataOverride={{ ...(entry.data.metadata || {}), - description: `Explore CCIP Directory for ${environment === Environment.Mainnet ? "Mainnet" : "Testnet"}: configuration data for supported blockchains and tokens, cross-chain lanes, contract addresses, rate limits, and operational status on ${environment === Environment.Mainnet ? "Mainnet" : "Testnet"}.`, + description: `Explore CCIP Directory for ${environment === Environment.Mainnet ? "Mainnet" : "Testnet"}.`, image: "/files/ccip-directory.jpg", }} suppressDefaultStructuredData={true} > +

Networks {environment} ({networks.length})

- +
+

Tokens ({allTokens.length})

- +
+

Verifiers ({allVerifiers.length})