feat: add post toc
This commit is contained in:
parent
1258a97714
commit
576aed6e68
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div className={clsx("xlog-post-content", `prose`, className)}>
|
||||
{content && renderPageContent(content).element}
|
||||
{content && renderPageContent(content, false, toc).element}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import { useRef, useEffect, useState } from "react"
|
||||
|
||||
export const PostToc: React.FC<{
|
||||
children: React.ReactNode
|
||||
}> = ({ children }) => {
|
||||
const containerRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
const [maxWidth, setMaxWidth] = useState(0)
|
||||
useEffect(() => {
|
||||
if (containerRef?.current) {
|
||||
setMaxWidth(
|
||||
(window.innerWidth -
|
||||
(containerRef.current?.parentElement?.clientWidth || 0)) /
|
||||
2 -
|
||||
40,
|
||||
)
|
||||
}
|
||||
}, [containerRef])
|
||||
|
||||
return (
|
||||
<div
|
||||
className="xlog-post-toc absolute left-full pl-10 h-full top-0"
|
||||
style={{
|
||||
maxWidth: maxWidth > 40 ? maxWidth : 0,
|
||||
}}
|
||||
ref={containerRef}
|
||||
>
|
||||
<div className="sticky top-14 text-sm leading-loose whitespace-nowrap truncate text-ellipsis">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ export const SitePage: React.FC<{
|
|||
<PageContent
|
||||
className="mt-10"
|
||||
content={page?.body?.content}
|
||||
toc={true}
|
||||
></PageContent>
|
||||
<PostFooter page={page} />
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: "<toc>" },
|
||||
result.map,
|
||||
{ type: "html", value: "</toc>" },
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
.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)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const scheme = {
|
|||
"iframe",
|
||||
"style",
|
||||
"youtube",
|
||||
"toc",
|
||||
],
|
||||
attributes: {
|
||||
...defaultSchema.attributes,
|
||||
|
|
|
|||
Loading…
Reference in New Issue