From 79ec8030cc234e926802c4c0dcf8eddeffe4b783 Mon Sep 17 00:00:00 2001 From: "saica.go" Date: Wed, 24 Jan 2024 12:28:16 +0800 Subject: [PATCH] feat: implement post search using Pagefind (#12) --- astro.config.mjs | 3 + package.json | 6 +- pnpm-lock.yaml | 174 +++++++++++++++++++++++------ src/components/GlobalStyles.astro | 10 ++ src/components/Navbar.astro | 41 ++++--- src/components/SearchPanel.vue | 100 +++++++++++++++++ src/components/misc/Markdown.astro | 2 +- src/layouts/Layout.astro | 21 ++-- src/pages/posts/[...slug].astro | 1 + 9 files changed, 297 insertions(+), 61 deletions(-) create mode 100644 src/components/SearchPanel.vue diff --git a/astro.config.mjs b/astro.config.mjs index aa974c1..4676e10 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -9,6 +9,7 @@ import rehypeKatex from "rehype-katex" import rehypeSlug from "rehype-slug" import remarkMath from "remark-math" import { remarkReadingTime } from "./src/plugins/remark-reading-time.mjs" +import vue from "@astrojs/vue" const oklchToHex = (str) => { const DEFAULT_HUE = 250 @@ -37,6 +38,7 @@ export default defineConfig({ Compress({ Image: false, }), + vue() ], markdown: { remarkPlugins: [remarkMath, remarkReadingTime], @@ -55,6 +57,7 @@ export default defineConfig({ tagName: "span", properties: { className: ["anchor-icon"], + 'data-pagefind-ignore': true, }, children: [ { diff --git a/package.json b/package.json index a6c8984..40393eb 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "astro dev", "start": "astro dev", - "build": "astro build", + "build": "astro build && pagefind --site dist", "preview": "astro preview", "astro": "astro", "new-post": "node scripts/new-post.js", @@ -23,6 +23,7 @@ "colorjs.io": "^0.4.5", "mdast-util-to-string": "^4.0.0", "overlayscrollbars": "^2.4.6", + "pagefind": "^1.0.4", "reading-time": "^1.5.0", "rehype-autolink-headings": "^7.1.0", "rehype-katex": "^7.0.0", @@ -31,7 +32,8 @@ "sharp": "^0.32.6", "tailwindcss": "^3.3.7", "typescript": "^5.2.2", - "valine": "^1.5.1" + "valine": "^1.5.1", + "vue": "^3.4.15" }, "devDependencies": { "@astrojs/ts-plugin": "^1.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a4ad939..4618e03 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ dependencies: version: 5.1.0(astro@4.1.1)(tailwindcss@3.3.7) '@astrojs/vue': specifier: ^4.0.8 - version: 4.0.8(@babel/core@7.23.6)(astro@4.1.1)(vite@5.0.10)(vue@3.3.12) + version: 4.0.8(@babel/core@7.23.6)(astro@4.1.1)(vite@5.0.10)(vue@3.4.15) '@fontsource-variable/jetbrains-mono': specifier: ^5.0.19 version: 5.0.19 @@ -35,6 +35,9 @@ dependencies: overlayscrollbars: specifier: ^2.4.6 version: 2.4.6 + pagefind: + specifier: ^1.0.4 + version: 1.0.4 reading-time: specifier: ^1.5.0 version: 1.5.0 @@ -62,6 +65,9 @@ dependencies: valine: specifier: ^1.5.1 version: 1.5.1 + vue: + specifier: ^3.4.15 + version: 3.4.15(typescript@5.3.3) devDependencies: '@astrojs/ts-plugin': @@ -250,19 +256,19 @@ packages: vscode-languageserver-textdocument: 1.0.11 dev: true - /@astrojs/vue@4.0.8(@babel/core@7.23.6)(astro@4.1.1)(vite@5.0.10)(vue@3.3.12): + /@astrojs/vue@4.0.8(@babel/core@7.23.6)(astro@4.1.1)(vite@5.0.10)(vue@3.4.15): resolution: {integrity: sha512-RnNA4wFy4HvQxU4vswH3c6sa7Br1F/JVzWdQvHYLP4CEe5OZ6yhEqxAUUo3LDkF+sNn23XznFLOPqZak6ziBwg==} engines: {node: '>=18.14.1'} peerDependencies: astro: ^4.0.0 vue: ^3.2.30 dependencies: - '@vitejs/plugin-vue': 4.5.2(vite@5.0.10)(vue@3.3.12) - '@vitejs/plugin-vue-jsx': 3.1.0(vite@5.0.10)(vue@3.3.12) + '@vitejs/plugin-vue': 4.5.2(vite@5.0.10)(vue@3.4.15) + '@vitejs/plugin-vue-jsx': 3.1.0(vite@5.0.10)(vue@3.4.15) '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.23.6) '@vue/compiler-sfc': 3.3.12 astro: 4.1.1(stylus@0.59.0)(typescript@5.3.3) - vue: 3.3.12(typescript@5.3.3) + vue: 3.4.15(typescript@5.3.3) transitivePeerDependencies: - '@babel/core' - supports-color @@ -1424,6 +1430,46 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.16.0 + /@pagefind/darwin-arm64@1.0.4: + resolution: {integrity: sha512-2OcthvceX2xhm5XbgOmW+lT45oLuHqCmvFeFtxh1gsuP5cO8vcD8ZH8Laj4pXQFCcK6eAdSShx+Ztx/LsQWZFQ==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@pagefind/darwin-x64@1.0.4: + resolution: {integrity: sha512-xkdvp0D9Ld/ZKsjo/y1bgfhTEU72ITimd2PMMQtts7jf6JPIOJbsiErCvm37m/qMFuPGEq/8d+fZ4pydOj08HQ==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@pagefind/linux-arm64@1.0.4: + resolution: {integrity: sha512-jGBrcCzIrMnNxLKVtogaQyajVfTAXM59KlBEwg6vTn8NW4fQ6nuFbbhlG4dTIsaamjEM5e8ZBEAKZfTB/qd9xw==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@pagefind/linux-x64@1.0.4: + resolution: {integrity: sha512-LIn/QcvcEtLEBqKe5vpSbSC2O3fvqbRCWOTIklslqSORisCsvzsWbP6j+LYxE9q0oWIfkdMoWV1vrE/oCKRxHg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@pagefind/windows-x64@1.0.4: + resolution: {integrity: sha512-QlBCVeZfj9fc9sbUgdOz76ZDbeK4xZihOBAFqGuRJeChfM8pnVeH9iqSnXgO3+m9oITugTf7PicyRUFAG76xeQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@rollup/plugin-yaml@4.1.2: resolution: {integrity: sha512-RpupciIeZMUqhgFE97ba0s98mOFS7CWzN3EJNhJkqSv9XLlWYtwVdtE6cDw6ASOF/sZVFS7kRJXftaqM2Vakdw==} engines: {node: '>=14.0.0'} @@ -1712,7 +1758,7 @@ packages: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: false - /@vitejs/plugin-vue-jsx@3.1.0(vite@5.0.10)(vue@3.3.12): + /@vitejs/plugin-vue-jsx@3.1.0(vite@5.0.10)(vue@3.4.15): resolution: {integrity: sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -1723,12 +1769,12 @@ packages: '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.23.6) '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.23.6) vite: 5.0.10(stylus@0.59.0) - vue: 3.3.12(typescript@5.3.3) + vue: 3.4.15(typescript@5.3.3) transitivePeerDependencies: - supports-color dev: false - /@vitejs/plugin-vue@4.5.2(vite@5.0.10)(vue@3.3.12): + /@vitejs/plugin-vue@4.5.2(vite@5.0.10)(vue@3.4.15): resolution: {integrity: sha512-UGR3DlzLi/SaVBPX0cnSyE37vqxU3O6chn8l0HJNzQzDia6/Au2A4xKv+iIJW8w2daf80G7TYHhi1pAUjdZ0bQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -1736,7 +1782,7 @@ packages: vue: ^3.2.25 dependencies: vite: 5.0.10(stylus@0.59.0) - vue: 3.3.12(typescript@5.3.3) + vue: 3.4.15(typescript@5.3.3) dev: false /@volar/kit@1.10.10(typescript@5.3.3): @@ -1838,6 +1884,16 @@ packages: source-map-js: 1.0.2 dev: false + /@vue/compiler-core@3.4.15: + resolution: {integrity: sha512-XcJQVOaxTKCnth1vCxEChteGuwG6wqnUHxAm1DO3gCz0+uXKaJNx8/digSz4dLALCy8n2lKq24jSUs8segoqIw==} + dependencies: + '@babel/parser': 7.23.6 + '@vue/shared': 3.4.15 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.0.2 + dev: false + /@vue/compiler-dom@3.3.12: resolution: {integrity: sha512-RdJU9oEYaoPKUdGXCy0l+i4clesdDeLmbvRlszoc9iagsnBnMmQtYfCPVQ5BHB6o7K4SCucDdJM2Dh3oXB0D6g==} dependencies: @@ -1845,6 +1901,13 @@ packages: '@vue/shared': 3.3.12 dev: false + /@vue/compiler-dom@3.4.15: + resolution: {integrity: sha512-wox0aasVV74zoXyblarOM3AZQz/Z+OunYcIHe1OsGclCHt8RsRm04DObjefaI82u6XDzv+qGWZ24tIsRAIi5MQ==} + dependencies: + '@vue/compiler-core': 3.4.15 + '@vue/shared': 3.4.15 + dev: false + /@vue/compiler-sfc@3.3.12: resolution: {integrity: sha512-yy5b9e7b79dsGbMmglCe/YnhCQgBkHO7Uf6JfjWPSf2/5XH+MKn18LhzhHyxbHdJgnA4lZCqtXzLaJz8Pd8lMw==} dependencies: @@ -1860,6 +1923,20 @@ packages: source-map-js: 1.0.2 dev: false + /@vue/compiler-sfc@3.4.15: + resolution: {integrity: sha512-LCn5M6QpkpFsh3GQvs2mJUOAlBQcCco8D60Bcqmf3O3w5a+KWS5GvYbrrJBkgvL1BDnTp+e8q0lXCLgHhKguBA==} + dependencies: + '@babel/parser': 7.23.6 + '@vue/compiler-core': 3.4.15 + '@vue/compiler-dom': 3.4.15 + '@vue/compiler-ssr': 3.4.15 + '@vue/shared': 3.4.15 + estree-walker: 2.0.2 + magic-string: 0.30.5 + postcss: 8.4.33 + source-map-js: 1.0.2 + dev: false + /@vue/compiler-ssr@3.3.12: resolution: {integrity: sha512-adCiMJPznfWcQyk/9HSuXGja859IaMV+b8UNSVzDatqv7h0PvT9BEeS22+gjkWofDiSg5d78/ZLls3sLA+cn3A==} dependencies: @@ -1867,6 +1944,13 @@ packages: '@vue/shared': 3.3.12 dev: false + /@vue/compiler-ssr@3.4.15: + resolution: {integrity: sha512-1jdeQyiGznr8gjFDadVmOJqZiLNSsMa5ZgqavkPZ8O2wjHv0tVuAEsw5hTdUoUW4232vpBbL/wJhzVW/JwY1Uw==} + dependencies: + '@vue/compiler-dom': 3.4.15 + '@vue/shared': 3.4.15 + dev: false + /@vue/reactivity-transform@3.3.12: resolution: {integrity: sha512-g5TijmML7FyKkLt6QnpqNmA4KD7K/T5SbXa88Bhq+hydNQEkzA8veVXWAQuNqg9rjaFYD0rPf0a9NofKA0ENgg==} dependencies: @@ -1877,41 +1961,45 @@ packages: magic-string: 0.30.5 dev: false - /@vue/reactivity@3.3.12: - resolution: {integrity: sha512-vOJORzO8DlIx88cgTnMLIf2GlLYpoXAKsuoQsK6SGdaqODjxO129pVPTd2s/N/Mb6KKZEFIHIEwWGmtN4YPs+g==} + /@vue/reactivity@3.4.15: + resolution: {integrity: sha512-55yJh2bsff20K5O84MxSvXKPHHt17I2EomHznvFiJCAZpJTNW8IuLj1xZWMLELRhBK3kkFV/1ErZGHJfah7i7w==} dependencies: - '@vue/shared': 3.3.12 + '@vue/shared': 3.4.15 dev: false - /@vue/runtime-core@3.3.12: - resolution: {integrity: sha512-5iL4w7MZrSGKEZU2wFAYhDZdZmgn+s//73EfgDXW1M+ZUOl36md7tlWp1QFK/ladiq4FvQ82shVjo0KiPDPr0A==} + /@vue/runtime-core@3.4.15: + resolution: {integrity: sha512-6E3by5m6v1AkW0McCeAyhHTw+3y17YCOKG0U0HDKDscV4Hs0kgNT5G+GCHak16jKgcCDHpI9xe5NKb8sdLCLdw==} dependencies: - '@vue/reactivity': 3.3.12 - '@vue/shared': 3.3.12 + '@vue/reactivity': 3.4.15 + '@vue/shared': 3.4.15 dev: false - /@vue/runtime-dom@3.3.12: - resolution: {integrity: sha512-8mMzqiIdl+IYa/OXwKwk6/4ebLq7cYV1pUcwCSwBK2KerUa6cwGosen5xrCL9f8o2DJ9TfPFwbPEvH7OXzUpoA==} + /@vue/runtime-dom@3.4.15: + resolution: {integrity: sha512-EVW8D6vfFVq3V/yDKNPBFkZKGMFSvZrUQmx196o/v2tHKdwWdiZjYUBS+0Ez3+ohRyF8Njwy/6FH5gYJ75liUw==} dependencies: - '@vue/runtime-core': 3.3.12 - '@vue/shared': 3.3.12 + '@vue/runtime-core': 3.4.15 + '@vue/shared': 3.4.15 csstype: 3.1.3 dev: false - /@vue/server-renderer@3.3.12(vue@3.3.12): - resolution: {integrity: sha512-OZ0IEK5TU5GXb5J8/wSplyxvGGdIcwEmS8EIO302Vz8K6fGSgSJTU54X0Sb6PaefzZdiN3vHsLXO8XIeF8crQQ==} + /@vue/server-renderer@3.4.15(vue@3.4.15): + resolution: {integrity: sha512-3HYzaidu9cHjrT+qGUuDhFYvF/j643bHC6uUN9BgM11DVy+pM6ATsG6uPBLnkwOgs7BpJABReLmpL3ZPAsUaqw==} peerDependencies: - vue: 3.3.12 + vue: 3.4.15 dependencies: - '@vue/compiler-ssr': 3.3.12 - '@vue/shared': 3.3.12 - vue: 3.3.12(typescript@5.3.3) + '@vue/compiler-ssr': 3.4.15 + '@vue/shared': 3.4.15 + vue: 3.4.15(typescript@5.3.3) dev: false /@vue/shared@3.3.12: resolution: {integrity: sha512-6p0Yin0pclvnER7BLNOQuod9Z+cxSYh8pSh7CzHnWNjAIP6zrTlCdHRvSCb1aYEx6i3Q3kvfuWU7nG16CgG1ag==} dev: false + /@vue/shared@3.4.15: + resolution: {integrity: sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==} + dev: false + /acorn@8.11.2: resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} engines: {node: '>=0.4.0'} @@ -4807,6 +4895,17 @@ packages: engines: {node: '>=6'} dev: false + /pagefind@1.0.4: + resolution: {integrity: sha512-oRIizYe+zSI2Jw4zcMU0ebDZm27751hRFiSOBLwc1OIYMrsZKk+3m8p9EVaOmc6zZdtqwwdilNUNxXvBeHcP9w==} + hasBin: true + optionalDependencies: + '@pagefind/darwin-arm64': 1.0.4 + '@pagefind/darwin-x64': 1.0.4 + '@pagefind/linux-arm64': 1.0.4 + '@pagefind/linux-x64': 1.0.4 + '@pagefind/windows-x64': 1.0.4 + dev: false + /param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} dependencies: @@ -4982,6 +5081,15 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /postcss@8.4.33: + resolution: {integrity: sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: false + /prebuild-install@7.1.1: resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} engines: {node: '>=10'} @@ -6482,19 +6590,19 @@ packages: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} dev: false - /vue@3.3.12(typescript@5.3.3): - resolution: {integrity: sha512-jYNv2QmET2OTHsFzfWHMnqgCfqL4zfo97QwofdET+GBRCHhSCHuMTTvNIgeSn0/xF3JRT5OGah6MDwUFN7MPlg==} + /vue@3.4.15(typescript@5.3.3): + resolution: {integrity: sha512-jC0GH4KkWLWJOEQjOpkqU1bQsBwf4R1rsFtw5GQJbjHVKWDzO6P0nWWBTmjp1xSemAioDFj1jdaK1qa3DnMQoQ==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@vue/compiler-dom': 3.3.12 - '@vue/compiler-sfc': 3.3.12 - '@vue/runtime-dom': 3.3.12 - '@vue/server-renderer': 3.3.12(vue@3.3.12) - '@vue/shared': 3.3.12 + '@vue/compiler-dom': 3.4.15 + '@vue/compiler-sfc': 3.4.15 + '@vue/runtime-dom': 3.4.15 + '@vue/server-renderer': 3.4.15(vue@3.4.15) + '@vue/shared': 3.4.15 typescript: 5.3.3 dev: false diff --git a/src/components/GlobalStyles.astro b/src/components/GlobalStyles.astro index 1da7378..0ce57dd 100644 --- a/src/components/GlobalStyles.astro +++ b/src/components/GlobalStyles.astro @@ -195,5 +195,15 @@ color_set({ .float-panel.closed { @apply top-[4.75rem] opacity-0 pointer-events-none } + .search-panel mark { + @apply bg-transparent text-[var(--primary)] + } + + .text-deep { + @apply text-black/90 dark:text-white/90 + } + .text-sub { + @apply text-black/50 dark:text-white/50 + } } \ No newline at end of file diff --git a/src/components/Navbar.astro b/src/components/Navbar.astro index 8281b45..288bf9f 100644 --- a/src/components/Navbar.astro +++ b/src/components/Navbar.astro @@ -7,6 +7,7 @@ import {i18n} from "../i18n/translation"; import {LinkPreset, NavBarLink} from "../types/config"; import {navBarConfig, siteConfig} from "../config"; import NavMenuPanel from "./widget/NavMenuPanel.astro"; +import SearchPanel from "./SearchPanel.vue" const className = Astro.props.class; function isI18nKey(key: string): key is I18nKey { @@ -63,19 +64,18 @@ function getLinkPresetInfo(p: LinkPreset): NavBarLink { })}
-
- -
-
- -
-
- -
- + + + + + + + + +
@@ -121,7 +121,16 @@ loadButtonScript(); document.addEventListener('astro:after-swap', () => { loadButtonScript(); }, { once: false }); - - - + + \ No newline at end of file diff --git a/src/components/SearchPanel.vue b/src/components/SearchPanel.vue new file mode 100644 index 0000000..25ee6dd --- /dev/null +++ b/src/components/SearchPanel.vue @@ -0,0 +1,100 @@ + + + + + \ No newline at end of file diff --git a/src/components/misc/Markdown.astro b/src/components/misc/Markdown.astro index 45519a9..39dd49b 100644 --- a/src/components/misc/Markdown.astro +++ b/src/components/misc/Markdown.astro @@ -7,7 +7,7 @@ interface Props { } const className = Astro.props.class; --- -
+
diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index f2b1f95..1415da6 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -234,19 +234,22 @@ function activateDisplaySettings() { setHue(hue); } - function setClickOutsideToClose(panel, switchBtn) { + function setClickOutsideToClose(panel: string, ignores: string[]) { document.addEventListener("click", event => { - var cDom = document.getElementById(panel); - let settingBtn = document.getElementById(switchBtn); - var tDom = event.target; - if (cDom == tDom || cDom.contains(tDom) || settingBtn == tDom || settingBtn.contains(tDom)) { - return; + let panelDom = document.getElementById(panel); + let tDom = event.target; + for (let ig of ignores) { + let ie = document.getElementById(ig) + if (ie == tDom || ie.contains(tDom)) { + return; + } } - cDom.classList.add("closed"); + panelDom.classList.add("closed"); }); } - setClickOutsideToClose("display-setting", "display-settings-switch") - setClickOutsideToClose("nav-menu-panel", "nav-menu-switch") + setClickOutsideToClose("display-setting", ["display-setting", "display-settings-switch"]) + setClickOutsideToClose("nav-menu-panel", ["nav-menu-panel", "nav-menu-switch"]) + setClickOutsideToClose("search-panel", ["search-panel", "search-bar", "search-switch"]) } function loadTheme() { diff --git a/src/pages/posts/[...slug].astro b/src/pages/posts/[...slug].astro index bfba41b..4acfa2a 100644 --- a/src/pages/posts/[...slug].astro +++ b/src/pages/posts/[...slug].astro @@ -52,6 +52,7 @@ const { remarkPluginFrontmatter } = await entry.render();