Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
'use client';

import { Button } from '@tangle-network/sandbox-ui/primitives';
import { lazy, Suspense, useMemo, useState } from 'react';
import { isAddress } from 'viem';
import Spinner from '@tangle-network/icons/Spinner';
import { isEvmAddress } from '@tangle-network/ui-components';
import Button from '@tangle-network/ui-components/components/buttons/Button';
import { EvmAddress } from '@tangle-network/ui-components/types/address';
import { useMemo, useState } from 'react';
import { useAccount } from 'wagmi';
import type { EvmAddress } from '@tangle-network/ui-components/types/address';

const EvmWalletModal = lazy(() => import('../EvmWalletModal/EvmWalletModal'));
const WalletDropdown = lazy(() => import('./WalletDropdown'));
import { EvmWalletModal } from '../EvmWalletModal';
import WalletDropdown from './WalletDropdown';
import { getWalletIcon } from './walletIcons';

type ConnectWalletButtonProps = {
className?: string;
Expand All @@ -21,13 +22,14 @@ const ConnectWalletButton = ({ className }: ConnectWalletButtonProps) => {
if (!address) {
return null;
}
if (isAddress(address)) {
return address as EvmAddress;
if (isEvmAddress(address)) {
return address;
}
return null;
}, [address]);

const walletName = connector?.name ?? 'Wallet';
const walletIcon = getWalletIcon(connector?.id, connector?.name);
const isReady = isConnected && accountAddress !== null;

return (
Expand All @@ -36,44 +38,30 @@ const ConnectWalletButton = ({ className }: ConnectWalletButtonProps) => {
{!isReady ? (
<Button
data-testid="evm-connect-trigger"
loading={isConnecting}
isLoading={isConnecting}
spinner={<Spinner size="lg" />}
loadingText="Connecting"
onClick={() => setIsModalOpen(true)}
variant="sandbox"
className="flex items-center justify-center px-6"
>
{isConnecting ? 'Connecting' : 'Connect'}
Connect
</Button>
) : (
<Suspense
fallback={<ConnectedWalletFallback address={accountAddress} />}
>
<WalletDropdown
accountAddress={accountAddress}
walletName={walletName}
connectorId={connector?.id}
connectorName={connector?.name}
onAccountClick={() => setIsModalOpen(true)}
/>
</Suspense>
<WalletDropdown
accountAddress={accountAddress}
walletName={walletName}
walletIcon={walletIcon}
onAccountClick={() => setIsModalOpen(true)}
/>
)}
</div>

{isModalOpen && (
<Suspense fallback={null}>
<EvmWalletModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
/>
</Suspense>
)}
<EvmWalletModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
/>
</>
);
};

const ConnectedWalletFallback = ({ address }: { address: EvmAddress }) => (
<Button variant="outline" className="h-11 px-3 font-bold">
{`${address.slice(0, 6)}...${address.slice(-4)}`}
</Button>
);

export default ConnectWalletButton;
Original file line number Diff line number Diff line change
@@ -1,43 +1,38 @@
'use client';

import { Trigger as DropdownTrigger } from '@radix-ui/react-dropdown-menu';
import { ChevronDown } from '@tangle-network/icons/ChevronDown';
import { LoginBoxLineIcon, WalletLineIcon } from '@tangle-network/icons';
import {
Button,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@tangle-network/sandbox-ui/primitives';
Dropdown,
DropdownBody,
ExternalLinkIcon,
KeyValueWithButton,
shortenHex,
Typography,
} from '@tangle-network/ui-components';
import { EvmAddress } from '@tangle-network/ui-components/types/address';
import { cloneElement, FC, ReactElement, useCallback, useMemo } from 'react';
import { useDisconnect } from 'wagmi';
import type { EvmAddress } from '@tangle-network/ui-components/types/address';
import useNetworkStore from '../../context/useNetworkStore';
import { twMerge } from 'tailwind-merge';
import { getFlexBasic } from '@tangle-network/icons/utils';
import { getWalletIcon } from './walletIcons';

type WalletDropdownProps = {
accountAddress: EvmAddress;
walletName: string;
connectorId?: string;
connectorName?: string;
walletIcon: ReactElement;
onAccountClick?: () => void;
};

const WalletDropdown: FC<WalletDropdownProps> = ({
accountAddress,
walletName,
connectorId,
connectorName,
walletIcon,
onAccountClick,
}) => {
const { disconnect } = useDisconnect();
const walletIcon = useMemo<ReactElement>(() => {
return getWalletIcon(connectorId, connectorName);
}, [connectorId, connectorName]);

const createExplorerAccountUrl = useNetworkStore(
(store) => store.network.createExplorerAccountUrl,
Expand All @@ -52,13 +47,15 @@ const WalletDropdown: FC<WalletDropdownProps> = ({
}, [disconnect]);

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Dropdown>
<DropdownTrigger asChild>
<button
type="button"
className={twMerge(
'inline-flex h-11 max-w-64 items-center gap-2 rounded-lg border border-border bg-card px-3 text-foreground shadow-[var(--shadow-card)] transition-colors',
'hover:bg-muted/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary',
'max-w-56 rounded-lg border-2 p-2 flex items-center gap-2',
'bg-mono-0/10 dark:bg-mono-0/5',
'hover:bg-mono-100/10 dark:hover:bg-mono-0/10',
'border-2 border-mono-60 dark:border-mono-140',
)}
>
{cloneElement(walletIcon, {
Expand All @@ -69,78 +66,89 @@ const WalletDropdown: FC<WalletDropdownProps> = ({
),
})}

<span className="truncate font-bold text-sm sr-only sm:not-sr-only">
{shortenAddress(accountAddress)}
</span>
<Typography
variant="body1"
fw="bold"
component="p"
className="truncate dark:text-mono-0 sr-only sm:not-sr-only"
>
{shortenHex(accountAddress)}
</Typography>

<ChevronDown size="lg" className="shrink-0 grow-0 opacity-70" />
<ChevronDown size="lg" className="shrink-0 grow-0" />
</button>
</DropdownMenuTrigger>
</DropdownTrigger>

<DropdownMenuContent
align="end"
className="z-50 mt-2 w-[min(92vw,420px)] border-border bg-popover p-3 text-popover-foreground shadow-[var(--shadow-dropdown)]"
<DropdownBody
isPortal
className="mt-2 md:w-[540px] p-4 space-y-4 dark:bg-mono-180"
>
<DropdownMenuLabel className="p-0">
<div className="flex items-center gap-3 rounded-md border border-border bg-muted/30 p-3">
<div className="flex flex-col justify-between gap-2 md:flex-row md:items-center">
<div className="flex space-x-2 items-center">
{walletIcon}

<div className="min-w-0">
<p className="truncate font-display font-bold text-foreground text-sm capitalize">
<div>
<Typography
variant="h5"
fw="bold"
className="capitalize truncate max-w-[200px]"
>
{walletName}
</p>
<p className="mt-1 truncate font-mono text-muted-foreground text-xs">
{accountAddress}
</p>
</Typography>

<div className="flex items-center space-x-1">
<KeyValueWithButton
className="mt-0.5"
isHiddenLabel
keyValue={accountAddress}
size="sm"
labelVariant="body1"
valueVariant="h5"
displayCharCount={5}
/>

{accountExplorerUrl !== null && (
<ExternalLinkIcon href={accountExplorerUrl} size="md" />
)}
</div>
</div>
</div>
</DropdownMenuLabel>

<DropdownMenuSeparator className="my-3 bg-border" />

{onAccountClick && (
<DropdownMenuItem
className="cursor-pointer gap-2"
onClick={onAccountClick}
>
<WalletLineIcon className="fill-current" size="md" />
Switch wallet
</DropdownMenuItem>
)}

{accountExplorerUrl !== null && (
<DropdownMenuItem className="cursor-pointer gap-2" asChild>
<a href={accountExplorerUrl} target="_blank" rel="noreferrer">
<WalletLineIcon className="fill-current" size="md" />
View on explorer
</a>
</DropdownMenuItem>
)}

<DropdownMenuItem
className="cursor-pointer gap-2 text-destructive focus:text-destructive"
onClick={handleDisconnect}
>
<LoginBoxLineIcon className="fill-current" size="md" />
Disconnect
</DropdownMenuItem>

<div className="mt-3">
<Button
variant="outline"
size="sm"
className="w-full"
onClick={handleDisconnect}
>
Disconnect wallet
</Button>
<div className="flex items-center md:justify-end space-x-2.5">
{onAccountClick && (
<Button
onClick={onAccountClick}
leftIcon={
<WalletLineIcon
className="fill-current dark:fill-current"
size="md"
/>
}
variant="link"
className="text-lg"
>
Switch
</Button>
)}

<Button
onClick={handleDisconnect}
leftIcon={
<LoginBoxLineIcon
className="fill-current dark:fill-current"
size="md"
/>
}
variant="link"
className="text-lg"
>
Disconnect
</Button>
</div>
</div>
</DropdownMenuContent>
</DropdownMenu>
</DropdownBody>
</Dropdown>
);
};

const shortenAddress = (address: EvmAddress) =>
`${address.slice(0, 6)}...${address.slice(-4)}`;

export default WalletDropdown;
Loading
Loading