11'use client' ;
22
3- import { Fragment , useState } from 'react' ;
3+ import { Fragment , useEffect , useState } from 'react' ;
44import { jsx , jsxs } from 'react/jsx-runtime' ;
5+ import { Clipboard } from 'react-feather' ;
56import { toJsxRuntime } from 'hast-util-to-jsx-runtime' ;
67import { Nodes } from 'hastscript/lib/create-h' ;
78import bash from 'refractor/lang/bash.js' ;
@@ -10,6 +11,7 @@ import {refractor} from 'refractor/lib/core.js';
1011
1112import { type API } from 'sentry-docs/build/resolveOpenAPI' ;
1213
14+ import codeBlockStyles from '../codeBlock/code-blocks.module.scss' ;
1315import styles from './apiExamples.module.scss' ;
1416
1517import { CodeBlock } from '../codeBlock' ;
@@ -18,50 +20,6 @@ import {CodeTabs} from '../codeTabs';
1820refractor . register ( bash ) ;
1921refractor . register ( json ) ;
2022
21- type ExampleProps = {
22- api : API ;
23- selectedResponse : number ;
24- selectedTabView : number ;
25- } ;
26-
27- function Example ( { api, selectedTabView, selectedResponse} : ExampleProps ) {
28- let exampleJson : any ;
29- if ( api . responses [ selectedResponse ] . content ?. examples ) {
30- exampleJson = Object . values (
31- api . responses [ selectedResponse ] . content ?. examples ?? { }
32- ) . map ( e => e . value ) [ 0 ] ;
33- } else if ( api . responses [ selectedResponse ] . content ?. example ) {
34- exampleJson = api . responses [ selectedResponse ] . content ?. example ;
35- }
36-
37- return (
38- < pre className = { styles [ 'api-block-example' ] } >
39- { selectedTabView === 0 &&
40- ( exampleJson ? (
41- < code className = "!text-[0.8rem]" >
42- { toJsxRuntime (
43- refractor . highlight ( JSON . stringify ( exampleJson , null , 2 ) , 'json' ) as Nodes ,
44- { Fragment, jsx, jsxs}
45- ) }
46- </ code >
47- ) : (
48- strFormat ( api . responses [ selectedResponse ] . description )
49- ) ) }
50- { selectedTabView === 1 && (
51- < code className = "!text-[0.8rem]" >
52- { toJsxRuntime (
53- refractor . highlight (
54- JSON . stringify ( api . responses [ selectedResponse ] . content ?. schema , null , 2 ) ,
55- 'json'
56- ) as Nodes ,
57- { Fragment, jsx, jsxs}
58- ) }
59- </ code >
60- ) }
61- </ pre >
62- ) ;
63- }
64-
6523const strFormat = ( str : string ) => {
6624 const s = str . trim ( ) ;
6725 if ( s . endsWith ( '.' ) ) {
@@ -104,6 +62,36 @@ export function ApiExamples({api}: Props) {
10462 ? [ 'RESPONSE' , 'SCHEMA' ]
10563 : [ 'RESPONSE' ] ;
10664
65+ const [ showCopied , setShowCopied ] = useState ( false ) ;
66+
67+ // Show the copy button after js has loaded
68+ // otherwise the copy button will not work
69+ const [ showCopyButton , setShowCopyButton ] = useState ( false ) ;
70+ useEffect ( ( ) => {
71+ setShowCopyButton ( true ) ;
72+ } , [ ] ) ;
73+ async function copyCode ( code : string ) {
74+ await navigator . clipboard . writeText ( code ) ;
75+ setShowCopied ( true ) ;
76+ setTimeout ( ( ) => setShowCopied ( false ) , 1200 ) ;
77+ }
78+
79+ let exampleJson : any ;
80+ if ( api . responses [ selectedResponse ] . content ?. examples ) {
81+ exampleJson = Object . values (
82+ api . responses [ selectedResponse ] . content ?. examples ?? { }
83+ ) . map ( e => e . value ) [ 0 ] ;
84+ } else if ( api . responses [ selectedResponse ] . content ?. example ) {
85+ exampleJson = api . responses [ selectedResponse ] . content ?. example ;
86+ }
87+
88+ const codeToCopy =
89+ selectedTabView === 0
90+ ? exampleJson
91+ ? JSON . stringify ( exampleJson , null , 2 )
92+ : strFormat ( api . responses [ selectedResponse ] . description )
93+ : JSON . stringify ( api . responses [ selectedResponse ] . content ?. schema , null , 2 ) ;
94+
10795 return (
10896 < Fragment >
10997 < CodeTabs >
@@ -152,12 +140,45 @@ export function ApiExamples({api}: Props) {
152140 )
153141 ) }
154142 </ div >
143+
144+ < button className = { styles . copy } onClick = { ( ) => copyCode ( codeToCopy ) } >
145+ { showCopyButton && < Clipboard size = { 16 } /> }
146+ </ button >
155147 </ div >
156- < Example
157- api = { api }
158- selectedTabView = { selectedTabView }
159- selectedResponse = { selectedResponse }
160- />
148+ < pre className = { `${ styles [ 'api-block-example' ] } relative` } >
149+ < div className = { codeBlockStyles . copied } style = { { opacity : showCopied ? 1 : 0 } } >
150+ Copied
151+ </ div >
152+ { selectedTabView === 0 &&
153+ ( exampleJson ? (
154+ < code className = "!text-[0.8rem]" >
155+ { toJsxRuntime (
156+ refractor . highlight (
157+ JSON . stringify ( exampleJson , null , 2 ) ,
158+ 'json'
159+ ) as Nodes ,
160+ { Fragment, jsx, jsxs}
161+ ) }
162+ </ code >
163+ ) : (
164+ strFormat ( api . responses [ selectedResponse ] . description )
165+ ) ) }
166+ { selectedTabView === 1 && (
167+ < code className = "!text-[0.8rem]" >
168+ { toJsxRuntime (
169+ refractor . highlight (
170+ JSON . stringify (
171+ api . responses [ selectedResponse ] . content ?. schema ,
172+ null ,
173+ 2
174+ ) ,
175+ 'json'
176+ ) as Nodes ,
177+ { Fragment, jsx, jsxs}
178+ ) }
179+ </ code >
180+ ) }
181+ </ pre >
161182 </ div >
162183 </ Fragment >
163184 ) ;
0 commit comments