diff --git a/packages/docsearch-react/src/Footer/AlgoliaLogo.tsx b/packages/docsearch-react/src/AlgoliaLogo.tsx similarity index 100% rename from packages/docsearch-react/src/Footer/AlgoliaLogo.tsx rename to packages/docsearch-react/src/AlgoliaLogo.tsx diff --git a/packages/docsearch-react/src/DocSearch.tsx b/packages/docsearch-react/src/DocSearch.tsx index a616fa64f..8358a0b4b 100644 --- a/packages/docsearch-react/src/DocSearch.tsx +++ b/packages/docsearch-react/src/DocSearch.tsx @@ -8,14 +8,14 @@ import { getAlgoliaHits } from '@francoischalifour/autocomplete-preset-algolia'; import { DocSearchHit, InternalDocSearchHit, - RecentDocSearchHit, + StoredDocSearchHit, } from './types'; import { createSearchClient, groupBy, noop } from './utils'; import { SearchBox } from './SearchBox'; -import { Dropdown } from './Dropdown'; +import { ScreenState } from './ScreenState'; import { Footer } from './Footer'; -import { createRecentSearches } from './recent-searches'; +import { createStoredSearches } from './stored-searches'; interface DocSearchProps { appId?: string; @@ -48,7 +48,18 @@ export function DocSearch({ appId, apiKey, ]); - const recentSearches = useRef(createRecentSearches()); + const recentSearches = useRef( + createStoredSearches({ + key: '__DOCSEARCH_RECENT_SEARCHES__', + limit: 5, + }) + ).current; + const favoriteSearches = useRef( + createStoredSearches({ + key: '__DOCSEARCH_FAVORITE_SEARCHES__', + limit: 10, + }) + ).current; const autocomplete = React.useMemo( () => @@ -128,14 +139,26 @@ export function DocSearch({ return [ { onSelect({ suggestion }) { - recentSearches.current.saveSearch(suggestion); + recentSearches.add(suggestion); onClose(); }, getSuggestionUrl({ suggestion }) { return suggestion.url; }, getSuggestions() { - return recentSearches.current.getSearches(); + return recentSearches.getAll(); + }, + }, + { + onSelect({ suggestion }) { + recentSearches.add(suggestion); + onClose(); + }, + getSuggestionUrl({ suggestion }) { + return suggestion.url; + }, + getSuggestions() { + return favoriteSearches.getAll(); }, }, ]; @@ -144,7 +167,7 @@ export function DocSearch({ return Object.values(sources).map(items => { return { onSelect({ suggestion }) { - recentSearches.current.saveSearch(suggestion); + recentSearches.add(suggestion); onClose(); }, getSuggestionUrl({ suggestion }) { @@ -177,7 +200,14 @@ export function DocSearch({ }); }, }), - [indexName, searchParameters, searchClient, onClose] + [ + indexName, + searchParameters, + searchClient, + onClose, + recentSearches, + favoriteSearches, + ] ); const { getEnvironmentProps, getRootProps } = autocomplete; @@ -244,18 +274,16 @@ export function DocSearch({
- { - recentSearches.current.saveSearch(item); + recentSearches.add(item); onClose(); }} - onAction={item => { - recentSearches.current.deleteSearch(item); - autocomplete.refresh(); - }} + inputRef={inputRef} />
diff --git a/packages/docsearch-react/src/Dropdown/Dropdown.tsx b/packages/docsearch-react/src/Dropdown/Dropdown.tsx deleted file mode 100644 index 0643b814c..000000000 --- a/packages/docsearch-react/src/Dropdown/Dropdown.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import { - AutocompleteApi, - AutocompleteState, -} from '@francoischalifour/autocomplete-core'; - -import { InternalDocSearchHit, RecentDocSearchHit } from '../types'; -import { EmptyScreen } from '../EmptyScreen'; -import { Results } from '../Results'; -import { NoResults } from '../NoResults'; -import { Error } from '../Error'; - -interface DropdownProps - extends AutocompleteApi< - TItem, - React.FormEvent, - React.MouseEvent, - React.KeyboardEvent - > { - state: AutocompleteState; - onItemClick(search: RecentDocSearchHit): void; - onAction(search: RecentDocSearchHit): void; - inputRef: React.MutableRefObject; -} - -export function Dropdown(props: DropdownProps) { - if (props.state.status === 'error') { - return ; - } - - const hasSuggestions = props.state.suggestions.some( - source => source.items.length > 0 - ); - - if (!props.state.query) { - return ( - )} - hasSuggestions={hasSuggestions} - /> - ); - } - - if (props.state.status === 'idle' && hasSuggestions === false) { - return ; - } - - return ; -} diff --git a/packages/docsearch-react/src/Dropdown/index.ts b/packages/docsearch-react/src/Dropdown/index.ts deleted file mode 100644 index 2f29bad4e..000000000 --- a/packages/docsearch-react/src/Dropdown/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Dropdown'; diff --git a/packages/docsearch-react/src/EmptyScreen.tsx b/packages/docsearch-react/src/EmptyScreen.tsx new file mode 100644 index 000000000..c0967dd31 --- /dev/null +++ b/packages/docsearch-react/src/EmptyScreen.tsx @@ -0,0 +1,110 @@ +import React from 'react'; +import { + AutocompleteApi, + AutocompleteState, +} from '@francoischalifour/autocomplete-core'; + +import { StoredDocSearchHit } from './types'; +import { StoredSearchPlugin } from './stored-searches'; +import { Results } from './Results'; +import { ResetIcon, RecentIcon, StarIcon } from './icons'; + +interface EmptyScreenProps + extends AutocompleteApi< + StoredDocSearchHit, + React.FormEvent, + React.MouseEvent, + React.KeyboardEvent + > { + state: AutocompleteState; + hasSuggestions: boolean; + onItemClick(item: StoredDocSearchHit): void; + recentSearches: StoredSearchPlugin; + favoriteSearches: StoredSearchPlugin; +} + +export function EmptyScreen(props: EmptyScreenProps) { + if (props.state.status === 'idle' && props.hasSuggestions === false) { + return ( +
+

Your search history will appear here.

+
+ ); + } + + if (props.hasSuggestions === false) { + return null; + } + + return ( +
+ ( +
+ +
+ )} + renderAction={({ item }) => ( + <> +
+ +
+
+ +
+ + )} + /> + + ( +
+ +
+ )} + renderAction={({ item }) => ( + + )} + /> +
+ ); +} diff --git a/packages/docsearch-react/src/EmptyScreen/EmptyScreen.tsx b/packages/docsearch-react/src/EmptyScreen/EmptyScreen.tsx deleted file mode 100644 index 2722ef0ad..000000000 --- a/packages/docsearch-react/src/EmptyScreen/EmptyScreen.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import React from 'react'; -import { - AutocompleteApi, - AutocompleteState, -} from '@francoischalifour/autocomplete-core'; - -import { RecentDocSearchHit } from '../types'; - -import { ResetIcon } from '../SearchBox/ResetIcon'; - -interface EmptyScreenProps - extends AutocompleteApi< - RecentDocSearchHit, - React.FormEvent, - React.MouseEvent, - React.KeyboardEvent - > { - state: AutocompleteState; - hasSuggestions: boolean; - onItemClick(item: RecentDocSearchHit): void; - onAction(search: RecentDocSearchHit): void; -} - -export function EmptyScreen(props: EmptyScreenProps) { - if (props.state.status === 'idle' && props.hasSuggestions === false) { - return ( -
-

Your search history will appear here.

-
- ); - } - - return ( - - ); -} diff --git a/packages/docsearch-react/src/EmptyScreen/index.ts b/packages/docsearch-react/src/EmptyScreen/index.ts deleted file mode 100644 index f184be926..000000000 --- a/packages/docsearch-react/src/EmptyScreen/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './EmptyScreen'; diff --git a/packages/docsearch-react/src/Error/index.ts b/packages/docsearch-react/src/Error/index.ts deleted file mode 100644 index ae6e95d01..000000000 --- a/packages/docsearch-react/src/Error/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Error'; diff --git a/packages/docsearch-react/src/Error/Error.tsx b/packages/docsearch-react/src/ErrorScreen.tsx similarity index 83% rename from packages/docsearch-react/src/Error/Error.tsx rename to packages/docsearch-react/src/ErrorScreen.tsx index 12d983b23..0248090f3 100644 --- a/packages/docsearch-react/src/Error/Error.tsx +++ b/packages/docsearch-react/src/ErrorScreen.tsx @@ -1,6 +1,6 @@ import React from 'react'; -export function Error() { +export function ErrorScreen() { return (

