Skip to content

Commit 2fb7e8a

Browse files
committed
[Docs Site] Re-design /search/ and add view more results footer to searchbox
1 parent 7bc572b commit 2fb7e8a

File tree

5 files changed

+171
-646
lines changed

5 files changed

+171
-646
lines changed

package-lock.json

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

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@
7171
"globals": "16.0.0",
7272
"hastscript": "9.0.1",
7373
"he": "1.2.0",
74-
"instantsearch.css": "8.5.1",
75-
"instantsearch.js": "4.78.0",
7674
"jsonc-parser": "3.3.1",
7775
"lz-string": "1.5.0",
7876
"marked": "15.0.7",
@@ -88,6 +86,7 @@
8886
"react": "19.0.0",
8987
"react-dom": "19.0.0",
9088
"react-icons": "5.5.0",
89+
"react-instantsearch": "7.15.4",
9190
"react-markdown": "10.0.1",
9291
"redirects-in-workers": "0.0.5",
9392
"rehype": "13.0.2",
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { liteClient as algoliasearch } from "algoliasearch/lite";
2+
import { useEffect } from "react";
3+
import {
4+
InstantSearch,
5+
Highlight,
6+
Configure,
7+
useSearchBox,
8+
type UseSearchBoxProps,
9+
useInfiniteHits,
10+
type UseInfiniteHitsProps,
11+
} from "react-instantsearch";
12+
13+
function SearchBox(props: UseSearchBoxProps) {
14+
const { query, refine } = useSearchBox(props);
15+
16+
useEffect(() => {
17+
const params = new URLSearchParams(window.location.search);
18+
const query = params.get("query");
19+
20+
if (query) {
21+
refine(query);
22+
}
23+
}, []);
24+
25+
return (
26+
<div className="flex items-center rounded border border-cl1-gray-8 p-2 dark:border-cl1-gray-2">
27+
<input
28+
type="text"
29+
value={query}
30+
onChange={(event) => refine(event.target.value)}
31+
className="w-full border-none bg-transparent p-0 text-sm outline-none"
32+
placeholder="Search..."
33+
/>
34+
</div>
35+
);
36+
}
37+
38+
function InfiniteHits(props: UseInfiniteHitsProps) {
39+
const { items, isLastPage, showMore } = useInfiniteHits(props);
40+
41+
return (
42+
<div className="space-y-4">
43+
{items.map((item) => {
44+
const hierarchy = Object.entries(item.hierarchy)
45+
.filter(([, value]) => value !== null)
46+
.sort((a, b) => a[0].localeCompare(b[0]))
47+
.map(([, value]) => value);
48+
49+
const title = hierarchy ? hierarchy.join(" > ") : "Documentation";
50+
51+
return (
52+
<a
53+
key={item.objectID}
54+
href={item.url}
55+
className="flex flex-col rounded border border-cl1-gray-8 p-6 !text-black no-underline hover:bg-cl1-gray-9 dark:border-cl1-gray-2 dark:bg-cl1-gray-0 dark:hover:bg-cl1-gray-1"
56+
>
57+
<strong>{title}</strong>
58+
<p className="line-clamp-2">
59+
<Highlight attribute="content" hit={item} />
60+
</p>
61+
</a>
62+
);
63+
})}
64+
{items.length !== 0 && !isLastPage && (
65+
<div className="flex items-center justify-center">
66+
<button
67+
onClick={showMore}
68+
className="h-12 cursor-pointer rounded bg-cl1-brand-orange px-6 font-medium text-cl1-black"
69+
>
70+
Load more
71+
</button>
72+
</div>
73+
)}
74+
</div>
75+
);
76+
}
77+
78+
export default function InstantSearchComponent() {
79+
return (
80+
<InstantSearch
81+
searchClient={algoliasearch(
82+
"D32WIYFTUF",
83+
"5cec275adc19dd3bc17617f7d9cf312a",
84+
)}
85+
indexName="prod_devdocs"
86+
future={{
87+
preserveSharedStateOnUnmount: true,
88+
}}
89+
>
90+
<Configure facetFilters={["type:content"]} />
91+
<SearchBox />
92+
<InfiniteHits />
93+
</InstantSearch>
94+
);
95+
}

0 commit comments

Comments
 (0)