Skip to content

Commit 706d696

Browse files
committed
[MNY-285] Dashboard: Bridge page UI updates (#8295)
<!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR introduces a new `bridgeStats` object to enhance the dashboard with dynamic statistics regarding supported chains, tokens, and routes. It updates various components to utilize these statistics, improving the accuracy of displayed information. ### Detailed summary - Added `bridgeStats` object in `data.ts` with properties for supported chains, tokens, and routes. - Updated text in `page.tsx` files to use dynamic values from `bridgeStats`. - Introduced `AnimatedNumbers` component to display statistics with animations. - Replaced static statistics with dynamic `DataSquare` components in `bridge-page.tsx`. > The following files were skipped due to too many changes: `pnpm-lock.yaml` > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent c36cfbb commit 706d696

File tree

11 files changed

+576
-129
lines changed

11 files changed

+576
-129
lines changed

apps/dashboard/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"dependencies": {
33
"@hookform/resolvers": "^3.9.1",
44
"@marsidev/react-turnstile": "^1.1.0",
5+
"@number-flow/react": "^0.5.10",
56
"@radix-ui/react-accordion": "^1.2.11",
67
"@radix-ui/react-alert-dialog": "^1.1.14",
78
"@radix-ui/react-avatar": "^1.1.10",

apps/dashboard/src/app/(app)/(dashboard)/tokens/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { Metadata } from "next";
33
import { unstable_cache } from "next/cache";
44
import { Bridge } from "thirdweb";
55
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
6+
import { bridgeStats } from "../../../bridge/data";
67
import { PageHeader } from "./components/header";
78
import { TokenPage } from "./components/token-page";
89

@@ -36,7 +37,8 @@ export default async function Page() {
3637
</h1>
3738

3839
<p className="text-muted-foreground">
39-
85+ chains, 4500+ tokens and 9+ million routes supported
40+
{bridgeStats.supportedChains} chains, {bridgeStats.supportedTokens}{" "}
41+
tokens and {bridgeStats.supportedRoutes} routes supported
4042
</p>
4143
</div>
4244
</div>
14.3 KB
Loading
63.6 KB
Loading
12 KB
Loading

apps/dashboard/src/app/bridge/components/bridge-page.tsx

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
import type { Format } from "@number-flow/react";
12
import { cn } from "@workspace/ui/lib/utils";
3+
import Image, { type StaticImageData } from "next/image";
24
import type { BuyAndSwapEmbedProps } from "@/components/blocks/BuyAndSwapEmbed";
35
import { FaqAccordion } from "@/components/blocks/faq-section";
6+
import ChainsImage from "../assets/chains.png";
7+
import RoutesImage from "../assets/routes.png";
8+
import TokensImage from "../assets/tokens.png";
9+
import { bridgeStats } from "../data";
10+
import { AnimatedNumbers } from "./client/animated-numbers";
411
import { UniversalBridgeEmbed } from "./client/UniversalBridgeEmbed";
512
import { BridgePageHeader } from "./header";
613

@@ -35,24 +42,58 @@ function HeadingSection(props: { title: React.ReactNode }) {
3542
<div className="mb-3 lg:mb-6">{props.title}</div>
3643

3744
<p className="text-muted-foreground text-sm text-pretty text-center lg:text-lg mb-6 lg:mb-8">
38-
Seamlessly move your assets across 85+ chains with the best rates and
39-
fastest execution
45+
Seamlessly move your assets across {bridgeStats.supportedChains} chains
46+
with the best rates and fastest execution
4047
</p>
4148

42-
<div className="flex flex-col lg:flex-row gap-3 lg:gap-2 items-center justify-center">
43-
<DataPill>85+ Chains Supported</DataPill>
44-
<DataPill>4500+ Tokens Supported</DataPill>
45-
<DataPill>9+ Million Routes Available</DataPill>
49+
<div className="flex gap-3 items-center lg:justify-center flex-wrap">
50+
<DataSquare data={90} label="Chains Supported" src={ChainsImage} />
51+
<DataSquare
52+
data={6700}
53+
label="Tokens Supported"
54+
src={TokensImage}
55+
format={{ notation: "compact" }}
56+
/>
57+
<DataSquare
58+
data={14000000}
59+
format={{ notation: "compact" }}
60+
label="Routes Available"
61+
src={RoutesImage}
62+
/>
4663
</div>
4764
</div>
4865
);
4966
}
5067

51-
function DataPill(props: { children: React.ReactNode }) {
68+
function DataSquare(props: {
69+
data: number;
70+
label: string;
71+
src: StaticImageData;
72+
format?: Format;
73+
imageClassName?: string;
74+
}) {
5275
return (
53-
<p className="bg-card flex items-center text-xs lg:text-sm gap-1.5 text-foreground border rounded-full px-8 lg:px-3 py-1.5 hover:text-foreground transition-colors duration-300">
54-
{props.children}
55-
</p>
76+
<div className="py-2 lg:py-0 size-full lg:size-[220px] rounded-xl border hover:bg-card bg-card/50 relative shrink-0 overflow-hidden">
77+
<div className="p-4">
78+
<div className="flex items-center gap-1 text-3xl lg:text-5xl font-medium tracking-tight font-mono mb-1 h-[45px] lg:h-[56px]">
79+
<AnimatedNumbers
80+
value={props.data}
81+
format={props.format}
82+
suffix="+"
83+
/>
84+
</div>
85+
<p className="text-sm text-foreground">{props.label}</p>
86+
</div>
87+
<Image
88+
draggable={false}
89+
src={props.src}
90+
className={cn(
91+
"object-cover h-full lg:h-auto absolute right-0 top-0 bottom-0 left-1/2 lg:left-0 lg:top-auto invert dark:invert-0 opacity-50 lg:opacity-100",
92+
props.imageClassName,
93+
)}
94+
alt=""
95+
/>
96+
</div>
5697
);
5798
}
5899

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"use client";
2+
3+
import NumberFlow, { type Format } from "@number-flow/react";
4+
import { useLayoutEffect, useRef, useState } from "react";
5+
6+
export function AnimatedNumbers(props: {
7+
value: number;
8+
format?: Format;
9+
suffix?: string;
10+
}) {
11+
const ref = useRef<HTMLDivElement>(null);
12+
const [value, setValue] = useState(props.value);
13+
14+
useLayoutEffect(() => {
15+
if (ref.current) {
16+
// when the div becomes visible, set the value to the props value
17+
const observer = new IntersectionObserver((entries) => {
18+
entries.forEach((entry) => {
19+
if (entry.isIntersecting) {
20+
setValue(props.value);
21+
} else {
22+
setValue(0);
23+
}
24+
});
25+
});
26+
observer.observe(ref.current);
27+
return () => observer.disconnect();
28+
}
29+
}, [props.value]);
30+
31+
return (
32+
<div ref={ref}>
33+
<NumberFlow
34+
willChange
35+
value={value}
36+
format={props.format}
37+
suffix={props.suffix}
38+
/>
39+
</div>
40+
);
41+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const bridgeStats = {
2+
supportedChains: "90+",
3+
supportedTokens: "6700+",
4+
supportedRoutes: "14M+",
5+
};

apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { ChainMetadata } from "thirdweb/chains";
55
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
66
import { fetchChain } from "@/utils/fetchChain";
77
import { BridgePageUI } from "../../components/bridge-page";
8+
import { bridgeStats } from "../../data";
89
import { generateTokenPairSlugs, getTokenPairData } from "./slug-map";
910

1011
type Params = {
@@ -35,8 +36,7 @@ export async function generateMetadata(
3536
}
3637

3738
const title = getTitle(tokenMetadata);
38-
const description =
39-
"Bridge and swap 4500+ tokens across 85+ chains (Ethereum, Base, Optimism, Arbitrum, BNB & more). Best-price routing with near-instant finality";
39+
const description = `Bridge and swap ${bridgeStats.supportedTokens} tokens across ${bridgeStats.supportedChains} chains (Ethereum, Base, Optimism, Arbitrum, BNB & more). Best-price routing with near-instant finality`;
4040

4141
const result: Metadata = {
4242
title,

apps/dashboard/src/app/bridge/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { Metadata } from "next";
22
import { isAddress, NATIVE_TOKEN_ADDRESS } from "thirdweb";
33
import { BridgePageUI } from "./components/bridge-page";
4+
import { bridgeStats } from "./data";
45

5-
const title = "thirdweb Bridge: Buy, Bridge & Swap Crypto on 85+ Chains";
6-
const description =
7-
"Bridge and swap 4500+ tokens across 85+ chains (Ethereum, Base, Optimism, Arbitrum, BNB & more). Best-price routing with near-instant finality";
6+
const title = `thirdweb Bridge: Buy, Bridge & Swap Crypto on ${bridgeStats.supportedChains} Chains`;
7+
const description = `Bridge and swap ${bridgeStats.supportedTokens} tokens across ${bridgeStats.supportedChains} chains (Ethereum, Base, Optimism, Arbitrum, BNB & more). Best-price routing with near-instant finality`;
88

99
export const metadata: Metadata = {
1010
description,

0 commit comments

Comments
 (0)