(feat:highlightSearch) recursively filter the DOM

This commit is contained in:
ManishMadan2882
2024-12-06 03:31:59 +05:30
parent ed2609d3b3
commit 3ce04de161
2 changed files with 79 additions and 28 deletions

View File

@@ -6,7 +6,7 @@ import { getSearchResults } from '../requests/searchAPI'
import { Result } from '@/types';
import MarkdownIt from 'markdown-it';
import DOMPurify from 'dompurify';
import { getOS } from '../utils/helper'
import { getOS, preprocessSearchResultsToHTML } from '../utils/helper'
const themes = {
dark: {
bg: '#000',
@@ -291,6 +291,8 @@ export const SearchBar = ({
}, 500);
return () => {
console.log(results);
abortController.abort();
clearTimeout(debounceTimeout.current ?? undefined);
};
@@ -352,7 +354,7 @@ export const SearchBar = ({
<Title>{res.title}</Title>
<Content>
<Markdown
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(md.render((res.text).substring(0, 256) + "...")) }}
dangerouslySetInnerHTML={{ __html: preprocessSearchResultsToHTML(res.text,input) }}
/>
</Content>
</ResultWrapper>

View File

@@ -1,27 +1,76 @@
import MarkdownIt from "markdown-it";
import DOMPurify from "dompurify";
export const getOS = () => {
const platform = window.navigator.platform;
const userAgent = window.navigator.userAgent || window.navigator.vendor;
if (/Mac/i.test(platform)) {
return 'mac';
}
if (/Win/i.test(platform)) {
return 'win';
}
if (/Linux/i.test(platform) && !/Android/i.test(userAgent)) {
return 'linux';
}
if (/Android/i.test(userAgent)) {
return 'android';
}
if (/iPhone|iPad|iPod/i.test(userAgent)) {
return 'ios';
}
return 'other';
};
const platform = window.navigator.platform;
const userAgent = window.navigator.userAgent || window.navigator.vendor;
if (/Mac/i.test(platform)) {
return 'mac';
}
if (/Win/i.test(platform)) {
return 'win';
}
if (/Linux/i.test(platform) && !/Android/i.test(userAgent)) {
return 'linux';
}
if (/Android/i.test(userAgent)) {
return 'android';
}
if (/iPhone|iPad|iPod/i.test(userAgent)) {
return 'ios';
}
return 'other';
};
export const preprocessSearchResultsToHTML = (text: string, keyword: string) => {
const md = new MarkdownIt();
const htmlString = md.render(text);
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, "text/html");
const filteredResults = document.createElement("div")
recursiveFilter(doc.body, keyword, filteredResults)
console.log(filteredResults)
return DOMPurify.sanitize(filteredResults)
}
const recursiveFilter = (element: Node, keyword: string, parent: Node | null) => {
const content = element.textContent?.toLowerCase() ?? null;
const childNodes = element.childNodes
childNodes.forEach((child) => {
if (recursiveFilter(child, keyword, element))
parent?.appendChild(highlightFilteredContent(child, keyword))
})
if (content && content.includes(keyword.toLowerCase())) {
return true
}
return false
}
const highlightFilteredContent = (element: Node, keyword: string) => {
if (!element.textContent || !keyword.trim()) return element;
const regex = new RegExp(`(${keyword})`, 'gi');
const splitted = element.textContent.split(regex);
console.log(splitted);
// Create a new HTML string with the keyword wrapped in a <span>
const highlightedHTML = splitted
.map((part) =>
regex.test(part)
? `<span style="color: yellow;">${part}</span>`
: part
)
.join("");
if (element instanceof HTMLElement) {
element.innerHTML = highlightedHTML;
}
return element
};