@@ -2,137 +2,19 @@ import { useEditor, getSvgAsImage, useToasts, createShapeId } from '@tldraw/tldr
2
2
import { useState } from 'react'
3
3
import { PreviewShape } from '../PreviewShape/PreviewShape'
4
4
import { getHtmlFromOpenAI } from '../lib/getHtmlFromOpenAI'
5
+ import { useMakeReal } from '../hooks/useMakeReal'
5
6
6
7
export function ExportButton ( ) {
7
- const editor = useEditor ( )
8
- const toast = useToasts ( )
8
+ const makeReal = useMakeReal ( )
9
9
10
10
// A tailwind styled button that is pinned to the bottom right of the screen
11
11
return (
12
12
< button
13
- onClick = { async ( e ) => {
14
- const newShapeId = createShapeId ( )
15
-
16
- try {
17
- e . preventDefault ( )
18
-
19
- const selectedShapes = editor . getSelectedShapes ( )
20
-
21
- if ( selectedShapes . length === 0 ) {
22
- toast . addToast ( {
23
- title : 'Nothing selected' ,
24
- description : 'First select something to make real.' ,
25
- id : 'nothing_selected: First select something to make real.' ,
26
- } )
27
- return
28
- }
29
-
30
- const previewPosition = selectedShapes . reduce (
31
- ( acc , shape ) => {
32
- const bounds = editor . getShapePageBounds ( shape )
33
- const right = bounds ?. maxX ?? 0
34
- const top = bounds ?. minY ?? 0
35
- return {
36
- x : Math . max ( acc . x , right ) ,
37
- y : Math . min ( acc . y , top ) ,
38
- }
39
- } ,
40
- { x : 0 , y : Infinity }
41
- )
42
-
43
- const previousPreviews = selectedShapes . filter ( ( shape ) => {
44
- return shape . type === 'preview'
45
- } ) as PreviewShape [ ]
46
-
47
- if ( previousPreviews . length > 1 ) {
48
- toast . addToast ( {
49
- title : 'Too many previous designs' ,
50
- description :
51
- 'Currently, you can only give the developer one previous design to work with.' ,
52
- id : 'too_many_previous_designs' ,
53
- } )
54
- return
55
- }
56
-
57
- const previousHtml =
58
- previousPreviews . length === 1
59
- ? previousPreviews [ 0 ] . props . html
60
- : 'No previous design has been provided this time.'
61
-
62
- const svg = await editor . getSvg ( selectedShapes )
63
- if ( ! svg ) {
64
- return
65
- }
66
-
67
- const IS_SAFARI = / ^ ( (? ! c h r o m e | a n d r o i d ) .) * s a f a r i / i. test ( navigator . userAgent )
68
-
69
- const blob = await getSvgAsImage ( svg , IS_SAFARI , {
70
- type : 'png' ,
71
- quality : 1 ,
72
- scale : 1 ,
73
- } )
74
-
75
- const dataUrl = await blobToBase64 ( blob ! )
76
-
77
- editor . createShape < PreviewShape > ( {
78
- id : newShapeId ,
79
- type : 'preview' ,
80
- x : previewPosition . x + 60 ,
81
- y : previewPosition . y ,
82
- props : { html : '' , source : dataUrl as string } ,
83
- } )
84
-
85
- const json = await getHtmlFromOpenAI ( {
86
- image : dataUrl ,
87
- html : previousHtml ,
88
- apiKey :
89
- ( document . getElementById ( 'openai_key_risky_but_cool' ) as HTMLInputElement ) ?. value ??
90
- null ,
91
- } )
92
-
93
- if ( json . error ) {
94
- console . error ( json )
95
- toast . addToast ( {
96
- icon : 'cross-2' ,
97
- title : 'OpenAI API Error' ,
98
- description : `${ json . error . message ?. slice ( 0 , 100 ) } ...` ,
99
- } )
100
- editor . deleteShape ( newShapeId )
101
- return
102
- }
103
-
104
- const message = json . choices [ 0 ] . message . content
105
- const start = message . indexOf ( '<!DOCTYPE html>' )
106
- const end = message . indexOf ( '</html>' )
107
- const html = message . slice ( start , end + '</html>' . length )
108
-
109
- editor . updateShape < PreviewShape > ( {
110
- id : newShapeId ,
111
- type : 'preview' ,
112
- props : { html, source : dataUrl as string } ,
113
- } )
114
- } catch ( e : any ) {
115
- console . error ( e )
116
- toast . addToast ( {
117
- icon : 'cross-2' ,
118
- title : 'Error' ,
119
- description : `Something went wrong: ${ e . message . slice ( 0 , 100 ) } ` ,
120
- } )
121
- editor . deleteShape ( newShapeId )
122
- }
123
- } }
13
+ onClick = { makeReal }
124
14
className = "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded m-2"
125
15
style = { { cursor : 'pointer' , zIndex : 100000 , pointerEvents : 'all' } }
126
16
>
127
17
Make Real
128
18
</ button >
129
19
)
130
20
}
131
-
132
- export function blobToBase64 ( blob : Blob ) : Promise < string > {
133
- return new Promise ( ( resolve , _ ) => {
134
- const reader = new FileReader ( )
135
- reader . onloadend = ( ) => resolve ( reader . result as string )
136
- reader . readAsDataURL ( blob )
137
- } )
138
- }
0 commit comments