@tscircuit/fake-snippets 0.0.89 → 0.0.91
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.lock +84 -108
- package/dist/bundle.js +493 -372
- package/fake-snippets-api/routes/api/autocomplete/create_autocomplete.ts +135 -0
- package/package.json +8 -10
- package/src/App.tsx +47 -2
- package/src/ContextProviders.tsx +0 -2
- package/src/components/CircuitJsonImportDialog.tsx +1 -1
- package/src/components/PackageBuildsPage/package-build-header.tsx +2 -12
- package/src/components/PageSearchComponent.tsx +2 -2
- package/src/components/SearchComponent.tsx +2 -2
- package/src/components/TrendingPackagesCarousel.tsx +2 -2
- package/src/components/dialogs/import-component-dialog.tsx +25 -0
- package/src/components/package-port/CodeAndPreview.tsx +1 -16
- package/src/components/package-port/CodeEditor.tsx +34 -8
- package/src/components/package-port/CodeEditorHeader.tsx +75 -13
- package/src/components/package-port/EditorNav.tsx +58 -65
- package/src/components/package-port/GlobalFindReplace.tsx +1 -1
- package/src/components/package-port/QuickOpen.tsx +1 -1
- package/src/hooks/use-axios.ts +2 -2
- package/src/hooks/use-code-completion-ai-api.ts +3 -3
- package/src/hooks/use-delete-package.ts +6 -2
- package/src/hooks/use-packages-base-api-url.ts +3 -0
- package/src/hooks/use-request-ai-review-mutation.ts +1 -1
- package/src/hooks/use-sign-in.ts +2 -2
- package/src/hooks/use-toast.tsx +1 -0
- package/src/hooks/useFileManagement.ts +10 -5
- package/src/lib/utils/findTargetFile.ts +1 -1
- package/src/lib/utils/package-utils.ts +10 -0
- package/src/main.tsx +0 -3
- package/src/pages/dashboard.tsx +12 -2
- package/src/pages/dev-login.tsx +2 -2
- package/src/pages/latest.tsx +2 -2
- package/src/pages/search.tsx +2 -2
- package/src/pages/trending.tsx +2 -2
- package/src/pages/user-profile.tsx +2 -2
- package/src/types/package.ts +4 -0
- package/vite.config.ts +0 -19
- package/src/build-watcher.ts +0 -52
- package/src/global.d.ts +0 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useState, useCallback } from "react"
|
|
2
2
|
import { Button } from "@/components/ui/button"
|
|
3
3
|
import { handleManualEditsImportWithSupportForMultipleFiles } from "@/lib/handleManualEditsImportWithSupportForMultipleFiles"
|
|
4
|
-
import {
|
|
4
|
+
import { useImportComponentDialog } from "@/components/dialogs/import-component-dialog"
|
|
5
5
|
import { useToast } from "@/hooks/use-toast"
|
|
6
6
|
import {
|
|
7
7
|
DropdownMenu,
|
|
@@ -19,13 +19,16 @@ import {
|
|
|
19
19
|
SelectValue,
|
|
20
20
|
} from "../ui/select"
|
|
21
21
|
import { isHiddenFile } from "../ViewPackagePage/utils/is-hidden-file"
|
|
22
|
-
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
23
22
|
import {
|
|
24
23
|
Tooltip,
|
|
25
24
|
TooltipContent,
|
|
26
25
|
TooltipProvider,
|
|
27
26
|
TooltipTrigger,
|
|
28
27
|
} from "@/components/ui/tooltip"
|
|
28
|
+
import { convertRawEasyToTsx, fetchEasyEDAComponent } from "easyeda/browser"
|
|
29
|
+
import { ComponentSearchResult } from "@tscircuit/runframe/runner"
|
|
30
|
+
import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
|
|
31
|
+
import { ICreateFileProps, ICreateFileResult } from "@/hooks/useFileManagement"
|
|
29
32
|
|
|
30
33
|
export type FileName = string
|
|
31
34
|
|
|
@@ -36,21 +39,28 @@ interface CodeEditorHeaderProps {
|
|
|
36
39
|
fileSidebarState: ReturnType<typeof useState<boolean>>
|
|
37
40
|
handleFileChange: (filename: FileName) => void
|
|
38
41
|
entrypointFileName?: string
|
|
42
|
+
appendNewFile: (path: string, content: string) => void
|
|
43
|
+
createFile: (props: ICreateFileProps) => ICreateFileResult
|
|
44
|
+
aiAutocompleteState: [boolean, React.Dispatch<React.SetStateAction<boolean>>]
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
42
48
|
currentFile,
|
|
43
49
|
files,
|
|
44
50
|
updateFileContent,
|
|
51
|
+
appendNewFile,
|
|
45
52
|
fileSidebarState,
|
|
46
53
|
handleFileChange,
|
|
47
54
|
entrypointFileName = "index.tsx",
|
|
55
|
+
createFile,
|
|
56
|
+
aiAutocompleteState,
|
|
48
57
|
}) => {
|
|
49
|
-
const { Dialog:
|
|
50
|
-
|
|
51
|
-
const { toast } = useToast()
|
|
58
|
+
const { Dialog: ImportComponentDialog, openDialog: openImportDialog } =
|
|
59
|
+
useImportComponentDialog()
|
|
60
|
+
const { toast, toastLibrary } = useToast()
|
|
52
61
|
const [sidebarOpen, setSidebarOpen] = fileSidebarState
|
|
53
|
-
const
|
|
62
|
+
const API_BASE = usePackagesBaseApiUrl()
|
|
63
|
+
const [aiAutocompleteEnabled, setAiAutocompleteEnabled] = aiAutocompleteState
|
|
54
64
|
|
|
55
65
|
const handleFormatFile = useCallback(() => {
|
|
56
66
|
if (!window.prettier || !window.prettierPlugins) return
|
|
@@ -141,6 +151,49 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
141
151
|
}
|
|
142
152
|
}, [currentFile, files, toast, updateFileContent])
|
|
143
153
|
|
|
154
|
+
const handleComponentImport = async (component: ComponentSearchResult) => {
|
|
155
|
+
if (component.source == "tscircuit.com") {
|
|
156
|
+
const newContent = `import {} from "@tsci/${component.owner}.${component.name}"\n${files[currentFile || ""]}`
|
|
157
|
+
updateFileContent(currentFile, newContent)
|
|
158
|
+
}
|
|
159
|
+
if (component.source == "jlcpcb") {
|
|
160
|
+
const jlcpcbComponent = await fetchEasyEDAComponent("C1", {
|
|
161
|
+
fetch: ((url, options: any) => {
|
|
162
|
+
return fetch(`${API_BASE}/proxy`, {
|
|
163
|
+
...options,
|
|
164
|
+
headers: {
|
|
165
|
+
...options?.headers,
|
|
166
|
+
"X-Target-Url": url.toString(),
|
|
167
|
+
"X-Sender-Origin": options?.headers?.origin ?? "",
|
|
168
|
+
"X-Sender-Host": options?.headers?.host ?? "https://easyeda.com",
|
|
169
|
+
"X-Sender-Referer": options?.headers?.referer ?? "",
|
|
170
|
+
"X-Sender-User-Agent": options?.headers?.userAgent ?? "",
|
|
171
|
+
"X-Sender-Cookie": options?.headers?.cookie ?? "",
|
|
172
|
+
},
|
|
173
|
+
})
|
|
174
|
+
}) as typeof fetch,
|
|
175
|
+
})
|
|
176
|
+
const tsxComponent = await convertRawEasyToTsx(jlcpcbComponent)
|
|
177
|
+
let componentName = component.name.replace(/ /g, "-")
|
|
178
|
+
if (files[`${componentName}.tsx`] || files[`./${componentName}.tsx`]) {
|
|
179
|
+
componentName = `${componentName}-1`
|
|
180
|
+
}
|
|
181
|
+
const createFileResult = createFile({
|
|
182
|
+
newFileName: `${componentName}.tsx`,
|
|
183
|
+
content: tsxComponent,
|
|
184
|
+
onError: (error) => {
|
|
185
|
+
throw error
|
|
186
|
+
},
|
|
187
|
+
openFile: false,
|
|
188
|
+
})
|
|
189
|
+
if (!createFileResult.newFileCreated) {
|
|
190
|
+
throw new Error("Failed to create file")
|
|
191
|
+
}
|
|
192
|
+
const newContent = `import ${componentName.replace(/-/g, "")} from "./${componentName}.tsx"\n${files[currentFile || ""]}`
|
|
193
|
+
updateFileContent(currentFile, newContent)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
144
197
|
return (
|
|
145
198
|
<>
|
|
146
199
|
<div className="flex items-center gap-2 px-2 border-b border-gray-200">
|
|
@@ -239,15 +292,16 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
239
292
|
</DropdownMenuContent>
|
|
240
293
|
</DropdownMenu>
|
|
241
294
|
)}
|
|
295
|
+
|
|
242
296
|
<TooltipProvider>
|
|
243
297
|
<Tooltip>
|
|
244
298
|
<TooltipTrigger asChild>
|
|
245
299
|
<Button
|
|
246
300
|
size="sm"
|
|
247
301
|
variant="ghost"
|
|
248
|
-
onClick={() =>
|
|
249
|
-
setAiAutocompleteEnabled(!
|
|
250
|
-
}
|
|
302
|
+
onClick={() => {
|
|
303
|
+
setAiAutocompleteEnabled((prev) => !prev)
|
|
304
|
+
}}
|
|
251
305
|
className={`relative bg-transparent ${aiAutocompleteEnabled ? "text-gray-600 bg-gray-50" : "text-gray-400"}`}
|
|
252
306
|
>
|
|
253
307
|
<Bot className="h-4 w-4" />
|
|
@@ -263,6 +317,7 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
263
317
|
</TooltipContent>
|
|
264
318
|
</Tooltip>
|
|
265
319
|
</TooltipProvider>
|
|
320
|
+
|
|
266
321
|
<Button size="sm" variant="ghost" onClick={() => openImportDialog()}>
|
|
267
322
|
Import
|
|
268
323
|
</Button>
|
|
@@ -270,10 +325,17 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
270
325
|
Format
|
|
271
326
|
</Button>
|
|
272
327
|
</div>
|
|
273
|
-
<
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
328
|
+
<ImportComponentDialog
|
|
329
|
+
onComponentSelected={async (component) => {
|
|
330
|
+
toastLibrary.promise(handleComponentImport(component), {
|
|
331
|
+
loading: "Importing component...",
|
|
332
|
+
success: <p>Component imported successfully!</p>,
|
|
333
|
+
error: (error) => (
|
|
334
|
+
<p>
|
|
335
|
+
Error importing component: {error.message || String(error)}
|
|
336
|
+
</p>
|
|
337
|
+
),
|
|
338
|
+
})
|
|
277
339
|
}}
|
|
278
340
|
/>
|
|
279
341
|
</div>
|
|
@@ -18,19 +18,16 @@ import { Package } from "fake-snippets-api/lib/db/schema"
|
|
|
18
18
|
import {
|
|
19
19
|
ChevronDown,
|
|
20
20
|
CodeIcon,
|
|
21
|
-
Download,
|
|
22
21
|
Edit2,
|
|
23
22
|
Eye,
|
|
24
23
|
EyeIcon,
|
|
25
24
|
File,
|
|
26
25
|
FilePenLine,
|
|
27
26
|
MoreVertical,
|
|
28
|
-
Package as PackageIcon,
|
|
29
27
|
Pencil,
|
|
30
28
|
Save,
|
|
31
29
|
Share,
|
|
32
30
|
Sidebar,
|
|
33
|
-
Sparkles,
|
|
34
31
|
Trash2,
|
|
35
32
|
Undo2,
|
|
36
33
|
} from "lucide-react"
|
|
@@ -41,7 +38,6 @@ import { useAxios } from "@/hooks/use-axios"
|
|
|
41
38
|
import { useHotkeyCombo } from "@/hooks/use-hotkey"
|
|
42
39
|
import { useToast } from "@/hooks/use-toast"
|
|
43
40
|
import { useConfirmDeletePackageDialog } from "@/components/dialogs/confirm-delete-package-dialog"
|
|
44
|
-
import { useFilesDialog } from "@/components/dialogs/files-dialog"
|
|
45
41
|
import { useViewTsFilesDialog } from "@/components/dialogs/view-ts-files-dialog"
|
|
46
42
|
import { DownloadButtonAndMenu } from "@/components/DownloadButtonAndMenu"
|
|
47
43
|
import { TypeBadge } from "@/components/TypeBadge"
|
|
@@ -86,7 +82,6 @@ export default function EditorNav({
|
|
|
86
82
|
} = useUpdatePackageDescriptionDialog()
|
|
87
83
|
const { Dialog: DeleteDialog, openDialog: openDeleteDialog } =
|
|
88
84
|
useConfirmDeletePackageDialog()
|
|
89
|
-
const { Dialog: FilesDialog, openDialog: openFilesDialog } = useFilesDialog()
|
|
90
85
|
const { Dialog: ViewTsFilesDialog, openDialog: openViewTsFilesDialog } =
|
|
91
86
|
useViewTsFilesDialog()
|
|
92
87
|
|
|
@@ -376,13 +371,6 @@ export default function EditorNav({
|
|
|
376
371
|
</Button>
|
|
377
372
|
</DropdownMenuTrigger>
|
|
378
373
|
<DropdownMenuContent>
|
|
379
|
-
<DropdownMenuItem
|
|
380
|
-
className="text-xs"
|
|
381
|
-
onClick={() => openFilesDialog()}
|
|
382
|
-
>
|
|
383
|
-
<File className="mr-2 h-3 w-3" />
|
|
384
|
-
View Files
|
|
385
|
-
</DropdownMenuItem>
|
|
386
374
|
<DropdownMenuItem
|
|
387
375
|
className="text-xs"
|
|
388
376
|
onClick={() => openupdateDescriptionDialog()}
|
|
@@ -395,62 +383,68 @@ export default function EditorNav({
|
|
|
395
383
|
onClick={() => openViewTsFilesDialog()}
|
|
396
384
|
>
|
|
397
385
|
<File className="mr-2 h-3 w-3" />
|
|
398
|
-
|
|
386
|
+
View Files
|
|
399
387
|
</DropdownMenuItem>
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
388
|
+
{session?.github_username === pkg.owner_github_username && (
|
|
389
|
+
<>
|
|
390
|
+
<DropdownMenuSub>
|
|
391
|
+
<DropdownMenuSubTrigger
|
|
392
|
+
className="text-xs"
|
|
393
|
+
disabled={isChangingType || hasUnsavedChanges}
|
|
394
|
+
>
|
|
395
|
+
<Edit2 className="mr-2 h-3 w-3" />
|
|
396
|
+
{isChangingType ? "Changing..." : "Change Type"}
|
|
397
|
+
</DropdownMenuSubTrigger>
|
|
398
|
+
<DropdownMenuSubContent>
|
|
399
|
+
<DropdownMenuItem
|
|
400
|
+
className="text-xs"
|
|
401
|
+
disabled={currentType === "board" || isChangingType}
|
|
402
|
+
onClick={() => handleTypeChange("board")}
|
|
403
|
+
>
|
|
404
|
+
Board {currentType === "board" && "✓"}
|
|
405
|
+
</DropdownMenuItem>
|
|
406
|
+
<DropdownMenuItem
|
|
407
|
+
className="text-xs"
|
|
408
|
+
disabled={currentType === "package" || isChangingType}
|
|
409
|
+
onClick={() => handleTypeChange("package")}
|
|
410
|
+
>
|
|
411
|
+
Module {currentType === "package" && "✓"}
|
|
412
|
+
</DropdownMenuItem>
|
|
413
|
+
</DropdownMenuSubContent>
|
|
414
|
+
</DropdownMenuSub>
|
|
415
|
+
<DropdownMenuSub>
|
|
416
|
+
<DropdownMenuSubTrigger className="text-xs">
|
|
417
|
+
<Edit2 className="mr-2 h-3 w-3" />
|
|
418
|
+
Change Package Visibility
|
|
419
|
+
</DropdownMenuSubTrigger>
|
|
420
|
+
<DropdownMenuSubContent>
|
|
421
|
+
<DropdownMenuItem
|
|
422
|
+
className="text-xs"
|
|
423
|
+
disabled={isPrivate}
|
|
424
|
+
onClick={() => updatePackageVisibilityToPrivate(true)}
|
|
425
|
+
>
|
|
426
|
+
Private {isPrivate && "✓"}
|
|
427
|
+
</DropdownMenuItem>
|
|
428
|
+
<DropdownMenuItem
|
|
429
|
+
className="text-xs"
|
|
430
|
+
disabled={!isPrivate}
|
|
431
|
+
onClick={() =>
|
|
432
|
+
updatePackageVisibilityToPrivate(false)
|
|
433
|
+
}
|
|
434
|
+
>
|
|
435
|
+
Public {!isPrivate && "✓"}
|
|
436
|
+
</DropdownMenuItem>
|
|
437
|
+
</DropdownMenuSubContent>
|
|
438
|
+
</DropdownMenuSub>
|
|
416
439
|
<DropdownMenuItem
|
|
417
|
-
className="text-xs"
|
|
418
|
-
|
|
419
|
-
onClick={() => handleTypeChange("package")}
|
|
440
|
+
className="text-xs text-red-600"
|
|
441
|
+
onClick={() => openDeleteDialog()}
|
|
420
442
|
>
|
|
421
|
-
|
|
443
|
+
<Trash2 className="mr-2 h-3 w-3" />
|
|
444
|
+
Delete Package
|
|
422
445
|
</DropdownMenuItem>
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
<DropdownMenuSub>
|
|
426
|
-
<DropdownMenuSubTrigger className="text-xs">
|
|
427
|
-
<Edit2 className="mr-2 h-3 w-3" />
|
|
428
|
-
Change Package Visibility
|
|
429
|
-
</DropdownMenuSubTrigger>
|
|
430
|
-
<DropdownMenuSubContent>
|
|
431
|
-
<DropdownMenuItem
|
|
432
|
-
className="text-xs"
|
|
433
|
-
disabled={isPrivate}
|
|
434
|
-
onClick={() => updatePackageVisibilityToPrivate(true)}
|
|
435
|
-
>
|
|
436
|
-
Private {isPrivate && "✓"}
|
|
437
|
-
</DropdownMenuItem>
|
|
438
|
-
<DropdownMenuItem
|
|
439
|
-
className="text-xs"
|
|
440
|
-
disabled={!isPrivate}
|
|
441
|
-
onClick={() => updatePackageVisibilityToPrivate(false)}
|
|
442
|
-
>
|
|
443
|
-
Public {!isPrivate && "✓"}
|
|
444
|
-
</DropdownMenuItem>
|
|
445
|
-
</DropdownMenuSubContent>
|
|
446
|
-
</DropdownMenuSub>
|
|
447
|
-
<DropdownMenuItem
|
|
448
|
-
className="text-xs text-red-600"
|
|
449
|
-
onClick={() => openDeleteDialog()}
|
|
450
|
-
>
|
|
451
|
-
<Trash2 className="mr-2 h-3 w-3" />
|
|
452
|
-
Delete Package
|
|
453
|
-
</DropdownMenuItem>
|
|
446
|
+
</>
|
|
447
|
+
)}
|
|
454
448
|
<DropdownMenuItem className="text-xs text-gray-500" disabled>
|
|
455
449
|
@tscircuit/core@{tscircuitCorePkg.version}
|
|
456
450
|
</DropdownMenuItem>
|
|
@@ -566,7 +560,6 @@ export default function EditorNav({
|
|
|
566
560
|
packageName={pkg?.unscoped_name ?? ""}
|
|
567
561
|
packageOwner={pkg?.owner_github_username ?? ""}
|
|
568
562
|
/>
|
|
569
|
-
<FilesDialog snippetId={pkg?.package_id ?? ""} />
|
|
570
563
|
<ViewTsFilesDialog />
|
|
571
564
|
</nav>
|
|
572
565
|
)
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
TooltipProvider,
|
|
24
24
|
TooltipTrigger,
|
|
25
25
|
} from "@/components/ui/tooltip"
|
|
26
|
-
import type { PackageFile } from "
|
|
26
|
+
import type { PackageFile } from "@/types/package"
|
|
27
27
|
import { isHiddenFile } from "../ViewPackagePage/utils/is-hidden-file"
|
|
28
28
|
|
|
29
29
|
interface Match {
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
BookOpen,
|
|
9
9
|
FileText,
|
|
10
10
|
} from "lucide-react"
|
|
11
|
-
import type { PackageFile } from "
|
|
11
|
+
import type { PackageFile } from "@/types/package"
|
|
12
12
|
import { fuzzyMatch } from "../ViewPackagePage/utils/fuzz-search"
|
|
13
13
|
|
|
14
14
|
interface ScoredFile extends PackageFile {
|
package/src/hooks/use-axios.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import axios from "redaxios"
|
|
2
2
|
import { useMemo } from "react"
|
|
3
|
-
import { useSnippetsBaseApiUrl } from "./use-snippets-base-api-url"
|
|
4
3
|
import { useGlobalStore } from "./use-global-store"
|
|
4
|
+
import { usePackagesBaseApiUrl } from "./use-packages-base-api-url"
|
|
5
5
|
|
|
6
6
|
export const useAxios = () => {
|
|
7
|
-
const snippetsBaseApiUrl =
|
|
7
|
+
const snippetsBaseApiUrl = usePackagesBaseApiUrl()
|
|
8
8
|
const session = useGlobalStore((s) => s.session)
|
|
9
9
|
return useMemo(() => {
|
|
10
10
|
const instance = axios.create({
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useMemo } from "react"
|
|
2
2
|
|
|
3
3
|
export const useCodeCompletionApi = () => {
|
|
4
|
-
const
|
|
4
|
+
const openrouterApiKey = useMemo(() => {
|
|
5
5
|
return {
|
|
6
|
-
apiKey: import.meta.env.
|
|
6
|
+
apiKey: import.meta.env.VITE_OPENROUTER_API_KEY,
|
|
7
7
|
}
|
|
8
8
|
}, [])
|
|
9
9
|
|
|
10
|
-
return
|
|
10
|
+
return openrouterApiKey
|
|
11
11
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useMutation } from "react-query"
|
|
1
|
+
import { useMutation, useQueryClient } from "react-query"
|
|
2
2
|
import { useAxios } from "./use-axios"
|
|
3
3
|
import { useToast } from "./use-toast"
|
|
4
4
|
|
|
@@ -7,6 +7,7 @@ export const useDeletePackage = ({
|
|
|
7
7
|
}: { onSuccess?: () => void } = {}) => {
|
|
8
8
|
const axios = useAxios()
|
|
9
9
|
const { toast } = useToast()
|
|
10
|
+
const queryClient = useQueryClient()
|
|
10
11
|
|
|
11
12
|
return useMutation(
|
|
12
13
|
["deletePackage"],
|
|
@@ -22,11 +23,14 @@ export const useDeletePackage = ({
|
|
|
22
23
|
return response.data
|
|
23
24
|
},
|
|
24
25
|
{
|
|
25
|
-
onSuccess: () => {
|
|
26
|
+
onSuccess: (_, variables) => {
|
|
26
27
|
toast({
|
|
27
28
|
title: "Package deleted",
|
|
28
29
|
description: "Package deleted successfully",
|
|
29
30
|
})
|
|
31
|
+
if (variables?.package_id) {
|
|
32
|
+
queryClient.invalidateQueries(["packages", variables.package_id])
|
|
33
|
+
}
|
|
30
34
|
onSuccess?.()
|
|
31
35
|
},
|
|
32
36
|
onError: (error: any) => {
|
|
@@ -34,7 +34,7 @@ export const useRequestAiReviewMutation = ({
|
|
|
34
34
|
onSuccess: ({ package_release, ai_review }) => {
|
|
35
35
|
toast({
|
|
36
36
|
title: "AI review requested",
|
|
37
|
-
description: "An AI review has been
|
|
37
|
+
description: "An AI review has been requested.",
|
|
38
38
|
})
|
|
39
39
|
queryClient.invalidateQueries(["packageRelease"])
|
|
40
40
|
onSuccess?.(package_release, ai_review)
|
package/src/hooks/use-sign-in.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useGlobalStore } from "./use-global-store"
|
|
2
2
|
import { useIsUsingFakeApi } from "./use-is-using-fake-api"
|
|
3
|
-
import {
|
|
3
|
+
import { usePackagesBaseApiUrl } from "./use-packages-base-api-url"
|
|
4
4
|
|
|
5
5
|
export const useSignIn = () => {
|
|
6
|
-
const snippetsBaseApiUrl =
|
|
6
|
+
const snippetsBaseApiUrl = usePackagesBaseApiUrl()
|
|
7
7
|
const isUsingFakeApi = useIsUsingFakeApi()
|
|
8
8
|
const setSession = useGlobalStore((s) => s.setSession)
|
|
9
9
|
return () => {
|
package/src/hooks/use-toast.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useEffect, useMemo, useState, useCallback, useRef } from "react"
|
|
2
2
|
import { isValidFileName } from "@/lib/utils/isValidFileName"
|
|
3
|
+
import { PackageFile } from "@/types/package"
|
|
3
4
|
import {
|
|
4
5
|
DEFAULT_CODE,
|
|
5
6
|
generateRandomPackageName,
|
|
6
|
-
|
|
7
|
-
} from "../components/package-port/CodeAndPreview"
|
|
7
|
+
} from "@/lib/utils/package-utils"
|
|
8
8
|
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
9
9
|
import { usePackageFiles } from "./use-package-files"
|
|
10
10
|
import { decodeUrlHashToText } from "@/lib/decodeUrlHashToText"
|
|
@@ -20,7 +20,9 @@ import { encodeFsMapToUrlHash } from "@/lib/encodeFsMapToUrlHash"
|
|
|
20
20
|
|
|
21
21
|
export interface ICreateFileProps {
|
|
22
22
|
newFileName: string
|
|
23
|
+
content?: string
|
|
23
24
|
onError: (error: Error) => void
|
|
25
|
+
openFile?: boolean
|
|
24
26
|
}
|
|
25
27
|
export interface ICreateFileResult {
|
|
26
28
|
newFileCreated: boolean
|
|
@@ -182,6 +184,8 @@ export function useFileManagement({
|
|
|
182
184
|
const createFile = ({
|
|
183
185
|
newFileName,
|
|
184
186
|
onError,
|
|
187
|
+
content,
|
|
188
|
+
openFile = true,
|
|
185
189
|
}: ICreateFileProps): ICreateFileResult => {
|
|
186
190
|
newFileName = newFileName.trim()
|
|
187
191
|
if (!newFileName) {
|
|
@@ -206,11 +210,12 @@ export function useFileManagement({
|
|
|
206
210
|
}
|
|
207
211
|
const updatedFiles = [
|
|
208
212
|
...(localFiles || []),
|
|
209
|
-
{ path: newFileName, content: "" },
|
|
213
|
+
{ path: newFileName, content: content || "" },
|
|
210
214
|
]
|
|
211
215
|
setLocalFiles(updatedFiles)
|
|
212
|
-
|
|
213
|
-
|
|
216
|
+
if (openFile) {
|
|
217
|
+
setCurrentFile(newFileName)
|
|
218
|
+
}
|
|
214
219
|
return {
|
|
215
220
|
newFileCreated: true,
|
|
216
221
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const DEFAULT_CODE = `
|
|
2
|
+
export default () => (
|
|
3
|
+
<board width="10mm" height="10mm">
|
|
4
|
+
{/* write your code here! */}
|
|
5
|
+
</board>
|
|
6
|
+
)
|
|
7
|
+
`.trim()
|
|
8
|
+
|
|
9
|
+
export const generateRandomPackageName = () =>
|
|
10
|
+
`untitled-package-${Math.floor(Math.random() * 900) + 100}`
|
package/src/main.tsx
CHANGED
|
@@ -6,9 +6,6 @@ if (typeof window !== "undefined" && !window.__APP_LOADED_AT) {
|
|
|
6
6
|
window.__APP_LOADED_AT = Date.now()
|
|
7
7
|
}
|
|
8
8
|
import "./index.css"
|
|
9
|
-
import { setupBuildWatcher } from "./build-watcher"
|
|
10
|
-
|
|
11
|
-
setupBuildWatcher()
|
|
12
9
|
|
|
13
10
|
createRoot(document.getElementById("root")!).render(
|
|
14
11
|
<StrictMode>
|
package/src/pages/dashboard.tsx
CHANGED
|
@@ -12,7 +12,7 @@ import { PrefetchPageLink } from "@/components/PrefetchPageLink"
|
|
|
12
12
|
import { PackagesList } from "@/components/PackagesList"
|
|
13
13
|
import { Helmet } from "react-helmet-async"
|
|
14
14
|
import { useSignIn } from "@/hooks/use-sign-in"
|
|
15
|
-
import {
|
|
15
|
+
import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
|
|
16
16
|
import { useConfirmDeletePackageDialog } from "@/components/dialogs/confirm-delete-package-dialog"
|
|
17
17
|
import { PackageCardSkeleton } from "@/components/PackageCardSkeleton"
|
|
18
18
|
import { PackageCard } from "@/components/PackageCard"
|
|
@@ -61,6 +61,11 @@ export const DashboardPage = () => {
|
|
|
61
61
|
const response = await axios.get("/packages/list_trending")
|
|
62
62
|
return response.data.packages
|
|
63
63
|
},
|
|
64
|
+
{
|
|
65
|
+
refetchOnWindowFocus: false,
|
|
66
|
+
refetchOnMount: false,
|
|
67
|
+
refetchOnReconnect: false,
|
|
68
|
+
},
|
|
64
69
|
)
|
|
65
70
|
|
|
66
71
|
const { data: latestPackages } = useQuery<Package[]>(
|
|
@@ -69,9 +74,14 @@ export const DashboardPage = () => {
|
|
|
69
74
|
const response = await axios.get("/packages/list_latest")
|
|
70
75
|
return response.data.packages
|
|
71
76
|
},
|
|
77
|
+
{
|
|
78
|
+
refetchOnWindowFocus: false,
|
|
79
|
+
refetchOnMount: false,
|
|
80
|
+
refetchOnReconnect: false,
|
|
81
|
+
},
|
|
72
82
|
)
|
|
73
83
|
|
|
74
|
-
const baseUrl =
|
|
84
|
+
const baseUrl = usePackagesBaseApiUrl()
|
|
75
85
|
|
|
76
86
|
const handleDeleteClick = (e: React.MouseEvent, pkg: Package) => {
|
|
77
87
|
e.preventDefault() // Prevent navigation
|
package/src/pages/dev-login.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
2
|
-
import {
|
|
2
|
+
import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
|
|
3
3
|
import { useState } from "react"
|
|
4
4
|
import { useLocation } from "wouter"
|
|
5
5
|
|
|
6
6
|
export const DevLoginPage = () => {
|
|
7
|
-
const snippetsBaseApiUrl =
|
|
7
|
+
const snippetsBaseApiUrl = usePackagesBaseApiUrl()
|
|
8
8
|
const [username, setUsername] = useState("")
|
|
9
9
|
const setSession = useGlobalStore((s) => s.setSession)
|
|
10
10
|
const [, setLocation] = useLocation()
|
package/src/pages/latest.tsx
CHANGED
|
@@ -6,7 +6,7 @@ import Header from "@/components/Header"
|
|
|
6
6
|
import Footer from "@/components/Footer"
|
|
7
7
|
import { Search, Keyboard, Cpu, Layers, LucideBellElectric } from "lucide-react"
|
|
8
8
|
import { Input } from "@/components/ui/input"
|
|
9
|
-
import {
|
|
9
|
+
import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
|
|
10
10
|
import {
|
|
11
11
|
Select,
|
|
12
12
|
SelectContent,
|
|
@@ -18,7 +18,7 @@ import PackageSearchResults from "@/components/PackageSearchResults"
|
|
|
18
18
|
|
|
19
19
|
const LatestPage: React.FC = () => {
|
|
20
20
|
const axios = useAxios()
|
|
21
|
-
const apiBaseUrl =
|
|
21
|
+
const apiBaseUrl = usePackagesBaseApiUrl()
|
|
22
22
|
const [searchQuery, setSearchQuery] = useState("")
|
|
23
23
|
const [category, setCategory] = useState("all")
|
|
24
24
|
|
package/src/pages/search.tsx
CHANGED
|
@@ -7,7 +7,7 @@ import Footer from "@/components/Footer"
|
|
|
7
7
|
import { Input } from "@/components/ui/input"
|
|
8
8
|
import { Search } from "lucide-react"
|
|
9
9
|
import PackageSearchResults from "@/components/PackageSearchResults"
|
|
10
|
-
import {
|
|
10
|
+
import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
|
|
11
11
|
import {
|
|
12
12
|
Select,
|
|
13
13
|
SelectContent,
|
|
@@ -19,7 +19,7 @@ import { Package } from "fake-snippets-api/lib/db/schema"
|
|
|
19
19
|
|
|
20
20
|
export const SearchPage = () => {
|
|
21
21
|
const axios = useAxios()
|
|
22
|
-
const apiBaseUrl =
|
|
22
|
+
const apiBaseUrl = usePackagesBaseApiUrl()
|
|
23
23
|
const [searchParams, setSearchParams] = useSearchParams()
|
|
24
24
|
|
|
25
25
|
const [searchQuery, setSearchQuery] = useState(searchParams.get("q") || "")
|
package/src/pages/trending.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { useAxios } from "@/hooks/use-axios"
|
|
|
4
4
|
import Header from "@/components/Header"
|
|
5
5
|
import Footer from "@/components/Footer"
|
|
6
6
|
import { useSearchParams } from "wouter"
|
|
7
|
-
import {
|
|
7
|
+
import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
|
|
8
8
|
import { Search, Keyboard, Cpu, Layers, LucideBellElectric } from "lucide-react"
|
|
9
9
|
import { Input } from "@/components/ui/input"
|
|
10
10
|
import {
|
|
@@ -19,7 +19,7 @@ import PackageSearchResults from "@/components/PackageSearchResults"
|
|
|
19
19
|
|
|
20
20
|
const TrendingPage: React.FC = () => {
|
|
21
21
|
const axios = useAxios()
|
|
22
|
-
const apiBaseUrl =
|
|
22
|
+
const apiBaseUrl = usePackagesBaseApiUrl()
|
|
23
23
|
const [searchParams, setSearchParams] = useSearchParams()
|
|
24
24
|
|
|
25
25
|
const [searchQuery, setSearchQuery] = useState(searchParams.get("q") || "")
|
|
@@ -8,7 +8,7 @@ import { Input } from "@/components/ui/input"
|
|
|
8
8
|
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|
9
9
|
import { useAxios } from "@/hooks/use-axios"
|
|
10
10
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
11
|
-
import {
|
|
11
|
+
import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
|
|
12
12
|
import { GitHubLogoIcon } from "@radix-ui/react-icons"
|
|
13
13
|
import type { Package } from "fake-snippets-api/lib/db/schema"
|
|
14
14
|
import type React from "react"
|
|
@@ -95,7 +95,7 @@ export const UserProfilePage = () => {
|
|
|
95
95
|
},
|
|
96
96
|
)
|
|
97
97
|
|
|
98
|
-
const baseUrl =
|
|
98
|
+
const baseUrl = usePackagesBaseApiUrl()
|
|
99
99
|
|
|
100
100
|
if (accountError) {
|
|
101
101
|
return <NotFoundPage heading="User Not Found" />
|