mirror of
https://github.com/DefectingCat/DefectingCat.github.io
synced 2025-07-15 16:51:37 +00:00
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:
1
.gitignore
vendored
1
.gitignore
vendored
@ -27,6 +27,7 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
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} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
39
components/search/CustomHighlight.tsx
Normal file
39
components/search/CustomHighlight.tsx
Normal 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;
|
37
components/search/CustomHits.tsx
Normal file
37
components/search/CustomHits.tsx
Normal 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;
|
31
components/search/CustomSearchBox.tsx
Normal file
31
components/search/CustomSearchBox.tsx
Normal 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;
|
50
components/search/index.tsx
Normal file
50
components/search/index.tsx
Normal 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;
|
@ -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=='
|
||||
|
@ -1,4 +1,4 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
module.exports = {
|
||||
reactStrictMode: true,
|
||||
}
|
||||
};
|
||||
|
@ -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
5
pages/message.module.css
Normal file
@ -0,0 +1,5 @@
|
||||
.wrapper h2 {
|
||||
font-size: 1.6rem;
|
||||
line-height: 2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
37
pages/message.tsx
Normal file
37
pages/message.tsx
Normal 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
5
pages/pgp.module.css
Normal file
@ -0,0 +1,5 @@
|
||||
.wrapper h2 {
|
||||
font-size: 1.6rem;
|
||||
line-height: 2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
37
pages/pgp.tsx
Normal file
37
pages/pgp.tsx
Normal 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;
|
@ -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}
|
||||
|
@ -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
|
@ -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
91
scripts/build-search.mjs
Normal 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);
|
||||
}
|
||||
})();
|
@ -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
187
yarn.lock
@ -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"
|
||||
|
Reference in New Issue
Block a user