1
- import React , { FunctionComponent , useCallback , useMemo , useState } from 'react' ;
1
+ import React , { ClipboardEventHandler , FunctionComponent , useCallback , useMemo , useState } from 'react' ;
2
2
import PageContainer from '../../layouts/pages/pageContainer/PageContainer' ;
3
3
import styles from './DataUrlPage.module.scss' ;
4
4
import { Button , Col , Input , notification , Space , Switch , Upload } from 'antd' ;
@@ -17,29 +17,36 @@ import { UploadFile } from 'antd/lib/upload/interface';
17
17
import getErrorMessage from '../../utils/getErrorMessage' ;
18
18
import { Base64 } from 'js-base64' ;
19
19
import readFileAsBase64 from '../../utils/readFileAsBase64' ;
20
+ import CopyButton from '../../components/copyButton/CopyButton' ;
20
21
21
22
interface DataUrlState {
22
23
title : string ;
23
24
mimeType : string ;
24
25
encoding : string ;
25
26
content : string ;
26
27
isBase64 : boolean ;
28
+ isAutoBase64 : boolean ;
27
29
}
28
30
29
31
const initialState : DataUrlState = {
30
32
title : '' ,
31
33
mimeType : 'text/plain' ,
32
34
encoding : 'utf-8' ,
33
35
content : 'Hello World' ,
34
- isBase64 : false
36
+ isBase64 : false ,
37
+ isAutoBase64 : false
35
38
} ;
36
39
37
40
const getDataUrlQueryParams = ( state : DataUrlState ) : DataUrlViewPageQueryParams => {
38
41
// data:[<MIME-type>][;charset=<encoding>][;base64],<data>
39
42
43
+ const isAutoBase64 = state . isAutoBase64 && ! state . isBase64 ;
44
+ const isBase64 = state . isBase64 || isAutoBase64 ;
45
+ const content = isAutoBase64 ? Base64 . encode ( state . content ) : state . content ;
46
+
40
47
const charsetPart = state . encoding && `;charset=${ state . encoding } ` ;
41
- const base64Part = state . isBase64 ? ';base64' : '' ;
42
- const dataPart = `,${ state . content } ` ;
48
+ const base64Part = isBase64 ? ';base64' : '' ;
49
+ const dataPart = `,${ content } ` ;
43
50
44
51
const data = `data:${ state . mimeType } ${ charsetPart } ${ base64Part } ${ dataPart } ` ;
45
52
@@ -91,33 +98,60 @@ const DataUrlPage: FunctionComponent = () => {
91
98
const encodeBase64Content = useCallback ( ( ) => transformContent ( Base64 . encode ) , [ transformContent ] ) ;
92
99
const decodeBase64Content = useCallback ( ( ) => transformContent ( Base64 . decode ) , [ transformContent ] ) ;
93
100
94
- const handleFileChange = useCallback ( async ( info : UploadChangeParam < UploadFile < unknown > > ) => {
95
- const { file } = info ;
96
-
97
- if ( file . status !== 'done' ) {
98
- return ;
99
- }
100
-
101
- const { name, type } = file ;
102
-
103
- const blob = file . originFileObj ;
104
-
101
+ const handleFileChange = useCallback ( async ( blob : Blob , name : string ) => {
105
102
const content = ( blob && ( await readFileAsBase64 ( blob ) ) ) ?? '' ;
106
103
107
104
setState ( {
108
105
title : name ,
109
- mimeType : type ?? '' ,
106
+ mimeType : blob . type ?? '' ,
110
107
isBase64 : true ,
108
+ isAutoBase64 : false ,
111
109
encoding : '' ,
112
110
content
113
111
} ) ;
114
112
} , [ ] ) ;
115
113
114
+ const handleUploadedFileChange = useCallback (
115
+ async ( info : UploadChangeParam < UploadFile < unknown > > ) => {
116
+ const { file } = info ;
117
+
118
+ if ( file . status !== 'done' ) {
119
+ return ;
120
+ }
121
+
122
+ const blob = file . originFileObj ;
123
+
124
+ if ( ! blob ) {
125
+ return ;
126
+ }
127
+
128
+ await handleFileChange ( blob , file . name ) ;
129
+ } ,
130
+ [ handleFileChange ]
131
+ ) ;
132
+
133
+ const handleContentPaste = useCallback < ClipboardEventHandler < HTMLTextAreaElement > > (
134
+ async ( event ) => {
135
+ const file = event . clipboardData . files [ 0 ] ;
136
+
137
+ if ( file === undefined ) {
138
+ return ;
139
+ }
140
+
141
+ await handleFileChange ( file , file . name ) ;
142
+ } ,
143
+ [ handleFileChange ]
144
+ ) ;
145
+
116
146
return (
117
147
< PageContainer title = "Data URL Generator" >
118
148
< Col xs = { 24 } lg = { 18 } xl = { 12 } className = { styles . container } >
119
149
< Space className = "mb-2" >
120
- < Upload customRequest = { dummyAntdUploadRequest } onChange = { handleFileChange } showUploadList = { false } >
150
+ < Upload
151
+ customRequest = { dummyAntdUploadRequest }
152
+ onChange = { handleUploadedFileChange }
153
+ showUploadList = { false }
154
+ >
121
155
< Button icon = { < UploadOutlined /> } > Upload file</ Button >
122
156
</ Upload >
123
157
</ Space >
@@ -141,21 +175,33 @@ const DataUrlPage: FunctionComponent = () => {
141
175
value = { state . content }
142
176
onChange = { handleStateChange ( 'content' ) }
143
177
rows = { 3 }
178
+ showCount
179
+ onPaste = { handleContentPaste }
180
+ allowClear
144
181
/>
145
- < Space className = "mt-2" >
182
+ < Space className = "mt-2" wrap >
146
183
< Button onClick = { encodeBase64Content } > Encode base64</ Button >
147
184
< Button onClick = { decodeBase64Content } > Decode base64</ Button >
148
185
</ Space >
149
186
< label className = { classNames ( styles . formItem , 'mt-2' ) } >
150
187
< Switch checked = { state . isBase64 } onChange = { handleStateChange ( 'isBase64' ) } />
151
188
< span className = "ms-3" > Base64</ span >
152
189
</ label >
190
+ < label className = { classNames ( styles . formItem , 'mt-2' ) } >
191
+ < Switch
192
+ checked = { state . isAutoBase64 && ! state . isBase64 }
193
+ onChange = { handleStateChange ( 'isAutoBase64' ) }
194
+ disabled = { state . isBase64 }
195
+ />
196
+ < span className = "ms-3" > Auto convert text to base64</ span >
197
+ </ label >
153
198
</ div >
154
199
</ label >
155
- < Link to = { dataUrlViewUrl } className = "mt-3" ref = { dataUrlViewLinkRef } >
200
+ < Link to = { dataUrlViewUrl } target = "_blank" className = "mt-3" ref = { dataUrlViewLinkRef } >
156
201
View the iframe
157
202
</ Link >
158
- < TextArea readOnly value = { displayedDataUrlViewUrl } rows = { 4 } />
203
+ < TextArea readOnly value = { displayedDataUrlViewUrl } rows = { 4 } showCount />
204
+ < CopyButton value = { displayedDataUrlViewUrl } className = { styles . copyButton } />
159
205
</ Col >
160
206
</ PageContainer >
161
207
) ;
0 commit comments