diff --git a/package.json b/package.json index 1232a25ab..fc018884f 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "license": "MIT", "devDependencies": { "@crowdin/cli": "^3.7.10", + "@types/mark.js": "^8.11.8", "@types/node": "^18.7.5", "@types/streamsaver": "^2.0.1", "@vitejs/plugin-legacy": "^2.0.1", @@ -63,6 +64,7 @@ "flv.js": "^1.6.2", "hls.js": "^1.2.1", "lightgallery": "^2.5.0", + "mark.js": "^8.11.1", "mitt": "^3.0.0", "rehype-katex": "^6.0.3", "rehype-raw": "^6.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ea9429337..ded07427b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ dependencies: lightgallery: specifier: ^2.5.0 version: 2.5.0 + mark.js: + specifier: ^8.11.1 + version: 8.11.1 mitt: specifier: ^3.0.0 version: 3.0.0 @@ -94,6 +97,9 @@ devDependencies: '@crowdin/cli': specifier: ^3.7.10 version: 3.7.10 + '@types/mark.js': + specifier: ^8.11.8 + version: 8.11.8 '@types/node': specifier: ^18.7.5 version: 18.7.5 @@ -656,6 +662,12 @@ packages: '@types/unist': 2.0.6 dev: false + /@types/jquery@3.5.16: + resolution: {integrity: sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==} + dependencies: + '@types/sizzle': 2.3.3 + dev: true + /@types/katex@0.14.0: resolution: {integrity: sha512-+2FW2CcT0K3P+JMR8YG846bmDwplKUTsWgT2ENwdQ1UdVfRk3GQrh6Mi4sTopy30gI8Uau5CEqHTDZ6YvWIUPA==} dev: false @@ -664,6 +676,12 @@ packages: resolution: {integrity: sha512-hz+S3nV6Mym5xPbT9fnO8dDhBFQguMYpY0Ipxv06JMi1ORgnEM4M1ymWDUhUNer3ElLmT583opRo4RzxKmh9jw==} dev: false + /@types/mark.js@8.11.8: + resolution: {integrity: sha512-BoWCd9ydi1hZxDfu/lF0v1hHMsNUjuxZEDJsdHlmm6GlKk4qxlLya7D3FS81QmabwFbYPpoDOh9603JESUkHbA==} + dependencies: + '@types/jquery': 3.5.16 + dev: true + /@types/mdast@3.0.10: resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==} dependencies: @@ -686,6 +704,10 @@ packages: resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==} dev: false + /@types/sizzle@2.3.3: + resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==} + dev: true + /@types/streamsaver@2.0.1: resolution: {integrity: sha512-I49NtT8w6syBI3Zg3ixCyygTHoTVMY0z2TMRcTgccdIsVd2MwlKk7ITLHLsJtgchUHcOd7QEARG9h0ifcA6l2Q==} dev: true @@ -1792,6 +1814,10 @@ packages: sourcemap-codec: 1.4.8 dev: true + /mark.js@8.11.1: + resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + dev: false + /markdown-table@3.0.2: resolution: {integrity: sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==} dev: false diff --git a/src/pages/home/folder/Search.tsx b/src/pages/home/folder/Search.tsx index cbef2c110..43a0294aa 100644 --- a/src/pages/home/folder/Search.tsx +++ b/src/pages/home/folder/Search.tsx @@ -13,9 +13,19 @@ import { ModalOverlay, Text, VStack, + hope, } from "@hope-ui/solid" import { BsSearch } from "solid-icons/bs" -import { createSignal, For, Match, onCleanup, Show, Switch } from "solid-js" +import { + createSignal, + For, + Match, + onCleanup, + onMount, + Show, + Switch, +} from "solid-js" +import Mark from "mark.js" import { FullLoading, LinkWithBase, @@ -36,7 +46,85 @@ import { import { isMac } from "~/utils/compatibility" import { getIconByObj } from "~/utils/icon" -const SearchResult = (props: SearchNode) => { +// class MarkKeywords { +// root +// rootHTML +// style + +// /** +// * Keyword highlight +// * @param root Find root elements +// * @param style The default background is highly bright yellow +// */ +// constructor(config: { root: Element | null; style?: string }) { +// if (!config.root) return +// this.root = config.root +// this.rootHTML = config.root.innerHTML +// this.style = config.style ?? "background-color: #FF0" +// } + +// /** mark keyword */ +// light(keyword: string) { +// const handler = (root: any) => { +// if ( +// root.nodeName === "#text" && +// root.parentNode.childNodes.length === 1 +// ) { +// root.parentNode.innerHTML = root.parentNode.innerHTML.replace( +// new RegExp(keyword, "g"), +// `${keyword}`, +// ) +// } else { +// for (const node of root.childNodes) { +// handler(node) +// } +// } +// } + +// if (!this.root) return + +// // reset HTML +// this.root.innerHTML = this.rootHTML! + +// if (!keyword) return +// handler(this.root) +// } +// } + +function NodeName(props: { keywords: string; name: string }) { + let ref: HTMLSpanElement + onMount(() => { + // const highlighter = new MarkKeywords({ + // root: ref!, + // style: `background-color: var(--hope-colors-info5); border-radius: var(--hope-radii-md); margin: 0 1px; padding: 0 1px;`, + // }) + // highlighter.light(props.keywords) + const mark = new Mark(ref!) + mark.mark(props.keywords, { + separateWordSearch: true, + diacritics: true, + }) + }) + return ( + + {props.name} + + ) +} + +const SearchResult = (props: { node: SearchNode; keywords: string }) => { const { setPathAs } = usePath() return ( { cursor="pointer" px="$2" as={LinkWithBase} - href={props.path} + href={props.node.path} encode onMouseEnter={() => { - setPathAs(props.path, props.is_dir) + setPathAs(props.node.path, props.node.is_dir) }} > @@ -68,10 +156,10 @@ const SearchResult = (props: SearchNode) => { wordBreak: "break-all", }} > - {props.name} - 0 || !props.is_dir}> + + 0 || !props.node.is_dir}> - {getFileSize(props.size)} + {getFileSize(props.node.size)} @@ -82,7 +170,7 @@ const SearchResult = (props: SearchNode) => { wordBreak: "break-all", }} > - {props.parent} + {props.node.parent} @@ -213,7 +301,7 @@ const Search = () => { - {(item) => } + {(item) => } 0}>