diff --git a/src/components/AppHandlerContent.tsx b/src/components/AppHandlerContent.tsx index 0c8d5688..adaa0ca5 100644 --- a/src/components/AppHandlerContent.tsx +++ b/src/components/AppHandlerContent.tsx @@ -1,12 +1,11 @@ import type { NostrEvent, NostrMetadata } from '@nostrify/nostrify'; import { ExternalLink, GitFork, Package } from 'lucide-react'; -import { useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { Link } from 'react-router-dom'; import { Button } from '@/components/ui/button'; import { ExternalFavicon } from '@/components/ExternalFavicon'; import { Skeleton } from '@/components/ui/skeleton'; -import { useLinkPreview } from '@/hooks/useLinkPreview'; import { NostrURI } from '@/lib/NostrURI'; import { cn } from '@/lib/utils'; @@ -79,42 +78,32 @@ export function AppHandlerContent({ event, compact }: AppHandlerContentProps) { const name = metadata.name || getTag(event.tags, 'name') || getTag(event.tags, 'd') || 'Unknown App'; const about = metadata.about; const picture = metadata.picture; + const banner = metadata.banner; const websiteUrl = getWebsiteUrl(event.tags, metadata); const hashtags = getAllTags(event.tags, 't'); const shakespeareUrl = useMemo(() => getShakespeareUrl(event.tags), [event.tags]); - const { data: preview, isLoading: previewLoading } = useLinkPreview(websiteUrl ?? null); - const thumbnailUrl = preview?.thumbnail_url; - - const [imgError, setImgError] = useState(false); - const showThumbnail = thumbnailUrl && !imgError; - if (compact) { return (
- {/* Screenshot hero — only shown while loading or when a thumbnail exists */} - {(previewLoading || showThumbnail) && ( + {/* Banner hero */} + {banner && (
- {previewLoading ? ( - - ) : ( - {name} setImgError(true)} - /> - )} +
)} {/* Content */} -
- {/* App icon — overlaps the screenshot hero like a profile avatar */} -
+
+ {/* App icon — overlaps the banner hero like a profile avatar */} +
{picture ? (
- {/* Screenshot hero — only shown while loading or when a thumbnail exists */} - {(previewLoading || showThumbnail) && ( + {/* Banner hero */} + {banner && (
- {previewLoading ? ( - - ) : ( - {name} setImgError(true)} - /> - )} +
)} {/* Content */} -
- {/* App icon — overlaps the screenshot hero like a profile avatar */} +
+ {/* App icon — overlaps the banner hero like a profile avatar */}
{picture ? ( = { 30030: 'an emoji pack', 30054: 'a podcast episode', 30055: 'a podcast trailer', - 3063: 'an asset', - 30063: 'a release', + 3063: 'a Zapstore asset', + 30063: 'a Zapstore release', 30311: 'a stream', 30315: 'a status', 30617: 'a repository', @@ -117,7 +117,7 @@ const KIND_LABELS: Record = { 31922: 'a calendar event', 31923: 'a calendar event', 31990: 'an app', - 32267: 'an app', + 32267: 'a Zapstore app', 34139: 'a playlist', 34236: 'a divine', 34550: 'a community', @@ -214,11 +214,11 @@ const KIND_SUFFIXES: Partial> = { 34139: 'playlist', }; -/** Postfix that replaces the default pattern (e.g. "Ditto on Zapstore" instead of "Ditto app"). */ +/** Postfix that replaces the default pattern (e.g. "Ditto on Zapstore" instead of "Ditto Zapstore app"). */ const KIND_POSTFIXES: Partial> = { 32267: 'on Zapstore', - 30063: 'release', - 3063: 'asset', + 30063: 'Zapstore release', + 3063: 'Zapstore asset', }; /** Get a display name for an event based on its kind and tags. */ diff --git a/src/components/ExternalContentHeader.tsx b/src/components/ExternalContentHeader.tsx index ea77f36f..a22a70c6 100644 --- a/src/components/ExternalContentHeader.tsx +++ b/src/components/ExternalContentHeader.tsx @@ -1083,9 +1083,9 @@ function hasVideo(tags: string[][]): boolean { /** Fallback labels for well-known kinds not in EXTRA_KINDS. */ const WELL_KNOWN_KIND_LABELS: Record = { 31990: 'App', - 32267: 'App', - 30063: 'Release', - 3063: 'Asset', + 32267: 'Zapstore App', + 30063: 'Zapstore Release', + 3063: 'Zapstore Asset', 15128: 'Nsite', 35128: 'Nsite', 31124: 'Blobbi', diff --git a/src/components/MainLayout.tsx b/src/components/MainLayout.tsx index d1cd5d00..178aafc9 100644 --- a/src/components/MainLayout.tsx +++ b/src/components/MainLayout.tsx @@ -135,7 +135,7 @@ function MainLayoutInner() { being hidden. This depends on MobileTopBar having a transparent / semi-transparent background — a solid top bar would obscure the content underneath. Only active below the sidebar breakpoint. */} -
+
{/* Desktop FAB — sticky within the feed column so it stays diff --git a/src/components/NoteCard.tsx b/src/components/NoteCard.tsx index f6336d6b..a11b5f66 100644 --- a/src/components/NoteCard.tsx +++ b/src/components/NoteCard.tsx @@ -539,11 +539,23 @@ export const NoteCard = memo(function NoteCard({ ) : isNsite ? ( ) : isZapstoreApp ? ( - +
+
+ +
+
) : isZapstoreRelease ? ( - +
+
+ +
+
) : isZapstoreAsset ? ( - +
+
+ +
+
) : isAppHandler ? ( ) : isEncryptedDM ? ( @@ -2014,15 +2026,15 @@ const KIND_HEADER_MAP: Record = { }, 32267: { icon: Package, - action: "published an app", + action: "published a Zapstore app", }, 30063: { icon: Package, - action: "published a release", + action: "published a Zapstore release", }, 3063: { icon: Package, - action: "published an asset", + action: "published a Zapstore asset", }, 31990: { icon: Package, diff --git a/src/components/ZapstoreAppContent.tsx b/src/components/ZapstoreAppContent.tsx index 298dc0d1..4be4da4f 100644 --- a/src/components/ZapstoreAppContent.tsx +++ b/src/components/ZapstoreAppContent.tsx @@ -255,7 +255,7 @@ export function ZapstoreAppContent({ event, compact }: ZapstoreAppContentProps) if (compact) { return ( -
+
{/* Header: icon + name + summary */}
{icon ? ( @@ -326,7 +326,7 @@ export function ZapstoreAppContent({ event, compact }: ZapstoreAppContentProps) // Full detail view return ( -
+
{/* Header: icon + name + summary */}
{icon ? ( diff --git a/src/components/ZapstoreReleaseContent.tsx b/src/components/ZapstoreReleaseContent.tsx index 3557817f..7335b5ce 100644 --- a/src/components/ZapstoreReleaseContent.tsx +++ b/src/components/ZapstoreReleaseContent.tsx @@ -308,7 +308,7 @@ export function ZapstoreReleaseContent({ event, compact }: ZapstoreReleaseConten if (compact) { return ( -
+
{/* Header: icon + app name + version */}
{appIcon ? ( @@ -367,7 +367,7 @@ export function ZapstoreReleaseContent({ event, compact }: ZapstoreReleaseConten // Full detail view return ( -
+
{/* Header */}
{appIcon ? ( @@ -488,7 +488,7 @@ export function ZapstoreReleaseContent({ event, compact }: ZapstoreReleaseConten /** Skeleton loading state for ZapstoreReleaseContent. */ export function ZapstoreReleaseSkeleton() { return ( -
+
@@ -554,7 +554,7 @@ export function ZapstoreAssetContent({ event, compact }: ZapstoreAssetContentPro if (compact) { return ( -
+
@@ -581,7 +581,7 @@ export function ZapstoreAssetContent({ event, compact }: ZapstoreAssetContentPro } return ( -
+
{/* Header */}
@@ -694,7 +694,7 @@ function MetaRow({ label, value }: { label: string; value: React.ReactNode }) { /** Skeleton for ZapstoreAssetContent. */ export function ZapstoreAssetSkeleton() { return ( -
+
diff --git a/src/lib/extraKinds.ts b/src/lib/extraKinds.ts index 2ace7787..3ae01e3a 100644 --- a/src/lib/extraKinds.ts +++ b/src/lib/extraKinds.ts @@ -546,10 +546,10 @@ const KIND_SPECIFIC_LABELS: Record = { 35128: 'nsite', 30008: 'profile badges', 30817: 'repository issue', - 32267: 'app', + 32267: 'Zapstore app', 31990: 'app', - 30063: 'release', - 3063: 'asset', + 30063: 'Zapstore release', + 3063: 'Zapstore asset', }; /** diff --git a/src/pages/NotificationsPage.tsx b/src/pages/NotificationsPage.tsx index 573c17e6..146bfb92 100644 --- a/src/pages/NotificationsPage.tsx +++ b/src/pages/NotificationsPage.tsx @@ -78,15 +78,15 @@ const NOTIFICATION_KIND_NOUNS: Record = { 30030: 'emoji pack', 30054: 'podcast episode', 30055: 'podcast trailer', - 3063: 'asset', - 30063: 'release', + 3063: 'Zapstore asset', + 30063: 'Zapstore release', 30311: 'stream', 30315: 'status', 30617: 'repository', 30817: 'custom NIP', 31922: 'calendar event', 31923: 'calendar event', - 32267: 'app', + 32267: 'Zapstore app', 34139: 'playlist', 34236: 'divine', 34550: 'community', diff --git a/src/pages/PostDetailPage.tsx b/src/pages/PostDetailPage.tsx index e331a6fe..89d186bc 100644 --- a/src/pages/PostDetailPage.tsx +++ b/src/pages/PostDetailPage.tsx @@ -136,9 +136,9 @@ function shellTitleForKind(kind?: number): string { if (kind === BADGE_DEFINITION_KIND) return "Badge Details"; if (kind === BADGE_PROFILE_KIND_NEW || kind === BADGE_PROFILE_KIND_LEGACY) return "Badge Collection"; if (kind === BOOK_REVIEW_KIND) return "Book Review"; - if (kind === 32267) return "App Details"; - if (kind === 30063) return "Release"; - if (kind === 3063) return "Asset"; + if (kind === 32267) return "Zapstore App"; + if (kind === 30063) return "Zapstore Release"; + if (kind === 3063) return "Zapstore Asset"; if (kind === 31990) return "App"; if (kind === 15128 || kind === 35128) return "Nsite"; if (kind === VANISH_KIND) return "Request to Vanish"; @@ -1950,6 +1950,15 @@ function PostDetailContent({ event }: { event: NostrEvent }) { {isAppHandler && ( )} + {isZapstoreApp && ( + + )} + {isZapstoreRelease && ( + + )} + {isZapstoreAsset && ( + + )} {isNsite && ( )} @@ -2064,15 +2073,21 @@ function PostDetailContent({ event }: { event: NostrEvent }) {
) : isZapstoreApp ? ( - +
+ +
) : isZapstoreRelease ? ( - }> - - +
+ }> + + +
) : isZapstoreAsset ? ( - }> - - +
+ }> + + +
) : isAppHandler ? ( ) : isEncryptedDM ? (