mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-11 16:07:15 +02:00
refactor: Simplify badge renderers
Simplify NIP-58 badge renderers based on feedback: - Rename "badge definition" to "badge" in comments and docs - Remove image and ID from feed view (show only name + description) - Remove award statistics fetching/display from detail view - Remove badge address section from detail view Feed view now shows minimal info (name, description) while detail view focuses on badge metadata and image variants without external queries.
This commit is contained in:
@@ -8,10 +8,6 @@ import {
|
||||
} from "@/lib/nip58-helpers";
|
||||
import { UserName } from "../UserName";
|
||||
import { Award } from "lucide-react";
|
||||
import { useMemo } from "react";
|
||||
import { useLiveTimeline } from "@/hooks/useLiveTimeline";
|
||||
import { getSeenRelays } from "applesauce-core/helpers/relays";
|
||||
import { relayListCache } from "@/services/relay-list-cache";
|
||||
|
||||
interface BadgeDefinitionDetailRendererProps {
|
||||
event: NostrEvent;
|
||||
@@ -50,8 +46,8 @@ function ImageVariant({
|
||||
}
|
||||
|
||||
/**
|
||||
* Detail renderer for Kind 30009 - Badge Definition (NIP-58)
|
||||
* Shows comprehensive badge information including all image variants
|
||||
* Detail renderer for Kind 30009 - Badge (NIP-58)
|
||||
* Shows badge information including all image variants
|
||||
*/
|
||||
export function BadgeDefinitionDetailRenderer({
|
||||
event,
|
||||
@@ -65,61 +61,6 @@ export function BadgeDefinitionDetailRenderer({
|
||||
// Use name if available, fallback to identifier
|
||||
const displayTitle = name || identifier || "Badge";
|
||||
|
||||
// Build relay list for fetching badge awards (kind 8)
|
||||
const relays = useMemo(() => {
|
||||
const relaySet = new Set<string>();
|
||||
|
||||
// Add seen relays from the badge definition event
|
||||
const seenRelays = getSeenRelays(event);
|
||||
if (seenRelays) {
|
||||
for (const relay of seenRelays) {
|
||||
relaySet.add(relay);
|
||||
}
|
||||
}
|
||||
|
||||
// Add issuer's outbox relays
|
||||
const outboxRelays = relayListCache.getOutboxRelaysSync(event.pubkey);
|
||||
if (outboxRelays) {
|
||||
for (const relay of outboxRelays.slice(0, 3)) {
|
||||
relaySet.add(relay);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(relaySet);
|
||||
}, [event]);
|
||||
|
||||
// Query for awards (kind 8) that reference this badge definition
|
||||
const awardsFilter = useMemo(() => {
|
||||
if (!identifier) {
|
||||
return { kinds: [8], ids: [] }; // No match if no identifier
|
||||
}
|
||||
return {
|
||||
kinds: [8],
|
||||
"#a": [`30009:${event.pubkey}:${identifier}`],
|
||||
};
|
||||
}, [event.pubkey, identifier]);
|
||||
|
||||
// Fetch awards from relays
|
||||
const { events: awards } = useLiveTimeline(
|
||||
`badge-awards-${event.id}`,
|
||||
awardsFilter,
|
||||
relays,
|
||||
{ limit: 100 },
|
||||
);
|
||||
|
||||
// Count unique recipients
|
||||
const uniqueRecipients = useMemo(() => {
|
||||
if (!awards || awards.length === 0) return 0;
|
||||
const recipients = new Set<string>();
|
||||
for (const award of awards) {
|
||||
const pTags = award.tags.filter((tag) => tag[0] === "p" && tag[1]);
|
||||
for (const pTag of pTags) {
|
||||
recipients.add(pTag[1]);
|
||||
}
|
||||
}
|
||||
return recipients.size;
|
||||
}, [awards]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 p-6 max-w-4xl mx-auto">
|
||||
{/* Header Section */}
|
||||
@@ -164,26 +105,6 @@ export function BadgeDefinitionDetailRenderer({
|
||||
</code>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Awards Count */}
|
||||
{awards && awards.length > 0 && (
|
||||
<div className="flex flex-col gap-1">
|
||||
<h3 className="text-muted-foreground">Times Awarded</h3>
|
||||
<span className="text-sm">
|
||||
{awards.length} award{awards.length !== 1 ? "s" : ""}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Recipients Count */}
|
||||
{uniqueRecipients > 0 && (
|
||||
<div className="flex flex-col gap-1">
|
||||
<h3 className="text-muted-foreground">Recipients</h3>
|
||||
<span className="text-sm">
|
||||
{uniqueRecipients} user{uniqueRecipients !== 1 ? "s" : ""}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Image Variants Section */}
|
||||
@@ -209,18 +130,6 @@ export function BadgeDefinitionDetailRenderer({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Award Address for Reference */}
|
||||
{identifier && (
|
||||
<div className="flex flex-col gap-2 p-4 bg-muted/30 rounded-lg">
|
||||
<h3 className="text-sm font-medium text-muted-foreground">
|
||||
Badge Address (for awarding)
|
||||
</h3>
|
||||
<code className="text-xs font-mono break-all">
|
||||
30009:{event.pubkey}:{identifier}
|
||||
</code>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,61 +7,35 @@ import {
|
||||
getBadgeIdentifier,
|
||||
getBadgeName,
|
||||
getBadgeDescription,
|
||||
getBadgeImageUrl,
|
||||
} from "@/lib/nip58-helpers";
|
||||
import { Award } from "lucide-react";
|
||||
|
||||
/**
|
||||
* Renderer for Kind 30009 - Badge Definition (NIP-58)
|
||||
* Clean feed view with badge image, name, and description
|
||||
* Renderer for Kind 30009 - Badge (NIP-58)
|
||||
* Simple feed view with name and description
|
||||
*/
|
||||
export function BadgeDefinitionRenderer({ event }: BaseEventProps) {
|
||||
const identifier = getBadgeIdentifier(event);
|
||||
const name = getBadgeName(event);
|
||||
const description = getBadgeDescription(event);
|
||||
const imageUrl = getBadgeImageUrl(event);
|
||||
|
||||
// Use name if available, fallback to identifier
|
||||
const displayTitle = name || identifier || "Badge";
|
||||
|
||||
return (
|
||||
<BaseEventContainer event={event}>
|
||||
<div className="flex gap-3">
|
||||
{/* Badge Image */}
|
||||
{imageUrl ? (
|
||||
<img
|
||||
src={imageUrl}
|
||||
alt={displayTitle}
|
||||
className="size-16 rounded-lg object-cover flex-shrink-0"
|
||||
loading="lazy"
|
||||
/>
|
||||
) : (
|
||||
<div className="size-16 rounded-lg bg-muted flex items-center justify-center flex-shrink-0">
|
||||
<Award className="size-8 text-muted-foreground" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<ClickableEventTitle
|
||||
event={event}
|
||||
className="text-base font-semibold text-foreground"
|
||||
>
|
||||
{displayTitle}
|
||||
</ClickableEventTitle>
|
||||
|
||||
{description && (
|
||||
<p className="text-sm text-muted-foreground line-clamp-2">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Badge Info */}
|
||||
<div className="flex flex-col gap-1 flex-1 min-w-0">
|
||||
<ClickableEventTitle
|
||||
event={event}
|
||||
className="text-base font-semibold text-foreground"
|
||||
>
|
||||
{displayTitle}
|
||||
</ClickableEventTitle>
|
||||
|
||||
{description && (
|
||||
<p className="text-sm text-muted-foreground line-clamp-2">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{identifier && (
|
||||
<code className="text-xs text-muted-foreground font-mono truncate">
|
||||
{identifier}
|
||||
</code>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</BaseEventContainer>
|
||||
);
|
||||
|
||||
@@ -202,7 +202,7 @@ const kindRenderers: Record<number, React.ComponentType<BaseEventProps>> = {
|
||||
30005: VideoCurationSetRenderer, // Video Curation Sets (NIP-51)
|
||||
30006: PictureCurationSetRenderer, // Picture Curation Sets (NIP-51)
|
||||
30007: KindMuteSetRenderer, // Kind Mute Sets (NIP-51)
|
||||
30009: BadgeDefinitionRenderer, // Badge Definition (NIP-58)
|
||||
30009: BadgeDefinitionRenderer, // Badge (NIP-58)
|
||||
30015: InterestSetRenderer, // Interest Sets (NIP-51)
|
||||
30023: Kind30023Renderer, // Long-form Article
|
||||
30030: EmojiSetRenderer, // Emoji Sets (NIP-30)
|
||||
@@ -296,7 +296,7 @@ const detailRenderers: Record<
|
||||
30005: VideoCurationSetDetailRenderer, // Video Curation Sets Detail (NIP-51)
|
||||
30006: PictureCurationSetDetailRenderer, // Picture Curation Sets Detail (NIP-51)
|
||||
30007: KindMuteSetDetailRenderer, // Kind Mute Sets Detail (NIP-51)
|
||||
30009: BadgeDefinitionDetailRenderer, // Badge Definition Detail (NIP-58)
|
||||
30009: BadgeDefinitionDetailRenderer, // Badge Detail (NIP-58)
|
||||
30015: InterestSetDetailRenderer, // Interest Sets Detail (NIP-51)
|
||||
30023: Kind30023DetailRenderer, // Long-form Article Detail
|
||||
30030: EmojiSetDetailRenderer, // Emoji Sets Detail (NIP-30)
|
||||
|
||||
Reference in New Issue
Block a user