Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add copyable behavior to links/addresses in blob, block and transaction tables #622

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
5 changes: 5 additions & 0 deletions .changeset/tricky-yaks-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/web": minor
---

Added copyable behavior to hashes and addresses in blob, block and transaction tables.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { FC } from "react";
import { ArrowRightIcon, ChevronDownIcon } from "@heroicons/react/24/outline";

import { Collapsable } from "~/components/Collapsable";
import { Copyable } from "~/components/Copyable";
import { EtherUnitDisplay } from "~/components/Displays/EtherUnitDisplay";
import { IconButton } from "~/components/IconButton";
import { RollupIcon } from "~/components/RollupIcon";
Expand Down Expand Up @@ -219,9 +220,10 @@ const BlobTransactionCard: FC<BlobTransactionCardProps> = function ({
<React.Fragment key={`${versionedHash}-${index}`}>
<TableCol>{index}</TableCol>
<TableCol>
<Link href={buildBlobRoute(versionedHash)}>
{versionedHash}
</Link>
<Copyable
href={buildBlobRoute(versionedHash)}
value={versionedHash}
/>
</TableCol>
<TableCol>{formatBytes(size)}</TableCol>
</React.Fragment>
Expand Down
24 changes: 9 additions & 15 deletions apps/web/src/components/CopyToClipboard.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import type { FC } from "react";
import { useState } from "react";
import { CheckIcon } from "@heroicons/react/24/outline";

import Copy from "~/icons/copy.svg";
import { Tooltip, TooltipContent, TooltipTrigger } from "./Tooltip";

type CopyToClipboardProps = {
label?: string;
tooltipText?: string;
value: string;
};

export function CopyToClipboard({
label = "Copy to clipboard",
export const CopyToClipboard: FC<CopyToClipboardProps> = ({
tooltipText,
value,
}: CopyToClipboardProps) {
}) => {
const [isCopied, setIsCopied] = useState(false);

return (
Expand All @@ -23,7 +24,9 @@ export function CopyToClipboard({
}
}}
>
<TooltipContent>{isCopied ? "Copied!" : label}</TooltipContent>
{(tooltipText || isCopied) && (
<TooltipContent>{isCopied ? "Copied!" : tooltipText}</TooltipContent>
)}
<TooltipTrigger
className="text-contentTertiary-light hover:text-link-light dark:text-contentTertiary-dark dark:hover:text-link-dark"
onClick={async () => {
Expand All @@ -43,13 +46,4 @@ export function CopyToClipboard({
</TooltipTrigger>
</Tooltip>
);
}

export function Copyable({ label, value }: CopyToClipboardProps) {
return (
<div className="flex items-center gap-2">
<div className="truncate">{value}</div>
<CopyToClipboard value={value} label={label} />
</div>
);
}
};
30 changes: 30 additions & 0 deletions apps/web/src/components/Copyable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { FC } from "react";
import React from "react";

import { CopyToClipboard } from "./CopyToClipboard";
import { Link } from "./Link";

export interface CopyableProps {
href?: string;
value: string;
tooltipText?: string;
children?: React.ReactNode;
}

export const Copyable: FC<CopyableProps> = ({
href,
value,
tooltipText,
children,
}) => {
return (
<div className="flex items-center gap-1" title={value}>
{href ? (
<Link href={href}>{children || value}</Link>
) : (
<div className="truncate">{children || value}</div>
)}
<CopyToClipboard value={value} tooltipText={tooltipText} />
</div>
);
};
16 changes: 11 additions & 5 deletions apps/web/src/pages/blob/[hash].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import { StorageBadge } from "~/components/Badges/StorageBadge";
import { BlobViewer, DEFAULT_BLOB_VIEW_MODES } from "~/components/BlobViewer";
import type { BlobViewMode } from "~/components/BlobViewer";
import { Card } from "~/components/Cards/Card";
import { Copyable, CopyToClipboard } from "~/components/CopyToClipboard";
import { CopyToClipboard } from "~/components/CopyToClipboard";
import { Copyable } from "~/components/Copyable";
import { Dropdown } from "~/components/Dropdown";
import type { DropdownProps } from "~/components/Dropdown";
import type { DetailsLayoutProps } from "~/components/Layouts/DetailsLayout";
Expand Down Expand Up @@ -110,11 +111,13 @@ const Blob: NextPage = function () {
detailsFields.push(
{
name: "Commitment",
value: <Copyable value={blob.commitment} label="Copy commitment" />,
value: (
<Copyable value={blob.commitment} tooltipText="Copy commitment" />
),
},
{
name: "Proof",
value: <Copyable value={blob.proof} label="Copy proof" />,
value: <Copyable value={blob.proof} tooltipText="Copy proof" />,
}
);

Expand Down Expand Up @@ -148,7 +151,7 @@ const Blob: NextPage = function () {
title={txHash}
>
{<Link href={buildTransactionRoute(txHash)}>{txHash}</Link>}
<CopyToClipboard value={txHash} label="Copy tx hash" />
<CopyToClipboard value={txHash} tooltipText="Copy tx hash" />
</div>
</div>
<div className="flex gap-1">
Expand Down Expand Up @@ -176,7 +179,10 @@ const Blob: NextPage = function () {
<div>Blob Data</div>
{blob && (
<div className="flex items-center gap-4">
<CopyToClipboard label="Copy blob data" value={blob.data} />
<CopyToClipboard
tooltipText="Copy blob data"
value={blob.data}
/>
<div className="flex items-center gap-2">
<div className="text-sm font-normal text-contentSecondary-light dark:text-contentSecondary-dark">
View as:
Expand Down
24 changes: 20 additions & 4 deletions apps/web/src/pages/blobs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useMemo } from "react";
import type { NextPage } from "next";
import NextError from "next/error";

import { Copyable } from "~/components/Copyable";
import { Filters } from "~/components/Filters";
import { Header } from "~/components/Header";
import { Link } from "~/components/Link";
Expand Down Expand Up @@ -39,6 +40,10 @@ const BLOBS_TABLE_HEADERS = [
item: "Timestamp",
className: "2xl:w-[185px] xl:w-[160px] lg:w-[127px] w-[100px]",
},
{
item: "Category",
className: "w-[60px]",
},
{
item: "Size",
className: "2xl:w-[178px] xl:w-[145px] lg:w-[101px] w-[66px]",
Expand Down Expand Up @@ -87,16 +92,24 @@ const Blobs: NextPage = function () {
cells: [
{
item: (
<Link href={buildBlobRoute(versionedHash)}>
<Copyable
href={buildBlobRoute(versionedHash)}
value={versionedHash}
tooltipText="Copy versioned hash"
>
{shortenAddress(versionedHash, 8)}
</Link>
</Copyable>
),
},
{
item: (
<Link href={buildTransactionRoute(txHash)}>
<Copyable
href={buildTransactionRoute(txHash)}
value={txHash}
tooltipText="Copy transaction hash"
>
{shortenAddress(txHash, 8)}
</Link>
</Copyable>
),
},
{
Expand All @@ -115,6 +128,9 @@ const Blobs: NextPage = function () {
</div>
),
},
{
item: <span></span>,
},
{
item: (
<div className="flex gap-2">
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/pages/block/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { NextRouter } from "next/router";

import { Card } from "~/components/Cards/Card";
import { BlobTransactionCard } from "~/components/Cards/SurfaceCards/BlobTransactionCard";
import { Copyable } from "~/components/CopyToClipboard";
import { Copyable } from "~/components/Copyable";
import { BlobGasUsageDisplay } from "~/components/Displays/BlobGasUsageDisplay";
import { EtherUnitDisplay } from "~/components/Displays/EtherUnitDisplay";
import { DetailsLayout } from "~/components/Layouts/DetailsLayout";
Expand Down Expand Up @@ -113,7 +113,7 @@ const Block: NextPage = function () {
{ name: "Status", value: <BlockStatus blockNumber={blockData.number} /> },
{
name: "Hash",
value: <Copyable value={blockData.hash} label="Copy Hash" />,
value: <Copyable value={blockData.hash} tooltipText="Copy Hash" />,
},
{
name: "Timestamp",
Expand Down
17 changes: 11 additions & 6 deletions apps/web/src/pages/blocks.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMemo } from "react";
import type { NextPage } from "next";

import { Copyable } from "~/components/Copyable";
import { BlobGasUsageDisplay } from "~/components/Displays/BlobGasUsageDisplay";
import { EtherUnitDisplay } from "~/components/Displays/EtherUnitDisplay";
import { Filters } from "~/components/Filters";
Expand Down Expand Up @@ -134,16 +135,20 @@ const Blocks: NextPage = function () {
cells: [
{
item: (
<Link href={buildTransactionRoute(transactionHash)}>
{transactionHash}
</Link>
<Copyable
href={buildTransactionRoute(transactionHash)}
value={transactionHash}
tooltipText="Copy transaction hash"
/>
),
},
{
item: (
<Link href={buildBlobRoute(blobVersionedHash)}>
{blobVersionedHash}
</Link>
<Copyable
href={buildBlobRoute(blobVersionedHash)}
value={blobVersionedHash}
tooltipText="Copy blob versioned hash"
/>
),
},
],
Expand Down
13 changes: 7 additions & 6 deletions apps/web/src/pages/tx/[hash].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { parseDecodedData } from "~/utils/decoded-transaction";
import { RollupBadge } from "~/components/Badges/RollupBadge";
import { Card } from "~/components/Cards/Card";
import { BlobCard } from "~/components/Cards/SurfaceCards/BlobCard";
import { Copyable, CopyToClipboard } from "~/components/CopyToClipboard";
import { CopyToClipboard } from "~/components/CopyToClipboard";
import { Copyable } from "~/components/Copyable";
import { StandardEtherUnitDisplay } from "~/components/Displays/StandardEtherUnitDisplay";
import { InfoGrid } from "~/components/InfoGrid";
import { DetailsLayout } from "~/components/Layouts/DetailsLayout";
Expand Down Expand Up @@ -102,7 +103,7 @@ const Tx: NextPage = () => {
detailsFields = [
{
name: "Hash",
value: <Copyable value={hash} label="Copy Hash" />,
value: <Copyable value={hash} tooltipText="Copy Hash" />,
},
{ name: "Status", value: <BlockStatus blockNumber={blockNumber} /> },
{
Expand All @@ -126,7 +127,7 @@ const Tx: NextPage = () => {
value: (
<div className="flex items-center gap-2">
<Link href={buildAddressRoute(from)}>{from}</Link>
<CopyToClipboard value={from} label="Copy from address" />
<CopyToClipboard value={from} tooltipText="Copy from address" />
</div>
),
},
Expand All @@ -135,7 +136,7 @@ const Tx: NextPage = () => {
value: (
<div className="flex items-center gap-2">
<Link href={buildAddressRoute(to)}>{to}</Link>
<CopyToClipboard value={to} label="Copy to address" />
<CopyToClipboard value={to} tooltipText="Copy to address" />
</div>
),
},
Expand Down Expand Up @@ -288,7 +289,7 @@ const Tx: NextPage = () => {
</Link>
<CopyToClipboard
value={"0x" + decodedData.parentL2BlockHash}
label="Copy parent L2 block hash"
tooltipText="Copy parent L2 block hash"
/>
</div>
),
Expand All @@ -308,7 +309,7 @@ const Tx: NextPage = () => {
</Link>
<CopyToClipboard
value={"0x" + decodedData.l1OriginBlockHash}
label="Copy L1 origin block hash"
tooltipText="Copy L1 origin block hash"
/>
</div>
),
Expand Down
33 changes: 24 additions & 9 deletions apps/web/src/pages/txs.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMemo } from "react";
import type { NextPage } from "next";

import { Copyable } from "~/components/Copyable";
import { EtherUnitDisplay } from "~/components/Displays/EtherUnitDisplay";
import { Filters } from "~/components/Filters";
import { Header } from "~/components/Header";
Expand Down Expand Up @@ -166,9 +167,11 @@ const Txs: NextPage = function () {
cells: [
{
item: (
<Link href={buildBlobRoute(b.versionedHash)}>
{b.versionedHash}
</Link>
<Copyable
href={buildBlobRoute(b.versionedHash)}
value={b.versionedHash}
tooltipText="Copy blob versioned hash"
/>
),
},
{
Expand Down Expand Up @@ -198,9 +201,13 @@ const Txs: NextPage = function () {
cells: [
{
item: (
<Link href={buildTransactionRoute(hash)}>
<Copyable
href={buildTransactionRoute(hash)}
value={hash}
tooltipText="Copy hash"
>
{shortenAddress(hash, 6)}
</Link>
</Copyable>
),
},
{
Expand All @@ -217,16 +224,24 @@ const Txs: NextPage = function () {
},
{
item: (
<Link href={buildAddressRoute(from)}>
<Copyable
href={buildAddressRoute(from)}
value={from}
tooltipText="Copy the origin address"
>
{shortenAddress(from, 6)}
</Link>
</Copyable>
),
},
{
item: (
<Link href={buildAddressRoute(to)}>
<Copyable
href={buildAddressRoute(to)}
value={to}
tooltipText="Copy the destination address"
>
{shortenAddress(to, 6)}
</Link>
</Copyable>
),
},
{
Expand Down
Loading