@tscircuit/fake-snippets 0.0.66 → 0.0.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun-tests/fake-snippets-api/fixtures/get-circuit-json.ts +5 -143
- package/bun-tests/fake-snippets-api/fixtures/get-test-server.ts +1 -4
- package/bun-tests/fake-snippets-api/fixtures/start-server.ts +7 -3
- package/bun-tests/fake-snippets-api/routes/order_quotes/create.test.ts +20 -56
- package/bun-tests/fake-snippets-api/routes/package_files/create_or_update.test.ts +2 -2
- package/bun-tests/fake-snippets-api/routes/package_releases/update.test.ts +1 -1
- package/bun-tests/fake-snippets-api/routes/packages/images.test.ts +0 -11
- package/bun.lock +26 -75
- package/dist/bundle.js +32 -39
- package/fake-snippets-api/routes/api/order_quotes/create.ts +30 -37
- package/fake-snippets-api/routes/api/order_quotes/get.ts +5 -8
- package/package.json +4 -4
- package/src/App.tsx +0 -11
- package/src/ContextProviders.tsx +2 -0
- package/src/components/CmdKMenu.tsx +19 -19
- package/src/components/DownloadButtonAndMenu.tsx +1 -4
- package/src/components/FAQ.tsx +3 -1
- package/src/components/FileSidebar.tsx +50 -1
- package/src/components/Footer.tsx +5 -2
- package/src/components/Header2.tsx +20 -9
- package/src/components/HeaderLogin.tsx +37 -54
- package/src/components/ImageWithFallback.tsx +37 -0
- package/src/components/JLCPCBImportDialog.tsx +45 -29
- package/src/components/PackageCard.tsx +2 -2
- package/src/components/{SnippetLink.tsx → PackageLink.tsx} +8 -16
- package/src/components/PackageSearchResults.tsx +87 -0
- package/src/components/PackagesList.tsx +3 -3
- package/src/components/PageSearchComponent.tsx +9 -9
- package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +5 -28
- package/src/components/ViewPackagePage/components/important-files-view.tsx +1 -1
- package/src/components/ViewPackagePage/components/main-content-header.tsx +8 -8
- package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +24 -14
- package/src/components/ViewPackagePage/components/package-header.tsx +7 -2
- package/src/components/dialogs/confirm-delete-package-dialog.tsx +8 -0
- package/src/components/dialogs/edit-package-details-dialog.tsx +145 -138
- package/src/components/package-port/CodeAndPreview.tsx +40 -19
- package/src/components/package-port/CodeEditor.tsx +21 -37
- package/src/components/package-port/CodeEditorHeader.tsx +1 -1
- package/src/components/package-port/EditorNav.tsx +3 -13
- package/src/hooks/use-global-store.ts +1 -0
- package/src/hooks/use-shiki-highlighter.ts +13 -6
- package/src/hooks/useFileManagement.ts +59 -0
- package/src/lib/download-fns/download-gltf.ts +3 -10
- package/src/lib/handleManualEditsImport.tsx +1 -1
- package/src/lib/types.ts +4 -2
- package/src/lib/utils/isValidFileName.ts +5 -0
- package/src/pages/dashboard.tsx +4 -4
- package/src/pages/editor.tsx +20 -14
- package/src/pages/latest.tsx +25 -26
- package/src/pages/quickstart.tsx +5 -5
- package/src/pages/search.tsx +121 -20
- package/src/pages/trending.tsx +14 -58
- package/src/pages/user-profile.tsx +14 -8
- package/bun-tests/fake-snippets-api/routes/snippets/add_star.test.ts +0 -84
- package/bun-tests/fake-snippets-api/routes/snippets/create.test.ts +0 -53
- package/bun-tests/fake-snippets-api/routes/snippets/delete.test.ts +0 -82
- package/bun-tests/fake-snippets-api/routes/snippets/download.test.ts +0 -90
- package/bun-tests/fake-snippets-api/routes/snippets/generate_from_jlcpcb.test.ts +0 -16
- package/bun-tests/fake-snippets-api/routes/snippets/get.test.ts +0 -163
- package/bun-tests/fake-snippets-api/routes/snippets/get_image.test.ts +0 -117
- package/bun-tests/fake-snippets-api/routes/snippets/images.test.ts +0 -114
- package/bun-tests/fake-snippets-api/routes/snippets/list.test.ts +0 -169
- package/bun-tests/fake-snippets-api/routes/snippets/list_newest.test.ts +0 -50
- package/bun-tests/fake-snippets-api/routes/snippets/list_trending.test.ts +0 -72
- package/bun-tests/fake-snippets-api/routes/snippets/remove_star.test.ts +0 -80
- package/bun-tests/fake-snippets-api/routes/snippets/search.test.ts +0 -75
- package/bun-tests/fake-snippets-api/routes/snippets/star-count.test.ts +0 -51
- package/bun-tests/fake-snippets-api/routes/snippets/update.test.ts +0 -175
- package/src/components/AiChatInterface.tsx +0 -229
- package/src/components/CodeAndPreview.tsx +0 -289
- package/src/components/CodeEditor.tsx +0 -539
- package/src/components/CodeEditorHeader.tsx +0 -135
- package/src/components/EditorNav.tsx +0 -502
- package/src/components/OrderPreviewContent.tsx +0 -61
- package/src/components/PreviewContent.tsx +0 -372
- package/src/components/SnippetCard.tsx +0 -159
- package/src/components/SnippetList.tsx +0 -71
- package/src/components/ViewSnippetSidebar.tsx +0 -162
- package/src/components/dialogs/create-order-dialog.tsx +0 -146
- package/src/hooks/use-compiled-tsx.ts +0 -37
- package/src/hooks/use-run-tsx/construct-circuit.tsx +0 -62
- package/src/hooks/use-run-tsx/index.tsx +0 -256
- package/src/hooks/use-save-snippet.ts +0 -66
- package/src/hooks/use-typecheck.ts +0 -54
- package/src/lib/utils/getSyntaxError.ts +0 -13
- package/src/pages/ai.tsx +0 -92
- package/src/pages/preview.tsx +0 -44
- package/src/pages/view-order.tsx +0 -111
- package/src/pages/view-snippet.tsx +0 -166
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
Dialog,
|
|
17
17
|
DialogContent,
|
|
18
18
|
DialogDescription,
|
|
19
|
+
DialogFooter,
|
|
19
20
|
DialogHeader,
|
|
20
21
|
DialogTitle,
|
|
21
22
|
} from "../ui/dialog"
|
|
@@ -217,151 +218,157 @@ export const EditPackageDetailsDialog = ({
|
|
|
217
218
|
</DialogContent>
|
|
218
219
|
</Dialog>
|
|
219
220
|
<Dialog open={open !== showConfirmDelete} onOpenChange={onOpenChange}>
|
|
220
|
-
<DialogContent className="sm:max-w-[500px] lg:h-[70vh] sm:h-[90vh] overflow-y-auto w-[95vw] p-6 gap-6 rounded-2xl shadow-lg">
|
|
221
|
-
<
|
|
222
|
-
<
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
221
|
+
<DialogContent className="sm:max-w-[500px] lg:h-[70vh] sm:h-[90vh] overflow-y-auto w-[95vw] h-[80vh] p-6 gap-6 rounded-2xl shadow-lg">
|
|
222
|
+
<div className="flex flex-col gap-10">
|
|
223
|
+
<DialogHeader>
|
|
224
|
+
<DialogTitle>Edit Package Details</DialogTitle>
|
|
225
|
+
<DialogDescription>
|
|
226
|
+
Update your package's description, website, visibility, or
|
|
227
|
+
delete it.
|
|
228
|
+
</DialogDescription>
|
|
229
|
+
</DialogHeader>
|
|
230
|
+
<div className="">
|
|
231
|
+
<div className="grid gap-2">
|
|
232
|
+
<div className="space-y-1">
|
|
233
|
+
<Label htmlFor="website">Website</Label>
|
|
234
|
+
<Input
|
|
235
|
+
id="website"
|
|
236
|
+
value={formData.website}
|
|
237
|
+
onChange={(e) =>
|
|
238
|
+
setFormData((prev) => ({
|
|
239
|
+
...prev,
|
|
240
|
+
website: e.target.value,
|
|
241
|
+
}))
|
|
242
|
+
}
|
|
243
|
+
placeholder="https://example.com"
|
|
244
|
+
disabled={updatePackageDetailsMutation.isLoading}
|
|
245
|
+
className="w-full"
|
|
246
|
+
aria-invalid={!!websiteError}
|
|
247
|
+
/>
|
|
248
|
+
{websiteError && (
|
|
249
|
+
<p className="text-sm text-red-500">{websiteError}</p>
|
|
250
|
+
)}
|
|
251
|
+
</div>
|
|
252
|
+
<div className="space-y-1">
|
|
253
|
+
<Label htmlFor="visibility">Visibility</Label>
|
|
254
|
+
<Select
|
|
255
|
+
value={formData.visibility}
|
|
256
|
+
onValueChange={(val) => {
|
|
257
|
+
setFormData((prev) => ({
|
|
258
|
+
...prev,
|
|
259
|
+
visibility: val,
|
|
260
|
+
}))
|
|
261
|
+
}}
|
|
262
|
+
disabled={updatePackageDetailsMutation.isLoading}
|
|
263
|
+
>
|
|
264
|
+
<SelectTrigger className="w-full">
|
|
265
|
+
<SelectValue placeholder="Select visibility" />
|
|
266
|
+
</SelectTrigger>
|
|
267
|
+
<SelectContent className="!z-[999]">
|
|
268
|
+
<SelectItem value="public">public</SelectItem>
|
|
269
|
+
<SelectItem value="private">private</SelectItem>
|
|
270
|
+
</SelectContent>
|
|
271
|
+
</Select>
|
|
272
|
+
</div>
|
|
273
|
+
<div className="space-y-1">
|
|
274
|
+
<Label htmlFor="description">Description</Label>
|
|
275
|
+
<Textarea
|
|
276
|
+
id="description"
|
|
277
|
+
value={formData.description}
|
|
278
|
+
onChange={(e) =>
|
|
279
|
+
setFormData((prev) => ({
|
|
280
|
+
...prev,
|
|
281
|
+
description: e.target.value,
|
|
282
|
+
}))
|
|
283
|
+
}
|
|
284
|
+
placeholder="Enter package description"
|
|
285
|
+
disabled={updatePackageDetailsMutation.isLoading}
|
|
286
|
+
className="w-full min-h-[80px] resize-none"
|
|
287
|
+
/>
|
|
288
|
+
</div>
|
|
289
|
+
<div className="space-y-1">
|
|
290
|
+
<Label htmlFor="license">License</Label>
|
|
291
|
+
<Select
|
|
292
|
+
value={formData.license || "unset"}
|
|
293
|
+
onValueChange={(value) =>
|
|
294
|
+
setFormData((prev) => ({
|
|
295
|
+
...prev,
|
|
296
|
+
license: value === "unset" ? null : value,
|
|
297
|
+
}))
|
|
298
|
+
}
|
|
299
|
+
disabled={updatePackageDetailsMutation.isLoading}
|
|
300
|
+
>
|
|
301
|
+
<SelectTrigger className="w-full">
|
|
302
|
+
<SelectValue placeholder="Select a license" />
|
|
303
|
+
</SelectTrigger>
|
|
304
|
+
<SelectContent className="!z-[999]">
|
|
305
|
+
<SelectItem value="MIT">MIT</SelectItem>
|
|
306
|
+
<SelectItem value="Apache-2.0">Apache-2.0</SelectItem>
|
|
307
|
+
<SelectItem value="BSD-3-Clause">BSD-3-Clause</SelectItem>
|
|
308
|
+
<SelectItem value="GPL-3.0">GPL-3.0</SelectItem>
|
|
309
|
+
<SelectItem value="unset">Unset</SelectItem>
|
|
310
|
+
</SelectContent>
|
|
311
|
+
</Select>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
228
314
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
<Input
|
|
233
|
-
id="website"
|
|
234
|
-
value={formData.website}
|
|
235
|
-
onChange={(e) =>
|
|
236
|
-
setFormData((prev) => ({
|
|
237
|
-
...prev,
|
|
238
|
-
website: e.target.value,
|
|
239
|
-
}))
|
|
240
|
-
}
|
|
241
|
-
placeholder="https://example.com"
|
|
242
|
-
disabled={updatePackageDetailsMutation.isLoading}
|
|
243
|
-
className="w-full"
|
|
244
|
-
aria-invalid={!!websiteError}
|
|
245
|
-
/>
|
|
246
|
-
{websiteError && (
|
|
247
|
-
<p className="text-sm text-red-500">{websiteError}</p>
|
|
248
|
-
)}
|
|
249
|
-
</div>
|
|
250
|
-
<div className="space-y-1">
|
|
251
|
-
<Label htmlFor="visibility">Visibility</Label>
|
|
252
|
-
<Select
|
|
253
|
-
value={formData.visibility}
|
|
254
|
-
onValueChange={(val) => {
|
|
255
|
-
setFormData((prev) => ({
|
|
256
|
-
...prev,
|
|
257
|
-
visibility: val,
|
|
258
|
-
}))
|
|
259
|
-
}}
|
|
260
|
-
disabled={updatePackageDetailsMutation.isLoading}
|
|
315
|
+
<details
|
|
316
|
+
className="mt-2 rounded-md"
|
|
317
|
+
onToggle={(e) => setDangerOpen(e.currentTarget.open)}
|
|
261
318
|
>
|
|
262
|
-
<
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
319
|
+
<summary className="cursor-pointer p-2 font-medium text-sm text-black list-none flex justify-between items-center">
|
|
320
|
+
Danger Zone
|
|
321
|
+
<ChevronDown
|
|
322
|
+
className={`w-4 h-4 mr-1 transition-transform ${dangerOpen ? "rotate-180" : ""}`}
|
|
323
|
+
/>
|
|
324
|
+
</summary>
|
|
325
|
+
<div className="p-2 pr-2">
|
|
326
|
+
<div className="flex justify-between items-center">
|
|
327
|
+
<div>
|
|
328
|
+
<p className="text-sm text-muted-foreground">
|
|
329
|
+
Once deleted, it cannot be recovered.
|
|
330
|
+
</p>
|
|
331
|
+
</div>
|
|
332
|
+
<Button
|
|
333
|
+
variant="destructive"
|
|
334
|
+
size="default"
|
|
335
|
+
onClick={() => setShowConfirmDelete(true)}
|
|
336
|
+
disabled={deleting}
|
|
337
|
+
className="shrink-0 lg:w-[115px] w-[70px]"
|
|
338
|
+
>
|
|
339
|
+
{deleting ? "Deleting..." : "Delete"}
|
|
340
|
+
</Button>
|
|
341
|
+
</div>
|
|
342
|
+
</div>
|
|
343
|
+
</details>
|
|
270
344
|
</div>
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
...prev,
|
|
279
|
-
description: e.target.value,
|
|
280
|
-
}))
|
|
281
|
-
}
|
|
282
|
-
placeholder="Enter package description"
|
|
345
|
+
</div>
|
|
346
|
+
|
|
347
|
+
<DialogFooter className="mt-auto">
|
|
348
|
+
<div className="lg:px-2 flex flex-col sm:flex-row justify-end gap-2">
|
|
349
|
+
<Button
|
|
350
|
+
variant="outline"
|
|
351
|
+
onClick={() => onOpenChange(false)}
|
|
283
352
|
disabled={updatePackageDetailsMutation.isLoading}
|
|
284
|
-
className="w-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
<
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
license: value === "unset" ? null : value,
|
|
295
|
-
}))
|
|
353
|
+
className="sm:w-auto w-full"
|
|
354
|
+
>
|
|
355
|
+
Cancel
|
|
356
|
+
</Button>
|
|
357
|
+
<Button
|
|
358
|
+
onClick={() => updatePackageDetailsMutation.mutate()}
|
|
359
|
+
disabled={
|
|
360
|
+
updatePackageDetailsMutation.isLoading ||
|
|
361
|
+
!hasChanges ||
|
|
362
|
+
!isFormValid
|
|
296
363
|
}
|
|
297
|
-
|
|
364
|
+
className="sm:w-auto lg:w-[115px]"
|
|
298
365
|
>
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
<SelectItem value="MIT">MIT</SelectItem>
|
|
304
|
-
<SelectItem value="Apache-2.0">Apache-2.0</SelectItem>
|
|
305
|
-
<SelectItem value="BSD-3-Clause">BSD-3-Clause</SelectItem>
|
|
306
|
-
<SelectItem value="GPL-3.0">GPL-3.0</SelectItem>
|
|
307
|
-
<SelectItem value="unset">Unset</SelectItem>
|
|
308
|
-
</SelectContent>
|
|
309
|
-
</Select>
|
|
310
|
-
</div>
|
|
311
|
-
</div>
|
|
312
|
-
<details
|
|
313
|
-
className="mt-2 rounded-md"
|
|
314
|
-
onToggle={(e) => setDangerOpen(e.currentTarget.open)}
|
|
315
|
-
>
|
|
316
|
-
<summary className="cursor-pointer p-2 font-medium text-sm text-black list-none flex justify-between items-center">
|
|
317
|
-
Danger Zone
|
|
318
|
-
<ChevronDown
|
|
319
|
-
className={`w-4 h-4 mr-1 transition-transform ${dangerOpen ? "rotate-180" : ""}`}
|
|
320
|
-
/>
|
|
321
|
-
</summary>
|
|
322
|
-
<div className="p-2 pr-2">
|
|
323
|
-
<div className="flex justify-between items-center">
|
|
324
|
-
<div>
|
|
325
|
-
<p className="text-sm text-muted-foreground">
|
|
326
|
-
Once deleted, it cannot be recovered.
|
|
327
|
-
</p>
|
|
328
|
-
</div>
|
|
329
|
-
<Button
|
|
330
|
-
variant="destructive"
|
|
331
|
-
size="default"
|
|
332
|
-
onClick={() => setShowConfirmDelete(true)}
|
|
333
|
-
disabled={deleting}
|
|
334
|
-
className="shrink-0 lg:w-[115px] w-[70px]"
|
|
335
|
-
>
|
|
336
|
-
{deleting ? "Deleting..." : "Delete"}
|
|
337
|
-
</Button>
|
|
338
|
-
</div>
|
|
366
|
+
{updatePackageDetailsMutation.isLoading
|
|
367
|
+
? "Updating..."
|
|
368
|
+
: "Save Changes"}
|
|
369
|
+
</Button>
|
|
339
370
|
</div>
|
|
340
|
-
</
|
|
341
|
-
|
|
342
|
-
<div className=" lg:px-2 flex flex-col sm:flex-row justify-end gap-3">
|
|
343
|
-
<Button
|
|
344
|
-
variant="outline"
|
|
345
|
-
onClick={() => onOpenChange(false)}
|
|
346
|
-
disabled={updatePackageDetailsMutation.isLoading}
|
|
347
|
-
className="sm:w-auto w-full"
|
|
348
|
-
>
|
|
349
|
-
Cancel
|
|
350
|
-
</Button>
|
|
351
|
-
<Button
|
|
352
|
-
onClick={() => updatePackageDetailsMutation.mutate()}
|
|
353
|
-
disabled={
|
|
354
|
-
updatePackageDetailsMutation.isLoading ||
|
|
355
|
-
!hasChanges ||
|
|
356
|
-
!isFormValid
|
|
357
|
-
}
|
|
358
|
-
className="sm:w-auto lg:w-[115px]"
|
|
359
|
-
>
|
|
360
|
-
{updatePackageDetailsMutation.isLoading
|
|
361
|
-
? "Updating..."
|
|
362
|
-
: "Save Changes"}
|
|
363
|
-
</Button>
|
|
364
|
-
</div>
|
|
371
|
+
</DialogFooter>
|
|
365
372
|
</DialogContent>
|
|
366
373
|
</Dialog>
|
|
367
374
|
</div>
|
|
@@ -22,6 +22,8 @@ import { usePackageFilesLoader } from "@/hooks/usePackageFilesLoader"
|
|
|
22
22
|
import { findTargetFile } from "@/lib/utils/findTargetFile"
|
|
23
23
|
import { toastManualEditConflicts } from "@/lib/utils/toastManualEditConflicts"
|
|
24
24
|
import { ManualEditEvent } from "@tscircuit/props"
|
|
25
|
+
import { isValidFileName } from "@/lib/utils/isValidFileName"
|
|
26
|
+
import { useFileManagement } from "@/hooks/useFileManagement"
|
|
25
27
|
|
|
26
28
|
interface Props {
|
|
27
29
|
pkg?: Package
|
|
@@ -32,12 +34,19 @@ export interface PackageFile {
|
|
|
32
34
|
content: string
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
interface
|
|
37
|
+
export interface CreateFileProps {
|
|
38
|
+
newFileName: string
|
|
39
|
+
setErrorMessage: (message: string) => void
|
|
40
|
+
onFileSelect: (fileName: string) => void
|
|
41
|
+
setNewFileName: (fileName: string) => void
|
|
42
|
+
setIsCreatingFile: (isCreatingFile: boolean) => void
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface CodeAndPreviewState {
|
|
36
46
|
pkgFilesWithContent: PackageFile[]
|
|
37
47
|
initialFilesLoad: PackageFile[]
|
|
38
48
|
showPreview: boolean
|
|
39
49
|
fullScreen: boolean
|
|
40
|
-
dts: string
|
|
41
50
|
lastSavedAt: number
|
|
42
51
|
circuitJson: null | any
|
|
43
52
|
isPrivate: boolean
|
|
@@ -92,7 +101,6 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
92
101
|
initialFilesLoad: [],
|
|
93
102
|
showPreview: true,
|
|
94
103
|
fullScreen: false,
|
|
95
|
-
dts: "",
|
|
96
104
|
lastSavedAt: Date.now(),
|
|
97
105
|
circuitJson: null,
|
|
98
106
|
isPrivate: false,
|
|
@@ -148,7 +156,6 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
148
156
|
|
|
149
157
|
if (loadedFiles && !isLoadingFiles) {
|
|
150
158
|
const processedResults = [...loadedFiles]
|
|
151
|
-
|
|
152
159
|
setState((prev) => ({
|
|
153
160
|
...prev,
|
|
154
161
|
pkgFilesWithContent: processedResults,
|
|
@@ -159,13 +166,7 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
159
166
|
defaultCode,
|
|
160
167
|
}))
|
|
161
168
|
}
|
|
162
|
-
}, [
|
|
163
|
-
isLoadingFiles,
|
|
164
|
-
pkg,
|
|
165
|
-
pkgFiles.data,
|
|
166
|
-
state.pkgFilesWithContent.length,
|
|
167
|
-
defaultCode,
|
|
168
|
-
])
|
|
169
|
+
}, [isLoadingFiles, pkg, pkgFiles.data, defaultCode])
|
|
169
170
|
|
|
170
171
|
const createPackageMutation = useCreatePackageMutation()
|
|
171
172
|
const { mutate: createRelease } = useCreatePackageReleaseMutation({
|
|
@@ -250,10 +251,21 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
250
251
|
setState((prev) => ({ ...prev, lastSavedAt: Date.now() }))
|
|
251
252
|
|
|
252
253
|
if (pkg) {
|
|
253
|
-
updatePackageFilesMutation.mutate(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
updatePackageFilesMutation.mutate(
|
|
255
|
+
{
|
|
256
|
+
package_name_with_version: `${pkg.name}@latest`,
|
|
257
|
+
...pkg,
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
onSuccess: () => {
|
|
261
|
+
setState((prev) => ({
|
|
262
|
+
...prev,
|
|
263
|
+
initialFilesLoad: [...prev.pkgFilesWithContent],
|
|
264
|
+
}))
|
|
265
|
+
pkgFiles.refetch()
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
)
|
|
257
269
|
}
|
|
258
270
|
}
|
|
259
271
|
|
|
@@ -284,10 +296,17 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
284
296
|
state.pkgFilesWithContent,
|
|
285
297
|
])
|
|
286
298
|
const mainComponentPath = useMemo(() => {
|
|
287
|
-
|
|
299
|
+
const isReactComponentExported =
|
|
300
|
+
/export function\s+\w+/.test(currentFileCode) ||
|
|
301
|
+
/export const\s+\w+\s*=/.test(currentFileCode) ||
|
|
302
|
+
/export default\s+\w+/.test(currentFileCode) ||
|
|
303
|
+
/export default\s+function\s*(\w*)\s*\(/.test(currentFileCode) ||
|
|
304
|
+
/export default\s*\(\s*\)\s*=>/.test(currentFileCode)
|
|
305
|
+
|
|
306
|
+
return (state.currentFile?.endsWith(".tsx") ||
|
|
307
|
+
state.currentFile?.endsWith(".ts")) &&
|
|
288
308
|
!!state.pkgFilesWithContent.some((x) => x.path == state.currentFile) &&
|
|
289
|
-
|
|
290
|
-
currentFileCode.match(/export const (\w+) ?=/))
|
|
309
|
+
isReactComponentExported
|
|
291
310
|
? state.currentFile
|
|
292
311
|
: state.defaultComponentFile
|
|
293
312
|
}, [state.currentFile, state.pkgFilesWithContent, currentFileCode])
|
|
@@ -327,6 +346,8 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
327
346
|
})
|
|
328
347
|
}
|
|
329
348
|
|
|
349
|
+
const { handleCreateFile } = useFileManagement(state, setState)
|
|
350
|
+
|
|
330
351
|
if ((!pkg && urlParams.package_id) || pkgFiles.isLoading || isLoadingFiles) {
|
|
331
352
|
return (
|
|
332
353
|
<div className="flex items-center justify-center h-64">
|
|
@@ -363,6 +384,7 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
363
384
|
)}
|
|
364
385
|
>
|
|
365
386
|
<CodeEditor
|
|
387
|
+
handleCreateFile={handleCreateFile}
|
|
366
388
|
currentFile={state.currentFile}
|
|
367
389
|
setCurrentFile={(file) =>
|
|
368
390
|
setState((prev) => ({ ...prev, currentFile: file }))
|
|
@@ -379,7 +401,6 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
379
401
|
),
|
|
380
402
|
}))
|
|
381
403
|
}}
|
|
382
|
-
onDtsChange={(dts) => setState((prev) => ({ ...prev, dts }))}
|
|
383
404
|
pkgFilesLoaded={state.pkgFilesLoaded}
|
|
384
405
|
/>
|
|
385
406
|
</div>
|
|
@@ -23,12 +23,12 @@ import {
|
|
|
23
23
|
} from "@valtown/codemirror-ts"
|
|
24
24
|
import { EditorView } from "codemirror"
|
|
25
25
|
import { useEffect, useMemo, useRef, useState } from "react"
|
|
26
|
-
import
|
|
26
|
+
import tsModule from "typescript"
|
|
27
27
|
import CodeEditorHeader from "@/components/package-port/CodeEditorHeader"
|
|
28
28
|
import { useCodeCompletionApi } from "@/hooks/use-code-completion-ai-api"
|
|
29
29
|
import FileSidebar from "../FileSidebar"
|
|
30
30
|
import { findTargetFile } from "@/lib/utils/findTargetFile"
|
|
31
|
-
import type { PackageFile } from "./CodeAndPreview"
|
|
31
|
+
import type { CreateFileProps, PackageFile } from "./CodeAndPreview"
|
|
32
32
|
import { useShikiHighlighter } from "@/hooks/use-shiki-highlighter"
|
|
33
33
|
|
|
34
34
|
const defaultImports = `
|
|
@@ -39,7 +39,6 @@ import type { CommonLayoutProps } from "@tscircuit/props"
|
|
|
39
39
|
|
|
40
40
|
export const CodeEditor = ({
|
|
41
41
|
onCodeChange,
|
|
42
|
-
onDtsChange,
|
|
43
42
|
readOnly = false,
|
|
44
43
|
files = [],
|
|
45
44
|
isStreaming = false,
|
|
@@ -48,10 +47,11 @@ export const CodeEditor = ({
|
|
|
48
47
|
pkgFilesLoaded,
|
|
49
48
|
currentFile,
|
|
50
49
|
setCurrentFile,
|
|
50
|
+
handleCreateFile,
|
|
51
51
|
}: {
|
|
52
52
|
onCodeChange: (code: string, filename?: string) => void
|
|
53
|
-
onDtsChange?: (dts: string) => void
|
|
54
53
|
files: PackageFile[]
|
|
54
|
+
handleCreateFile: (props: CreateFileProps) => void
|
|
55
55
|
readOnly?: boolean
|
|
56
56
|
isStreaming?: boolean
|
|
57
57
|
pkgFilesLoaded?: boolean
|
|
@@ -67,9 +67,8 @@ export const CodeEditor = ({
|
|
|
67
67
|
const codeCompletionApi = useCodeCompletionApi()
|
|
68
68
|
const [cursorPosition, setCursorPosition] = useState<number | null>(null)
|
|
69
69
|
const [code, setCode] = useState(files[0]?.content || "")
|
|
70
|
-
const [isCodeEditorReady, setIsCodeEditorReady] = useState(false)
|
|
71
70
|
|
|
72
|
-
const { highlighter
|
|
71
|
+
const { highlighter } = useShikiHighlighter()
|
|
73
72
|
|
|
74
73
|
// Get URL search params for file_path
|
|
75
74
|
const urlParams = new URLSearchParams(window.location.search)
|
|
@@ -134,10 +133,10 @@ export const CodeEditor = ({
|
|
|
134
133
|
;(window as any).__DEBUG_CODE_EDITOR_FS_MAP = fsMap
|
|
135
134
|
|
|
136
135
|
createDefaultMapFromCDN(
|
|
137
|
-
{ target:
|
|
136
|
+
{ target: tsModule.ScriptTarget.ES2022 },
|
|
138
137
|
"5.6.3",
|
|
139
138
|
true,
|
|
140
|
-
|
|
139
|
+
tsModule,
|
|
141
140
|
).then((defaultFsMap) => {
|
|
142
141
|
defaultFsMap.forEach((content, filename) => {
|
|
143
142
|
fsMap.set(filename, content)
|
|
@@ -145,11 +144,12 @@ export const CodeEditor = ({
|
|
|
145
144
|
})
|
|
146
145
|
|
|
147
146
|
const system = createSystem(fsMap)
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
|
|
148
|
+
const env = createVirtualTypeScriptEnvironment(system, [], tsModule, {
|
|
149
|
+
jsx: tsModule.JsxEmit.ReactJSX,
|
|
150
150
|
declaration: true,
|
|
151
151
|
allowJs: true,
|
|
152
|
-
target:
|
|
152
|
+
target: tsModule.ScriptTarget.ES2022,
|
|
153
153
|
resolveJsonModule: true,
|
|
154
154
|
})
|
|
155
155
|
|
|
@@ -160,7 +160,7 @@ export const CodeEditor = ({
|
|
|
160
160
|
// Initialize ATA
|
|
161
161
|
const ataConfig: ATABootstrapConfig = {
|
|
162
162
|
projectName: "my-project",
|
|
163
|
-
typescript:
|
|
163
|
+
typescript: tsModule,
|
|
164
164
|
logger: console,
|
|
165
165
|
fetcher: async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
166
166
|
const registryPrefixes = [
|
|
@@ -190,9 +190,6 @@ export const CodeEditor = ({
|
|
|
190
190
|
return fetch(input, init)
|
|
191
191
|
},
|
|
192
192
|
delegate: {
|
|
193
|
-
finished: () => {
|
|
194
|
-
setIsCodeEditorReady(true)
|
|
195
|
-
},
|
|
196
193
|
started: () => {
|
|
197
194
|
const manualEditsTypeDeclaration = `
|
|
198
195
|
declare module "manual-edits.json" {
|
|
@@ -247,20 +244,6 @@ export const CodeEditor = ({
|
|
|
247
244
|
// setCode(newContent)
|
|
248
245
|
onCodeChange(newContent, currentFile)
|
|
249
246
|
onFileContentChanged?.(currentFile, newContent)
|
|
250
|
-
|
|
251
|
-
// Generate TypeScript declarations for TypeScript/TSX files
|
|
252
|
-
if (currentFile.endsWith(".ts") || currentFile.endsWith(".tsx")) {
|
|
253
|
-
const { outputFiles } = env.languageService.getEmitOutput(
|
|
254
|
-
currentFile,
|
|
255
|
-
true,
|
|
256
|
-
)
|
|
257
|
-
const dtsFile = outputFiles.find((file) =>
|
|
258
|
-
file.name.endsWith(".d.ts"),
|
|
259
|
-
)
|
|
260
|
-
if (dtsFile?.text && onDtsChange) {
|
|
261
|
-
onDtsChange(dtsFile.text)
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
247
|
}
|
|
265
248
|
if (update.selectionSet) {
|
|
266
249
|
const pos = update.state.selection.main.head
|
|
@@ -336,12 +319,14 @@ export const CodeEditor = ({
|
|
|
336
319
|
|
|
337
320
|
const start = info.textSpan.start
|
|
338
321
|
const end = start + info.textSpan.length
|
|
339
|
-
const content =
|
|
322
|
+
const content = tsModule?.displayPartsToString(
|
|
323
|
+
info.displayParts || [],
|
|
324
|
+
)
|
|
340
325
|
|
|
341
326
|
const dom = document.createElement("div")
|
|
342
327
|
if (highlighter) {
|
|
343
328
|
dom.innerHTML = highlighter.codeToHtml(content, {
|
|
344
|
-
lang: "
|
|
329
|
+
lang: "tsx",
|
|
345
330
|
themes: {
|
|
346
331
|
light: "github-light",
|
|
347
332
|
dark: "github-dark",
|
|
@@ -449,14 +434,12 @@ export const CodeEditor = ({
|
|
|
449
434
|
|
|
450
435
|
if (currentFile.endsWith(".tsx") || currentFile.endsWith(".ts")) {
|
|
451
436
|
ata(`${defaultImports}${code}`)
|
|
452
|
-
} else if (!!currentFile) {
|
|
453
|
-
setIsCodeEditorReady(true)
|
|
454
437
|
}
|
|
455
438
|
|
|
456
439
|
return () => {
|
|
457
440
|
view.destroy()
|
|
458
441
|
}
|
|
459
|
-
}, [!isStreaming, currentFile, code !== ""])
|
|
442
|
+
}, [!isStreaming, currentFile, code !== "", Boolean(highlighter)])
|
|
460
443
|
|
|
461
444
|
const updateCurrentEditorContent = (newContent: string) => {
|
|
462
445
|
if (viewRef.current) {
|
|
@@ -539,6 +522,7 @@ export const CodeEditor = ({
|
|
|
539
522
|
[sidebarOpen, setSidebarOpen] as ReturnType<typeof useState<boolean>>
|
|
540
523
|
}
|
|
541
524
|
onFileSelect={handleFileChange}
|
|
525
|
+
handleCreateFile={handleCreateFile}
|
|
542
526
|
/>
|
|
543
527
|
<div className="flex flex-col flex-1 w-full min-w-0 h-full">
|
|
544
528
|
{showImportAndFormatButtons && (
|
|
@@ -557,9 +541,9 @@ export const CodeEditor = ({
|
|
|
557
541
|
)}
|
|
558
542
|
<div
|
|
559
543
|
ref={editorRef}
|
|
560
|
-
className={
|
|
561
|
-
|
|
562
|
-
}
|
|
544
|
+
className={
|
|
545
|
+
"flex-1 overflow-auto [&_.cm-editor]:h-full [&_.cm-scroller]:!h-full"
|
|
546
|
+
}
|
|
563
547
|
/>
|
|
564
548
|
</div>
|
|
565
549
|
</div>
|
|
@@ -101,7 +101,7 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
101
101
|
markdown: "markdown",
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
const parser = parserMap[fileExtension] || "
|
|
104
|
+
const parser = parserMap[fileExtension] || "tsx"
|
|
105
105
|
const formattedCode = window.prettier.format(currentContent, {
|
|
106
106
|
semi: false,
|
|
107
107
|
parser: parser,
|
|
@@ -39,7 +39,6 @@ import { Link, useLocation } from "wouter"
|
|
|
39
39
|
import { useAxios } from "@/hooks/use-axios"
|
|
40
40
|
import { useToast } from "@/hooks/use-toast"
|
|
41
41
|
import { useConfirmDeletePackageDialog } from "@/components/dialogs/confirm-delete-package-dialog"
|
|
42
|
-
import { useCreateOrderDialog } from "@/components/dialogs/create-order-dialog"
|
|
43
42
|
import { useFilesDialog } from "@/components/dialogs/files-dialog"
|
|
44
43
|
import { useViewTsFilesDialog } from "@/components/dialogs/view-ts-files-dialog"
|
|
45
44
|
import { DownloadButtonAndMenu } from "@/components/DownloadButtonAndMenu"
|
|
@@ -81,8 +80,6 @@ export default function EditorNav({
|
|
|
81
80
|
} = useUpdatePackageDescriptionDialog()
|
|
82
81
|
const { Dialog: DeleteDialog, openDialog: openDeleteDialog } =
|
|
83
82
|
useConfirmDeletePackageDialog()
|
|
84
|
-
const { Dialog: CreateOrderDialog, openDialog: openCreateOrderDialog } =
|
|
85
|
-
useCreateOrderDialog()
|
|
86
83
|
const { Dialog: FilesDialog, openDialog: openFilesDialog } = useFilesDialog()
|
|
87
84
|
const { Dialog: ViewTsFilesDialog, openDialog: openViewTsFilesDialog } =
|
|
88
85
|
useViewTsFilesDialog()
|
|
@@ -315,7 +312,7 @@ export default function EditorNav({
|
|
|
315
312
|
<div className="flex items-center justify-end -space-x-1">
|
|
316
313
|
<div className="flex mx-2 items-center space-x-1">
|
|
317
314
|
{pkg && <TypeBadge type={`${packageType ?? pkg.snippet_type}`} />}
|
|
318
|
-
<Button
|
|
315
|
+
{/* <Button
|
|
319
316
|
variant="ghost"
|
|
320
317
|
size="sm"
|
|
321
318
|
disabled={hasUnsavedChanges || isSaving || !pkg}
|
|
@@ -323,7 +320,7 @@ export default function EditorNav({
|
|
|
323
320
|
>
|
|
324
321
|
<Sparkles className="mr-1 h-3 w-3" />
|
|
325
322
|
Edit with AI
|
|
326
|
-
</Button>
|
|
323
|
+
</Button> */}
|
|
327
324
|
<DownloadButtonAndMenu
|
|
328
325
|
snippetUnscopedName={pkg?.unscoped_name}
|
|
329
326
|
circuitJson={circuitJson}
|
|
@@ -358,13 +355,6 @@ export default function EditorNav({
|
|
|
358
355
|
</Button>
|
|
359
356
|
</DropdownMenuTrigger>
|
|
360
357
|
<DropdownMenuContent>
|
|
361
|
-
<DropdownMenuItem
|
|
362
|
-
className="text-xs"
|
|
363
|
-
onClick={() => openCreateOrderDialog()}
|
|
364
|
-
>
|
|
365
|
-
<PackageIcon className="mr-2 h-3 w-3" />
|
|
366
|
-
Submit Order
|
|
367
|
-
</DropdownMenuItem>
|
|
368
358
|
<DropdownMenuItem
|
|
369
359
|
className="text-xs"
|
|
370
360
|
onClick={() => openFilesDialog()}
|
|
@@ -519,8 +509,8 @@ export default function EditorNav({
|
|
|
519
509
|
<DeleteDialog
|
|
520
510
|
packageId={pkg?.package_id ?? ""}
|
|
521
511
|
packageName={pkg?.unscoped_name ?? ""}
|
|
512
|
+
packageOwner={pkg?.owner_github_username ?? ""}
|
|
522
513
|
/>
|
|
523
|
-
<CreateOrderDialog />
|
|
524
514
|
<FilesDialog snippetId={pkg?.package_id ?? ""} />
|
|
525
515
|
<ViewTsFilesDialog />
|
|
526
516
|
</nav>
|