{app.name}
{pinned && Pinned} {hidden && ( Hidden )} {app.isExternal && ( External )}{app.description}
import type { ResolvedApp } from '../types'; interface AppCardProps { app: ResolvedApp; catalogueUrl: string; hidden: boolean; pinned: boolean; first: boolean; last: boolean; onHide: () => void; onMove: (direction: -1 | 1) => void; onPin: () => void; contextualUrl: (entryUrl: string, catalogueUrl: string) => string; } function RequirementSummary({ app }: { app: ResolvedApp }) { if (!app.requirements) return null; const requirements = [ app.requirements.secureContext && 'Secure context', app.requirements.workers && 'Web workers', app.requirements.indexedDb && 'IndexedDB', app.requirements.crossOriginIsolated && 'Cross-origin isolation', ].filter(Boolean); if (requirements.length === 0) return null; return
Needs {requirements.join(' · ')}
; } function PrivacySummary({ app }: { app: ResolvedApp }) { if (!app.privacy) return (External destination · review its privacy terms
); if (app.privacy.label) return{app.privacy.label}
; const processing = { local: 'Local processing', remote: 'Remote processing', mixed: 'Local and remote capabilities', }[app.privacy.processing]; return ({processing} ·{' '} {app.privacy.fileUploads ? 'file/data transmission declared' : 'no file uploads declared'}{' '} · {app.privacy.telemetry ? 'telemetry declared' : 'no telemetry declared'}
); } export function AppCard({ app, catalogueUrl, hidden, pinned, first, last, onHide, onMove, onPin, contextualUrl, }: AppCardProps) { const launchUrl = app.isExternal ? app.entryUrl : contextualUrl(app.entryUrl, catalogueUrl); const target = app.launchModes.includes('navigate') ? undefined : '_blank'; return ({app.description}