@@ -8,6 +8,89 @@ let langShortname = (lang: string) =>
8
8
| rest => rest
9
9
}
10
10
11
+ module LzString = {
12
+ @bs. module ("lz-string" )
13
+ external compressToEncodedURIComponent : string => string = "compressToEncodedURIComponent"
14
+ }
15
+
16
+ module CopyButton = {
17
+ let copyToClipboard : string => bool = %raw (j `
18
+ function(str) {
19
+ try {
20
+ const el = document.createElement('textarea');
21
+ el.value = str;
22
+ el.setAttribute('readonly', '');
23
+ el.style.position = 'absolute';
24
+ el.style.left = '-9999px';
25
+ document.body.appendChild(el);
26
+ const selected =
27
+ document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false;
28
+ el.select();
29
+ document.execCommand('copy');
30
+ document.body.removeChild(el);
31
+ if (selected) {
32
+ document.getSelection().removeAllRanges();
33
+ document.getSelection().addRange(selected);
34
+ }
35
+ return true;
36
+ } catch(e) {
37
+ return false;
38
+ }
39
+ }
40
+ ` )
41
+
42
+ type state =
43
+ | Init
44
+ | Copied
45
+ | Failed
46
+
47
+ @react.component
48
+ let make = (~code ) => {
49
+ let (state , setState ) = React .useState (_ => Init )
50
+
51
+ let onClick = evt => {
52
+ ReactEvent .Mouse .preventDefault (evt )
53
+ if copyToClipboard (code ) {
54
+ setState (_ => Copied )
55
+ } else {
56
+ setState (_ => Failed )
57
+ }
58
+ }
59
+
60
+ React .useEffect1 (() => {
61
+ switch state {
62
+ | Copied =>
63
+ let timeoutId = Js .Global .setTimeout (() => {
64
+ setState (_ => Init )
65
+ }, 2000 )
66
+
67
+ Some (
68
+ () => {
69
+ Js .Global .clearTimeout (timeoutId )
70
+ },
71
+ )
72
+ | _ => None
73
+ }
74
+ }, [state ])
75
+
76
+ let activeClass = switch state {
77
+ | Copied => "opacity-100"
78
+ | _ => "opacity-0 hidden"
79
+ }
80
+
81
+ let banner =
82
+ <div
83
+ className = {"absolute top-0 -mt-1 -mr-1 px-2 rounded right-0 bg-turtle text-gray-80-tr transition-all duration-500 ease-in-out " ++
84
+ activeClass }>
85
+ {React .string ("Copied!" )}
86
+ </div >
87
+
88
+ <button disabled = {state === Copied } className = "relative" onClick >
89
+ banner <Icon .Copy className = "text-gray-20 mt-px hover:cursor-pointer hover:text-gray-80" />
90
+ </button >
91
+ }
92
+ }
93
+
11
94
@react.component
12
95
let make = (~highlightedLines = [], ~code : string , ~showLabel = true , ~lang = "text" ) => {
13
96
let children = HighlightJs .renderHLJS (~highlightedLines , ~code , ~lang , ())
@@ -62,9 +145,9 @@ module Toggle = {
62
145
}
63
146
64
147
let activeClass = if selected === i {
65
- "font-medium text-gray-90 bg-gray-5 border-t-2 border-l border-r "
148
+ "font-medium text-gray-90 bg-gray-5 border-t-2 first: border-l"
66
149
} else {
67
- "font-medium hover:text-gray-60 border-t-2 border-l border-r bg-gray-10 hover:cursor-pointer"
150
+ "font-medium hover:text-gray-60 border-t-2 bg-gray-10 hover:cursor-pointer"
68
151
}
69
152
70
153
let onClick = evt => {
@@ -83,14 +166,14 @@ module Toggle = {
83
166
let borderColor = if selected === i {
84
167
"#f4646a #EDF0F2"
85
168
} else {
86
- "#CDCDD6 #EDF0F2 "
169
+ "transparent "
87
170
}
88
171
89
172
<span
90
173
key
91
174
style = {ReactDOM .Style .make (~borderColor , ())}
92
175
className = {paddingX ++
93
- (" flex-none px-4 first:ml-6 xs:first:ml-0 inline-block p-1 rounded-tl rounded-tr " ++
176
+ (" flex-none px-4 inline-block p-1 first: rounded-tl " ++
94
177
activeClass )}
95
178
onClick >
96
179
{React .string (label )}
@@ -105,13 +188,38 @@ module Toggle = {
105
188
})
106
189
-> Belt .Option .getWithDefault (React .null )
107
190
191
+ let buttonDiv = switch Js .Array2 .find (multiple , tab => {
192
+ switch tab .lang {
193
+ | Some ("res" ) | Some ("rescript" ) => true
194
+ | _ => false
195
+ }
196
+ }) {
197
+ | Some ({code : "" }) => React .null
198
+ | Some (tab ) =>
199
+ let playgroundLinkButton =
200
+ <Next .Link href = {` /try?code=${LzString.compressToEncodedURIComponent(tab.code)}}` }>
201
+ <a target = "_blank" >
202
+ <Icon .ExternalLink className = "text-gray-20 hover:cursor-pointer hover:text-gray-80" />
203
+ </a >
204
+ </Next .Link >
205
+
206
+ let copyButton = <CopyButton code = {tab .code } />
207
+
208
+ <div className = "flex items-center justify-end h-full pr-4 space-x-3" >
209
+ playgroundLinkButton copyButton
210
+ </div >
211
+ | None => React .null
212
+ }
213
+
108
214
<div className = "relative pt-6 w-full rounded-none text-gray-80" >
109
215
//text within code-box
110
216
<div
111
217
className = "absolute flex w-full overflow-auto scrolling-touch font-sans bg-transparent text-14 text-gray-40 "
112
218
style = {ReactDOM .Style .make (~marginTop = "-30px" , ())}>
113
- <div className = "flex space-x-1" > {React .array (tabElements )} </div >
114
- <div className = "flex-1 border-b border-gray-10" > {React .string (j ` \\ u00A0` )} </div >
219
+ <div className = "flex ml-2 xs:ml-0" > {React .array (tabElements )} </div >
220
+ <div className = "flex-1 w-full bg-gray-10 border-b rounded-tr border-gray-10 items-center" >
221
+ buttonDiv
222
+ </div >
115
223
</div >
116
224
<div
117
225
className = "px-4 lg:px-5 text-14 pb-4 pt-4 overflow-x-auto bg-gray-5 border-gray-10 xs:rounded-b-lg border" >
0 commit comments