Skip to content

Commit 48ef08e

Browse files
committed
feat: search functionality
1 parent 6f0eb61 commit 48ef08e

File tree

1 file changed

+94
-20
lines changed

1 file changed

+94
-20
lines changed

src/components/Navbar.tsx

Lines changed: 94 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,54 @@
1-
import { Link, useParams } from 'react-router-dom';
1+
import { FormEvent, useState } from 'react';
2+
import { Link } from 'react-router-dom';
23
import { PlaceholdersAndVanishInput } from './ui/input-component';
4+
import { topics as topicsData } from '../utils/lists';
35

46
type Props = {
57
isDark: boolean;
68
handleDarkToggle: () => void;
79
};
810

911
const Navbar = ({ isDark, handleDarkToggle }: Props) => {
10-
const placeholders = [
11-
'Which Type to Use',
12-
'Function Declaration Syntax',
13-
'Named Returns',
14-
'Nested Structs',
15-
'Type Assertion',
16-
'Formatting Strings',
17-
'Pointers',
18-
];
12+
const [searchTerm, setSearchTerm] = useState('');
13+
const [searchResults, setSearchResults] = useState<
14+
{ category: string; topic: string }[]
15+
>([]);
16+
const [displayedResults, setDisplayedResults] = useState<
17+
{ category: string; topic: string }[]
18+
>([]);
19+
const [maximumSearchResult, setMaximumSearchResult] = useState(8);
1920

2021
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
21-
console.log(e.target.value);
22+
setSearchTerm(e.target.value);
23+
!searchTerm && setMaximumSearchResult(8);
24+
25+
const searchQuery = e.target.value.toLowerCase();
26+
27+
// Perform search
28+
const filteredTopics: { category: string; topic: string }[] = [];
29+
30+
for (const category in topicsData) {
31+
// @ts-expect-error
32+
const topics = topicsData[category];
33+
for (const topic of topics) {
34+
if (topic.toLowerCase().includes(searchQuery)) {
35+
filteredTopics.push({ category, topic });
36+
}
37+
}
38+
}
39+
40+
setSearchResults(filteredTopics);
41+
setDisplayedResults(filteredTopics.slice(0, maximumSearchResult)); // Limit results to specified max search result
2242
};
23-
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
43+
const onLinkClick = (e: FormEvent) => {
2444
e.preventDefault();
25-
console.log('submitted');
45+
setSearchTerm('');
46+
setSearchResults([]);
47+
setMaximumSearchResult(8);
48+
};
49+
const handleShowMore = () => {
50+
setMaximumSearchResult(maximumSearchResult + 5);
51+
setDisplayedResults(searchResults.slice(0, maximumSearchResult));
2652
};
2753

2854
return (
@@ -54,19 +80,57 @@ const Navbar = ({ isDark, handleDarkToggle }: Props) => {
5480
<label className='switch'>
5581
<input
5682
type='checkbox'
57-
onClick={handleDarkToggle}
83+
checked={isDark}
84+
onChange={handleDarkToggle}
5885
/>
5986
<span className='slider'></span>
6087
</label>
6188
</div>
6289
</div>
6390
</div>
6491

65-
<PlaceholdersAndVanishInput
66-
placeholders={placeholders}
67-
onChange={handleChange}
68-
onSubmit={onSubmit}
69-
/>
92+
<div className='w-full relative'>
93+
<PlaceholdersAndVanishInput
94+
placeholders={placeholders}
95+
onChange={handleChange}
96+
onSubmit={onLinkClick}
97+
/>
98+
{searchTerm ? (
99+
<div className='text-white absolute left-1/2 -translate-x-1/2 mt-3 py-5 px-8 tracking-wide leading-loose w-11/12 lg:w-[70%] rounded-md z-40 bg-zinc-800'>
100+
{displayedResults.length > 0 ? (
101+
<div>
102+
<ul>
103+
{displayedResults.map((result) => (
104+
<li
105+
key={`${result.category}-${result.topic}`}
106+
onClick={(e: FormEvent) => onLinkClick(e)}
107+
>
108+
<Link
109+
to={`/${result.category.replaceAll('_', '-')}/${
110+
result.topic
111+
}`}
112+
>
113+
<span>{result.category.replaceAll('_', '-')}</span>/
114+
<span>{result.topic.replaceAll('-', ' ')}</span>
115+
</Link>
116+
</li>
117+
))}
118+
</ul>
119+
{searchResults.length > 9 ? (
120+
<button
121+
className='mt-2 text-blue-400 underline'
122+
onClick={handleShowMore}
123+
>
124+
Show more
125+
</button>
126+
) : null}
127+
</div>
128+
) : (
129+
<p>No matching topics found.</p>
130+
)}
131+
</div>
132+
) : null}
133+
</div>
70134

71135
<div className='gap-8 hidden md:flex'>
72136
<div>
@@ -89,7 +153,7 @@ const Navbar = ({ isDark, handleDarkToggle }: Props) => {
89153
<input
90154
type='checkbox'
91155
checked={isDark}
92-
onClick={handleDarkToggle}
156+
onChange={handleDarkToggle}
93157
/>
94158
<span className='slider'></span>
95159
</label>
@@ -100,4 +164,14 @@ const Navbar = ({ isDark, handleDarkToggle }: Props) => {
100164
);
101165
};
102166

167+
export const placeholders = [
168+
'Which Type to Use',
169+
'Function Declaration Syntax',
170+
'Nested Structs',
171+
'Type Assertion',
172+
'Formatting Strings',
173+
'Pointers',
174+
'Mutexes',
175+
];
176+
103177
export default Navbar;

0 commit comments

Comments
 (0)