text highlight and og image
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
"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 <mark> 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;
|
||||
}
|
||||
Reference in New Issue
Block a user