feat(app): add nostr social embeds with bech32 NIP-19 decoding
Create NostrEmbed.vue component that renders nostr:note1, nostr:npub1, and nostr:nevent1 URIs as rich embedded cards. Add bech32 decoder utility with NIP-19 TLV support for nevent/nprofile. Extend useNostr with fetchNote() for single-note relay lookups. ChatMessage.vue now detects and strips nostr URIs, rendering them as inline embed cards. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
557f9e6220
commit
771e13aaf2
@@ -75,6 +75,14 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="nostrUris.length > 0" class="mt-3 space-y-1.5" @click.stop>
|
||||
<NostrEmbed
|
||||
v-for="uri in nostrUris"
|
||||
:key="uri"
|
||||
:uri="uri"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="inlineNewsLinks.length > 0" class="mt-3 space-y-1" @click.stop>
|
||||
<NewsCard
|
||||
v-for="(link, i) in inlineNewsLinks"
|
||||
@@ -186,6 +194,7 @@ import SongCard from '@/components/content/SongCard.vue'
|
||||
import PodcastCard from '@/components/content/PodcastCard.vue'
|
||||
import PlaceCard from '@/components/content/PlaceCard.vue'
|
||||
import NewsCard from '@/components/content/NewsCard.vue'
|
||||
import NostrEmbed from '@/components/chat/NostrEmbed.vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -224,6 +233,13 @@ const inlineNewsLinks = computed(() => inlineContent.value.newsLinks ?? [])
|
||||
const inlineWebsitesLinks = computed(() => inlineContent.value.websitesLinks ?? [])
|
||||
const inlineMagazineSections = computed(() => inlineContent.value.magazineSections ?? [])
|
||||
|
||||
const NOSTR_URI_RE = /nostr:(note1[a-z0-9]{58}|npub1[a-z0-9]{58}|nevent1[a-z0-9]+|nprofile1[a-z0-9]+)/g
|
||||
const nostrUris = computed(() => {
|
||||
if (isUser.value) return []
|
||||
const matches = props.message.content.match(NOSTR_URI_RE)
|
||||
return matches ? [...new Set(matches)] : []
|
||||
})
|
||||
|
||||
const isCodeResponse = computed(() =>
|
||||
!isUser.value && props.triggeringQuery.trim().toLowerCase() === '/code'
|
||||
)
|
||||
@@ -261,6 +277,7 @@ const displayText = computed(() => {
|
||||
if (isUser.value) return props.message.content
|
||||
let text = stripContentTags(props.message.content)
|
||||
if (inlineNewsLinks.value.length > 0 || inlineWebsitesLinks.value.length > 0) text = stripMarkdownLinks(text)
|
||||
if (nostrUris.value.length > 0) text = text.replace(NOSTR_URI_RE, '').replace(/\n{3,}/g, '\n\n').trim()
|
||||
return text
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user