"use client"; import { useEffect } from "react"; import { useSearchParams } from "next/navigation"; import { decodeTextFragment, findAndHighlightText } from "@/lib/text-highlight"; /** * TextHighlighter — processes incoming `?hl=` URLs on page load. * * When a user visits a URL with `?hl=prefix,suffix,length`, this component: * 1. Decodes the text fragment from the query param * 2. Searches the page's content areas for matching text * 3. Wraps the matched text in a with a highlight animation * 4. Scrolls to the highlighted text * 5. Fades the highlight out after a few seconds * * This is rendered once in layout.tsx alongside TextSelectionToolbar. * It only activates when the `hl` search param is present. */ export function TextHighlighter() { const searchParams = useSearchParams(); const hl = searchParams.get("hl"); useEffect(() => { if (!hl) return; const fragment = decodeTextFragment(hl); if (!fragment) return; // Wait for the page content to be fully rendered before searching. // Use a series of attempts in case content loads asynchronously // (e.g., client components hydrating, paginated verse loading, etc.) let attempts = 0; const maxAttempts = 10; const interval = 500; // ms between attempts function tryHighlight() { attempts++; const found = findAndHighlightText(fragment!); if (!found && attempts < maxAttempts) { setTimeout(tryHighlight, interval); } if (found) { // Clean the URL without triggering a navigation — remove the hl param // so the user can share a clean URL after viewing const url = new URL(window.location.href); url.searchParams.delete("hl"); const cleanUrl = url.pathname + (url.search || "") + url.hash; window.history.replaceState({}, "", cleanUrl); } } // First attempt after a short delay to let the DOM settle setTimeout(tryHighlight, 300); }, [hl]); return null; }