@hot-labs/kit 1.4.15 → 1.4.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -1
- package/README.md +7 -5
- package/build/core/OmniConnector.d.ts +1 -0
- package/build/core/OmniConnector.js +1 -0
- package/build/core/OmniConnector.js.map +1 -1
- package/build/core/chains.d.ts +1 -0
- package/build/core/chains.js +28 -0
- package/build/core/chains.js.map +1 -1
- package/build/core/exchange.d.ts +6 -5
- package/build/core/exchange.js +28 -14
- package/build/core/exchange.js.map +1 -1
- package/build/evm/wallet.d.ts +1 -1
- package/build/evm/wallet.js +1 -3
- package/build/evm/wallet.js.map +1 -1
- package/build/hot-wallet/google.d.ts +1 -0
- package/build/hot-wallet/google.js +10 -7
- package/build/hot-wallet/google.js.map +1 -1
- package/build/stellar/wallet.js +8 -3
- package/build/stellar/wallet.js.map +1 -1
- package/build/ui/bridge/Bridge.js +57 -11
- package/build/ui/bridge/Bridge.js.map +1 -1
- package/build/ui/bridge/SelectRecipient.js +2 -2
- package/build/ui/bridge/SelectRecipient.js.map +1 -1
- package/build/ui/connect/ConnectWallet.js +2 -2
- package/build/ui/connect/ConnectWallet.js.map +1 -1
- package/build/ui/icons/home.d.ts +1 -0
- package/build/ui/icons/home.js +5 -0
- package/build/ui/icons/home.js.map +1 -0
- package/build/ui/profile/Profile.js +6 -3
- package/build/ui/profile/Profile.js.map +1 -1
- package/build/ui/styles.js +1 -1
- package/build/ui/uikit/button.js +2 -2
- package/examples-node/.env +2 -0
- package/examples-node/transfer.ts +2 -2
- package/examples-node/withdraw.ts +2 -1
- package/package.json +1 -1
- package/skill.md +19 -20
- package/src/core/OmniConnector.ts +2 -0
- package/src/core/chains.ts +29 -0
- package/src/core/exchange.ts +30 -19
- package/src/evm/wallet.ts +1 -4
- package/src/hot-wallet/google.ts +11 -7
- package/src/stellar/wallet.ts +9 -4
- package/src/ui/bridge/Bridge.tsx +62 -5
- package/src/ui/bridge/SelectRecipient.tsx +3 -3
- package/src/ui/connect/ConnectWallet.tsx +18 -18
- package/src/ui/icons/home.tsx +12 -0
- package/src/ui/profile/Profile.tsx +15 -3
- package/src/ui/styles.ts +1 -1
- package/src/ui/uikit/button.tsx +2 -2
package/src/ui/bridge/Bridge.tsx
CHANGED
|
@@ -142,6 +142,17 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
|
|
|
142
142
|
setIsReviewing(false);
|
|
143
143
|
};
|
|
144
144
|
|
|
145
|
+
const openTooltip = (id: string) => {
|
|
146
|
+
const tooltip = document.getElementById(id);
|
|
147
|
+
if (!tooltip) return;
|
|
148
|
+
tooltip.style.transform = "translateY(0)";
|
|
149
|
+
tooltip.style.opacity = "1";
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
tooltip.style.transform = "translateY(8px)";
|
|
152
|
+
tooltip.style.opacity = "0";
|
|
153
|
+
}, 3000);
|
|
154
|
+
};
|
|
155
|
+
|
|
145
156
|
const reviewSwap = useCallback(() => {
|
|
146
157
|
reviewId.current = uuid4();
|
|
147
158
|
const currentReviewId = reviewId.current;
|
|
@@ -151,9 +162,6 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
|
|
|
151
162
|
|
|
152
163
|
const refund = sender !== "qr" ? sender : hot.priorityWallet;
|
|
153
164
|
if (valueInTokens <= 0) return throwError("Enter amount");
|
|
154
|
-
if (!sender) return throwError("Set sender");
|
|
155
|
-
if (!recipient) return throwError("Set recipient");
|
|
156
|
-
if (!refund) return throwError("Connect any wallet");
|
|
157
165
|
|
|
158
166
|
const debounceTimer = setTimeout(async () => {
|
|
159
167
|
try {
|
|
@@ -162,6 +170,12 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
|
|
|
162
170
|
const recipientWallet = hot.wallets.find((w) => w.address === recipient?.address && w.type === recipient?.type) || recipient;
|
|
163
171
|
const review = await hot.exchange.reviewSwap({ recipient: recipientWallet, slippage: 0.005, sender, refund, amount, type, from, to });
|
|
164
172
|
if (currentReviewId !== reviewId.current) return;
|
|
173
|
+
|
|
174
|
+
if (amount > 0) {
|
|
175
|
+
if (!sender) setTimeout(() => openTooltip("sender-tooltip"), 100);
|
|
176
|
+
if (!recipient) openTooltip("recipient-tooltip");
|
|
177
|
+
}
|
|
178
|
+
|
|
165
179
|
setIsReviewing(false);
|
|
166
180
|
setIsError(null);
|
|
167
181
|
setReview(review);
|
|
@@ -283,8 +297,8 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
|
|
|
283
297
|
}
|
|
284
298
|
|
|
285
299
|
const button = () => {
|
|
286
|
-
if (sender == null) return <ActionButton disabled>
|
|
287
|
-
if (recipient == null) return <ActionButton disabled>
|
|
300
|
+
if (sender == null) return <ActionButton disabled>Confirm</ActionButton>;
|
|
301
|
+
if (recipient == null) return <ActionButton disabled>Confirm</ActionButton>;
|
|
288
302
|
if (sender !== "qr" && +from.float(hot.balance(sender, from)).toFixed(FIXED) < +amountFrom.toFixed(FIXED)) return <ActionButton disabled>Insufficient balance</ActionButton>;
|
|
289
303
|
return (
|
|
290
304
|
<ActionButton style={{ width: "100%", marginTop: 40 }} disabled={isReviewing || isError != null} onClick={handleConfirm}>
|
|
@@ -307,6 +321,7 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
|
|
|
307
321
|
|
|
308
322
|
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
|
309
323
|
<PSmall>Sender:</PSmall>
|
|
324
|
+
|
|
310
325
|
<BadgeButton
|
|
311
326
|
onClick={() => {
|
|
312
327
|
if (from.type === WalletType.OMNI) openSelectSender({ hot, type: from.type, onSelect: (sender) => setSender(sender) });
|
|
@@ -314,6 +329,9 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
|
|
|
314
329
|
}}
|
|
315
330
|
>
|
|
316
331
|
<PSmall>{sender == null ? "Select" : sender !== "qr" ? formatter.truncateAddress(sender.address, 8) : "QR"}</PSmall>
|
|
332
|
+
<Tooltip id="sender-tooltip">
|
|
333
|
+
<PSmall>Select sender wallet</PSmall>
|
|
334
|
+
</Tooltip>
|
|
317
335
|
</BadgeButton>
|
|
318
336
|
</div>
|
|
319
337
|
</CardHeader>
|
|
@@ -433,6 +451,9 @@ export const Bridge = observer(({ hot, widget, setup, onClose, onProcess, onSele
|
|
|
433
451
|
<PSmall>Recipient:</PSmall>
|
|
434
452
|
<BadgeButton onClick={() => openSelectRecipient({ hot, chain: to.chain, onSelect: (recipient) => setRecipient(recipient) })}>
|
|
435
453
|
<PSmall>{recipient == null ? "Select" : formatter.truncateAddress(recipient.address, 8)}</PSmall>
|
|
454
|
+
<Tooltip id="recipient-tooltip">
|
|
455
|
+
<PSmall>Select recipient wallet</PSmall>
|
|
456
|
+
</Tooltip>
|
|
436
457
|
</BadgeButton>
|
|
437
458
|
</div>
|
|
438
459
|
</CardHeader>
|
|
@@ -495,6 +516,41 @@ const TokenPreview = ({ style, token, onSelect }: { style?: React.CSSProperties;
|
|
|
495
516
|
);
|
|
496
517
|
};
|
|
497
518
|
|
|
519
|
+
const Tooltip = styled.div`
|
|
520
|
+
transition: 0.2s transform, 0.2s opacity;
|
|
521
|
+
transform: translateY(8px);
|
|
522
|
+
opacity: 0;
|
|
523
|
+
position: absolute;
|
|
524
|
+
top: -48px;
|
|
525
|
+
right: 0;
|
|
526
|
+
z-index: 100000000;
|
|
527
|
+
border-radius: 16px;
|
|
528
|
+
background: var(--surface-white, #fff);
|
|
529
|
+
padding: 4px 12px;
|
|
530
|
+
justify-content: center;
|
|
531
|
+
pointer-events: none;
|
|
532
|
+
align-items: center;
|
|
533
|
+
gap: 4px;
|
|
534
|
+
|
|
535
|
+
p {
|
|
536
|
+
white-space: nowrap;
|
|
537
|
+
color: #000;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
&::after {
|
|
541
|
+
content: "";
|
|
542
|
+
position: absolute;
|
|
543
|
+
top: 100%;
|
|
544
|
+
right: 8px;
|
|
545
|
+
transform: translateX(-50%);
|
|
546
|
+
width: 0;
|
|
547
|
+
height: 0;
|
|
548
|
+
border-left: 8px solid transparent;
|
|
549
|
+
border-right: 8px solid transparent;
|
|
550
|
+
border-top: 8px solid #fff;
|
|
551
|
+
}
|
|
552
|
+
`;
|
|
553
|
+
|
|
498
554
|
const BadgeButton = styled.button`
|
|
499
555
|
display: flex;
|
|
500
556
|
border-radius: 8px;
|
|
@@ -502,6 +558,7 @@ const BadgeButton = styled.button`
|
|
|
502
558
|
padding: 4px 8px;
|
|
503
559
|
background: transparent;
|
|
504
560
|
transition: 0.2s border-color;
|
|
561
|
+
position: relative;
|
|
505
562
|
cursor: pointer;
|
|
506
563
|
outline: none;
|
|
507
564
|
gap: 4px;
|
|
@@ -25,10 +25,7 @@ interface SelectRecipientProps {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export const SelectRecipient = observer(({ recipient, hot, chain, onSelect, onClose }: SelectRecipientProps) => {
|
|
28
|
-
const connectors = hot.connectors.filter((t) => t.walletTypes.includes(type) && t.type !== ConnectorType.SOCIAL);
|
|
29
28
|
const [customAddress, setCustomAddress] = useState<string>(recipient?.address || "");
|
|
30
|
-
|
|
31
|
-
const isError = !Recipient.isValidAddress(chain, customAddress) && customAddress.length > 0;
|
|
32
29
|
const type = chains.get(chain)?.type;
|
|
33
30
|
|
|
34
31
|
if (!type)
|
|
@@ -38,6 +35,9 @@ export const SelectRecipient = observer(({ recipient, hot, chain, onSelect, onCl
|
|
|
38
35
|
</Popup>
|
|
39
36
|
);
|
|
40
37
|
|
|
38
|
+
const connectors = hot.connectors.filter((t) => t.walletTypes.includes(type) && t.type !== ConnectorType.SOCIAL);
|
|
39
|
+
const isError = !Recipient.isValidAddress(chain, customAddress) && customAddress.length > 0;
|
|
40
|
+
|
|
41
41
|
const selectCustom = async () => {
|
|
42
42
|
const recipient = await Recipient.fromAddress(type, customAddress);
|
|
43
43
|
onSelect(recipient);
|
|
@@ -23,7 +23,7 @@ interface MultichainPopupProps {
|
|
|
23
23
|
|
|
24
24
|
export const Connector = observer(({ hot, onClose, title, walletType, widget }: MultichainPopupProps) => {
|
|
25
25
|
const onechain = hot.connectors.filter((t) => t.type === ConnectorType.WALLET && (walletType == null || t.walletTypes.includes(walletType as WalletType)) && t.options.length > 0);
|
|
26
|
-
const social = hot.connectors.filter((t) => t.type === ConnectorType.SOCIAL && (walletType == null || t.walletTypes.includes(walletType as WalletType))
|
|
26
|
+
const social = hot.connectors.filter((t) => t.type === ConnectorType.SOCIAL && (walletType == null || t.walletTypes.includes(walletType as WalletType)));
|
|
27
27
|
|
|
28
28
|
const selectConnector = async (t: OmniConnector) => {
|
|
29
29
|
if (t.wallets[0]) return t.disconnect();
|
|
@@ -33,25 +33,8 @@ export const Connector = observer(({ hot, onClose, title, walletType, widget }:
|
|
|
33
33
|
|
|
34
34
|
return (
|
|
35
35
|
<Popup header={<p>{title || "Connect wallet"}</p>} onClose={onClose} widget={widget}>
|
|
36
|
-
{onechain.map((t) => (
|
|
37
|
-
<PopupOption key={t.id} onClick={() => selectConnector(t)}>
|
|
38
|
-
<ImageView src={t.icon} alt={t.name} size={44} />
|
|
39
|
-
<PopupOptionInfo>
|
|
40
|
-
<p>{t.name}</p>
|
|
41
|
-
{t.wallets[0]?.address && <span className="wallet-address">{formatter.truncateAddress(t.wallets[0].address, 24)}</span>}
|
|
42
|
-
</PopupOptionInfo>
|
|
43
|
-
{t.wallets[0]?.address && <LogoutIcon width={32} height={32} />}
|
|
44
|
-
</PopupOption>
|
|
45
|
-
))}
|
|
46
|
-
|
|
47
36
|
{social.length > 0 && (
|
|
48
37
|
<>
|
|
49
|
-
<div style={{ margin: "4px 0", display: "flex", width: "100%", alignItems: "center", justifyContent: "center", gap: "8px" }}>
|
|
50
|
-
<div style={{ height: "1px", flex: 1, background: "rgba(255,255,255,0.1)" }}></div>
|
|
51
|
-
<div>or</div>
|
|
52
|
-
<div style={{ height: "1px", flex: 1, background: "rgba(255,255,255,0.1)" }}></div>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
38
|
{social.map((t) => (
|
|
56
39
|
<PopupOption key={t.id} onClick={() => selectConnector(t)}>
|
|
57
40
|
<ImageView src={t.icon} alt={t.name} size={44} />
|
|
@@ -62,8 +45,25 @@ export const Connector = observer(({ hot, onClose, title, walletType, widget }:
|
|
|
62
45
|
{t.wallets[0]?.address && <LogoutIcon width={32} height={32} />}
|
|
63
46
|
</PopupOption>
|
|
64
47
|
))}
|
|
48
|
+
|
|
49
|
+
<div style={{ margin: "4px 0", display: "flex", width: "100%", alignItems: "center", justifyContent: "center", gap: "8px" }}>
|
|
50
|
+
<div style={{ height: "1px", flex: 1, background: "rgba(255,255,255,0.1)" }}></div>
|
|
51
|
+
<div>or</div>
|
|
52
|
+
<div style={{ height: "1px", flex: 1, background: "rgba(255,255,255,0.1)" }}></div>
|
|
53
|
+
</div>
|
|
65
54
|
</>
|
|
66
55
|
)}
|
|
56
|
+
|
|
57
|
+
{onechain.map((t) => (
|
|
58
|
+
<PopupOption key={t.id} onClick={() => selectConnector(t)}>
|
|
59
|
+
<ImageView src={t.icon} alt={t.name} size={44} />
|
|
60
|
+
<PopupOptionInfo>
|
|
61
|
+
<p>{t.name}</p>
|
|
62
|
+
{t.wallets[0]?.address && <span className="wallet-address">{formatter.truncateAddress(t.wallets[0].address, 24)}</span>}
|
|
63
|
+
</PopupOptionInfo>
|
|
64
|
+
{t.wallets[0]?.address && <LogoutIcon width={32} height={32} />}
|
|
65
|
+
</PopupOption>
|
|
66
|
+
))}
|
|
67
67
|
</Popup>
|
|
68
68
|
);
|
|
69
69
|
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const HomeIcon = (props: React.SVGProps<SVGSVGElement>) => {
|
|
2
|
+
return (
|
|
3
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
|
4
|
+
<path
|
|
5
|
+
fill-rule="evenodd"
|
|
6
|
+
clip-rule="evenodd"
|
|
7
|
+
d="M3.16669 11.7087C3.16669 11.9848 3.39054 12.2087 3.66669 12.2087H6.34718C6.33809 12.1545 6.33335 12.0988 6.33335 12.042V10.042C6.33335 9.48973 6.78107 9.04202 7.33335 9.04202H8.00002C8.5523 9.04202 9.00002 9.48973 9.00002 10.042V12.042C9.00002 12.0988 8.99529 12.1545 8.98619 12.2087H11.6667C11.9428 12.2087 12.1667 11.9848 12.1667 11.7087V6.85598C12.1667 6.70408 12.0976 6.56043 11.979 6.46554L7.95259 3.24438C7.77663 3.10362 7.52835 3.09799 7.34624 3.23039C7.34568 3.2308 7.34512 3.2312 7.34456 3.23161L3.37101 6.14556C3.33507 6.17191 3.30325 6.20261 3.27605 6.23665C3.21212 6.31668 3.17375 6.41517 3.16757 6.51902C3.16698 6.52889 3.16669 6.5388 3.16669 6.54875V6.54876M8.56531 2.4331C8.03636 2.02861 7.30406 2.02125 6.76709 2.41503L6.75611 2.42308C6.75514 2.42379 6.75416 2.4245 6.75319 2.42521L2.77964 5.33915C2.39433 5.62171 2.16669 6.07094 2.16669 6.54875V11.7087C2.16669 11.7088 2.16669 11.7088 2.16669 11.7089V12.3754C2.16669 13.2038 2.83826 13.8754 3.66669 13.8754H12.3334C13.1618 13.8754 13.8334 13.2038 13.8334 12.3754V7.20286C13.8334 6.73566 13.6157 6.29513 13.2445 6.01133L8.56531 2.4331Z"
|
|
8
|
+
fill="#2C3034"
|
|
9
|
+
/>
|
|
10
|
+
</svg>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
@@ -5,7 +5,10 @@ import { useEffect } from "react";
|
|
|
5
5
|
import PlusIcon from "../icons/plus";
|
|
6
6
|
import { LogoutIcon } from "../icons/logout";
|
|
7
7
|
import ExchangeIcon from "../icons/exchange";
|
|
8
|
+
import { ImageView } from "../uikit/image";
|
|
9
|
+
import { Loader } from "../uikit/loader";
|
|
8
10
|
|
|
11
|
+
import { ConnectorType } from "../../core/OmniConnector";
|
|
9
12
|
import { formatter } from "../../core/utils";
|
|
10
13
|
import { OmniToken } from "../../core/chains";
|
|
11
14
|
import { tokens } from "../../core/tokens";
|
|
@@ -13,8 +16,6 @@ import { tokens } from "../../core/tokens";
|
|
|
13
16
|
import { HotConnector } from "../../HotConnector";
|
|
14
17
|
import { openBridge, openConnector } from "../router";
|
|
15
18
|
import { TokenCard, TokenIcon } from "../bridge/TokenCard";
|
|
16
|
-
import { ImageView } from "../uikit/image";
|
|
17
|
-
import { Loader } from "../uikit/loader";
|
|
18
19
|
import { PopupOption } from "../styles";
|
|
19
20
|
import Popup from "../Popup";
|
|
20
21
|
|
|
@@ -45,6 +46,7 @@ export const Profile = observer(({ hot, onClose }: { hot: HotConnector; onClose:
|
|
|
45
46
|
|
|
46
47
|
const omniTokens = tokensList.filter((t) => t.chain === -4);
|
|
47
48
|
const nonOmniTokens = tokensList.filter((t) => t.chain !== -4);
|
|
49
|
+
const socialConnector = hot.connectors.find((connector) => connector.type === ConnectorType.SOCIAL && connector.wallets.length > 0);
|
|
48
50
|
|
|
49
51
|
useEffect(() => {
|
|
50
52
|
if (hot.wallets.length > 0) return;
|
|
@@ -58,6 +60,7 @@ export const Profile = observer(({ hot, onClose }: { hot: HotConnector; onClose:
|
|
|
58
60
|
connector.wallets.map((wallet) => (
|
|
59
61
|
<WalletCard onClick={() => connector.disconnect()}>
|
|
60
62
|
<ImageView src={wallet.icon} alt={connector.name} size={20} />
|
|
63
|
+
{connector.type === ConnectorType.SOCIAL && <ImageView style={{ position: "absolute", bottom: 4, left: 20 }} src={connector.icon} alt={connector.name} size={12} />}
|
|
61
64
|
<div>{formatter.truncateAddress(wallet.address, 8)}</div>
|
|
62
65
|
<LogoutIcon />
|
|
63
66
|
</WalletCard>
|
|
@@ -76,11 +79,19 @@ export const Profile = observer(({ hot, onClose }: { hot: HotConnector; onClose:
|
|
|
76
79
|
<PSmall>YOUR BALANCE</PSmall>
|
|
77
80
|
<BalanceCard>${formatter.amount(totalBalance)}</BalanceCard>
|
|
78
81
|
|
|
79
|
-
<div style={{ width: "100%", display: "flex", gap: 12, marginTop:
|
|
82
|
+
<div style={{ width: "100%", display: "flex", gap: 12, marginTop: 12, flexWrap: "wrap" }}>
|
|
80
83
|
<ActionButton onClick={() => (onClose(), openBridge(hot, { title: "Exchange" }))}>
|
|
81
84
|
<ExchangeIcon />
|
|
82
85
|
Exchange
|
|
83
86
|
</ActionButton>
|
|
87
|
+
|
|
88
|
+
{socialConnector != null && (
|
|
89
|
+
<ActionButton onClick={() => socialConnector.openWallet()}>
|
|
90
|
+
<ImageView src={socialConnector.icon} alt={socialConnector.name} size={20} />
|
|
91
|
+
Open wallet
|
|
92
|
+
</ActionButton>
|
|
93
|
+
)}
|
|
94
|
+
|
|
84
95
|
<ActionButton disabled onClick={() => (onClose(), openBridge(hot, { title: "Deposit" }))}>
|
|
85
96
|
Deposit
|
|
86
97
|
</ActionButton>
|
|
@@ -184,6 +195,7 @@ const WalletCard = styled.div`
|
|
|
184
195
|
background: #1a1a1a;
|
|
185
196
|
cursor: pointer;
|
|
186
197
|
transition: background 0.2s ease-in-out;
|
|
198
|
+
position: relative;
|
|
187
199
|
|
|
188
200
|
&:hover {
|
|
189
201
|
background: rgba(255, 255, 255, 0.04);
|
package/src/ui/styles.ts
CHANGED
package/src/ui/uikit/button.tsx
CHANGED
|
@@ -19,7 +19,7 @@ export const ActionButton = styled.button<{ $stroke?: boolean }>`
|
|
|
19
19
|
flex: 1;
|
|
20
20
|
width: 100%;
|
|
21
21
|
|
|
22
|
-
color: #121212;
|
|
22
|
+
color: #121212 !important;
|
|
23
23
|
text-align: center;
|
|
24
24
|
font-family: "Golos Text";
|
|
25
25
|
font-size: 16px;
|
|
@@ -43,7 +43,7 @@ export const ActionButton = styled.button<{ $stroke?: boolean }>`
|
|
|
43
43
|
css`
|
|
44
44
|
background: transparent;
|
|
45
45
|
border: 1px solid #d2d2d2;
|
|
46
|
-
color: #fff;
|
|
46
|
+
color: #fff !important;
|
|
47
47
|
|
|
48
48
|
&:hover {
|
|
49
49
|
background: rgba(255, 255, 255, 0.1);
|