Skip to content

Commit 9119125

Browse files
committed
feat!: add pagefind for static search (#458)
Replace React with pagefind for static site search
1 parent 79c7df4 commit 9119125

6 files changed

Lines changed: 191 additions & 4 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ pnpm-debug.log*
2222

2323
# jetbrains setting folder
2424
.idea/
25+
26+
# pagefind
27+
28+
public/pagefind

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"version": "0.0.1",
55
"scripts": {
66
"dev": "astro dev",
7-
"build": "astro check && astro build",
7+
"build": "astro check && astro build && pagefind --site dist && cp -r dist/pagefind public/",
88
"preview": "astro preview",
99
"astro": "astro",
1010
"format:check": "prettier --check .",
@@ -27,12 +27,14 @@
2727
},
2828
"devDependencies": {
2929
"@astrojs/check": "^0.9.4",
30+
"@pagefind/default-ui": "^1.3.0",
3031
"@tailwindcss/typography": "^0.5.16",
3132
"@types/lodash.kebabcase": "^4.1.9",
3233
"@typescript-eslint/parser": "^8.25.0",
3334
"eslint": "^9.21.0",
3435
"eslint-plugin-astro": "^1.3.1",
3536
"globals": "^16.0.0",
37+
"pagefind": "^1.3.0",
3638
"prettier": "^3.5.2",
3739
"prettier-plugin-astro": "^0.14.1",
3840
"prettier-plugin-tailwindcss": "^0.6.11",

pnpm-lock.yaml

Lines changed: 63 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/layouts/PostDetails.astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ const nextPost =
7474
"mx-auto w-full max-w-3xl px-4 pb-12",
7575
{ "mt-8": !SITE.showBackButton },
7676
]}
77+
data-pagefind-body
7778
>
7879
<h1
7980
transition:name={slugifyStr(title)}
@@ -119,7 +120,7 @@ const nextPost =
119120
<hr class="my-6 border-dashed" />
120121

121122
<!-- Previous/Next Post Buttons -->
122-
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
123+
<div data-pagefind-ignore class="grid grid-cols-1 gap-6 sm:grid-cols-2">
123124
{
124125
prevPost && (
125126
<a

src/pages/search.astro

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,132 @@
11
---
2+
import "@pagefind/default-ui/css/ui.css";
23
import Main from "@/layouts/Main.astro";
34
import Layout from "@/layouts/Layout.astro";
45
import Header from "@/components/Header.astro";
56
import Footer from "@/components/Footer.astro";
67
import { SITE } from "@/config";
8+
9+
const backUrl = SITE.showBackButton ? `${Astro.url.pathname}` : "/";
710
---
811

912
<Layout title={`Search | ${SITE.title}`}>
1013
<Header />
1114
<Main pageTitle="Search" pageDesc="Search any article ...">
12-
<!-- Search bar -->
15+
<div id="pagefind-search" transition:persist data-backurl={backUrl}></div>
1316
</Main>
1417
<Footer />
1518
</Layout>
19+
20+
<script>
21+
function initSearch() {
22+
const pageFindSearch: HTMLElement | null =
23+
document.querySelector("#pagefind-search");
24+
25+
if (!pageFindSearch) return;
26+
27+
const params = new URLSearchParams(window.location.search);
28+
29+
const onIdle = window.requestIdleCallback || (cb => setTimeout(cb, 1));
30+
31+
onIdle(async () => {
32+
// @ts-expect-error — Missing types for @pagefind/default-ui package.
33+
const { PagefindUI } = await import("@pagefind/default-ui");
34+
35+
// Display warning inn dev mode
36+
if (import.meta.env.DEV) {
37+
pageFindSearch.innerHTML = `
38+
<div class="bg-muted/75 rounded p-4 space-y-4 mb-4">
39+
<p><strong>DEV mode Warning! </strong>You need to build the project at least once to see the search results during development.</p>
40+
<code class="block bg-black text-white px-2 py-1 rounded">pnpm run build</code>
41+
</div>
42+
`;
43+
}
44+
45+
// Init pagefind ui
46+
const search = new PagefindUI({
47+
element: "#pagefind-search",
48+
showSubResults: true,
49+
showImages: false,
50+
processTerm: function (term: string) {
51+
params.set("q", term); // Update the `q` parameter in the URL
52+
history.replaceState(history.state, "", "?" + params.toString()); // Push the new URL without reloading
53+
54+
const backUrl = pageFindSearch?.dataset?.backurl;
55+
sessionStorage.setItem("backUrl", backUrl + "?" + params.toString());
56+
57+
return term;
58+
},
59+
});
60+
61+
// If search param exists (eg: search?q=astro), trigger search
62+
const query = params.get("q");
63+
if (query) {
64+
search.triggerSearch(query);
65+
}
66+
67+
// Reset search param if search input is cleared
68+
const searchInput = document.querySelector(".pagefind-ui__search-input");
69+
const clearButton = document.querySelector(".pagefind-ui__search-clear");
70+
searchInput?.addEventListener("input", resetSearchParam);
71+
clearButton?.addEventListener("click", resetSearchParam);
72+
73+
function resetSearchParam(e: Event) {
74+
if ((e.target as HTMLInputElement)?.value.trim() === "") {
75+
history.replaceState(history.state, "", window.location.pathname);
76+
}
77+
}
78+
});
79+
}
80+
81+
document.addEventListener("astro:after-swap", initSearch);
82+
initSearch();
83+
</script>
84+
85+
<style is:global>
86+
#pagefind-search {
87+
--pagefind-ui-font: var(--font-mono);
88+
--pagefind-ui-text: var(--foreground);
89+
--pagefind-ui-background: var(--background);
90+
--pagefind-ui-border: var(--border);
91+
--pagefind-ui-primary: var(--accent);
92+
--pagefind-ui-tag: var(--background);
93+
--pagefind-ui-border-radius: 0.375rem;
94+
--pagefind-ui-border-width: 1px;
95+
--pagefind-ui-image-border-radius: 8px;
96+
--pagefind-ui-image-box-ratio: 3 / 2;
97+
98+
form::before {
99+
background-color: var(--foreground);
100+
}
101+
102+
input {
103+
font-weight: 400;
104+
border: 1px solid var(--border);
105+
}
106+
107+
input:focus-visible {
108+
outline: 1px solid var(--accent);
109+
}
110+
111+
.pagefind-ui__result-title a {
112+
color: var(--accent);
113+
outline-offset: 1px;
114+
outline-color: var(--accent);
115+
}
116+
117+
.pagefind-ui__result-title a:focus-visible,
118+
.pagefind-ui__search-clear:focus-visible {
119+
text-decoration-line: none;
120+
outline-width: 2px;
121+
outline-style: dashed;
122+
}
123+
124+
.pagefind-ui__result:last-of-type {
125+
border-bottom: 0;
126+
}
127+
128+
.pagefind-ui__result-nested .pagefind-ui__result-link:before {
129+
font-family: system-ui;
130+
}
131+
}
132+
</style>

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"extends": "astro/tsconfigs/strict",
33
"include": [".astro/types.d.ts", "**/*"],
4-
"exclude": ["dist"],
4+
"exclude": ["dist", "public/pagefind"],
55
"compilerOptions": {
66
"baseUrl": ".",
77
"paths": {

0 commit comments

Comments
 (0)