mirror of
https://github.com/lumina-rocks/lumina.git
synced 2026-06-04 01:31:13 +02:00
feat: Add renderTextWithLinkedTags utility to hyperlink hashtags in text content (#112)
Co-authored-by: highperfocused <highperfocused@pm.me>
This commit is contained in:
@@ -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<KIND20CardProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<div className="break-word overflow-hidden">{text}</div>
|
||||
<div className="break-word overflow-hidden">{renderTextWithLinkedTags(text, tags)}</div>
|
||||
<hr className="my-4" />
|
||||
<div className="space-x-4 flex justify-between items-start">
|
||||
<div className="flex space-x-4">
|
||||
|
||||
@@ -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<NoteCardProps> = ({ pubkey, text, eventId, tags, event,
|
||||
}
|
||||
<br />
|
||||
<div className='break-word overflow-hidden'>
|
||||
{textWithoutImage}
|
||||
{renderTextWithLinkedTags(textWithoutImage, tags)}
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
56
utils/textUtils.tsx
Normal file
56
utils/textUtils.tsx
Normal file
@@ -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(
|
||||
<Link href={`/tag/${hashtag}`} key={`${hashtag}-${matchIndex}`} className="text-blue-500 hover:underline">
|
||||
{fullHashtag}
|
||||
</Link>
|
||||
);
|
||||
} 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;
|
||||
}
|
||||
Reference in New Issue
Block a user