mirror of
https://github.com/lumina-rocks/lumina.git
synced 2026-06-04 09:41:32 +02:00
Feature: Hide failed images (#43)
* fix: handle image loading errors in KIND20Card and QuickViewKind20NoteCard components * refactor: streamline KIND20Card component structure and improve readability
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type React from "react"
|
||||
import { useProfile } from "nostr-react"
|
||||
import { nip19 } from "nostr-tools"
|
||||
import { useState } from "react"
|
||||
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
|
||||
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel"
|
||||
@@ -36,8 +37,9 @@ const KIND20Card: React.FC<KIND20CardProps> = ({
|
||||
const { data: userData } = useProfile({
|
||||
pubkey,
|
||||
})
|
||||
const [imageError, setImageError] = useState(false);
|
||||
|
||||
if (!image) return null;
|
||||
if (!image || imageError) return null;
|
||||
|
||||
const title =
|
||||
userData?.username || userData?.display_name || userData?.name || userData?.npub || nip19.npubEncode(pubkey)
|
||||
@@ -49,69 +51,70 @@ const KIND20Card: React.FC<KIND20CardProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
<Link href={hrefProfile} style={{ textDecoration: "none" }}>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Avatar>
|
||||
<AvatarImage src={profileImageSrc} />
|
||||
</Avatar>
|
||||
<span className="break-all" style={{ marginLeft: "10px" }}>
|
||||
{title}
|
||||
</span>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{title}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</Link>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<div className="px-2 sm:px-4">
|
||||
<div className="w-full">
|
||||
<div className="relative w-full" style={{ paddingBottom: "100%" }}>
|
||||
{image && (
|
||||
|
||||
<div key={event.id} className="py-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
<Link href={hrefProfile} style={{ textDecoration: "none" }}>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Avatar>
|
||||
<AvatarImage src={profileImageSrc} />
|
||||
</Avatar>
|
||||
<span className="break-all" style={{ marginLeft: "10px" }}>
|
||||
{title}
|
||||
</span>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{title}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</Link>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<div className="px-2 sm:px-4">
|
||||
<div className="w-full">
|
||||
<div className="relative w-full" style={{ paddingBottom: "100%" }}>
|
||||
<Image
|
||||
src={image || "/placeholder.svg"}
|
||||
src={image}
|
||||
alt={text}
|
||||
fill
|
||||
className="rounded-lg object-contain"
|
||||
// sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
||||
onError={() => setImageError(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<div className="break-word overflow-hidden">{text}</div>
|
||||
<hr className="my-4" />
|
||||
<div className="space-x-4 flex justify-between items-start">
|
||||
<div className="flex space-x-4">
|
||||
<ReactionButton event={event} />
|
||||
<ZapButton event={event} />
|
||||
{showViewNoteCardButton && <ViewNoteButton event={event} />}
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
<ViewCopyButton event={event} />
|
||||
<ViewRawButton event={event} />
|
||||
<div className="p-4">
|
||||
<div className="break-word overflow-hidden">{text}</div>
|
||||
<hr className="my-4" />
|
||||
<div className="space-x-4 flex justify-between items-start">
|
||||
<div className="flex space-x-4">
|
||||
<ReactionButton event={event} />
|
||||
<ZapButton event={event} />
|
||||
{showViewNoteCardButton && <ViewNoteButton event={event} />}
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
<ViewCopyButton event={event} />
|
||||
<ViewRawButton event={event} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<div className="grid grid-cols-1">
|
||||
<small className="text-muted">{createdAt.toLocaleString()}</small>
|
||||
{uploadedVia && <small className="text-muted">Uploaded via {uploadedVia}</small>}
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<div className="grid grid-cols-1">
|
||||
<small className="text-muted">{createdAt.toLocaleString()}</small>
|
||||
{uploadedVia && <small className="text-muted">Uploaded via {uploadedVia}</small>}
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -41,18 +41,16 @@ const ProfileFeed: React.FC<ProfileFeedProps> = ({ pubkey }) => {
|
||||
{events.map((event) => {
|
||||
const imageUrl = getImageUrl(event.tags);
|
||||
return imageUrl ? (
|
||||
<div key={event.id} className="py-6">
|
||||
<KIND20Card
|
||||
key={event.id}
|
||||
pubkey={event.pubkey}
|
||||
text={event.content}
|
||||
image={imageUrl}
|
||||
event={event}
|
||||
tags={event.tags}
|
||||
eventId={event.id}
|
||||
showViewNoteCardButton={true}
|
||||
/>
|
||||
</div>
|
||||
<KIND20Card
|
||||
key={event.id}
|
||||
pubkey={event.pubkey}
|
||||
text={event.content}
|
||||
image={imageUrl}
|
||||
event={event}
|
||||
tags={event.tags}
|
||||
eventId={event.id}
|
||||
showViewNoteCardButton={true}
|
||||
/>
|
||||
) : null;
|
||||
})}
|
||||
{!isLoading && (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useProfile } from "nostr-react";
|
||||
import {
|
||||
nip19,
|
||||
@@ -25,8 +25,9 @@ const QuickViewKind20NoteCard: React.FC<QuickViewKind20NoteCardProps> = ({ pubke
|
||||
const {data, isLoading} = useProfile({
|
||||
pubkey,
|
||||
});
|
||||
const [imageError, setImageError] = useState(false);
|
||||
|
||||
if (!image) return null;
|
||||
if (!image || imageError) return null;
|
||||
|
||||
text = text.replaceAll('\n', ' ');
|
||||
const encodedNoteId = nip19.noteEncode(event.id)
|
||||
@@ -45,6 +46,7 @@ const QuickViewKind20NoteCard: React.FC<QuickViewKind20NoteCardProps> = ({ pubke
|
||||
sizes="(max-width: 768px) 100vw, 300px"
|
||||
className='rounded lg:rounded-lg object-cover'
|
||||
priority
|
||||
onError={() => setImageError(true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user