You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
60 lines
1.7 KiB
60 lines
1.7 KiB
import { useFetchEvent } from '@/hooks' |
|
import CitationCard from '@/components/CitationCard' |
|
import { Skeleton } from '@/components/ui/skeleton' |
|
import { nip19 } from 'nostr-tools' |
|
|
|
interface EmbeddedCitationProps { |
|
citationId: string // nevent or note ID |
|
displayType?: 'end' | 'foot' | 'foot-end' | 'inline' | 'quote' | 'prompt-end' | 'prompt-inline' |
|
className?: string |
|
} |
|
|
|
export default function EmbeddedCitation({ citationId, displayType = 'end', className }: EmbeddedCitationProps) { |
|
// Strip all nostr: prefixes if present (handle cases like nostr:nostr:nevent1...) |
|
let cleanId = citationId.trim() |
|
while (cleanId.startsWith('nostr:')) { |
|
cleanId = cleanId.substring(6) // Remove 'nostr:' prefix |
|
} |
|
|
|
// Try to decode as bech32 first |
|
let eventId: string | null = null |
|
|
|
try { |
|
const decoded = nip19.decode(cleanId) |
|
if (decoded.type === 'nevent') { |
|
const data = decoded.data as any |
|
eventId = data.id || cleanId |
|
} else if (decoded.type === 'note') { |
|
eventId = decoded.data as string |
|
} else { |
|
// If it's not a note/nevent, use the original ID |
|
eventId = cleanId |
|
} |
|
} catch { |
|
// If decoding fails, assume it's already a hex ID |
|
eventId = cleanId |
|
} |
|
|
|
const { event, isFetching } = useFetchEvent(eventId || '') |
|
|
|
if (isFetching) { |
|
return ( |
|
<div className={className}> |
|
<Skeleton className="h-24 w-full" /> |
|
</div> |
|
) |
|
} |
|
|
|
if (!event) { |
|
return ( |
|
<div className={className}> |
|
<div className="text-sm text-muted-foreground p-2 border rounded"> |
|
Citation not found: {citationId.slice(0, 20)}... |
|
</div> |
|
</div> |
|
) |
|
} |
|
|
|
return <CitationCard event={event} displayType={displayType} className={className} /> |
|
} |
|
|
|
|