Browse Source

got rid of profile drawer and hover

imwald
Silberengel 5 months ago
parent
commit
93612879f2
  1. 41
      src/PageManager.tsx
  2. 51
      src/components/UserAvatar/index.tsx
  3. 51
      src/components/Username/index.tsx

41
src/PageManager.tsx

@ -172,15 +172,14 @@ export function useSmartProfileNavigation() {
const { setPrimaryNoteView } = usePrimaryNoteView() const { setPrimaryNoteView } = usePrimaryNoteView()
const navigateToProfile = (url: string) => { const navigateToProfile = (url: string) => {
if (!showRecommendedRelaysPanel) { if (showRecommendedRelaysPanel) {
// When right panel is hidden, show profile in primary area // Secondary panel is available - show profile in secondary panel
// Extract profile ID from URL (e.g., "/users/npub1..." -> "npub1...") pushSecondary(url)
} else {
// Secondary panel is not available - show profile in primary panel
const profileId = url.replace('/users/', '') const profileId = url.replace('/users/', '')
window.history.replaceState(null, '', url) window.history.replaceState(null, '', url)
setPrimaryNoteView(<SecondaryProfilePage id={profileId} index={0} hideTitlebar={true} />, 'profile') setPrimaryNoteView(<SecondaryProfilePage id={profileId} index={0} hideTitlebar={true} />, 'profile')
} else {
// Normal behavior - use secondary navigation
pushSecondary(url)
} }
} }
@ -678,6 +677,34 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
<CurrentRelaysProvider> <CurrentRelaysProvider>
<NotificationProvider> <NotificationProvider>
<PrimaryNoteViewContext.Provider value={{ setPrimaryNoteView, primaryViewType }}> <PrimaryNoteViewContext.Provider value={{ setPrimaryNoteView, primaryViewType }}>
{primaryNoteView ? (
// Show primary note view with back button on mobile
<div className="flex flex-col h-full w-full">
<div className="flex gap-1 p-1 items-center justify-between font-semibold border-b">
<div className="flex items-center flex-1 w-0">
<Button
className="flex gap-1 items-center w-fit max-w-full justify-start pl-2 pr-3"
variant="ghost"
size="titlebar-icon"
title="Back to feed"
onClick={() => setPrimaryNoteView(null)}
>
<ChevronLeft />
<div className="truncate text-lg font-semibold">
{primaryViewType === 'settings' ? 'Settings' :
primaryViewType === 'settings-sub' ? 'Settings' :
primaryViewType === 'profile' ? 'Back' :
primaryViewType === 'hashtag' ? 'Hashtag' : 'Note'}
</div>
</Button>
</div>
</div>
<div className="flex-1 overflow-auto">
{primaryNoteView}
</div>
</div>
) : (
<>
{!!secondaryStack.length && {!!secondaryStack.length &&
secondaryStack.map((item, index) => ( secondaryStack.map((item, index) => (
<div <div
@ -700,6 +727,8 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
{props ? cloneElement(element as React.ReactElement, props) : element} {props ? cloneElement(element as React.ReactElement, props) : element}
</div> </div>
))} ))}
</>
)}
<BottomNavigationBar /> <BottomNavigationBar />
<TooManyRelaysAlertDialog /> <TooManyRelaysAlertDialog />
<CreateWalletGuideToast /> <CreateWalletGuideToast />

51
src/components/UserAvatar/index.tsx

@ -1,13 +1,11 @@
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Drawer, DrawerContent, DrawerOverlay } from '@/components/ui/drawer'
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
import { Skeleton } from '@/components/ui/skeleton' import { Skeleton } from '@/components/ui/skeleton'
import { useFetchProfile } from '@/hooks' import { useFetchProfile } from '@/hooks'
import { generateImageByPubkey } from '@/lib/pubkey' import { generateImageByPubkey } from '@/lib/pubkey'
import { toProfile } from '@/lib/link'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { useScreenSize } from '@/providers/ScreenSizeProvider' import { useSmartProfileNavigation } from '@/PageManager'
import { useMemo, useState } from 'react' import { useMemo } from 'react'
import ProfileCard from '../ProfileCard'
const UserAvatarSizeCnMap = { const UserAvatarSizeCnMap = {
large: 'w-24 h-24', large: 'w-24 h-24',
@ -30,8 +28,7 @@ export default function UserAvatar({
size?: 'large' | 'big' | 'semiBig' | 'normal' | 'medium' | 'small' | 'xSmall' | 'tiny' size?: 'large' | 'big' | 'semiBig' | 'normal' | 'medium' | 'small' | 'xSmall' | 'tiny'
}) { }) {
const { profile } = useFetchProfile(userId) const { profile } = useFetchProfile(userId)
const { isSmallScreen } = useScreenSize() const { navigateToProfile } = useSmartProfileNavigation()
const [drawerOpen, setDrawerOpen] = useState(false)
const defaultAvatar = useMemo( const defaultAvatar = useMemo(
() => (profile?.pubkey ? generateImageByPubkey(profile.pubkey) : ''), () => (profile?.pubkey ? generateImageByPubkey(profile.pubkey) : ''),
[profile] [profile]
@ -42,59 +39,30 @@ export default function UserAvatar({
<Skeleton className={cn('shrink-0', UserAvatarSizeCnMap[size], 'rounded-full', className)} /> <Skeleton className={cn('shrink-0', UserAvatarSizeCnMap[size], 'rounded-full', className)} />
) )
} }
const { avatar, pubkey } = profile const { avatar, pubkey } = profile
if (isSmallScreen) {
return ( return (
<>
<Avatar <Avatar
className={cn('shrink-0 cursor-pointer', UserAvatarSizeCnMap[size], className)} className={cn('shrink-0 cursor-pointer', UserAvatarSizeCnMap[size], className)}
onClick={() => setDrawerOpen(true)} onClick={() => navigateToProfile(toProfile(pubkey))}
> >
<AvatarImage src={avatar} className="object-cover object-center" /> <AvatarImage src={avatar} className="object-cover object-center" />
<AvatarFallback> <AvatarFallback>
<img src={defaultAvatar} alt={pubkey} /> <img src={defaultAvatar} alt={pubkey} />
</AvatarFallback> </AvatarFallback>
</Avatar> </Avatar>
<Drawer open={drawerOpen} onOpenChange={setDrawerOpen}>
<DrawerOverlay onClick={() => setDrawerOpen(false)} />
<DrawerContent hideOverlay className="max-h-[90vh]">
<div className="overflow-y-auto overscroll-contain p-4" style={{ touchAction: 'pan-y' }}>
<ProfileCard pubkey={pubkey} />
</div>
</DrawerContent>
</Drawer>
</>
)
}
return (
<HoverCard>
<HoverCardTrigger asChild>
<Avatar className={cn('shrink-0 cursor-pointer', UserAvatarSizeCnMap[size], className)}>
<AvatarImage src={avatar} className="object-cover object-center" />
<AvatarFallback>
<img src={defaultAvatar} alt={pubkey} />
</AvatarFallback>
</Avatar>
</HoverCardTrigger>
<HoverCardContent className="w-72">
<ProfileCard pubkey={pubkey} />
</HoverCardContent>
</HoverCard>
) )
} }
export function SimpleUserAvatar({ export function SimpleUserAvatar({
userId, userId,
size = 'normal', size = 'normal',
className, className
onClick
}: { }: {
userId: string userId: string
size?: 'large' | 'big' | 'normal' | 'medium' | 'small' | 'xSmall' | 'tiny' size?: 'large' | 'big' | 'semiBig' | 'normal' | 'medium' | 'small' | 'xSmall' | 'tiny'
className?: string className?: string
onClick?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
}) { }) {
const { profile } = useFetchProfile(userId) const { profile } = useFetchProfile(userId)
const defaultAvatar = useMemo( const defaultAvatar = useMemo(
@ -107,10 +75,11 @@ export function SimpleUserAvatar({
<Skeleton className={cn('shrink-0', UserAvatarSizeCnMap[size], 'rounded-full', className)} /> <Skeleton className={cn('shrink-0', UserAvatarSizeCnMap[size], 'rounded-full', className)} />
) )
} }
const { avatar, pubkey } = profile const { avatar, pubkey } = profile
return ( return (
<Avatar className={cn('shrink-0', UserAvatarSizeCnMap[size], className)} onClick={onClick}> <Avatar className={cn('shrink-0', UserAvatarSizeCnMap[size], className)}>
<AvatarImage src={avatar} className="object-cover object-center" /> <AvatarImage src={avatar} className="object-cover object-center" />
<AvatarFallback> <AvatarFallback>
<img src={defaultAvatar} alt={pubkey} /> <img src={defaultAvatar} alt={pubkey} />

51
src/components/Username/index.tsx

@ -1,11 +1,8 @@
import { Drawer, DrawerContent, DrawerOverlay } from '@/components/ui/drawer'
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
import { Skeleton } from '@/components/ui/skeleton' import { Skeleton } from '@/components/ui/skeleton'
import { useFetchProfile } from '@/hooks' import { useFetchProfile } from '@/hooks'
import { toProfile } from '@/lib/link'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { useScreenSize } from '@/providers/ScreenSizeProvider' import { useSmartProfileNavigation } from '@/PageManager'
import { useState } from 'react'
import ProfileCard from '../ProfileCard'
export default function Username({ export default function Username({
userId, userId,
@ -21,8 +18,7 @@ export default function Username({
withoutSkeleton?: boolean withoutSkeleton?: boolean
}) { }) {
const { profile } = useFetchProfile(userId) const { profile } = useFetchProfile(userId)
const { isSmallScreen } = useScreenSize() const { navigateToProfile } = useSmartProfileNavigation()
const [drawerOpen, setDrawerOpen] = useState(false)
if (!profile && !withoutSkeleton) { if (!profile && !withoutSkeleton) {
return ( return (
@ -31,44 +27,21 @@ export default function Username({
</div> </div>
) )
} }
if (!profile) return null
if (!profile) {
return null
}
const { username, pubkey } = profile const { username, pubkey } = profile
if (isSmallScreen) {
return ( return (
<>
<div <div
className={cn('truncate hover:underline cursor-pointer', className)} className={cn('truncate hover:underline cursor-pointer', className)}
onClick={() => setDrawerOpen(true)} onClick={() => navigateToProfile(toProfile(pubkey))}
> >
{showAt && '@'} {showAt && '@'}
{username} {username}
</div> </div>
<Drawer open={drawerOpen} onOpenChange={setDrawerOpen}>
<DrawerOverlay onClick={() => setDrawerOpen(false)} />
<DrawerContent hideOverlay className="max-h-[90vh]">
<div className="overflow-y-auto overscroll-contain p-4" style={{ touchAction: 'pan-y' }}>
<ProfileCard pubkey={pubkey} />
</div>
</DrawerContent>
</Drawer>
</>
)
}
return (
<HoverCard>
<HoverCardTrigger asChild>
<div className={cn('truncate hover:underline cursor-pointer', className)}>
{showAt && '@'}
{username}
</div>
</HoverCardTrigger>
<HoverCardContent className="w-80">
<ProfileCard pubkey={pubkey} />
</HoverCardContent>
</HoverCard>
) )
} }
@ -86,6 +59,7 @@ export function SimpleUsername({
withoutSkeleton?: boolean withoutSkeleton?: boolean
}) { }) {
const { profile } = useFetchProfile(userId) const { profile } = useFetchProfile(userId)
if (!profile && !withoutSkeleton) { if (!profile && !withoutSkeleton) {
return ( return (
<div className="py-1"> <div className="py-1">
@ -93,12 +67,15 @@ export function SimpleUsername({
</div> </div>
) )
} }
if (!profile) return null
if (!profile) {
return null
}
const { username } = profile const { username } = profile
return ( return (
<div className={className}> <div className={cn('truncate', className)}>
{showAt && '@'} {showAt && '@'}
{username} {username}
</div> </div>

Loading…
Cancel
Save