You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
74 lines
2.0 KiB
74 lines
2.0 KiB
import { useFetchProfile } from '@/hooks' |
|
import { toNostrBuildThumbUrl } from '@/lib/nostr-build' |
|
import { isVideo } from '@/lib/url' |
|
import { cn } from '@/lib/utils' |
|
import { Calendar } from 'lucide-react' |
|
import { useEffect, useMemo, useState } from 'react' |
|
|
|
function profileAvatarThumbUrl(avatar: string | undefined): string { |
|
const a = avatar?.trim() |
|
if (!a || !/^https?:\/\//i.test(a)) return '' |
|
if (isVideo(a)) return a |
|
return toNostrBuildThumbUrl(a) |
|
} |
|
|
|
/** |
|
* NIP-52 calendar card cover: event `image` tag, else author profile picture, else calendar icon. |
|
*/ |
|
export function CalendarEventCoverImage({ |
|
coverUrl, |
|
pubkey, |
|
className, |
|
iconClassName |
|
}: { |
|
coverUrl: string |
|
pubkey: string |
|
className?: string |
|
/** Passed to the Lucide {@link Calendar} icon when event image and profile avatar are unavailable. */ |
|
iconClassName?: string |
|
}) { |
|
const trimmedCover = coverUrl?.trim() ?? '' |
|
const { profile } = useFetchProfile(pubkey) |
|
const profileThumb = useMemo(() => profileAvatarThumbUrl(profile?.avatar), [profile?.avatar]) |
|
|
|
const [profileImgFailed, setProfileImgFailed] = useState(false) |
|
useEffect(() => { |
|
setProfileImgFailed(false) |
|
}, [profileThumb, trimmedCover, pubkey]) |
|
|
|
if (trimmedCover) { |
|
return ( |
|
<img |
|
src={trimmedCover} |
|
alt="" |
|
loading="lazy" |
|
referrerPolicy="no-referrer" |
|
className={cn('object-cover shadow-sm ring-1 ring-border/40', className)} |
|
/> |
|
) |
|
} |
|
|
|
if (profileThumb && !profileImgFailed) { |
|
return ( |
|
<img |
|
src={profileThumb} |
|
alt="" |
|
loading="lazy" |
|
referrerPolicy="no-referrer" |
|
className={cn('object-cover shadow-sm ring-1 ring-border/40', className)} |
|
onError={() => setProfileImgFailed(true)} |
|
/> |
|
) |
|
} |
|
|
|
return ( |
|
<div |
|
className={cn( |
|
'flex shrink-0 items-center justify-center bg-primary/10 shadow-sm ring-1 ring-border/40', |
|
className |
|
)} |
|
> |
|
<Calendar className={cn('text-primary/80', iconClassName ?? 'size-7')} aria-hidden /> |
|
</div> |
|
) |
|
}
|
|
|