From d64d2c908b1620373f7019ddef611f622c9c0597 Mon Sep 17 00:00:00 2001 From: alez04 Date: Sun, 29 Mar 2026 00:45:40 +0200 Subject: [PATCH 1/2] feat: add reusable account avatar component --- bun.lock | 3 ++ package.json | 1 + src/components/account-avatar.tsx | 58 +++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 src/components/account-avatar.tsx diff --git a/bun.lock b/bun.lock index c67ae89c..a1475adf 100644 --- a/bun.lock +++ b/bun.lock @@ -41,6 +41,7 @@ "@radix-ui/react-tooltip": "^1.2.8", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-query": "^5.90.20", + "boring-avatars": "^2.0.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -719,6 +720,8 @@ "blakejs": ["blakejs@1.2.1", "", {}, "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ=="], + "boring-avatars": ["boring-avatars@2.0.4", "", { "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-xhZO/w/6aFmRfkaWohcl2NfyIy87gK5SBbys8kctZeTGF1Apjpv/10pfUuv+YEfVPkESU/h2Y6tt/Dwp+bIZPw=="], + "bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], diff --git a/package.json b/package.json index a29fa9c3..52258dbc 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "@radix-ui/react-tooltip": "^1.2.8", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-query": "^5.90.20", + "boring-avatars": "^2.0.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", diff --git a/src/components/account-avatar.tsx b/src/components/account-avatar.tsx new file mode 100644 index 00000000..bb370cd1 --- /dev/null +++ b/src/components/account-avatar.tsx @@ -0,0 +1,58 @@ +import BoringAvatar from 'boring-avatars' +import { EyeIcon } from 'lucide-react' +import { cn } from '@/lib/utils' + +const ACCOUNT_AVATAR_COLORS = [ + '#1ADEF5', + '#03C1DB', + '#61F0FE', + '#0C131B', + '#152A38', + '#47CD89', + '#FABC3C', +] + +const SIZE_STYLES = { + xs: { className: 'h-6 w-6', pixelSize: 24 }, + sm: { className: 'h-8 w-8', pixelSize: 32 }, + md: { className: 'h-10 w-10', pixelSize: 40 }, + lg: { className: 'h-12 w-12', pixelSize: 48 }, +} as const + +type AccountAvatarProps = { + identity: string + name?: string + watchOnly?: boolean + size?: keyof typeof SIZE_STYLES + className?: string +} + +const AccountAvatar = ({ + identity, + name, + watchOnly = false, + size = 'md', + className, +}: AccountAvatarProps) => { + const { className: sizeClassName, pixelSize } = SIZE_STYLES[size] + const avatarName = name?.trim() ? `${name}-${identity}` : identity + + return ( +
+ + {watchOnly && ( + + + + )} +
+ ) +} + +export default AccountAvatar From 7fdf9bb2c05d5d636a340b406b4c647587b116aa Mon Sep 17 00:00:00 2001 From: alez04 Date: Sun, 29 Mar 2026 00:45:58 +0200 Subject: [PATCH 2/2] feat: show account avatars across account surfaces --- src/components/app-header.tsx | 33 +++++++----- src/components/dapp/dapp-approval-drawer.tsx | 50 +++++++++++++------ .../manage-accounts/account-list-item.tsx | 7 +++ 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/components/app-header.tsx b/src/components/app-header.tsx index 5467289f..2c1ba69e 100644 --- a/src/components/app-header.tsx +++ b/src/components/app-header.tsx @@ -1,12 +1,5 @@ -import { - CopyIcon, - EyeIcon, - XIcon, - PanelRightOpenIcon, - PlusIcon, - UsersIcon, - WalletIcon, -} from 'lucide-react' +import { CopyIcon, EyeIcon, XIcon, PanelRightOpenIcon, PlusIcon, UsersIcon } from 'lucide-react' +import AccountAvatar from '@/components/account-avatar' import { Button } from '@/components/ui/button' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' import { truncateString } from '@/lib/utils' @@ -59,6 +52,10 @@ const AppHeader = ({ Array<{ name: string; identity: string; watchOnly?: boolean }> >([]) const [isMenuOpen, setIsMenuOpen] = useState(false) + const activeAccount = useMemo( + () => accounts.find((account) => account.identity === identity), + [accounts, identity], + ) const refreshAccounts = useCallback(() => { const nextAccountName = @@ -160,9 +157,12 @@ const AppHeader = ({ className="flex min-w-0 items-center gap-3 text-left" aria-label={t('home.accounts.selectLabel')} > -
- -
+
{accountName} @@ -212,10 +212,17 @@ const AppHeader = ({ key={account.identity} type="button" onClick={() => handleSelectAccount(account)} - className={`flex w-full items-center rounded-md px-2 py-2 text-left text-sm transition hover:bg-muted/30 ${ + className={`flex w-full items-center gap-3 rounded-md px-2 py-2 text-left text-sm transition hover:bg-muted/30 ${ account.identity === identity ? 'bg-muted/20' : '' }`} > +
diff --git a/src/components/dapp/dapp-approval-drawer.tsx b/src/components/dapp/dapp-approval-drawer.tsx index 0931c89f..89a61a94 100644 --- a/src/components/dapp/dapp-approval-drawer.tsx +++ b/src/components/dapp/dapp-approval-drawer.tsx @@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { useLocation } from 'react-router-dom' import { ChevronDownIcon, ChevronUpIcon, GlobeIcon, Link2OffIcon, LinkIcon } from 'lucide-react' +import AccountAvatar from '@/components/account-avatar' import { Button } from '@/components/ui/button' import { Drawer, @@ -282,12 +283,21 @@ const DappApprovalDrawer = () => {

{t('dapp.approval.sharedAccount')}

-

- {connectSummary.accountName || t('dapp.approval.sharedAccountFallback')} -

-

- {truncateString(connectSummary.accountIdentity)} -

+
+ +
+

+ {connectSummary.accountName || t('dapp.approval.sharedAccountFallback')} +

+

+ {truncateString(connectSummary.accountIdentity)} +

+
+
)} {current.method === 'signMessage' && ( @@ -371,15 +381,25 @@ const DappApprovalDrawer = () => { )} {isWatchOnlySigningRequest && accountSummary && (
-

- {t('dapp.approval.watchOnlyTitle')} -

-

- {t('dapp.approval.watchOnlyDescription', { - accountName: - accountSummary.accountName || t('dapp.approval.sharedAccountFallback'), - })} -

+
+ +
+

+ {t('dapp.approval.watchOnlyTitle')} +

+

+ {t('dapp.approval.watchOnlyDescription', { + accountName: + accountSummary.accountName || t('dapp.approval.sharedAccountFallback'), + })} +

+
+
)} {requiresPassphrase && !isWatchOnlySigningRequest && ( diff --git a/src/components/pages/manage-accounts/account-list-item.tsx b/src/components/pages/manage-accounts/account-list-item.tsx index 763a269c..e4afdd17 100644 --- a/src/components/pages/manage-accounts/account-list-item.tsx +++ b/src/components/pages/manage-accounts/account-list-item.tsx @@ -8,6 +8,7 @@ import { TrashIcon, } from 'lucide-react' import { useTranslation } from 'react-i18next' +import AccountAvatar from '@/components/account-avatar' import { Button } from '@/components/ui/button' import { DropdownMenu, @@ -76,6 +77,12 @@ const AccountListItem = ({ } ${isDragging ? 'opacity-60' : ''}`} >
+
{account.name}