@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,66 +0,0 @@
|
|
|
1
|
-
import { Snippet } from "fake-snippets-api/lib/db/schema"
|
|
2
|
-
import { useMutation } from "react-query"
|
|
3
|
-
import { useAxios } from "./use-axios"
|
|
4
|
-
import { safeCompileTsx } from "./use-compiled-tsx"
|
|
5
|
-
import { useCurrentSnippetId } from "./use-current-snippet-id"
|
|
6
|
-
|
|
7
|
-
export const useSaveSnippet = () => {
|
|
8
|
-
const axios = useAxios()
|
|
9
|
-
|
|
10
|
-
const { snippetId } = useCurrentSnippetId()
|
|
11
|
-
|
|
12
|
-
const saveSnippetMutation = useMutation<
|
|
13
|
-
Snippet,
|
|
14
|
-
Error,
|
|
15
|
-
{ code: string; snippet_type: string; dts?: string; circuit_json?: any[] }
|
|
16
|
-
>({
|
|
17
|
-
mutationFn: async ({ code, snippet_type, dts, circuit_json }) => {
|
|
18
|
-
const compileResult = safeCompileTsx(code)
|
|
19
|
-
|
|
20
|
-
if (snippetId) {
|
|
21
|
-
const response = await axios.post("/snippets/update", {
|
|
22
|
-
snippet_id: snippetId,
|
|
23
|
-
code,
|
|
24
|
-
snippet_type,
|
|
25
|
-
compiled_js: compileResult.success
|
|
26
|
-
? compileResult.compiledTsx
|
|
27
|
-
: undefined,
|
|
28
|
-
circuit_json: circuit_json,
|
|
29
|
-
dts,
|
|
30
|
-
})
|
|
31
|
-
return response.data.snippet
|
|
32
|
-
} else {
|
|
33
|
-
const response = await axios.post("/snippets/create", {
|
|
34
|
-
code,
|
|
35
|
-
snippet_type,
|
|
36
|
-
owner_name: "seveibar", // Replace with actual user name or fetch from user context
|
|
37
|
-
compiled_js: compileResult.success
|
|
38
|
-
? compileResult.compiledTsx
|
|
39
|
-
: undefined,
|
|
40
|
-
dts,
|
|
41
|
-
})
|
|
42
|
-
return response.data.snippet
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
const saveSnippet = async (
|
|
48
|
-
code: string,
|
|
49
|
-
snippet_type: string,
|
|
50
|
-
dts?: string,
|
|
51
|
-
circuit_json?: any[],
|
|
52
|
-
) => {
|
|
53
|
-
return saveSnippetMutation.mutateAsync({
|
|
54
|
-
code,
|
|
55
|
-
snippet_type,
|
|
56
|
-
dts,
|
|
57
|
-
circuit_json,
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
saveSnippet,
|
|
63
|
-
isLoading: saveSnippetMutation.isLoading,
|
|
64
|
-
error: saveSnippetMutation.error,
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// import * as ts from "typescript"
|
|
2
|
-
|
|
3
|
-
// export function checkTypeScriptErrors(code: string): ts.Diagnostic[] {
|
|
4
|
-
// // Create a virtual TypeScript compiler
|
|
5
|
-
// const compilerOptions: ts.CompilerOptions = {
|
|
6
|
-
// noEmit: true,
|
|
7
|
-
// allowJs: true,
|
|
8
|
-
// checkJs: true,
|
|
9
|
-
// strict: true,
|
|
10
|
-
// }
|
|
11
|
-
|
|
12
|
-
// // Create a virtual file system
|
|
13
|
-
// const fileSystem = {
|
|
14
|
-
// "example.ts": code,
|
|
15
|
-
// }
|
|
16
|
-
|
|
17
|
-
// // Create a compiler host
|
|
18
|
-
// const compilerHost = ts.createCompilerHost(compilerOptions)
|
|
19
|
-
// compilerHost.getSourceFile = (fileName: string) => {
|
|
20
|
-
// return ts.createSourceFile(
|
|
21
|
-
// fileName,
|
|
22
|
-
// fileSystem[fileName] || "",
|
|
23
|
-
// ts.ScriptTarget.Latest,
|
|
24
|
-
// )
|
|
25
|
-
// }
|
|
26
|
-
// compilerHost.writeFile = () => {}
|
|
27
|
-
// compilerHost.getCurrentDirectory = () => "/"
|
|
28
|
-
// compilerHost.getDefaultLibFileName = () => "lib.d.ts"
|
|
29
|
-
|
|
30
|
-
// // Create a program
|
|
31
|
-
// const program = ts.createProgram(
|
|
32
|
-
// ["example.ts"],
|
|
33
|
-
// compilerOptions,
|
|
34
|
-
// compilerHost,
|
|
35
|
-
// )
|
|
36
|
-
|
|
37
|
-
// // Get the diagnostics (errors)
|
|
38
|
-
// const diagnostics = ts.getPreEmitDiagnostics(program)
|
|
39
|
-
|
|
40
|
-
// return diagnostics
|
|
41
|
-
// }
|
|
42
|
-
|
|
43
|
-
// // Example usage
|
|
44
|
-
// const code = `
|
|
45
|
-
// let x: number = "string"; // Type error
|
|
46
|
-
// let y: string = 5; // Another type error
|
|
47
|
-
// let z: number = 10; // No error
|
|
48
|
-
// `
|
|
49
|
-
|
|
50
|
-
// const errors = checkTypeScriptErrors(code)
|
|
51
|
-
// console.log("Errors found:", errors.length)
|
|
52
|
-
// errors.forEach((error) => {
|
|
53
|
-
// console.log(`Error on line ${error.start}: ${error.messageText}`)
|
|
54
|
-
// })
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import * as Babel from "@babel/standalone"
|
|
2
|
-
|
|
3
|
-
export function getSyntaxError(code: string): string | null {
|
|
4
|
-
try {
|
|
5
|
-
Babel.transform(code, {
|
|
6
|
-
filename: "index.tsx",
|
|
7
|
-
presets: ["react", "typescript"],
|
|
8
|
-
})
|
|
9
|
-
return null
|
|
10
|
-
} catch (error: unknown) {
|
|
11
|
-
return (error as Error).message
|
|
12
|
-
}
|
|
13
|
-
}
|
package/src/pages/ai.tsx
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import AIChatInterface from "@/components/AiChatInterface"
|
|
2
|
-
import Header from "@/components/Header"
|
|
3
|
-
import { PreviewContent } from "@/components/PreviewContent"
|
|
4
|
-
import { useRunTsx } from "@/hooks/use-run-tsx"
|
|
5
|
-
import { useSaveSnippet } from "@/hooks/use-save-snippet"
|
|
6
|
-
import { useSnippet } from "@/hooks/use-snippet"
|
|
7
|
-
import { useToast } from "@/hooks/use-toast"
|
|
8
|
-
import { useEffect, useState } from "react"
|
|
9
|
-
import { useLocation } from "wouter"
|
|
10
|
-
|
|
11
|
-
export const AiPage = () => {
|
|
12
|
-
const [code, setCode] = useState("")
|
|
13
|
-
const [manualEditsFileContent, setManualEditsFileContent] = useState("")
|
|
14
|
-
const [dts, setDts] = useState("")
|
|
15
|
-
const [isStreaming, setIsStreaming] = useState(false)
|
|
16
|
-
const { saveSnippet, isLoading: isSaving } = useSaveSnippet()
|
|
17
|
-
const snippetIdFromUrl = new URLSearchParams(window.location.search).get(
|
|
18
|
-
"snippet_id",
|
|
19
|
-
)
|
|
20
|
-
const [snippetId, setSnippetId] = useState<string | null>(snippetIdFromUrl)
|
|
21
|
-
const { data: snippet } = useSnippet(snippetId)
|
|
22
|
-
const { toast } = useToast()
|
|
23
|
-
const [, navigate] = useLocation()
|
|
24
|
-
const {
|
|
25
|
-
message: errorMessage,
|
|
26
|
-
circuitJson,
|
|
27
|
-
triggerRunTsx,
|
|
28
|
-
isRunningCode,
|
|
29
|
-
tsxRunTriggerCount,
|
|
30
|
-
circuitJsonKey,
|
|
31
|
-
} = useRunTsx({
|
|
32
|
-
code,
|
|
33
|
-
type: "board",
|
|
34
|
-
isStreaming,
|
|
35
|
-
circuitDisplayName: snippet?.name,
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
if (!code && snippet && snippetIdFromUrl) {
|
|
40
|
-
setCode(snippet.code)
|
|
41
|
-
}
|
|
42
|
-
}, [code, snippet])
|
|
43
|
-
|
|
44
|
-
const hasUnsavedChanges = snippet?.code !== code
|
|
45
|
-
|
|
46
|
-
return (
|
|
47
|
-
<div>
|
|
48
|
-
<Header />
|
|
49
|
-
<div className="flex bg-gray-100">
|
|
50
|
-
<div className="w-1/2">
|
|
51
|
-
<AIChatInterface
|
|
52
|
-
code={code}
|
|
53
|
-
hasUnsavedChanges={hasUnsavedChanges}
|
|
54
|
-
snippetId={snippet?.snippet_id}
|
|
55
|
-
onCodeChange={setCode}
|
|
56
|
-
errorMessage={errorMessage}
|
|
57
|
-
onStartStreaming={() => {
|
|
58
|
-
setIsStreaming(true)
|
|
59
|
-
}}
|
|
60
|
-
onStopStreaming={() => {
|
|
61
|
-
setIsStreaming(false)
|
|
62
|
-
}}
|
|
63
|
-
/>
|
|
64
|
-
</div>
|
|
65
|
-
<div className="w-1/2">
|
|
66
|
-
<div className="p-4 h-full">
|
|
67
|
-
<PreviewContent
|
|
68
|
-
className="bg-white h-full p-4 rounded-lg shadow"
|
|
69
|
-
code={code}
|
|
70
|
-
isStreaming={isStreaming}
|
|
71
|
-
isRunningCode={isRunningCode}
|
|
72
|
-
onCodeChange={setCode}
|
|
73
|
-
onDtsChange={setDts}
|
|
74
|
-
showCodeTab
|
|
75
|
-
triggerRunTsx={triggerRunTsx}
|
|
76
|
-
errorMessage={errorMessage}
|
|
77
|
-
circuitJson={circuitJson}
|
|
78
|
-
circuitJsonKey={circuitJsonKey}
|
|
79
|
-
manualEditsFileContent={manualEditsFileContent}
|
|
80
|
-
onManualEditsFileContentChange={(
|
|
81
|
-
newManualEditsFileContent: string,
|
|
82
|
-
) => {
|
|
83
|
-
setManualEditsFileContent(newManualEditsFileContent)
|
|
84
|
-
}}
|
|
85
|
-
tsxRunTriggerCount={tsxRunTriggerCount}
|
|
86
|
-
/>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
90
|
-
</div>
|
|
91
|
-
)
|
|
92
|
-
}
|
package/src/pages/preview.tsx
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { useSnippet } from "@/hooks/use-snippet"
|
|
2
|
-
import { useUrlParams } from "@/hooks/use-url-params"
|
|
3
|
-
import { CircuitJsonPreview } from "@tscircuit/runframe"
|
|
4
|
-
import { Loader2 } from "lucide-react"
|
|
5
|
-
|
|
6
|
-
export const PreviewPage = () => {
|
|
7
|
-
const urlParams = useUrlParams()
|
|
8
|
-
const snippetId = urlParams.snippet_id
|
|
9
|
-
const { data: snippet, isLoading, error } = useSnippet(snippetId)
|
|
10
|
-
|
|
11
|
-
if (isLoading) {
|
|
12
|
-
return (
|
|
13
|
-
<div className="w-full h-screen flex items-center justify-center">
|
|
14
|
-
<Loader2 className="w-8 h-8 animate-spin" />
|
|
15
|
-
</div>
|
|
16
|
-
)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (error) {
|
|
20
|
-
return (
|
|
21
|
-
<div className="w-full h-screen flex items-center justify-center text-red-500">
|
|
22
|
-
Error loading snippet: {error.message}
|
|
23
|
-
</div>
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (!snippet) {
|
|
28
|
-
return (
|
|
29
|
-
<div className="w-full h-screen flex items-center justify-center text-gray-500">
|
|
30
|
-
Snippet not found
|
|
31
|
-
</div>
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!snippet.circuit_json) {
|
|
36
|
-
return (
|
|
37
|
-
<div className="w-full h-screen flex items-center justify-center text-gray-500">
|
|
38
|
-
No circuit data available
|
|
39
|
-
</div>
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return <CircuitJsonPreview circuitJson={snippet.circuit_json as any} />
|
|
44
|
-
}
|
package/src/pages/view-order.tsx
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
import { useQuery } from "react-query"
|
|
3
|
-
import { useAxios } from "@/hooks/use-axios"
|
|
4
|
-
import Header from "@/components/Header"
|
|
5
|
-
import Footer from "@/components/Footer"
|
|
6
|
-
import { Order } from "fake-snippets-api/lib/db/schema"
|
|
7
|
-
import { Link, useParams } from "wouter"
|
|
8
|
-
import { Button } from "@/components/ui/button"
|
|
9
|
-
import { OrderPreviewContent } from "@/components/OrderPreviewContent"
|
|
10
|
-
import { AnyCircuitElement } from "circuit-json"
|
|
11
|
-
|
|
12
|
-
export const ViewOrderPage = () => {
|
|
13
|
-
const { orderId } = useParams()
|
|
14
|
-
const axios = useAxios()
|
|
15
|
-
|
|
16
|
-
const {
|
|
17
|
-
data: order,
|
|
18
|
-
isLoading,
|
|
19
|
-
error,
|
|
20
|
-
} = useQuery<Order>(
|
|
21
|
-
["order", orderId],
|
|
22
|
-
async () => {
|
|
23
|
-
const response = await axios.get(`/orders/get?order_id=${orderId}`)
|
|
24
|
-
return response.data.order
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
enabled: !!orderId,
|
|
28
|
-
},
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
if (isLoading) {
|
|
32
|
-
return <div>Loading order...</div>
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (error) {
|
|
36
|
-
return <div>Error loading order: {(error as Error).message}</div>
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (!order) {
|
|
40
|
-
return <div>Order not found</div>
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<div>
|
|
45
|
-
<Header />
|
|
46
|
-
<div className="container mx-auto px-4 py-4">
|
|
47
|
-
<h1 className="text-3xl font-bold mb-6">Order Details</h1>
|
|
48
|
-
<div className="flex flex-col md:flex-row gap-6">
|
|
49
|
-
<div className="w-full md:w-1/2 md:max-w-[50%]">
|
|
50
|
-
<div className="bg-white shadow overflow-hidden sm:rounded-lg mb-6">
|
|
51
|
-
<div className="px-4 py-5 sm:px-6">
|
|
52
|
-
<h3 className="text-lg leading-6 font-medium text-gray-900">
|
|
53
|
-
Order #{order.order_id}
|
|
54
|
-
</h3>
|
|
55
|
-
<p className="mt-1 max-w-2xl text-sm text-gray-500">
|
|
56
|
-
Created at: {new Date(order.created_at).toLocaleString()}
|
|
57
|
-
</p>
|
|
58
|
-
</div>
|
|
59
|
-
<div className="border-t border-gray-200">
|
|
60
|
-
<dl>
|
|
61
|
-
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
62
|
-
<dt className="text-sm font-medium text-gray-500">
|
|
63
|
-
Status
|
|
64
|
-
</dt>
|
|
65
|
-
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
66
|
-
{order.is_running ? "Running" : "Finished"}
|
|
67
|
-
</dd>
|
|
68
|
-
</div>
|
|
69
|
-
<div className="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
70
|
-
<dt className="text-sm font-medium text-gray-500">
|
|
71
|
-
Started at
|
|
72
|
-
</dt>
|
|
73
|
-
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
74
|
-
{order.started_at
|
|
75
|
-
? new Date(order.started_at).toLocaleString()
|
|
76
|
-
: "Not started"}
|
|
77
|
-
</dd>
|
|
78
|
-
</div>
|
|
79
|
-
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
80
|
-
<dt className="text-sm font-medium text-gray-500">
|
|
81
|
-
Pending Validation
|
|
82
|
-
</dt>
|
|
83
|
-
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
84
|
-
{order.completed_at
|
|
85
|
-
? new Date(order.completed_at).toLocaleString()
|
|
86
|
-
: "Not finished"}
|
|
87
|
-
</dd>
|
|
88
|
-
</div>
|
|
89
|
-
</dl>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
<div className="mt-6">
|
|
93
|
-
<Link href={`/my-orders`}>
|
|
94
|
-
<Button variant="outline" onClick={() => window.history.back()}>
|
|
95
|
-
Back to Orders
|
|
96
|
-
</Button>
|
|
97
|
-
</Link>
|
|
98
|
-
</div>
|
|
99
|
-
</div>
|
|
100
|
-
<div className="w-full md:w-1/2 md:max-w-[50%]">
|
|
101
|
-
<OrderPreviewContent
|
|
102
|
-
circuitJson={order.circuit_json as AnyCircuitElement[]}
|
|
103
|
-
className="h-[calc(100vh-200px)]"
|
|
104
|
-
/>
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
<Footer />
|
|
109
|
-
</div>
|
|
110
|
-
)
|
|
111
|
-
}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { DownloadButtonAndMenu } from "@/components/DownloadButtonAndMenu"
|
|
2
|
-
import Header from "@/components/Header"
|
|
3
|
-
import { Button } from "@/components/ui/button"
|
|
4
|
-
import ViewSnippetHeader from "@/components/ViewSnippetHeader"
|
|
5
|
-
import ViewSnippetSidebar from "@/components/ViewSnippetSidebar"
|
|
6
|
-
import { useCurrentSnippet } from "@/hooks/use-current-snippet"
|
|
7
|
-
import { useRunTsx } from "@/hooks/use-run-tsx"
|
|
8
|
-
import { encodeTextToUrlHash } from "@/lib/encodeTextToUrlHash"
|
|
9
|
-
import { Share } from "lucide-react"
|
|
10
|
-
import { useParams } from "wouter"
|
|
11
|
-
import { PreviewContent } from "@/components/PreviewContent"
|
|
12
|
-
import Footer from "@/components/Footer"
|
|
13
|
-
import { Helmet } from "react-helmet-async"
|
|
14
|
-
import type { AnyCircuitElement } from "circuit-json"
|
|
15
|
-
import StaticViewSnippetHeader from "../components/StaticViewSnippetHeader"
|
|
16
|
-
import StaticPreviewContent from "../components/StaticPreviewContent"
|
|
17
|
-
import StaticViewSnippetSidebar from "../components/StaticViewSnippetSidebar"
|
|
18
|
-
import { useEffect, useMemo, useState } from "react"
|
|
19
|
-
import { parseJsonOrNull } from "@/lib/utils/parseJsonOrNull"
|
|
20
|
-
|
|
21
|
-
export const ViewSnippetPage = () => {
|
|
22
|
-
const { author, snippetName } = useParams()
|
|
23
|
-
const { snippet, error: snippetError, isLoading } = useCurrentSnippet()
|
|
24
|
-
|
|
25
|
-
const [manualEditsFileContent, setManualEditsFileContent] = useState<
|
|
26
|
-
string | null
|
|
27
|
-
>(null)
|
|
28
|
-
|
|
29
|
-
useEffect(() => {
|
|
30
|
-
if (snippet?.manual_edits_json_content) {
|
|
31
|
-
setManualEditsFileContent(snippet.manual_edits_json_content ?? "")
|
|
32
|
-
}
|
|
33
|
-
}, [Boolean(snippet?.manual_edits_json_content)])
|
|
34
|
-
|
|
35
|
-
const userImports = useMemo(
|
|
36
|
-
() => ({
|
|
37
|
-
"./manual-edits.json": parseJsonOrNull(manualEditsFileContent) ?? "",
|
|
38
|
-
}),
|
|
39
|
-
[manualEditsFileContent],
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
const {
|
|
43
|
-
circuitJson: tsxResultCircuitJson,
|
|
44
|
-
message,
|
|
45
|
-
triggerRunTsx,
|
|
46
|
-
isRunningCode,
|
|
47
|
-
tsxRunTriggerCount,
|
|
48
|
-
circuitJsonKey: tsxResultCircuitJsonKey,
|
|
49
|
-
} = useRunTsx({
|
|
50
|
-
code: snippet?.code ?? "",
|
|
51
|
-
type: snippet?.snippet_type,
|
|
52
|
-
userImports,
|
|
53
|
-
circuitDisplayName: snippet?.name,
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
const circuitJsonForPreview = tsxResultCircuitJson ?? snippet?.circuit_json
|
|
57
|
-
const circuitJsonKeyForPreview = tsxResultCircuitJson
|
|
58
|
-
? tsxResultCircuitJsonKey
|
|
59
|
-
: snippet?.circuit_json
|
|
60
|
-
? "snippet"
|
|
61
|
-
: ""
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<>
|
|
65
|
-
<Helmet>
|
|
66
|
-
<title>{`${author}/${snippetName} - tscircuit`}</title>
|
|
67
|
-
{snippet && (
|
|
68
|
-
<>
|
|
69
|
-
<meta
|
|
70
|
-
property="og:title"
|
|
71
|
-
content={`${author}/${snippetName} - tscircuit`}
|
|
72
|
-
/>
|
|
73
|
-
<meta
|
|
74
|
-
property="og:image"
|
|
75
|
-
content={`https://registry-api.tscircuit.com/snippets/images/${author}/${snippetName}/pcb.png`}
|
|
76
|
-
/>
|
|
77
|
-
<meta name="twitter:card" content="summary_large_image" />
|
|
78
|
-
<meta
|
|
79
|
-
name="twitter:image"
|
|
80
|
-
content={`https://registry-api.tscircuit.com/snippets/images/${author}/${snippetName}/pcb.png`}
|
|
81
|
-
/>
|
|
82
|
-
</>
|
|
83
|
-
)}
|
|
84
|
-
</Helmet>
|
|
85
|
-
<div>
|
|
86
|
-
<Header />
|
|
87
|
-
{isLoading && (
|
|
88
|
-
<>
|
|
89
|
-
<StaticViewSnippetHeader
|
|
90
|
-
author={author as string}
|
|
91
|
-
snippetName={snippetName as string}
|
|
92
|
-
/>
|
|
93
|
-
<div className="flex flex-row min-h-full">
|
|
94
|
-
<div className="flex-grow overflow-auto">
|
|
95
|
-
<StaticPreviewContent />
|
|
96
|
-
</div>
|
|
97
|
-
<StaticViewSnippetSidebar />
|
|
98
|
-
</div>
|
|
99
|
-
</>
|
|
100
|
-
)}
|
|
101
|
-
{snippetError && snippetError.status === 404 && (
|
|
102
|
-
<div className="text-gray-500 flex items-center justify-center h-64">
|
|
103
|
-
Snippet not found: {author}/{snippetName}
|
|
104
|
-
</div>
|
|
105
|
-
)}
|
|
106
|
-
{snippetError && snippetError.status !== 404 && (
|
|
107
|
-
<div>Error: {snippetError.toString()}</div>
|
|
108
|
-
)}
|
|
109
|
-
{snippet && (
|
|
110
|
-
<>
|
|
111
|
-
<ViewSnippetHeader />
|
|
112
|
-
<div className="flex flex-row min-h-full">
|
|
113
|
-
<div className="flex-grow overflow-auto">
|
|
114
|
-
<PreviewContent
|
|
115
|
-
className="h-full"
|
|
116
|
-
code={snippet?.code ?? ""}
|
|
117
|
-
triggerRunTsx={triggerRunTsx}
|
|
118
|
-
tsxRunTriggerCount={tsxRunTriggerCount}
|
|
119
|
-
errorMessage={message}
|
|
120
|
-
circuitJson={circuitJsonForPreview}
|
|
121
|
-
circuitJsonKey={circuitJsonKeyForPreview}
|
|
122
|
-
isRunningCode={isRunningCode}
|
|
123
|
-
showCodeTab={true}
|
|
124
|
-
showJsonTab={false}
|
|
125
|
-
showImportAndFormatButtons={false}
|
|
126
|
-
readOnly
|
|
127
|
-
headerClassName="p-4 border-b border-gray-200"
|
|
128
|
-
leftHeaderContent={
|
|
129
|
-
<>
|
|
130
|
-
<Button
|
|
131
|
-
variant="outline"
|
|
132
|
-
size="sm"
|
|
133
|
-
className="h-6 px-2 text-xs"
|
|
134
|
-
onClick={() => {
|
|
135
|
-
if (!snippet) return
|
|
136
|
-
const url = encodeTextToUrlHash(snippet.code)
|
|
137
|
-
navigator.clipboard.writeText(url)
|
|
138
|
-
alert("URL copied to clipboard!")
|
|
139
|
-
}}
|
|
140
|
-
>
|
|
141
|
-
<Share className="mr-1 h-3 w-3" />
|
|
142
|
-
Copy URL
|
|
143
|
-
</Button>
|
|
144
|
-
<DownloadButtonAndMenu
|
|
145
|
-
snippetUnscopedName={snippet?.unscoped_name}
|
|
146
|
-
circuitJson={
|
|
147
|
-
circuitJsonForPreview as AnyCircuitElement[]
|
|
148
|
-
}
|
|
149
|
-
className="hidden md:flex"
|
|
150
|
-
/>
|
|
151
|
-
</>
|
|
152
|
-
}
|
|
153
|
-
isStreaming={false}
|
|
154
|
-
onCodeChange={() => {}}
|
|
155
|
-
onDtsChange={() => {}}
|
|
156
|
-
/>
|
|
157
|
-
</div>
|
|
158
|
-
<ViewSnippetSidebar />
|
|
159
|
-
</div>
|
|
160
|
-
</>
|
|
161
|
-
)}
|
|
162
|
-
<Footer />
|
|
163
|
-
</div>
|
|
164
|
-
</>
|
|
165
|
-
)
|
|
166
|
-
}
|