mirror of
https://gitlab.com/soapbox-pub/mkstack.git
synced 2025-08-27 13:09:22 +00:00
Use generated username fallback in other parts of the UI
This commit is contained in:
parent
9cb2795496
commit
130300f1c1
@ -122,14 +122,15 @@ The data may be transformed into a more appropriate format if needed, and multip
|
|||||||
To display profile data for a user by their Nostr pubkey (such as an event author), use the `useAuthor` hook.
|
To display profile data for a user by their Nostr pubkey (such as an event author), use the `useAuthor` hook.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import { NostrEvent, NostrMetadata } from '@nostrify/nostrify';
|
import type { NostrEvent, NostrMetadata } from '@nostrify/nostrify';
|
||||||
import { useAuthor } from '@/hooks/useAuthor';
|
import { useAuthor } from '@/hooks/useAuthor';
|
||||||
|
import { genUserName } from '@/lib/genUserName';
|
||||||
|
|
||||||
function Post({ event }: { event: NostrEvent }) {
|
function Post({ event }: { event: NostrEvent }) {
|
||||||
const author = useAuthor(event.pubkey);
|
const author = useAuthor(event.pubkey);
|
||||||
const metadata: NostrMetadata | undefined = author.data?.metadata;
|
const metadata: NostrMetadata | undefined = author.data?.metadata;
|
||||||
|
|
||||||
const displayName = metadata?.name || event.pubkey.slice(0, 8);
|
const displayName = metadata?.name ?? genUserName(event.pubkey);
|
||||||
const profileImage = metadata?.picture;
|
const profileImage = metadata?.picture;
|
||||||
|
|
||||||
// ...render elements with this data
|
// ...render elements with this data
|
||||||
|
@ -3,6 +3,7 @@ import { type NostrEvent } from '@nostrify/nostrify';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { nip19 } from 'nostr-tools';
|
import { nip19 } from 'nostr-tools';
|
||||||
import { useAuthor } from '@/hooks/useAuthor';
|
import { useAuthor } from '@/hooks/useAuthor';
|
||||||
|
import { genUserName } from '@/lib/genUserName';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
interface NoteContentProps {
|
interface NoteContentProps {
|
||||||
@ -118,7 +119,7 @@ function NostrMention({ pubkey }: { pubkey: string }) {
|
|||||||
const author = useAuthor(pubkey);
|
const author = useAuthor(pubkey);
|
||||||
const npub = nip19.npubEncode(pubkey);
|
const npub = nip19.npubEncode(pubkey);
|
||||||
const hasRealName = !!author.data?.metadata?.name;
|
const hasRealName = !!author.data?.metadata?.name;
|
||||||
const displayName = author.data?.metadata?.name ?? generateDeterministicName(pubkey);
|
const displayName = author.data?.metadata?.name ?? genUserName(pubkey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
@ -133,34 +134,4 @@ function NostrMention({ pubkey }: { pubkey: string }) {
|
|||||||
@{displayName}
|
@{displayName}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a deterministic name based on pubkey
|
|
||||||
function generateDeterministicName(pubkey: string): string {
|
|
||||||
// Use a simple hash of the pubkey to generate consistent adjective + noun combinations
|
|
||||||
const adjectives = [
|
|
||||||
'Swift', 'Bright', 'Calm', 'Bold', 'Wise', 'Kind', 'Quick', 'Brave',
|
|
||||||
'Cool', 'Sharp', 'Clear', 'Strong', 'Smart', 'Fast', 'Keen', 'Pure',
|
|
||||||
'Noble', 'Gentle', 'Fierce', 'Steady', 'Clever', 'Proud', 'Silent', 'Wild'
|
|
||||||
];
|
|
||||||
|
|
||||||
const nouns = [
|
|
||||||
'Fox', 'Eagle', 'Wolf', 'Bear', 'Lion', 'Tiger', 'Hawk', 'Owl',
|
|
||||||
'Deer', 'Raven', 'Falcon', 'Lynx', 'Otter', 'Whale', 'Shark', 'Dolphin',
|
|
||||||
'Phoenix', 'Dragon', 'Panther', 'Jaguar', 'Cheetah', 'Leopard', 'Puma', 'Cobra'
|
|
||||||
];
|
|
||||||
|
|
||||||
// Create a simple hash from the pubkey
|
|
||||||
let hash = 0;
|
|
||||||
for (let i = 0; i < pubkey.length; i++) {
|
|
||||||
const char = pubkey.charCodeAt(i);
|
|
||||||
hash = ((hash << 5) - hash) + char;
|
|
||||||
hash = hash & hash; // Convert to 32-bit integer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use absolute value to ensure positive index
|
|
||||||
const adjIndex = Math.abs(hash) % adjectives.length;
|
|
||||||
const nounIndex = Math.abs(hash >> 8) % nouns.length;
|
|
||||||
|
|
||||||
return `${adjectives[adjIndex]}${nouns[nounIndex]}`;
|
|
||||||
}
|
}
|
@ -10,7 +10,8 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu.tsx';
|
} from '@/components/ui/dropdown-menu.tsx';
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar.tsx';
|
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar.tsx';
|
||||||
import { useLoggedInAccounts } from '@/hooks/useLoggedInAccounts';
|
import { useLoggedInAccounts, type Account } from '@/hooks/useLoggedInAccounts';
|
||||||
|
import { genUserName } from '@/lib/genUserName';
|
||||||
|
|
||||||
interface AccountSwitcherProps {
|
interface AccountSwitcherProps {
|
||||||
onAddAccountClick: () => void;
|
onAddAccountClick: () => void;
|
||||||
@ -21,16 +22,18 @@ export function AccountSwitcher({ onAddAccountClick }: AccountSwitcherProps) {
|
|||||||
|
|
||||||
if (!currentUser) return null;
|
if (!currentUser) return null;
|
||||||
|
|
||||||
|
const getDisplayName = (account: Account): string => account.metadata.name ?? genUserName(account.pubkey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<button className='flex items-center gap-3 p-3 rounded-full hover:bg-accent transition-all w-full text-foreground'>
|
<button className='flex items-center gap-3 p-3 rounded-full hover:bg-accent transition-all w-full text-foreground'>
|
||||||
<Avatar className='w-10 h-10'>
|
<Avatar className='w-10 h-10'>
|
||||||
<AvatarImage src={currentUser.metadata.picture} alt={currentUser.metadata.name} />
|
<AvatarImage src={currentUser.metadata.picture} alt={getDisplayName(currentUser)} />
|
||||||
<AvatarFallback>{currentUser.metadata.name?.charAt(0) || <UserIcon />}</AvatarFallback>
|
<AvatarFallback>{getDisplayName(currentUser).charAt(0)}</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<div className='flex-1 text-left hidden md:block truncate'>
|
<div className='flex-1 text-left hidden md:block truncate'>
|
||||||
<p className='font-medium text-sm truncate'>{currentUser.metadata.name || currentUser.pubkey}</p>
|
<p className='font-medium text-sm truncate'>{getDisplayName(currentUser)}</p>
|
||||||
</div>
|
</div>
|
||||||
<ChevronDown className='w-4 h-4 text-muted-foreground' />
|
<ChevronDown className='w-4 h-4 text-muted-foreground' />
|
||||||
</button>
|
</button>
|
||||||
@ -44,11 +47,11 @@ export function AccountSwitcher({ onAddAccountClick }: AccountSwitcherProps) {
|
|||||||
className='flex items-center gap-2 cursor-pointer p-2 rounded-md'
|
className='flex items-center gap-2 cursor-pointer p-2 rounded-md'
|
||||||
>
|
>
|
||||||
<Avatar className='w-8 h-8'>
|
<Avatar className='w-8 h-8'>
|
||||||
<AvatarImage src={user.metadata.picture} alt={user.metadata.name} />
|
<AvatarImage src={user.metadata.picture} alt={getDisplayName(user)} />
|
||||||
<AvatarFallback>{user.metadata.name?.charAt(0) || <UserIcon />}</AvatarFallback>
|
<AvatarFallback>{getDisplayName(user)?.charAt(0) || <UserIcon />}</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<div className='flex-1 truncate'>
|
<div className='flex-1 truncate'>
|
||||||
<p className='text-sm font-medium'>{user.metadata.name || user.pubkey}</p>
|
<p className='text-sm font-medium'>{getDisplayName(user)}</p>
|
||||||
</div>
|
</div>
|
||||||
{user.id === currentUser.id && <div className='w-2 h-2 rounded-full bg-primary'></div>}
|
{user.id === currentUser.id && <div className='w-2 h-2 rounded-full bg-primary'></div>}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user