@@ -15,7 +15,6 @@ import { blankOverlay, petstore } from "./defaults";
1515import speakeasyWhiteLogo from "./assets/speakeasy-white.svg" ;
1616import openapiLogo from "./assets/openapi.svg" ;
1717import { compress , decompress } from "@/compress" ;
18- import { CopyButton } from "@/components/CopyButton" ;
1918import { Button } from "@/components/ui/button" ;
2019import {
2120 ImperativePanelGroupHandle ,
@@ -25,7 +24,13 @@ import {
2524} from "react-resizable-panels" ;
2625import posthog from "posthog-js" ;
2726import { useDebounceCallback , useMediaQuery } from "usehooks-ts" ;
28- import { formatDocument , guessDocumentLanguage } from "./lib/utils" ;
27+ import {
28+ arraysEqual ,
29+ formatDocument ,
30+ guessDocumentLanguage ,
31+ } from "./lib/utils" ;
32+ import ShareDialog , { ShareDialogHandle } from "./components/ShareDialog" ;
33+ import { Loader2Icon , ShareIcon } from "lucide-react" ;
2934
3035const Link = ( { children, href } : { children : ReactNode ; href : string } ) => (
3136 < a
@@ -73,7 +78,6 @@ function Playground() {
7378 const result = useRef ( blankOverlay ) ;
7479 const [ resultLoading , setResultLoading ] = useState ( false ) ;
7580 const [ error , setError ] = useState ( "" ) ;
76- const [ shareUrl , setShareUrl ] = useState ( "" ) ;
7781 const [ shareUrlLoading , setShareUrlLoading ] = useState ( false ) ;
7882 const [ overlayMarkers , setOverlayMarkers ] = useState < editor . IMarkerData [ ] > (
7983 [ ] ,
@@ -135,7 +139,12 @@ function Playground() {
135139
136140 const onChangeOverlayDebounced = useDebounceCallback ( onChangeOverlay , 500 ) ;
137141
142+ const shareDialogRef = useRef < ShareDialogHandle > ( null ) ;
143+ const lastSharedStart = useRef < string > ( "" ) ;
144+
138145 const getShareUrl = useCallback ( async ( ) => {
146+ if ( ! shareDialogRef . current ) return ;
147+
139148 try {
140149 setShareUrlLoading ( true ) ;
141150 const info = await GetInfo ( original . current , false ) ;
@@ -144,14 +153,19 @@ function Playground() {
144153 original : original . current ,
145154 info : info ,
146155 } ) ;
147- const blob = await compress ( start ) ;
156+
157+ const alreadySharedThis = lastSharedStart . current === start ;
158+ if ( alreadySharedThis ) {
159+ shareDialogRef . current . setOpen ( true ) ;
160+ return ;
161+ }
148162
149163 const response = await fetch ( "/api/share" , {
150164 method : "POST" ,
151165 headers : {
152166 "Content-Type" : "application/json" ,
153167 } ,
154- body : blob ,
168+ body : await compress ( start ) ,
155169 } ) ;
156170
157171 if ( response . ok ) {
@@ -161,7 +175,10 @@ function Playground() {
161175 currentUrl . hash = "" ;
162176 currentUrl . searchParams . set ( "s" , base64Data ) ;
163177
164- setShareUrl ( currentUrl . toString ( ) ) ;
178+ lastSharedStart . current = start ;
179+ shareDialogRef . current . setUrl ( currentUrl . toString ( ) ) ;
180+ shareDialogRef . current . setOpen ( true ) ;
181+
165182 history . pushState ( null , "" , currentUrl . toString ( ) ) ;
166183 posthog . capture ( "overlay.speakeasy.com:share" , {
167184 openapi : JSON . parse ( info ) ,
@@ -283,14 +300,25 @@ function Playground() {
283300
284301 const maxLayout = useCallback ( ( index : number ) => {
285302 const panelGroup = ref . current ;
286- const desiredWidths = [ 10 , 10 , 10 ] ;
287- if ( index < desiredWidths . length && index >= 0 ) {
288- desiredWidths [ index ] = 80 ;
303+ if ( ! panelGroup ) return ;
304+
305+ const currentLayout = panelGroup ?. getLayout ( ) ;
306+
307+ if ( ! arraysEqual ( currentLayout , defaultLayout ) ) {
308+ panelGroup . setLayout ( defaultLayout ) ;
309+ return ;
289310 }
290- if ( panelGroup ) {
291- // Reset each Panel to 50% of the group's width
292- panelGroup . setLayout ( desiredWidths ) ;
311+
312+ const baseWidth = 10 ;
313+ const maxedWidth = 80 ;
314+ const desiredWidths = Array ( 3 ) . fill ( baseWidth ) ;
315+
316+ if ( index < desiredWidths . length && index >= 0 ) {
317+ desiredWidths [ index ] = maxedWidth ;
293318 }
319+
320+ // Reset each Panel to 50% of the group's width
321+ panelGroup . setLayout ( desiredWidths ) ;
294322 } , [ ] ) ;
295323
296324 if ( ! ready ) {
@@ -312,7 +340,7 @@ function Playground() {
312340 For proper user experience, please use a desktop device
313341 </ Alert >
314342 ) : null }
315- < div style = { { paddingBottom : "1rem" , width : "100vw" } } >
343+ < div style = { { width : "100vw" } } >
316344 < div className = "border-b border-muted p-4 md:p-6 text-left" >
317345 < div className = "flex gap-2" >
318346 < div className = "flex flex-1" >
@@ -341,7 +369,7 @@ function Playground() {
341369 </ div >
342370 </ div >
343371 < div className = "flex flex-1 flex-row-reverse" >
344- < div className = "flex flex-col justify-between" >
372+ < div className = "flex flex-col gap-4 justify-between" >
345373 < div className = "flex gap-x-2" >
346374 < span >
347375 < Link href = "https://www.speakeasy.com?utm_source=overlay.speakeasy.com" >
@@ -365,21 +393,27 @@ function Playground() {
365393 </ Link >
366394 </ span >
367395 </ div >
368- < div className = "flex gap-x-2 justify-evenly " >
396+ < div className = "flex gap-x-2 justify-end " >
369397 < Button
370- className = "border-b border-transparent transition-all duration-200 hover:border-current"
398+ className = "border-b border-transparent hover:border-current"
371399 style = { {
372400 color : "#FBE331" ,
373401 backgroundColor : "#1E1E1E" ,
374402 } }
375403 onClick = { getShareUrl }
376404 disabled = { shareUrlLoading }
377405 >
406+ { shareUrlLoading ? (
407+ < Loader2Icon
408+ className = "animate-spin"
409+ style = { { height : "75%" } }
410+ />
411+ ) : (
412+ < ShareIcon style = { { height : "75%" } } />
413+ ) }
378414 Share
379415 </ Button >
380- < div className = "flex items-center gap-x-2 grow" >
381- { shareUrl ? < CopyButton value = { shareUrl } /> : null }
382- </ div >
416+ < ShareDialog ref = { shareDialogRef } />
383417 </ div >
384418 </ div >
385419 </ div >
0 commit comments