@@ -38,34 +38,70 @@ const HOVER = 'light-dark(rgba(0,0,0,0.05), rgba(255,255,255,0.07))'
3838const MENU_BG = 'light-dark(#ffffff, #1c1c1f)'
3939const MUTED = 'light-dark(#52525b, #a1a1aa)'
4040
41+ function writeClipboard ( text ) {
42+ if ( navigator . clipboard && window . isSecureContext ) {
43+ return navigator . clipboard . writeText ( text )
44+ }
45+ return new Promise ( ( resolve , reject ) => {
46+ const ta = document . createElement ( 'textarea' )
47+ ta . value = text
48+ ta . style . position = 'fixed'
49+ ta . style . opacity = '0'
50+ document . body . appendChild ( ta )
51+ ta . focus ( )
52+ ta . select ( )
53+ try {
54+ document . execCommand ( 'copy' ) ? resolve ( ) : reject ( new Error ( 'execCommand failed' ) )
55+ } catch ( e ) {
56+ reject ( e )
57+ } finally {
58+ document . body . removeChild ( ta )
59+ }
60+ } )
61+ }
62+
4163export default function CopyPage ( ) {
4264 const pathname = usePathname ( )
4365 const [ open , setOpen ] = useState ( false )
4466 const [ copied , setCopied ] = useState ( false )
4567 const ref = useRef ( null )
46-
47- useEffect ( ( ) => {
48- const onDoc = ( e ) => ref . current && ! ref . current . contains ( e . target ) && setOpen ( false )
49- document . addEventListener ( 'click' , onDoc )
50- return ( ) => document . removeEventListener ( 'click' , onDoc )
51- } , [ ] )
68+ const mdRef = useRef ( null )
5269
5370 const slug = slugFrom ( pathname )
5471 const mdUrl = `${ BASE } /md/${ slug } .md`
5572 const pageUrl = typeof window !== 'undefined' ? window . location . href : ''
5673 const absMd = typeof window !== 'undefined' ? `${ window . location . origin } ${ mdUrl } ` : mdUrl
5774 const prompt = `Read ${ pageUrl } (raw markdown: ${ absMd } ) — a Zaileys documentation page — then help me with it.`
5875
76+ useEffect ( ( ) => {
77+ const onDoc = ( e ) => ref . current && ! ref . current . contains ( e . target ) && setOpen ( false )
78+ document . addEventListener ( 'click' , onDoc )
79+ let alive = true
80+ fetch ( mdUrl )
81+ . then ( ( r ) => ( r . ok ? r . text ( ) : null ) )
82+ . then ( ( t ) => alive && ( mdRef . current = t ) )
83+ . catch ( ( ) => { } )
84+ return ( ) => {
85+ alive = false
86+ document . removeEventListener ( 'click' , onDoc )
87+ }
88+ } , [ mdUrl ] )
89+
5990 const copy = async ( ) => {
91+ setOpen ( false )
92+ let text = mdRef . current
6093 try {
61- const text = await ( await fetch ( mdUrl ) ) . text ( )
62- await navigator . clipboard . writeText ( text )
94+ if ( ! text ) text = await ( await fetch ( mdUrl ) ) . text ( )
95+ await writeClipboard ( text )
6396 } catch {
64- await navigator . clipboard . writeText ( pageUrl )
97+ try {
98+ await writeClipboard ( pageUrl )
99+ } catch {
100+ return
101+ }
65102 }
66103 setCopied ( true )
67104 setTimeout ( ( ) => setCopied ( false ) , 1800 )
68- setOpen ( false )
69105 }
70106
71107 const item = {
0 commit comments