From 576aed6e689d1779e1a4410f79574b4bde203bc5 Mon Sep 17 00:00:00 2001 From: DIYgod Date: Wed, 5 Oct 2022 21:11:59 +0100 Subject: [PATCH] feat: add post toc --- package.json | 2 +- pnpm-lock.yaml | 12 ++-------- src/components/common/PageContent.tsx | 5 ++-- src/components/site/PostToc.tsx | 33 +++++++++++++++++++++++++++ src/components/site/SitePage.tsx | 1 + src/css/prose.css | 8 +++++-- src/markdown/index.ts | 24 ++++++++++++++----- src/markdown/sanitize-schema.ts | 1 + 8 files changed, 65 insertions(+), 21 deletions(-) create mode 100644 src/components/site/PostToc.tsx diff --git a/package.json b/package.json index 5ee9f5f4..44ad4c72 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "ioredis": "^5.2.3", "js-yaml": "^4.1.0", "mdast-util-to-string": "^3.1.0", + "mdast-util-toc": "^6.1.0", "nanoid": "^4.0.0", "next": "^12.3.1", "nextjs-progressbar": "^0.0.14", @@ -89,7 +90,6 @@ "remark-parse": "^10.0.1", "remark-rehype": "^10.1.0", "remark-stringify": "^10.0.2", - "remark-toc": "^8.0.1", "sharp": "^0.31.0", "sortablejs": "^1.15.0", "ua-parser-js": "^1.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 79a36a4e..f94a8a37 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -76,6 +76,7 @@ specifiers: js-yaml: ^4.1.0 lint-staged: ^13.0.3 mdast-util-to-string: ^3.1.0 + mdast-util-toc: ^6.1.0 nanoid: ^4.0.0 next: ^12.3.1 nextjs-progressbar: ^0.0.14 @@ -109,7 +110,6 @@ specifiers: remark-parse: ^10.0.1 remark-rehype: ^10.1.0 remark-stringify: ^10.0.2 - remark-toc: ^8.0.1 sharp: ^0.31.0 sortablejs: ^1.15.0 tailwindcss: ^3.1.8 @@ -170,6 +170,7 @@ dependencies: ioredis: 5.2.3 js-yaml: 4.1.0 mdast-util-to-string: 3.1.0 + mdast-util-toc: 6.1.0 nanoid: 4.0.0 next: 12.3.1_biqbaboplfbrettd7655fr4n2y nextjs-progressbar: 0.0.14_next@12.3.1+react@18.2.0 @@ -201,7 +202,6 @@ dependencies: remark-parse: 10.0.1 remark-rehype: 10.1.0 remark-stringify: 10.0.2 - remark-toc: 8.0.1 sharp: 0.31.0 sortablejs: 1.15.0 ua-parser-js: 1.0.2 @@ -9396,14 +9396,6 @@ packages: unified: 10.1.2 dev: false - /remark-toc/8.0.1: - resolution: {integrity: sha512-7he2VOm/cy13zilnOTZcyAoyoolV26ULlon6XyCFU+vG54Z/LWJnwphj/xKIDLOt66QmJUgTyUvLVHi2aAElyg==} - dependencies: - '@types/mdast': 3.0.10 - mdast-util-toc: 6.1.0 - unified: 10.1.2 - dev: false - /remove-accents/0.4.2: resolution: {integrity: sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==} dev: false diff --git a/src/components/common/PageContent.tsx b/src/components/common/PageContent.tsx index ad7d9715..c04ab2d1 100644 --- a/src/components/common/PageContent.tsx +++ b/src/components/common/PageContent.tsx @@ -5,7 +5,8 @@ import { renderPageContent } from "~/markdown" export const PageContent: React.FC<{ content?: string className?: string -}> = ({ className, content }) => { + toc?: boolean +}> = ({ className, content, toc }) => { useCodeCopy() // TODO @@ -21,7 +22,7 @@ export const PageContent: React.FC<{ return (
- {content && renderPageContent(content).element} + {content && renderPageContent(content, false, toc).element}
) } diff --git a/src/components/site/PostToc.tsx b/src/components/site/PostToc.tsx new file mode 100644 index 00000000..81fb84e9 --- /dev/null +++ b/src/components/site/PostToc.tsx @@ -0,0 +1,33 @@ +import { useRef, useEffect, useState } from "react" + +export const PostToc: React.FC<{ + children: React.ReactNode +}> = ({ children }) => { + const containerRef = useRef(null) + + const [maxWidth, setMaxWidth] = useState(0) + useEffect(() => { + if (containerRef?.current) { + setMaxWidth( + (window.innerWidth - + (containerRef.current?.parentElement?.clientWidth || 0)) / + 2 - + 40, + ) + } + }, [containerRef]) + + return ( +
40 ? maxWidth : 0, + }} + ref={containerRef} + > +
+ {children} +
+
+ ) +} diff --git a/src/components/site/SitePage.tsx b/src/components/site/SitePage.tsx index a8d27036..d5eccf59 100644 --- a/src/components/site/SitePage.tsx +++ b/src/components/site/SitePage.tsx @@ -21,6 +21,7 @@ export const SitePage: React.FC<{ diff --git a/src/css/prose.css b/src/css/prose.css index 99da4d1c..014e9967 100644 --- a/src/css/prose.css +++ b/src/css/prose.css @@ -1,5 +1,5 @@ .prose { - @apply text-zinc-600 leading-loose; + @apply text-zinc-600 leading-loose relative; } .prose > p { @@ -66,7 +66,7 @@ .prose ol { @apply list-decimal; - @apply pl-5; + @apply pl-6; } .prose > ul, @@ -151,3 +151,7 @@ .prose .code-wrapper:hover .copy-button { @apply inline-flex; } + +.xlog-post-toc a { + @apply truncate inline-block max-w-full align-bottom text-zinc-700 hover:text-accent-dark; +} diff --git a/src/markdown/index.ts b/src/markdown/index.ts index 694b0ca2..7cc3c3c8 100644 --- a/src/markdown/index.ts +++ b/src/markdown/index.ts @@ -24,7 +24,8 @@ import { remarkYoutube } from "./remark-youtube" import sanitizeScheme from "./sanitize-schema" import rehypeSlug from "rehype-slug" import rehypeAutolinkHeadings from "rehype-autolink-headings" -import remarkToc from "remark-toc" +import { toc } from "mdast-util-toc" +import { PostToc } from "~/components/site/PostToc" export type MarkdownEnv = { excerpt: string @@ -48,6 +49,7 @@ const rehypePrism = rehypePrismGenerator(refractor) export const renderPageContent = ( content: string, html?: boolean, + enableToc?: boolean, ): Rendered => { const env: MarkdownEnv = { excerpt: "", @@ -70,9 +72,18 @@ export const renderPageContent = ( console.log(e) } }) - .use(remarkToc, { - tight: true, - ordered: true, + .use(() => (tree) => { + if (enableToc) { + const result = toc(tree, { tight: true, ordered: true }) + if (result.map) { + tree.children = [ + ...tree.children, + { type: "html", value: "" }, + result.map, + { type: "html", value: "" }, + ] + } + } }) .use(remarkGfm, {}) .use(remarkExcerpt, { env }) @@ -111,8 +122,9 @@ export const renderPageContent = ( .use(html ? () => (tree: any) => {} : rehypeReact, { createElement: createElement, components: { - img: Image as any, - }, + img: Image, + toc: PostToc, + } as any, }) .processSync(content) diff --git a/src/markdown/sanitize-schema.ts b/src/markdown/sanitize-schema.ts index 1ffadbbb..6054f27d 100644 --- a/src/markdown/sanitize-schema.ts +++ b/src/markdown/sanitize-schema.ts @@ -9,6 +9,7 @@ const scheme = { "iframe", "style", "youtube", + "toc", ], attributes: { ...defaultSchema.attributes,