1
0
Fork 0

feat(dev): Re-implemented search

This commit is contained in:
Joost De Cock 2023-05-24 16:18:59 +02:00
parent 483daa10d7
commit b3b5d225b8
10 changed files with 230 additions and 236 deletions

View file

@ -236,6 +236,7 @@ dev:
'react-dom': *react
'react-hotkeys-hook': &reactHotkeysHook '4.4.0'
'react-instantsearch-dom': &reactInstantsearchDom '6.40.0'
'react-instantsearch-hooks-web': '6.44.0'
'react-markdown': &reactMarkdown '8.0.7'
'react-swipeable': &reactSwipeable '7.0.0'
'react-timeago': &reactTimeago '7.1.0'
@ -400,3 +401,4 @@ shared:
'web-worker': '1.2.0'
dev:
'recursive-readdir': '^2.2.3'
'html-to-text': '^9.0.5'

View file

@ -16,7 +16,7 @@ export const DocsLayout = ({ children = [], pageTitle = false }) => {
{title && (
<div className="xl:pl-4">
<Breadcrumbs crumbs={crumbs} title={pageTitle ? pageTitle : title} />
<h1 className="break-words">{pageTitle ? pageTitle : title}</h1>
<h1 className="break-words searchme">{pageTitle ? pageTitle : title}</h1>
</div>
)}
<div className="xl:pl-4">{children}</div>

View file

@ -1,64 +1,10 @@
// Hooks
import { useState, useRef } from 'react'
import { useRouter } from 'next/router'
import { useHotkeys } from 'react-hotkeys-hook'
// Dependencies
import algoliasearch from 'algoliasearch/lite'
import {
InstantSearch,
connectHits,
connectHighlight,
connectSearchBox,
} from 'react-instantsearch-dom'
import config from 'site/algolia.config.mjs'
// Components
import { InstantSearch, SearchBox, Hits, Highlight, Snippet } from 'react-instantsearch-hooks-web'
import { siteConfig } from 'site/site.config.mjs'
import Link from 'next/link'
import { CloseIcon } from 'shared/components/icons.mjs'
import { ClearIcon } from 'shared/components/icons.mjs'
export const ns = ['search']
const searchClient = algoliasearch(config.algolia.app, config.algolia.key)
const Hits = (props) => {
// When we hit enter in the text field, we want to navigate to the result
// which means we must make the result links available in the input somehow
// so let's stuff them in a data attribute
const links = props.hits.map((hit) => hit.page)
props.input.current.setAttribute('data-links', JSON.stringify(links))
return props.hits.map((hit, index) => (
<Hit
key={hit.page}
{...props}
hit={hit}
index={index}
len={props.hits.length}
activeLink={links[props.active]}
/>
))
}
const CustomHits = connectHits(Hits)
const Highlight = ({ highlight, attribute, hit, snippet = false }) => {
const parsedHit = highlight({
highlightProperty: snippet ? '_snippetResult' : '_highlightResult',
attribute,
hit,
})
return parsedHit.map((part, index) =>
part.isHighlighted ? (
<mark className="text-base-content bg-secondary-focus bg-opacity-30" key={index}>
{part.value}
</mark>
) : (
<span key={index}>{part.value}</span>
)
)
}
const CustomHighlight = connectHighlight(Highlight)
const searchClient = algoliasearch(siteConfig.algolia.app, siteConfig.algolia.key)
const Hit = (props) => (
<div
@ -67,152 +13,55 @@ const Hit = (props) => (
text-base text-base-content
sm:rounded
lg:px-4 lg:py-2
hover:bg-secondary hover:bg-opacity-10 hover:text-base-content
${props.index === props.active ? 'bg-secondary bg-opacity-30' : 'bg-base-300 bg-opacity-10'}
border border-solid border-secondary
bg-secondary bg-opacity-10
hover:bg-secondary hover:bg-opacity-30
`}
>
<Link href={props.hit.page} className="flex flex-row justify-between gap-2">
<span className="text-base sm:text-xl font-bold leading-5">
{props.hit._highlightResult?.title ? (
<CustomHighlight hit={props.hit} attribute="title" />
<Highlight hit={props.hit} attribute="title" />
) : (
props.hit.title
)}
</span>
<span className="text-xs pt-0.5 sm:text-base sm:pt-1 font-bold uppercase">
<div>
<badge className="badge badge-primary uppercase mr-1 badge-sm">{props.hit.type}</badge>
<badge className="badge badge-secondary uppercase badge-sm">
{props.hit.page.split('/')[1]}
</span>
</badge>
</div>
</Link>
{props.hit._snippetResult?.body && (
{props.hit._snippetResult?.body?.value ? (
<Link href={props.hit.page} className="text-sm sm:text-base block py-1">
<CustomHighlight hit={props.hit} attribute="body" snippet />
<Snippet hit={props.hit} attribute="body" />
</Link>
)}
{props.hit?._highlightResult?.page && (
) : (
<Link href={props.hit.page} className="text-xs sm:text-sm block opacity-70">
<CustomHighlight hit={props.hit} attribute="page" />
<Highlight hit={props.hit} attribute="body" />
</Link>
)}
</div>
)
// We use this for trapping ctrl-c
const handleInputKeydown = (evt, setSearch, setActive, active, router) => {
if (evt.key === 'Escape') setSearch(false)
if (evt.key === 'ArrowDown') setActive((act) => act + 1)
if (evt.key === 'ArrowUp') setActive((act) => act - 1)
if (evt.key === 'Enter') {
// Trigger navigation
if (evt.target?.dataset?.links) {
router.push(JSON.parse(evt.target.dataset.links)[active])
setSearch(false)
}
}
}
const SearchBox = (props) => {
const input = useRef(null)
const router = useRouter()
useHotkeys('ctrl+x', () => {
input.current.value = ''
})
if (input.current && props.active < 0) input.current.focus()
const { currentRefinement, refine, setSearch, setActive } = props
export const Search = () => {
return (
<div className="py-8">
<form noValidate action="" role="search" onSubmit={(evt) => evt.preventDefault()}>
<div className="form-control">
<div className="relative">
<input
ref={input}
type="search"
<InstantSearch indexName={siteConfig.algolia.index} searchClient={searchClient}>
<SearchBox
searchAsYouType={true}
autoFocus={true}
value={currentRefinement}
onChange={(event) => refine(event.currentTarget.value)}
onKeyDown={(evt) =>
handleInputKeydown(evt, setSearch, setActive, props.active, router)
}
className="input lg:input-lg input-bordered input-neutral w-full pr-16"
placeholder="Type to search"
classNames={{
root: 'relative mb-4',
input: 'input lg:input-lg input-bordered input-neutral w-full pr-16',
reset:
'absolute right-0 top-0 rounded-l-none btn btn-neutral lg:btn-lg text-neutral-content',
submit: 'absolute right-0 top-0 rounded-l-none btn btn-neutral lg:btn-lg',
}}
resetIconComponent={() => <ClearIcon />}
/>
<button
className="absolute right-0 top-0 rounded-l-none btn btn-neutral lg:btn-lg"
onClick={() => props.setSearch(false)}
>
X
</button>
</div>
<label className="label hidden sm:block">
<div className="label-text flex flex-row gap-4 justify-between">
<div>
<b> Escape</b> to exit
</div>
<div>
<b> Up</b> or <b>Down</b> to select
</div>
<div>
<b> Enter</b> to navigate
</div>
</div>
</label>
</div>
<div
className="overscroll-auto overflow-y-auto mt-2"
style={{ maxHeight: 'calc(100vh - 10rem)' }}
>
{input.current && input.current.value.length > 0 && (
<CustomHits hitComponent={Hit} {...props} input={input} />
)}
</div>
</form>
<div
className={`
bg-neutral text-neutral-content
z-20 w-full mx-auto
lg:bg-base-100 lg:border-base-200
fixed bottom-0 left-0 border-t-2
lg:hidden
`}
>
<div className="px-4 py-0 flex flex-row w-full lg:py-2">
<button className={`btn btn-ghost btn-block`} onClick={() => props.setSearch(false)}>
<span className="px-2 pt-2 pb-2">
<CloseIcon />
</span>
</button>
</div>
</div>
</div>
)
}
const CustomSearchBox = connectSearchBox(SearchBox)
export const Search = (props) => {
const [active, setActive] = useState(0)
useHotkeys('esc', () => props.setSearch(false))
useHotkeys('up', () => {
if (active) setActive((act) => act - 1)
})
useHotkeys('down', () => {
setActive((act) => act + 1)
})
useHotkeys('down', () => {
console.log('enter', active)
})
const stateProps = {
setSearch: props.setSearch,
setMenu: props.setMenu,
active,
setActive,
}
return (
<InstantSearch indexName={config.algolia.index} searchClient={searchClient}>
<CustomSearchBox {...stateProps} />
{/* Widgets */}
<Hits hitComponent={Hit} />
</InstantSearch>
)
}

View file

@ -1,17 +1,10 @@
import Head from 'next/head'
import { Header, ns as headerNs } from 'site/components/header/index.mjs'
import { Footer, ns as footerNs } from 'shared/components/footer/index.mjs'
import { Search, ns as searchNs } from 'site/components/search.mjs'
export const ns = [...new Set([...headerNs, ...footerNs, ...searchNs])]
export const ns = [...new Set([...headerNs, ...footerNs])]
export const LayoutWrapper = ({
children = [],
search,
setSearch,
noSearch = false,
header = false,
}) => {
export const LayoutWrapper = ({ children = [], header = false }) => {
const ChosenHeader = header ? header : Header
return (
@ -25,24 +18,8 @@ export const LayoutWrapper = ({
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<ChosenHeader setSearch={setSearch} />
<ChosenHeader />
<main className="grow">{children}</main>
{!noSearch && search && (
<>
<div
className={`
fixed w-full max-h-screen bg-base-100 top-0 z-30 pt-0 pb-16 px-8
md:rounded-lg md:top-24
md:max-w-xl md:m-auto md:inset-x-12
md:max-w-2xl
lg:max-w-4xl
`}
>
<Search search={search} setSearch={setSearch} />
</div>
<div className="fixed top-0 left-0 w-full min-h-screen bg-neutral z-20 bg-opacity-70"></div>
</>
)}
<Footer />
</div>
)

View file

@ -46,6 +46,7 @@
"react-dom": "18.2.0",
"react-hotkeys-hook": "4.4.0",
"react-instantsearch-dom": "6.40.0",
"react-instantsearch-hooks-web": "6.44.0",
"react-markdown": "8.0.7",
"react-swipeable": "7.0.0",
"react-timeago": "7.1.0",

View file

@ -1,10 +1,8 @@
/*
* This will update (replace really) the Algolia index with the
* current website contents. Or at least the markdown and Strapi
* content
* current website contents. Or at least the markdown content.
*
* It expects the following environment vars to be set in a
* .env file in the 'sites/dev' folder:
* It expects the following environment vars to be set:
*
* ALGOLIA_API_WRITE_KEY -> Needs permission to index/create/delete
*
@ -23,15 +21,18 @@ import remarkRehype from 'remark-rehype'
import rehypeSanitize from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import yaml from 'yaml'
import { getMdxFileList } from '../../shared/prebuild/mdx.mjs'
import config from '../algolia.config.mjs'
import { getMdxFileList } from '../../shared/prebuild/docs.mjs'
import { siteConfig } from '../site.config.mjs'
import { compile } from 'html-to-text'
dotenv.config()
const convert = compile()
/*
* Initialize Algolia client
*/
const client = algoliasearch(config.algolia.app, process.env.ALGOLIA_API_WRITE_KEY)
const index = client.initIndex(config.algolia.index)
const client = algoliasearch(siteConfig.algolia.app, process.env.ALGOLIA_API_WRITE_KEY)
const index = client.initIndex(siteConfig.algolia.index)
/*
* Loads markdown from disk and compiles it into HTML for indexing
@ -65,8 +66,20 @@ const markdownLoader = async (file) => {
*/
const clearIndex = async () => {
console.log(`🗑️ Clearing index`)
try {
await index.clearObjects()
} catch (err) {
console.log(err)
}
}
const splitContent = (content) =>
content.body.split('<h2>').map((chunk, i) => ({
...content,
objectID: `${content.objectID}-${i}`,
title: content.title + ' / ' + chunk.split('</h2>')[0],
body: convert(chunk.split('</h2>').slice(1).join('</h2>')),
}))
/*
* Get and index markdown content
@ -82,9 +95,17 @@ const indexMarkdownContent = async () => {
const list = await getMdxFileList(mdxRoot, 'en')
const pages = []
// max page size
const MAX = 1500
for (const file of list) {
const content = await markdownLoader(file)
pages.push(content)
if (content.body.length < MAX)
pages.push({
...content,
body: convert(content.body),
})
else pages.push(...splitContent(content))
}
// Index markdown to Algolia
await index.clearObjects()

View file

@ -1,7 +1,7 @@
export const siteConfig = {
algolia: {
app: 'MA0Y5A2PF0', // Application ID
index: 'canary_freesewing.dev',
index: 'freesewing.dev',
key: '589c7a7e4d9c95a4f12868581259bf3a', // Search-only API key
},
bugsnag: {

View file

@ -116,7 +116,7 @@ export const MdxWrapper = ({ MDX = false, frontmatter = {}, components = {}, chi
updated={updates.u}
{...{ locale, slug, t }}
/>
{MDX ? <MDX components={allComponents} /> : children}
<div className="searchme">{MDX ? <MDX components={allComponents} /> : children}</div>
</div>
)
}

View file

@ -59,7 +59,8 @@
"web-worker": "1.2.0"
},
"devDependencies": {
"recursive-readdir": "^2.2.3"
"recursive-readdir": "^2.2.3",
"html-to-text": "^9.0.5"
},
"engines": {
"node": ">=16.0.0",

165
yarn.lock
View file

@ -111,6 +111,19 @@
"@algolia/logger-common" "4.17.0"
"@algolia/requester-common" "4.17.0"
"@algolia/ui-components-highlight-vdom@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@algolia/ui-components-highlight-vdom/-/ui-components-highlight-vdom-1.2.1.tgz#c430c9f090ef8c68477ef4b685324ed231ce0c13"
integrity sha512-IlYgIaCUEkz9ezNbwugwKv991oOHhveyq6nzL0F1jDzg1p3q5Yj/vO4KpNG910r2dwGCG3nEm5GtChcLnarhFA==
dependencies:
"@algolia/ui-components-shared" "1.2.1"
"@babel/runtime" "^7.0.0"
"@algolia/ui-components-shared@1.2.1", "@algolia/ui-components-shared@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@algolia/ui-components-shared/-/ui-components-shared-1.2.1.tgz#62e3a04fc11623f149312942cd764d4528dd994c"
integrity sha512-a7mYHf/GVQfhAx/HRiMveKkFvHspQv/REdG+C/FIOosiSmNZxX7QebDwJkrGSmDWdXO12D0Qv1xn3AytFcEDlQ==
"@alloc/quick-lru@^5.2.0":
version "5.2.0"
resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
@ -3839,6 +3852,14 @@
json5 "^2.2.3"
lodash "^4.17.21"
"@selderee/plugin-htmlparser2@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz#d5b5e29a7ba6d3958a1972c7be16f4b2c188c517"
integrity sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==
dependencies:
domhandler "^5.0.3"
selderee "^0.11.0"
"@sigstore/protobuf-specs@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz#957cb64ea2f5ce527cc9cf02a096baeb0d2b99b4"
@ -4092,6 +4113,11 @@
resolved "https://registry.yarnpkg.com/@types/diff-match-patch/-/diff-match-patch-1.0.32.tgz#d9c3b8c914aa8229485351db4865328337a3d09f"
integrity sha512-bPYT5ECFiblzsVzyURaNhljBH2Gh1t9LowgUwciMrNAhFewLkHT2H0Mto07Y4/3KCOGZHRQll3CTtQZ0X11D/A==
"@types/dom-speech-recognition@^0.0.1":
version "0.0.1"
resolved "https://registry.yarnpkg.com/@types/dom-speech-recognition/-/dom-speech-recognition-0.0.1.tgz#e326761a04b4a49c0eec2ac7948afc1c6aa12baa"
integrity sha512-udCxb8DvjcDKfk1WTBzDsxFbLgYxmQGKrE/ricoMqHRNjSlSUCcamVTA5lIQqzY10mY5qCY0QDwBfFEwhfoDPw==
"@types/estree-jsx@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.0.tgz#7bfc979ab9f692b492017df42520f7f765e98df1"
@ -4146,6 +4172,11 @@
"@types/minimatch" "*"
"@types/node" "*"
"@types/google.maps@^3.45.3":
version "3.53.1"
resolved "https://registry.yarnpkg.com/@types/google.maps/-/google.maps-3.53.1.tgz#c1fb7325eaa5af3574aedb9390d16798be0dad00"
integrity sha512-+7JVpq+kFzTU3TweSz6huYuFedZ4s60WeABaXYU6rDZczdpfoQ5DuZNCDc/eAAcdFJpxMMDpzf3d9YTMNodBFg==
"@types/hast@^2.0.0":
version "2.3.4"
resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc"
@ -4153,6 +4184,11 @@
dependencies:
"@types/unist" "*"
"@types/hogan.js@^3.0.0":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/hogan.js/-/hogan.js-3.0.1.tgz#64c54407b30da359763e14877f5702b8ae85d61c"
integrity sha512-D03i/2OY7kGyMq9wdQ7oD8roE49z/ZCZThe/nbahtvuqCNZY9T2MfedOWyeBdbEpY2W8Gnh/dyJLdFtUCOkYbg==
"@types/hoist-non-react-statics@^3.3.1":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
@ -4277,7 +4313,7 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
"@types/qs@*":
"@types/qs@*", "@types/qs@^6.5.3":
version "6.9.7"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==
@ -7388,7 +7424,7 @@ deep-is@^0.1.3, deep-is@~0.1.3:
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
deepmerge@^4.2.2:
deepmerge@^4.2.2, deepmerge@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
@ -10177,6 +10213,14 @@ history@^5.3.0:
dependencies:
"@babel/runtime" "^7.7.6"
hogan.js@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/hogan.js/-/hogan.js-3.0.2.tgz#4cd9e1abd4294146e7679e41d7898732b02c7bfd"
integrity sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==
dependencies:
mkdirp "0.3.0"
nopt "1.0.10"
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
@ -10222,6 +10266,11 @@ hosted-git-info@^6.0.0, hosted-git-info@^6.1.1:
dependencies:
lru-cache "^7.5.1"
htm@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/htm/-/htm-3.1.1.tgz#49266582be0dc66ed2235d5ea892307cc0c24b78"
integrity sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==
html-crush@^4.0.0, html-crush@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/html-crush/-/html-crush-4.2.0.tgz#ec5774d252ab15235c5c27af056d691b4f5abb07"
@ -10254,6 +10303,17 @@ html-parse-stringify@^3.0.1:
dependencies:
void-elements "3.1.0"
html-to-text@^9.0.5:
version "9.0.5"
resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-9.0.5.tgz#6149a0f618ae7a0db8085dca9bbf96d32bb8368d"
integrity sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==
dependencies:
"@selderee/plugin-htmlparser2" "^0.11.0"
deepmerge "^4.3.1"
dom-serializer "^2.0.0"
htmlparser2 "^8.0.2"
selderee "^0.11.0"
html-void-elements@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f"
@ -10305,7 +10365,7 @@ htmlparser2@^7.1.1:
domutils "^2.8.0"
entities "^3.0.1"
htmlparser2@^8.0.1:
htmlparser2@^8.0.1, htmlparser2@^8.0.2:
version "8.0.2"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
@ -10703,6 +10763,25 @@ inquirer@^8.0.0, inquirer@^8.2.4:
through "^2.3.6"
wrap-ansi "^7.0.0"
instantsearch.js@4.56.0:
version "4.56.0"
resolved "https://registry.yarnpkg.com/instantsearch.js/-/instantsearch.js-4.56.0.tgz#faedcbaac1c94575703470a048cf39e4170fc6d0"
integrity sha512-A50GZjcK9c3o3y49fqOX6ghI4leCPAiz0h5xY/yvU7mMXCwwXZw1BsUbOPM02gDvaUdYvibycW7byVQno3DK1g==
dependencies:
"@algolia/events" "^4.0.1"
"@algolia/ui-components-highlight-vdom" "^1.2.1"
"@algolia/ui-components-shared" "^1.2.1"
"@types/dom-speech-recognition" "^0.0.1"
"@types/google.maps" "^3.45.3"
"@types/hogan.js" "^3.0.0"
"@types/qs" "^6.5.3"
algoliasearch-helper "^3.13.0"
hogan.js "^3.0.2"
htm "^3.0.0"
preact "^10.10.0"
qs "^6.5.1 < 6.10"
search-insights "^2.6.0"
internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986"
@ -11804,6 +11883,11 @@ lazystream@^1.0.0:
dependencies:
readable-stream "^2.0.5"
leac@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/leac/-/leac-0.6.0.tgz#dcf136e382e666bd2475f44a1096061b70dc0912"
integrity sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==
lerna@^6.0.0:
version "6.6.2"
resolved "https://registry.yarnpkg.com/lerna/-/lerna-6.6.2.tgz#ad921f913aca4e7307123a598768b6f15ca5804f"
@ -13727,6 +13811,11 @@ mkdirp-infer-owner@^2.0.0:
infer-owner "^1.0.4"
mkdirp "^1.0.3"
mkdirp@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e"
integrity sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==
mkdirp@^1.0.3, mkdirp@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
@ -14044,6 +14133,13 @@ non-layered-tidy-tree-layout@^2.0.2:
resolved "https://registry.yarnpkg.com/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz#57d35d13c356643fc296a55fb11ac15e74da7804"
integrity sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==
nopt@1.0.10, nopt@~1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==
dependencies:
abbrev "1"
nopt@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d"
@ -14058,13 +14154,6 @@ nopt@^7.0.0:
dependencies:
abbrev "^2.0.0"
nopt@~1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==
dependencies:
abbrev "1"
normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@ -15150,6 +15239,14 @@ parse5@^7.0.0, parse5@^7.1.1:
dependencies:
entities "^4.4.0"
parseley@^0.12.0:
version "0.12.1"
resolved "https://registry.yarnpkg.com/parseley/-/parseley-0.12.1.tgz#4afd561d50215ebe259e3e7a853e62f600683aef"
integrity sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==
dependencies:
leac "^0.6.0"
peberminta "^0.9.0"
parseurl@~1.3.2, parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@ -15276,6 +15373,11 @@ pdfkit@0.13.0:
linebreak "^1.0.2"
png-js "^1.0.0"
peberminta@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/peberminta/-/peberminta-0.9.0.tgz#8ec9bc0eb84b7d368126e71ce9033501dca2a352"
integrity sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==
peek-stream@^1.1.0, peek-stream@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67"
@ -15772,6 +15874,11 @@ posthtml@^0.16.4, posthtml@^0.16.5, posthtml@^0.16.6:
posthtml-parser "^0.11.0"
posthtml-render "^3.0.0"
preact@^10.10.0:
version "10.15.0"
resolved "https://registry.yarnpkg.com/preact/-/preact-10.15.0.tgz#14bae0afe3547ca9d45d22fda2a4266462d31cf3"
integrity sha512-nZSa8M2R2m1n7nJSBlzDpxRJaIsejrTO1vlFbdpFvyC8qM1iU+On2y0otfoUm6SRB5o0lF0CKDFxg6grEFU0iQ==
prebuild-install@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45"
@ -16074,6 +16181,11 @@ qs@^6.11.0, qs@^6.5.1:
dependencies:
side-channel "^1.0.4"
"qs@^6.5.1 < 6.10":
version "6.9.7"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe"
integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==
query-string@7.1.3, query-string@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328"
@ -16283,6 +16395,25 @@ react-instantsearch-dom@6.40.0:
react-fast-compare "^3.0.0"
react-instantsearch-core "6.40.0"
react-instantsearch-hooks-web@6.44.0:
version "6.44.0"
resolved "https://registry.yarnpkg.com/react-instantsearch-hooks-web/-/react-instantsearch-hooks-web-6.44.0.tgz#cd40bcdcfd6953652e4d9b9cc94c38adaa512772"
integrity sha512-jLCU0r1UtVPEbMIP7YL+qU8Lfoy/Z3nLMDS6iBVn3ybB/IBESjYASJsqYGZ1Yk17W6Dl0TWSIacgQsfu8QcE2Q==
dependencies:
"@babel/runtime" "^7.1.2"
instantsearch.js "4.56.0"
react-instantsearch-hooks "6.44.0"
react-instantsearch-hooks@6.44.0:
version "6.44.0"
resolved "https://registry.yarnpkg.com/react-instantsearch-hooks/-/react-instantsearch-hooks-6.44.0.tgz#59d98a6f2938009add633998832cd0f842df8c5a"
integrity sha512-1c/cd6OHAe8hP3PBeEUBwdVi6j3lu0AxGR17wun6j+aKC8/7gTyW0LXGUgm54xU5CORez8/OVh0akK+XDxu+9g==
dependencies:
"@babel/runtime" "^7.1.2"
algoliasearch-helper "^3.13.0"
instantsearch.js "4.56.0"
use-sync-external-store "^1.0.0"
react-is@18.2.0, react-is@^18.0.0, react-is@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
@ -17774,6 +17905,18 @@ scroll-into-view-if-needed@^3.0.3:
dependencies:
compute-scroll-into-view "^3.0.2"
search-insights@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/search-insights/-/search-insights-2.6.0.tgz#bb8771a73b83c4a0f1f207c2f64fea01acd3e7d0"
integrity sha512-vU2/fJ+h/Mkm/DJOe+EaM5cafJv/1rRTZpGJTuFPf/Q5LjzgMDsqPdSaZsAe+GAWHHsfsu+rQSAn6c8IGtBEVw==
selderee@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/selderee/-/selderee-0.11.0.tgz#6af0c7983e073ad3e35787ffe20cefd9daf0ec8a"
integrity sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==
dependencies:
parseley "^0.12.0"
semver-diff@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b"
@ -19981,7 +20124,7 @@ use-sidecar@^1.1.2:
detect-node-es "^1.1.0"
tslib "^2.0.0"
use-sync-external-store@^1.2.0:
use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==