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)
*/