From 5ada84fc156b8ae83a903a35879577dcd8ce5fc2 Mon Sep 17 00:00:00 2001 From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com> Date: Wed, 19 Aug 2026 10:14:52 +0200 Subject: [PATCH] revert hub strip nav, restore footer links, redirect trading-apps to benchmarks --- next.config.ts | 1 + src/app/trading-apps/page.tsx | 484 --------------------------------- src/components/site-footer.tsx | 9 + src/components/site-header.tsx | 47 +--- 4 files changed, 11 insertions(+), 530 deletions(-) delete mode 100644 src/app/trading-apps/page.tsx diff --git a/next.config.ts b/next.config.ts index ad07b9bb..5c228840 100644 --- a/next.config.ts +++ b/next.config.ts @@ -204,6 +204,7 @@ const nextConfig: NextConfig = { permanent: true, })); return [ + { source: "/trading-apps", destination: "/benchmarks", permanent: false }, { source: "/live", destination: "/", permanent: true }, { source: "/networks", destination: "/", permanent: true }, { source: "/providers", destination: "/products", permanent: true }, diff --git a/src/app/trading-apps/page.tsx b/src/app/trading-apps/page.tsx deleted file mode 100644 index f71ab7ce..00000000 --- a/src/app/trading-apps/page.tsx +++ /dev/null @@ -1,484 +0,0 @@ -import Link from "next/link"; -import { ProviderLogo } from "@/components/provider-logo"; -import { getBenchmark } from "@/data/benchmarks"; -import type { ProviderResult } from "@/types/benchmark"; -import { pageMetadata } from "@/lib/page-metadata"; -import { safeJsonLd, buildBreadcrumbJsonLd } from "@/lib/jsonld"; -import { SITE } from "@/data/site"; - -const DESCRIPTION = - "Live benchmarks for Solana trading platforms and Telegram bots — volume, fees, execution quality, unique traders, and app store ratings."; - -export const metadata: import("next").Metadata = pageMetadata({ - path: "/trading-apps", - title: "Best Solana Trading Apps 2026, ranked by benchmark", - description: DESCRIPTION, -}); - -export const revalidate = 60; - -const BENCH_SLUGS = [ - "solana-trading-platform-wars", - "solana-dex-volume", - "solana-unique-traders", - "solana-avg-trade-size", - "solana-launchpad-wars", - "memecoin-platforms", - "trading-app-execution", - "app-store-ratings", -] as const; - -const PLATFORMS = [ - { slug: "pump-fun", name: "pump.fun" }, - { slug: "gmgn", name: "GMGN" }, - { slug: "axiom", name: "Axiom" }, - { slug: "fomo", name: "FOMO" }, - { slug: "trojan", name: "Trojan" }, - { slug: "photon", name: "Photon" }, - { slug: "maestro", name: "Maestro" }, -] as const; - -const COLUMNS = [ - { - key: "volume" as const, - label: "24h Volume", - bench: "solana-trading-platform-wars", - fmt: fmtUSD, - tip: "Attributed 24h trading volume", - higherBetter: true, - }, - { - key: "traders" as const, - label: "Unique Traders", - bench: "solana-unique-traders", - fmt: fmtCount, - tip: "Unique swap transactions in 24h", - higherBetter: true, - }, - { - key: "tradeSize" as const, - label: "Avg Trade", - bench: "solana-avg-trade-size", - fmt: fmtUSD, - tip: "Average swap size in USD", - higherBetter: false, - }, - { - key: "feeRate" as const, - label: "Fee Rate", - bench: "memecoin-platforms", - fmt: fmtPct, - tip: "Protocol fee revenue ÷ volume (take rate)", - higherBetter: false, - }, - { - key: "rating" as const, - label: "App Rating", - bench: "app-store-ratings", - fmt: fmtRating, - tip: "Apple App Store rating (out of 5)", - higherBetter: true, - }, -] as const; - -type ColKey = (typeof COLUMNS)[number]["key"]; - -function indexBySlug(results: ProviderResult[] | undefined): Record { - const out: Record = {}; - for (const r of results ?? []) { - out[r.slug] = r.ms.mean; - } - return out; -} - -function fmtUSD(v: number | null): string { - if (v === null) return "—"; - if (v >= 1_000_000_000) return `$${(v / 1_000_000_000).toFixed(1)}B`; - if (v >= 1_000_000) return `$${(v / 1_000_000).toFixed(0)}M`; - if (v >= 1_000) return `$${(v / 1_000).toFixed(0)}K`; - return `$${v.toFixed(0)}`; -} - -function fmtCount(v: number | null): string { - if (v === null) return "—"; - if (v >= 1_000_000) return `${(v / 1_000_000).toFixed(1)}M`; - if (v >= 1_000) return `${(v / 1_000).toFixed(0)}K`; - return v.toFixed(0); -} - -function fmtPct(v: number | null): string { - if (v === null) return "—"; - return `${v.toFixed(2)}%`; -} - -function fmtRating(v: number | null): string { - if (v === null) return "—"; - return `${v.toFixed(1)} / 5`; -} - -const GROUPS = [ - { - label: "Volume & activity", - items: [ - { slug: "solana-trading-platform-wars", title: "Trading platform volume" }, - { slug: "solana-dex-volume", title: "DEX volume & protocol revenue" }, - { slug: "solana-unique-traders", title: "Unique traders" }, - { slug: "solana-avg-trade-size", title: "Average trade size" }, - ], - }, - { - label: "Launchpads", - items: [{ slug: "solana-launchpad-wars", title: "Launchpad volume" }], - }, - { - label: "Fees & execution", - items: [ - { slug: "memecoin-platforms", title: "Platform fee rates" }, - { slug: "trading-app-execution", title: "Execution quality" }, - ], - }, - { - label: "App store", - items: [{ slug: "app-store-ratings", title: "iOS app store ratings" }], - }, -] as const; - -export default async function TradingAppsHubPage() { - const [volBench, tradersBench, tradeSizeBench, feeBench, ratingsBench] = - await Promise.all([ - getBenchmark("solana-trading-platform-wars"), - getBenchmark("solana-unique-traders"), - getBenchmark("solana-avg-trade-size"), - getBenchmark("memecoin-platforms"), - getBenchmark("app-store-ratings"), - ]); - - const volIdx = indexBySlug(volBench?.results); - const tradersIdx = indexBySlug(tradersBench?.results); - const tradeSizeIdx = indexBySlug(tradeSizeBench?.results); - const feeIdx = indexBySlug(feeBench?.results); - const ratingIdx = indexBySlug(ratingsBench?.results); - - type Row = { - slug: string; - name: string; - volume: number | null; - traders: number | null; - tradeSize: number | null; - feeRate: number | null; - rating: number | null; - }; - - const matrix: Row[] = PLATFORMS.map((p) => ({ - slug: p.slug, - name: p.name, - volume: volIdx[p.slug] ?? null, - traders: tradersIdx[p.slug] ?? null, - tradeSize: tradeSizeIdx[p.slug] ?? null, - feeRate: feeIdx[p.slug] ?? null, - rating: ratingIdx[p.slug] ?? null, - })).sort((a, b) => (b.volume ?? -1) - (a.volume ?? -1)); - - // Find the best value per column (for highlighting) - function best(key: ColKey, higherBetter: boolean): number | null { - const vals = matrix.map((r) => r[key]).filter((v): v is number => v !== null); - if (!vals.length) return null; - return higherBetter ? Math.max(...vals) : Math.min(...vals); - } - - const bests: Partial> = {}; - for (const col of COLUMNS) { - bests[col.key] = best(col.key, col.higherBetter); - } - - const topVolume = volBench?.results[0]; - const topRating = ratingsBench?.results.find((r) => - PLATFORMS.some((p) => p.slug === r.slug) - ); - - const breadcrumbLd = { - "@context": "https://schema.org", - ...buildBreadcrumbJsonLd([ - { name: "Home", item: SITE.url }, - { name: "Trading Apps", item: `${SITE.url}/trading-apps` }, - ]), - }; - - const itemListLd = { - "@context": "https://schema.org", - "@type": "ItemList", - name: "Trading app benchmarks by OpenChainBench", - description: DESCRIPTION, - numberOfItems: BENCH_SLUGS.length, - itemListElement: BENCH_SLUGS.map((slug, i) => ({ - "@type": "ListItem", - position: i + 1, - name: slug, - url: `${SITE.url}/benchmarks/${slug}`, - })), - }; - - return ( -
-