Skip to content

Commit 74deaa6

Browse files
committed
Add icons
1 parent b322068 commit 74deaa6

File tree

8 files changed

+97
-117
lines changed

8 files changed

+97
-117
lines changed

src/components/Search.scss

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,17 @@
104104
}
105105
}
106106

107+
&__item-content {
108+
overflow-x: hidden;
109+
}
110+
107111
&__item-highlight {
108112
text-overflow: ellipsis;
109113
overflow: hidden;
110114
white-space: nowrap;
111115
}
112116

113-
&__item-content {
114-
text-overflow: ellipsis;
115-
overflow: hidden;
116-
white-space: nowrap;
117+
&__item-icon {
118+
color: var(--gray-11);
117119
}
118120
}

src/components/Search.tsx

Lines changed: 72 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import type { Hit } from "@algolia/client-search";
44
import Link from "@docusaurus/Link";
55
import SearchIcon from "/img/icons/search.svg";
66
import CloseIcon from "/img/icons/x.svg";
7+
import HashIcon from "/img/icons/hash.svg";
8+
import GithubIcon from "/img/icons/github.svg";
9+
import FileIcon from "/img/icons/file.svg";
10+
import TerminalIcon from "/img/icons/terminal.svg";
11+
import CodeIcon from "/img/icons/code.svg";
712
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
813
import { search, SearchResult } from "../lib";
914

