Skip to content

Commit 8d9ff4d

Browse files
authored
Support BTC DAI and LINK tokens (#792)
* Support BTC DAI and LINK tokens * Fix failed to build
1 parent 3f651d5 commit 8d9ff4d

File tree

6 files changed

+97
-4
lines changed

6 files changed

+97
-4
lines changed

apps/web/public/images/token/btc.png

4.18 KB
Loading

apps/web/public/images/token/link.png

4.97 KB
Loading

apps/web/public/images/token/more.svg

+13
Loading

apps/web/src/components/transfer-token-select.tsx

+79-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
1+
import {
2+
FloatingPortal,
3+
offset,
4+
useClick,
5+
useDismiss,
6+
useFloating,
7+
useHover,
8+
useInteractions,
9+
useTransitionStyles,
10+
} from "@floating-ui/react";
111
import { TokenCategory, TokenSymbol } from "../types";
212
import { getTokenLogoSrc } from "../utils";
3-
import { useState } from "react";
13+
import { useMemo, useState } from "react";
14+
import { safePolygon } from "@floating-ui/react";
15+
import { useMediaQuery } from "../hooks";
416

517
interface Value {
618
logo: string;
@@ -17,13 +29,17 @@ interface Props {
1729
export default function TransferTokenSelect({ value, options, onChange }: Props) {
1830
const [hoveIndex, setHoverIndex] = useState(-1);
1931

32+
const isPC = useMediaQuery("lg");
33+
const nonMoreTokensAmount = useMemo(() => (isPC ? 5 : 4), [isPC]);
34+
2035
return (
2136
<div className="gap-medium px-medium flex items-center">
2237
<TokenImage token={value} active />
2338
<span className="text-base font-bold text-white">{value.symbol}</span>
2439
<div className="gap-medium group ml-2 flex items-center">
2540
{options
2641
.filter((option) => option.symbol !== value.symbol)
42+
.slice(0, nonMoreTokensAmount)
2743
.map((option, index) => (
2844
<TokenImage
2945
key={option.symbol}
@@ -34,6 +50,12 @@ export default function TransferTokenSelect({ value, options, onChange }: Props)
3450
onHoverChange={setHoverIndex}
3551
/>
3652
))}
53+
{nonMoreTokensAmount + 1 < options.length && (
54+
<MoreTokens
55+
options={options.filter((option) => option.symbol !== value.symbol).slice(nonMoreTokensAmount)}
56+
onClick={onChange}
57+
/>
58+
)}
3759
</div>
3860
</div>
3961
);
@@ -79,3 +101,59 @@ function TokenImage({
79101
/>
80102
);
81103
}
104+
105+
function MoreTokens({ options, onClick = () => undefined }: { options: Value[]; onClick?: (token: Value) => void }) {
106+
const [isOpen, setIsOpen] = useState(false);
107+
108+
const { refs, context, floatingStyles } = useFloating({
109+
open: isOpen,
110+
onOpenChange: setIsOpen,
111+
middleware: [offset(4)],
112+
});
113+
const { styles, isMounted } = useTransitionStyles(context, {
114+
initial: { transform: "translateY(-10px)", opacity: 0 },
115+
open: { transform: "translateY(0)", opacity: 1 },
116+
close: { transform: "translateY(-10px)", opacity: 0 },
117+
});
118+
const hover = useHover(context, { handleClose: safePolygon() });
119+
const click = useClick(context);
120+
const dismiss = useDismiss(context);
121+
const { getReferenceProps, getFloatingProps } = useInteractions([hover, click, dismiss]);
122+
123+
return (
124+
<>
125+
<img
126+
width={36}
127+
height={36}
128+
src={getTokenLogoSrc("more.svg")}
129+
alt="More tokens"
130+
className={`transition-opacity duration-200 hover:cursor-pointer hover:opacity-80 ${isOpen ? "opacity-80" : "opacity-50"}`}
131+
ref={refs.setReference}
132+
{...getReferenceProps()}
133+
/>
134+
135+
{isMounted && (
136+
<FloatingPortal>
137+
<div style={floatingStyles} ref={refs.setFloating} {...getFloatingProps()} className="z-20">
138+
<div
139+
className="bg-app-bg flex flex-col gap-2 rounded-xl border border-white/20 px-3 py-2"
140+
style={styles}
141+
onClick={() => setIsOpen(false)}
142+
>
143+
{options.map((option) => (
144+
<img
145+
key={option.symbol}
146+
width={36}
147+
height={36}
148+
src={getTokenLogoSrc(option.logo)}
149+
className="rounded-full opacity-60 transition-opacity duration-200 hover:cursor-pointer hover:opacity-80"
150+
onClick={() => onClick(option)}
151+
/>
152+
))}
153+
</div>
154+
</div>
155+
</FloatingPortal>
156+
)}
157+
</>
158+
);
159+
}

apps/web/src/providers/transfer-provider/index.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ export default function TransferProvider({ children }: PropsWithChildren<unknown
111111
const _availableTokenOptions = tokenOptions.filter((tokenOpt) =>
112112
allTokenKeys.includes(tokenOpt.category.toUpperCase() as Uppercase<string>),
113113
);
114-
115114
if (!_availableTokenOptions.some(({ category }) => category === tokenRef.current.category)) {
116115
setToken(_availableTokenOptions[0]);
117116
}

apps/web/src/utils/transfer.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
import { ChainConfig, Token, TokenCategory, TokenOption } from "../types";
22
import { getChainConfig, getChainConfigs, isMainnet } from ".";
33

4-
// ['ETH', 'RING', 'USDT', 'USDC', 'CRAB', 'PINK']
4+
// ['ETH', 'RING', 'USDT', 'USDC', 'BTC', 'DAI', 'LINK', 'CRAB', 'PINK']
55
const allTokenOptions: Record<Exclude<TokenCategory, "others">, TokenOption> = {
66
CRAB: { logo: "crab.png", category: "CRAB", symbol: "CRAB" },
77
ETH: { logo: "eth.png", category: "ETH", symbol: "ETH" },
88
RING: { logo: "ring.png", category: "RING", symbol: "RING" },
99
USDC: { logo: "usdc.png", category: "USDC", symbol: "USDC" },
1010
USDT: { logo: "usdt.png", category: "USDT", symbol: "USDT" },
1111
PINK: { logo: "pink.png", category: "PINK", symbol: "PINK" },
12+
LINK: { logo: "link.png", category: "LINK", symbol: "LINK" },
13+
DAI: { logo: "xdai.png", category: "DAI", symbol: "DAI" },
14+
BTC: { logo: "btc.png", category: "BTC", symbol: "BTC" },
1215
};
1316
const sortedTokenCategories: Exclude<TokenCategory, "others">[] = isMainnet()
14-
? ["USDC", "USDT", "ETH", "RING", "CRAB", "PINK"]
17+
? ["USDC", "USDT", "ETH", "BTC", "DAI", "LINK", "RING", "CRAB", "PINK"]
1518
: ["USDC", "USDT", "ETH", "RING", "CRAB"];
1619
const availableTokenCategories = new Set<TokenCategory>();
1720
const sourceChainOptions = new Map<TokenCategory, ChainConfig[]>();

0 commit comments

Comments
 (0)