We‘re unable to fetch results. You might want to check your network diff --git a/packages/docsearch-react/src/Footer/Footer.tsx b/packages/docsearch-react/src/Footer.tsx similarity index 100% rename from packages/docsearch-react/src/Footer/Footer.tsx rename to packages/docsearch-react/src/Footer.tsx diff --git a/packages/docsearch-react/src/Footer/index.ts b/packages/docsearch-react/src/Footer/index.ts deleted file mode 100644 index ddcc5a9cd..000000000 --- a/packages/docsearch-react/src/Footer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Footer'; diff --git a/packages/docsearch-react/src/Footer/index.tsx b/packages/docsearch-react/src/Footer/index.tsx deleted file mode 100644 index ddcc5a9cd..000000000 --- a/packages/docsearch-react/src/Footer/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './Footer'; diff --git a/packages/docsearch-react/src/NoResults/index.ts b/packages/docsearch-react/src/NoResults/index.ts deleted file mode 100644 index 20eae4db4..000000000 --- a/packages/docsearch-react/src/NoResults/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './NoResults'; diff --git a/packages/docsearch-react/src/NoResults/NoResults.tsx b/packages/docsearch-react/src/NoResultsScreen.tsx similarity index 88% rename from packages/docsearch-react/src/NoResults/NoResults.tsx rename to packages/docsearch-react/src/NoResultsScreen.tsx index e4f3d7a0c..f32eaf6b0 100644 --- a/packages/docsearch-react/src/NoResults/NoResults.tsx +++ b/packages/docsearch-react/src/NoResultsScreen.tsx @@ -4,7 +4,7 @@ import { AutocompleteState, } from '@francoischalifour/autocomplete-core'; -import { InternalDocSearchHit } from '../types'; +import { InternalDocSearchHit } from './types'; interface NoResultsProps extends AutocompleteApi< @@ -17,7 +17,7 @@ interface NoResultsProps inputRef: React.MutableRefObject; } -export function NoResults(props: NoResultsProps) { +export function NoResultsScreen(props: NoResultsProps) { return (

