@@ -11,16 +11,11 @@ import {
1111 TransactionHistoryElement ,
1212 DisconnectElement ,
1313} from '@solana/connector/react' ;
14- import {
15- DropdownMenu ,
16- DropdownMenuContent ,
17- DropdownMenuItem ,
18- DropdownMenuTrigger ,
19- } from '@/components/ui/dropdown-menu' ;
2014import {
2115 Wallet ,
2216 Copy ,
2317 Globe ,
18+ ChevronLeft ,
2419 Check ,
2520 RefreshCw ,
2621 Coins ,
@@ -31,13 +26,16 @@ import {
3126 LogOut ,
3227} from 'lucide-react' ;
3328import { useState } from 'react' ;
29+ import { motion } from 'motion/react' ;
3430
3531interface WalletDropdownContentProps {
3632 selectedAccount : string ;
3733 walletIcon ?: string ;
3834 walletName : string ;
3935}
4036
37+ type DropdownView = 'wallet' | 'network' ;
38+
4139const clusterColors : Record < string , string > = {
4240 'solana:mainnet' : 'bg-green-500' ,
4341 'solana:devnet' : 'bg-blue-500' ,
@@ -46,6 +44,7 @@ const clusterColors: Record<string, string> = {
4644} ;
4745
4846export function WalletDropdownContent ( { selectedAccount, walletIcon, walletName } : WalletDropdownContentProps ) {
47+ const [ view , setView ] = useState < DropdownView > ( 'wallet' ) ;
4948 const [ copied , setCopied ] = useState ( false ) ;
5049
5150 const shortAddress = `${ selectedAccount . slice ( 0 , 4 ) } ...${ selectedAccount . slice ( - 4 ) } ` ;
@@ -56,72 +55,63 @@ export function WalletDropdownContent({ selectedAccount, walletIcon, walletName
5655 setTimeout ( ( ) => setCopied ( false ) , 2000 ) ;
5756 }
5857
59- return (
60- < div className = "w-[360px] p-4 space-y-4" >
61- { /* Header with Avatar and Address */ }
62- < div className = "flex items-center justify-between" >
63- < div className = "flex items-center gap-3" >
64- < Avatar className = "h-12 w-12" >
65- { walletIcon && < AvatarImage src = { walletIcon } alt = { walletName } /> }
66- < AvatarFallback >
67- < Wallet className = "h-6 w-6" />
68- </ AvatarFallback >
69- </ Avatar >
70- < div >
71- < div className = "font-semibold text-lg" > { shortAddress } </ div >
72- < div className = "text-xs text-muted-foreground" > { walletName } </ div >
58+ // Wallet View
59+ if ( view === 'wallet' ) {
60+ return (
61+ < motion . div
62+ key = "wallet"
63+ initial = { { opacity : 0 } }
64+ animate = { { opacity : 1 } }
65+ exit = { { opacity : 0 } }
66+ transition = { { duration : 0.15 } }
67+ className = "w-[360px] p-4 space-y-4"
68+ >
69+ { /* Header with Avatar and Address */ }
70+ < div className = "flex items-center justify-between" >
71+ < div className = "flex items-center gap-3" >
72+ < Avatar className = "h-12 w-12" >
73+ { walletIcon && < AvatarImage src = { walletIcon } alt = { walletName } /> }
74+ < AvatarFallback >
75+ < Wallet className = "h-6 w-6" />
76+ </ AvatarFallback >
77+ </ Avatar >
78+ < div >
79+ < div className = "font-semibold text-lg" > { shortAddress } </ div >
80+ < div className = "text-xs text-muted-foreground" > { walletName } </ div >
81+ </ div >
7382 </ div >
74- </ div >
75- < div className = "flex items-center gap-2" >
76- < Button
77- type = "button"
78- onClick = { handleCopy }
79- variant = "outline"
80- size = "icon"
81- className = "rounded-full"
82- title = { copied ? 'Copied!' : 'Copy address' }
83- >
84- { copied ? < Check className = "h-4 w-4 text-green-500" /> : < Copy className = "h-4 w-4" /> }
85- </ Button >
83+ < div className = "flex items-center gap-2" >
84+ < Button
85+ type = "button"
86+ onClick = { handleCopy }
87+ variant = "outline"
88+ size = "icon"
89+ className = "rounded-full"
90+ title = { copied ? 'Copied!' : 'Copy address' }
91+ >
92+ { copied ? < Check className = "h-4 w-4 text-green-500" /> : < Copy className = "h-4 w-4" /> }
93+ </ Button >
8694
87- { /* Network Selector Globe Button */ }
88- < ClusterElement
89- render = { ( { cluster, clusters, setCluster } ) => (
90- < DropdownMenu >
91- < DropdownMenuTrigger asChild >
92- < Button
93- type = "button"
94- variant = "outline"
95- size = "icon"
96- className = "rounded-full relative"
97- title = { `Network: ${ cluster ?. label || 'Unknown' } ` }
98- >
99- < Globe className = "h-4 w-4" />
100- < span
101- className = { `absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 rounded-full border-2 border-background ${ clusterColors [ cluster ?. id || '' ] || 'bg-emerald-500' } ` }
102- />
103- </ Button >
104- </ DropdownMenuTrigger >
105- < DropdownMenuContent align = "end" className = "w-auto rounded-[16px]" >
106- { clusters . map ( c => (
107- < DropdownMenuItem
108- key = { c . id }
109- onClick = { ( ) => setCluster ( c . id ) }
110- className = "flex items-center gap-2 cursor-pointer rounded-[13px]"
111- >
112- < span
113- className = { `h-2 w-2 rounded-full ${ clusterColors [ c . id ] || 'bg-purple-500' } ` }
114- />
115- < span className = "flex-1" > { c . label } </ span >
116- { cluster ?. id === c . id && < Check className = "h-4 w-4" /> }
117- </ DropdownMenuItem >
118- ) ) }
119- </ DropdownMenuContent >
120- </ DropdownMenu >
121- ) }
122- />
95+ { /* Network Selector Globe Button */ }
96+ < ClusterElement
97+ render = { ( { cluster } ) => (
98+ < Button
99+ type = "button"
100+ variant = "outline"
101+ size = "icon"
102+ className = "rounded-full relative"
103+ onClick = { ( ) => setView ( 'network' ) }
104+ title = { `Network: ${ cluster ?. label || 'Unknown' } ` }
105+ >
106+ < Globe className = "h-4 w-4" />
107+ < span
108+ className = { `absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 rounded-full border-2 border-background ${ clusterColors [ cluster ?. id || '' ] || 'bg-emerald-500' } ` }
109+ />
110+ </ Button >
111+ ) }
112+ />
113+ </ div >
123114 </ div >
124- </ div >
125115
126116 { /* Full Width Balance */ }
127117 < BalanceElement
@@ -306,20 +296,90 @@ export function WalletDropdownContent({ selectedAccount, walletIcon, walletName
306296 </ AccordionItem >
307297 </ Accordion >
308298
309- { /* Disconnect Button */ }
310- < DisconnectElement
311- render = { ( { disconnect, disconnecting } ) => (
312- < Button
313- variant = "destructive"
314- className = "w-full h-11 text-base rounded-[12px]"
315- onClick = { disconnect }
316- disabled = { disconnecting }
317- >
318- < LogOut className = "h-4 w-4 mr-2" />
319- { disconnecting ? 'Disconnecting...' : 'Disconnect' }
320- </ Button >
321- ) }
299+ { /* Disconnect Button */ }
300+ < DisconnectElement
301+ render = { ( { disconnect, disconnecting } ) => (
302+ < Button
303+ variant = "destructive"
304+ className = "w-full h-11 text-base rounded-[12px]"
305+ onClick = { disconnect }
306+ disabled = { disconnecting }
307+ >
308+ < LogOut className = "h-4 w-4 mr-2" />
309+ { disconnecting ? 'Disconnecting...' : 'Disconnect' }
310+ </ Button >
311+ ) }
312+ />
313+ </ motion . div >
314+ ) ;
315+ }
316+
317+ // Network Settings View
318+ return (
319+ < motion . div
320+ key = "network"
321+ initial = { { opacity : 0 } }
322+ animate = { { opacity : 1 } }
323+ exit = { { opacity : 0 } }
324+ transition = { { duration : 0.15 } }
325+ className = "w-[360px] p-4 space-y-4"
326+ >
327+ { /* Header */ }
328+ < div className = "flex items-center gap-3" >
329+ < button
330+ type = "button"
331+ onClick = { ( ) => setView ( 'wallet' ) }
332+ className = "rounded-full border border-border p-2 hover:bg-accent transition-colors"
333+ >
334+ < ChevronLeft className = "h-4 w-4" />
335+ </ button >
336+ < span className = "font-semibold text-lg" > Network Settings</ span >
337+ </ div >
338+
339+ { /* Network Options */ }
340+ < ClusterElement
341+ render = { ( { cluster, clusters, setCluster } ) => {
342+ const currentClusterId = ( cluster as { id ?: string } ) ?. id || 'solana:mainnet' ;
343+ return (
344+ < div className = "rounded-[12px] border bg-muted/50 overflow-hidden" >
345+ { clusters . map ( ( network , index ) => {
346+ const isSelected = currentClusterId === network . id ;
347+ return (
348+ < div
349+ key = { network . id }
350+ role = "button"
351+ tabIndex = { 0 }
352+ onClick = { ( ) => setCluster ( network . id ) }
353+ onKeyDown = { e => {
354+ if ( e . key === 'Enter' || e . key === ' ' ) {
355+ e . preventDefault ( ) ;
356+ setCluster ( network . id ) ;
357+ }
358+ } }
359+ className = { `w-full flex items-center justify-between p-4 hover:bg-accent/50 transition-colors cursor-pointer ${
360+ index !== clusters . length - 1 ? 'border-b border-border' : ''
361+ } `}
362+ >
363+ < div className = "flex items-center gap-2" >
364+ < span
365+ className = { `h-2 w-2 rounded-full ${ clusterColors [ network . id ] || 'bg-purple-500' } ` }
366+ />
367+ < span className = "font-medium" > { network . label } </ span >
368+ </ div >
369+ < div
370+ className = { `h-5 w-5 rounded-full border-2 flex items-center justify-center transition-colors ${
371+ isSelected ? 'bg-primary border-primary' : 'border-muted-foreground/30'
372+ } `}
373+ >
374+ { isSelected && < Check className = "h-3 w-3 text-primary-foreground" /> }
375+ </ div >
376+ </ div >
377+ ) ;
378+ } ) }
379+ </ div >
380+ ) ;
381+ } }
322382 />
323- </ div >
383+ </ motion . div >
324384 ) ;
325385}
0 commit comments