From 2ad3fe1e4aca10f6bc14c85b683899594eab5d1a Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 24 Mar 2026 22:05:25 -0500 Subject: [PATCH 1/4] Render nsite events with rich link preview from OEmbed data --- src/components/NsiteCard.tsx | 154 +++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 50 deletions(-) diff --git a/src/components/NsiteCard.tsx b/src/components/NsiteCard.tsx index 53dc5a9d..f21a2f3e 100644 --- a/src/components/NsiteCard.tsx +++ b/src/components/NsiteCard.tsx @@ -1,14 +1,18 @@ import type { NostrEvent } from "@nostrify/nostrify"; -import { ExternalLink, FileText, Globe } from "lucide-react"; +import { ExternalLink, FileText, Globe, Server } from "lucide-react"; import { nip19 } from "nostr-tools"; +import { ExternalFavicon } from "@/components/ExternalFavicon"; +import { Skeleton } from "@/components/ui/skeleton"; +import { useLinkPreview } from "@/hooks/useLinkPreview"; +import { cn } from "@/lib/utils"; + interface NsiteCardProps { event: NostrEvent; } /** Encode a 32-byte hex pubkey as a base36 string (50 chars, zero-padded). */ function hexToBase36(hex: string): string { - // Process the hex string in chunks to build a BigInt let n = 0n; for (let i = 0; i < hex.length; i++) { n = n * 16n + BigInt(parseInt(hex[i], 16)); @@ -22,17 +26,24 @@ function getNsiteUrl(event: NostrEvent): string { const dTag = event.tags.find(([n]) => n === "d")?.[1]; if (event.kind === 35128 && dTag) { - // Named site: .nsite.lol const pubkeyB36 = hexToBase36(event.pubkey); return `https://${pubkeyB36}${dTag}.nsite.lol`; } - // Root site (kind 15128): .nsite.lol const npub = nip19.npubEncode(event.pubkey); return `https://${npub}.nsite.lol`; } -/** Renders an nsite deployment card for kind 15128 (root site) or 35128 (named site). */ +/** Extract display domain from a URL. */ +function displayDomain(url: string): string { + try { + return new URL(url).hostname.replace(/^www\./, ""); + } catch { + return url; + } +} + +/** Renders an nsite deployment card with a rich link preview. */ export function NsiteCard({ event }: NsiteCardProps) { const title = event.tags.find(([n]) => n === "title")?.[1]; const description = event.tags.find(([n]) => n === "description")?.[1]; @@ -45,29 +56,65 @@ export function NsiteCard({ event }: NsiteCardProps) { const siteUrl = getNsiteUrl(event); const displayName = title || (isNamed ? dTag : "Root Site"); + const { data: preview, isLoading } = useLinkPreview(siteUrl); + const image = preview?.thumbnail_url; + const previewTitle = preview?.title; + const domain = preview?.provider_name || displayDomain(siteUrl); + + if (isLoading) { + return ; + } + return ( -
-
- {/* Site name + type badge */} -
- - - {displayName} - - + e.stopPropagation()} + > + {/* Link preview thumbnail */} + {image && ( +
+ { + (e.currentTarget.parentElement as HTMLElement).style.display = "none"; + }} + /> +
+ )} + +
+ {/* Domain bar with favicon */} +
+ + {domain} + {isNamed ? "Named Site" : "Root Site"}
- {/* Description */} - {description && ( -

- {description} + {/* Title — use OEmbed title if available, fall back to event title/d-tag */} +

+ {previewTitle || displayName} +

+ + {/* Description — prefer event description (it's curated), fall back to OEmbed author */} + {(description || preview?.author_name) && ( +

+ {description || preview?.author_name}

)} - {/* File count + server info */} -
+ + ); +} - {/* Action buttons */} -
- - {sourceUrl && ( - - )} -
+function NsiteCardSkeleton() { + return ( +
+ +
+ + + +
); From 973e62115d314777272af28ea0929af89c994138 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 24 Mar 2026 22:09:20 -0500 Subject: [PATCH 2/4] Show 'nsite.lol' instead of the full gateway URL in the domain bar --- src/components/NsiteCard.tsx | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/components/NsiteCard.tsx b/src/components/NsiteCard.tsx index f21a2f3e..3d96ebe4 100644 --- a/src/components/NsiteCard.tsx +++ b/src/components/NsiteCard.tsx @@ -34,15 +34,6 @@ function getNsiteUrl(event: NostrEvent): string { return `https://${npub}.nsite.lol`; } -/** Extract display domain from a URL. */ -function displayDomain(url: string): string { - try { - return new URL(url).hostname.replace(/^www\./, ""); - } catch { - return url; - } -} - /** Renders an nsite deployment card with a rich link preview. */ export function NsiteCard({ event }: NsiteCardProps) { const title = event.tags.find(([n]) => n === "title")?.[1]; @@ -59,7 +50,7 @@ export function NsiteCard({ event }: NsiteCardProps) { const { data: preview, isLoading } = useLinkPreview(siteUrl); const image = preview?.thumbnail_url; const previewTitle = preview?.title; - const domain = preview?.provider_name || displayDomain(siteUrl); + const domain = preview?.provider_name || "nsite.lol"; if (isLoading) { return ; From a8fed56929c6321f3f2913d839f33ca743346c0f Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 24 Mar 2026 22:11:13 -0500 Subject: [PATCH 3/4] Always display 'nsite.lol' as domain, ignore OEmbed provider_name --- src/components/NsiteCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/NsiteCard.tsx b/src/components/NsiteCard.tsx index 3d96ebe4..5068ea2d 100644 --- a/src/components/NsiteCard.tsx +++ b/src/components/NsiteCard.tsx @@ -50,7 +50,7 @@ export function NsiteCard({ event }: NsiteCardProps) { const { data: preview, isLoading } = useLinkPreview(siteUrl); const image = preview?.thumbnail_url; const previewTitle = preview?.title; - const domain = preview?.provider_name || "nsite.lol"; + const domain = "nsite.lol"; if (isLoading) { return ; From 0459590d24e494c3b547e779f2cb69ce5df29193 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 24 Mar 2026 22:12:35 -0500 Subject: [PATCH 4/4] Replace domain bar with favicon next to the title --- src/components/NsiteCard.tsx | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/components/NsiteCard.tsx b/src/components/NsiteCard.tsx index 5068ea2d..7454b508 100644 --- a/src/components/NsiteCard.tsx +++ b/src/components/NsiteCard.tsx @@ -50,7 +50,6 @@ export function NsiteCard({ event }: NsiteCardProps) { const { data: preview, isLoading } = useLinkPreview(siteUrl); const image = preview?.thumbnail_url; const previewTitle = preview?.title; - const domain = "nsite.lol"; if (isLoading) { return ; @@ -83,20 +82,14 @@ export function NsiteCard({ event }: NsiteCardProps) { )}
- {/* Domain bar with favicon */} -
- - {domain} - - {isNamed ? "Named Site" : "Root Site"} - + {/* Title with favicon */} +
+ +

+ {previewTitle || displayName} +

- {/* Title — use OEmbed title if available, fall back to event title/d-tag */} -

- {previewTitle || displayName} -

- {/* Description — prefer event description (it's curated), fall back to OEmbed author */} {(description || preview?.author_name) && (