fix highlighted text in searched notes

This commit is contained in:
Martti Malmi
2024-02-29 11:14:17 +02:00
parent 04e7d0b54f
commit 95dc979b8d
14 changed files with 104 additions and 108 deletions

View File

@ -41,7 +41,7 @@ export interface NoteProps {
ignoreModeration?: boolean;
onClick?: (e: TaggedNostrEvent) => void;
depth?: number;
searchedValue?: string;
highlightText?: string;
threadChains?: Map<string, Array<NostrEvent>>;
context?: ReactNode;
options?: NotePropsOptions;

View File

@ -40,7 +40,7 @@ export const NoteText = memo(function InnerContent(
{shouldTruncate && showMore && <ToggleShowMore />}
<Text
id={id}
highlighText={props.searchedValue}
highlightText={props.highlightText}
content={body}
tags={ev.tags}
creator={ev.pubkey}

View File

@ -93,6 +93,7 @@ const Timeline = (props: TimelineProps) => {
showLatest={t => onShowLatest(t)}
displayAs={displayAs}
loadMore={() => feed.loadMore()}
highlightText={props.subject.type === "post_keyword" ? props.subject.items[0] : undefined}
/>
</>
);

View File

@ -14,6 +14,7 @@ export interface TimelineFragProps {
noteRenderer?: (ev: TaggedNostrEvent) => ReactNode;
noteOnClick?: (ev: TaggedNostrEvent) => void;
noteContext?: (ev: TaggedNostrEvent) => ReactNode;
highlightText?: string;
}
const options = {
@ -35,6 +36,7 @@ export function TimelineFragment(props: TimelineFragProps) {
context={props.noteContext?.(e)}
options={options}
waitUntilInView={index > 5}
highlightText={props.highlightText}
/>
),
)}

View File

@ -25,6 +25,7 @@ export interface TimelineRendererProps {
noteContext?: (ev: TaggedNostrEvent) => ReactNode;
displayAs?: DisplayAs;
loadMore?: () => void;
highlightText?: string;
}
// filter frags[0].events that have media
@ -105,6 +106,7 @@ export function TimelineRenderer(props: TimelineRendererProps) {
noteRenderer={props.noteRenderer}
noteOnClick={props.noteOnClick}
noteContext={props.noteContext}
highlightText={props.highlightText}
/>
</ErrorBoundary>
));

View File

@ -1,5 +0,0 @@
const HighlightedText = ({ content }: { content: string }) => {
return <strong className="highlighted-text">{content}</strong>;
};
export default HighlightedText;

View File

@ -0,0 +1,23 @@
import React from "react";
const HighlightedText = ({ content, textToHighlight }: { content: string; textToHighlight: string }) => {
const textToHighlightArray = textToHighlight.trim().toLowerCase().split(" ");
const re = new RegExp(`(${textToHighlightArray.join("|")})`, "gi");
const splittedContent = content.split(re);
const fragments = splittedContent.map((part, index) => {
if (textToHighlightArray.includes(part.toLowerCase())) {
return (
<strong key={index} className="highlighted-text">
{part}
</strong>
);
} else {
return part;
}
});
return <>{fragments}</>;
};
export default HighlightedText;

View File

@ -8,12 +8,13 @@ import CashuNuts from "@/Components/Embed/CashuNuts";
import Hashtag from "@/Components/Embed/Hashtag";
import HyperText from "@/Components/Embed/HyperText";
import Invoice from "@/Components/Embed/Invoice";
import { baseImageWidth, GRID_GAP, gridConfigMap, ROW_HEIGHT } from "@/Components/Text/const";
import { useTextTransformer } from "@/Hooks/useTextTransformCache";
import RevealMedia from "../Event/RevealMedia";
import HighlightedText from "../HighlightedText";
import { ProxyImg } from "../ProxyImg";
import { SpotlightMediaModal } from "../Spotlight/SpotlightMedia";
import HighlightedText from "./HighlightedText";
export interface TextProps {
id: string;
@ -26,64 +27,10 @@ export interface TextProps {
depth?: number;
truncate?: number;
className?: string;
highlighText?: string;
highlightText?: string;
onClick?: (e: React.MouseEvent) => void;
}
const baseImageWidth = 910;
const gridConfigMap = new Map<number, number[][]>([
[1, [[4, 3]]],
[
2,
[
[2, 2],
[2, 2],
],
],
[
3,
[
[2, 2],
[2, 1],
[2, 1],
],
],
[
4,
[
[2, 1],
[2, 1],
[2, 1],
[2, 1],
],
],
[
5,
[
[2, 1],
[2, 1],
[2, 1],
[1, 1],
[1, 1],
],
],
[
6,
[
[2, 2],
[1, 1],
[1, 1],
[2, 2],
[1, 1],
[1, 1],
],
],
]);
const ROW_HEIGHT = 140;
const GRID_GAP = 2;
export default function Text({
id,
content,
@ -95,7 +42,7 @@ export default function Text({
disableLinkPreview,
truncate,
className,
highlighText,
highlightText,
onClick,
}: TextProps) {
const [showSpotlight, setShowSpotlight] = useState(false);
@ -104,35 +51,6 @@ export default function Text({
const elements = useTextTransformer(id, content, tags);
const images = elements.filter(a => a.type === "media" && a.mimeType?.startsWith("image")).map(a => a.content);
function renderContentWithHighlightedText(content: string, textToHighlight: string) {
const textToHighlightArray = textToHighlight.trim().toLowerCase().split(" ");
const re = new RegExp(`(${textToHighlightArray.join("|")})`, "gi");
const splittedContent = content.split(re);
const fragments = splittedContent.map(c => {
if (textToHighlightArray.includes(c.toLowerCase())) {
return {
type: "highlighted_text",
content: c,
} as ParsedFragment;
}
return c;
});
return (
<>
{fragments.map((f, index) => {
if (typeof f === "string") {
return f;
}
return <HighlightedText key={index} content={f.content} />;
})}
</>
);
}
const DisableMedia = ({ content }: { content: string }) => (
<a href={content} onClick={e => e.stopPropagation()} target="_blank" rel="noreferrer" className="ext">
{content}
@ -284,7 +202,11 @@ export default function Text({
if (element.type === "text") {
chunks.push(
<div className="text-frag">
{highlighText ? renderContentWithHighlightedText(element.content, highlighText) : element.content}
{highlightText ? (
<HighlightedText content={element.content} textToHighlight={highlightText} />
) : (
element.content
)}
</div>,
);
}

View File

@ -0,0 +1,51 @@
export const baseImageWidth = 910;
export const gridConfigMap = new Map<number, number[][]>([
[1, [[4, 3]]],
[
2,
[
[2, 2],
[2, 2],
],
],
[
3,
[
[2, 2],
[2, 1],
[2, 1],
],
],
[
4,
[
[2, 1],
[2, 1],
[2, 1],
[2, 1],
],
],
[
5,
[
[2, 1],
[2, 1],
[2, 1],
[1, 1],
[1, 1],
],
],
[
6,
[
[2, 2],
[1, 1],
[1, 1],
[2, 2],
[1, 1],
[1, 1],
],
],
]);
export const ROW_HEIGHT = 140;
export const GRID_GAP = 2;