feat: add website display and filter non-platform tags

NIP-89 renderer improvements:
- Add getAppWebsite() helper to extract website from content JSON
- Display website URL in both feed and detail renderers with external link
- Filter out non-platform tags (r, t, client, alt, e, p, a) to prevent garbage display
- Remove relay hint display from HandlerRecommendationDetailRenderer
- Clean up unused relayHint parameter

Fixes the 'r r' tag appearing as a platform by properly excluding
common non-platform tags when detecting platform URLs.
This commit is contained in:
Claude
2026-01-05 09:45:59 +00:00
parent b00e9b1915
commit 91d801cbaf
4 changed files with 61 additions and 17 deletions

View File

@@ -5,6 +5,7 @@ import {
getSupportedKinds,
getPlatformUrls,
getHandlerIdentifier,
getAppWebsite,
} from "@/lib/nip89-helpers";
import { KindBadge } from "@/components/KindBadge";
import { Badge } from "@/components/ui/badge";
@@ -16,6 +17,7 @@ import {
Globe,
Smartphone,
TabletSmartphone,
ExternalLink,
} from "lucide-react";
interface ApplicationHandlerDetailRendererProps {
@@ -76,6 +78,7 @@ export function ApplicationHandlerDetailRenderer({
const supportedKinds = getSupportedKinds(event);
const platformUrls = getPlatformUrls(event);
const identifier = getHandlerIdentifier(event);
const website = getAppWebsite(event);
return (
<div className="flex flex-col gap-6 p-6">
@@ -89,6 +92,19 @@ export function ApplicationHandlerDetailRenderer({
<p className="text-muted-foreground text-lg">{description}</p>
)}
{/* Website */}
{website && (
<a
href={website}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 text-primary hover:underline"
>
{website}
<ExternalLink className="size-3" />
</a>
)}
{/* Metadata Grid */}
<div className="grid grid-cols-2 gap-4 text-sm">
{/* Publisher */}

View File

@@ -7,6 +7,7 @@ import {
getAppName,
getSupportedKinds,
getAvailablePlatforms,
getAppWebsite,
} from "@/lib/nip89-helpers";
import { KindBadge } from "@/components/KindBadge";
import { Badge } from "@/components/ui/badge";
@@ -40,6 +41,7 @@ export function ApplicationHandlerRenderer({ event }: BaseEventProps) {
const appName = getAppName(event);
const supportedKinds = getSupportedKinds(event);
const platforms = getAvailablePlatforms(event);
const website = getAppWebsite(event);
// Show max 8 kinds in feed view
const MAX_KINDS_IN_FEED = 8;
@@ -57,6 +59,19 @@ export function ApplicationHandlerRenderer({ event }: BaseEventProps) {
{appName}
</ClickableEventTitle>
{/* Website */}
{website && (
<a
href={website}
target="_blank"
rel="noopener noreferrer"
className="text-xs text-primary hover:underline"
onClick={(e) => e.stopPropagation()}
>
{website}
</a>
)}
{/* Supported Kinds */}
{displayKinds.length > 0 && (
<div className="flex items-center gap-2 flex-wrap">

View File

@@ -45,11 +45,9 @@ function PlatformIcon({ platform }: { platform: string }) {
function HandlerCard({
address,
platform,
relayHint,
}: {
address: { kind: number; pubkey: string; identifier: string };
platform?: string;
relayHint?: string;
}) {
const { addWindow } = useGrimoire();
const handlerEvent = useNostrEvent(address);
@@ -142,19 +140,14 @@ function HandlerCard({
)}
{/* Recommendation Context */}
{(platform || relayHint) && (
{platform && (
<div className="flex flex-col gap-1 pt-2 border-t border-border text-xs text-muted-foreground">
{platform && (
<div>
Recommended for:{" "}
<Badge variant="outline" className="text-[10px] ml-1">
{platform}
</Badge>
</div>
)}
{relayHint && (
<div className="font-mono">Relay hint: {relayHint}</div>
)}
<div>
Recommended for:{" "}
<Badge variant="outline" className="text-[10px] ml-1">
{platform}
</Badge>
</div>
</div>
)}
</div>
@@ -260,7 +253,6 @@ export function HandlerRecommendationDetailRenderer({
key={idx}
address={ref.address}
platform={ref.platform}
relayHint={ref.relayHint}
/>
))}
</div>

View File

@@ -123,14 +123,15 @@ export function getPlatformUrls(event: NostrEvent): Record<string, string> {
}
// Also check for any other platform tags
// Exclude common non-platform tags: d, k, r, t, client, etc.
const excludedTags = ["d", "k", "r", "t", "client", "alt", "e", "p", "a"];
for (const tag of event.tags) {
const tagName = tag[0];
const tagValue = tag[1];
if (
tagValue &&
!knownPlatforms.includes(tagName) &&
tagName !== "d" &&
tagName !== "k"
!excludedTags.includes(tagName)
) {
// Could be a custom platform tag
if (tagValue.includes("://") || tagValue.includes("<bech32>")) {
@@ -149,6 +150,26 @@ export function getAvailablePlatforms(event: NostrEvent): string[] {
return Object.keys(getPlatformUrls(event));
}
/**
* Extract website URL from kind 31990 event content JSON
*/
export function getAppWebsite(event: NostrEvent): string | undefined {
if (event.kind !== 31990 || !event.content) return undefined;
try {
const metadata = JSON.parse(event.content);
if (metadata && typeof metadata === "object") {
const website = metadata.website;
if (website && typeof website === "string") {
return website;
}
}
} catch {
// Invalid JSON
}
return undefined;
}
/**
* Get the d tag identifier from kind 31990 event
*/