diff --git a/src/components/CodeAndPreview.tsx b/src/components/CodeAndPreview.tsx
index f32f453a..054a798c 100644
--- a/src/components/CodeAndPreview.tsx
+++ b/src/components/CodeAndPreview.tsx
@@ -15,11 +15,12 @@ import { useAxios } from "@/hooks/use-axios"
import { TypeBadge } from "./TypeBadge"
import { useToast } from "@/hooks/use-toast"
import { useMutation, useQueryClient } from "react-query"
-import { ClipboardIcon, Share, Eye, EyeOff } from "lucide-react"
+import { ClipboardIcon, Share, Eye, EyeOff, PlayIcon } from "lucide-react"
import { MagicWandIcon } from "@radix-ui/react-icons"
import { ErrorBoundary } from "react-error-boundary"
import { ErrorTabContent } from "./ErrorTabContent"
import { cn } from "@/lib/utils"
+import { PreviewContent } from "./PreviewContent"
interface Props {
snippet?: Snippet | null
@@ -41,10 +42,16 @@ export function CodeAndPreview({ snippet }: Props) {
}, [snippet?.code])
const { toast } = useToast()
- const { message, circuitJson, compiledJs } = useRunTsx(
+ const {
+ message,
+ circuitJson,
+ compiledJs,
+ triggerRunTsx,
+ tsxRunTriggerCount,
+ } = useRunTsx({
code,
- snippet?.snippet_type,
- )
+ type: snippet?.snippet_type,
+ })
const qc = useQueryClient()
const updateSnippetMutation = useMutation({
@@ -113,43 +120,14 @@ export function CodeAndPreview({ snippet }: Props) {
/>
{showPreview && (
-
-
-
- PCB
- 3D
- JSON
-
- Errors
- {message && (
-
- 1
-
- )}
-
-
-
-
-
-
-
- Error loading 3D viewer
}>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
)}
diff --git a/src/components/ErrorTabContent.tsx b/src/components/ErrorTabContent.tsx
index 3538f478..7b86f260 100644
--- a/src/components/ErrorTabContent.tsx
+++ b/src/components/ErrorTabContent.tsx
@@ -12,7 +12,7 @@ export const ErrorTabContent = ({
}: {
code?: string
isStreaming?: boolean
- errorMessage?: string
+ errorMessage?: string | null
}) => {
const anthropic = useAiApi()
const simplifiedErrorMessage = useAsyncMemo(async () => {
diff --git a/src/components/PreviewContent.tsx b/src/components/PreviewContent.tsx
new file mode 100644
index 00000000..94ebff6f
--- /dev/null
+++ b/src/components/PreviewContent.tsx
@@ -0,0 +1,119 @@
+import { useEffect, useMemo, useState } from "react"
+import { CodeEditor } from "@/components/CodeEditor"
+import { PCBViewer } from "@tscircuit/pcb-viewer"
+import { CadViewer } from "@tscircuit/3d-viewer"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { defaultCodeForBlankPage } from "@/lib/defaultCodeForBlankCode"
+import { decodeUrlHashToText } from "@/lib/decodeUrlHashToText"
+import { encodeTextToUrlHash } from "@/lib/encodeTextToUrlHash"
+import { Button } from "@/components/ui/button"
+import { useRunTsx } from "@/hooks/use-run-tsx"
+import EditorNav from "./EditorNav"
+import { CircuitJsonTableViewer } from "./TableViewer/CircuitJsonTableViewer"
+import { Snippet } from "fake-snippets-api/lib/db/schema"
+import { useAxios } from "@/hooks/use-axios"
+import { TypeBadge } from "./TypeBadge"
+import { useToast } from "@/hooks/use-toast"
+import { useMutation, useQueryClient } from "react-query"
+import { ClipboardIcon, Share, Eye, EyeOff, PlayIcon } from "lucide-react"
+import { MagicWandIcon } from "@radix-ui/react-icons"
+import { ErrorBoundary } from "react-error-boundary"
+import { ErrorTabContent } from "./ErrorTabContent"
+import { cn } from "@/lib/utils"
+
+export interface PreviewContentProps {
+ code: string
+ triggerRunTsx: () => void
+ hasUnsavedChanges: boolean
+ tsxRunTriggerCount: number
+ errorMessage: string | null
+ circuitJson: any
+}
+
+const PreviewEmptyState = ({
+ triggerRunTsx,
+}: { triggerRunTsx: () => void }) => (
+
+ No circuit json loaded
+
+
+)
+
+export const PreviewContent = ({
+ code,
+ triggerRunTsx,
+ hasUnsavedChanges,
+ tsxRunTriggerCount,
+ errorMessage,
+ circuitJson,
+}: PreviewContentProps) => {
+ return (
+
+
+
+
+
+
+ PCB
+ 3D
+ JSON
+
+ Errors
+ {errorMessage && (
+
+ 1
+
+ )}
+
+
+
+
+
+ Error loading PCB viewer
}>
+ {circuitJson ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ Error loading 3D viewer
}>
+ {circuitJson ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ Error loading 3D viewer
}>
+ {circuitJson ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/hooks/use-run-tsx/construct-circuit.tsx b/src/hooks/use-run-tsx/construct-circuit.tsx
index c291465f..60c66dfd 100644
--- a/src/hooks/use-run-tsx/construct-circuit.tsx
+++ b/src/hooks/use-run-tsx/construct-circuit.tsx
@@ -4,7 +4,6 @@ import * as React from "react"
import { useCompiledTsx } from "../use-compiled-tsx"
import { createJSCADRenderer } from "jscad-fiber"
import { jscadPlanner } from "jscad-planner"
-import { getImportsFromCode } from "@tscircuit/prompt-benchmarks/code-runner-utils"
export const constructCircuit = (
UserElm: any,
diff --git a/src/hooks/use-run-tsx/index.tsx b/src/hooks/use-run-tsx/index.tsx
index 77552e19..0287238c 100644
--- a/src/hooks/use-run-tsx/index.tsx
+++ b/src/hooks/use-run-tsx/index.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useMemo, useState } from "react"
+import { useEffect, useMemo, useReducer, useState } from "react"
import * as React from "react"
import { useCompiledTsx } from "../use-compiled-tsx"
import { Circuit } from "@tscircuit/core"
@@ -17,13 +17,24 @@ type RunTsxResult = {
isLoading: boolean
}
-export const useRunTsx = (
- code?: string,
- type?: "board" | "footprint" | "package" | "model",
- { isStreaming = false }: { isStreaming?: boolean } = {},
-): RunTsxResult => {
+export const useRunTsx = ({
+ code,
+ type,
+ isStreaming = false,
+}: {
+ code?: string
+ type?: "board" | "footprint" | "package" | "model"
+ isStreaming?: boolean
+} = {}): RunTsxResult & {
+ triggerRunTsx: () => void
+ tsxRunTriggerCount: number
+} => {
type ??= "board"
const compiledJs = useCompiledTsx(code, { isStreaming })
+ const [tsxRunTriggerCount, incTsxRunTriggerCount] = useReducer(
+ (c) => c + 1,
+ 0,
+ )
const [tsxResult, setTsxResult] = useState({
compiledModule: null,
message: "",
@@ -33,6 +44,7 @@ export const useRunTsx = (
const apiBaseUrl = useSnippetsBaseApiUrl()
useEffect(() => {
+ if (tsxRunTriggerCount === 0) return
async function run() {
if (isStreaming || !compiledJs || !code) {
setTsxResult({
@@ -61,11 +73,9 @@ export const useRunTsx = (
).then((res) => res.json())
try {
- console.log("importedSnippet", importedSnippet)
- // eval the imported snippet compiled_js
preSuppliedImports[importName] = evalCompiledJs(
importedSnippet.compiled_js,
- )
+ ).default.exports
} catch (e) {
console.error("Error importing snippet", e)
}
@@ -127,7 +137,11 @@ export const useRunTsx = (
}
}
run()
- }, [compiledJs, isStreaming])
+ }, [tsxRunTriggerCount, compiledJs, isStreaming])
- return tsxResult
+ return {
+ ...tsxResult,
+ triggerRunTsx: incTsxRunTriggerCount,
+ tsxRunTriggerCount,
+ }
}
diff --git a/src/pages/ai.tsx b/src/pages/ai.tsx
index 8d4d340a..c1647ff4 100644
--- a/src/pages/ai.tsx
+++ b/src/pages/ai.tsx
@@ -19,7 +19,9 @@ export const AiPage = () => {
const [code, setCode] = useState("")
const [dts, setDts] = useState("")
const [isStreaming, setIsStreaming] = useState(false)
- const { message: errorMessage, circuitJson } = useRunTsx(code, "board", {
+ const { message: errorMessage, circuitJson } = useRunTsx({
+ code,
+ type: "board",
isStreaming,
})
const { saveSnippet, isLoading: isSaving } = useSaveSnippet()
diff --git a/src/pages/view-snippet.tsx b/src/pages/view-snippet.tsx
index 4178920a..d8db8258 100644
--- a/src/pages/view-snippet.tsx
+++ b/src/pages/view-snippet.tsx
@@ -18,10 +18,10 @@ export const ViewSnippetPage = () => {
const { author, snippetName } = useParams()
const { snippet } = useCurrentSnippet()
- const { circuitJson, message } = useRunTsx(
- snippet?.code ?? "",
- snippet?.snippet_type,
- )
+ const { circuitJson, message } = useRunTsx({
+ code: snippet?.code ?? "",
+ type: snippet?.snippet_type,
+ })
return (