From f6565f321fdae20686043c2c5b9c6a2c16672b5f Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Wed, 31 May 2023 21:45:29 +0330 Subject: [PATCH] feat: implement search component --- .../src/client/components/Icon/Icon.tsx | 18 ++- .../src/client/components/Modal/Modal.scss | 81 +++++++++++ .../src/client/components/Modal/Modal.tsx | 53 ++++++++ .../src/client/components/Modal/index.ts | 1 + .../src/client/components/Portal/Portal.tsx | 4 +- .../src/client/lib/usePersistedHistory.ts | 46 +++++++ .../src/client/static/icons/close.svg | 5 + .../src/client/static/icons/document.svg | 4 +- .../src/client/static/icons/history.svg | 3 + .../theme/SearchBar/SearchBar.module.scss | 29 +++- .../src/client/theme/SearchBar/SearchBar.tsx | 126 ++++++++++++------ .../SearchHistory/SearchHistory.module.scss | 45 +++++++ .../SearchBar/SearchHistory/SearchHistory.tsx | 63 +++++++++ .../theme/SearchBar/SearchHistory/index.ts | 1 + .../SearchInput/SearchInput.module.scss | 84 ++---------- .../SearchBar/SearchInput/SearchInput.tsx | 63 +++------ .../SearchResultGroup.module.scss | 11 +- .../SearchResultGroup/SearchResultGroup.tsx | 3 +- .../SearchResultItem.module.scss | 4 +- .../SearchResultItemBase.module.scss | 23 ++-- .../SearchResultItemBase.tsx | 10 +- .../SearchResultMessage.module.scss | 12 ++ .../SearchResultMessage.tsx | 23 ++++ .../SearchBar/SearchResultMessage/index.ts | 1 + .../SearchResults/SearchResults.module.scss | 58 +++----- .../SearchBar/SearchResults/SearchResults.tsx | 33 ++--- .../SearchResultsContainer.module.scss | 31 ----- .../SearchResultsContainer.tsx | 34 ----- .../SearchBar/SearchResultsContainer/index.ts | 1 - .../src/client/theme/SearchBar/index.tsx | 5 +- 30 files changed, 553 insertions(+), 322 deletions(-) create mode 100644 packages/logos-docusaurus-theme/src/client/components/Modal/Modal.scss create mode 100644 packages/logos-docusaurus-theme/src/client/components/Modal/Modal.tsx create mode 100644 packages/logos-docusaurus-theme/src/client/components/Modal/index.ts create mode 100644 packages/logos-docusaurus-theme/src/client/lib/usePersistedHistory.ts create mode 100644 packages/logos-docusaurus-theme/src/client/static/icons/close.svg create mode 100644 packages/logos-docusaurus-theme/src/client/static/icons/history.svg create mode 100644 packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/SearchHistory.module.scss create mode 100644 packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/SearchHistory.tsx create mode 100644 packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/index.ts create mode 100644 packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/SearchResultMessage.module.scss create mode 100644 packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/SearchResultMessage.tsx create mode 100644 packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/index.ts delete mode 100644 packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/SearchResultsContainer.module.scss delete mode 100644 packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/SearchResultsContainer.tsx delete mode 100644 packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/index.ts diff --git a/packages/logos-docusaurus-theme/src/client/components/Icon/Icon.tsx b/packages/logos-docusaurus-theme/src/client/components/Icon/Icon.tsx index a8299c4..6636a7c 100644 --- a/packages/logos-docusaurus-theme/src/client/components/Icon/Icon.tsx +++ b/packages/logos-docusaurus-theme/src/client/components/Icon/Icon.tsx @@ -5,9 +5,11 @@ import React from 'react' import styles from './style.module.scss' import ArrowLCircleSvg from '../../static/icons/arrow-left-circle.svg' -import ArrowRCircleSvg from '../../static/icons/arrow-right-circle.svg' import ArrowL from '../../static/icons/arrow-left.svg' +import ArrowRCircleSvg from '../../static/icons/arrow-right-circle.svg' import ArrowR from '../../static/icons/arrow-right.svg' +import CloseSvg from '../../static/icons/close.svg' +import CopySvg from '../../static/icons/copy.svg' import DiscordSvg from '../../static/icons/discord.svg' import DiscourseSvg from '../../static/icons/discourse.svg' import DotSvg from '../../static/icons/dot.svg' @@ -15,12 +17,12 @@ import DropdownSvg from '../../static/icons/dropdown.svg' import FolderSvg from '../../static/icons/folder.svg' import GithubSvg from '../../static/icons/github.svg' import GScholarSvg from '../../static/icons/gscholar.svg' +import HistorySvg from '../../static/icons/history.svg' import LinkedinSvg from '../../static/icons/linkedin.svg' import SearchSvg from '../../static/icons/search.svg' import StatusSvg from '../../static/icons/status.svg' import TelegramSvg from '../../static/icons/telegram.svg' import TwitterSvg from '../../static/icons/twitter.svg' -import CopySvg from '../../static/icons/copy.svg' type TIconProps = { size?: 's' | 'm' | 'l' @@ -157,3 +159,15 @@ export const IconCopy = (props: TIconProps): JSX.Element => ( ) + +export const IconHistory = (props: TIconProps): JSX.Element => ( + + + +) + +export const IconClose = (props: TIconProps): JSX.Element => ( + + + +) diff --git a/packages/logos-docusaurus-theme/src/client/components/Modal/Modal.scss b/packages/logos-docusaurus-theme/src/client/components/Modal/Modal.scss new file mode 100644 index 0000000..7edfafe --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/components/Modal/Modal.scss @@ -0,0 +1,81 @@ +@use '../../css/utils'; + +.l-modal { + opacity: 0; + visibility: hidden; + transition: 0.3s; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100vh; + z-index: 9999; +} + +.l-modal__container { + max-width: 1376px; + margin: 0 auto; + + display: grid; + grid-template-columns: repeat(24, 1fr); + gap: 1rem; + overflow: auto; +} + +.l-modal--open { + opacity: 1; + visibility: visible; +} + +.l-modal__content { + z-index: 9998; + grid-column: 8 / 19; + background: rgb(var(--lsd-surface-primary)); + + border: 1px solid rgb(var(--lsd-border-primary)); + padding: 7px; + height: fit-content; + margin: 64px 0; + max-height: 80vh; +} + +.l-modal__backdrop { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(var(--lsd-surface-primary), 0.6); + z-index: 9997; +} + +@include utils.responsive('lg', 'down') { + .l-modal { + width: 100vw; + overflow: hidden; + } + + .l-modal__container { + width: 100%; + max-width: unset; + display: grid; + grid-template-columns: 1fr; + height: 100vh; + min-height: -webkit-fill-available; + } + + .l-modal__content { + grid-column: 1 / 2; + grid-row: 1 / 2; + margin: 0; + border: none; + height: 100vh; + max-height: 100vh; + overflow: hidden; + height: 100%; + } + + .l-modal__backdrop { + display: none; + } +} diff --git a/packages/logos-docusaurus-theme/src/client/components/Modal/Modal.tsx b/packages/logos-docusaurus-theme/src/client/components/Modal/Modal.tsx new file mode 100644 index 0000000..e1d69e8 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/components/Modal/Modal.tsx @@ -0,0 +1,53 @@ +import { useLockBodyScroll } from '@docusaurus/theme-common/internal' +import clsx from 'clsx' +import React from 'react' +import { useKeyPressEvent } from 'react-use' +import { useHydrated } from '../../lib/useHydrated' +import { Portal } from '../Portal/Portal' +import './Modal.scss' + +export type ModalProps = React.HTMLAttributes & { + open?: boolean + onClose?: () => void + keepMounted?: boolean +} + +export const Modal: React.FC = ({ + open = false, + onClose, + keepMounted = false, + className, + children, + ...props +}) => { + const hydrated = useHydrated() + + const handleClose = () => { + onClose && onClose() + } + + useLockBodyScroll(open) + useKeyPressEvent( + (key) => key.code === 'Escape', + (event) => { + handleClose() + }, + ) + + if (!hydrated) return <> + if (!open && !keepMounted) return <> + + return ( + +
+
+
{children}
+
+
+
+ + ) +} diff --git a/packages/logos-docusaurus-theme/src/client/components/Modal/index.ts b/packages/logos-docusaurus-theme/src/client/components/Modal/index.ts new file mode 100644 index 0000000..8d3bcd7 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/components/Modal/index.ts @@ -0,0 +1 @@ +export * from './Modal' diff --git a/packages/logos-docusaurus-theme/src/client/components/Portal/Portal.tsx b/packages/logos-docusaurus-theme/src/client/components/Portal/Portal.tsx index 5c3eec8..5bb293f 100644 --- a/packages/logos-docusaurus-theme/src/client/components/Portal/Portal.tsx +++ b/packages/logos-docusaurus-theme/src/client/components/Portal/Portal.tsx @@ -18,5 +18,7 @@ export const Portal: React.FC> = ({ const portalElement = usePortal({ parentId: containerId }) - return createPortal(children, portalElement, id) + const portal = createPortal(children, portalElement, id) + + return portal } diff --git a/packages/logos-docusaurus-theme/src/client/lib/usePersistedHistory.ts b/packages/logos-docusaurus-theme/src/client/lib/usePersistedHistory.ts new file mode 100644 index 0000000..9deceb0 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/lib/usePersistedHistory.ts @@ -0,0 +1,46 @@ +import { useLocalStorage } from 'react-use' + +export const usePersistedHistory = ( + key: string, + options?: { + equals?: (a: T, b: T) => boolean + unique?: boolean + }, +) => { + const unique = options?.unique ?? false + const equals = options?.equals ?? ((a, b) => a === b) + + const [history, setHistory] = useLocalStorage( + 'logos-docusaurus-theme-' + key, + [], + ) + + const add = (value: T) => { + const arr = history ?? [] + setHistory([ + value, + ...(unique ? arr.filter((item) => !equals(item, value)) : arr), + ]) + } + + const remove = (rm: (item: T, index: number) => boolean) => { + const arr = history ?? [] + setHistory(arr.filter((item, index) => !rm(item, index))) + } + + const removeByIndex = (index: number) => { + remove((item, idx) => idx === index) + } + + const clear = () => { + setHistory([]) + } + + return { + add, + clear, + remove, + removeByIndex, + list: history, + } +} diff --git a/packages/logos-docusaurus-theme/src/client/static/icons/close.svg b/packages/logos-docusaurus-theme/src/client/static/icons/close.svg new file mode 100644 index 0000000..c247608 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/static/icons/close.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/logos-docusaurus-theme/src/client/static/icons/document.svg b/packages/logos-docusaurus-theme/src/client/static/icons/document.svg index df2985f..248ad06 100644 --- a/packages/logos-docusaurus-theme/src/client/static/icons/document.svg +++ b/packages/logos-docusaurus-theme/src/client/static/icons/document.svg @@ -1,3 +1,3 @@ - - + + diff --git a/packages/logos-docusaurus-theme/src/client/static/icons/history.svg b/packages/logos-docusaurus-theme/src/client/static/icons/history.svg new file mode 100644 index 0000000..b210843 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/static/icons/history.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchBar.module.scss b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchBar.module.scss index b672e06..2197c2f 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchBar.module.scss +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchBar.module.scss @@ -1,11 +1,32 @@ @use '../../css/utils'; -.root { - position: relative; +.modal { + > div > div:first-child { + padding: 0; + } + + .closeButton { + display: none; + } + + .header { + display: flex; + flex-direction: row; + align-items: center; + gap: 0.5rem; + } } @include utils.responsive('lg', 'down') { - .root { - position: unset; + .modal { + .header { + padding: 12px 16px; + } + + .closeButton { + display: block; + width: 2rem; + height: 2rem; + } } } diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchBar.tsx b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchBar.tsx index ad460e0..2a36110 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchBar.tsx +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchBar.tsx @@ -1,49 +1,49 @@ -import { useLocation } from '@docusaurus/router' -import clsx from 'clsx' +import { CloseIcon, IconButton, SearchIcon } from '@acid-info/lsd-react' import React, { useEffect, useRef, useState } from 'react' +import { Modal } from '../../components/Modal/Modal' +import { usePersistedHistory } from '../../lib/usePersistedHistory' +import { useWindowEventListener } from '../../lib/useWindowEventListener' import { useSearch } from './hooks/useSearch' import styles from './SearchBar.module.scss' -import { SearchInput } from './SearchInput' -import { SearchResults } from './SearchResults' -import { SearchResultsContainer } from './SearchResultsContainer' -import { SearchResult } from './types' +import { SearchHistory } from './SearchHistory/SearchHistory' +import { SearchInput } from './SearchInput/SearchInput' +import { SearchResults } from './SearchResults/SearchResults' +import { SearchResult, SearchResultGroupItem } from './types' export const SearchBar: React.FC<{}> = ({}) => { + const history = usePersistedHistory('search', { + unique: true, + equals: (a, b) => a.title === b.title && a.href === b.href, + }) const search = useSearch() const ref = useRef(null) - const inputRef = useRef(null) - - const location = useLocation() const [input, setInput] = useState('') const [results, setResults] = useState([]) - const [showResultsContainer, setShowResultsContainer] = useState(false) + const [displayModal, setDisplayModal] = useState(false) const onInputChange = (e: React.ChangeEvent) => { setInput(e.target.value) } - const onInputFocus = () => { - setShowResultsContainer(true) - } + const focusOnInput = () => { + const el = ref.current + if (!el) return - const onInputCancel = () => { - setShowResultsContainer(false) - } - - const onClickOutsideResultsContainer = (event: Event) => { - if (!event.composedPath().find((el) => el === ref.current)) onInputCancel() + const inputEl = el.querySelector('input') + if (inputEl) + setTimeout(() => { + inputEl.focus() + }, 50) } const onClear = () => { setInput('') - inputRef.current && inputRef.current.focus() } const query = async (input: string) => { const { results } = await search.query(input) setResults(results) - setShowResultsContainer(true) } useEffect(() => { @@ -52,31 +52,69 @@ export const SearchBar: React.FC<{}> = ({}) => { }, [input]) useEffect(() => { - if (showResultsContainer) { - setShowResultsContainer(false) - } - }, [location.key]) + displayModal ? focusOnInput() : setInput('') + }, [displayModal]) + + const onNavigate = ( + e: React.MouseEvent, + item: SearchResultGroupItem, + ) => { + e.preventDefault() + setDisplayModal(false) + history.add(item) + window.location.href = item.href + } + + useWindowEventListener( + 'keydown', + (event) => { + if ((event.ctrlKey || event.metaKey) && event.code === 'KeyK') { + event.preventDefault() + setDisplayModal(true) + } + }, + {}, + [], + ) return ( -
- - 0} - inputRef={inputRef} - onClickOutside={onClickOutsideResultsContainer} + <> + setDisplayModal(true)} size="medium"> + + + setDisplayModal(false)} + className={styles.modal} > - - -
+
+ + setDisplayModal(false)} + > + + +
+ {input.length > 0 && ( + + )} + {input.length === 0 && ( + setDisplayModal(false)} + /> + )} + + ) } diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/SearchHistory.module.scss b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/SearchHistory.module.scss new file mode 100644 index 0000000..1d89225 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/SearchHistory.module.scss @@ -0,0 +1,45 @@ +@use '../../../css/utils'; + +.root { + padding: 24px; + max-height: 60vh; + overflow-y: auto; +} + +.root.empty { + padding: 0; +} + +.title { + font-size: 0.75rem !important; +} + +.item { + margin-top: 1rem; + display: flex; + flex-direction: row; + align-items: center; + + .itemTitle { + flex-grow: 1; + padding-left: 1rem; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + + mark { + background: none; + color: inherit; + } + } +} + +@include utils.responsive('lg', 'down') { + .root { + overflow: auto; + height: 100%; + max-height: 100%; + padding: 24px 24px; + padding-bottom: 64px; + } +} diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/SearchHistory.tsx b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/SearchHistory.tsx new file mode 100644 index 0000000..13b0cdf --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/SearchHistory.tsx @@ -0,0 +1,63 @@ +import { Typography } from '@acid-info/lsd-react' +import clsx from 'clsx' +import React from 'react' +import { IconClose, IconHistory } from '../../../components/Icon/Icon' +import { SearchResultMessage } from '../SearchResultMessage/SearchResultMessage' +import { SearchResultGroupItem } from '../types' +import styles from './SearchHistory.module.scss' + +export type SearchHistoryProps = React.HTMLProps & { + history: SearchResultGroupItem[] + onRemove: (index: number) => void + onClose?: () => void +} + +export const SearchHistory: React.FC = ({ + history: list = [], + onRemove, + onClose, + className, + children, + ...props +}) => { + return ( +
+ {list.length === 0 ? ( + No recent searches + ) : ( + <> + + Recent + + {list.map((item, index) => ( +
+ + onClose && onClose()} + /> + +
+ ))} + + )} +
+ ) +} diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/index.ts b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/index.ts new file mode 100644 index 0000000..9802537 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchHistory/index.ts @@ -0,0 +1 @@ +export * from './SearchHistory' diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchInput/SearchInput.module.scss b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchInput/SearchInput.module.scss index 1b205cf..907a8a1 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchInput/SearchInput.module.scss +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchInput/SearchInput.module.scss @@ -5,96 +5,30 @@ .root { width: auto; position: relative; + width: 100%; + padding: 8px; + padding-bottom: 0; + box-sizing: border-box; +} + +.textField { + width: 100% !important; } .root input { - width: 134px; - - border: 0; - border-radius: 8px; - background: rgb(var(--lsd-surface-primary)); - - padding: 9px 48px 9px 16px; - - transition: 0.2s; - - &:focus { - outline: none; - } } .root.expanded input { - background: rgb(var(--lsd-surface-primary)); - width: 334px; } .root.expanded .label { - display: none; -} - -.label { - position: absolute; - left: 16px; - top: 50%; - transform: translateY(-50%); - - color: #747475; - font-size: 0.875rem; - pointer-events: none; -} - -.shortcuts { - position: absolute; - right: 16px; - top: 50%; - transform: translateY(-50%); - line-height: 0; - pointer-events: none; - - & > kbd { - margin-left: 0.375rem; - } - - kbd { - background: none; - border: none; - padding: 0; - color: #bababa; - box-shadow: none; - font-size: 0.75rem; - } } [data-theme='dark'] { - .root input { - color: rgb(var(--lsd-text-primary)); - } - - .root.expanded input { - background-color: rgb(var(--lsd-surface-primary)); - } } @include utils.responsive('lg', 'down') { - .shortcuts { - display: none; - } - .root { - width: 100%; - } - - .root input { - width: 100%; - border-radius: 12px; - background: #eeeef0; - } - - .root.expanded input { - width: 100%; - } - - .label { - display: none; + padding: 0; } } diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchInput/SearchInput.tsx b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchInput/SearchInput.tsx index 8e5f47e..c0af2e1 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchInput/SearchInput.tsx +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchInput/SearchInput.tsx @@ -1,88 +1,65 @@ -import { useOS } from '@logos-theme/lib/useOS' -import { useWindowEventListener } from '@logos-theme/lib/useWindowEventListener' +import { SearchIcon, TextField } from '@acid-info/lsd-react' import clsx from 'clsx' import React from 'react' import { useMedia } from 'react-use' import styles from './SearchInput.module.scss' -import { Typography } from '@acid-info/lsd-react' export type SearchInputProps = Omit< React.HTMLProps, 'value' | 'onChange' > & Pick, 'onChange'> & { - inputProps?: Omit, 'ref'> & { - ref: React.RefObject - } + inputProps?: React.HTMLProps + containerRef?: React.RefObject value?: string active?: boolean onFocus?: () => void onCancel?: () => void + onClear?: () => void } export const SearchInput: React.FC = ({ value = '', active, onChange, + onClear, onFocus: onFocusCallback, onCancel, className, inputProps: { ref: inputRef, ...inputProps } = { placeholder: '' }, + containerRef, ...props }) => { - const os = useOS() const isMobile = useMedia('(max-width: 996px)') const expanded = active || value?.length > 0 - const focus = () => { - inputRef?.current && inputRef.current.focus() - } - - const blur = () => { - inputRef?.current && inputRef.current.blur() - onCancel && onCancel() - } - - useWindowEventListener('keydown', (event) => { - if ((event.ctrlKey || event.metaKey) && event.code === 'KeyK') { - event.preventDefault() - focus() - } else if (event.code === 'Escape') { - blur() - } - }) - const onFocus = (event: React.FocusEvent) => { onFocusCallback && onFocusCallback() } return (
{ + if (e.code === 'Escape' && value.length > 0) { + e.stopPropagation() + onClear && onClear() + } + }} {...props} > - - Search - - } + {...(inputProps as any)} /> -
- {active ? ( - esc - ) : ( - <> - {os === 'mac' ? '⌘' : 'ctrl'} - k - - )} -
) } diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultGroup/SearchResultGroup.module.scss b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultGroup/SearchResultGroup.module.scss index 489f853..654a3e3 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultGroup/SearchResultGroup.module.scss +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultGroup/SearchResultGroup.module.scss @@ -1,17 +1,20 @@ .root { & > div:first-child { - padding: 0 14px; - font-size: 0.75rem; - font-weight: bold; + padding: 0 24px; color: #828285; + + &, + * { + font-size: 0.75rem; + } } ul { - margin-top: 16px; padding: 0; } ul li { list-style: none; + margin-top: 1rem; } } diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultGroup/SearchResultGroup.tsx b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultGroup/SearchResultGroup.tsx index f51ebec..a22b629 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultGroup/SearchResultGroup.tsx +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultGroup/SearchResultGroup.tsx @@ -1,3 +1,4 @@ +import { Typography } from '@acid-info/lsd-react' import clsx from 'clsx' import React from 'react' import styles from './SearchResultGroup.module.scss' @@ -15,7 +16,7 @@ export const SearchResultGroup: React.FC = ({ return (
- {title} + {title}
    {children}
diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItem/SearchResultItem.module.scss b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItem/SearchResultItem.module.scss index b7da2a6..ee93faa 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItem/SearchResultItem.module.scss +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItem/SearchResultItem.module.scss @@ -3,11 +3,13 @@ } .icon { + width: 16px; + height: auto; + &.l1 { } &.l2 { - opacity: 0.6; } &.fill { diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItemBase/SearchResultItemBase.module.scss b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItemBase/SearchResultItemBase.module.scss index 8ea62ea..404f740 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItemBase/SearchResultItemBase.module.scss +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItemBase/SearchResultItemBase.module.scss @@ -3,26 +3,21 @@ .root { display: flex; align-items: center; - padding: 12px; + padding: 0 24px; + + > span { + svg { + vertical-align: middle; + } + } mark { - color: #3165b4; + color: inherit; background: none; } & > div { - margin-left: 26px; - - & > div { - color: #373738; - font-size: 0.875rem; - } - - & > p { - color: #828285; - font-size: 0.625rem; - margin: 0; - } + margin-left: 1rem; } } diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItemBase/SearchResultItemBase.tsx b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItemBase/SearchResultItemBase.tsx index 83f8de2..4642352 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItemBase/SearchResultItemBase.tsx +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultItemBase/SearchResultItemBase.tsx @@ -1,3 +1,4 @@ +import { Typography } from '@acid-info/lsd-react' import clsx from 'clsx' import React from 'react' import styles from './SearchResultItemBase.module.scss' @@ -19,8 +20,13 @@ export const SearchResultItemBase: React.FC = ({
  • {icon}
    - {title &&
    } - {content &&

    } + {title && ( + + )}

  • ) diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/SearchResultMessage.module.scss b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/SearchResultMessage.module.scss new file mode 100644 index 0000000..36f2043 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/SearchResultMessage.module.scss @@ -0,0 +1,12 @@ +@use '../../../css/utils'; + +.root { + text-align: center; + padding: 32px; +} + +@include utils.responsive('lg', 'down') { + .root { + padding: 40px 24px; + } +} diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/SearchResultMessage.tsx b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/SearchResultMessage.tsx new file mode 100644 index 0000000..5997b30 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/SearchResultMessage.tsx @@ -0,0 +1,23 @@ +import { Typography, TypographyProps } from '@acid-info/lsd-react' +import clsx from 'clsx' +import React from 'react' +import styles from './SearchResultMessage.module.scss' + +export type SearchResultMessageProps = TypographyProps & {} + +export const SearchResultMessage: React.FC = ({ + className, + children, + ...props +}) => { + return ( + + {children} + + ) +} diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/index.ts b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/index.ts new file mode 100644 index 0000000..f1c3030 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultMessage/index.ts @@ -0,0 +1 @@ +export * from './SearchResultMessage' diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResults/SearchResults.module.scss b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResults/SearchResults.module.scss index be53fc3..87b34fe 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResults/SearchResults.module.scss +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResults/SearchResults.module.scss @@ -1,51 +1,22 @@ +@use '../../../css/utils'; // TODO: use ifm variables .root { - padding: 0; -} - -.divider { - width: 100%; - padding: 0 14px; - - & > div { - height: 1px; - background-color: #ededed; - } -} - -.topBar { - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - padding: 14px; - - span, - button { - font-size: 0.75rem; - font-weight: bold; - color: #c0c0c2; - } - - button { - color: #909091; - background: #eeeef1; - padding: 4px 12px; - border-radius: 8px; - } + padding: 24px 0; } .noResults { - color: #909091; + padding: 0; } .groups { - max-height: 500px; + max-height: 60vh; overflow-y: auto; + display: flex; + flex-direction: column; + gap: 16px; .group { - margin: 16px 0; } .divider:last-child { @@ -66,3 +37,18 @@ } } } + +@include utils.responsive('lg', 'down') { + .groups { + max-height: unset; + overflow: auto; + } + + .root { + overflow: auto; + height: 100%; + padding: 0; + padding-top: 24px; + padding-bottom: 64px; + } +} diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResults/SearchResults.tsx b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResults/SearchResults.tsx index 0a4bc2b..2a86832 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResults/SearchResults.tsx +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResults/SearchResults.tsx @@ -1,46 +1,32 @@ import clsx from 'clsx' -import React, { MutableRefObject, useMemo } from 'react' +import React, { useMemo } from 'react' import { SearchResultGroup } from '../SearchResultGroup' import { SearchResultItem } from '../SearchResultItem' -import { SearchResult } from '../types' +import { SearchResultMessage } from '../SearchResultMessage/SearchResultMessage' +import { SearchResult, SearchResultGroupItem } from '../types' import { groupSearchResult } from '../utils/groupSearchResult' import styles from './SearchResults.module.scss' -const divider = ( -
    -
    -
    -) - export type SearchResultsProps = Omit< React.HTMLProps, 'results' > & { - inputRef?: MutableRefObject results: SearchResult[] - onClear: () => void + onNavigate?: (e: React.MouseEvent, item: SearchResultGroupItem) => void } export const SearchResults: React.FC = ({ results, - onClear, className, + onNavigate, ...props }) => { const total = results.length const grouped = useMemo(() => groupSearchResult(results), [results]) return ( -
    -
    - {total} results - -
    - - {divider} - +
    + {total === 0 && No result.}
    {grouped.map(([category, items], index) => ( @@ -52,11 +38,12 @@ export const SearchResults: React.FC = ({ href={item.href} title={item.title} content={item.content} + linkProps={ + onNavigate ? { onClick: (e) => onNavigate(e, item) } : {} + } /> ))} - - {divider} ))}
    diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/SearchResultsContainer.module.scss b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/SearchResultsContainer.module.scss deleted file mode 100644 index 4095b72..0000000 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/SearchResultsContainer.module.scss +++ /dev/null @@ -1,31 +0,0 @@ -@use '../../../css/utils'; - -.root { - background-color: rgb(var(--lsd-surface-primary)); - border-radius: 1rem; - - left: 0; - top: 100%; - position: absolute; - - margin-top: 16px; - - width: 100%; - - opacity: 0; - visibility: hidden; - transition: 0.2s; - - &.visible { - opacity: 1; - visibility: visible; - } -} - -@include utils.responsive('lg', 'down') { - .root { - width: 100%; - margin-top: 0; - border-radius: 0; - } -} diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/SearchResultsContainer.tsx b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/SearchResultsContainer.tsx deleted file mode 100644 index d0e2697..0000000 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/SearchResultsContainer.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import clsx from 'clsx' -import React, { RefObject, useRef } from 'react' -import { useClickAway } from 'react-use' -import styles from './SearchResultsContainer.module.scss' - -export type SearchResultsContainerProps = React.HTMLProps & { - visible?: boolean - inputRef?: RefObject - onClickOutside: (event: Event) => void -} - -export const SearchResultsContainer: React.FC = ({ - visible, - inputRef, - className, - onClickOutside, - children, - ...props -}) => { - const ref = useRef(null) - - useClickAway(ref, (event) => { - onClickOutside(event) - }) - - return ( -
    - {children} -
    - ) -} diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/index.ts b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/index.ts deleted file mode 100644 index 5ff8ed0..0000000 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/SearchResultsContainer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './SearchResultsContainer' diff --git a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/index.tsx b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/index.tsx index d948395..69799e3 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/SearchBar/index.tsx +++ b/packages/logos-docusaurus-theme/src/client/theme/SearchBar/index.tsx @@ -6,10 +6,7 @@ const SearchBarWrapper: React.FC = () => { const activePlugin = useActivePlugin() if (!activePlugin) return <> - // temporarily disable search bar - return <> - - // return typeof window === 'undefined' ? <> : + return typeof window === 'undefined' ? <> : } export default SearchBarWrapper