Tested to add algolia search

This commit is contained in:
Henrik Larsson 2023-08-10 20:49:53 +02:00
parent 04477fe83a
commit dc2856c4c8
17 changed files with 486 additions and 316 deletions

View File

@ -20,11 +20,14 @@ VERCEL_GIT_PULL_REQUEST_ID=""
NEXT_PUBLIC_SANITY_PROJECT_ID=""
NEXT_PUBLIC_SANITY_DATASET=""
NEXT_PUBLIC_SANITY_API_VERSION=""
# Preview
SANITY_API_READ_TOKEN=""
SANITY_WEBHOOK_SECRET=""
# Algolia
NEXT_PUBLIC_ALGOLIA_APPLICATION_ID="YOUR_ALGOLIA_APPLICATION_ID"
NEXT_PUBLIC_ALGOLIA_SEARCH_ONLY_API_KEY="YOUR_ALGOLIA_SEARCH_ONLY_APY_KEY"
ALGOLIA_ADMIN_KEY="YOUR_ALGOLIA_ADMIN_KEY"
# Site
TWITTER_CREATOR="@kodamera"
TWITTER_SITE="https://kodamera.se"

View File

@ -29,6 +29,7 @@ export async function generateMetadata({
slug: `${params.slug}`
};
}
const page = await clientFetch(pageQuery, queryParams);
if (!page) return notFound();

View File

