mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-20 02:16:39 +00:00
(feat:highlightSearch) recursively filter the DOM
This commit is contained in:
1 parent
ed2609d3b3
commit
3ce04de161
2 files changed
+79
-28
No files matched your search
@@ -6,7 +6,7 @@ import { getSearchResults } from '../requests/searchAPI'
|
|||||||
import { Result } from '@/types';
|
import { Result } from '@/types';
|
||||||
import MarkdownIt from 'markdown-it';
|
import MarkdownIt from 'markdown-it';
|
||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import { getOS } from '../utils/helper'
|
import { getOS, preprocessSearchResultsToHTML } from '../utils/helper'
|
||||||
const themes = {
|
const themes = {
|
||||||
dark: {
|
dark: {
|
||||||
bg: '#000',
|
bg: '#000',
|
||||||
@@ -291,6 +291,8 @@ export const SearchBar = ({
|
|||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
console.log(results);
|
||||||
|
|
||||||
abortController.abort();
|
abortController.abort();
|
||||||
clearTimeout(debounceTimeout.current ?? undefined);
|
clearTimeout(debounceTimeout.current ?? undefined);
|
||||||
};
|
};
|
||||||
@@ -352,7 +354,7 @@ export const SearchBar = ({
|
|||||||
<Title>{res.title}</Title>
|
<Title>{res.title}</Title>
|
||||||
<Content>
|
<Content>
|
||||||
<Markdown
|
<Markdown
|
||||||
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(md.render((res.text).substring(0, 256) + "...")) }}
|
dangerouslySetInnerHTML={{ __html: preprocessSearchResultsToHTML(res.text,input) }}
|
||||||
/>
|
/>
|
||||||
</Content>
|
</Content>
|
||||||
</ResultWrapper>
|
</ResultWrapper>
|
||||||
|
|||||||
@@ -1,27 +1,76 @@
|
|||||||
|
import MarkdownIt from "markdown-it";
|
||||||
|
import DOMPurify from "dompurify";
|
||||||
export const getOS = () => {
|
export const getOS = () => {
|
||||||
const platform = window.navigator.platform;
|
const platform = window.navigator.platform;
|
||||||
const userAgent = window.navigator.userAgent || window.navigator.vendor;
|
const userAgent = window.navigator.userAgent || window.navigator.vendor;
|
||||||
|
|
||||||
if (/Mac/i.test(platform)) {
|
if (/Mac/i.test(platform)) {
|
||||||
return 'mac';
|
return 'mac';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/Win/i.test(platform)) {
|
if (/Win/i.test(platform)) {
|
||||||
return 'win';
|
return 'win';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/Linux/i.test(platform) && !/Android/i.test(userAgent)) {
|
if (/Linux/i.test(platform) && !/Android/i.test(userAgent)) {
|
||||||
return 'linux';
|
return 'linux';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/Android/i.test(userAgent)) {
|
if (/Android/i.test(userAgent)) {
|
||||||
return 'android';
|
return 'android';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/iPhone|iPad|iPod/i.test(userAgent)) {
|
if (/iPhone|iPad|iPod/i.test(userAgent)) {
|
||||||
return 'ios';
|
return 'ios';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'other';
|
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
|
||||||
|
};
|
||||||
Reference in new issue
Block a user