Skip to content

Commit 9116fc1

Browse files
authored
feat(hooks): add facet dropdown code sample (#401)
1 parent 1489496 commit 9116fc1

File tree

19 files changed

+2432
-0
lines changed

19 files changed

+2432
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 2
6+
end_of_line = lf
7+
insert_final_newline = true
8+
trim_trailing_whitespace = true
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
.parcel-cache
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode
17+
.idea
18+
.DS_Store
19+
*.suo
20+
*.ntvs*
21+
*.njsproj
22+
*.sln
23+
*.sw?
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"singleQuote": true,
3+
"proseWrap": "never",
4+
"trailingComma": "es5"
5+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# facet-dropdown
2+
3+
_This project was generated with [create-instantsearch-app](https://github.com/algolia/create-instantsearch-app) by [Algolia](https://algolia.com)._
4+
5+
## Get started
6+
7+
To run this project locally, install the dependencies and run the local server:
8+
9+
```sh
10+
npm install
11+
npm start
12+
```
13+
14+
Alternatively, you may use [Yarn](https://http://yarnpkg.com/):
15+
16+
```sh
17+
yarn
18+
yarn start
19+
```
20+
21+
Open http://localhost:1234 to see your app.
Loading
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
7+
<link rel="shortcut icon" href="favicon.png" />
8+
9+
<!--
10+
Do not use @7 in production, use a complete version like x.x.x, see website for latest version:
11+
https://www.algolia.com/doc/guides/building-search-ui/installation/react/#load-the-style
12+
-->
13+
<link
14+
rel="stylesheet"
15+
href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/satellite-min.css"
16+
/>
17+
18+
<title>facet-dropdown</title>
19+
</head>
20+
21+
<body>
22+
<noscript> You need to enable JavaScript to run this app. </noscript>
23+
24+
<div id="root"></div>
25+
26+
<script type="module" src="src/index.tsx"></script>
27+
</body>
28+
</html>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "facet-dropdown",
3+
"version": "0.1.0",
4+
"private": true,
5+
"scripts": {
6+
"build": "parcel build index.html",
7+
"start": "parcel index.html"
8+
},
9+
"dependencies": {
10+
"algoliasearch": "4.14.2",
11+
"instantsearch.js": "4.43.1",
12+
"react": "18.2.0",
13+
"react-dom": "18.2.0",
14+
"react-instantsearch-hooks-web": "6.30.3"
15+
},
16+
"devDependencies": {
17+
"@types/react": "18.0.15",
18+
"@types/react-dom": "18.0.6",
19+
"parcel": "2.5.0",
20+
"typescript": "4.7.4"
21+
}
22+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* Global */
2+
body,
3+
h1 {
4+
margin: 0;
5+
padding: 0;
6+
}
7+
8+
body {
9+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
10+
Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
11+
}
12+
13+
em {
14+
background: cyan;
15+
font-style: normal;
16+
}
17+
18+
#root {
19+
overflow: hidden;
20+
}
21+
22+
/* Header */
23+
.header {
24+
display: flex;
25+
align-items: center;
26+
min-height: 50px;
27+
padding: 0.5rem 1rem;
28+
background-image: linear-gradient(to right, #8e43e7, #00aeff);
29+
color: #fff;
30+
margin-bottom: 1rem;
31+
}
32+
33+
.header a {
34+
color: #fff;
35+
text-decoration: none;
36+
}
37+
38+
.header-title {
39+
font-size: 1.2rem;
40+
font-weight: normal;
41+
}
42+
43+
.header-title::after {
44+
content: ' ▸ ';
45+
padding: 0 0.5rem;
46+
}
47+
48+
.header-subtitle {
49+
font-size: 1.2rem;
50+
}
51+
52+
/* Container */
53+
.container {
54+
max-width: 1200px;
55+
margin: 0 auto;
56+
padding: 1rem;
57+
}
58+
59+
/* Search */
60+
.search-panel {
61+
display: flex;
62+
flex-direction: column;
63+
gap: 2rem;
64+
}
65+
66+
.search-panel__filters {
67+
display: flex;
68+
gap: 1rem;
69+
flex-wrap: wrap;
70+
}
71+
72+
.search-panel__pagination {
73+
margin: 0 auto 1rem;
74+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import algoliasearch from 'algoliasearch/lite';
2+
import {
3+
Configure,
4+
HierarchicalMenu,
5+
Highlight,
6+
Hits,
7+
InstantSearch,
8+
Pagination,
9+
RangeInput,
10+
RefinementList,
11+
SearchBox,
12+
} from 'react-instantsearch-hooks-web';
13+
import type { Hit as AlgoliaHit } from 'instantsearch.js';
14+
15+
import { Dropdown } from './components/Dropdown';
16+
17+
import './App.css';
18+
19+
const searchClient = algoliasearch(
20+
'latency',
21+
'6be0576ff61c053d5f9a3225e2a90f76'
22+
);
23+
24+
const closeOnChange = () => window.innerWidth > 375;
25+
26+
type HitProps = {
27+
hit: AlgoliaHit;
28+
};
29+
30+
function Hit({ hit }: HitProps) {
31+
return (
32+
<article>
33+
<h1>
34+
<Highlight attribute="name" hit={hit} />
35+
</h1>
36+
<p>
37+
<Highlight attribute="description" hit={hit} />
38+
</p>
39+
</article>
40+
);
41+
}
42+
43+
export function App() {
44+
return (
45+
<div>
46+
<header className="header">
47+
<h1 className="header-title">
48+
<a href="/">facet-dropdown</a>
49+
</h1>
50+
<p className="header-subtitle">
51+
using{' '}
52+
<a href="https://github.com/algolia/react-instantsearch">
53+
React InstantSearch Hooks
54+
</a>
55+
</p>
56+
</header>
57+
58+
<div className="container">
59+
<InstantSearch searchClient={searchClient} indexName="instant_search">
60+
<Configure hitsPerPage={8} />
61+
62+
<div className="search-panel">
63+
<SearchBox placeholder="Search..." className="searchbox" />
64+
65+
<div className="search-panel__filters">
66+
<Dropdown closeOnChange={closeOnChange}>
67+
<RefinementList
68+
attribute="brand"
69+
searchable={true}
70+
searchablePlaceholder="Search..."
71+
/>
72+
</Dropdown>
73+
74+
<Dropdown closeOnChange={closeOnChange}>
75+
<RefinementList attribute="type" />
76+
</Dropdown>
77+
78+
<Dropdown
79+
buttonText={({ refinements }) => {
80+
const label = refinements[0]?.label.split(' > ').pop();
81+
return label ? `Category (${label})` : `Category`;
82+
}}
83+
>
84+
<HierarchicalMenu
85+
attributes={[
86+
'hierarchicalCategories.lvl0',
87+
'hierarchicalCategories.lvl1',
88+
'hierarchicalCategories.lvl2',
89+
]}
90+
/>
91+
</Dropdown>
92+
93+
<Dropdown
94+
closeOnChange={closeOnChange}
95+
buttonText={({ refinements }) => {
96+
const [start, end] = refinements;
97+
return start || end
98+
? `Price (${(start || end).label}${
99+
end ? ' & ' + end.label : ''
100+
})`
101+
: `Price`;
102+
}}
103+
>
104+
<RangeInput attribute="price" />
105+
</Dropdown>
106+
</div>
107+
108+
<Hits hitComponent={Hit} />
109+
110+
<Pagination className="search-panel__pagination" />
111+
</div>
112+
</InstantSearch>
113+
</div>
114+
</div>
115+
);
116+
}

0 commit comments

Comments
 (0)