@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.
Files changed (89) hide show
  1. package/bun-tests/fake-snippets-api/fixtures/get-circuit-json.ts +5 -143
  2. package/bun-tests/fake-snippets-api/fixtures/get-test-server.ts +1 -4
  3. package/bun-tests/fake-snippets-api/fixtures/start-server.ts +7 -3
  4. package/bun-tests/fake-snippets-api/routes/order_quotes/create.test.ts +20 -56
  5. package/bun-tests/fake-snippets-api/routes/package_files/create_or_update.test.ts +2 -2
  6. package/bun-tests/fake-snippets-api/routes/package_releases/update.test.ts +1 -1
  7. package/bun-tests/fake-snippets-api/routes/packages/images.test.ts +0 -11
  8. package/bun.lock +26 -75
  9. package/dist/bundle.js +32 -39
  10. package/fake-snippets-api/routes/api/order_quotes/create.ts +30 -37
  11. package/fake-snippets-api/routes/api/order_quotes/get.ts +5 -8
  12. package/package.json +4 -4
  13. package/src/App.tsx +0 -11
  14. package/src/ContextProviders.tsx +2 -0
  15. package/src/components/CmdKMenu.tsx +19 -19
  16. package/src/components/DownloadButtonAndMenu.tsx +1 -4
  17. package/src/components/FAQ.tsx +3 -1
  18. package/src/components/FileSidebar.tsx +50 -1
  19. package/src/components/Footer.tsx +5 -2
  20. package/src/components/Header2.tsx +20 -9
  21. package/src/components/HeaderLogin.tsx +37 -54
  22. package/src/components/ImageWithFallback.tsx +37 -0
  23. package/src/components/JLCPCBImportDialog.tsx +45 -29
  24. package/src/components/PackageCard.tsx +2 -2
  25. package/src/components/{SnippetLink.tsx → PackageLink.tsx} +8 -16
  26. package/src/components/PackageSearchResults.tsx +87 -0
  27. package/src/components/PackagesList.tsx +3 -3
  28. package/src/components/PageSearchComponent.tsx +9 -9
  29. package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +5 -28
  30. package/src/components/ViewPackagePage/components/important-files-view.tsx +1 -1
  31. package/src/components/ViewPackagePage/components/main-content-header.tsx +8 -8
  32. package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +24 -14
  33. package/src/components/ViewPackagePage/components/package-header.tsx +7 -2
  34. package/src/components/dialogs/confirm-delete-package-dialog.tsx +8 -0
  35. package/src/components/dialogs/edit-package-details-dialog.tsx +145 -138
  36. package/src/components/package-port/CodeAndPreview.tsx +40 -19
  37. package/src/components/package-port/CodeEditor.tsx +21 -37
  38. package/src/components/package-port/CodeEditorHeader.tsx +1 -1
  39. package/src/components/package-port/EditorNav.tsx +3 -13
  40. package/src/hooks/use-global-store.ts +1 -0
  41. package/src/hooks/use-shiki-highlighter.ts +13 -6
  42. package/src/hooks/useFileManagement.ts +59 -0
  43. package/src/lib/download-fns/download-gltf.ts +3 -10
  44. package/src/lib/handleManualEditsImport.tsx +1 -1
  45. package/src/lib/types.ts +4 -2
  46. package/src/lib/utils/isValidFileName.ts +5 -0
  47. package/src/pages/dashboard.tsx +4 -4
  48. package/src/pages/editor.tsx +20 -14
  49. package/src/pages/latest.tsx +25 -26
  50. package/src/pages/quickstart.tsx +5 -5
  51. package/src/pages/search.tsx +121 -20
  52. package/src/pages/trending.tsx +14 -58
  53. package/src/pages/user-profile.tsx +14 -8
  54. package/bun-tests/fake-snippets-api/routes/snippets/add_star.test.ts +0 -84
  55. package/bun-tests/fake-snippets-api/routes/snippets/create.test.ts +0 -53
  56. package/bun-tests/fake-snippets-api/routes/snippets/delete.test.ts +0 -82
  57. package/bun-tests/fake-snippets-api/routes/snippets/download.test.ts +0 -90
  58. package/bun-tests/fake-snippets-api/routes/snippets/generate_from_jlcpcb.test.ts +0 -16
  59. package/bun-tests/fake-snippets-api/routes/snippets/get.test.ts +0 -163
  60. package/bun-tests/fake-snippets-api/routes/snippets/get_image.test.ts +0 -117
  61. package/bun-tests/fake-snippets-api/routes/snippets/images.test.ts +0 -114
  62. package/bun-tests/fake-snippets-api/routes/snippets/list.test.ts +0 -169
  63. package/bun-tests/fake-snippets-api/routes/snippets/list_newest.test.ts +0 -50
  64. package/bun-tests/fake-snippets-api/routes/snippets/list_trending.test.ts +0 -72
  65. package/bun-tests/fake-snippets-api/routes/snippets/remove_star.test.ts +0 -80
  66. package/bun-tests/fake-snippets-api/routes/snippets/search.test.ts +0 -75
  67. package/bun-tests/fake-snippets-api/routes/snippets/star-count.test.ts +0 -51
  68. package/bun-tests/fake-snippets-api/routes/snippets/update.test.ts +0 -175
  69. package/src/components/AiChatInterface.tsx +0 -229
  70. package/src/components/CodeAndPreview.tsx +0 -289
  71. package/src/components/CodeEditor.tsx +0 -539
  72. package/src/components/CodeEditorHeader.tsx +0 -135
  73. package/src/components/EditorNav.tsx +0 -502
  74. package/src/components/OrderPreviewContent.tsx +0 -61
  75. package/src/components/PreviewContent.tsx +0 -372
  76. package/src/components/SnippetCard.tsx +0 -159
  77. package/src/components/SnippetList.tsx +0 -71
  78. package/src/components/ViewSnippetSidebar.tsx +0 -162
  79. package/src/components/dialogs/create-order-dialog.tsx +0 -146
  80. package/src/hooks/use-compiled-tsx.ts +0 -37
  81. package/src/hooks/use-run-tsx/construct-circuit.tsx +0 -62
  82. package/src/hooks/use-run-tsx/index.tsx +0 -256
  83. package/src/hooks/use-save-snippet.ts +0 -66
  84. package/src/hooks/use-typecheck.ts +0 -54
  85. package/src/lib/utils/getSyntaxError.ts +0 -13
  86. package/src/pages/ai.tsx +0 -92
  87. package/src/pages/preview.tsx +0 -44
  88. package/src/pages/view-order.tsx +0 -111
  89. 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
- }