11'use client' ;
22
33import { cn } from '@/utils/cn' ;
4- import { Github , AlertCircle , MessageSquare , ChevronDown , ExternalLink } from 'lucide-react' ;
4+ import { Github , AlertCircle , MessageSquare , ChevronDown , ExternalLink , Copy , Check } from 'lucide-react' ;
55import newGithubIssueUrl from 'new-github-issue-url' ;
6+ import { useState } from 'react' ;
67import { Button } from '@/components/ui/button' ;
78import {
89 DropdownMenu ,
@@ -18,12 +19,53 @@ export interface SidebarActionsProps {
1819 pageType ?: 'docs' | 'academy' ;
1920}
2021
21- export function SidebarActions ( {
22- editUrl,
23- title,
22+ export function SidebarActions ( {
23+ editUrl,
24+ title,
2425 pagePath,
25- pageType = 'docs'
26+ pageType = 'docs'
2627} : SidebarActionsProps ) {
28+ const [ isCopyingMarkdown , setIsCopyingMarkdown ] = useState ( false ) ;
29+ const [ isCopied , setIsCopied ] = useState ( false ) ;
30+
31+ const handleCopyMarkdown = async ( ) => {
32+ setIsCopyingMarkdown ( true ) ;
33+ setIsCopied ( false ) ;
34+
35+ try {
36+ // Construct the full path with the correct prefix for the API
37+ const fullPath = pagePath . startsWith ( `/${ pageType } ` ) ? pagePath : `/${ pageType } ${ pagePath } ` ;
38+ const apiUrl = `${ window . location . origin } /api/llms/page?path=${ encodeURIComponent ( fullPath ) } ` ;
39+ const response = await fetch ( apiUrl ) ;
40+
41+ if ( ! response . ok ) {
42+ throw new Error ( 'Failed to fetch markdown content' ) ;
43+ }
44+
45+ const markdownContent = await response . text ( ) ;
46+ await navigator . clipboard . writeText ( markdownContent ) ;
47+ setIsCopied ( true ) ;
48+
49+ setTimeout ( ( ) => {
50+ setIsCopied ( false ) ;
51+ } , 2000 ) ;
52+ } catch ( err ) {
53+ console . error ( 'Failed to copy markdown:' , err ) ;
54+ // Fallback to copying the page URL
55+ try {
56+ await navigator . clipboard . writeText ( `${ window . location . origin } ${ pagePath } ` ) ;
57+ setIsCopied ( true ) ;
58+ setTimeout ( ( ) => {
59+ setIsCopied ( false ) ;
60+ } , 2000 ) ;
61+ } catch ( clipboardErr ) {
62+ console . error ( 'Failed to copy URL:' , clipboardErr ) ;
63+ }
64+ } finally {
65+ setIsCopyingMarkdown ( false ) ;
66+ }
67+ } ;
68+
2769 const openInChatGPT = ( ) => {
2870 const mdxUrl = `${ typeof window !== 'undefined' ? window . location . origin : 'https://build.avax.network' } ${ pagePath } ` ;
2971 const prompt = `Read ${ mdxUrl } , I want to ask questions about it.` ;
@@ -73,8 +115,8 @@ Page: [${pagePath}](https://build.avax.network${pagePath})
73115 </ Button >
74116
75117 { /* Secondary action: Report Issue */ }
76- < Button
77- variant = "outline"
118+ < Button
119+ variant = "outline"
78120 size = "sm"
79121 className = "w-full justify-start gap-2"
80122 asChild
@@ -90,6 +132,32 @@ Page: [${pagePath}](https://build.avax.network${pagePath})
90132 </ a >
91133 </ Button >
92134
135+ { /* Copy Markdown */ }
136+ < Button
137+ variant = "outline"
138+ size = "sm"
139+ className = "w-full justify-start gap-2"
140+ onClick = { handleCopyMarkdown }
141+ disabled = { isCopyingMarkdown }
142+ >
143+ { isCopied ? (
144+ < >
145+ < Check className = "size-4" />
146+ Copied!
147+ </ >
148+ ) : isCopyingMarkdown ? (
149+ < >
150+ < Copy className = "size-4 animate-pulse" />
151+ Copying...
152+ </ >
153+ ) : (
154+ < >
155+ < Copy className = "size-4" />
156+ Copy Markdown
157+ </ >
158+ ) }
159+ </ Button >
160+
93161 { /* AI Assistant Dropdown */ }
94162 < DropdownMenu >
95163 < DropdownMenuTrigger asChild >
0 commit comments