Skip to content

Commit 752e625

Browse files
committed
highlight search
1 parent a5f52c9 commit 752e625

5 files changed

Lines changed: 77 additions & 2 deletions

File tree

client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"react-player": "^2.16.0",
8181
"react-toastify": "^10.0.5",
8282
"react-world-flags": "^1.6.0",
83+
"rehype-sanitize": "^6.0.0",
8384
"rooks": "7.14.1",
8485
"screenfull": "^6.0.2",
8586
"tailwind-merge": "1.14.0",
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from "react";
2+
import Markdown from "react-markdown";
3+
import rehypeRaw from "rehype-raw";
4+
import rehypeSanitize, { defaultSchema } from "rehype-sanitize";
5+
6+
import { highlightMd } from "@/lib/utils/highlighted-text";
7+
8+
export function HighlightedMarkdown({ text, query }: { text: string; query: string }) {
9+
const processed = highlightMd(text, query);
10+
const schema = {
11+
...defaultSchema,
12+
tagNames: [...(defaultSchema.tagNames || []), "mark"],
13+
};
14+
console.log(processed, typeof processed);
15+
return (
16+
<Markdown
17+
rehypePlugins={[rehypeRaw, [rehypeSanitize, schema]]}
18+
className="prose"
19+
components={{
20+
mark({ children }) {
21+
return <span className="rounded bg-brand1/50">{children}</span>;
22+
},
23+
}}
24+
>
25+
{processed}
26+
</Markdown>
27+
);
28+
}

client/src/containers/projects/popup.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { cn } from "@/lib/classnames";
77

88
import { useGetProjectsId } from "@/types/generated/project";
99

10-
import { useSyncProject } from "@/app/store";
10+
import { projectSearchAtom, useSyncProject } from "@/app/store";
1111

1212
import { PROJECT_PILLARS } from "@/constants/projects";
1313

@@ -19,6 +19,9 @@ import { Tooltip, TooltipArrow, TooltipContent, TooltipTrigger } from "@/compone
1919
import { LuInfo } from "react-icons/lu";
2020

2121
import { TooltipPortal } from "@radix-ui/react-tooltip";
22+
import { useAtomValue } from "jotai";
23+
24+
import { HighlightedMarkdown } from "@/components/ui/highlighted-markdown";
2225

2326
const ProjectFieldHeader = ({ title, data }: { title: string; data: string | undefined }) => (
2427
<div className="flex items-center">
@@ -40,6 +43,7 @@ const ProjectFieldHeader = ({ title, data }: { title: string; data: string | und
4043

4144
const ProjectPopup = () => {
4245
const [project] = useSyncProject();
46+
const projectSearch = useAtomValue(projectSearchAtom);
4347

4448
const { data } = useGetProjectsId(
4549
project as number,
@@ -112,7 +116,13 @@ const ProjectPopup = () => {
112116
{!!data?.data?.attributes?.highlight && (
113117
<section className="space-y-2.5 py-5">
114118
<ProjectFieldHeader title="Description" data={dataInfo?.data?.attributes?.highlight} />
115-
<Markdown className="prose">{data?.data?.attributes?.highlight}</Markdown>
119+
120+
{projectSearch && (
121+
<HighlightedMarkdown text={data?.data?.attributes?.highlight} query={projectSearch} />
122+
)}
123+
{!projectSearch && (
124+
<Markdown className="text-sm">{data?.data?.attributes?.highlight}</Markdown>
125+
)}
116126
</section>
117127
)}
118128

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
function escapeRegExp(s: string) {
2+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3+
}
4+
5+
export function highlightMd(md: string, query?: string) {
6+
const stripped = md.replaceAll("@@HIGHLIGHT@@", "").replaceAll("@@END@@", "");
7+
8+
if (!query?.trim()) return stripped;
9+
10+
const terms = query.trim().split(/\s+/).map(escapeRegExp);
11+
const re = new RegExp(`(${terms.join("|")})`, "gi");
12+
13+
return stripped.replace(re, "<mark>$1</mark>");
14+
}

client/yarn.lock

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6445,6 +6445,7 @@ __metadata:
64456445
react-player: ^2.16.0
64466446
react-toastify: ^10.0.5
64476447
react-world-flags: ^1.6.0
6448+
rehype-sanitize: ^6.0.0
64486449
rooks: 7.14.1
64496450
screenfull: ^6.0.2
64506451
tailwind-merge: 1.14.0
@@ -9429,6 +9430,17 @@ __metadata:
94299430
languageName: node
94309431
linkType: hard
94319432

9433+
"hast-util-sanitize@npm:^5.0.0":
9434+
version: 5.0.2
9435+
resolution: "hast-util-sanitize@npm:5.0.2"
9436+
dependencies:
9437+
"@types/hast": ^3.0.0
9438+
"@ungap/structured-clone": ^1.0.0
9439+
unist-util-position: ^5.0.0
9440+
checksum: 2ab506b847e0ef799dafabae764893bd6ee43dfdf10e65154436c3ded5210abcc637d8e630354f2efd0aa771cd9de78624e2ed9a82c7054029f2b9e18ca7bb70
9441+
languageName: node
9442+
linkType: hard
9443+
94329444
"hast-util-select@npm:^6.0.0":
94339445
version: 6.0.2
94349446
resolution: "hast-util-select@npm:6.0.2"
@@ -13588,6 +13600,16 @@ __metadata:
1358813600
languageName: node
1358913601
linkType: hard
1359013602

13603+
"rehype-sanitize@npm:^6.0.0":
13604+
version: 6.0.0
13605+
resolution: "rehype-sanitize@npm:6.0.0"
13606+
dependencies:
13607+
"@types/hast": ^3.0.0
13608+
hast-util-sanitize: ^5.0.0
13609+
checksum: 8f1b44323a6012fbfa83ee6bc48163b846398952c60e5ddbd3d2275cb46cec4fb8d98a919ffce1b3322af469c6dcef9a0127bcf0a1d96203a5c193d07cd26742
13610+
languageName: node
13611+
linkType: hard
13612+
1359113613
"rehype-slug@npm:~6.0.0":
1359213614
version: 6.0.0
1359313615
resolution: "rehype-slug@npm:6.0.0"

0 commit comments

Comments
 (0)