From 731b0e613c60b9a9becc19fc6837837466999d67 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Tue, 13 Jan 2026 15:48:13 +0800 Subject: [PATCH 1/2] feat: market click dropdown --- .../shared/account-actions-popover.tsx | 93 ++++++------------- .../components/market-id-actions-popover.tsx | 59 ++++++++++++ .../markets/components/market-id-badge.tsx | 30 +++--- 3 files changed, 105 insertions(+), 77 deletions(-) create mode 100644 src/features/markets/components/market-id-actions-popover.tsx diff --git a/src/components/shared/account-actions-popover.tsx b/src/components/shared/account-actions-popover.tsx index e0120df6..3e7fe38c 100644 --- a/src/components/shared/account-actions-popover.tsx +++ b/src/components/shared/account-actions-popover.tsx @@ -1,8 +1,7 @@ 'use client'; -import { useState, useCallback, type ReactNode } from 'react'; -import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover'; -import { motion, AnimatePresence } from 'framer-motion'; +import { useCallback, type ReactNode } from 'react'; +import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@/components/ui/dropdown-menu'; import { LuCopy, LuUser } from 'react-icons/lu'; import { SiEthereum } from 'react-icons/si'; import { useStyledToast } from '@/hooks/useStyledToast'; @@ -16,20 +15,18 @@ type AccountActionsPopoverProps = { }; /** - * Minimal popover showing account actions: + * Dropdown menu showing account actions: * - Copy address * - View account (positions page) * - View on Etherscan */ export function AccountActionsPopover({ address, children }: AccountActionsPopoverProps) { - const [isOpen, setIsOpen] = useState(false); const toast = useStyledToast(); const handleCopy = useCallback(async () => { try { await navigator.clipboard.writeText(address); toast.success('Address copied', `${address.slice(0, 6)}...${address.slice(-4)}`); - setIsOpen(false); } catch (error) { console.error('Failed to copy address', error); } @@ -37,72 +34,38 @@ export function AccountActionsPopover({ address, children }: AccountActionsPopov const handleViewAccount = useCallback(() => { window.location.href = `/positions/${address}`; - setIsOpen(false); }, [address]); const handleViewExplorer = useCallback(() => { const explorerUrl = getExplorerURL(address, SupportedNetworks.Mainnet); window.open(explorerUrl, '_blank', 'noopener,noreferrer'); - setIsOpen(false); }, [address]); return ( - - -
{children}
-
- - - {isOpen && ( - - {/* Copy Address */} - void handleCopy()} - className="flex items-center gap-3 px-4 py-2.5 text-sm text-secondary transition-colors hover:bg-hovered hover:text-primary" - whileHover={{ x: 2 }} - whileTap={{ scale: 0.98 }} - > - - Copy Address - - - {/* View Account */} - - - View Account - - - {/* View on Explorer */} - - - View on Explorer - - - )} - - -
+ + +
{children}
+
+ + void handleCopy()} + startContent={} + > + Copy Address + + } + > + View Account + + } + > + View on Explorer + + +
); } diff --git a/src/features/markets/components/market-id-actions-popover.tsx b/src/features/markets/components/market-id-actions-popover.tsx new file mode 100644 index 00000000..4e2d5af8 --- /dev/null +++ b/src/features/markets/components/market-id-actions-popover.tsx @@ -0,0 +1,59 @@ +'use client'; + +import { useCallback, type ReactNode } from 'react'; +import { useRouter } from 'next/navigation'; +import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@/components/ui/dropdown-menu'; +import { LuCopy } from 'react-icons/lu'; +import { GoGraph } from 'react-icons/go'; +import { useStyledToast } from '@/hooks/useStyledToast'; + +type MarketIdActionsPopoverProps = { + marketId: string; + chainId: number; + children: ReactNode; +}; + +/** + * Dropdown menu showing market ID actions: + * - Copy ID + * - View Market + */ +export function MarketIdActionsPopover({ marketId, chainId, children }: MarketIdActionsPopoverProps) { + const toast = useStyledToast(); + const router = useRouter(); + + const handleCopy = useCallback(async () => { + try { + await navigator.clipboard.writeText(marketId); + toast.success('Market ID copied', `${marketId.slice(0, 10)}...${marketId.slice(-6)}`); + } catch (error) { + console.error('Failed to copy market ID', error); + } + }, [marketId, toast]); + + const handleViewMarket = useCallback(() => { + router.push(`/market/${chainId}/${marketId}`); + }, [chainId, marketId, router]); + + return ( + + +
{children}
+
+ + void handleCopy()} + startContent={} + > + Copy ID + + } + > + View Market + + +
+ ); +} diff --git a/src/features/markets/components/market-id-badge.tsx b/src/features/markets/components/market-id-badge.tsx index 657d0e75..f507f8cb 100644 --- a/src/features/markets/components/market-id-badge.tsx +++ b/src/features/markets/components/market-id-badge.tsx @@ -1,6 +1,8 @@ -import Link from 'next/link'; +'use client'; + import Image from 'next/image'; import { getNetworkImg } from '@/utils/networks'; +import { MarketIdActionsPopover } from './market-id-actions-popover'; type MarketIdBadgeProps = { marketId: string; @@ -13,7 +15,7 @@ export function MarketIdBadge({ marketId, chainId, showNetworkIcon = false, show const displayId = marketId.slice(2, 8); const chainImg = getNetworkImg(chainId); - return ( + const badge = (
{showNetworkIcon && chainImg && ( )} - {showLink ? ( - - {displayId} - - ) : ( - {displayId} - )} + {displayId}
); + + if (showLink) { + return ( + + {badge} + + ); + } + + return badge; } From f02f7c81309c268101613cee9794496bbf8c6ed3 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Tue, 13 Jan 2026 15:56:55 +0800 Subject: [PATCH 2/2] feat: action dropdown --- .../components/market-id-actions-popover.tsx | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/features/markets/components/market-id-actions-popover.tsx b/src/features/markets/components/market-id-actions-popover.tsx index 4e2d5af8..96656c78 100644 --- a/src/features/markets/components/market-id-actions-popover.tsx +++ b/src/features/markets/components/market-id-actions-popover.tsx @@ -36,24 +36,29 @@ export function MarketIdActionsPopover({ marketId, chainId, children }: MarketId }, [chainId, marketId, router]); return ( - - -
{children}
-
- - void handleCopy()} - startContent={} - > - Copy ID - - } - > - View Market - - -
+
e.stopPropagation()} + onKeyDown={(e) => e.stopPropagation()} + > + + +
{children}
+
+ + void handleCopy()} + startContent={} + > + Copy ID + + } + > + View Market + + +
+
); }