From d3a085cf431b8e21f05ade83e31ead7f66c75c73 Mon Sep 17 00:00:00 2001 From: mroxso <24775431+mroxso@users.noreply.github.com> Date: Thu, 22 May 2025 22:00:44 +0200 Subject: [PATCH] feat: Add renderTextWithLinkedTags utility to hyperlink hashtags in text content (#112) Co-authored-by: highperfocused --- components/KIND20Card.tsx | 3 ++- components/NoteCard.tsx | 3 ++- utils/textUtils.tsx | 56 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 utils/textUtils.tsx diff --git a/components/KIND20Card.tsx b/components/KIND20Card.tsx index 5eaaedf..e4971a9 100644 --- a/components/KIND20Card.tsx +++ b/components/KIND20Card.tsx @@ -14,6 +14,7 @@ import ViewCopyButton from "./ViewCopyButton" import type { Event as NostrEvent } from "nostr-tools" import ZapButton from "./ZapButton" import Image from "next/image" +import { renderTextWithLinkedTags } from "@/utils/textUtils" interface KIND20CardProps { pubkey: string @@ -95,7 +96,7 @@ const KIND20Card: React.FC = ({
-
{text}
+
{renderTextWithLinkedTags(text, tags)}

diff --git a/components/NoteCard.tsx b/components/NoteCard.tsx index c182f2a..9399c53 100644 --- a/components/NoteCard.tsx +++ b/components/NoteCard.tsx @@ -31,6 +31,7 @@ import Link from 'next/link'; import ViewCopyButton from './ViewCopyButton'; import { Event as NostrEvent } from "nostr-tools"; import ZapButton from './ZapButton'; +import { renderTextWithLinkedTags } from '@/utils/textUtils'; interface NoteCardProps { pubkey: string; @@ -142,7 +143,7 @@ const NoteCard: React.FC = ({ pubkey, text, eventId, tags, event, }
- {textWithoutImage} + {renderTextWithLinkedTags(textWithoutImage, tags)}

diff --git a/utils/textUtils.tsx b/utils/textUtils.tsx new file mode 100644 index 0000000..99b45fe --- /dev/null +++ b/utils/textUtils.tsx @@ -0,0 +1,56 @@ +import React, { ReactNode } from 'react'; +import Link from 'next/link'; + +/** + * Renders text content with hyperlinked hashtags + * @param content The text content that may contain hashtags + * @param eventTags The tags array from a Nostr event + * @returns An array of text and link elements + */ +export function renderTextWithLinkedTags(content: string, eventTags: string[][]): ReactNode[] { + if (!content) return []; + + // Extract all hashtags from the event tags + const eventHashtags = eventTags + .filter((tag) => tag[0] === "t") + .map((tag) => tag[1].toLowerCase()); + + // Find hashtags in the content with regex + const hashtagRegex = /#(\w+)/g; + let lastIndex = 0; + const result: ReactNode[] = []; + let match; + + while ((match = hashtagRegex.exec(content)) !== null) { + const hashtag = match[1].toLowerCase(); + const fullHashtag = match[0]; // #hashtag + const matchIndex = match.index; + + // Add text before the hashtag + if (matchIndex > lastIndex) { + result.push(content.substring(lastIndex, matchIndex)); + } + + // Check if this hashtag exists in the event tags + if (eventHashtags.includes(hashtag)) { + // Create a link for matching hashtags + result.push( + + {fullHashtag} + + ); + } else { + // Add the hashtag without a link if it's not in the tags + result.push(fullHashtag); + } + + lastIndex = matchIndex + fullHashtag.length; + } + + // Add any remaining text + if (lastIndex < content.length) { + result.push(content.substring(lastIndex)); + } + + return result; +}