Fix checklist in markdown

* Add strip-markdown
* Add CopyButton component
* Fix copy code
* Add about page
* Use async function with get all markdown content
* Add shortcut icon
* Remove useless code
This commit is contained in:
DefectingCat
2021-11-20 11:34:21 +08:00
parent f19f817ad1
commit 1d48411138
12 changed files with 189 additions and 157 deletions

View File

@ -1,38 +1,7 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## 小破站
## Getting Started
一个个人博客Powered by [Next.js](https://nextjs.org/).
First, run the development server:
## 施工中
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
## Todo
- [ ] Add types https://github1s.com/vercel/next.js/blob/canary/examples/blog-starter-typescript/
- [x] 归档页面

View File

@ -1,4 +1,4 @@
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
import { configureStore } from '@reduxjs/toolkit';
import routerReducer from '../features/router/routerSlice';
export const store = configureStore({

View File

@ -0,0 +1,39 @@
import { Button, useClipboard } from '@chakra-ui/react';
import { FC, MouseEventHandler, useEffect, useState } from 'react';
const CopyButton: FC = ({ children }) => {
// Copy code
const [codeContent, setCodeContent] = useState('');
const { hasCopied, onCopy } = useClipboard(codeContent);
const copyCode: MouseEventHandler<HTMLButtonElement> = (e) => {
const target = e.target as HTMLButtonElement;
// Button is sibling with Code tag
const codeToCopy = target.nextElementSibling?.textContent;
codeToCopy && setCodeContent(codeToCopy);
};
useEffect(() => {
codeContent && onCopy();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [codeContent]);
return (
<>
<pre>
<Button
size="xs"
colorScheme="teal"
position="absolute"
top="5px"
right="5px"
onClick={copyCode}
>
{hasCopied ? 'COPYIED' : 'COPY'}
</Button>
{children}
</pre>
</>
);
};
export default CopyButton;

View File

@ -1,7 +1,8 @@
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
import markdownToTxt from 'markdown-to-txt';
import { remark } from 'remark';
import strip from 'strip-markdown';
const postsDirectory = path.join(process.cwd(), 'public/posts');
@ -23,10 +24,11 @@ export interface AllPostsData extends MyMatters {
* Get all sorted posts
* @returns
*/
export function getSortedPostsData() {
export async function getSortedPostsData() {
// Get file names under /posts
const fileNames = fs.readdirSync(postsDirectory);
const allPostsData = fileNames.map((fileName) => {
const allPostsData = await Promise.all(
fileNames.map(async (fileName) => {
// Remove ".md" from file name to get id
const id = fileName.replace(/\.md$/, '');
@ -38,19 +40,22 @@ export function getSortedPostsData() {
const matterResult = matter(fileContents);
// Process markdown to plain text
const contentText = markdownToTxt(matterResult.content);
const contentText = await remark()
.use(strip)
.process(matterResult.content);
// Combine the data with the id
return {
id,
// Add post description
desc: `${contentText.slice(0, 100)}...`,
desc: `${contentText.toString().slice(0, 100)}...`,
...({
...matterResult.data,
date: matterResult.data.date.toISOString(),
} as MyMatters),
};
});
})
);
// Sort posts by date
return allPostsData.sort(({ date: a }, { date: b }) => {
@ -62,12 +67,6 @@ export function getSortedPostsData() {
return 0;
}
});
// Convert Date to locale string.
// return allPostsData.map((post) => {
// if (typeof post.date == 'object') post.date = post.date.toISOString();
// return post;
// });
}
/**
@ -119,7 +118,7 @@ export function getPagingData(allPostsData: AllPostsData[], start?: string) {
};
}
export function getAllPostSlugs() {
export async function getAllPostSlugs() {
const fileNames = fs.readdirSync(postsDirectory);
// Returns an array that looks like this:
@ -135,8 +134,9 @@ export function getAllPostSlugs() {
// }
// }
// ]
return fileNames.map((fileName) => {
const allPostsData = getSortedPostsData();
return await Promise.all(
fileNames.map(async (fileName) => {
const allPostsData = await getSortedPostsData();
const slug = allPostsData.find(
(item) => item.id === fileName.replace(/\.md$/, '')
);
@ -146,7 +146,8 @@ export function getAllPostSlugs() {
slug: slug?.url,
},
};
});
})
);
}
export interface MyPost extends AllPostsData {
@ -154,7 +155,7 @@ export interface MyPost extends AllPostsData {
}
export async function getPostData(slug: string) {
const allPostsData = getSortedPostsData();
const allPostsData = await getSortedPostsData();
const post = allPostsData.find((item) => item.url === slug);
const fullPath = path.join(postsDirectory, `${post?.id}.md`);

View File

@ -25,7 +25,6 @@
"framer-motion": "^5.0.2",
"gray-matter": "^4.0.3",
"highlight.js": "^11.3.1",
"markdown-to-txt": "^1.0.1",
"next": "11.1.2",
"postcss": "^8.3.11",
"react": "17.0.2",
@ -44,6 +43,7 @@
"remark-parse": "^10.0.0",
"remark-rehype": "^10.0.1",
"remark-toc": "^8.0.1",
"strip-markdown": "^5.0.0",
"unified": "^10.1.0"
},
"devDependencies": {

View File

@ -7,6 +7,7 @@ import { Provider } from 'react-redux';
import { store } from '../app/store';
import 'antd/dist/antd.css';
import '../assets/css/rua.css';
import Head from 'next/head';
const theme = extendTheme({
colors: {
@ -35,11 +36,17 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
const getLayout = Component.getLayout ?? ((page) => page);
return (
<>
<Head>
<link rel="shortcut icon" href="/images/img/favicon.webp"></link>
</Head>
<Provider store={store}>
<ChakraProvider theme={theme}>
{getLayout(<Component {...pageProps} />)}
</ChakraProvider>
</Provider>
</>
);
}
export default MyApp;

31
pages/about.tsx Normal file
View File

@ -0,0 +1,31 @@
import { Box } from '@chakra-ui/react';
import Head from 'next/head';
import { ReactElement } from 'react';
import HomeLayout from '../layouts/HomeLayout';
const about = () => {
return (
<>
<Head>
<title>RUA - About</title>
</Head>
<Box
w={['full', 'full', '55rem']}
borderRadius="10px"
shadow="lg"
bg="white"
overflow="hidden"
p={['1rem', '1rem', '1.5rem']}
>
...
</Box>
</>
);
};
about.getLayout = function getLayout(page: ReactElement) {
return <HomeLayout>{page}</HomeLayout>;
};
export default about;

View File

@ -7,7 +7,7 @@ import { getArchiveData, getSortedPostsData } from '../lib/posts';
import ArchiveCard from '../components/ArchiveCard';
export const getStaticProps = async () => {
const allPostsData = getSortedPostsData();
const allPostsData = await getSortedPostsData();
return {
props: {

View File

@ -7,7 +7,7 @@ import HomeLayout from '../layouts/HomeLayout';
import PostCard from '../components/PostCard';
export const getStaticProps = async () => {
const allPostsData = getSortedPostsData();
const allPostsData = await getSortedPostsData();
return {
props: {

View File

@ -10,13 +10,7 @@ import remarkParse from 'remark-parse';
import remarkGfm from 'remark-gfm';
import rehypeHighlight from 'rehype-highlight';
import { unified } from 'unified';
import {
createElement,
Fragment,
MouseEventHandler,
useEffect,
useState,
} from 'react';
import { createElement, Fragment } from 'react';
import {
Box,
Image,
@ -25,7 +19,6 @@ import {
Icon,
Link,
Button,
useClipboard,
Tag,
} from '@chakra-ui/react';
import 'highlight.js/styles/github.css';
@ -41,9 +34,10 @@ import { Giscus } from '@giscus/react';
import { RootState } from '../../app/store';
import { useSelector, useDispatch } from 'react-redux';
import { cleanFromPath } from '../../features/router/routerSlice';
import CopyButton from '../../components/post/CopyButton';
export async function getStaticPaths() {
const paths = getAllPostSlugs();
const paths = await getAllPostSlugs();
return {
paths,
fallback: false,
@ -66,23 +60,9 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
const goBack = () => {
dispatch(cleanFromPath());
router.push(fromPath);
router.push(fromPath || '/');
};
// Copy code
const [codeContent, setCodeContent] = useState('');
const { hasCopied, onCopy } = useClipboard(codeContent);
const copyCode: MouseEventHandler<HTMLButtonElement> = (e) => {
const target = e.target as HTMLButtonElement;
// Button is sibling with Code tag
const codeToCopy = target.nextElementSibling?.textContent;
codeToCopy && setCodeContent(codeToCopy);
};
useEffect(() => {
codeContent && onCopy();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [codeContent]);
const processedContent = unified()
.use(remarkParse)
.use(remarkToc, {
@ -116,23 +96,7 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
</Box>
);
},
pre: (props: any) => {
return (
<pre {...props}>
<Button
size="xs"
colorScheme="teal"
position="absolute"
top="5px"
right="5px"
onClick={copyCode}
>
{hasCopied ? 'COPYIED' : 'COPY'}
</Button>
{props.children}
</pre>
);
},
pre: CopyButton,
},
Fragment,
});
@ -165,6 +129,7 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
flexFlow={['column', 'column', 'row']}
px="0.5rem"
>
{/* Back button */}
<Button
size="lg"
mt={['1rem', '1rem', '3rem']}
@ -175,6 +140,7 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
BACK
</Button>
{/* Main article area */}
<Flex
w={['full', 'full', '55rem', '68rem']}
flexFlow="column"
@ -188,6 +154,7 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
overflow="hidden"
flex="1"
>
{/* Post image */}
{postData.index_img && (
<Image
src={postData.index_img}
@ -197,12 +164,15 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
alt="Head image"
/>
)}
{/* Post heading */}
<Box as="article" p={['1rem', '1rem', '2rem']}>
<Box as="header">
<Heading as="h1" mb="1rem">
{postData.title}
</Heading>
{/* Post tags */}
<Box mb="1rem">
{Array.isArray(postData.tags)
? // Mutil tags
@ -222,12 +192,14 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
</Flex>
</Box>
{/* Post content */}
<Box as="section" id="write" mt="2rem">
{postContent}
</Box>
</Box>
</Box>
{/* Comment */}
<Box mt="2rem">
<Giscus
repo="DefectingCat/DefectingCat.github.io"
@ -244,6 +216,7 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
<Footer />
</Flex>
{/* Table of content */}
{toc && (
<Box
display={['none', 'none', 'none', 'block']}

View File

@ -6,23 +6,6 @@ categories: 踩坑
url: markdown-test
---
## Hello world
This is a test.
---
__Advertisement :)__
- __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image
resize in browser.
- __[babelfish](https://github.com/nodeca/babelfish/)__ - developer friendly
i18n with plurals support and easy syntax.
You will like those projects!
---
# h1 Heading
## h2 Heading
### h3 Heading
#### h4 Heading
@ -38,6 +21,38 @@ ___
***
## Lists
### Solar System Exploration, 1950s 1960s
- [ ] Mercury
- [x] Venus
- [x] Earth (Orbit/Moon)
- [x] Mars
- [ ] Jupiter
- [ ] Saturn
- [ ] Uranus
- [ ] Neptune
- [ ] Comet Haley
### Numbers
1. One
2. Two
3. Three
### Solar System Exploration, 1950s 1960s
- Mercury
- Venus
- Earth (Orbit/Moon)
- Mars
- Jupiter
- Saturn
- Uranus
- Neptune
- Comet Haley
## Typographic replacements

View File

@ -1208,7 +1208,7 @@
resolved "https://registry.npmmirror.com/@types/sizzle/download/@types/sizzle-2.3.3.tgz?cache=0&sync_timestamp=1637272274009&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40types%2Fsizzle%2Fdownload%2F%40types%2Fsizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef"
integrity sha1-/14vGQKWnTBSJaBHyKD9XJFc6+8=
"@types/unist@*", "@types/unist@^2.0.0":
"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.6":
version "2.0.6"
resolved "https://registry.nlark.com/@types/unist/download/@types/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
integrity sha1-JQp7FsO5H2cqJFUuxkZ47rHToI0=
@ -4144,18 +4144,6 @@ markdown-table@^3.0.0:
resolved "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.1.tgz#88c48957aaf2a8014ccb2ba026776a1d736fe3dc"
integrity sha512-CBbaYXKSGnE1uLRpKA1SWgIRb2PQrpkllNWpZtZe6VojOJ4ysqiq7/2glYcmKsOYN09QgH/HEBX5hIshAeiK6A==
markdown-to-txt@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/markdown-to-txt/download/markdown-to-txt-1.0.1.tgz#f02528acaf77366d6f29569546de61acd74ba2b7"
integrity sha1-8CUorK93Nm1vKVaVRt5hrNdLorc=
dependencies:
marked "^0.6.2"
marked@^0.6.2:
version "0.6.3"
resolved "https://registry.npmmirror.com/marked/download/marked-0.6.3.tgz#79babad78af638ba4d522a9e715cdfdd2429e946"
integrity sha1-ebq614r2OLpNUiqecVzf3SQp6UY=
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@ -6512,6 +6500,15 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.nlark.com/strip-json-comments/download/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=
strip-markdown@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/strip-markdown/-/strip-markdown-5.0.0.tgz#222b864ecce6cf2ef87b2bb1e6466464e8127081"
integrity sha512-PXSts6Ta9A/TwGxVVSRlQs1ukJTAwwtbip2OheJEjPyfykaQ4sJSTnQWjLTI2vYWNts/R/91/csagp15W8n9gA==
dependencies:
"@types/mdast" "^3.0.0"
"@types/unist" "^2.0.6"
unified "^10.0.0"
style-to-object@^0.3.0:
version "0.3.0"
resolved "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46"