Make more things copyable

This commit is contained in:
Justin Starry 2020-04-22 22:01:56 +08:00 committed by Michael Vines
parent bdbd037257
commit 1172d9cd41
5 changed files with 70 additions and 24 deletions

View File

@ -7,6 +7,7 @@ import {
Status Status
} from "../providers/accounts"; } from "../providers/accounts";
import { TransactionError } from "@solana/web3.js"; import { TransactionError } from "@solana/web3.js";
import Copyable from "./Copyable";
function AccountModal() { function AccountModal() {
const selected = useSelectedAccount(); const selected = useSelectedAccount();
@ -135,9 +136,11 @@ function ListGroupItem({
</span> </span>
</div> </div>
<div className="col min-width-0"> <div className="col min-width-0">
<h5 className="mb-0 text-truncate"> <Copyable text={signature}>
<code>{signature}</code> <h5 className="mb-0 text-truncate">
</h5> <code>{signature}</code>
</h5>
</Copyable>
</div> </div>
</div> </div>
</div> </div>

View File

@ -209,7 +209,15 @@ const renderAccountRow = (
</td> </td>
<td>{balance}</td> <td>{balance}</td>
<td>{data}</td> <td>{data}</td>
<td>{owner === "-" ? owner : <code>{owner}</code>}</td> <td>
{owner === "-" ? (
owner
) : (
<Copyable text={owner}>
<code>{owner}</code>
</Copyable>
)}
</td>
<td>{renderDetails()}</td> <td>{renderDetails()}</td>
</tr> </tr>
); );

View File

@ -5,27 +5,39 @@ type CopyableProps = {
children: ReactNode; children: ReactNode;
}; };
const popover = ( type State = "hide" | "copy" | "copied";
<div className="popover fade bs-popover-right show">
<div className="arrow" /> function Popover({ state }: { state: State }) {
<div className="popover-body">Copied!</div> if (state === "hide") return null;
</div> const text = state === "copy" ? "Copy" : "Copied!";
); return (
<div className="popover bs-popover-top show">
<div className="arrow" />
<div className="popover-body">{text}</div>
</div>
);
}
function Copyable({ text, children }: CopyableProps) { function Copyable({ text, children }: CopyableProps) {
const [showPopover, setShowPopover] = useState(false); const [state, setState] = useState<State>("hide");
const copyToClipboard = () => navigator.clipboard.writeText(text); const copyToClipboard = () => navigator.clipboard.writeText(text);
const handleClick = () => const handleClick = () =>
copyToClipboard().then(() => { copyToClipboard().then(() => {
setShowPopover(true); setState("copied");
setTimeout(setShowPopover.bind(null, false), 2500); setTimeout(() => setState("hide"), 1000);
}); });
return ( return (
<div className="copyable"> <div className="copyable">
<div onClick={handleClick}>{children}</div> <div
{showPopover && popover} onClick={handleClick}
onMouseOver={() => setState("copy")}
onMouseOut={() => state === "copy" && setState("hide")}
>
{children}
</div>
<Popover state={state} />
</div> </div>
); );
} }

View File

@ -13,6 +13,7 @@ import {
CreateAccountParams, CreateAccountParams,
TransactionInstruction TransactionInstruction
} from "@solana/web3.js"; } from "@solana/web3.js";
import Copyable from "./Copyable";
function TransactionModal() { function TransactionModal() {
const { selected } = useTransactions(); const { selected } = useTransactions();
@ -106,15 +107,21 @@ function TransferDetails({
transfer: TransferParams; transfer: TransferParams;
index: number; index: number;
}) { }) {
const from = transfer.fromPubkey.toBase58();
const to = transfer.toPubkey.toBase58();
return ( return (
<div className="card-body"> <div className="card-body">
<h4 className="ix-pill">{`Instruction #${index + 1} (Transfer)`}</h4> <h4 className="ix-pill">{`Instruction #${index + 1} (Transfer)`}</h4>
<div className="list-group list-group-flush my-n3"> <div className="list-group list-group-flush my-n3">
<ListGroupItem label="From"> <ListGroupItem label="From">
<code>{transfer.fromPubkey.toBase58()}</code> <Copyable text={from}>
<code>{from}</code>
</Copyable>
</ListGroupItem> </ListGroupItem>
<ListGroupItem label="To"> <ListGroupItem label="To">
<code>{transfer.toPubkey.toBase58()}</code> <Copyable text={to}>
<code>{to}</code>
</Copyable>
</ListGroupItem> </ListGroupItem>
<ListGroupItem label="Amount (SOL)"> <ListGroupItem label="Amount (SOL)">
{`${(1.0 * transfer.lamports) / LAMPORTS_PER_SOL}`} {`${(1.0 * transfer.lamports) / LAMPORTS_PER_SOL}`}
@ -131,16 +138,22 @@ function CreateDetails({
create: CreateAccountParams; create: CreateAccountParams;
index: number; index: number;
}) { }) {
const from = create.fromPubkey.toBase58();
const newKey = create.newAccountPubkey.toBase58();
return ( return (
<div className="card-body"> <div className="card-body">
<h4 className="ix-pill">{`Instruction #${index + <h4 className="ix-pill">{`Instruction #${index +
1} (Create Account)`}</h4> 1} (Create Account)`}</h4>
<div className="list-group list-group-flush my-n3"> <div className="list-group list-group-flush my-n3">
<ListGroupItem label="From"> <ListGroupItem label="From">
<code>{create.fromPubkey.toBase58()}</code> <Copyable text={from}>
<code>{from}</code>
</Copyable>
</ListGroupItem> </ListGroupItem>
<ListGroupItem label="New Account"> <ListGroupItem label="New Account">
<code>{create.newAccountPubkey.toBase58()}</code> <Copyable text={newKey}>
<code>{newKey}</code>
</Copyable>
</ListGroupItem> </ListGroupItem>
<ListGroupItem label="Amount (SOL)"> <ListGroupItem label="Amount (SOL)">
{`${(1.0 * create.lamports) / LAMPORTS_PER_SOL}`} {`${(1.0 * create.lamports) / LAMPORTS_PER_SOL}`}
@ -167,7 +180,9 @@ function InstructionDetails({
<div className="list-group list-group-flush my-n3"> <div className="list-group list-group-flush my-n3">
{ix.keys.map(({ pubkey }, keyIndex) => ( {ix.keys.map(({ pubkey }, keyIndex) => (
<ListGroupItem key={keyIndex} label={`Address #${keyIndex + 1}`}> <ListGroupItem key={keyIndex} label={`Address #${keyIndex + 1}`}>
<code>{pubkey.toBase58()}</code> <Copyable text={pubkey.toBase58()}>
<code>{pubkey.toBase58()}</code>
</Copyable>
</ListGroupItem> </ListGroupItem>
))} ))}
<ListGroupItem label="Data (Bytes)">{ix.data.length}</ListGroupItem> <ListGroupItem label="Data (Bytes)">{ix.data.length}</ListGroupItem>

View File

@ -17,10 +17,18 @@ code {
cursor: pointer; cursor: pointer;
} }
.popover { .popover.bs-popover-top {
top: -1rem; background-color: $dark;
right: -5.12rem; top: -4rem;
left: auto; left: 40%;
.popover-body {
color: white;
}
.arrow::after {
border-top-color: $dark;
}
} }
} }