tldraw/apps/docs/components/Search.tsx
Steve Ruiz 538734782c
[docs] Autocomplete styling tweaks (#2732)
This PR tweaks the styling in the autocomplete. It removes icons and
matches styles to the sidebar. It improves the mobile design to hide the
search bar on mobile.

### Change Type

- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [x] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
2024-02-05 20:46:07 +00:00

113 lines
3.3 KiB
TypeScript

'use client'
import { SEARCH_TYPE, SearchResult } from '@/types/search-types'
import { debounce } from '@/utils/debounce'
import { useRouter } from 'next/navigation'
import { useEffect, useRef, useState } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { Autocomplete, DropdownOption } from './Autocomplete'
const HOST_URL =
process.env.NODE_ENV === 'development'
? 'http://localhost:3001'
: process.env.NEXT_PUBLIC_SITE_URL ?? 'https://tldraw.dev'
export function Search() {
const [searchType, setSearchType] = useState<SEARCH_TYPE>(SEARCH_TYPE.NORMAL)
const [isLoading, setIsLoading] = useState(false)
const [searchResults, setSearchResults] = useState<DropdownOption[]>([])
const [query, setQuery] = useState('')
const [platform, setPlatform] = useState<'mac' | 'nonMac' | null>()
const rInput = useRef<HTMLInputElement>(null)
const router = useRouter()
const handleInputChange = debounce((query: string) => setQuery(query), 200)
useEffect(() => {
async function handleFetchResults() {
if (!query) {
return
}
setIsLoading(true)
try {
const endPoint =
searchType === SEARCH_TYPE.AI
? `${HOST_URL}/api/ai?q=${query}`
: `${HOST_URL}/api/search?q=${query}`
const res = await fetch(endPoint)
if (res.ok) {
const json = await res.json()
const topArticles = json.results.articles.slice(0, 10)
const topAPI = json.results.apiDocs.slice(0, 10)
const topExamples = json.results.examples.slice(0, 10)
const allResults = topExamples.concat(topArticles).concat(topAPI)
setSearchResults(
allResults.map((result: SearchResult) => ({
label: result.title,
value: result.url,
group: result.sectionType,
}))
)
}
} catch (err) {
console.error(err)
}
setIsLoading(false)
}
handleFetchResults()
}, [query, searchType])
const handleChange = (url: string) => {
router.push(url.startsWith('/') ? url : `/${url}`)
}
const handleSearchTypeChange = () => {
setSearchType(searchType === SEARCH_TYPE.AI ? SEARCH_TYPE.NORMAL : SEARCH_TYPE.AI)
handleInputChange(query)
}
useEffect(() => {
setPlatform(
// TODO(mime): we should have a standard hook for this.
// And also, we should navigator.userAgentData.platform where available.
// eslint-disable-next-line deprecation/deprecation
typeof window !== 'undefined' && /mac/i.test(window.navigator.platform) ? 'mac' : 'nonMac'
)
}, [])
useHotkeys('meta+k,ctrl+k', (e) => {
e.preventDefault()
rInput.current?.focus()
rInput.current?.select()
})
return (
<div className="search__wrapper">
<Autocomplete
ref={rInput}
customUI={
<button className="search__ai-toggle" onClick={handleSearchTypeChange}>
{searchType === SEARCH_TYPE.NORMAL ? '✨ Search using AI' : '⭐ Search without AI'}
</button>
}
groups={['examples', 'docs', 'reference']}
groupsToLabel={{ examples: 'Examples', docs: 'Articles', reference: 'Reference' }}
options={searchResults}
isLoading={isLoading}
onInputChange={handleInputChange}
onChange={handleChange}
/>
{platform && (
<span className="search__keyboard">
{platform === 'mac' && <kbd data-platform="mac"></kbd>}
{platform === 'nonMac' && <kbd data-platform="win">Ctrl</kbd>}
<kbd>K</kbd>
</span>
)}
</div>
)
}