diff --git a/src/components/nostr/kinds/ZapstoreAppDetailRenderer.tsx b/src/components/nostr/kinds/ZapstoreAppDetailRenderer.tsx index 7b77aaa..4e08dff 100644 --- a/src/components/nostr/kinds/ZapstoreAppDetailRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreAppDetailRenderer.tsx @@ -4,21 +4,79 @@ import { getAppSummary, getAppIcon, getAppImages, - getAppPlatforms, + detectPlatforms, getAppRepository, getAppLicense, getAppIdentifier, } from "@/lib/zapstore-helpers"; -import { Badge } from "@/components/ui/badge"; +import type { Platform } from "@/lib/zapstore-helpers"; import { UserName } from "../UserName"; import { ExternalLink } from "@/components/ExternalLink"; import { MediaEmbed } from "../MediaEmbed"; -import { Package } from "lucide-react"; +import { + Package, + Globe, + Smartphone, + TabletSmartphone, + Monitor, + Laptop, +} from "lucide-react"; interface ZapstoreAppDetailRendererProps { event: NostrEvent; } +/** + * Platform icon and label component + */ +function PlatformItem({ platform }: { platform: Platform }) { + const iconClass = "size-5"; + + const getPlatformName = () => { + 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()} + {getPlatformName()} +
+ ); +} + /** * Detail renderer for Kind 32267 - Zapstore App Metadata * Shows comprehensive app information including screenshots @@ -31,7 +89,7 @@ export function ZapstoreAppDetailRenderer({ const summary = getAppSummary(event); const iconUrl = getAppIcon(event); const images = getAppImages(event); - const platforms = getAppPlatforms(event); + const platforms = detectPlatforms(event); const repository = getAppRepository(event); const license = getAppLicense(event); const identifier = getAppIdentifier(event); @@ -103,18 +161,10 @@ export function ZapstoreAppDetailRenderer({ {/* Platforms Section */} {platforms.length > 0 && (
-

- Platforms ({platforms.length}) -

+

Available On

{platforms.map((platform) => ( - - {platform} - + ))}
diff --git a/src/components/nostr/kinds/ZapstoreAppRenderer.tsx b/src/components/nostr/kinds/ZapstoreAppRenderer.tsx index 3d7a14d..70fd630 100644 --- a/src/components/nostr/kinds/ZapstoreAppRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreAppRenderer.tsx @@ -7,25 +7,50 @@ import { getAppName, getAppSummary, getAppIcon, - getAppPlatforms, - getAppRepository, - getAppLicense, + detectPlatforms, } from "@/lib/zapstore-helpers"; -import { Badge } from "@/components/ui/badge"; -import { ExternalLink } from "@/components/ExternalLink"; -import { Package } from "lucide-react"; +import { + Package, + Globe, + Smartphone, + TabletSmartphone, + Monitor, + Laptop, +} from "lucide-react"; +import type { Platform } from "@/lib/zapstore-helpers"; + +/** + * Platform icon component + */ +function PlatformIcon({ platform }: { platform: Platform }) { + const iconClass = "size-4 text-muted-foreground"; + + switch (platform) { + case "android": + return ; + case "ios": + return ; + case "web": + return ; + case "macos": + return ; + case "windows": + case "linux": + return ; + default: + return null; + } +} /** * Renderer for Kind 32267 - Zapstore App Metadata - * Displays app name, icon, summary, and platforms in feed + * Displays app name, icon, summary, and platform icons in feed */ export function ZapstoreAppRenderer({ event }: BaseEventProps) { const appName = getAppName(event); const summary = getAppSummary(event); const iconUrl = getAppIcon(event); - const platforms = getAppPlatforms(event); - const repository = getAppRepository(event); - const license = getAppLicense(event); + const platforms = detectPlatforms(event); return ( @@ -61,41 +86,13 @@ export function ZapstoreAppRenderer({ event }: BaseEventProps) {

)} - {/* Platforms & License */} -
- {platforms.length > 0 && ( - <> - {platforms.slice(0, 4).map((platform) => ( - - {platform} - - ))} - {platforms.length > 4 && ( - - +{platforms.length - 4} more - - )} - - )} - {license && ( - - {license} - - )} -
- - {/* Repository Link */} - {repository && ( - - {repository} - + {/* Platform Icons */} + {platforms.length > 0 && ( +
+ {platforms.map((platform) => ( + + ))} +
)} diff --git a/src/lib/zapstore-helpers.ts b/src/lib/zapstore-helpers.ts index 6c5398b..aa3f2b1 100644 --- a/src/lib/zapstore-helpers.ts +++ b/src/lib/zapstore-helpers.ts @@ -101,6 +101,53 @@ export function getAppPlatforms(event: NostrEvent): string[] { return getTagValues(event, "f"); } +/** + * Platform names for display + */ +export type Platform = + | "android" + | "ios" + | "web" + | "linux" + | "windows" + | "macos"; + +/** + * Detect unique platforms from f tags + * Normalizes architecture-specific tags (e.g., "android-arm64-v8a" → "android") + */ +export function detectPlatforms(event: NostrEvent): Platform[] { + if (event.kind !== 32267 && event.kind !== 1063) return []; + + const fTags = getTagValues(event, "f"); + const platformSet = new Set(); + + for (const tag of fTags) { + const lower = tag.toLowerCase(); + + if (lower.startsWith("android")) { + platformSet.add("android"); + } else if (lower.startsWith("ios") || lower.includes("iphone")) { + platformSet.add("ios"); + } else if (lower === "web" || lower.includes("web")) { + platformSet.add("web"); + } else if (lower.includes("linux")) { + platformSet.add("linux"); + } else if (lower.includes("windows") || lower.includes("win")) { + platformSet.add("windows"); + } else if ( + lower.includes("macos") || + lower.includes("mac") || + lower.includes("darwin") + ) { + platformSet.add("macos"); + } + } + + // Sort for consistent order + return Array.from(platformSet).sort(); +} + /** * Get release artifact references from kind 32267 a tags (usually kind 30063) */