@@ -50,7 +50,9 @@ export function NoResults(props: NoResultsProps) {

- If you believe this query should return results,
please{' '} + If you believe this query should return results, +
+ please{' '} + extends AutocompleteApi< + TItem, + React.FormEvent, + React.MouseEvent, + React.KeyboardEvent + > { + title: string; + suggestion: AutocompleteState['suggestions'][0]; + renderIcon(props: { item: TItem; index: number }): React.ReactNode; + renderAction(props: { item: TItem }): React.ReactNode; + onItemClick(item: TItem): void; +} + +export function Results( + props: ResultsProps +) { + if (props.suggestion.items.length === 0) { + return null; + } + + return ( +

+
{props.title}
+ +
+
+ ); +} diff --git a/packages/docsearch-react/src/Results/Results.tsx b/packages/docsearch-react/src/Results/Results.tsx deleted file mode 100644 index 4d12fbcfc..000000000 --- a/packages/docsearch-react/src/Results/Results.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import React from 'react'; -import { - AutocompleteApi, - AutocompleteState, -} from '@francoischalifour/autocomplete-core'; - -import { Snippet } from '../Snippet'; -import { SourceIcon } from './SourceIcon'; -import { SelectIcon } from './ActionIcon'; -import { InternalDocSearchHit } from '../types'; - -interface ResultsProps - extends AutocompleteApi< - InternalDocSearchHit, - React.FormEvent, - React.MouseEvent, - React.KeyboardEvent - > { - state: AutocompleteState; - onItemClick(item: InternalDocSearchHit): void; - onAction(search: InternalDocSearchHit): void; -} - -export function Results(props: ResultsProps) { - return ( - - ); -} diff --git a/packages/docsearch-react/src/Results/index.ts b/packages/docsearch-react/src/Results/index.ts deleted file mode 100644 index 9646dd49e..000000000 --- a/packages/docsearch-react/src/Results/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Results'; diff --git a/packages/docsearch-react/src/ResultsScreen.tsx b/packages/docsearch-react/src/ResultsScreen.tsx new file mode 100644 index 000000000..f7fc529a5 --- /dev/null +++ b/packages/docsearch-react/src/ResultsScreen.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { + AutocompleteApi, + AutocompleteState, +} from '@francoischalifour/autocomplete-core'; + +import { InternalDocSearchHit } from './types'; +import { Results } from './Results'; +import { SourceIcon, SelectIcon } from './icons'; + +interface ResultsProps + extends AutocompleteApi< + InternalDocSearchHit, + React.FormEvent, + React.MouseEvent, + React.KeyboardEvent + > { + state: AutocompleteState; + onItemClick(item: InternalDocSearchHit): void; +} + +export function ResultsScreen(props: ResultsProps) { + return ( +
+ {props.state.suggestions.map((suggestion, index) => { + if (suggestion.items.length === 0) { + return null; + } + + const title = suggestion.items[0].hierarchy.lvl0; + + return ( + ( + <> + {item.__docsearch_parent && ( + + + {item.__docsearch_parent !== + suggestion.items[index + 1]?.__docsearch_parent ? ( + + ) : ( + + )} + + + )} + +
+ +
+ + )} + renderAction={() => ( +
+ +
+ )} + /> + ); + })} +
+ ); +} diff --git a/packages/docsearch-react/src/ScreenState.tsx b/packages/docsearch-react/src/ScreenState.tsx new file mode 100644 index 000000000..3ad421696 --- /dev/null +++ b/packages/docsearch-react/src/ScreenState.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { + AutocompleteApi, + AutocompleteState, +} from '@francoischalifour/autocomplete-core'; + +import { StoredSearchPlugin } from './stored-searches'; +import { InternalDocSearchHit, StoredDocSearchHit } from './types'; +import { EmptyScreen } from './EmptyScreen'; +import { ResultsScreen } from './ResultsScreen'; +import { NoResultsScreen } from './NoResultsScreen'; +import { ErrorScreen } from './ErrorScreen'; + +interface DropdownProps + extends AutocompleteApi< + TItem, + React.FormEvent, + React.MouseEvent, + React.KeyboardEvent + > { + state: AutocompleteState; + recentSearches: StoredSearchPlugin; + favoriteSearches: StoredSearchPlugin; + onItemClick(item: StoredDocSearchHit): void; + inputRef: React.MutableRefObject; +} + +export function ScreenState(props: DropdownProps) { + if (props.state.status === 'error') { + return ; + } + + const hasSuggestions = props.state.suggestions.some( + suggestion => suggestion.items.length > 0 + ); + + if (!props.state.query) { + return ( + )} + hasSuggestions={hasSuggestions} + /> + ); + } + + if (props.state.status === 'idle' && hasSuggestions === false) { + return ; + } + + return ; +} diff --git a/packages/docsearch-react/src/SearchBox/SearchBox.tsx b/packages/docsearch-react/src/SearchBox.tsx similarity index 89% rename from packages/docsearch-react/src/SearchBox/SearchBox.tsx rename to packages/docsearch-react/src/SearchBox.tsx index 12b6b23e1..2189d9c62 100644 --- a/packages/docsearch-react/src/SearchBox/SearchBox.tsx +++ b/packages/docsearch-react/src/SearchBox.tsx @@ -4,10 +4,10 @@ import { AutocompleteState, } from '@francoischalifour/autocomplete-core'; -import { InternalDocSearchHit } from '../types'; -import { SearchIcon } from './SearchIcon'; -import { ResetIcon } from './ResetIcon'; -import { LoadingIcon } from './LoadingIcon'; +import { InternalDocSearchHit } from './types'; +import { SearchIcon } from './icons/SearchIcon'; +import { ResetIcon } from './icons/ResetIcon'; +import { LoadingIcon } from './icons/LoadingIcon'; interface SearchBoxProps extends AutocompleteApi< diff --git a/packages/docsearch-react/src/SearchBox/index.tsx b/packages/docsearch-react/src/SearchBox/index.tsx deleted file mode 100644 index ffc46c999..000000000 --- a/packages/docsearch-react/src/SearchBox/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './SearchBox'; diff --git a/packages/docsearch-react/src/SearchButton/SearchButton.tsx b/packages/docsearch-react/src/SearchButton.tsx similarity index 94% rename from packages/docsearch-react/src/SearchButton/SearchButton.tsx rename to packages/docsearch-react/src/SearchButton.tsx index 4179cda92..364b4fba5 100644 --- a/packages/docsearch-react/src/SearchButton/SearchButton.tsx +++ b/packages/docsearch-react/src/SearchButton.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from 'react'; -import { SearchIcon } from '../SearchBox/SearchIcon'; + +import { SearchIcon } from './icons/SearchIcon'; interface SearchButtonProps { onClick(): void; diff --git a/packages/docsearch-react/src/SearchButton/index.ts b/packages/docsearch-react/src/SearchButton/index.ts deleted file mode 100644 index 6f4ca0984..000000000 --- a/packages/docsearch-react/src/SearchButton/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './SearchButton'; diff --git a/packages/docsearch-react/src/Snippet.tsx b/packages/docsearch-react/src/Snippet.tsx index 807ca1d23..39d1ceae9 100644 --- a/packages/docsearch-react/src/Snippet.tsx +++ b/packages/docsearch-react/src/Snippet.tsx @@ -1,6 +1,6 @@ import { createElement } from 'react'; -import { InternalDocSearchHit } from './types'; +import { StoredDocSearchHit } from './types'; function getPropertyByPath(object: object, path: string): any { const parts = path.split('.'); @@ -8,25 +8,25 @@ function getPropertyByPath(object: object, path: string): any { return parts.reduce((current, key) => current && current[key], object); } -interface SnippetProps { +interface SnippetProps { [prop: string]: unknown; - hit: InternalDocSearchHit; + hit: TItem; attribute: string; tagName?: string; } -export function Snippet({ +export function Snippet({ hit, attribute, tagName = 'span', ...rest -}: SnippetProps) { +}: SnippetProps) { return createElement(tagName, { ...rest, dangerouslySetInnerHTML: { __html: getPropertyByPath(hit, `_snippetResult.${attribute}.value`) || - hit[attribute], + getPropertyByPath(hit, attribute), }, }); } diff --git a/packages/docsearch-react/src/icons/GoToExternalIcon.tsx b/packages/docsearch-react/src/icons/GoToExternalIcon.tsx new file mode 100644 index 000000000..4b47c7f84 --- /dev/null +++ b/packages/docsearch-react/src/icons/GoToExternalIcon.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +export function GoToExternal() { + return ( + + + + ); +} diff --git a/packages/docsearch-react/src/SearchBox/LoadingIcon.tsx b/packages/docsearch-react/src/icons/LoadingIcon.tsx similarity index 100% rename from packages/docsearch-react/src/SearchBox/LoadingIcon.tsx rename to packages/docsearch-react/src/icons/LoadingIcon.tsx diff --git a/packages/docsearch-react/src/icons/RecentIcon.tsx b/packages/docsearch-react/src/icons/RecentIcon.tsx new file mode 100644 index 000000000..51f7ba318 --- /dev/null +++ b/packages/docsearch-react/src/icons/RecentIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +export function RecentIcon() { + return ( + + + + + + + ); +} diff --git a/packages/docsearch-react/src/SearchBox/ResetIcon.tsx b/packages/docsearch-react/src/icons/ResetIcon.tsx similarity index 100% rename from packages/docsearch-react/src/SearchBox/ResetIcon.tsx rename to packages/docsearch-react/src/icons/ResetIcon.tsx diff --git a/packages/docsearch-react/src/SearchBox/SearchIcon.tsx b/packages/docsearch-react/src/icons/SearchIcon.tsx similarity index 100% rename from packages/docsearch-react/src/SearchBox/SearchIcon.tsx rename to packages/docsearch-react/src/icons/SearchIcon.tsx diff --git a/packages/docsearch-react/src/Results/ActionIcon.tsx b/packages/docsearch-react/src/icons/SelectIcon.tsx similarity index 53% rename from packages/docsearch-react/src/Results/ActionIcon.tsx rename to packages/docsearch-react/src/icons/SelectIcon.tsx index 3027c50d9..3835f0151 100644 --- a/packages/docsearch-react/src/Results/ActionIcon.tsx +++ b/packages/docsearch-react/src/icons/SelectIcon.tsx @@ -16,15 +16,3 @@ export function SelectIcon() { ); } - -export function GoToExternal() { - return ( - - - - ); -} diff --git a/packages/docsearch-react/src/Results/SourceIcon.tsx b/packages/docsearch-react/src/icons/SourceIcon.tsx similarity index 100% rename from packages/docsearch-react/src/Results/SourceIcon.tsx rename to packages/docsearch-react/src/icons/SourceIcon.tsx diff --git a/packages/docsearch-react/src/icons/StarIcon.tsx b/packages/docsearch-react/src/icons/StarIcon.tsx new file mode 100644 index 000000000..01d795b04 --- /dev/null +++ b/packages/docsearch-react/src/icons/StarIcon.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +export function StarIcon() { + return ( + + + + ); +} diff --git a/packages/docsearch-react/src/icons/index.ts b/packages/docsearch-react/src/icons/index.ts new file mode 100644 index 000000000..7f1f7c8b8 --- /dev/null +++ b/packages/docsearch-react/src/icons/index.ts @@ -0,0 +1,8 @@ +export * from './GoToExternalIcon'; +export * from './LoadingIcon'; +export * from './RecentIcon'; +export * from './ResetIcon'; +export * from './SearchIcon'; +export * from './SelectIcon'; +export * from './SourceIcon'; +export * from './StarIcon'; diff --git a/packages/docsearch-react/src/recent-searches.ts b/packages/docsearch-react/src/stored-searches.ts similarity index 50% rename from packages/docsearch-react/src/recent-searches.ts rename to packages/docsearch-react/src/stored-searches.ts index 0dbd32f9d..5e45ef4ba 100644 --- a/packages/docsearch-react/src/recent-searches.ts +++ b/packages/docsearch-react/src/stored-searches.ts @@ -1,4 +1,4 @@ -import { DocSearchHit, RecentDocSearchHit } from './types'; +import { DocSearchHit, StoredDocSearchHit } from './types'; function isLocalStorageSupported() { const key = '__TEST_KEY__'; @@ -13,7 +13,7 @@ function isLocalStorageSupported() { } } -function createStorage() { +function createStorage(key: string) { if (isLocalStorageSupported() === false) { return { setItem() {}, @@ -23,57 +23,67 @@ function createStorage() { }; } - const STORAGE_KEY = '__DOCSEARCH_RECENT_SEARCHES__'; - return { setItem(item: TItem[]) { - return window.localStorage.setItem(STORAGE_KEY, JSON.stringify(item)); + return window.localStorage.setItem(key, JSON.stringify(item)); }, getItem(): TItem[] { - const item = window.localStorage.getItem(STORAGE_KEY); + const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : []; }, }; } -export function createRecentSearches() { - const storage = createStorage(); +type CreateStoredSearchesOptions = { + key: string; + limit?: number; +}; + +export type StoredSearchPlugin = { + add(item: TItem): void; + remove(item: TItem): void; + getAll(): TItem[]; +}; + +export function createStoredSearches({ + key, + limit = 5, +}: CreateStoredSearchesOptions): StoredSearchPlugin { + const storage = createStorage(key); let items = storage.getItem(); return { - saveSearch(search: TItem) { + add(item: TItem) { const { _highlightResult, _snippetResult, - ...item - } = (search as unknown) as DocSearchHit; + ...hit + } = (item as unknown) as DocSearchHit; - if (item.type === 'content') { - return false; + if (hit.type === 'content') { + return; } const isQueryAlreadySaved = items.findIndex( - x => x.objectID === item.objectID + x => x.objectID === hit.objectID ); if (isQueryAlreadySaved > -1) { items.splice(isQueryAlreadySaved, 1); } - items.unshift(item as TItem); - items = items.slice(0, 5); + items.unshift(hit as TItem); + items = items.slice(0, limit); storage.setItem(items); - - return true; }, - deleteSearch(item: TItem) { + remove(item: TItem) { items = items.filter(x => x.objectID !== item.objectID); storage.setItem(items); }, - getSearches() { + getAll() { return items; }, }; diff --git a/packages/docsearch-react/src/style.css b/packages/docsearch-react/src/style.css index c4efc8474..6f0471d65 100644 --- a/packages/docsearch-react/src/style.css +++ b/packages/docsearch-react/src/style.css @@ -460,6 +460,10 @@ html[data-theme='dark'] { stroke-width: var(--docsearch-icon-stroke-width); } +.DocSearch-Hit-action + .DocSearch-Hit-action { + margin-left: 5px; +} + .DocSearch-Hit-action-button { appearance: none; background: none; diff --git a/packages/docsearch-react/src/types/RecentDocSearchHit.ts b/packages/docsearch-react/src/types/StoredDocSearchHit.ts similarity index 73% rename from packages/docsearch-react/src/types/RecentDocSearchHit.ts rename to packages/docsearch-react/src/types/StoredDocSearchHit.ts index e00c482b9..db41dbf4e 100644 --- a/packages/docsearch-react/src/types/RecentDocSearchHit.ts +++ b/packages/docsearch-react/src/types/StoredDocSearchHit.ts @@ -1,6 +1,6 @@ import { DocSearchHit } from './DocSearchHit'; -export type RecentDocSearchHit = Omit< +export type StoredDocSearchHit = Omit< DocSearchHit, '_highlightResult' | '_snippetResult' >; diff --git a/packages/docsearch-react/src/types/index.ts b/packages/docsearch-react/src/types/index.ts index 76849a249..93285bd19 100644 --- a/packages/docsearch-react/src/types/index.ts +++ b/packages/docsearch-react/src/types/index.ts @@ -1,3 +1,3 @@ export * from './DocSearchHit'; export * from './InternalDocSearchHit'; -export * from './RecentDocSearchHit'; +export * from './StoredDocSearchHit';