Add algoliasearch

* add menu item
* add pages
* add build search script

Add custom algolia component
* fix image in post width

Delete useless file

Modify post data to algolia script
This commit is contained in:
DefectingCat
2021-11-27 11:05:41 +08:00
parent 09a4ec43a7
commit 9460f7569c
20 changed files with 613 additions and 37 deletions

1
.gitignore vendored
View File

@ -27,6 +27,7 @@ yarn-debug.log*
yarn-error.log*
# local env files
.env
.env.local
.env.development.local
.env.test.local

View File

@ -8,7 +8,7 @@
- [x] 归档页面
- [x] 关于页面
- [ ] PGP页面
- [x] PGP页面
- [ ] 其他
### 其他功能
@ -19,6 +19,12 @@
- [x] NProgress
- [ ] 暗色模式代码高亮
## Todo
- [ ] 提高文章页面加载速度
- [ ] 图片懒加载占位问题
- [ ] algolia 搜索样式
## ❤️
* Markdown 样式:[https://github.com/mingluosunyi/typora-theme-ava-diana](https://github.com/mingluosunyi/typora-theme-ava-diana)

View File

@ -14,9 +14,17 @@ import {
} from '@chakra-ui/react';
import UseAnimations from 'react-useanimations';
import menu3 from 'react-useanimations/lib/menu3';
import { FiHome, FiArchive, FiUser, FiSun, FiMoon } from 'react-icons/fi';
import {
FiHome,
FiArchive,
FiUser,
FiSun,
FiMoon,
FiSearch,
} from 'react-icons/fi';
import useGetColors from '../lib/hooks/useGetColors';
import { useRouter } from 'next/router';
import Search from './search';
const menu = [
{
@ -31,12 +39,29 @@ const menu = [
path: '/archive',
icon: FiArchive,
},
// {
// id: 2,
// name: '闲言',
// path: '/message',
// icon: FiMessageSquare,
// },
// {
// id: 3,
// name: '密语',
// path: '/pgp',
// icon: FiLock,
// },
{
id: 3,
id: 4,
name: '关于',
path: '/about',
icon: FiUser,
},
{
id: 5,
name: '搜索',
icon: FiSearch,
},
];
interface MenuListProps {
@ -45,7 +70,7 @@ interface MenuListProps {
// eslint-disable-next-line no-unused-vars
e: MouseEvent<HTMLDivElement, globalThis.MouseEvent>,
// eslint-disable-next-line no-unused-vars
path: string
path?: string
) => void;
}
const MenuList: FC<MenuListProps> = ({ boxBg, handleMenuClick }) => {
@ -62,7 +87,7 @@ const MenuList: FC<MenuListProps> = ({ boxBg, handleMenuClick }) => {
{menu.map((item) => {
return (
<Flex
onClick={(e) => handleMenuClick(e, item.path)}
onClick={(e) => handleMenuClick(e, item?.path)}
href={item.path}
key={item.id}
as="a"
@ -85,7 +110,14 @@ const NavBar: FC = () => {
const router = useRouter();
const [isLargerThan768] = useMediaQuery('(min-width: 768px)');
// Menu toggle
const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: false });
// Modal toggle
const {
isOpen: isModalOpen,
onOpen: onModalOpen,
onClose: onModalClose,
} = useDisclosure();
const { colorMode, toggleColorMode } = useColorMode();
@ -95,30 +127,35 @@ const NavBar: FC = () => {
// Switch pages
const handleMenuClick = (
e: MouseEvent<HTMLDivElement, globalThis.MouseEvent>,
path: string
path?: string
) => {
e.preventDefault();
!isLargerThan768 &&
// Click the animate icon.
(iconRef.current?.children[0] as HTMLDivElement).click();
router.push(path);
if (path) {
!isLargerThan768 &&
// Click the animate icon.
(iconRef.current?.children[0] as HTMLDivElement).click();
router.push(path);
} else {
onModalOpen();
}
};
return (
<>
<Box
color={textColor}
w={[null, null, '120px']}
w={[null, null, '8rem']}
p={['3rem 1rem 1rem 1rem', null, 'unset']}
position={'relative'}
flex={[1, 1, 'unset']}
>
<Box position={'relative'} boxSize="120px">
<Box position={'relative'} boxSize="8rem">
{/* avatar */}
<Image
borderRadius="full"
src="/images/img/avatar.svg"
boxSize="120px"
boxSize="8rem"
boxShadow={'card'}
objectFit={'cover'}
alt="Avatar"
@ -178,6 +215,7 @@ const NavBar: FC = () => {
</Box>
</Box>
{/* Mobile menu icon */}
<Box
display={[null, null, 'none']}
position={'absolute'}
@ -194,6 +232,8 @@ const NavBar: FC = () => {
/>
</Box>
</Box>
<Search isModalOpen={isModalOpen} onModalClose={onModalClose} />
</>
);
};

View File

@ -0,0 +1,39 @@
import { FC } from 'react';
import { HighlightProvided } from 'react-instantsearch-core';
import { connectHighlight } from 'react-instantsearch-dom';
import type { PostHits } from './CustomHits';
type Props = {
attribute: string;
hit: PostHits;
};
const Highlight: FC<HighlightProvided & Props> = ({
highlight,
attribute,
hit,
}) => {
const parsedHit = highlight({
highlightProperty: '_highlightResult',
attribute,
hit,
});
return (
<>
<span>
{parsedHit.map((part, index) =>
part.isHighlighted ? (
<mark key={index}>{part.value}</mark>
) : (
<span key={index}>{part.value}</span>
)
)}
</span>
</>
);
};
const CustomHighlight = connectHighlight(Highlight as any);
export default CustomHighlight;

View File

@ -0,0 +1,37 @@
import { FC } from 'react';
import { HitsProvided } from 'react-instantsearch-core';
import { connectHits } from 'react-instantsearch-dom';
import CustomHighlight from './CustomHighlight';
export interface PostHits {
objectID: string;
title: string;
id: string;
desc: string;
date: Date;
tags: string | string[];
categories: string;
url: string;
index_img: string;
}
const Hits: FC<HitsProvided<PostHits>> = ({ hits }) => {
return (
<>
<ol>
{hits.map((item) => {
return (
<li key={item.objectID}>
<CustomHighlight attribute="title" hit={item} />
<CustomHighlight attribute="desc" hit={item} />
</li>
);
})}
</ol>
</>
);
};
const CustomHits = connectHits(Hits);
export default CustomHits;

View File

@ -0,0 +1,31 @@
import { FC } from 'react';
import { connectSearchBox } from 'react-instantsearch-dom';
import { SearchBoxProvided } from 'react-instantsearch-core';
import {
InputGroup,
Input,
InputRightElement,
CloseButton,
} from '@chakra-ui/react';
const SearchBox: FC<SearchBoxProvided> = ({ currentRefinement, refine }) => {
return (
<>
<InputGroup>
<Input
value={currentRefinement}
onChange={(event) => refine(event.currentTarget.value)}
autoFocus
placeholder="Seach posts..."
/>
<InputRightElement>
{currentRefinement && <CloseButton onClick={() => refine('')} />}
</InputRightElement>
</InputGroup>
</>
);
};
const CustomSearchBox = connectSearchBox(SearchBox);
export default CustomSearchBox;

View File

@ -0,0 +1,50 @@
import { FC } from 'react';
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch } from 'react-instantsearch-dom';
import {
Flex,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalOverlay,
} from '@chakra-ui/react';
import CustomSearchBox from './CustomSearchBox';
import CustomHits from './CustomHits';
const searchClient = algoliasearch(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID ?? '',
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_API_KEY ?? ''
);
interface Props {
isModalOpen: boolean;
onModalClose: () => void;
}
const Search: FC<Props> = ({ isModalOpen, onModalClose }) => {
return (
<>
<Modal size="xl" isOpen={isModalOpen} onClose={onModalClose}>
<ModalOverlay />
<ModalContent>
<ModalBody p="0.5rem">
<InstantSearch searchClient={searchClient} indexName="rua">
<Flex justifyContent="space-between" alignItems="center">
<CustomSearchBox />
<ModalCloseButton
position="unset"
display={[null, null, 'none']}
/>
</Flex>
<CustomHits />
</InstantSearch>
</ModalBody>
</ModalContent>
</Modal>
</>
);
};
export default Search;

View File

@ -1,8 +1,14 @@
import { useEffect, useRef, useState } from 'react';
const useLazyLoad = (src: string) => {
/**
* Use IntersectionObserver API to lazy load taget DOM.
* @param src src path
* @param blurPx blur px
* @returns
*/
const useLazyLoad = (src: string, blurPx = '10px') => {
const targetRef = useRef(null);
const [blur, setBlur] = useState('blur(20px)');
const [blur, setBlur] = useState(`blur(${blurPx})`);
const [initSrc, setInitSrc] = useState(
'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='

View File

@ -1,4 +1,4 @@
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
}
};

View File

@ -7,6 +7,7 @@
"build": "next build",
"start": "next start",
"build:export": "next build && next export",
"postbuild": "node ./scripts/build-search.mjs",
"lint": "next lint",
"cypress": "cypress open",
"cypress:headless": "cypress run",
@ -21,8 +22,10 @@
"@giscus/react": "^1.0.1",
"@reduxjs/toolkit": "^1.6.2",
"ahooks": "^2.10.12",
"algoliasearch": "^4.11.0",
"autoprefixer": "^10.3.7",
"date-fns": "^2.25.0",
"dotenv": "^10.0.0",
"framer-motion": "^5.0.2",
"gray-matter": "^4.0.3",
"highlight.js": "^11.3.1",
@ -32,6 +35,7 @@
"react": "17.0.2",
"react-dom": "17.0.2",
"react-icons": "^4.3.1",
"react-instantsearch-dom": "^6.16.0",
"react-medium-image-zoom": "^4.3.5",
"react-redux": "^7.2.6",
"react-useanimations": "^2.0.6",
@ -51,6 +55,7 @@
"devDependencies": {
"@types/nprogress": "^0.2.0",
"@types/react": "17.0.31",
"@types/react-instantsearch-dom": "^6.12.0",
"@types/react-redux": "^7.1.20",
"cypress": "^9.0.0",
"eslint": "7.32.0",

5
pages/message.module.css Normal file
View File

@ -0,0 +1,5 @@
.wrapper h2 {
font-size: 1.6rem;
line-height: 2rem;
margin: 1rem 0;
}

37
pages/message.tsx Normal file
View File

@ -0,0 +1,37 @@
import { ReactElement } from 'react';
import useGetColors from '../lib/hooks/useGetColors';
import Head from 'next/head';
import { Box, Heading } from '@chakra-ui/react';
import style from './message.module.css';
import HomeLayout from '../layouts/HomeLayout';
const message = () => {
const { boxBg } = useGetColors();
return (
<>
<Head>
<title>RUA - Message</title>
</Head>
<Box
as="article"
w={['full', 'full', '55rem']}
borderRadius="10px"
shadow="lg"
overflow="hidden"
bg={boxBg}
p={['1rem', '1rem', '1.5rem']}
className={style.wrapper}
>
<Heading my="0.5rem">Hi, there 👋</Heading>
</Box>
</>
);
};
message.getLayout = function getLayout(page: ReactElement) {
return <HomeLayout>{page}</HomeLayout>;
};
export default message;

5
pages/pgp.module.css Normal file
View File

@ -0,0 +1,5 @@
.wrapper h2 {
font-size: 1.6rem;
line-height: 2rem;
margin: 1rem 0;
}

37
pages/pgp.tsx Normal file
View File

@ -0,0 +1,37 @@
import { ReactElement } from 'react';
import useGetColors from '../lib/hooks/useGetColors';
import Head from 'next/head';
import { Box, Heading } from '@chakra-ui/react';
import style from './pgp.module.css';
import HomeLayout from '../layouts/HomeLayout';
const pgp = () => {
const { boxBg } = useGetColors();
return (
<>
<Head>
<title>RUA - Message</title>
</Head>
<Box
as="article"
w={['full', 'full', '55rem']}
borderRadius="10px"
shadow="lg"
overflow="hidden"
bg={boxBg}
p={['1rem', '1rem', '1.5rem']}
className={style.wrapper}
>
<Heading my="0.5rem">Hi, there 👋</Heading>
</Box>
</>
);
};
pgp.getLayout = function getLayout(page: ReactElement) {
return <HomeLayout>{page}</HomeLayout>;
};
export default pgp;

View File

@ -13,7 +13,6 @@ import {
import { getAllPostSlugs, getPostData } from '../../lib/posts';
import { GetStaticProps, InferGetStaticPropsType } from 'next';
import Head from 'next/head';
import Date from '../../components/DateFormater';
import remarkToc from 'remark-toc';
import rehypeSlug from 'rehype-slug';
import rehypeReact from 'rehype-react';
@ -31,15 +30,18 @@ import rehypeRaw from 'rehype-raw';
import 'react-medium-image-zoom/dist/styles.css';
import { FiCalendar } from 'react-icons/fi';
import { useRouter } from 'next/router';
import Footer from '../../components/Footer';
import { Giscus } from '@giscus/react';
import { RootState } from '../../app/store';
import { cleanFromPath } from '../../features/router/routerSlice';
import CopyButton from '../../components/post/CopyButton';
import useGetColors from '../../lib/hooks/useGetColors';
import Zoom from 'react-medium-image-zoom';
import useLazyLoad from '../../lib/hooks/useLazyload';
import { useAppSelector, useAppDispatch } from '../../app/hooks';
import dynamic from 'next/dynamic';
const CopyButton = dynamic(() => import('../../components/post/CopyButton'));
const Footer = dynamic(() => import('../../components/Footer'));
const Date = dynamic(() => import('../../components/DateFormater'));
export async function getStaticPaths() {
const paths = await getAllPostSlugs();
@ -90,18 +92,13 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
createElement,
components: {
img: (props: any) => {
const { initSrc, blur, targetRef } = useLazyLoad(props.src);
const { initSrc, blur, targetRef } = useLazyLoad(props.src, '20px');
return (
<Zoom
wrapElement="a"
wrapStyle={{ width: '100%' }}
zoomMargin={isLargerThan768 ? 300 : 0}
>
<Zoom wrapElement="a" zoomMargin={isLargerThan768 ? 300 : 0}>
<Image
ref={targetRef}
borderRadius="10px"
src={initSrc}
w="100%"
filter={blur}
transitionDuration="slower"
alt="Post image"
@ -124,7 +121,7 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
filter={blur}
w="100%"
transitionDuration="slower"
ratio={16 / 9}
ratio={isLargerThan768 ? 16 / 9 : 1}
>
<Box as="iframe" src={initSrc} ref={targetRef}>
{props.child}

View File

@ -1,4 +0,0 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://cloudconvert.com/
HostUrl=https://storage.cloudconvert.com/tasks/26da36ae-4f65-40e0-9cfd-cacdae9421f8/default%20%281%29.webp?AWSAccessKeyId=cloudconvert-production&Expires=1637766629&Signature=YV2hGzZxW7vZKjg2JOI3jAZMIi4%3D&response-content-disposition=attachment%3B%20filename%3D%22default%20%281%29.webp%22&response-content-type=image%2Fwebp

View File

@ -1,4 +0,0 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://cloudconvert.com/
HostUrl=https://storage.cloudconvert.com/tasks/5cc2ab54-b332-4ded-af05-5ed4e8dc8cba/default2%20%281%29.webp?AWSAccessKeyId=cloudconvert-production&Expires=1637766757&Signature=LsEjK9%2BKehCwLMPFpEmV1wFV2wc%3D&response-content-disposition=attachment%3B%20filename%3D%22default2%20%281%29.webp%22&response-content-type=image%2Fwebp

91
scripts/build-search.mjs Normal file
View File

@ -0,0 +1,91 @@
import { config } from 'dotenv';
import algoliasearch from 'algoliasearch/lite.js';
import { readdir, readFile } from 'fs/promises';
import { join } from 'path';
import matter from 'gray-matter';
import { remark } from 'remark';
import strip from 'strip-markdown';
const postsDirectory = join(process.cwd(), 'public/posts');
/**
* Get all sorted posts
* @returns
*/
async function getSortedPostsData() {
// Get file names under /posts
const fileNames = await readdir(postsDirectory);
const allPostsData = await Promise.all(
fileNames.map(async (fileName) => {
// Remove ".md" from file name to get id
const id = fileName.replace(/\.md$/, '');
// Read markdown file as string
const fullPath = join(postsDirectory, fileName);
const fileContents = await readFile(fullPath, 'utf8');
// Use gray-matter to parse the post metadata section
const matterResult = matter(fileContents);
// Process markdown to plain text
const contentText = await remark()
.use(strip)
.process(matterResult.content);
// Combine the data with the id
return {
objectID: id,
id,
// Add post description
desc: `${contentText.toString().slice(0, 100)}...`,
...{
...matterResult.data,
date: matterResult.data.date.toISOString(),
},
};
})
);
// Sort posts by date
return allPostsData.sort(({ date: a }, { date: b }) => {
if (a < b) {
return 1;
} else if (a > b) {
return -1;
} else {
return 0;
}
});
}
(async function () {
// initialize environment variables
config();
try {
const posts = await getSortedPostsData();
// initialize the client with your environment variables
const client = algoliasearch(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
process.env.ALGOLIA_SEARCH_ADMIN_KEY
);
// initialize the index with your index name
const index = client.initIndex('rua');
// save the objects!
const algoliaResponse = await index.saveObjects(posts);
// check the output of the response in the console
console.log(
`🎉 Sucessfully added ${
algoliaResponse.objectIDs.length
} records to Algolia search. Object IDs:\n${algoliaResponse.objectIDs.join(
'\n'
)}`
);
} catch (e) {
console.log(e);
}
})();

View File

@ -14,6 +14,18 @@
"isolatedModules": true,
"jsx": "preserve"
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"ts-node": {
"compilerOptions": {
"esModuleInterop": true,
"module": "CommonJS"
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"lib/build-search.js",
"scripts/build-search.mjs"
],
"exclude": ["node_modules"]
}

187
yarn.lock
View File

@ -10,6 +10,110 @@
lodash.debounce "^4.0.8"
lodash.throttle "^4.1.1"
"@algolia/cache-browser-local-storage@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.11.0.tgz#1c168add00b398a860db6c86039e33b2843a9425"
integrity sha512-4sr9vHIG1fVA9dONagdzhsI/6M5mjs/qOe2xUP0yBmwsTsuwiZq3+Xu6D3dsxsuFetcJgC6ydQoCW8b7fDJHYQ==
dependencies:
"@algolia/cache-common" "4.11.0"
"@algolia/cache-common@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.11.0.tgz#066fe6d58b18e4b028dbef9bb8de07c5e22a3594"
integrity sha512-lODcJRuPXqf+6mp0h6bOxPMlbNoyn3VfjBVcQh70EDP0/xExZbkpecgHyyZK4kWg+evu+mmgvTK3GVHnet/xKw==
"@algolia/cache-in-memory@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.11.0.tgz#763c8cb655e6fd2261588e04214fca0959ac07c1"
integrity sha512-aBz+stMSTBOBaBEQ43zJXz2DnwS7fL6dR0e2myehAgtfAWlWwLDHruc/98VOy1ZAcBk1blE2LCU02bT5HekGxQ==
dependencies:
"@algolia/cache-common" "4.11.0"
"@algolia/client-account@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.11.0.tgz#67fadd3b0802b013ebaaa4b47bb7babae892374e"
integrity sha512-jwmFBoUSzoMwMqgD3PmzFJV/d19p1RJXB6C1ADz4ju4mU7rkaQLtqyZroQpheLoU5s5Tilmn/T8/0U2XLoJCRQ==
dependencies:
"@algolia/client-common" "4.11.0"
"@algolia/client-search" "4.11.0"
"@algolia/transporter" "4.11.0"
"@algolia/client-analytics@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.11.0.tgz#cbdc8128205e2da749cafc79e54708d14c413974"
integrity sha512-v5U9585aeEdYml7JqggHAj3E5CQ+jPwGVztPVhakBk8H/cmLyPS2g8wvmIbaEZCHmWn4TqFj3EBHVYxAl36fSA==
dependencies:
"@algolia/client-common" "4.11.0"
"@algolia/client-search" "4.11.0"
"@algolia/requester-common" "4.11.0"
"@algolia/transporter" "4.11.0"
"@algolia/client-common@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.11.0.tgz#9a2d1f6f8eaad25ba5d6d4ce307ba5bd84e6f999"
integrity sha512-Qy+F+TZq12kc7tgfC+FM3RvYH/Ati7sUiUv/LkvlxFwNwNPwWGoZO81AzVSareXT/ksDDrabD4mHbdTbBPTRmQ==
dependencies:
"@algolia/requester-common" "4.11.0"
"@algolia/transporter" "4.11.0"
"@algolia/client-personalization@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.11.0.tgz#d3bf0e760f85df876b4baf5b81996f0aa3a59940"
integrity sha512-mI+X5IKiijHAzf9fy8VSl/GTT67dzFDnJ0QAM8D9cMPevnfX4U72HRln3Mjd0xEaYUOGve8TK/fMg7d3Z5yG6g==
dependencies:
"@algolia/client-common" "4.11.0"
"@algolia/requester-common" "4.11.0"
"@algolia/transporter" "4.11.0"
"@algolia/client-search@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.11.0.tgz#c1105d715a2a04ba27231eca86f5d6620f68f4ae"
integrity sha512-iovPLc5YgiXBdw2qMhU65sINgo9umWbHFzInxoNErWnYoTQWfXsW6P54/NlKx5uscoLVjSf+5RUWwFu5BX+lpw==
dependencies:
"@algolia/client-common" "4.11.0"
"@algolia/requester-common" "4.11.0"
"@algolia/transporter" "4.11.0"
"@algolia/logger-common@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.11.0.tgz#bac1c2d59d29dee378b57412c8edd435b97de663"
integrity sha512-pRMJFeOY8hoWKIxWuGHIrqnEKN/kqKh7UilDffG/+PeEGxBuku+Wq5CfdTFG0C9ewUvn8mAJn5BhYA5k8y0Jqg==
"@algolia/logger-console@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.11.0.tgz#ced19e3abb22eb782ed5268d51efb5aa9ef109ef"
integrity sha512-wXztMk0a3VbNmYP8Kpc+F7ekuvaqZmozM2eTLok0XIshpAeZ/NJDHDffXK2Pw+NF0wmHqurptLYwKoikjBYvhQ==
dependencies:
"@algolia/logger-common" "4.11.0"
"@algolia/requester-browser-xhr@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.11.0.tgz#f9e1ad56f185432aa8dde8cad53ae271fd5d6181"
integrity sha512-Fp3SfDihAAFR8bllg8P5ouWi3+qpEVN5e7hrtVIYldKBOuI/qFv80Zv/3/AMKNJQRYglS4zWyPuqrXm58nz6KA==
dependencies:
"@algolia/requester-common" "4.11.0"
"@algolia/requester-common@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.11.0.tgz#d16de98d3ff72434bac39e4d915eab08035946a9"
integrity sha512-+cZGe/9fuYgGuxjaBC+xTGBkK7OIYdfapxhfvEf03dviLMPmhmVYFJtJlzAjQ2YmGDJpHrGgAYj3i/fbs8yhiA==
"@algolia/requester-node-http@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.11.0.tgz#beb2b6b68d5f4ce15aec80ede623f0ac96991368"
integrity sha512-qJIk9SHRFkKDi6dMT9hba8X1J1z92T5AZIgl+tsApjTGIRQXJLTIm+0q4yOefokfu4CoxYwRZ9QAq+ouGwfeOg==
dependencies:
"@algolia/requester-common" "4.11.0"
"@algolia/transporter@4.11.0":
version "4.11.0"
resolved "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.11.0.tgz#a8de3c173093ceceb02b26b577395ce3b3d4b96f"
integrity sha512-k4dyxiaEfYpw4UqybK9q7lrFzehygo6KV3OCYJMMdX0IMWV0m4DXdU27c1zYRYtthaFYaBzGF4Kjcl8p8vxCKw==
dependencies:
"@algolia/cache-common" "4.11.0"
"@algolia/logger-common" "4.11.0"
"@algolia/requester-common" "4.11.0"
"@babel/code-frame@7.12.11":
version "7.12.11"
resolved "https://registry.npmmirror.com/@babel/code-frame/download/@babel/code-frame-7.12.11.tgz?cache=0&sync_timestamp=1633554562995&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
@ -1153,6 +1257,23 @@
resolved "https://registry.nlark.com/@types/prop-types/download/@types/prop-types-15.7.4.tgz?cache=0&sync_timestamp=1629708737049&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fprop-types%2Fdownload%2F%40types%2Fprop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
integrity sha1-/PcgXCXf95Xuea8eMNosl5CAjxE=
"@types/react-instantsearch-core@*":
version "6.10.5"
resolved "https://registry.npmjs.org/@types/react-instantsearch-core/-/react-instantsearch-core-6.10.5.tgz#909870ad8bbdbd8ba501b34df8f952d983c3d8ce"
integrity sha512-VjXJFUfsPdWMSiugJiQc950G9ZRjCEIzqQ9/K915d1f1BsVE2TE57PcfHSxAy1pGDDR8FT5uAgAaOMyKJ66NJQ==
dependencies:
"@types/react" "*"
algoliasearch ">=4"
algoliasearch-helper ">=3"
"@types/react-instantsearch-dom@^6.12.0":
version "6.12.0"
resolved "https://registry.npmjs.org/@types/react-instantsearch-dom/-/react-instantsearch-dom-6.12.0.tgz#716be1b48193bbb65271205a9bd112a65d8a2661"
integrity sha512-O08H+ye4e4kEnYHmMrov9FPNRDJwfCWthNZf4aztqahpU8LSbAiuFQGVy84SHUvg/jfNcG4333SsVnAQLtbS7A==
dependencies:
"@types/react" "*"
"@types/react-instantsearch-core" "*"
"@types/react-redux@^7.1.20":
version "7.1.20"
resolved "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz#42f0e61ababb621e12c66c96dda94c58423bd7df"
@ -1334,6 +1455,33 @@ ajv@^8.0.1:
require-from-string "^2.0.2"
uri-js "^4.2.2"
algoliasearch-helper@>=3, algoliasearch-helper@^3.6.2:
version "3.6.2"
resolved "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.6.2.tgz#45e19b12589cfa0c611b573287f65266ea2cc14a"
integrity sha512-Xx0NOA6k4ySn+R2l3UMSONAaMkyfmrZ3AP1geEMo32MxDJQJesZABZYsldO9fa6FKQxH91afhi4hO1G0Zc2opg==
dependencies:
events "^1.1.1"
algoliasearch@>=4, algoliasearch@^4.11.0:
version "4.11.0"
resolved "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.11.0.tgz#234befb3ac355c094077f0edf3777240b1ee013c"
integrity sha512-IXRj8kAP2WrMmj+eoPqPc6P7Ncq1yZkFiyDrjTBObV1ADNL8Z/KdZ+dWC5MmYcBLAbcB/mMCpak5N/D1UIZvsA==
dependencies:
"@algolia/cache-browser-local-storage" "4.11.0"
"@algolia/cache-common" "4.11.0"
"@algolia/cache-in-memory" "4.11.0"
"@algolia/client-account" "4.11.0"
"@algolia/client-analytics" "4.11.0"
"@algolia/client-common" "4.11.0"
"@algolia/client-personalization" "4.11.0"
"@algolia/client-search" "4.11.0"
"@algolia/logger-common" "4.11.0"
"@algolia/logger-console" "4.11.0"
"@algolia/requester-browser-xhr" "4.11.0"
"@algolia/requester-common" "4.11.0"
"@algolia/requester-node-http" "4.11.0"
"@algolia/transporter" "4.11.0"
anser@1.4.9:
version "1.4.9"
resolved "https://registry.npmmirror.com/anser/download/anser-1.4.9.tgz#1f85423a5dcf8da4631a341665ff675b96845760"
@ -1870,6 +2018,11 @@ classnames@2.2.6:
resolved "https://registry.npm.taobao.org/classnames/download/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha1-Q5Nb/90pHzJtrQogUwmzjQD2UM4=
classnames@^2.2.5:
version "2.3.1"
resolved "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
clean-stack@^2.0.0:
version "2.2.0"
resolved "https://registry.nlark.com/clean-stack/download/clean-stack-2.2.0.tgz?cache=0&sync_timestamp=1621915044030&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fclean-stack%2Fdownload%2Fclean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
@ -2322,6 +2475,11 @@ domain-browser@^1.1.1:
resolved "https://registry.nlark.com/domain-browser/download/domain-browser-1.2.0.tgz?cache=0&sync_timestamp=1627591557212&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdomain-browser%2Fdownload%2Fdomain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
integrity sha1-PTH1AZGmdJ3RN1p/Ui6CPULlTto=
dotenv@^10.0.0:
version "10.0.0"
resolved "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==
duplexer@~0.1.1:
version "0.1.2"
resolved "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fduplexer%2Fdownload%2Fduplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
@ -2709,6 +2867,11 @@ eventemitter2@^6.4.3:
resolved "https://registry.npmmirror.com/eventemitter2/download/eventemitter2-6.4.5.tgz?cache=0&sync_timestamp=1633287607262&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feventemitter2%2Fdownload%2Feventemitter2-6.4.5.tgz#97380f758ae24ac15df8353e0cc27f8b95644655"
integrity sha1-lzgPdYriSsFd+DU+DMJ/i5VkRlU=
events@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=
events@^3.0.0:
version "3.3.0"
resolved "https://registry.nlark.com/events/download/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
@ -5306,7 +5469,7 @@ react-dom@17.0.2:
object-assign "^4.1.1"
scheduler "^0.20.2"
react-fast-compare@3.2.0:
react-fast-compare@3.2.0, react-fast-compare@^3.0.0:
version "3.2.0"
resolved "https://registry.npm.taobao.org/react-fast-compare/download/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
integrity sha1-ZBqdqBtqYyDycOiXJPtFoLOeQ7s=
@ -5328,6 +5491,28 @@ react-icons@^4.3.1:
resolved "https://registry.npmmirror.com/react-icons/download/react-icons-4.3.1.tgz#2fa92aebbbc71f43d2db2ed1aed07361124e91ca"
integrity sha1-L6kq67vHH0PS2y7RrtBzYRJOkco=
react-instantsearch-core@^6.16.0:
version "6.16.0"
resolved "https://registry.npmjs.org/react-instantsearch-core/-/react-instantsearch-core-6.16.0.tgz#6e64fb81628605073d247331959ef9f3978c0046"
integrity sha512-urtTbVWafrW5XqAVDW6LntU0yK4WF5L6Ms+P6SIKhYXq9FX3i3JtKWKR+9ebJU/0x7CDvfBr9f45EHD9SiX1hw==
dependencies:
"@babel/runtime" "^7.1.2"
algoliasearch-helper "^3.6.2"
prop-types "^15.6.2"
react-fast-compare "^3.0.0"
react-instantsearch-dom@^6.16.0:
version "6.16.0"
resolved "https://registry.npmjs.org/react-instantsearch-dom/-/react-instantsearch-dom-6.16.0.tgz#db179c0be48f4e85ba179339be75bf58f68696d2"
integrity sha512-fciP0/XRk0/Hi0E4db6zrwC1mW/4Gui9X1q/pBUxDivQtUGGd3RHfhjv9pYHca3ha+251bzcUgjvgJpty+xJ5A==
dependencies:
"@babel/runtime" "^7.1.2"
algoliasearch-helper "^3.6.2"
classnames "^2.2.5"
prop-types "^15.6.2"
react-fast-compare "^3.0.0"
react-instantsearch-core "^6.16.0"
react-is@17.0.2, react-is@^17.0.2:
version "17.0.2"
resolved "https://registry.npmmirror.com/react-is/download/react-is-17.0.2.tgz?cache=0&sync_timestamp=1634892328318&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Freact-is%2Fdownload%2Freact-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"