@@ -2,15 +2,23 @@ import { useState, Fragment } from 'react';
2
2
import Head from 'next/head' ;
3
3
import Image from 'next/image' ;
4
4
import Link from 'next/link' ;
5
- import { Menu , Transition , Disclosure } from '@headlessui/react' ;
5
+ import axios from 'axios' ;
6
+ import {
7
+ Menu , Transition , Disclosure , Switch ,
8
+ } from '@headlessui/react' ;
6
9
import { ChevronDownIcon } from '@heroicons/react/solid' ;
7
10
import {
8
11
MailIcon , PencilAltIcon ,
9
12
} from '@heroicons/react/outline' ;
13
+ import { languages , Grammar } from 'prismjs' ;
10
14
import CodeEditor from '../components/CodeEditor' ;
11
15
import Output from '../components/Output' ;
12
16
import vscode from '../assets/vsc.svg' ;
13
17
18
+ const ENDPOINT = process . env . NODE_ENV === 'development'
19
+ ? 'http://localhost:5000'
20
+ : 'https://api.mintlify.com' ;
21
+
14
22
const footer = {
15
23
main : [
16
24
{ name : 'Documentation' , href : 'https://nicedoc.io/mintlify/inferapp' } ,
@@ -55,19 +63,86 @@ const footer = {
55
63
] ,
56
64
} ;
57
65
66
+ type LanguageOption = {
67
+ name : string ;
68
+ id : string ;
69
+ grammar : Grammar ;
70
+ }
71
+
72
+ const languagesDropdown : LanguageOption [ ] = [
73
+ { name : 'Auto-detect' , id : 'auto' , grammar : languages . plain } ,
74
+ { name : 'JavaScript' , id : 'javascript' , grammar : languages . javascript } ,
75
+ { name : 'TypeScript' , id : 'typescript' , grammar : languages . typescript } ,
76
+ { name : 'Python' , id : 'python' , grammar : languages . python } ,
77
+ ] ;
78
+
79
+ const formats = [
80
+ { name : 'Auto-detect' , id : 'auto' } ,
81
+ { name : 'JSDoc' , id : 'JSDoc' } ,
82
+ { name : 'reST' , id : 'reST' } ,
83
+ { name : 'Google' , id : 'Google' } ,
84
+ ] ;
85
+
58
86
function classNames ( ...classes : any ) {
59
87
return classes . filter ( Boolean ) . join ( ' ' ) ;
60
88
}
61
89
62
90
export default function Example ( ) {
63
91
const [ code , setCode ] = useState ( '' ) ;
64
92
const [ outputDisplay , setOutputDisplay ] = useState ( '' ) ;
93
+ const [ selectedLanguage , setSelectedLanguage ] = useState ( languagesDropdown [ 0 ] ) ;
94
+ const [ selectedFormat , setSelectedFormat ] = useState ( formats [ 0 ] ) ;
95
+ const [ commentsEnabled , setCommentsEnabled ] = useState ( true ) ;
96
+ const [ isGenerating , setIsGenerating ] = useState ( false ) ;
65
97
66
- const codeOnChange = async ( newCode : string ) => {
98
+ const onCodeChange = async ( newCode : string ) => {
67
99
setCode ( newCode ) ;
100
+ if ( newCode . length < 30 ) return ;
101
+
102
+ const { data : { language } } : { data : { language : string } } = await axios . post ( 'https://figstack.uc.r.appspot.com/infer' , {
103
+ code : newCode . trim ( ) ,
104
+ } ) ;
105
+
106
+ const languageToUse = languagesDropdown . find (
107
+ ( languageOption ) => languageOption . name === language ,
108
+ ) ;
109
+
110
+ if ( languageToUse ) {
111
+ setSelectedLanguage ( {
112
+ ...languageToUse ,
113
+ name : `${ language } (auto)` ,
114
+ } ) ;
115
+ return ;
116
+ }
117
+
118
+ setSelectedLanguage ( {
119
+ name : `${ language } (auto)` ,
120
+ id : language ,
121
+ grammar : languages . plain ,
122
+ } ) ;
123
+ } ;
124
+
125
+ const onClickGenerate = async ( ) => {
126
+ setIsGenerating ( true ) ;
127
+ setOutputDisplay ( '' ) ;
128
+
129
+ try {
130
+ const { data : { docstring } } : { data : { docstring : string } } = await axios . post ( `${ ENDPOINT } /web/write` , {
131
+ code,
132
+ languageId : selectedLanguage . id ,
133
+ commented : commentsEnabled ,
134
+ userId : 'web' ,
135
+ docStyle : 'Auto-generate' ,
136
+ context : code ,
137
+ } ) ;
68
138
69
- const detectedLanguage = '' ;
70
- setOutputDisplay ( detectedLanguage ) ;
139
+ setOutputDisplay ( docstring ) ;
140
+ } catch ( error : any ) {
141
+ const errorMessage = error . response ?. data . error || 'An enexpected error occurred' ;
142
+ alert ( errorMessage ) ;
143
+ } finally {
144
+ setIsGenerating ( false ) ;
145
+ }
71
146
} ;
72
147
73
148
return (
@@ -125,28 +200,28 @@ export default function Example() {
125
200
< header className = "relative py-6" >
126
201
< div className = "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" >
127
202
< h1 className = "text-2xl font-bold text-white" > Documentation Writer</ h1 >
128
- < p className = "mt-1 text-gray-300 " > Add some code to get started</ p >
203
+ < p className = "mt-1 text-gray-200 " > Add some code to get started</ p >
129
204
</ div >
130
205
</ header >
131
206
</ >
132
207
) }
133
208
</ Disclosure >
134
- < main className = "relative -mt-32" >
209
+ < main className = "relative -mt-32 z-10 " >
135
210
< div className = "max-w-screen-xl mx-auto pb-6 px-4 sm:px-6 lg:pb-16 lg:px-8" >
136
211
< div className = "rounded-lg overflow-hidden" >
137
212
< div className = "grid sm:grid-cols-2 sm:gap-4" >
138
213
< div className = "h-full" >
139
214
< CodeEditor
140
215
code = { code }
141
- setCode = { codeOnChange }
216
+ setCode = { onCodeChange }
142
217
placeholder = "Type or paste code here"
143
- language = { outputDisplay }
218
+ languageGrammar = { selectedLanguage . grammar }
144
219
/>
145
220
</ div >
146
221
< div className = "h-full mt-4 sm:m-0" >
147
222
< Output
148
223
output = { outputDisplay }
149
- isLoading = { false }
224
+ isLoading = { isGenerating }
150
225
/>
151
226
</ div >
152
227
</ div >
@@ -159,8 +234,10 @@ export default function Example() {
159
234
< p className = "text-sm text-gray-600 mb-1 font-medium" > Language</ p >
160
235
< Menu as = "div" className = "relative inline-block text-left" >
161
236
< div >
162
- < Menu . Button className = "inline-flex justify-center w-full rounded-md border border-gray-200 shadow-sm px-2 py-1 bg-white text-sm text-gray-700 hover:bg-gray-50 hover:border-gray-300" >
163
- JavaScript (auto)
237
+ < Menu . Button className = "inline-flex items-stretch w-40 rounded-md border border-gray-200 shadow-sm px-2 py-1 bg-white text-sm text-gray-700 hover:bg-gray-50 hover:border-gray-300" >
238
+ < div className = "flex-1 text-left text-gray-700" >
239
+ { selectedLanguage . name }
240
+ </ div >
164
241
< ChevronDownIcon className = "-mr-1 ml-2 h-5 w-5" aria-hidden = "true" />
165
242
</ Menu . Button >
166
243
</ div >
@@ -174,20 +251,22 @@ export default function Example() {
174
251
leaveFrom = "transform opacity-100 scale-100"
175
252
leaveTo = "transform opacity-0 scale-95"
176
253
>
177
- < Menu . Items className = "origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none " >
254
+ < Menu . Items className = "origin-top-right w-40 absolute right-0 mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5" >
178
255
< div className = "py-1" >
179
- < Menu . Item >
180
- { ( { active } ) => (
181
- < span
256
+ { languagesDropdown . map ( ( language ) => (
257
+ < Menu . Item key = { language . id } >
258
+ < button
259
+ type = "button"
260
+ onClick = { ( ) => setSelectedLanguage ( language ) }
182
261
className = { classNames (
183
- active ? 'bg-gray-100 text-gray-900' : 'text-gray-700' ,
184
- 'block px-4 py-2 text-sm' ,
262
+ selectedLanguage . id === language . id ? 'bg-gray-100 text-gray-900' : 'text-gray-700' ,
263
+ 'block px-4 py-2 text-sm w-full text-left hover:bg-gray-100 ' ,
185
264
) }
186
265
>
187
- Account settings
188
- </ span >
189
- ) }
190
- </ Menu . Item >
266
+ { language . name }
267
+ </ button >
268
+ </ Menu . Item >
269
+ ) ) }
191
270
</ div >
192
271
</ Menu . Items >
193
272
</ Transition >
@@ -197,8 +276,10 @@ export default function Example() {
197
276
< p className = "text-sm text-gray-600 mb-1 font-medium" > Format</ p >
198
277
< Menu as = "div" className = "relative inline-block text-left" >
199
278
< div >
200
- < Menu . Button className = "inline-flex justify-center w-full rounded-md border border-gray-200 shadow-sm px-2 py-1 bg-white text-sm text-gray-700 hover:bg-gray-50 hover:border-gray-300" >
201
- JSDoc (auto)
279
+ < Menu . Button className = "inline-flex justify-center w-32 rounded-md border border-gray-200 shadow-sm px-2 py-1 bg-white text-sm hover:bg-gray-50 hover:border-gray-300" >
280
+ < div className = "flex-1 text-left text-gray-700" >
281
+ { selectedFormat . name }
282
+ </ div >
202
283
< ChevronDownIcon className = "-mr-1 ml-2 h-5 w-5" aria-hidden = "true" />
203
284
</ Menu . Button >
204
285
</ div >
@@ -212,43 +293,88 @@ export default function Example() {
212
293
leaveFrom = "transform opacity-100 scale-100"
213
294
leaveTo = "transform opacity-0 scale-95"
214
295
>
215
- < Menu . Items className = "origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none" >
296
+ < Menu . Items className = "origin-top-right w-32 absolute right-0 mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none" >
216
297
< div className = "py-1" >
217
- < Menu . Item >
218
- { ( { active } ) => (
219
- < span
220
- className = { classNames (
221
- active ? 'bg-gray-100 text-gray-900' : 'text-gray-700' ,
222
- 'block px-4 py-2 text-sm' ,
223
- ) }
224
- >
225
- Account settings
226
- </ span >
227
- ) }
228
- </ Menu . Item >
298
+ {
299
+ formats . map ( ( format ) => (
300
+ < Menu . Item key = { format . id } >
301
+ < button
302
+ type = "button"
303
+ onClick = { ( ) => setSelectedFormat ( format ) }
304
+ className = { classNames (
305
+ format . id === selectedFormat . id ? 'bg-gray-100 text-gray-900' : 'text-gray-700' ,
306
+ 'block px-4 py-2 text-sm w-full text-left' ,
307
+ ) }
308
+ >
309
+ { format . name }
310
+ </ button >
311
+ </ Menu . Item >
312
+ ) )
313
+ }
229
314
</ div >
230
315
</ Menu . Items >
231
316
</ Transition >
232
317
</ Menu >
233
318
</ div >
319
+ < div >
320
+ < p className = "text-sm text-gray-600 mb-1 font-medium" > Commented</ p >
321
+ < div className = "mt-2 flex" >
322
+ < Switch
323
+ checked = { commentsEnabled }
324
+ onChange = { setCommentsEnabled }
325
+ className = "flex-shrink-0 group relative rounded-full inline-flex items-center justify-center h-5 w-10 cursor-pointer"
326
+ >
327
+ < span className = "sr-only" > Use setting</ span >
328
+ < span aria-hidden = "true" className = "pointer-events-none absolute bg-white w-full h-full rounded-md" />
329
+ < span
330
+ aria-hidden = "true"
331
+ className = { classNames (
332
+ commentsEnabled ? 'bg-primary' : 'bg-gray-200' ,
333
+ 'pointer-events-none absolute h-4 w-9 mx-auto rounded-full transition-colors ease-in-out duration-200' ,
334
+ ) }
335
+ />
336
+ < span
337
+ aria-hidden = "true"
338
+ className = { classNames (
339
+ commentsEnabled ? 'translate-x-5' : 'translate-x-0' ,
340
+ 'pointer-events-none absolute left-0 inline-block h-5 w-5 border border-gray-200 rounded-full bg-white shadow transform ring-0 transition-transform ease-in-out duration-200' ,
341
+ ) }
342
+ />
343
+ </ Switch >
344
+ </ div >
345
+ </ div >
234
346
< button
235
347
type = "button"
236
- className = "inline-flex space-x-1 items-center px-4 py-2 text-sm rounded-md text-green-600 bg-green-500 bg-opacity-25 hover:bg-opacity-40 duration-200"
348
+ className = "relative flex w-32 space-x-1 justify-center items-center px-4 py-2 text-sm rounded-md text-green-600 bg-green-500 bg-opacity-25 hover:bg-opacity-40 duration-200"
349
+ onClick = { onClickGenerate }
237
350
>
238
- < div >
239
- Write Docs
240
- </ div >
241
- < div >
242
- < PencilAltIcon className = "h-4 w-4" />
243
- </ div >
351
+ {
352
+ isGenerating ? (
353
+ < div className = "absolute inset-0 flex items-center justify-center" >
354
+ < svg className = "animate-spin h-5 w-5" xmlns = "http://www.w3.org/2000/svg" fill = "none" viewBox = "0 0 24 24" >
355
+ < circle className = "opacity-25" cx = "12" cy = "12" r = "10" stroke = "currentColor" strokeWidth = "4" />
356
+ < path className = "opacity-75" fill = "currentColor" d = "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
357
+ </ svg >
358
+ </ div >
359
+ ) : (
360
+ < >
361
+ < div >
362
+ Write Docs
363
+ </ div >
364
+ < div >
365
+ < PencilAltIcon className = "h-4 w-4" />
366
+ </ div >
367
+ </ >
368
+ )
369
+ }
244
370
</ button >
245
371
</ span >
246
372
</ span >
247
373
</ div >
248
374
</ div >
249
375
</ div >
250
376
</ main >
251
- < footer className = "relative pb-8 z-10 bottom-0 w-full" >
377
+ < footer className = "relative pb-8 bottom-0 w-full" >
252
378
< div className = "max-w-7xl mx-auto px-4 overflow-hidden sm:px-6 lg:px-8" >
253
379
< div className = "mt-8 flex justify-center space-x-6" >
254
380
{ footer . social . map ( ( item ) => (
0 commit comments