diff --git a/src/components/HighlightItem.tsx b/src/components/HighlightItem.tsx
index f08e8fd9..c413dd57 100644
--- a/src/components/HighlightItem.tsx
+++ b/src/components/HighlightItem.tsx
@@ -29,16 +29,115 @@ const isImageUrl = (url: string): boolean => {
}
}
-// Component to render comment with links and inline images
+// Helper to render a nostr identifier
+const renderNostrId = (nostrUri: string, index: number): JSX.Element => {
+ try {
+ // Remove nostr: prefix
+ const identifier = nostrUri.replace(/^nostr:/, '')
+ const decoded = nip19.decode(identifier)
+
+ switch (decoded.type) {
+ case 'npub': {
+ const pubkey = decoded.data
+ return (
+ e.stopPropagation()}
+ >
+ @{pubkey.slice(0, 8)}...
+
+ )
+ }
+ case 'nprofile': {
+ const { pubkey } = decoded.data
+ const npub = nip19.npubEncode(pubkey)
+ return (
+ e.stopPropagation()}
+ >
+ @{pubkey.slice(0, 8)}...
+
+ )
+ }
+ case 'naddr': {
+ const { kind, pubkey, identifier } = decoded.data
+ // Check if it's a blog post (kind:30023)
+ if (kind === 30023) {
+ const naddr = nip19.naddrEncode({ kind, pubkey, identifier })
+ return (
+ e.stopPropagation()}
+ >
+ {identifier || 'Article'}
+
+ )
+ }
+ // For other kinds, show shortened identifier
+ return (
+
+ nostr:{identifier.slice(0, 12)}...
+
+ )
+ }
+ case 'note': {
+ const eventId = decoded.data
+ return (
+
+ note:{eventId.slice(0, 12)}...
+
+ )
+ }
+ case 'nevent': {
+ const { id } = decoded.data
+ return (
+
+ event:{id.slice(0, 12)}...
+
+ )
+ }
+ default:
+ // Fallback for unrecognized types
+ return (
+
+ {identifier.slice(0, 20)}...
+
+ )
+ }
+ } catch (error) {
+ // If decoding fails, show shortened identifier
+ const identifier = nostrUri.replace(/^nostr:/, '')
+ return (
+
+ {identifier.slice(0, 20)}...
+
+ )
+ }
+}
+
+// Component to render comment with links, inline images, and nostr identifiers
const CommentContent: React.FC<{ text: string }> = ({ text }) => {
- // URL regex pattern
- const urlPattern = /(https?:\/\/[^\s]+)/g
+ // Pattern to match both http(s) URLs and nostr: URIs
+ const urlPattern = /((?:https?:\/\/|nostr:)[^\s]+)/g
const parts = text.split(urlPattern)
return (
<>
{parts.map((part, index) => {
- if (part.match(urlPattern)) {
+ // Handle nostr: URIs
+ if (part.startsWith('nostr:')) {
+ return renderNostrId(part, index)
+ }
+
+ // Handle http(s) URLs
+ if (part.match(/^https?:\/\//)) {
if (isImageUrl(part)) {
return (
= ({ text }) => {
)
}
}
+
return {part}
})}
>
diff --git a/src/styles/layout/highlights.css b/src/styles/layout/highlights.css
index f341fe89..af0bbad9 100644
--- a/src/styles/layout/highlights.css
+++ b/src/styles/layout/highlights.css
@@ -134,6 +134,7 @@
.highlight-comment-text { flex: 1; min-width: 0; }
.highlight-comment-link { color: var(--color-primary); text-decoration: underline; word-wrap: break-word; overflow-wrap: break-word; }
.highlight-comment-link:hover { opacity: 0.8; }
+.highlight-comment-nostr-id { font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 0.8em; color: var(--color-text-secondary); background: rgba(255, 255, 255, 0.05); padding: 0.125rem 0.375rem; border-radius: 3px; word-wrap: break-word; overflow-wrap: break-word; }
.highlight-comment-image { display: block; max-width: 100%; height: auto; margin-top: 0.5rem; border-radius: 6px; border: 1px solid var(--color-border); }
/* Level-colored comment icons */