33import { Icon } from "@garden-co/design-system/src/components/atoms/Icon" ;
44import { clsx } from "clsx" ;
55import { useEffect , useState } from "react" ;
6-
7- /**
8- * Simple HTML to Markdown converter for common elements
9- */
10- function htmlToMarkdown ( html : string ) : string {
11- // Create a temporary container to parse HTML
12- const tempDiv = document . createElement ( "div" ) ;
13- tempDiv . innerHTML = html ;
14-
15- function convertNode ( node : Node ) : string {
16- if ( node . nodeType === Node . TEXT_NODE ) {
17- return node . textContent || "" ;
18- }
19-
20- if ( node . nodeType !== Node . ELEMENT_NODE ) {
21- return "" ;
22- }
23-
24- const element = node as Element ;
25- const tagName = element . tagName . toLowerCase ( ) ;
26- const children = Array . from ( element . childNodes )
27- . map ( convertNode )
28- . join ( "" )
29- . trim ( ) ;
30-
31- switch ( tagName ) {
32- case "h1" :
33- return `# ${ children } \n\n` ;
34- case "h2" :
35- return `## ${ children } \n\n` ;
36- case "h3" :
37- return `### ${ children } \n\n` ;
38- case "h4" :
39- return `#### ${ children } \n\n` ;
40- case "h5" :
41- return `##### ${ children } \n\n` ;
42- case "h6" :
43- return `###### ${ children } \n\n` ;
44- case "p" :
45- return `${ children } \n\n` ;
46- case "strong" :
47- case "b" :
48- return `**${ children } **` ;
49- case "em" :
50- case "i" :
51- return `*${ children } *` ;
52- case "code" :
53- // Check if parent is pre (code block) or inline
54- if ( element . parentElement ?. tagName . toLowerCase ( ) === "pre" ) {
55- return children ;
56- }
57- return `\`${ children } \`` ;
58- case "pre" :
59- const codeElement = element . querySelector ( "code" ) ;
60- const language = codeElement ?. className
61- ?. replace ( / l a n g u a g e - / , "" )
62- . replace ( / h l j s \s + / , "" ) || "" ;
63- const codeContent = codeElement
64- ? Array . from ( codeElement . childNodes )
65- . map ( convertNode )
66- . join ( "" )
67- : children ;
68- return `\`\`\`${ language } \n${ codeContent } \n\`\`\`\n\n` ;
69- case "ul" :
70- return `${ children } \n` ;
71- case "ol" :
72- return `${ children } \n` ;
73- case "li" :
74- const parent = element . parentElement ;
75- const isOrdered = parent ?. tagName . toLowerCase ( ) === "ol" ;
76- const index = parent
77- ? Array . from ( parent . children ) . indexOf ( element ) + 1
78- : 1 ;
79- const prefix = isOrdered ? `${ index } . ` : "- " ;
80- return `${ prefix } ${ children } \n` ;
81- case "a" :
82- const href = element . getAttribute ( "href" ) || "" ;
83- return `[${ children } ](${ href } )` ;
84- case "blockquote" :
85- return `> ${ children . split ( "\n" ) . join ( "\n> " ) } \n\n` ;
86- case "hr" :
87- return `---\n\n` ;
88- case "br" :
89- return "\n" ;
90- case "table" :
91- const thead = element . querySelector ( "thead" ) ;
92- const tbody = element . querySelector ( "tbody" ) ;
93- let result = "" ;
94-
95- // Process header row
96- if ( thead ) {
97- const headerRow = thead . querySelector ( "tr" ) ;
98- if ( headerRow ) {
99- const headerCells = Array . from ( headerRow . children )
100- . map ( ( cell ) => {
101- const cellContent = Array . from ( cell . childNodes )
102- . map ( convertNode )
103- . join ( "" )
104- . trim ( ) ;
105- return cellContent ;
106- } )
107- . join ( " | " ) ;
108- result += `| ${ headerCells } |\n` ;
109- // Add separator row
110- const cellCount = headerRow . children . length ;
111- result += `| ${ Array ( cellCount ) . fill ( "---" ) . join ( " | " ) } |\n` ;
112- }
113- }
114-
115- // Process body rows
116- if ( tbody ) {
117- const rows = tbody . querySelectorAll ( "tr" ) ;
118- rows . forEach ( ( row ) => {
119- const cells = Array . from ( row . children )
120- . map ( ( cell ) => {
121- const cellContent = Array . from ( cell . childNodes )
122- . map ( convertNode )
123- . join ( "" )
124- . trim ( ) ;
125- return cellContent ;
126- } )
127- . join ( " | " ) ;
128- result += `| ${ cells } |\n` ;
129- } ) ;
130- }
131-
132- return result + "\n" ;
133- case "thead" :
134- case "tbody" :
135- // Handled in table
136- return children ;
137- case "tr" :
138- // Handled in table/thead/tbody
139- return children ;
140- case "th" :
141- case "td" :
142- // Handled in tr
143- return children ;
144- case "img" :
145- const src = element . getAttribute ( "src" ) || "" ;
146- const alt = element . getAttribute ( "alt" ) || "" ;
147- return `` ;
148- default :
149- return children ;
150- }
151- }
152-
153- return Array . from ( tempDiv . childNodes )
154- . map ( convertNode )
155- . join ( "" )
156- . replace ( / \n { 3 , } / g, "\n\n" )
157- . trim ( ) ;
158- }
6+ import { usePathname } from "next/navigation" ;
1597
1608export function CopyAsMarkdownButton ( ) {
1619 const [ copied , setCopied ] = useState ( false ) ;
16210 const [ isLoading , setIsLoading ] = useState ( false ) ;
11+ const pathname = usePathname ( ) ;
16312
16413 useEffect ( ( ) => {
16514 if ( copied ) {
@@ -171,23 +20,16 @@ export function CopyAsMarkdownButton() {
17120 const handleCopy = async ( ) => {
17221 setIsLoading ( true ) ;
17322 try {
174- // Find the prose content area
175- const proseElement = document . querySelector ( ".prose" ) ;
176- if ( ! proseElement ) {
177- console . error ( "Could not find prose element" ) ;
178- return ;
23+ // Append .md to the current pathname to get the markdown route
24+ const markdownUrl = `${ pathname } .md` ;
25+
26+ // Fetch the markdown from the route
27+ const response = await fetch ( markdownUrl ) ;
28+ if ( ! response . ok ) {
29+ throw new Error ( `Failed to fetch markdown: ${ response . statusText } ` ) ;
17930 }
18031
181- // Clone the element to avoid modifying the original
182- const cloned = proseElement . cloneNode ( true ) as HTMLElement ;
183-
184- // Remove elements that shouldn't be in markdown
185- cloned . querySelectorAll ( ".not-prose, [data-pagefind-ignore]" ) . forEach ( ( el ) => {
186- el . remove ( ) ;
187- } ) ;
188-
189- // Convert HTML to markdown
190- const markdown = htmlToMarkdown ( cloned . innerHTML ) ;
32+ const markdown = await response . text ( ) ;
19133
19234 // Copy to clipboard
19335 await navigator . clipboard . writeText ( markdown ) ;
0 commit comments