-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
1,518 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"stackspulse": minor | ||
--- | ||
|
||
Create new token page. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { TokenHoldersTable } from "@/components/Token/TokenHoldersTable"; | ||
import { TokenInfo } from "@/components/Token/TokenInfo"; | ||
import { TokenStats } from "@/components/Token/TokenStats"; | ||
import { TokenTransactionsVolume } from "@/components/Token/TokenTransactionsVolume"; | ||
import { stacksTokensApi } from "@/lib/stacks"; | ||
import { Container } from "@radix-ui/themes"; | ||
import { notFound } from "next/navigation"; | ||
import { Suspense } from "react"; | ||
|
||
export const dynamic = "force-dynamic"; | ||
|
||
interface PageProps { | ||
params: { token: string }; | ||
} | ||
|
||
export default async function ProtocolPage({ params }: PageProps) { | ||
const token = decodeURIComponent(params.token); | ||
const tokenInfo = await stacksTokensApi | ||
.getFtMetadata(token.split("::")[0]) | ||
.catch((error) => { | ||
if (error.status === 404) { | ||
return null; | ||
} | ||
throw error; | ||
}); | ||
if (!tokenInfo) { | ||
notFound(); | ||
} | ||
|
||
return ( | ||
<Container size="2" className="px-4 pt-10"> | ||
<TokenInfo tokenInfo={tokenInfo} /> | ||
|
||
<Suspense> | ||
<TokenStats token={token} tokenInfo={tokenInfo} /> | ||
</Suspense> | ||
|
||
<Suspense> | ||
<TokenTransactionsVolume token={token} tokenInfo={tokenInfo} /> | ||
</Suspense> | ||
|
||
<Suspense> | ||
<TokenHoldersTable token={token} tokenInfo={tokenInfo} /> | ||
</Suspense> | ||
</Container> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
"use client"; | ||
|
||
import { useGetTokenHolders } from "@/hooks/api/useGetTokenHolders"; | ||
import type { FtMetadataResponse } from "@hirosystems/token-metadata-api-client"; | ||
import { Link, Table, Text } from "@radix-ui/themes"; | ||
|
||
interface TokenHoldersTableProps { | ||
token: string; | ||
tokenInfo: FtMetadataResponse; | ||
} | ||
|
||
export const TokenHoldersTable = ({ | ||
token, | ||
tokenInfo, | ||
}: TokenHoldersTableProps) => { | ||
const { data } = useGetTokenHolders({ token, limit: 10 }); | ||
|
||
const calculatePercentage = (balance: string) => { | ||
const holderBalance = Number.parseFloat(balance); | ||
const totalSupply = Number.parseFloat(data.total_supply); | ||
return ((holderBalance / totalSupply) * 100).toFixed(2); | ||
}; | ||
|
||
return ( | ||
<Table.Root className="mt-10"> | ||
<Table.Header> | ||
<Table.Row> | ||
<Table.ColumnHeaderCell>Rank</Table.ColumnHeaderCell> | ||
<Table.ColumnHeaderCell>Address</Table.ColumnHeaderCell> | ||
<Table.ColumnHeaderCell align="right">Balance</Table.ColumnHeaderCell> | ||
<Table.ColumnHeaderCell align="right"> | ||
% of Supply | ||
</Table.ColumnHeaderCell> | ||
</Table.Row> | ||
</Table.Header> | ||
|
||
<Table.Body> | ||
{data.results.map((holder, index) => ( | ||
<Table.Row key={holder.address}> | ||
<Table.Cell> | ||
<Text size="2">{index + 1}</Text> | ||
</Table.Cell> | ||
<Table.Cell> | ||
<Link | ||
href={`https://explorer.hiro.so/address/${holder.address}?chain=mainnet`} | ||
target="_blank" | ||
color="gray" | ||
> | ||
{holder.address} | ||
</Link> | ||
</Table.Cell> | ||
<Table.Cell align="right"> | ||
<Text size="2"> | ||
{( | ||
Number(holder.balance) / | ||
Number(10 ** (tokenInfo.decimals ?? 0)) | ||
).toLocaleString("en-US")} | ||
</Text> | ||
</Table.Cell> | ||
<Table.Cell align="right"> | ||
<Text size="2">{calculatePercentage(holder.balance)}%</Text> | ||
</Table.Cell> | ||
</Table.Row> | ||
))} | ||
</Table.Body> | ||
</Table.Root> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import type { FtMetadataResponse } from "@hirosystems/token-metadata-api-client"; | ||
import { Heading, Text } from "@radix-ui/themes"; | ||
import Image from "next/image"; | ||
|
||
interface TokenInfoProps { | ||
tokenInfo: FtMetadataResponse; | ||
} | ||
|
||
export const TokenInfo = ({ tokenInfo }: TokenInfoProps) => { | ||
const tokenImage = tokenInfo.image_thumbnail_uri || tokenInfo.image_uri; | ||
return ( | ||
<div className="flex items-start gap-5"> | ||
{tokenImage ? ( | ||
<Image | ||
className="rounded-full" | ||
src={tokenImage} | ||
alt={`${tokenInfo.name} logo`} | ||
width={50} | ||
height={50} | ||
priority | ||
/> | ||
) : null} | ||
<div> | ||
<Heading as="h1" size="5" color="gray" highContrast> | ||
{tokenInfo.symbol} - {tokenInfo.name} | ||
</Heading> | ||
<Text className="mt-1" as="p" size="2" color="gray"> | ||
{tokenInfo.description} | ||
</Text> | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
"use client"; | ||
|
||
import { useGetTokenHolders } from "@/hooks/api/useGetTokenHolders"; | ||
import type { FtMetadataResponse } from "@hirosystems/token-metadata-api-client"; | ||
import { Card, Text } from "@radix-ui/themes"; | ||
|
||
interface TokenStatsProps { | ||
token: string; | ||
tokenInfo: FtMetadataResponse; | ||
} | ||
|
||
export const TokenStats = ({ token, tokenInfo }: TokenStatsProps) => { | ||
const { data } = useGetTokenHolders({ token, limit: 1 }); | ||
|
||
return ( | ||
<div className="mt-5 grid grid-cols-2 gap-5"> | ||
<Card size="2"> | ||
<Text as="div" size="2" color="gray"> | ||
Supply | ||
</Text> | ||
<Text | ||
as="div" | ||
mt="2" | ||
size="5" | ||
weight="medium" | ||
title={data.total_supply} | ||
> | ||
{Number( | ||
Number(data.total_supply) / Number(10 ** (tokenInfo.decimals ?? 0)), | ||
).toLocaleString("en-US")} | ||
</Text> | ||
</Card> | ||
<Card size="2"> | ||
<Text as="div" size="2" color="gray"> | ||
Holders | ||
</Text> | ||
<Text as="div" mt="2" size="5" weight="medium"> | ||
{data.total.toLocaleString("en-US")} | ||
</Text> | ||
</Card> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
"use client"; | ||
|
||
import { useGetTransactionVolume } from "@/hooks/api/useGetTransactionVolume"; | ||
import type { FtMetadataResponse } from "@hirosystems/token-metadata-api-client"; | ||
import { Card, Inset, Separator, Text } from "@radix-ui/themes"; | ||
import { useMemo } from "react"; | ||
import { AreaChart } from "../ui/AreaChart"; | ||
import { bigNumberValueFormatter, numberValueFormatter } from "../ui/utils"; | ||
|
||
interface TokenStatsProps { | ||
token: string; | ||
tokenInfo: FtMetadataResponse; | ||
} | ||
|
||
export const TokenTransactionsVolume = ({ | ||
token, | ||
tokenInfo, | ||
}: TokenStatsProps) => { | ||
const { data } = useGetTransactionVolume({ token }); | ||
|
||
const formattedData = useMemo(() => { | ||
return data.map((d) => ({ | ||
date: d.date, | ||
daily_volume: | ||
Number(d.daily_volume) / Number(10 ** (tokenInfo.decimals ?? 0)), | ||
})); | ||
}, [data, tokenInfo.decimals]); | ||
|
||
return ( | ||
<Card size="2" className="mt-5"> | ||
<Text as="div" size="2" weight="medium" color="gray" highContrast> | ||
Transactions volume | ||
</Text> | ||
<Text className="mt-1" as="div" size="1" color="gray"> | ||
The total volume of transactions for the token. | ||
</Text> | ||
<Inset py="current" side="bottom"> | ||
<Separator size="4" /> | ||
</Inset> | ||
<AreaChart | ||
className="mt-3 pr-3" | ||
data={formattedData} | ||
index="date" | ||
categories={["daily_volume"]} | ||
colors={["orange"]} | ||
valueFormatter={numberValueFormatter} | ||
valueFormatterYAxis={bigNumberValueFormatter} | ||
/> | ||
</Card> | ||
); | ||
}; |
Oops, something went wrong.