@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
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
import { CodeEditor } from "@/components/CodeEditor"
|
|
2
|
-
import { usePackageVisibilitySettingsDialog } from "@/components/dialogs/package-visibility-settings-dialog"
|
|
3
|
-
import { useAxios } from "@/hooks/use-axios"
|
|
4
|
-
import { useCreateSnippetMutation } from "@/hooks/use-create-snippet-mutation"
|
|
5
|
-
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
6
|
-
import { useToast } from "@/hooks/use-toast"
|
|
7
|
-
import { useUrlParams } from "@/hooks/use-url-params"
|
|
8
|
-
import useWarnUserOnPageChange from "@/hooks/use-warn-user-on-page-change"
|
|
9
|
-
import { decodeUrlHashToText } from "@/lib/decodeUrlHashToText"
|
|
10
|
-
import { getSnippetTemplate } from "@/lib/get-snippet-template"
|
|
11
|
-
import { cn } from "@/lib/utils"
|
|
12
|
-
import { parseJsonOrNull } from "@/lib/utils/parseJsonOrNull"
|
|
13
|
-
import type { Snippet } from "fake-snippets-api/lib/db/schema"
|
|
14
|
-
import { Loader2 } from "lucide-react"
|
|
15
|
-
import { useEffect, useMemo, useState } from "react"
|
|
16
|
-
import { useMutation, useQueryClient } from "react-query"
|
|
17
|
-
import EditorNav from "./EditorNav"
|
|
18
|
-
import { SuspenseRunFrame } from "./SuspenseRunFrame"
|
|
19
|
-
import { applyEditEventsToManualEditsFile } from "@tscircuit/core"
|
|
20
|
-
|
|
21
|
-
interface Props {
|
|
22
|
-
snippet?: Snippet | null
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function CodeAndPreview({ snippet }: Props) {
|
|
26
|
-
const axios = useAxios()
|
|
27
|
-
const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
|
|
28
|
-
const urlParams = useUrlParams()
|
|
29
|
-
const templateFromUrl = useMemo(
|
|
30
|
-
() => (urlParams.template ? getSnippetTemplate(urlParams.template) : null),
|
|
31
|
-
[],
|
|
32
|
-
)
|
|
33
|
-
const defaultCode = useMemo(() => {
|
|
34
|
-
return (
|
|
35
|
-
decodeUrlHashToText(window.location.toString()) ??
|
|
36
|
-
snippet?.code ??
|
|
37
|
-
// If the snippet_id is in the url, use an empty string as the default
|
|
38
|
-
// code until the snippet code is loaded
|
|
39
|
-
(urlParams.snippet_id && "") ??
|
|
40
|
-
templateFromUrl?.code
|
|
41
|
-
)
|
|
42
|
-
}, [])
|
|
43
|
-
|
|
44
|
-
// Initialize with template or snippet's manual edits if available
|
|
45
|
-
const [manualEditsFileContent, setManualEditsFileContent] = useState<
|
|
46
|
-
string | null
|
|
47
|
-
>(null)
|
|
48
|
-
const [code, setCode] = useState(defaultCode ?? "")
|
|
49
|
-
const [dts, setDts] = useState("")
|
|
50
|
-
const [showPreview, setShowPreview] = useState(true)
|
|
51
|
-
const [lastRunCode, setLastRunCode] = useState(defaultCode ?? "")
|
|
52
|
-
const [fullScreen, setFullScreen] = useState(false)
|
|
53
|
-
const [circuitJson, setCircuitJson] = useState<any>(null)
|
|
54
|
-
const {
|
|
55
|
-
Dialog: PackageVisibilitySettingsDialog,
|
|
56
|
-
openDialog: openPackageVisibilitySettingsDialog,
|
|
57
|
-
} = usePackageVisibilitySettingsDialog()
|
|
58
|
-
const [isPrivate, setIsPrivate] = useState(false)
|
|
59
|
-
|
|
60
|
-
const snippetType: "board" | "package" | "model" | "footprint" =
|
|
61
|
-
snippet?.snippet_type ??
|
|
62
|
-
(templateFromUrl?.type as any) ??
|
|
63
|
-
urlParams.snippet_type
|
|
64
|
-
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
if (snippet?.code) {
|
|
67
|
-
setCode(snippet.code)
|
|
68
|
-
setLastRunCode(snippet.code)
|
|
69
|
-
}
|
|
70
|
-
}, [Boolean(snippet)])
|
|
71
|
-
|
|
72
|
-
const { toast } = useToast()
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (snippet?.manual_edits_json_content) {
|
|
76
|
-
setManualEditsFileContent(snippet.manual_edits_json_content ?? "")
|
|
77
|
-
}
|
|
78
|
-
}, [Boolean(snippet?.manual_edits_json_content)])
|
|
79
|
-
|
|
80
|
-
const userImports = useMemo(
|
|
81
|
-
() => ({
|
|
82
|
-
"./manual-edits.json": parseJsonOrNull(manualEditsFileContent) ?? "",
|
|
83
|
-
}),
|
|
84
|
-
[manualEditsFileContent],
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
const qc = useQueryClient()
|
|
88
|
-
|
|
89
|
-
const updateSnippetMutation = useMutation({
|
|
90
|
-
mutationFn: async () => {
|
|
91
|
-
if (!snippet) throw new Error("No snippet to update")
|
|
92
|
-
|
|
93
|
-
const updateSnippetPayload = {
|
|
94
|
-
snippet_id: snippet.snippet_id,
|
|
95
|
-
code: code,
|
|
96
|
-
dts: dts,
|
|
97
|
-
// compiled_js: compiledJs,
|
|
98
|
-
circuit_json: circuitJson,
|
|
99
|
-
manual_edits_json_content: manualEditsFileContent,
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
const response = await axios.post(
|
|
104
|
-
"/snippets/update",
|
|
105
|
-
updateSnippetPayload,
|
|
106
|
-
)
|
|
107
|
-
return response.data
|
|
108
|
-
} catch (error: any) {
|
|
109
|
-
const responseStatus = error?.status ?? error?.response?.status
|
|
110
|
-
// We would normally only do this if the error is a 413, but we're not
|
|
111
|
-
// able to check the status properly because of the browser CORS policy
|
|
112
|
-
// (the PAYLOAD_TOO_LARGE error does not have the proper CORS headers)
|
|
113
|
-
if (
|
|
114
|
-
import.meta.env.VITE_ALTERNATE_REGISTRY_URL &&
|
|
115
|
-
(responseStatus === undefined || responseStatus === 413)
|
|
116
|
-
) {
|
|
117
|
-
console.log(`Failed to update snippet, attempting alternate registry`)
|
|
118
|
-
const response = await axios.post(
|
|
119
|
-
`${import.meta.env.VITE_ALTERNATE_REGISTRY_URL}/snippets/update`,
|
|
120
|
-
updateSnippetPayload,
|
|
121
|
-
)
|
|
122
|
-
return response.data
|
|
123
|
-
}
|
|
124
|
-
throw error
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
onSuccess: () => {
|
|
128
|
-
qc.invalidateQueries({ queryKey: ["snippets", snippet?.snippet_id] })
|
|
129
|
-
toast({
|
|
130
|
-
title: "Snippet saved",
|
|
131
|
-
description: "Your changes have been saved successfully.",
|
|
132
|
-
})
|
|
133
|
-
},
|
|
134
|
-
onError: (error) => {
|
|
135
|
-
console.error("Error saving snippet:", error)
|
|
136
|
-
toast({
|
|
137
|
-
title: "Error",
|
|
138
|
-
description:
|
|
139
|
-
error instanceof Error
|
|
140
|
-
? error.message
|
|
141
|
-
: "Failed to save the snippet. Please try again.",
|
|
142
|
-
variant: "destructive",
|
|
143
|
-
})
|
|
144
|
-
},
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
const createSnippetMutation = useCreateSnippetMutation()
|
|
148
|
-
const [lastSavedAt, setLastSavedAt] = useState(Date.now())
|
|
149
|
-
|
|
150
|
-
const handleSave = async () => {
|
|
151
|
-
if (hasUnrunChanges) {
|
|
152
|
-
toast({
|
|
153
|
-
title: "Warning",
|
|
154
|
-
description: "You must run the snippet before saving your changes.",
|
|
155
|
-
variant: "destructive",
|
|
156
|
-
})
|
|
157
|
-
return
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (!snippet && isLoggedIn) {
|
|
161
|
-
openPackageVisibilitySettingsDialog()
|
|
162
|
-
return
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
setLastSavedAt(Date.now())
|
|
166
|
-
if (snippet) {
|
|
167
|
-
updateSnippetMutation.mutate()
|
|
168
|
-
} else {
|
|
169
|
-
createSnippetMutation.mutate({
|
|
170
|
-
code,
|
|
171
|
-
circuit_json: circuitJson as any,
|
|
172
|
-
manual_edits_json_content: manualEditsFileContent ?? "",
|
|
173
|
-
})
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const hasManualEditsChanged =
|
|
178
|
-
(snippet?.manual_edits_json_content ?? "") !==
|
|
179
|
-
(manualEditsFileContent ?? "")
|
|
180
|
-
|
|
181
|
-
const hasUnsavedChanges =
|
|
182
|
-
!updateSnippetMutation.isLoading &&
|
|
183
|
-
Date.now() - lastSavedAt > 1000 &&
|
|
184
|
-
(snippet?.code !== code || hasManualEditsChanged)
|
|
185
|
-
|
|
186
|
-
const hasUnrunChanges = code !== lastRunCode
|
|
187
|
-
|
|
188
|
-
useWarnUserOnPageChange({ hasUnsavedChanges })
|
|
189
|
-
|
|
190
|
-
const fsMap = useMemo(() => {
|
|
191
|
-
return {
|
|
192
|
-
"index.tsx": code,
|
|
193
|
-
"manual-edits.json": manualEditsFileContent || "",
|
|
194
|
-
}
|
|
195
|
-
}, [code, manualEditsFileContent])
|
|
196
|
-
|
|
197
|
-
if (!snippet && (urlParams.snippet_id || urlParams.should_create_snippet)) {
|
|
198
|
-
return (
|
|
199
|
-
<div className="flex items-center justify-center h-64">
|
|
200
|
-
<div className="flex flex-col items-center justify-center">
|
|
201
|
-
<div className="text-lg text-gray-500 mb-4">Loading</div>
|
|
202
|
-
<Loader2 className="w-16 h-16 animate-spin text-gray-400" />
|
|
203
|
-
</div>
|
|
204
|
-
</div>
|
|
205
|
-
)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return (
|
|
209
|
-
<div className="flex flex-col">
|
|
210
|
-
<EditorNav
|
|
211
|
-
circuitJson={circuitJson}
|
|
212
|
-
snippet={snippet}
|
|
213
|
-
snippetType={snippetType}
|
|
214
|
-
code={code}
|
|
215
|
-
isSaving={updateSnippetMutation.isLoading}
|
|
216
|
-
hasUnsavedChanges={hasUnsavedChanges}
|
|
217
|
-
onSave={() => handleSave()}
|
|
218
|
-
onTogglePreview={() => setShowPreview(!showPreview)}
|
|
219
|
-
previewOpen={showPreview}
|
|
220
|
-
canSave={!hasUnrunChanges} // Disable save if there are unrun changes
|
|
221
|
-
/>
|
|
222
|
-
<div className={`flex ${showPreview ? "flex-col md:flex-row" : ""}`}>
|
|
223
|
-
<div
|
|
224
|
-
className={cn(
|
|
225
|
-
"hidden flex-col md:flex border-r border-gray-200 bg-gray-50",
|
|
226
|
-
showPreview ? "w-full md:w-1/2" : "w-full flex",
|
|
227
|
-
)}
|
|
228
|
-
>
|
|
229
|
-
<CodeEditor
|
|
230
|
-
initialCode={code}
|
|
231
|
-
manualEditsFileContent={manualEditsFileContent ?? ""}
|
|
232
|
-
onManualEditsFileContentChanged={(newContent) => {
|
|
233
|
-
setManualEditsFileContent(newContent)
|
|
234
|
-
}}
|
|
235
|
-
onCodeChange={(newCode) => {
|
|
236
|
-
setCode(newCode)
|
|
237
|
-
}}
|
|
238
|
-
onDtsChange={(newDts) => setDts(newDts)}
|
|
239
|
-
/>
|
|
240
|
-
</div>
|
|
241
|
-
{showPreview && (
|
|
242
|
-
<div
|
|
243
|
-
className={cn(
|
|
244
|
-
"flex p-0 flex-col min-h-[640px]",
|
|
245
|
-
fullScreen
|
|
246
|
-
? "fixed inset-0 z-50 bg-white p-4 overflow-hidden"
|
|
247
|
-
: "w-full md:w-1/2",
|
|
248
|
-
)}
|
|
249
|
-
>
|
|
250
|
-
<SuspenseRunFrame
|
|
251
|
-
showRunButton
|
|
252
|
-
forceLatestEvalVersion
|
|
253
|
-
onRenderStarted={() => {
|
|
254
|
-
setLastRunCode(code)
|
|
255
|
-
}}
|
|
256
|
-
onRenderFinished={({ circuitJson }) => {
|
|
257
|
-
setCircuitJson(circuitJson)
|
|
258
|
-
}}
|
|
259
|
-
onEditEvent={(event) => {
|
|
260
|
-
const newManualEditsFileContent =
|
|
261
|
-
applyEditEventsToManualEditsFile({
|
|
262
|
-
circuitJson: circuitJson,
|
|
263
|
-
editEvents: [event],
|
|
264
|
-
manualEditsFile: JSON.parse(manualEditsFileContent ?? "{}"),
|
|
265
|
-
})
|
|
266
|
-
setManualEditsFileContent(
|
|
267
|
-
JSON.stringify(newManualEditsFileContent, null, 2),
|
|
268
|
-
)
|
|
269
|
-
}}
|
|
270
|
-
fsMap={fsMap}
|
|
271
|
-
/>
|
|
272
|
-
</div>
|
|
273
|
-
)}
|
|
274
|
-
</div>
|
|
275
|
-
<PackageVisibilitySettingsDialog
|
|
276
|
-
initialIsPrivate={false}
|
|
277
|
-
onSave={(isPrivate: boolean) => {
|
|
278
|
-
setLastSavedAt(Date.now())
|
|
279
|
-
createSnippetMutation.mutate({
|
|
280
|
-
code,
|
|
281
|
-
circuit_json: circuitJson as any,
|
|
282
|
-
manual_edits_json_content: manualEditsFileContent ?? "",
|
|
283
|
-
is_private: isPrivate,
|
|
284
|
-
})
|
|
285
|
-
}}
|
|
286
|
-
/>
|
|
287
|
-
</div>
|
|
288
|
-
)
|
|
289
|
-
}
|