The rendered Markdown preview had no way to search: the Electron desktop shell implements no find-in-page at all, and CodeMirror's search panel only exists in edit mode, so Ctrl/Cmd+F in the preview was a dead shortcut (web browsers happen to find plain-DOM text natively, but desktop does not). Adds a compact find bar for the rendered preview (Ctrl/Cmd+F or the search button): case-insensitive match highlighting with a live count, Enter / Shift+Enter and arrow buttons to navigate matches, Esc to close. Matches are wrapped in <mark> elements and re-applied via MutationObserver when the markdown renderer re-morphs the container (theme/content changes); svg (mermaid) and script/style text is skipped. The pure match-range logic is unit-tested. Fixes #2401
24 lines
784 B
TypeScript
24 lines
784 B
TypeScript
/**
|
|
* Case-insensitive substring match ranges over a single text string, using
|
|
* the same non-overlapping `String.prototype.indexOf` scan semantics as
|
|
* standard find-in-page (e.g. "aaa" in "aaaa" yields a single [0,3]).
|
|
*/
|
|
export const findMatchRanges = (text: string, query: string): Array<{ start: number; end: number }> => {
|
|
const normalized = query.trim().toLowerCase();
|
|
const ranges: Array<{ start: number; end: number }> = [];
|
|
if (!normalized) {
|
|
return ranges;
|
|
}
|
|
const lower = text.toLowerCase();
|
|
let cursor = 0;
|
|
while (true) {
|
|
const index = lower.indexOf(normalized, cursor);
|
|
if (index === -1) {
|
|
break;
|
|
}
|
|
ranges.push({ start: index, end: index + normalized.length });
|
|
cursor = index + normalized.length;
|
|
}
|
|
return ranges;
|
|
};
|