Skip to content

Commit

Permalink
add copy button
Browse files Browse the repository at this point in the history
  • Loading branch information
karooolis committed Jan 7, 2025
1 parent 1e09240 commit b1915b8
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useConnectModal } from "@rainbow-me/rainbowkit";
import { CopyButton } from "../../../../../../components/CopyButton";
import { Button } from "../../../../../../components/ui/Button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../../../../../../components/ui/Form";
import { Input } from "../../../../../../components/ui/Input";
Expand Down Expand Up @@ -115,7 +116,14 @@ export function FunctionField({ worldAbi, functionAbi }: Props) {
{(functionAbi.stateMutability === "payable" || functionAbi.stateMutability === "nonpayable") && "Write"}
</Button>

{result && <pre className="text-md rounded border p-3 text-sm">{result}</pre>}
{result && (
<pre className="text-md relative rounded border p-3 text-sm">
{result}
<div className="absolute right-2 top-2">
<CopyButton value={result} />
</div>
</pre>
)}
</form>

<Separator />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import { formatEther } from "viem";
import { Row, flexRender } from "@tanstack/react-table";
import { CopyButton } from "../../../../../../components/CopyButton";
import { Separator } from "../../../../../../components/ui/Separator";
import { Skeleton } from "../../../../../../components/ui/Skeleton";
import { TableCell, TableRow } from "../../../../../../components/ui/Table";
Expand Down Expand Up @@ -83,9 +84,9 @@ export function TransactionTableRow({ row }: { row: Row<ObservedTransaction> })
<h3 className="w-[45px] flex-shrink-0 text-2xs font-bold uppercase">Inputs</h3>

{data.calls.length > 0 ? (
<div className="flex w-full flex-col gap-y-4">
<div className="relative flex w-full flex-col gap-y-4">
{data.calls.map((call, idx) => (
<div key={idx} className="min-w-0 flex-grow border border-white/20 p-2 pt-1">
<div key={idx} className="min-w-0 flex-grow rounded border border-white/20 p-2 pt-1">
<span className="text-xs">{call.functionName}:</span>
{call.args?.map((arg, argIdx) => (
<div key={argIdx} className="flex">
Expand All @@ -101,6 +102,8 @@ export function TransactionTableRow({ row }: { row: Row<ObservedTransaction> })
) : null}
</div>
))}

<CopyButton value={JSON.stringify(data.calls, null, 2)} className="absolute right-1.5 top-1.5" />
</div>
) : (
<p className="text-2xs uppercase text-white/60">No inputs</p>
Expand All @@ -112,7 +115,7 @@ export function TransactionTableRow({ row }: { row: Row<ObservedTransaction> })
<Separator className="my-5" />
<div className="flex items-start gap-x-4">
<h3 className="w-[45px] flex-shrink-0 text-2xs font-bold uppercase">Error</h3>
<div className="flex-grow whitespace-pre-wrap border border-red-500 p-2 font-mono text-xs">
<div className="flex-grow whitespace-pre-wrap rounded border border-red-500 p-2 font-mono text-xs">
{data.error.message}
</div>
</div>
Expand All @@ -125,7 +128,7 @@ export function TransactionTableRow({ row }: { row: Row<ObservedTransaction> })
<div className="flex items-start gap-x-4">
<h3 className="inline-block w-[45px] flex-shrink-0 text-2xs font-bold uppercase">Logs</h3>
{Array.isArray(logs) && logs.length > 0 ? (
<div className="flex-grow break-all border border-white/20 p-2 pb-3">
<div className="relative flex-grow break-all rounded border border-white/20 p-2 pb-3">
<ul>
{logs.map((log, idx) => {
const eventName = "eventName" in log ? log.eventName : null;
Expand All @@ -148,6 +151,8 @@ export function TransactionTableRow({ row }: { row: Row<ObservedTransaction> })
);
})}
</ul>

<CopyButton value={JSON.stringify(logs, null, 2)} className="absolute right-1.5 top-1.5" />
</div>
) : status === "pending" ? (
<Skeleton className="h-4 w-full" />
Expand Down
43 changes: 43 additions & 0 deletions packages/explorer/src/components/CopyButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { CheckIcon, ClipboardIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { cn } from "../utils";
import { Button, ButtonProps } from "./ui/Button";

interface CopyButtonProps extends ButtonProps {
value: string;
}

function copyToClipboard(value: string) {
navigator.clipboard.writeText(value);
}

export function CopyButton({ className, variant = "outline", value, ...props }: CopyButtonProps) {
const [hasCopied, setHasCopied] = useState(false);

useEffect(() => {
if (hasCopied) {
setTimeout(() => {
setHasCopied(false);
}, 2000);
}
}, [hasCopied]);

return (
<Button
size="icon"
variant={variant}
className={cn(
"relative z-10 h-6 w-6 border-white/15 bg-transparent text-zinc-50 hover:bg-secondary hover:text-zinc-50 [&_svg]:h-3 [&_svg]:w-3",
className,
)}
onClick={() => {
copyToClipboard(value);
setHasCopied(true);
}}
{...props}
>
<span className="sr-only">Copy</span>
{hasCopied ? <CheckIcon /> : <ClipboardIcon />}
</Button>
);
}
6 changes: 6 additions & 0 deletions packages/explorer/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import { formatEther } from "viem";
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

Object.defineProperty(BigInt.prototype, "toJSON", {
get() {
return () => String(this);
},
});

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Expand Down

0 comments on commit b1915b8

Please sign in to comment.