-
-
- {t('testnet')}
-
-
+ const isDarkTheme = mounted && theme === 'dark'
+ const themeToggleLabel = isDarkTheme ? t('switchToLight') : t('switchToDark')
+
+ return (
+
- )
-}
-
-const iconBtnStyle = {
- display: 'inline-flex',
- alignItems: 'center',
- justifyContent: 'center',
- width: 38,
- height: 38,
- borderRadius: 'var(--radius-pill)',
- background: 'none',
- border: 'none',
- cursor: 'pointer',
- color: 'var(--ink-60)',
-} as const
-
-function ChevronDown() {
- return (
-
- )
-}
-function MoonIcon() {
- return (
-
- )
-}
-function SunIcon() {
- return (
-
- )
-}
-
-/** The connected wallet pill + its account menu (incl. Disconnect / sign out). */
-function WalletMenu({ address, isDemo }: { address: string; isDemo: boolean }) {
- const t = useTranslations('Nav')
- const router = useRouter()
- const { disconnect } = useWallet()
- const [open, setOpen] = useState(false)
- const [copied, setCopied] = useState(false)
- const ref = useRef
(null)
- const triggerRef = useRef(null)
- const itemRefs = useRef<(HTMLButtonElement | HTMLAnchorElement | null)[]>([])
-
- // Focus first item when menu opens; restore trigger focus when it closes.
- const prevOpen = useRef(false)
- useEffect(() => {
- if (open && !prevOpen.current) {
- setTimeout(() => itemRefs.current[0]?.focus(), 0)
- }
- if (!open && prevOpen.current) {
- triggerRef.current?.focus()
- }
- prevOpen.current = open
- }, [open])
-
- useEffect(() => {
- if (!open) return
- const onDown = (e: MouseEvent) => {
- if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false)
- }
- document.addEventListener('mousedown', onDown)
- return () => document.removeEventListener('mousedown', onDown)
- }, [open])
-
- const copy = () => {
- try {
- navigator.clipboard?.writeText(address)
- } catch {
- /* ignore */
- }
- setCopied(true)
- setTimeout(() => setCopied(false), 1400)
- }
-
- const handleMenuKeyDown = (e: React.KeyboardEvent) => {
- const items = itemRefs.current.filter(
- (el): el is HTMLButtonElement | HTMLAnchorElement => el !== null,
- )
- if (!items.length) return
- const focused = document.activeElement
- const idx = items.indexOf(focused as HTMLButtonElement)
-
- if (e.key === 'ArrowDown') {
- e.preventDefault()
- items[(idx + 1) % items.length].focus()
- } else if (e.key === 'ArrowUp') {
- e.preventDefault()
- items[(idx - 1 + items.length) % items.length].focus()
- } else if (e.key === 'Home') {
- e.preventDefault()
- items[0].focus()
- } else if (e.key === 'End') {
- e.preventDefault()
- items[items.length - 1].focus()
- } else if (e.key === 'Escape') {
- setOpen(false)
- } else if (e.key === 'Tab') {
- setOpen(false)
- }
- }
-
- // Reset item refs array before each render so stale refs don't linger
- // eslint-disable-next-line react-hooks/refs
- itemRefs.current = []
-
- return (
-
-
-
- {open && (
-
-
-
- {shortAddress(address, 6, 6)}
-
-
- {isDemo ? t('demoSession') : t('testnet')}
-
-
-
-
-
- {!isDemo && (
-
{
- itemRefs.current.push(el)
- }}
- href={`https://stellar.expert/explorer/testnet/account/${address}`}
- >
- {t('viewOnExplorer')}
-
- )}
-
-
- )}
-
- )
-}
-
-const MenuItem = function MenuItem({
- children,
- onClick,
- tone,
- ref: _ref,
-}: {
- children: ReactNode
- onClick: () => void
- tone?: 'ember'
- ref?: ((el: HTMLButtonElement | null) => void) | null
-}) {
- const [hover, setHover] = useState(false)
- return (
-
- )
-}
-
-const MenuLink = function MenuLink({
- children,
- href,
- ref: _ref,
-}: {
- children: ReactNode
- href: string
- ref?: ((el: HTMLAnchorElement | null) => void) | null
-}) {
- const [hover, setHover] = useState(false)
- return (
- setHover(true)}
- onMouseLeave={() => setHover(false)}
- style={{
- ...menuItemStyle,
- textDecoration: 'none',
- background: hover ? 'var(--ink-06)' : 'transparent',
- color: 'var(--ink)',
- }}
- >
- {children} ↗
-
- )
-}
-
-const menuItemStyle: CSSProperties = {
- display: 'block',
- width: '100%',
- textAlign: 'left',
- border: 'none',
- cursor: 'pointer',
- padding: '9px 10px',
- borderRadius: 'var(--radius-input)',
- fontFamily: 'var(--font-body)',
- fontSize: 14,
- fontWeight: 500,
-}
+ ...iconBtnStyle,
+ width: 'auto',
+ gap: 5,
+ padding: '0 6px',
+ fontFamily: 'var(--font-body)',
+ fontSize: 14,
+ color: 'var(--ink-60)',
+ }}
+ >
+ {locale.toUpperCase()}
+
+
+
+ {connected && address ? (
+
+ ) : (
+
+ )}
+
+