diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index e88bdafd..16072643 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -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 = ({ {res.title} diff --git a/extensions/react-widget/src/utils/helper.ts b/extensions/react-widget/src/utils/helper.ts index 39c720e2..eb2f836f 100644 --- a/extensions/react-widget/src/utils/helper.ts +++ b/extensions/react-widget/src/utils/helper.ts @@ -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'; - }; - \ No newline at end of file + 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 + const highlightedHTML = splitted + .map((part) => + regex.test(part) + ? `${part}` + : part + ) + .join(""); + if (element instanceof HTMLElement) { + element.innerHTML = highlightedHTML; + } + return element +}; \ No newline at end of file