Skip to content

Commit 7301778

Browse files
authored
Merge pull request #1907 from cprussin/re-do-feedback
feat(staking): re do feedback
2 parents 0c61a03 + 68107d7 commit 7301778

File tree

8 files changed

+286
-117
lines changed

8 files changed

+286
-117
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { ClipboardDocumentIcon, CheckIcon } from "@heroicons/react/24/outline";
2+
import clsx from "clsx";
3+
import { type ComponentProps, useCallback, useEffect, useState } from "react";
4+
import { Button } from "react-aria-components";
5+
6+
import { useLogger } from "../../hooks/use-logger";
7+
8+
type CopyButtonProps = ComponentProps<typeof Button> & {
9+
text: string;
10+
};
11+
12+
export const CopyButton = ({
13+
text,
14+
children,
15+
className,
16+
...props
17+
}: CopyButtonProps) => {
18+
const [isCopied, setIsCopied] = useState(false);
19+
const logger = useLogger();
20+
const copy = useCallback(() => {
21+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
22+
navigator.clipboard
23+
.writeText(text)
24+
.then(() => {
25+
setIsCopied(true);
26+
})
27+
.catch((error: unknown) => {
28+
/* TODO do something here? */
29+
logger.error(error);
30+
});
31+
}, [text, logger]);
32+
33+
useEffect(() => {
34+
setIsCopied(false);
35+
}, [text]);
36+
37+
useEffect(() => {
38+
if (isCopied) {
39+
const timeout = setTimeout(() => {
40+
setIsCopied(false);
41+
}, 2000);
42+
return () => {
43+
clearTimeout(timeout);
44+
};
45+
} else {
46+
return;
47+
}
48+
}, [isCopied]);
49+
50+
return (
51+
<Button
52+
onPress={copy}
53+
isDisabled={isCopied}
54+
className={clsx(
55+
"group -mt-0.5 rounded-md px-2 py-0.5 align-middle transition hover:bg-white/10 focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400",
56+
className,
57+
)}
58+
{...(isCopied && { "data-is-copied": true })}
59+
{...props}
60+
>
61+
{(...args) => (
62+
<>
63+
<span className="align-middle">
64+
{typeof children === "function" ? children(...args) : children}
65+
</span>
66+
<span className="relative ml-[0.25em] inline-block align-middle">
67+
<span className="opacity-50 transition-opacity duration-100 group-data-[is-copied]:opacity-0">
68+
<ClipboardDocumentIcon className="size-[1em]" />
69+
<div className="sr-only">Copy code to clipboaord</div>
70+
</span>
71+
<CheckIcon className="absolute inset-0 text-green-600 opacity-0 transition-opacity duration-100 group-data-[is-copied]:opacity-100" />
72+
</span>
73+
</>
74+
)}
75+
</Button>
76+
);
77+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"use client";
2+
3+
import clsx from "clsx";
4+
import { type HTMLProps } from "react";
5+
6+
import { StateType as ApiStateType, useApi } from "../../hooks/use-api";
7+
import { CopyButton } from "../CopyButton";
8+
import { TruncatedKey } from "../TruncatedKey";
9+
10+
export const CurrentStakeAccount = ({
11+
className,
12+
...props
13+
}: HTMLProps<HTMLDivElement>) => {
14+
const api = useApi();
15+
16+
return api.type === ApiStateType.Loaded ? (
17+
<div className={clsx("grid place-content-center", className)} {...props}>
18+
<div className="flex flex-col items-end text-xs md:flex-row md:items-baseline md:text-sm">
19+
<div className="font-semibold">Stake account:</div>
20+
<CopyButton
21+
text={api.account.address.toBase58()}
22+
className="-mr-2 ml-2 text-pythpurple-400 md:mr-0"
23+
>
24+
<TruncatedKey>{api.account.address}</TruncatedKey>
25+
</CopyButton>
26+
</div>
27+
</div>
28+
) : // eslint-disable-next-line unicorn/no-null
29+
null;
30+
};

apps/staking/src/components/Header/index.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import clsx from "clsx";
22
import type { HTMLAttributes } from "react";
33

4+
import { CurrentStakeAccount } from "./current-stake-account";
45
import Logo from "./logo.svg";
6+
import Logomark from "./logomark.svg";
57
import { MaxWidth } from "../MaxWidth";
68
import { WalletButton } from "../WalletButton";
79

@@ -14,9 +16,13 @@ export const Header = ({
1416
{...props}
1517
>
1618
<div className="border-b border-neutral-600/50 bg-pythpurple-800 sm:border-x">
17-
<MaxWidth className="flex h-16 items-center justify-between gap-8 sm:-mx-4">
18-
<Logo className="max-h-full py-4 text-pythpurple-100" />
19-
<WalletButton className="flex-none" />
19+
<MaxWidth className="flex h-16 items-center justify-between gap-2 sm:-mx-4">
20+
<Logo className="hidden max-h-full py-4 text-pythpurple-100 sm:block" />
21+
<Logomark className="max-h-full py-4 text-pythpurple-100 sm:hidden" />
22+
<div className="flex flex-none flex-row items-stretch gap-8">
23+
<CurrentStakeAccount />
24+
<WalletButton className="flex-none" />
25+
</div>
2026
</MaxWidth>
2127
</div>
2228
</header>
Lines changed: 4 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)