@ -3,7 +3,7 @@ import Header from 'components/layout/header/header';
import { NextIntlClientProvider } from 'next-intl';
import { Inter } from 'next/font/google';
import { notFound } from 'next/navigation';
import { ReactNode, Suspense } from 'react';
import { ReactNode } from 'react';
import { supportedLanguages } from '../../i18n-config';
import './globals.css';
@ -58,10 +58,8 @@ export default async function LocaleLayout({ children, params: { locale } }: Loc
<body className="flex min-h-screen flex-col">
<NextIntlClientProvider locale={locale} messages={messages}>
<Header locale={locale} />
<Suspense>
<main className="flex-1">{children}</main>
<Footer locale={locale} />
</Suspense>
</NextIntlClientProvider>
</body>
</html>

View File

@ -46,6 +46,7 @@ export default function CartModal({ cart }: { cart: Cart | undefined }) {
<SheetHeader>
<SheetTitle className="text-lg font-semibold">{t('myCartTitle')}</SheetTitle>
</SheetHeader>
{!cart || cart.lines.length === 0 ? (
<div className="mt-20 flex w-full flex-col items-center justify-center overflow-hidden">
<ShoppingBagIcon className="h-12" />
@ -153,6 +154,58 @@ export default function CartModal({ cart }: { cart: Cart | undefined }) {
</a>
</div>
)}
<div className="mt-4 flex flex-col">
<h2 className="font-bold">Line item examples</h2>
<ul>
<li className="flex w-full flex-col border-b border-neutral-300">
<div className="relative flex w-full flex-row justify-between px-1 py-4">
<Link
href={'/'}
onClick={() => setIsOpen(false)}
className="z-30 flex flex-row space-x-4"
>
<div className="relative h-16 w-16 cursor-pointer overflow-hidden rounded-md border border-neutral-300 bg-neutral-300 "></div>
<div className="flex flex-1 flex-col text-base">
<span className="leading-tight">Product title</span>
<p className="text-sm text-neutral-500 ">Option of product</p>
</div>
</Link>
<div className="flex h-16 flex-col justify-between">
<Price
className="flex justify-end space-y-2 text-right text-sm"
amount={'100'}
currencyCode={'SEK'}
/>
</div>
</div>
</li>
<li className="flex w-full flex-col border-b border-neutral-300">
<div className="relative flex w-full flex-row justify-between px-1 py-4">
<Link
href={'/'}
onClick={() => setIsOpen(false)}
className="z-30 flex flex-row space-x-4"
>
<div className="relative h-16 w-16 cursor-pointer overflow-hidden rounded-md border border-neutral-300 bg-neutral-300 "></div>
<div className="flex flex-1 flex-col text-base">
<span className="leading-tight">Product title</span>
<p className="text-sm text-neutral-500 ">Option of product</p>
</div>
</Link>
<div className="flex h-16 flex-col justify-between">
<Price
className="flex justify-end space-y-2 text-right text-sm"
amount={'100'}
currencyCode={'SEK'}
/>
</div>
</div>
</li>
</ul>
</div>
</SheetContent>
</Sheet>
</>

View File

@ -9,7 +9,7 @@ export default function OpenCart({
quantity?: number;
}) {
return (
<div className="relative flex h-11 w-11 items-center justify-center text-high-contrast">
<div className="relative flex h-10 w-10 items-center justify-center text-high-contrast">
<ShoppingBagIcon
className={clsx(
'h-5 stroke-current transition-all ease-in-out hover:scale-110 ',
@ -18,7 +18,7 @@ export default function OpenCart({
/>
{quantity ? (
<div className="bg-blue-600 absolute right-0 top-0 -mr-2 -mt-2 h-4 w-4 rounded text-[11px] font-medium text-white">
<div className="absolute right-0 top-0 -mr-2 -mt-2 h-4 w-4 rounded bg-high-contrast text-[11px] font-medium text-white">
{quantity}
</div>
) : null}

View File

@ -1,105 +1,27 @@
'use client';
import BlurbSection from '@/components/modules/blurb-section/blurb-section';
import FilteredProductList from '@/components/modules/filtered-product-list/filtered-product-list';
import dynamic from 'next/dynamic';
import Hero from '@/components/modules/hero';
import ReusableSection from '@/components/modules/reusable-section/reusable-section';
import Slider from '@/components/modules/slider/slider';
import USPSection from '@/components/modules/usp-section/usp-section';
const BlurbSection = dynamic(() => import('@/components/modules/blurb-section/blurb-section'));
const FilteredProductList = dynamic(
() => import('@/components/modules/filtered-product-list/filtered-product-list')
);
const ReusableSection = dynamic(
() => import('@/components/modules/reusable-section/reusable-section')
);
const Slider = dynamic(() => import('@/components/modules/slider/slider'));
const USPSection = dynamic(() => import('@/components/modules/usp-section/usp-section'));
import { InformationCircleIcon } from '@heroicons/react/24/outline';
import { Suspense } from 'react';
// interface getContentComponentProps {
// _type: string;
// _key: number;
// disabled: boolean;
// }
// const getContentComponent = ({ _type, _key, disabled, ...rest }: getContentComponentProps) => {
// let Component: any;
// switch (_type) {
// case 'hero':
// if (disabled !== true) {
// Component = Hero;
// } else {
// return;
// }
// break;
// case 'slider':
// if (disabled !== true) {
// Component = Slider;
// } else {
// return;
// }
// break;
// case 'filteredProductList':
// if (disabled !== true) {
// Component = FilteredProductList;
// } else {
// return;
// }
// break;
// case 'blurbSection':
// if (disabled !== true) {
// Component = BlurbSection;
// } else {
// return;
// }
// break;
// case 'uspSection':
// if (disabled !== true) {
// Component = USPSection;
// } else {
// return;
// }
// break;
// case 'reusableSection':
// if (disabled !== true) {
// Component = ReusableSection;
// } else {
// return;
// }
// break;
// default:
// return (
// <div
// className={`px-4 lg:px-8 2xl:px-16 ${
// process.env.NODE_ENV === 'production' ? 'hidden' : ''
// }`}
// key={`index-${_key}`}
// >
// <span className="inline-flex items-center bg-red p-2 text-sm font-bold">
// <InformationCircleIcon className="mr-1" />
// {`No matching component (Type: ${_type})`}
// </span>
// </div>
// );
// }
// return Component ? (
// <Component key={`${_key}`} {...rest} />
// ) : (
// <div key={`${_key}`}>Something else</div>
// );
// };
interface dynamicContentManagerProps {
content: [] | any;
interface getContentComponentProps {
_type: string;
_key: number;
disabled: boolean;
}
const DynamicContentManager = ({ content }: dynamicContentManagerProps) => {
return (
<div className="dynamic-content overflow-x-hidden">
{/* {content?.map(getContentComponent)} */}
{content.map(
(
component: { _type: string; _key: number; disabled: boolean; rest: any } | any,
index: number
) => {
const { _type, _key, disabled, ...rest } = component;
const getContentComponent = ({ _type, _key, disabled, ...rest }: getContentComponentProps) => {
let Component: any;
switch (_type) {
@ -161,20 +83,20 @@ const DynamicContentManager = ({ content }: dynamicContentManagerProps) => {
);
}
if (Component && index === 0) {
return <Component key={`${_key}`} {...rest} />;
} else if (Component) {
return (
<Suspense key={`${_key}`}>
<Component {...rest} />
</Suspense>
return Component ? (
<Component key={`${_key}`} {...rest} />
) : (
<div key={`${_key}`}>Something else</div>
);
} else {
<div key={`${_key}`}>Something else</div>;
}
}
)}
</div>
};
interface dynamicContentManagerProps {
content: [] | any;
}
const DynamicContentManager = ({ content }: dynamicContentManagerProps) => {
return (
<div className="dynamic-content overflow-x-hidden">{content?.map(getContentComponent)}</div>
);
};

View File

@ -1,29 +1,33 @@
import { categoriesQuery } from '@/lib/sanity/queries';
import { clientFetch } from '@/lib/sanity/sanity.client';
import Cart from 'components/cart';
import OpenCart from 'components/cart/open-cart';
import Logo from 'components/ui/logo/logo';
import Link from 'next/link';
import { Suspense } from 'react';
import HeaderRoot from './header-root';
import MainMenu from './main-menu/main-menu';
import MobileMenuModal from './mobile-menu/modal';
import OpenMobileMenu from './mobile-menu/open-mobile-menu';
import SearchModal from './search/modal';
import OpenSearch from './search/open-search';
import UserModal from './user-menu/modal';
import OpenUserMenu from './user-menu/open-user-menu';
interface HeaderProps {
locale: string;
}
export default async function Header({ locale }: HeaderProps) {
const params = {
locale: locale
};
const mainMenu = await clientFetch(categoriesQuery, params);
const Header = ({ locale }: HeaderProps) => {
return (
<HeaderRoot>
<div className="relative flex flex-col border-b border-ui-border bg-app">
<div className="relative flex h-14 w-full items-center justify-between px-4 py-2 lg:h-16 lg:px-8 lg:py-3 2xl:px-16">
<div className="-translate-x-3 transform md:hidden">
<Suspense fallback={<OpenMobileMenu />}>
<MobileMenuModal locale={locale} />
<MobileMenuModal items={mainMenu} />
</Suspense>
</div>
@ -38,9 +42,19 @@ const Header = ({ locale }: HeaderProps) => {
</div>
<div className="absolute left-1/2 top-1/2 hidden -translate-x-1/2 -translate-y-1/2 transform md:flex">
<MainMenu locale={locale} />
<ul className="flex gap-6">
{mainMenu.map((item: { title: string; slug: string }, i: number) => {
return (
<li key={i}>
<Link className="font-medium" href={`/category/${item.slug}`}>
{item.title}
</Link>
</li>
);
})}
</ul>
</div>
<div className="flex translate-x-3 transform justify-end space-x-1">
<div className="flex translate-x-2 transform justify-end space-x-1">
<Suspense fallback={<OpenSearch />}>
<SearchModal />
</Suspense>
@ -55,6 +69,4 @@ const Header = ({ locale }: HeaderProps) => {
</div>
</HeaderRoot>
);
};
export default Header;
}

View File

@ -1,33 +0,0 @@
import { categoriesQuery } from '@/lib/sanity/queries';
import { clientFetch } from '@/lib/sanity/sanity.client';
import Link from 'next/link';
interface MainMenuProps {
locale: string;
}
export default async function MainMenu({ locale }: MainMenuProps) {
const params = {
locale: locale
};
const categories = await clientFetch(categoriesQuery, params);
if (!categories) {
return;
}
return (
<ul className="flex flex-col gap-4 lg:flex-row lg:gap-6">
{categories.map((category: { slug: string } | any, index: number) => {
return (
<li className="font-medium" key={index}>
<Link className="hover:underline" href={`/category/${category.slug}`}>
{category.title}
</Link>
</li>
);
})}
</ul>
);
}

View File

@ -1,15 +1,15 @@
'use client';
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet';
import Link from 'next/link';
import { useState } from 'react';
import MainMenu from '../main-menu/main-menu';
import OpenMobileMenu from './open-mobile-menu';
interface MobileMenuModalProps {
locale: string;
items: [];
}
export default function MobileMenuModal({ locale }: MobileMenuModalProps) {
export default function MobileMenuModal({ items }: MobileMenuModalProps) {
const [isOpen, setIsOpen] = useState(false);
return (
@ -23,7 +23,17 @@ export default function MobileMenuModal({ locale }: MobileMenuModalProps) {
<SheetTitle className="text-lg font-semibold">Menu</SheetTitle>
</SheetHeader>
<div className="mt-4">
<MainMenu locale={locale} />
<ul className="flex flex-col gap-2">
{items.map((item: { title: string; slug: string }, i: number) => {
return (
<li key={i}>
<Link onClick={() => setIsOpen(false)} href={`/category/${item.slug}`}>
{item.title}
</Link>
</li>
);
})}
</ul>
</div>
</SheetContent>
</Sheet>

View File

@ -1,5 +1,6 @@
'use client';
import Search from '@/components/search/search';
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet';
import { useTranslations } from 'next-intl';
import { useState } from 'react';
@ -19,6 +20,7 @@ export default function SearchModal() {
<SheetHeader>
<SheetTitle className="text-lg font-semibold">{t('search')}</SheetTitle>
</SheetHeader>
<Search />
</SheetContent>
</Sheet>
</>

View File

@ -3,7 +3,7 @@ import clsx from 'clsx';
export default function OpenSearch({ className }: { className?: string }) {
return (
<div className="relative flex h-11 w-11 items-center justify-center text-high-contrast">
<div className="relative flex h-10 w-10 items-center justify-center text-high-contrast">
<MagnifyingGlassIcon
className={clsx('h-5 transition-all ease-in-out hover:scale-110 ', className)}
/>

View File

@ -5,8 +5,6 @@ import { useTranslations } from 'next-intl';
import { useState } from 'react';
import OpenUserMenu from './open-user-menu';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
export default function UserModal() {
const [isOpen, setIsOpen] = useState(false);
const t = useTranslations('auth');
@ -21,15 +19,6 @@ export default function UserModal() {
<SheetHeader>
<SheetTitle className="text-lg font-semibold">{t('login.logIn')}</SheetTitle>
</SheetHeader>
<Tabs defaultValue="login" className="mt-4 w-full">
<TabsList>
<TabsTrigger value="login">{t('login.logIn')}</TabsTrigger>
<TabsTrigger value="register">{t('signUp.register')}</TabsTrigger>
</TabsList>
<TabsContent value="login">Log in to your account here.</TabsContent>
<TabsContent value="register">Register for account here.</TabsContent>
</Tabs>
</SheetContent>
</Sheet>
</>

View File

@ -3,7 +3,7 @@ import clsx from 'clsx';
export default function OpenUserMenu({ className }: { className?: string }) {
return (
<div className="relative flex h-11 w-11 items-center justify-center text-high-contrast">
<div className="relative flex h-10 w-10 items-center justify-center text-high-contrast">
<UserCircleIcon
className={clsx(
'h-5 stroke-current transition-all ease-in-out hover:scale-110 ',

View File

@ -0,0 +1,52 @@
import algoliasearch from 'algoliasearch/lite';
import { Highlight, Hits, InstantSearch, SearchBox } from 'react-instantsearch';
const searchClient = algoliasearch(
`${process.env.NEXT_PUBLIC_ALGOLIA_APPLICATION_ID}`,
`${process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_ONLY_API_KEY}`
);
export default function Search() {
// Hit.
function Hit(props: any) {
return (
<li>
<a href={`/product/${props.hit.handle}`} className="flex gap-4">
<div className="relative aspect-square h-16 w-16 bg-neutral-300" />
<div>
<h3 className="mt-2 flex text-lg font-bold text-gray-900">
<Highlight attribute="title" hit={props.hit} />
</h3>
<p className="text-gray-700">{props.hit.price} SEK</p>
</div>
</a>
</li>
);
}
return (
<div className="flex flex-col overflow-auto">
<InstantSearch searchClient={searchClient} indexName="shopify_products">
{/* Widgets */}
<SearchBox
placeholder="Vad letar du efter?"
classNames={{
root: 'mt-4',
form: 'relative',
input:
'block w-full appearance-none rounded-none h-11 pl-9 pr-3 py-2 bg-white border border-ui-border',
submit: 'absolute flex items-center justify-center top-0 left-0 bottom-0 w-11 h-11',
submitIcon: 'w-4 h-4'
}}
/>
<Hits
classNames={{
root: 'flex flex-col mt-4',
list: 'grid grid-cols-1 gap-4'
}}
hitComponent={Hit}
/>
</InstantSearch>
</div>
);
}

View File

@ -1,55 +0,0 @@
"use client"
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import { cn } from "@/lib/utils"
const Tabs = TabsPrimitive.Root
const TabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
className
)}
{...props}
/>
))
TabsList.displayName = TabsPrimitive.List.displayName
const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
className
)}
{...props}
/>
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
const TabsContent = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className
)}
{...props}
/>
))
TabsContent.displayName = TabsPrimitive.Content.displayName
export { Tabs, TabsList, TabsTrigger, TabsContent }

View File

@ -25,7 +25,6 @@
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.4",
"@radix-ui/react-navigation-menu": "^1.1.2",
"@radix-ui/react-tabs": "^1.0.4",
"@sanity/client": "^6.4.4",
"@sanity/image-url": "^1.0.2",
"@sanity/preview-kit": "^2.4.9",
@ -34,6 +33,7 @@
"@sanity/webhook": "^2.0.0",
"@types/styled-components": "^5.1.26",
"@vercel/og": "^0.1.0",
"algoliasearch": "^4.19.1",
"class-variance-authority": "^0.6.0",
"clsx": "^1.2.1",
"framer-motion": "^8.5.5",
@ -45,6 +45,7 @@
"react-cookie": "^4.1.1",
"react-dom": "18.2.0",
"react-glider": "^4.0.2",
"react-instantsearch": "^7.0.1",
"sanity": "^3.11.1",
"sharp": "^0.32.1",
"styled-components": "^5.3.10",

275
pnpm-lock.yaml generated
View File

@ -8,7 +8,6 @@ specifiers:
'@radix-ui/react-dialog': ^1.0.4
'@radix-ui/react-dropdown-menu': ^2.0.4
'@radix-ui/react-navigation-menu': ^1.1.2
'@radix-ui/react-tabs': ^1.0.4
'@sanity/client': ^6.4.4
'@sanity/image-url': ^1.0.2
'@sanity/preview-kit': ^2.4.9
@ -23,6 +22,7 @@ specifiers:
'@types/styled-components': ^5.1.26
'@vercel/git-hooks': ^1.0.0
'@vercel/og': ^0.1.0
algoliasearch: ^4.19.1
autoprefixer: ^10.4.14
class-variance-authority: ^0.6.0
clsx: ^1.2.1
@ -43,6 +43,7 @@ specifiers:
react-cookie: ^4.1.1
react-dom: 18.2.0
react-glider: ^4.0.2
react-instantsearch: ^7.0.1
sanity: ^3.11.1
sharp: ^0.32.1
styled-components: ^5.3.10
@ -58,7 +59,6 @@ dependencies:
'@radix-ui/react-dialog': 1.0.4_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-dropdown-menu': 2.0.5_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-navigation-menu': 1.1.3_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-tabs': 1.0.4_ml6diaeoljuxdq7psn5bilsrme
'@sanity/client': 6.4.4
'@sanity/image-url': 1.0.2
'@sanity/preview-kit': 2.4.9_esptxo4lplqmefuoebcrocvktm
@ -67,6 +67,7 @@ dependencies:
'@sanity/webhook': 2.0.0
'@types/styled-components': 5.1.26
'@vercel/og': 0.1.0
algoliasearch: 4.19.1
class-variance-authority: 0.6.1
clsx: 1.2.1
framer-motion: 8.5.5_biqbaboplfbrettd7655fr4n2y
@ -78,6 +79,7 @@ dependencies:
react-cookie: 4.1.1_react@18.2.0
react-dom: 18.2.0_react@18.2.0
react-glider: 4.0.2_biqbaboplfbrettd7655fr4n2y
react-instantsearch: 7.0.1_y77g3ya36oki3hpn5frhdbwxre
sanity: 3.15.0_ylw2uyeewsplkaxo6s4hau5spa
sharp: 0.32.4
styled-components: 5.3.11_l266yphwesgudam3x3r2tm6dce
@ -111,6 +113,111 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/@algolia/cache-browser-local-storage/4.19.1:
resolution: {integrity: sha512-FYAZWcGsFTTaSAwj9Std8UML3Bu8dyWDncM7Ls8g+58UOe4XYdlgzXWbrIgjaguP63pCCbMoExKr61B+ztK3tw==}
dependencies:
'@algolia/cache-common': 4.19.1
dev: false
/@algolia/cache-common/4.19.1:
resolution: {integrity: sha512-XGghi3l0qA38HiqdoUY+wvGyBsGvKZ6U3vTiMBT4hArhP3fOGLXpIINgMiiGjTe4FVlTa5a/7Zf2bwlIHfRqqg==}
dev: false
/@algolia/cache-in-memory/4.19.1:
resolution: {integrity: sha512-+PDWL+XALGvIginigzu8oU6eWw+o76Z8zHbBovWYcrtWOEtinbl7a7UTt3x3lthv+wNuFr/YD1Gf+B+A9V8n5w==}
dependencies:
'@algolia/cache-common': 4.19.1
dev: false
/@algolia/client-account/4.19.1:
resolution: {integrity: sha512-Oy0ritA2k7AMxQ2JwNpfaEcgXEDgeyKu0V7E7xt/ZJRdXfEpZcwp9TOg4TJHC7Ia62gIeT2Y/ynzsxccPw92GA==}
dependencies:
'@algolia/client-common': 4.19.1
'@algolia/client-search': 4.19.1
'@algolia/transporter': 4.19.1
dev: false
/@algolia/client-analytics/4.19.1:
resolution: {integrity: sha512-5QCq2zmgdZLIQhHqwl55ZvKVpLM3DNWjFI4T+bHr3rGu23ew2bLO4YtyxaZeChmDb85jUdPDouDlCumGfk6wOg==}
dependencies:
'@algolia/client-common': 4.19.1
'@algolia/client-search': 4.19.1
'@algolia/requester-common': 4.19.1
'@algolia/transporter': 4.19.1
dev: false
/@algolia/client-common/4.19.1:
resolution: {integrity: sha512-3kAIVqTcPrjfS389KQvKzliC559x+BDRxtWamVJt8IVp7LGnjq+aVAXg4Xogkur1MUrScTZ59/AaUd5EdpyXgA==}
dependencies:
'@algolia/requester-common': 4.19.1
'@algolia/transporter': 4.19.1
dev: false
/@algolia/client-personalization/4.19.1:
resolution: {integrity: sha512-8CWz4/H5FA+krm9HMw2HUQenizC/DxUtsI5oYC0Jxxyce1vsr8cb1aEiSJArQT6IzMynrERif1RVWLac1m36xw==}
dependencies:
'@algolia/client-common': 4.19.1
'@algolia/requester-common': 4.19.1
'@algolia/transporter': 4.19.1
dev: false
/@algolia/client-search/4.19.1:
resolution: {integrity: sha512-mBecfMFS4N+yK/p0ZbK53vrZbL6OtWMk8YmnOv1i0LXx4pelY8TFhqKoTit3NPVPwoSNN0vdSN9dTu1xr1XOVw==}
dependencies:
'@algolia/client-common': 4.19.1
'@algolia/requester-common': 4.19.1
'@algolia/transporter': 4.19.1
dev: false
/@algolia/events/4.0.1:
resolution: {integrity: sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==}
dev: false
/@algolia/logger-common/4.19.1:
resolution: {integrity: sha512-i6pLPZW/+/YXKis8gpmSiNk1lOmYCmRI6+x6d2Qk1OdfvX051nRVdalRbEcVTpSQX6FQAoyeaui0cUfLYW5Elw==}
dev: false
/@algolia/logger-console/4.19.1:
resolution: {integrity: sha512-jj72k9GKb9W0c7TyC3cuZtTr0CngLBLmc8trzZlXdfvQiigpUdvTi1KoWIb2ZMcRBG7Tl8hSb81zEY3zI2RlXg==}
dependencies:
'@algolia/logger-common': 4.19.1
dev: false
/@algolia/requester-browser-xhr/4.19.1:
resolution: {integrity: sha512-09K/+t7lptsweRTueHnSnmPqIxbHMowejAkn9XIcJMLdseS3zl8ObnS5GWea86mu3vy4+8H+ZBKkUN82Zsq/zg==}
dependencies:
'@algolia/requester-common': 4.19.1
dev: false
/@algolia/requester-common/4.19.1:
resolution: {integrity: sha512-BisRkcWVxrDzF1YPhAckmi2CFYK+jdMT60q10d7z3PX+w6fPPukxHRnZwooiTUrzFe50UBmLItGizWHP5bDzVQ==}
dev: false
/@algolia/requester-node-http/4.19.1:
resolution: {integrity: sha512-6DK52DHviBHTG2BK/Vv2GIlEw7i+vxm7ypZW0Z7vybGCNDeWzADx+/TmxjkES2h15+FZOqVf/Ja677gePsVItA==}
dependencies:
'@algolia/requester-common': 4.19.1
dev: false
/@algolia/transporter/4.19.1:
resolution: {integrity: sha512-nkpvPWbpuzxo1flEYqNIbGz7xhfhGOKGAZS7tzC+TELgEmi7z99qRyTfNSUlW7LZmB3ACdnqAo+9A9KFBENviQ==}
dependencies:
'@algolia/cache-common': 4.19.1
'@algolia/logger-common': 4.19.1
'@algolia/requester-common': 4.19.1
dev: false
/@algolia/ui-components-highlight-vdom/1.2.1:
resolution: {integrity: sha512-IlYgIaCUEkz9ezNbwugwKv991oOHhveyq6nzL0F1jDzg1p3q5Yj/vO4KpNG910r2dwGCG3nEm5GtChcLnarhFA==}
dependencies:
'@algolia/ui-components-shared': 1.2.1
'@babel/runtime': 7.22.10
dev: false
/@algolia/ui-components-shared/1.2.1:
resolution: {integrity: sha512-a7mYHf/GVQfhAx/HRiMveKkFvHspQv/REdG+C/FIOosiSmNZxX7QebDwJkrGSmDWdXO12D0Qv1xn3AytFcEDlQ==}
dev: false
/@alloc/quick-lru/5.2.0:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
@ -1507,34 +1614,6 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-tabs/1.0.4_ml6diaeoljuxdq7psn5bilsrme:
resolution: {integrity: sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.10
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-context': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-direction': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-id': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-presence': 1.0.1_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-primitive': 1.0.3_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-roving-focus': 1.0.4_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-use-controllable-state': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@types/react': 18.2.19
'@types/react-dom': 18.2.7
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/@radix-ui/react-use-callback-ref/1.0.1_6kgymidexis2l23kiss4by6rqm:
resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
peerDependencies:
@ -2080,6 +2159,10 @@ packages:
resolution: {integrity: sha512-bPYT5ECFiblzsVzyURaNhljBH2Gh1t9LowgUwciMrNAhFewLkHT2H0Mto07Y4/3KCOGZHRQll3CTtQZ0X11D/A==}
dev: false
/@types/dom-speech-recognition/0.0.1:
resolution: {integrity: sha512-udCxb8DvjcDKfk1WTBzDsxFbLgYxmQGKrE/ricoMqHRNjSlSUCcamVTA5lIQqzY10mY5qCY0QDwBfFEwhfoDPw==}
dev: false
/@types/event-source-polyfill/1.0.1:
resolution: {integrity: sha512-dls8b0lUgJ/miRApF0efboQ9QZnAm7ofTO6P1ILu8bRPxUFKDxVwFf8+TeuuErmNui6blpltyr7+eV72dbQXlQ==}
dev: false
@ -2095,12 +2178,20 @@ packages:
'@types/node': 18.13.0
dev: false
/@types/google.maps/3.53.6:
resolution: {integrity: sha512-zDU8c7K0YR1Ob7Wn0qCSQvICIuxilZH9KFIDHK6JO/5QzqEMv8e4+9bmyoDEktA9vPNmwP++zzg65h9y53iZ6Q==}
dev: false
/@types/hast/2.3.5:
resolution: {integrity: sha512-SvQi0L/lNpThgPoleH53cdjB3y9zpLlVjRbqB3rH8hx1jiRSBGAhyjV3H+URFjNVRqt2EdYNrbZE5IsGlNfpRg==}
dependencies:
'@types/unist': 2.0.7
dev: false
/@types/hogan.js/3.0.1:
resolution: {integrity: sha512-D03i/2OY7kGyMq9wdQ7oD8roE49z/ZCZThe/nbahtvuqCNZY9T2MfedOWyeBdbEpY2W8Gnh/dyJLdFtUCOkYbg==}
dev: false
/@types/hoist-non-react-statics/3.3.1:
resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==}
dependencies:
@ -2137,6 +2228,10 @@ packages:
/@types/prop-types/15.7.5:
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
/@types/qs/6.9.7:
resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==}
dev: false
/@types/react-copy-to-clipboard/5.0.4:
resolution: {integrity: sha512-otTJsJpofYAeaIeOwV5xBUGpo6exXG2HX7X4nseToCB2VgPEBxGBHCm/FecZ676doNR7HCSTVtmohxfG2b3/yQ==}
dependencies:
@ -2328,6 +2423,10 @@ packages:
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
dev: false
/abbrev/1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
dev: false
/acorn-globals/7.0.1:
resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==}
dependencies:
@ -2378,6 +2477,34 @@ packages:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
/algoliasearch-helper/3.14.0_algoliasearch@4.19.1:
resolution: {integrity: sha512-gXDXzsSS0YANn5dHr71CUXOo84cN4azhHKUbg71vAWnH+1JBiR4jf7to3t3JHXknXkbV0F7f055vUSBKrltHLQ==}
peerDependencies:
algoliasearch: '>= 3.1 < 6'
dependencies:
'@algolia/events': 4.0.1
algoliasearch: 4.19.1
dev: false
/algoliasearch/4.19.1:
resolution: {integrity: sha512-IJF5b93b2MgAzcE/tuzW0yOPnuUyRgGAtaPv5UUywXM8kzqfdwZTO4sPJBzoGz1eOy6H9uEchsJsBFTELZSu+g==}
dependencies:
'@algolia/cache-browser-local-storage': 4.19.1
'@algolia/cache-common': 4.19.1
'@algolia/cache-in-memory': 4.19.1
'@algolia/client-account': 4.19.1
'@algolia/client-analytics': 4.19.1
'@algolia/client-common': 4.19.1
'@algolia/client-personalization': 4.19.1
'@algolia/client-search': 4.19.1
'@algolia/logger-common': 4.19.1
'@algolia/logger-console': 4.19.1
'@algolia/requester-browser-xhr': 4.19.1
'@algolia/requester-common': 4.19.1
'@algolia/requester-node-http': 4.19.1
'@algolia/transporter': 4.19.1
dev: false
/ansi-escapes/4.3.2:
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
engines: {node: '>=8'}
@ -4459,6 +4586,14 @@ packages:
'@babel/runtime': 7.22.10
dev: false
/hogan.js/3.0.2:
resolution: {integrity: sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==}
hasBin: true
dependencies:
mkdirp: 0.3.0
nopt: 1.0.10
dev: false
/hoist-non-react-statics/3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
dependencies:
@ -4468,6 +4603,10 @@ packages:
/hosted-git-info/2.8.9:
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
/htm/3.1.1:
resolution: {integrity: sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==}
dev: false
/html-encoding-sniffer/3.0.0:
resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
engines: {node: '>=12'}
@ -4558,6 +4697,27 @@ packages:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
dev: false
/instantsearch.js/4.56.9_algoliasearch@4.19.1:
resolution: {integrity: sha512-jyRbByRUPm/ISVdRknCUDenZh65IDO2KE3GMP+RLSpcl3PV9TRfqFCbzoaSAwholbZW7sm3InBP7isCWyQMPlw==}
peerDependencies:
algoliasearch: '>= 3.1 < 6'
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.53.6
'@types/hogan.js': 3.0.1
'@types/qs': 6.9.7
algoliasearch: 4.19.1
algoliasearch-helper: 3.14.0_algoliasearch@4.19.1
hogan.js: 3.0.2
htm: 3.1.1
preact: 10.16.0
qs: 6.9.7
search-insights: 2.7.0
dev: false
/internal-slot/1.0.5:
resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
engines: {node: '>= 0.4'}
@ -5254,6 +5414,11 @@ packages:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
dev: false
/mkdirp/0.3.0:
resolution: {integrity: sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==}
deprecated: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
dev: false
/module-alias/2.2.3:
resolution: {integrity: sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==}
dev: false
@ -5403,6 +5568,13 @@ packages:
/node-releases/2.0.13:
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
/nopt/1.0.10:
resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==}
hasBin: true
dependencies:
abbrev: 1.1.1
dev: false
/normalize-package-data/2.5.0:
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
dependencies:
@ -5861,6 +6033,10 @@ packages:
picocolors: 1.0.0
source-map-js: 1.0.2
/preact/10.16.0:
resolution: {integrity: sha512-XTSj3dJ4roKIC93pald6rWuB2qQJO9gO2iLLyTe87MrjQN+HklueLsmskbywEWqCHlclgz3/M4YLL2iBr9UmMA==}
dev: false
/prebuild-install/7.1.1:
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
engines: {node: '>=10'}
@ -6014,6 +6190,11 @@ packages:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
/qs/6.9.7:
resolution: {integrity: sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==}
engines: {node: '>=0.6'}
dev: false
/querystringify/2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
dev: false
@ -6115,6 +6296,35 @@ packages:
react-dom: 18.2.0_react@18.2.0
dev: false
/react-instantsearch-core/7.0.1_ailizoiapgog7erguzjq7gd4wq:
resolution: {integrity: sha512-qKe8sV03kyoc3HjEYmpGF2k038uaBV5Mzdxgf3ZUP1B7OyCPnzeC7YPvjZFZV89rvcfxr0lwzdExKVFV1GMR7g==}
peerDependencies:
algoliasearch: '>= 3.1 < 5'
react: '>= 16.8.0 < 19'
dependencies:
'@babel/runtime': 7.22.10
algoliasearch: 4.19.1
algoliasearch-helper: 3.14.0_algoliasearch@4.19.1
instantsearch.js: 4.56.9_algoliasearch@4.19.1
react: 18.2.0
use-sync-external-store: 1.2.0_react@18.2.0
dev: false
/react-instantsearch/7.0.1_y77g3ya36oki3hpn5frhdbwxre:
resolution: {integrity: sha512-Xi09wk3mjJ2/8TPm2/hbWPJLr7VtPv18JY73NGzUsVY6d5m9oRhOyLHTZUfyfnq641G8ROupQo7Vum5Csm8CLw==}
peerDependencies:
algoliasearch: '>= 3.1 < 5'
react: '>= 16.8.0 < 19'
react-dom: '>= 16.8.0 < 19'
dependencies:
'@babel/runtime': 7.22.10
algoliasearch: 4.19.1
instantsearch.js: 4.56.9_algoliasearch@4.19.1
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
react-instantsearch-core: 7.0.1_ailizoiapgog7erguzjq7gd4wq
dev: false
/react-is/16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
@ -6618,6 +6828,11 @@ packages:
compute-scroll-into-view: 3.0.3
dev: false
/search-insights/2.7.0:
resolution: {integrity: sha512-GLbVaGgzYEKMvuJbHRhLi1qoBFnjXZGZ6l4LxOYPCp4lI2jDRB3jPU9/XNhMwv6kvnA9slTreq6pvK+b3o3aqg==}
engines: {node: '>=8.16.0'}
dev: false
/semver/5.7.2:
resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
hasBin: true