1+ import React , { useState , useRef , useEffect } from 'react' ;
2+ import { useRouter } from 'next/router' ;
3+ import styles from './copy-page.module.css' ;
4+ import CopyIcon from './icons/copy' ;
5+ import CheckIcon from './icons/check' ;
6+ import ChevronDownIcon from './icons/chevron-down' ;
7+ import DocumentIcon from './icons/document' ;
8+ import ChatGPTIcon from './icons/chatgpt' ;
9+ import AnthropicIcon from './icons/anthropic' ;
10+
11+ const CopyPage : React . FC = ( ) => {
12+ const [ isOpen , setIsOpen ] = useState ( false ) ;
13+ const [ isCopied , setIsCopied ] = useState ( false ) ;
14+ const dropdownRef = useRef < HTMLDivElement > ( null ) ;
15+
16+ // Close dropdown when clicking outside
17+ useEffect ( ( ) => {
18+ const handleClickOutside = ( event : MouseEvent ) => {
19+ if ( dropdownRef . current && ! dropdownRef . current . contains ( event . target as Node ) ) {
20+ setIsOpen ( false ) ;
21+ }
22+ } ;
23+
24+ document . addEventListener ( 'mousedown' , handleClickOutside ) ;
25+ return ( ) => document . removeEventListener ( 'mousedown' , handleClickOutside ) ;
26+ } , [ ] ) ;
27+
28+ const copyPageAsMarkdown = async ( ) => {
29+ try {
30+ // Get the current page content
31+ const pageContent = document . querySelector ( 'main' ) ?. innerText || '' ;
32+ const pageTitle = document . title ;
33+
34+ // Create markdown content
35+ const markdownContent = `# ${ pageTitle } \n\n${ pageContent } ` ;
36+
37+ await navigator . clipboard . writeText ( markdownContent ) ;
38+
39+ // Show success feedback
40+ setIsCopied ( true ) ;
41+ setTimeout ( ( ) => {
42+ setIsCopied ( false ) ;
43+ } , 2000 ) ;
44+ } catch ( error ) {
45+ console . error ( 'Failed to copy page:' , error ) ;
46+ }
47+ setIsOpen ( false ) ;
48+ } ;
49+
50+ const viewAsMarkdown = ( ) => {
51+ const pageContent = document . querySelector ( 'main' ) ?. innerText || '' ;
52+ const pageTitle = document . title ;
53+ const markdownContent = `# ${ pageTitle } \n\n${ pageContent } ` ;
54+
55+ // Open in new window/tab
56+ const blob = new Blob ( [ markdownContent ] , { type : 'text/markdown' } ) ;
57+ const url = URL . createObjectURL ( blob ) ;
58+ window . open ( url , '_blank' ) ;
59+ URL . revokeObjectURL ( url ) ;
60+ setIsOpen ( false ) ;
61+ } ;
62+
63+ const openInAI = ( platform : 'chatgpt' | 'claude' ) => {
64+ const currentUrl = window . location . href ;
65+ const prompt = `I'm building with GenLayer - can you read this docs page ${ currentUrl } so I can ask you questions about it?` ;
66+ const encodedPrompt = encodeURIComponent ( prompt ) ;
67+
68+ const urls = {
69+ chatgpt : `https://chatgpt.com/?q=${ encodedPrompt } ` ,
70+ claude : `https://claude.ai/new?q=${ encodedPrompt } `
71+ } ;
72+
73+ window . open ( urls [ platform ] , '_blank' ) ;
74+ setIsOpen ( false ) ;
75+ } ;
76+
77+ const openInChatGPT = ( ) => openInAI ( 'chatgpt' ) ;
78+ const openInClaude = ( ) => openInAI ( 'claude' ) ;
79+
80+ return (
81+ < div className = { styles . container } ref = { dropdownRef } >
82+ < button
83+ onClick = { copyPageAsMarkdown }
84+ className = { styles . mainButton }
85+ >
86+ { isCopied ? (
87+ < CheckIcon className = { styles . mainButtonIcon } />
88+ ) : (
89+ < CopyIcon className = { styles . mainButtonIcon } />
90+ ) }
91+ Copy page
92+ </ button >
93+
94+ < button
95+ onClick = { ( ) => setIsOpen ( ! isOpen ) }
96+ className = { styles . arrowButton }
97+ >
98+ < ChevronDownIcon
99+ className = { `${ styles . arrowIcon } ${ isOpen ? styles . arrowIconRotated : '' } ` }
100+ />
101+ </ button >
102+
103+ { isOpen && (
104+ < div className = { styles . dropdown } >
105+ < div className = { styles . dropdownContent } >
106+ < button
107+ onClick = { copyPageAsMarkdown }
108+ className = { styles . dropdownButton }
109+ >
110+ < CopyIcon className = { styles . dropdownIcon } />
111+ < div className = { styles . dropdownText } >
112+ < span className = { styles . dropdownTitle } > Copy page</ span >
113+ < span className = { styles . dropdownDescription } > Copy the page as Markdown for LLMs</ span >
114+ </ div >
115+ </ button >
116+
117+ < button
118+ onClick = { viewAsMarkdown }
119+ className = { styles . dropdownButton }
120+ >
121+ < DocumentIcon className = { styles . dropdownIcon } />
122+ < div className = { styles . dropdownText } >
123+ < span className = { styles . dropdownTitle } > View as MarkDown</ span >
124+ < span className = { styles . dropdownDescription } > View this page as plain text</ span >
125+ </ div >
126+ </ button >
127+
128+ < button
129+ onClick = { openInChatGPT }
130+ className = { styles . dropdownButton }
131+ >
132+ < ChatGPTIcon className = { styles . dropdownIcon } />
133+ < div className = { styles . dropdownText } >
134+ < span className = { styles . dropdownTitle } > Open in ChatGPT</ span >
135+ < span className = { styles . dropdownDescription } > Ask questions about this page</ span >
136+ </ div >
137+ </ button >
138+
139+ < button
140+ onClick = { openInClaude }
141+ className = { styles . dropdownButton }
142+ >
143+ < AnthropicIcon className = { styles . dropdownIcon } />
144+ < div className = { styles . dropdownText } >
145+ < span className = { styles . dropdownTitle } > Open in Claude</ span >
146+ < span className = { styles . dropdownDescription } > Ask questions about this page</ span >
147+ </ div >
148+ </ button >
149+ </ div >
150+ </ div >
151+ ) }
152+ </ div >
153+ ) ;
154+ } ;
155+
156+ export default CopyPage ;
0 commit comments