@@ -2,11 +2,42 @@ import { MDXRemote } from 'next-mdx-remote/rsc';
22import remarkGfm from 'remark-gfm' ;
33import rehypeHighlight from 'rehype-highlight' ;
44import rehypeSlug from 'rehype-slug' ;
5+ import type { ComponentPropsWithoutRef , ReactNode } from 'react' ;
56
67interface MarkdownContentProps {
78 content : string ;
89}
910
11+ type HeadingLevel = 'h2' | 'h3' | 'h4' | 'h5' | 'h6' ;
12+
13+ function createLinkableHeading ( level : HeadingLevel ) {
14+ return function LinkableHeading ( {
15+ children,
16+ id,
17+ ...props
18+ } : ComponentPropsWithoutRef < HeadingLevel > & { children ?: ReactNode } ) {
19+ return (
20+ < div className = "group relative" >
21+ { id && (
22+ < a
23+ href = { `#${ id } ` }
24+ aria-label = { `Copy link to this section: ${ id } ` }
25+ title = "Copy section link"
26+ className = "absolute -left-6 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 focus:opacity-100 no-underline transition-opacity text-gray-500 hover:text-black"
27+ >
28+ #
29+ </ a >
30+ ) }
31+ { level === 'h2' && < h2 id = { id } { ...props } > { children } </ h2 > }
32+ { level === 'h3' && < h3 id = { id } { ...props } > { children } </ h3 > }
33+ { level === 'h4' && < h4 id = { id } { ...props } > { children } </ h4 > }
34+ { level === 'h5' && < h5 id = { id } { ...props } > { children } </ h5 > }
35+ { level === 'h6' && < h6 id = { id } { ...props } > { children } </ h6 > }
36+ </ div >
37+ ) ;
38+ } ;
39+ }
40+
1041export default async function MarkdownContent ( { content } : MarkdownContentProps ) {
1142 return (
1243 < div className = "prose prose-lg max-w-none
@@ -22,6 +53,13 @@ export default async function MarkdownContent({ content }: MarkdownContentProps)
2253 prose-strong:font-bold prose-strong:text-black" >
2354 < MDXRemote
2455 source = { content }
56+ components = { {
57+ h2 : createLinkableHeading ( 'h2' ) ,
58+ h3 : createLinkableHeading ( 'h3' ) ,
59+ h4 : createLinkableHeading ( 'h4' ) ,
60+ h5 : createLinkableHeading ( 'h5' ) ,
61+ h6 : createLinkableHeading ( 'h6' ) ,
62+ } }
2563 options = { {
2664 mdxOptions : {
2765 remarkPlugins : [ remarkGfm ] ,
@@ -32,4 +70,3 @@ export default async function MarkdownContent({ content }: MarkdownContentProps)
3270 </ div >
3371 ) ;
3472}
35-
0 commit comments