Skip to content

Commit cdc7d95

Browse files
committed
[TOOL-4959] Dashboard: Asset page UI improvements (#7599)
<!-- ## 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 focuses on refining the UI components and enhancing the functionality of the `ERC20` public page. It includes improvements in layout, styling, and the introduction of new features related to token price data and analytics. ### Detailed summary - Deleted unused files: `useTokenPriceData.ts` and `ContractCreatorBadge.tsx`. - Updated `PageHeader` to change border style. - Added `tooltip` prop in `CopyAddressButton`. - Changed API key usage in `fetchTokenInfoFromBridge`. - Enhanced `ThirdwebAreaChart` with better props handling. - Introduced `GridPattern` component for background. - Improved `RecentTransfers` UI and pagination buttons. - Updated `PriceChart` and `TokenStats` to directly use passed props for token price data. - Refactored `ContractHeaderUI` to improve layout and social link handling. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced a customizable grid background pattern component for enhanced visual design. * Added support for displaying token price data and analytics on ERC20 public pages, including conditional rendering of token statistics. * Enabled tooltip customization for the copy address button. * **Bug Fixes** * The contract creator badge icon is now visible, and spacing between elements has been improved. * **Refactor** * Simplified and unified chart headers and analytics section layouts. * Streamlined fetching and handling of token price data with a new asynchronous function and removed the previous hook. * Improved layout and container styling across ERC20 and NFT public pages, including card backgrounds, borders, and spacing. * Adjusted component structures for better visual separation and consistency. * Removed the contract creator badge component and replaced it with a simpler contract owner link. * **Style** * Updated card and header styles for better visual hierarchy and clarity. * Enhanced recent transfers and contract header sections with improved padding, borders, and rounded corners. * Removed small shadow effects from cards and refined header background and border styles. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 592bf6f commit cdc7d95

File tree

15 files changed

+410
-361
lines changed

15 files changed

+410
-361
lines changed

apps/dashboard/src/@/components/blocks/charts/area-chart.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type ThirdwebAreaChartProps<TConfig extends ChartConfig> = {
2929
title: string;
3030
description?: string;
3131
titleClassName?: string;
32+
headerClassName?: string;
3233
};
3334
customHeader?: React.ReactNode;
3435
// chart config
@@ -52,6 +53,12 @@ type ThirdwebAreaChartProps<TConfig extends ChartConfig> = {
5253
toolTipLabelFormatter?: (label: string, payload: unknown) => React.ReactNode;
5354
toolTipValueFormatter?: (value: unknown) => React.ReactNode;
5455
emptyChartState?: React.ReactElement;
56+
margin?: {
57+
top?: number;
58+
right?: number;
59+
bottom?: number;
60+
left?: number;
61+
};
5562
};
5663

5764
export function ThirdwebAreaChart<TConfig extends ChartConfig>(
@@ -62,7 +69,7 @@ export function ThirdwebAreaChart<TConfig extends ChartConfig>(
6269
return (
6370
<Card className={props.className}>
6471
{props.header && (
65-
<CardHeader>
72+
<CardHeader className={props.header.headerClassName}>
6673
<CardTitle className={cn("mb-2", props.header.titleClassName)}>
6774
{props.header.title}
6875
</CardTitle>
@@ -85,7 +92,16 @@ export function ThirdwebAreaChart<TConfig extends ChartConfig>(
8592
{props.emptyChartState}
8693
</EmptyChartState>
8794
) : (
88-
<AreaChart accessibilityLayer data={props.data}>
95+
<AreaChart
96+
accessibilityLayer
97+
data={props.data}
98+
margin={{
99+
right: props.margin?.right ?? 0,
100+
left: props.margin?.left ?? 0,
101+
bottom: props.margin?.bottom ?? 10,
102+
top: props.margin?.top ?? 0,
103+
}}
104+
>
89105
<CartesianGrid vertical={false} />
90106
{props.yAxis && <YAxis axisLine={false} tickLine={false} />}
91107
<XAxis

apps/dashboard/src/@/components/ui/CopyAddressButton.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export function CopyAddressButton(props: {
77
address: string;
88
className?: string;
99
iconClassName?: string;
10+
tooltip?: string;
1011
variant?:
1112
| "primary"
1213
| "default"
@@ -24,7 +25,7 @@ export function CopyAddressButton(props: {
2425
copyIconPosition={props.copyIconPosition}
2526
textToCopy={props.address}
2627
textToShow={shortenedAddress}
27-
tooltip="Copy Address"
28+
tooltip={props.tooltip || "Copy Address"}
2829
variant={props.variant}
2930
/>
3031
);

apps/dashboard/src/@/components/ui/background-patterns.tsx

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useId } from "react";
12
import { cn } from "@/lib/utils";
23

34
export function DotsBackgroundPattern(props: { className?: string }) {
@@ -16,3 +17,70 @@ export function DotsBackgroundPattern(props: { className?: string }) {
1617
/>
1718
);
1819
}
20+
21+
interface GridPatternProps extends React.SVGProps<SVGSVGElement> {
22+
width?: number;
23+
height?: number;
24+
x?: number;
25+
y?: number;
26+
squares?: Array<[x: number, y: number]>;
27+
strokeDasharray?: string;
28+
className?: string;
29+
[key: string]: unknown;
30+
}
31+
32+
export function GridPattern({
33+
width = 40,
34+
height = 40,
35+
x = -1,
36+
y = -1,
37+
strokeDasharray = "0",
38+
squares,
39+
className,
40+
...props
41+
}: GridPatternProps) {
42+
const id = useId();
43+
44+
return (
45+
<svg
46+
aria-hidden="true"
47+
className={cn(
48+
"pointer-events-none absolute inset-0 h-full w-full fill-current stroke-current",
49+
className,
50+
)}
51+
{...props}
52+
>
53+
<defs>
54+
<pattern
55+
id={id}
56+
width={width}
57+
height={height}
58+
patternUnits="userSpaceOnUse"
59+
x={x}
60+
y={y}
61+
>
62+
<path
63+
d={`M.5 ${height}V.5H${width}`}
64+
fill="none"
65+
strokeDasharray={strokeDasharray}
66+
/>
67+
</pattern>
68+
</defs>
69+
<rect width="100%" height="100%" strokeWidth={0} fill={`url(#${id})`} />
70+
{squares && (
71+
<svg x={x} y={y} className="overflow-visible" role="presentation">
72+
{squares.map(([x, y]) => (
73+
<rect
74+
strokeWidth="0"
75+
key={`${x}-${y}`}
76+
width={width - 1}
77+
height={height - 1}
78+
x={x * width + 1}
79+
y={y * height + 1}
80+
/>
81+
))}
82+
</svg>
83+
)}
84+
</svg>
85+
);
86+
}

apps/dashboard/src/@/components/ui/card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const Card = React.forwardRef<
88
>(({ className, ...props }, ref) => (
99
<div
1010
className={cn(
11-
"rounded-lg border border-border bg-card text-card-foreground shadow-sm",
11+
"rounded-lg border border-border bg-card text-card-foreground",
1212
className,
1313
)}
1414
ref={ref}

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { PublicPageConnectButton } from "./PublicPageConnectButton";
66

77
export function PageHeader(props: { containerClassName?: string }) {
88
return (
9-
<div className="border-b border-dashed">
9+
<div className="border-b bg-card">
1010
<header
1111
className={cn(
1212
"container flex max-w-8xl justify-between py-3",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import "server-only";
2+
import { isProd } from "@/constants/env-utils";
3+
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
4+
5+
export type TokenPriceData = {
6+
price_usd: number;
7+
price_usd_cents: number;
8+
percent_change_24h: number;
9+
market_cap_usd: number;
10+
volume_24h_usd: number;
11+
volume_change_24h: number;
12+
holders: number;
13+
historical_prices: Array<{
14+
date: string;
15+
price_usd: number;
16+
price_usd_cents: number;
17+
}>;
18+
};
19+
20+
export async function getTokenPriceData(params: {
21+
chainId: number;
22+
contractAddress: string;
23+
}) {
24+
try {
25+
const url = new URL(
26+
`https://insight.${isProd ? "thirdweb" : "thirdweb-dev"}.com/v1/tokens/price`,
27+
);
28+
29+
url.searchParams.set("include_historical_prices", "true");
30+
url.searchParams.set("chain_id", params.chainId.toString());
31+
url.searchParams.set("address", params.contractAddress);
32+
url.searchParams.set("include_holders", "true");
33+
34+
const res = await fetch(url, {
35+
headers: {
36+
"x-secret-key": DASHBOARD_THIRDWEB_SECRET_KEY,
37+
},
38+
});
39+
if (!res.ok) {
40+
console.error("Failed to fetch token price data", await res.text());
41+
return undefined;
42+
}
43+
44+
const json = await res.json();
45+
const priceData = json.data[0] as TokenPriceData | undefined;
46+
47+
return priceData;
48+
} catch {
49+
return undefined;
50+
}
51+
}

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractCreatorBadge.tsx

Lines changed: 0 additions & 19 deletions
This file was deleted.

0 commit comments

Comments
 (0)