From 8719c56f3c69aa45e31d27cd72cc89095f244c94 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Jan 2026 19:47:21 +0000 Subject: [PATCH] refactor: Update Zapstore app set renderers with improved UX - ZapstoreAppSetRenderer: Show ALL apps with compact spacing (gap-0.5) like relay lists, removed 5-app limit - ZapstoreAppSetDetailRenderer: Replace raw platform tags with normalized platform icons using detectPlatforms() - Both renderers now provide cleaner, more consistent UI following Grimoire patterns --- .../nostr/kinds/ZapstoreAppRenderer.tsx | 64 +++++--------- .../kinds/ZapstoreAppSetDetailRenderer.tsx | 87 +++++++++++++++---- .../nostr/kinds/ZapstoreAppSetRenderer.tsx | 20 ++--- .../kinds/ZapstoreReleaseDetailRenderer.tsx | 2 + .../nostr/kinds/ZapstoreReleaseRenderer.tsx | 6 +- 5 files changed, 100 insertions(+), 79 deletions(-) diff --git a/src/components/nostr/kinds/ZapstoreAppRenderer.tsx b/src/components/nostr/kinds/ZapstoreAppRenderer.tsx index 5a1aebf..ddb62b2 100644 --- a/src/components/nostr/kinds/ZapstoreAppRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreAppRenderer.tsx @@ -6,11 +6,9 @@ import { import { getAppName, getAppSummary, - getAppIcon, detectPlatforms, } from "@/lib/zapstore-helpers"; import { - Package, Globe, Smartphone, TabletSmartphone, @@ -79,52 +77,34 @@ function PlatformIcon({ platform }: { platform: Platform }) { export function ZapstoreAppRenderer({ event }: BaseEventProps) { const appName = getAppName(event); const summary = getAppSummary(event); - const iconUrl = getAppIcon(event); const platforms = detectPlatforms(event); return ( -
- {/* App Icon */} - {iconUrl ? ( - {appName} - ) : ( -
- -
+
+ {/* App Name */} + + {appName} + + + {/* Summary */} + {summary && ( +

+ {summary} +

)} - {/* App Info */} -
- {/* App Name */} - - {appName} - - - {/* Summary */} - {summary && ( -

- {summary} -

- )} - - {/* Platform Icons */} - {platforms.length > 0 && ( -
- {platforms.map((platform) => ( - - ))} -
- )} -
+ {/* Platform Icons */} + {platforms.length > 0 && ( +
+ {platforms.map((platform) => ( + + ))} +
+ )}
); diff --git a/src/components/nostr/kinds/ZapstoreAppSetDetailRenderer.tsx b/src/components/nostr/kinds/ZapstoreAppSetDetailRenderer.tsx index 866ac17..c1ec42f 100644 --- a/src/components/nostr/kinds/ZapstoreAppSetDetailRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreAppSetDetailRenderer.tsx @@ -5,19 +5,79 @@ import { getAppName, getAppSummary, getAppIcon, - getAppPlatforms, + detectPlatforms, getCurationSetIdentifier, } from "@/lib/zapstore-helpers"; -import { Badge } from "@/components/ui/badge"; +import type { Platform } from "@/lib/zapstore-helpers"; import { useNostrEvent } from "@/hooks/useNostrEvent"; import { useGrimoire } from "@/core/state"; import { UserName } from "../UserName"; -import { Package } from "lucide-react"; +import { + Package, + Globe, + Smartphone, + TabletSmartphone, + Monitor, + Laptop, +} from "lucide-react"; interface ZapstoreAppSetDetailRendererProps { event: NostrEvent; } +/** + * Platform icon component with label + */ +function PlatformIcon({ platform }: { platform: Platform }) { + const iconClass = "size-4 text-muted-foreground"; + + const getPlatformLabel = () => { + switch (platform) { + case "android": + return "Android"; + case "ios": + return "iOS"; + case "web": + return "Web"; + case "macos": + return "macOS"; + case "windows": + return "Windows"; + case "linux": + return "Linux"; + default: + return platform; + } + }; + + const getIcon = () => { + switch (platform) { + case "android": + return ; + case "ios": + return ; + case "web": + return ; + case "macos": + return ; + case "windows": + case "linux": + return ; + default: + return null; + } + }; + + return ( +
+ {getIcon()} + + {getPlatformLabel()} + +
+ ); +} + /** * Expanded app card showing full app details */ @@ -45,7 +105,7 @@ function AppCard({ const appName = getAppName(appEvent); const summary = getAppSummary(appEvent); const iconUrl = getAppIcon(appEvent); - const platforms = getAppPlatforms(appEvent); + const platforms = detectPlatforms(appEvent); const handleClick = () => { addWindow("open", { pointer: address }); @@ -84,23 +144,12 @@ function AppCard({

)} - {/* Platforms */} + {/* Platform Icons */} {platforms.length > 0 && ( -
- {platforms.slice(0, 6).map((platform) => ( - - {platform} - +
+ {platforms.map((platform) => ( + ))} - {platforms.length > 6 && ( - - +{platforms.length - 6} more - - )}
)}
diff --git a/src/components/nostr/kinds/ZapstoreAppSetRenderer.tsx b/src/components/nostr/kinds/ZapstoreAppSetRenderer.tsx index 9f939e3..e358790 100644 --- a/src/components/nostr/kinds/ZapstoreAppSetRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreAppSetRenderer.tsx @@ -45,17 +45,12 @@ function AppItem({ /** * Renderer for Kind 30267 - Zapstore App Curation Set - * Displays collection name and list of apps + * Displays collection name and list of all apps with compact layout */ export function ZapstoreAppSetRenderer({ event }: BaseEventProps) { const setName = getCurationSetName(event); const apps = getAppReferences(event); - // Show max 5 apps in feed view - const MAX_APPS_IN_FEED = 5; - const displayApps = apps.slice(0, MAX_APPS_IN_FEED); - const remainingCount = apps.length - displayApps.length; - return (
@@ -72,17 +67,12 @@ export function ZapstoreAppSetRenderer({ event }: BaseEventProps) { {apps.length} {apps.length === 1 ? "app" : "apps"}

- {/* App List */} - {displayApps.length > 0 && ( -
- {displayApps.map((ref, idx) => ( + {/* App List - Show all apps with compact spacing like relay lists */} + {apps.length > 0 && ( +
+ {apps.map((ref, idx) => ( ))} - {remainingCount > 0 && ( - - +{remainingCount} more app{remainingCount > 1 ? "s" : ""} - - )}
)}
diff --git a/src/components/nostr/kinds/ZapstoreReleaseDetailRenderer.tsx b/src/components/nostr/kinds/ZapstoreReleaseDetailRenderer.tsx index 5b56e7f..fce9701 100644 --- a/src/components/nostr/kinds/ZapstoreReleaseDetailRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreReleaseDetailRenderer.tsx @@ -37,8 +37,10 @@ export function ZapstoreReleaseDetailRenderer({ // Fetch related events const appEvent = useNostrEvent(appPointer || undefined); + // Load file event with release event as context for better relay selection const fileEvent = useNostrEvent( fileEventId ? { id: fileEventId } : undefined, + event, // Pass release event as context to use author's relays ); const appName = appEvent ? getAppName(appEvent) : appPointer?.identifier; diff --git a/src/components/nostr/kinds/ZapstoreReleaseRenderer.tsx b/src/components/nostr/kinds/ZapstoreReleaseRenderer.tsx index 7ac22bb..dc1bfd6 100644 --- a/src/components/nostr/kinds/ZapstoreReleaseRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreReleaseRenderer.tsx @@ -58,14 +58,14 @@ export function ZapstoreReleaseRenderer({ event }: BaseEventProps) { {/* Links */}
- {/* App Link */} + {/* App Link - show app name with icon */} {appName && ( )} @@ -76,7 +76,7 @@ export function ZapstoreReleaseRenderer({ event }: BaseEventProps) { className="flex items-center gap-1.5 text-primary hover:underline" > - Download File + Download )}