feat: 💨

This commit is contained in:
codytseng
2025-11-29 12:17:52 +08:00
parent a9f115d202
commit f48f7d9edd
3 changed files with 56 additions and 27 deletions

View File

@@ -1,8 +1,8 @@
import { FormattedTimestamp } from '@/components/FormattedTimestamp'
import { Button } from '@/components/ui/button'
import { Skeleton } from '@/components/ui/skeleton'
import UserAvatar from '@/components/UserAvatar'
import Username from '@/components/Username'
import UserAvatar, { SimpleUserAvatar } from '@/components/UserAvatar'
import Username, { SimpleUsername } from '@/components/Username'
import { isMentioningMutedUsers } from '@/lib/event'
import { toNote, toUserAggregationDetail } from '@/lib/link'
import { cn, isTouchDevice } from '@/lib/utils'
@@ -371,6 +371,7 @@ function UserAggregationItem({
onClick: () => void
}) {
const { t } = useTranslation()
const supportTouch = useMemo(() => isTouchDevice(), [])
const [hasNewEvents, setHasNewEvents] = useState(true)
const [isPinned, setIsPinned] = useState(userAggregationService.isPinned(aggregation.pubkey))
@@ -418,14 +419,26 @@ function UserAggregationItem({
className="group relative flex items-center gap-4 px-4 py-3 border-b hover:bg-accent/30 cursor-pointer transition-all duration-200"
onClick={onClick}
>
<UserAvatar userId={aggregation.pubkey} />
{supportTouch ? (
<SimpleUserAvatar userId={aggregation.pubkey} />
) : (
<UserAvatar userId={aggregation.pubkey} />
)}
<div className="flex-1 min-w-0 flex flex-col">
<Username
userId={aggregation.pubkey}
className="font-semibold text-base truncate max-w-fit"
skeletonClassName="h-4"
/>
{supportTouch ? (
<SimpleUsername
userId={aggregation.pubkey}
className="font-semibold text-base truncate max-w-fit"
skeletonClassName="h-4"
/>
) : (
<Username
userId={aggregation.pubkey}
className="font-semibold text-base truncate max-w-fit"
skeletonClassName="h-4"
/>
)}
<FormattedTimestamp
timestamp={aggregation.lastEventTime}
className="text-sm text-muted-foreground"

View File

@@ -3,7 +3,7 @@ import { Skeleton } from '@/components/ui/skeleton'
import { useFetchProfile } from '@/hooks'
import { toProfile } from '@/lib/link'
import { generateImageByPubkey } from '@/lib/pubkey'
import { cn } from '@/lib/utils'
import { cn, isTouchDevice } from '@/lib/utils'
import { SecondaryPageLink } from '@/PageManager'
import { useMemo } from 'react'
import Image from '../Image'
@@ -29,13 +29,21 @@ export default function UserAvatar({
className?: string
size?: 'large' | 'big' | 'semiBig' | 'normal' | 'medium' | 'small' | 'xSmall' | 'tiny'
}) {
const supportTouch = useMemo(() => isTouchDevice(), [])
const trigger = (
<SecondaryPageLink to={toProfile(userId)} onClick={(e) => e.stopPropagation()}>
<SimpleUserAvatar userId={userId} size={size} className={className} />
</SecondaryPageLink>
)
if (supportTouch) {
return trigger
}
return (
<HoverCard>
<HoverCardTrigger>
<SecondaryPageLink to={toProfile(userId)} onClick={(e) => e.stopPropagation()}>
<SimpleUserAvatar userId={userId} size={size} className={className} />
</SecondaryPageLink>
</HoverCardTrigger>
<HoverCardTrigger>{trigger}</HoverCardTrigger>
<HoverCardContent className="w-72">
<ProfileCard userId={userId} />
</HoverCardContent>

View File

@@ -2,10 +2,11 @@ import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/h
import { Skeleton } from '@/components/ui/skeleton'
import { useFetchProfile } from '@/hooks'
import { toProfile } from '@/lib/link'
import { cn } from '@/lib/utils'
import { cn, isTouchDevice } from '@/lib/utils'
import { SecondaryPageLink } from '@/PageManager'
import ProfileCard from '../ProfileCard'
import TextWithEmojis from '../TextWithEmojis'
import { useMemo } from 'react'
export default function Username({
userId,
@@ -21,6 +22,7 @@ export default function Username({
withoutSkeleton?: boolean
}) {
const { profile, isFetching } = useFetchProfile(userId)
const supportTouch = useMemo(() => isTouchDevice(), [])
if (!profile && isFetching && !withoutSkeleton) {
return (
<div className="py-1">
@@ -30,20 +32,26 @@ export default function Username({
}
if (!profile) return null
const trigger = (
<div className={className}>
<SecondaryPageLink
to={toProfile(userId)}
className="truncate hover:underline"
onClick={(e) => e.stopPropagation()}
>
{showAt && '@'}
<TextWithEmojis text={profile.username} emojis={profile.emojis} emojiClassName="mb-1" />
</SecondaryPageLink>
</div>
)
if (supportTouch) {
return trigger
}
return (
<HoverCard>
<HoverCardTrigger asChild>
<div className={className}>
<SecondaryPageLink
to={toProfile(userId)}
className="truncate hover:underline"
onClick={(e) => e.stopPropagation()}
>
{showAt && '@'}
<TextWithEmojis text={profile.username} emojis={profile.emojis} emojiClassName="mb-1" />
</SecondaryPageLink>
</div>
</HoverCardTrigger>
<HoverCardTrigger asChild>{trigger}</HoverCardTrigger>
<HoverCardContent className="w-80">
<ProfileCard userId={userId} />
</HoverCardContent>