@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,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
- }
@@ -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
- }
@@ -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
- }