@@ -70,17 +75,20 @@ function SearchModal() {
7075
const [searchQuery, setSearchQuery] = useState("");
7176
const { isModalOpen, setIsModalOpen } = useContext(SearchButtonContext);
7277
const [selectedTab, setSelectedTab] = useState("all");
73-
const tabsRef = useRef<HTMLElement[]>(new Array(5).fill(null));
78+
const tabsRef = useRef<HTMLElement[]>([]);
7479

7580
const onKeyDown = useCallback((event: KeyboardEvent) => {
81+
if (!tabsRef.current) return;
7682
if (!event.ctrlKey) return;
7783

78-
if (["1", "2", "3", "4", "5"].includes(event.key)) {
84+
const numericKeys = tabsRef.current.map((_, index) => `${index + 1}`);
85+
if (numericKeys.includes(event.key)) {
7986
const tabElement = tabsRef.current[Number(event.key) - 1];
8087
if (!tabElement) return;
8188
const tabValue = tabElement.getAttribute("data-value");
8289
if (!tabValue) return;
8390
setSelectedTab(tabValue);
91+
return;
8492
}
8593

8694
if (event.key === "]") {
@@ -91,6 +99,7 @@ function SearchModal() {
9199
const nextTabValue = nextTabElement.getAttribute("data-value");
92100
if (!nextTabValue) return;
93101
setSelectedTab(nextTabValue);
102+
return;
94103
}
95104

96105
if (event.key === "[") {
@@ -102,6 +111,7 @@ function SearchModal() {
102111
const previousTabValue = previousTabElement.getAttribute("data-value");
103112
if (!previousTabValue) return;
104113
setSelectedTab(previousTabValue);
114+
return;
105115
}
106116
}, []);
107117

@@ -161,60 +171,26 @@ function SearchModal() {
161171
</Box>
162172
<Tabs.Root value={selectedTab} onValueChange={setSelectedTab}>
163173
<Tabs.List wrap="wrap" className="search-modal__tabs-list">
164-
<Tabs.Trigger
165-
key="all"
166-
value="all"
167-
data-value="all"
168-
ref={(el) => {
169-
tabsRef.current[0] = el;
170-
}}
171-
>
172-
All
173-
</Tabs.Trigger>
174-
<Tabs.Trigger
175-
key="tutorial"
176-
value="tutorial"
177-
data-value="tutorial"
178-
ref={(el) => {
179-
tabsRef.current[1] = el;
180-
}}
181-
>
182-
Tutorials
183-
</Tabs.Trigger>
184-
<Tabs.Trigger
185-
key="guide"
186-
value="guide"
187-
data-value="guide"
188-
ref={(el) => {
189-
tabsRef.current[2] = el;
190-
}}
191-
>
192-
Guides
193-
</Tabs.Trigger>
194-
<Tabs.Trigger
195-
key="sdk-reference"
196-
value="sdk-reference"
197-
data-value="sdk-reference"
198-
ref={(el) => {
199-
tabsRef.current[3] = el;
200-
}}
201-
>
202-
SDK References
203-
</Tabs.Trigger>
204-
<Tabs.Trigger
205-
key="api-reference"
206-
value="api-reference"
207-
data-value="api-reference"
208-
ref={(el) => {
209-
tabsRef.current[4] = el;
210-
}}
211-
>
212-
API References
213-
</Tabs.Trigger>
174+
{[
175+
{ name: "all", label: "All" },
176+
{ name: "documentation", label: "Documentation" },
177+
{ name: "sdk-reference", label: "SDK References" },
178+
{ name: "api-reference", label: "API References" },
179+
].map((tab, index) => (
180+
<Tabs.Trigger
181+
key={tab.name}
182+
value={tab.name}
183+
data-value={tab.name}
184+
ref={(el) => {
185+
tabsRef.current[index] = el;
186+
}}
187+
>
188+
{tab.label}
189+
</Tabs.Trigger>
190+
))}
214191
</Tabs.List>
215192
<AllSearchResultsTabContent />
216-
<GuidesSearchResultsTabContent />
217-
<TutorialsSearchResultsTabContent />
193+
<DocumentationSearchResultsTabContent />
218194
<SDKReferencesSearchResultsTabContent />
219195
<APIReferencesSearchResultsTabContent />
220196
</Tabs.Root>
@@ -224,7 +200,6 @@ function SearchModal() {
224200
}
225201

226202
function AllSearchResultsTabContent() {
227-
const { query } = useContext(SearchModalContext);
228203
const searchFn = useCallback(async (searchQuery: string) => {
229204
return search(searchQuery);
230205
}, []);
@@ -238,40 +213,25 @@ function AllSearchResultsTabContent() {
238213
);
239214
}
240215

241-
function GuidesSearchResultsTabContent() {
242-
const { query } = useContext(SearchModalContext);
243-
const searchFn = useCallback(async (searchQuery: string) => {
244-
return search(searchQuery, ["supertokens_documentation"], "guide");
245-
}, []);
246-
247-
return (
248-
<SearchProvider searchFn={searchFn}>
249-
<Tabs.Content value="guide">
250-
<SearchResultsList />
251-
</Tabs.Content>
252-
</SearchProvider>
253-
);
254-
}
255-
256-
function TutorialsSearchResultsTabContent() {
257-
const { query } = useContext(SearchModalContext);
216+
function DocumentationSearchResultsTabContent() {
258217
const searchFn = useCallback(async (searchQuery: string) => {
259-
return search(searchQuery, ["supertokens_documentation"], "tutorial");
218+
return search(searchQuery, [
219+
{ indexName: "supertokens_documentation", facetFilters: [["type:guide", "type:tutorial"]] },
220+
]);
260221
}, []);
261222

262223
return (
263224
<SearchProvider searchFn={searchFn}>
264-
<Tabs.Content value="tutorial">
225+
<Tabs.Content value="documentation">
265226
<SearchResultsList />
266227
</Tabs.Content>
267228
</SearchProvider>
268229
);
269230
}
270231

271232
function SDKReferencesSearchResultsTabContent() {
272-
const { query } = useContext(SearchModalContext);
273233
const searchFn = useCallback(async (searchQuery: string) => {
274-
return search(searchQuery, ["supertokens_documentation"], "sdk-reference");
234+
return search(searchQuery, [{ indexName: "supertokens_documentation", facetFilters: ["type:sdk-reference"] }]);
275235
}, []);
276236

277237
return (
@@ -284,9 +244,8 @@ function SDKReferencesSearchResultsTabContent() {
284244
}
285245

286246
function APIReferencesSearchResultsTabContent() {
287-
const { query } = useContext(SearchModalContext);
288247
const searchFn = useCallback(async (searchQuery: string) => {
289-
return search(searchQuery, ["supertokens_documentation"], "api-reference");
248+
return search(searchQuery, [{ indexName: "supertokens_documentation", facetFilters: ["type:api-reference"] }]);
290249
}, []);
291250

292251
return (
@@ -298,16 +257,6 @@ function APIReferencesSearchResultsTabContent() {
298257
);
299258
}
300259

301-
function NoResultsTabContent() {
302-
return (
303-
<Box className="search-modal__no-results">
304-
<Text size="7" color="gray">
305-
No results found
306-
</Text>
307-
</Box>
308-
);
309-
}
310-
311260
type SearchContextType = {
312261
searchResults: SearchResult[] | null;
313262
searchState: "idle" | "loading" | "error" | "fetched";
@@ -466,10 +415,27 @@ function SearchResultsList() {
466415
);
467416
}
468417

418+
type SearchResultItemType = "page-title" | "page-heading" | "api-reference" | "sdk-reference" | "github-page";
419+
420+
TerminalIcon;
421+
const SearchResultItemTypeIcons: Record<SearchResultItemType, React.ComponentType<React.SVGProps<SVGElement>>> = {
422+
"page-title": FileIcon,
423+
"page-heading": HashIcon,
424+
"api-reference": TerminalIcon,
425+
"sdk-reference": CodeIcon,
426+
"github-page": GithubIcon,
427+
};
428+
469429
function SearchResultListItem({ result }: { result: SearchResult }) {
470430
const ref = useRef<HTMLLIElement>(null);
471431
const { interactionMode, setInteractionMode } = useContext(SearchResultListContext);
472432
const { onCloseModal } = useContext(SearchModalContext);
433+
const searchResultItemType = useMemo(() => {
434+
if (result.type === "sdk-reference") return "sdk-reference";
435+
if (result.type === "api-reference") return "api-reference";
436+
if (result.hierarchy.length === 1) return "page-title";
437+
return "page-heading";
438+
}, [result]);
473439
const breadcrumbs = useMemo(() => {
474440
if (!result.hierarchy) return undefined;
475441
return result.hierarchy.join(" › ");
@@ -516,6 +482,8 @@ function SearchResultListItem({ result }: { result: SearchResult }) {
516482
return result.url;
517483
}, [result]);
518484

485+
const Icon = SearchResultItemTypeIcons[searchResultItemType];
486+
519487
return (
520488
<li
521489
className="search-modal__item"
@@ -525,17 +493,22 @@ function SearchResultListItem({ result }: { result: SearchResult }) {
525493
onMouseMove={onMouseMove}
526494
>
527495
<Link href={urlOrPath} onClick={onClick} className="reset-link">
528-
<Flex direction="column" gap="2" p="2" className="search-result-item">
529-
<Text
530-
className="search-modal__item-highlight"
531-
as="div"
532-
size="3"
533-
m="0"
534-
dangerouslySetInnerHTML={{ __html: result.highlight }}
535-
/>
536-
<Text className="search-result__item-breadcrumbs" as="div" size="2" color="gray" trim="both">
537-
{breadcrumbs}
538-
</Text>
496+
<Flex direction="row" gap="1">
497+
<Flex align="center" className="search-modal__item-icon">
498+
<Icon width="20px" height="20px" />
499+
</Flex>
500+
<Flex direction="column" gap="2" p="2" className="search-modal__item-content">
501+
<Text
502+
className="search-modal__item-highlight"
503+
as="div"
504+
size="3"
505+
m="0"
506+
dangerouslySetInnerHTML={{ __html: result.highlight }}
507+
/>
508+
<Text className="search-modal__item-breadcrumbs" as="div" size="2" color="gray" trim="both">
509+
{breadcrumbs}
510+
</Text>
511+
</Flex>
539512
</Flex>
540513
</Link>
541514
</li>

src/lib/search.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,28 @@ const SearchCache: Record<string, { results: SearchResult[]; timestamp: Date; cl
3535
const CacheTTL = 1000 * 60 * 5;
3636
type IndexName = "supertokens_documentation" | "supertokens_api_reference" | "supertokens_github";
3737

38-
export async function search(
39-
query: string,
40-
indexes?: IndexName[],
41-
type?: SearchResultType,
42-
): Promise<SearchResult[] | null> {
43-
const indexNames = indexes || ["supertokens_documentation"];
44-
const facetFilters = type ? [`type:${type}`] : undefined;
45-
const cacheKey = `${indexNames.join(":")}-${query}-${facetFilters?.join(":")}`;
38+
type DocumentationIndexPageType = "guide" | "tutorial" | "sdk-reference" | "api-reference";
39+
type DocumentationIndexTypeFacetFilter = `type:${DocumentationIndexPageType}`;
40+
41+
type QueryParameters = {
42+
indexName: "supertokens_documentation";
43+
facetFilters?: DocumentationIndexTypeFacetFilter[] | DocumentationIndexTypeFacetFilter[][];
44+
};
45+
46+
export async function search(query: string, _parameters?: QueryParameters[]): Promise<SearchResult[] | null> {
47+
const parameters = _parameters || [{ indexName: "supertokens_documentation" }];
48+
const cacheKey = parameters.map((p) => `${p.indexName}-${query}-${p.facetFilters?.join(":")}`).join(";");
4649

4750
if (SearchCache[cacheKey] && SearchCache[cacheKey].timestamp > new Date(Date.now() - CacheTTL)) {
4851
return SearchCache[cacheKey].results;
4952
}
5053

5154
try {
5255
const response = await client.search<SearchResultHit>({
53-
requests: indexNames.map((indexName) => ({
54-
indexName,
56+
requests: parameters.map((param) => ({
57+
indexName: param.indexName,
5558
query,
56-
facetFilters,
59+
facetFilters: param.facetFilters,
5760
offset: 0,
5861
length: 50,
5962
highlightPreTag: "<mark>",

static/img/icons/code.svg

Lines changed: 1 addition & 3 deletions
Loading

static/img/icons/file.svg

Lines changed: 1 addition & 0 deletions
Loading

static/img/icons/github.svg

Lines changed: 1 addition & 0 deletions
Loading

static/img/icons/hash.svg

Lines changed: 1 addition & 0 deletions
Loading

static/img/icons/terminal.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)