@@ -11,18 +11,20 @@ const ui = uiStrings(locale.code);
1111---
1212
1313{ /*
14- Pagefind UI mounts inside #search and is initialized once the script
15- loads. The stylesheet is also produced by `pagefind` at build time, so
16- in dev (where pagefind hasn't run yet) both URLs 404 silently and the
17- search bar is inert — the rest of the page renders fine.
14+ Pagefind ships its own search UI as a self-contained module. We just
15+ give it a mount point, mount once, and let it draw the input and the
16+ result list itself. The wrapper is `position: relative` so the result
17+ list can be positioned as a floating dropdown that doesn't expand the
18+ sticky header when the user types.
19+
20+ In dev mode pagefind hasn't run yet, so /pagefind/* 404s and the
21+ search box is silently inert — the rest of the page is unaffected.
1822*/ }
1923<link rel =" stylesheet" href =" /pagefind/pagefind-ui.css" />
2024
21- <div
22- id =" search"
23- data-pagefind-search
24- class =" hidden md:block w-72 lg:w-80"
25- ></div >
25+ <div class =" search-shell relative hidden md:block" >
26+ <div id =" search" class =" w-56 lg:w-64" ></div >
27+ </div >
2628
2729<script src =" /pagefind/pagefind-ui.js" is:inline defer ></script >
2830<script
@@ -34,32 +36,33 @@ const ui = uiStrings(locale.code);
3436 languageCode: locale .code ,
3537 }}
3638>
37- // Pagefind UI is a UMD bundle that exposes `window.PagefindUI`. We can
38- // safely re-use the same #search element across navigations because we
39- // only mount once per page load.
39+ // pagefind-ui.js is loaded with `defer`, so per the HTML spec it has
40+ // executed by the time DOMContentLoaded fires. We mount exactly once
41+ // to avoid stacking duplicate widgets on the same element.
42+ let mounted = false;
4043 function mountPagefind() {
44+ if (mounted) return;
4145 if (typeof window.PagefindUI !== 'function') return;
46+ mounted = true;
4247 new window.PagefindUI({
4348 element: '#search',
4449 showImages: false,
4550 showSubResults: true,
46- resetStyles: false,
4751 placeholder,
4852 translations: {
4953 placeholder,
5054 clear_search: clearLabel,
5155 zero_results: zeroResults,
5256 },
53- // Restrict results to the current page locale so visitors browsing
54- // the German site don't get Spanish hits.
55- mergeIndex: [],
57+ // Restrict to the current page's language so a German page doesn't
58+ // surface Spanish hits.
5659 processResult: (result) => {
60+ const lang = result && result.meta && result.meta.language;
5761 if (
5862 languageCode &&
59- result.meta &&
60- result.meta.language &&
61- result.meta.language !== languageCode &&
62- !result.meta.language.startsWith(languageCode.split('-')[0])
63+ lang &&
64+ lang !== languageCode &&
65+ lang.split('-')[0] !== languageCode.split('-')[0]
6366 ) {
6467 return null;
6568 }
@@ -68,46 +71,60 @@ const ui = uiStrings(locale.code);
6871 });
6972 }
7073 if (document.readyState === 'loading') {
71- document.addEventListener('DOMContentLoaded', mountPagefind);
74+ document.addEventListener('DOMContentLoaded', mountPagefind, { once: true } );
7275 } else {
7376 mountPagefind();
7477 }
75- // pagefind-ui.js is loaded with `defer`, so it may not be ready by the
76- // time the listener above fires — also try once it's actually present.
77- window.addEventListener('load', mountPagefind);
7878</script >
7979
8080<style is:global >
81- /* Make Pagefind's default UI inherit the site's accent and surface
82- colours so the search box visually belongs to the header. */
83- #search {
81+ /*
82+ * Map Pagefind's CSS custom properties to the template's theme tokens
83+ * so the search input visually belongs to the header.
84+ */
85+ .search-shell {
8486 --pagefind-ui-primary: var(--color-accent, var(--accent, #3b82f6));
8587 --pagefind-ui-text: var(--color-text);
8688 --pagefind-ui-background: var(--color-surface);
8789 --pagefind-ui-border: var(--color-border);
8890 --pagefind-ui-tag: var(--color-surface-2);
8991 --pagefind-ui-border-width: 1px;
90- --pagefind-ui-border-radius: 9999px ;
92+ --pagefind-ui-border-radius: 0.5rem ;
9193 --pagefind-ui-font: inherit;
9294 }
93- #search .pagefind-ui__search-input {
94- height: 2.25rem;
95- padding- inline: 0.875rem 2.25rem;
96- font-size: 0.875rem;
97- }
98- /* The drawer with results: anchor it to the input and lift it above the
99- sticky header so it isn't clipped by the header's bottom border. */
100- # search .pagefind-ui__drawer {
95+
96+ /*
97+ * The result list is rendered inline below the input by default. Lift
98+ * it out of the document flow so that typing doesn't shove the rest
99+ * of the header content downward, and clamp its width so it doesn't
100+ * overflow the viewport's right edge.
101+ */
102+ . search-shell .pagefind-ui__drawer {
101103 position: absolute;
102- inset-inline-end: 0;
103104 top: calc(100% + 0.5rem);
104- width: min(28rem, 90vw);
105- max-height: 70vh;
105+ inset-inline-end: 0;
106+ width: min(28rem, calc(100vw - 2rem));
107+ max-height: min(70vh, 32rem);
106108 overflow: auto;
107- border-radius: 1rem ;
108- box-shadow : 0 24px 64px rgba(0, 0, 0, 0.18) ;
109+ margin: 0 ;
110+ padding : 0.5rem ;
109111 background: var(--color-surface);
110112 border: 1px solid var(--color-border);
113+ border-radius: 0.75rem;
114+ box-shadow: 0 16px 48px rgba(0, 0, 0, 0.18);
111115 z-index: 50;
112116 }
117+ .search-shell .pagefind-ui__drawer:empty,
118+ .search-shell .pagefind-ui__drawer.pagefind-ui__hidden {
119+ display: none;
120+ }
121+
122+ /* Tighten the input row to fit the header's vertical rhythm. */
123+ .search-shell .pagefind-ui__form {
124+ margin: 0;
125+ }
126+ .search-shell .pagefind-ui__search-input {
127+ height: 2.25rem;
128+ font-size: 0.875rem;
129+ }
113130</style >
0 commit comments