Openstatus www.openstatus.dev
at main 45 lines 1.2 kB view raw
1"use client"; 2 3import { useSearchParams } from "next/navigation"; 4import { useEffect, useRef } from "react"; 5 6function highlight(root: HTMLElement, query: string) { 7 if (!query) return; 8 9 const regex = new RegExp(`(${query})`, "gi"); 10 const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null); 11 12 const textNodes: Text[] = []; 13 let node = walker.nextNode(); 14 15 while (node) { 16 if (node instanceof Text) { 17 textNodes.push(node); 18 } 19 node = walker.nextNode(); 20 } 21 22 for (const textNode of textNodes) { 23 const nodeValue = textNode.nodeValue; 24 if (!nodeValue || !regex.test(nodeValue)) continue; 25 26 const span = document.createElement("span"); 27 span.innerHTML = nodeValue.replace(regex, "<mark>$1</mark>"); 28 29 textNode.parentNode?.replaceChild(span, textNode); 30 } 31} 32 33export function HighlightText({ children }: { children: React.ReactNode }) { 34 const ref = useRef<HTMLDivElement>(null); 35 const searchParams = useSearchParams(); 36 const q = searchParams.get("q"); 37 38 useEffect(() => { 39 if (ref.current && q) { 40 highlight(ref.current, q); 41 } 42 }, [q]); 43 44 return <div ref={ref}>{children}</div>; 45}