@tscircuit/fake-snippets 0.0.3 → 0.0.4
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/.github/workflows/bundle-size-analysis.yml +2 -2
- package/bun-tests/fake-snippets-api/routes/packages/create.test.ts +26 -0
- package/bun-tests/fake-snippets-api/routes/packages/delete.test.ts +100 -0
- package/bun-tests/fake-snippets-api/routes/packages/get.test.ts +59 -0
- package/bun-tests/fake-snippets-api/routes/packages/list.test.ts +167 -0
- package/bun.lock +3500 -0
- package/dist/bundle.js +467 -106
- package/fake-snippets-api/lib/db/db-client.ts +49 -2
- package/fake-snippets-api/lib/db/schema.ts +53 -0
- package/fake-snippets-api/lib/public-mapping/public-map-package.ts +31 -0
- package/fake-snippets-api/lib/with-winter-spec.ts +1 -0
- package/fake-snippets-api/routes/api/package_files/download.ts +170 -0
- package/fake-snippets-api/routes/api/package_files/get.ts +52 -0
- package/fake-snippets-api/routes/api/package_files/list.ts +60 -0
- package/fake-snippets-api/routes/api/packages/create.ts +58 -0
- package/fake-snippets-api/routes/api/packages/delete.ts +43 -0
- package/fake-snippets-api/routes/api/packages/get.ts +36 -0
- package/fake-snippets-api/routes/api/packages/list.ts +56 -0
- package/fake-snippets-api/routes/api/snippets/create.ts +5 -3
- package/package.json +10 -9
- package/playwright-tests/cmd-click.spec.ts +1 -1
- package/playwright-tests/editor-page.spec.ts +1 -1
- package/playwright-tests/preview-page.spec.ts +2 -9
- package/playwright-tests/snapshots/cmd-click.spec.ts-underlined-imports.png +0 -0
- package/playwright-tests/snapshots/editor-page.spec.ts-editor-with-snippet.png +0 -0
- package/playwright-tests/snapshots/preview-page.spec.ts-preview-snippet-pcb.png +0 -0
- package/src/components/CodeAndPreview.tsx +60 -2
- package/src/components/EditorNav.tsx +23 -2
- package/src/components/FootprintDialog.tsx +3 -6
- package/src/components/Header2.tsx +7 -0
- package/src/components/PrefetchPageLink.tsx +4 -1
- package/src/components/SuspenseRunFrame.tsx +16 -0
- package/src/components/dialogs/import-snippet-dialog.tsx +12 -8
- package/src/hooks/use-debounce.ts +17 -0
- package/src/hooks/use-global-store.ts +5 -0
- package/src/hooks/use-run-tsx/index.tsx +1 -0
- package/src/pages/landing.tsx +2 -2
- package/src/pages/preview.tsx +2 -28
- package/vite.config.ts +1 -1
- package/bun.lockb +0 -0
- package/playwright-tests/snapshots/preview-page.spec.ts-preview-snippet-schematic.png +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/fake-snippets",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -61,13 +61,13 @@
|
|
|
61
61
|
"@radix-ui/react-toggle": "^1.1.0",
|
|
62
62
|
"@radix-ui/react-toggle-group": "^1.1.0",
|
|
63
63
|
"@radix-ui/react-tooltip": "^1.1.2",
|
|
64
|
-
"@tscircuit/3d-viewer": "^0.0.
|
|
65
|
-
"@tscircuit/footprinter": "^0.0.
|
|
64
|
+
"@tscircuit/3d-viewer": "^0.0.113",
|
|
65
|
+
"@tscircuit/footprinter": "^0.0.102",
|
|
66
66
|
"@tscircuit/layout": "^0.0.29",
|
|
67
67
|
"@tscircuit/math-utils": "^0.0.10",
|
|
68
68
|
"@tscircuit/mm": "^0.0.8",
|
|
69
69
|
"@tscircuit/pcb-viewer": "^1.11.12",
|
|
70
|
-
"@tscircuit/props": "^0.0.
|
|
70
|
+
"@tscircuit/props": "^0.0.138",
|
|
71
71
|
"@tscircuit/schematic-viewer": "^1.4.3",
|
|
72
72
|
"@types/file-saver": "^2.0.7",
|
|
73
73
|
"@types/ms": "^0.7.34",
|
|
@@ -76,18 +76,18 @@
|
|
|
76
76
|
"@valtown/codemirror-ts": "^2.2.0",
|
|
77
77
|
"@vercel/analytics": "^1.4.1",
|
|
78
78
|
"change-case": "^5.4.4",
|
|
79
|
-
"circuit-json": "^0.0.
|
|
79
|
+
"circuit-json": "^0.0.135",
|
|
80
80
|
"circuit-json-to-bom-csv": "^0.0.6",
|
|
81
81
|
"circuit-json-to-gerber": "^0.0.16",
|
|
82
82
|
"circuit-json-to-pnp-csv": "^0.0.6",
|
|
83
|
-
"circuit-json-to-readable-netlist": "^0.0.
|
|
83
|
+
"circuit-json-to-readable-netlist": "^0.0.7",
|
|
84
84
|
"class-variance-authority": "^0.7.0",
|
|
85
85
|
"clsx": "^2.1.1",
|
|
86
86
|
"cmdk": "^1.0.4",
|
|
87
87
|
"codemirror": "^6.0.1",
|
|
88
88
|
"country-list": "^2.3.0",
|
|
89
89
|
"date-fns": "^4.1.0",
|
|
90
|
-
"dsn-converter": "^0.0.
|
|
90
|
+
"dsn-converter": "^0.0.60",
|
|
91
91
|
"easyeda": "^0.0.62",
|
|
92
92
|
"embla-carousel-react": "^8.3.0",
|
|
93
93
|
"extract-codefence": "^0.0.4",
|
|
@@ -129,8 +129,9 @@
|
|
|
129
129
|
"@babel/standalone": "^7.26.2",
|
|
130
130
|
"@biomejs/biome": "^1.9.2",
|
|
131
131
|
"@playwright/test": "^1.48.0",
|
|
132
|
-
"@tscircuit/core": "^0.0.
|
|
133
|
-
"@tscircuit/prompt-benchmarks": "^0.0.
|
|
132
|
+
"@tscircuit/core": "^0.0.296",
|
|
133
|
+
"@tscircuit/prompt-benchmarks": "^0.0.28",
|
|
134
|
+
"@tscircuit/runframe": "^0.0.139",
|
|
134
135
|
"@types/babel__standalone": "^7.1.7",
|
|
135
136
|
"@types/bun": "^1.1.10",
|
|
136
137
|
"@types/country-list": "^2.1.4",
|
|
@@ -3,7 +3,7 @@ import { test, expect } from "@playwright/test"
|
|
|
3
3
|
test("Editor handles imports with underlining and cmd+click", async ({
|
|
4
4
|
page,
|
|
5
5
|
}) => {
|
|
6
|
-
await page.goto("http://127.0.0.1:5177/editor?snippet_id=
|
|
6
|
+
await page.goto("http://127.0.0.1:5177/editor?snippet_id=snippet_3")
|
|
7
7
|
|
|
8
8
|
await page.waitForLoadState("networkidle")
|
|
9
9
|
|
|
@@ -8,7 +8,7 @@ test("Editor loads snippet correctly", async ({ page }) => {
|
|
|
8
8
|
await page.waitForLoadState("networkidle")
|
|
9
9
|
|
|
10
10
|
// Check for specific text that should be present
|
|
11
|
-
await expect(page.getByText("
|
|
11
|
+
await expect(page.getByText("A555Timer", { exact: true })).toBeVisible()
|
|
12
12
|
|
|
13
13
|
// Take a snapshot
|
|
14
14
|
await expect(page).toHaveScreenshot("editor-with-snippet.png")
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { expect, test } from "@playwright/test"
|
|
2
2
|
|
|
3
3
|
test(`preview-snippet Page`, async ({ page }) => {
|
|
4
|
-
await page.goto("http://127.0.0.1:5177/preview?snippet_id=snippet_5
|
|
5
|
-
await page.waitForTimeout(
|
|
4
|
+
await page.goto("http://127.0.0.1:5177/preview?snippet_id=snippet_5")
|
|
5
|
+
await page.waitForTimeout(20000)
|
|
6
6
|
await expect(page).toHaveScreenshot(`preview-snippet-pcb.png`)
|
|
7
|
-
|
|
8
|
-
await page.goto(
|
|
9
|
-
"http://127.0.0.1:5177/preview?snippet_id=snippet_5&view=schematic",
|
|
10
|
-
)
|
|
11
|
-
// Wait for schematic viewer to load
|
|
12
|
-
await page.waitForTimeout(5000)
|
|
13
|
-
await expect(page).toHaveScreenshot(`preview-snippet-schematic.png`)
|
|
14
7
|
})
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -15,8 +15,9 @@ import { Loader2 } from "lucide-react"
|
|
|
15
15
|
import { useEffect, useMemo, useState } from "react"
|
|
16
16
|
import { useMutation, useQueryClient } from "react-query"
|
|
17
17
|
import EditorNav from "./EditorNav"
|
|
18
|
-
import { PreviewContent } from "./PreviewContent"
|
|
19
18
|
import { parseJsonOrNull } from "@/lib/utils/parseJsonOrNull"
|
|
19
|
+
import { PreviewContent } from "./PreviewContent"
|
|
20
|
+
import { SuspenseRunFrame } from "./SuspenseRunFrame"
|
|
20
21
|
|
|
21
22
|
interface Props {
|
|
22
23
|
snippet?: Snippet | null
|
|
@@ -50,6 +51,9 @@ export function CodeAndPreview({ snippet }: Props) {
|
|
|
50
51
|
const [showPreview, setShowPreview] = useState(true)
|
|
51
52
|
const [lastRunCode, setLastRunCode] = useState(defaultCode ?? "")
|
|
52
53
|
const [fullScreen, setFullScreen] = useState(false)
|
|
54
|
+
const shouldUseWebworkerForRun = useGlobalStore(
|
|
55
|
+
(s) => s.should_use_webworker_for_run,
|
|
56
|
+
)
|
|
53
57
|
|
|
54
58
|
const snippetType: "board" | "package" | "model" | "footprint" =
|
|
55
59
|
snippet?.snippet_type ??
|
|
@@ -187,6 +191,41 @@ export function CodeAndPreview({ snippet }: Props) {
|
|
|
187
191
|
|
|
188
192
|
useWarnUserOnPageChange({ hasUnsavedChanges })
|
|
189
193
|
|
|
194
|
+
const fsMap = useMemo(() => {
|
|
195
|
+
const possibleExportNames = [
|
|
196
|
+
...(code.match(/export function (\w+)/)?.slice(1) ?? []),
|
|
197
|
+
...(code.match(/export const (\w+) ?=/)?.slice(1) ?? []),
|
|
198
|
+
]
|
|
199
|
+
|
|
200
|
+
console.log(possibleExportNames)
|
|
201
|
+
|
|
202
|
+
const exportName = possibleExportNames[0]
|
|
203
|
+
|
|
204
|
+
let entrypointContent: string
|
|
205
|
+
if (snippetType === "board") {
|
|
206
|
+
entrypointContent = `
|
|
207
|
+
import ${exportName ? `{ ${exportName} as Snippet }` : "Snippet"} from "./index.tsx"
|
|
208
|
+
circuit.add(<Snippet />)
|
|
209
|
+
`.trim()
|
|
210
|
+
} else {
|
|
211
|
+
entrypointContent = `
|
|
212
|
+
import ${exportName ? `{ ${exportName} as Snippet }` : "Snippet"} from "./index.tsx"
|
|
213
|
+
circuit.add(
|
|
214
|
+
<board width="10mm" height="10mm">
|
|
215
|
+
<Snippet name="U1" />
|
|
216
|
+
</board>
|
|
217
|
+
)
|
|
218
|
+
`.trim()
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
"index.tsx": code,
|
|
223
|
+
"manual-edits.json": manualEditsFileContent ?? "{}",
|
|
224
|
+
"main.tsx": entrypointContent,
|
|
225
|
+
}
|
|
226
|
+
}, [code, manualEditsFileContent])
|
|
227
|
+
console.log(fsMap)
|
|
228
|
+
|
|
190
229
|
if (!snippet && (urlParams.snippet_id || urlParams.should_create_snippet)) {
|
|
191
230
|
return (
|
|
192
231
|
<div className="flex items-center justify-center h-64">
|
|
@@ -231,7 +270,7 @@ export function CodeAndPreview({ snippet }: Props) {
|
|
|
231
270
|
onDtsChange={(newDts) => setDts(newDts)}
|
|
232
271
|
/>
|
|
233
272
|
</div>
|
|
234
|
-
{showPreview && (
|
|
273
|
+
{showPreview && !shouldUseWebworkerForRun && (
|
|
235
274
|
<PreviewContent
|
|
236
275
|
className={cn(
|
|
237
276
|
"flex p-2 flex-col min-h-[640px]",
|
|
@@ -252,6 +291,25 @@ export function CodeAndPreview({ snippet }: Props) {
|
|
|
252
291
|
isFullScreen={fullScreen}
|
|
253
292
|
/>
|
|
254
293
|
)}
|
|
294
|
+
{showPreview && shouldUseWebworkerForRun && (
|
|
295
|
+
<div
|
|
296
|
+
className={cn(
|
|
297
|
+
"flex p-0 flex-col min-h-[640px]",
|
|
298
|
+
fullScreen
|
|
299
|
+
? "fixed inset-0 z-50 bg-white p-4 overflow-hidden"
|
|
300
|
+
: "w-full md:w-1/2",
|
|
301
|
+
)}
|
|
302
|
+
>
|
|
303
|
+
<SuspenseRunFrame
|
|
304
|
+
showRunButton
|
|
305
|
+
onEditEvent={() => {
|
|
306
|
+
// TODO
|
|
307
|
+
}}
|
|
308
|
+
fsMap={fsMap}
|
|
309
|
+
entrypoint="main.tsx"
|
|
310
|
+
/>
|
|
311
|
+
</div>
|
|
312
|
+
)}
|
|
255
313
|
</div>
|
|
256
314
|
</div>
|
|
257
315
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Button } from "@/components/ui/button"
|
|
2
|
-
import { GitFork } from "lucide-react"
|
|
2
|
+
import { Check, CircleCheckBig, Cpu, GitFork, Square } from "lucide-react"
|
|
3
3
|
import {
|
|
4
4
|
DropdownMenu,
|
|
5
5
|
DropdownMenuContent,
|
|
@@ -75,6 +75,12 @@ export default function EditorNav({
|
|
|
75
75
|
const [, navigate] = useLocation()
|
|
76
76
|
const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
|
|
77
77
|
const session = useGlobalStore((s) => s.session)
|
|
78
|
+
const shouldUseWebworkerForRun = useGlobalStore(
|
|
79
|
+
(s) => s.should_use_webworker_for_run,
|
|
80
|
+
)
|
|
81
|
+
const setShouldUseWebworkerForRun = useGlobalStore(
|
|
82
|
+
(s) => s.setShouldUseWebworkerForRun,
|
|
83
|
+
)
|
|
78
84
|
const { Dialog: RenameDialog, openDialog: openRenameDialog } =
|
|
79
85
|
useRenameSnippetDialog()
|
|
80
86
|
const {
|
|
@@ -275,10 +281,25 @@ export default function EditorNav({
|
|
|
275
281
|
variant="ghost"
|
|
276
282
|
size="sm"
|
|
277
283
|
className="hidden md:flex px-2 text-xs"
|
|
284
|
+
onClick={() =>
|
|
285
|
+
setShouldUseWebworkerForRun(!shouldUseWebworkerForRun)
|
|
286
|
+
}
|
|
287
|
+
>
|
|
288
|
+
{shouldUseWebworkerForRun ? (
|
|
289
|
+
<CircleCheckBig className="mr-1 h-3 w-3" />
|
|
290
|
+
) : (
|
|
291
|
+
<Square className="mr-1 h-3 w-3" />
|
|
292
|
+
)}
|
|
293
|
+
Webworker (Beta)
|
|
294
|
+
</Button>
|
|
295
|
+
{/* <Button
|
|
296
|
+
variant="ghost"
|
|
297
|
+
size="sm"
|
|
298
|
+
className="hidden md:flex px-2 text-xs"
|
|
278
299
|
>
|
|
279
300
|
<Eye className="mr-1 h-3 w-3" />
|
|
280
301
|
Public
|
|
281
|
-
</Button>
|
|
302
|
+
</Button> */}
|
|
282
303
|
<DropdownMenu>
|
|
283
304
|
<DropdownMenuTrigger asChild>
|
|
284
305
|
<Button variant="ghost" size="icon" className="hidden md:flex">
|
|
@@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from "react"
|
|
|
3
3
|
import { parseFootprintParams } from "../lib/utils/parseFootprintParams"
|
|
4
4
|
import ParametersEditor from "./ParametersEditor"
|
|
5
5
|
import { convertCircuitJsonToPcbSvg } from "circuit-to-svg"
|
|
6
|
-
import { fp } from "@tscircuit/footprinter"
|
|
6
|
+
import { fp, getFootprintNamesByType } from "@tscircuit/footprinter"
|
|
7
7
|
import { useToast } from "../hooks/use-toast"
|
|
8
8
|
import { Button } from "./ui/button"
|
|
9
9
|
import { FileName } from "./CodeEditorHeader"
|
|
@@ -53,10 +53,7 @@ export const FootprintDialog = ({
|
|
|
53
53
|
const [error, setError] = useState<string | null>(null)
|
|
54
54
|
const { toast } = useToast()
|
|
55
55
|
|
|
56
|
-
const
|
|
57
|
-
const footprintNames = fp
|
|
58
|
-
.getFootprintNames()
|
|
59
|
-
.filter((footprintName) => !PASSIVE_COMPONENTS.includes(footprintName))
|
|
56
|
+
const { normalFootprintNames } = getFootprintNamesByType()
|
|
60
57
|
|
|
61
58
|
useEffect(() => {
|
|
62
59
|
if (copied) {
|
|
@@ -266,7 +263,7 @@ export const FootprintDialog = ({
|
|
|
266
263
|
handleFootprintPreview(value)
|
|
267
264
|
}
|
|
268
265
|
}}
|
|
269
|
-
options={
|
|
266
|
+
options={normalFootprintNames}
|
|
270
267
|
placeholder="Select footprint..."
|
|
271
268
|
searchPlaceholder="Search footprints..."
|
|
272
269
|
emptyText="No footprints found."
|
|
@@ -64,6 +64,13 @@ export const Header2 = () => {
|
|
|
64
64
|
const isLoggedIn = useGlobalStore((state) => Boolean(state.session))
|
|
65
65
|
return (
|
|
66
66
|
<>
|
|
67
|
+
{/* <div className="absolute left-0 top-0 z-[9999999]">
|
|
68
|
+
<div className="hidden xl:block">xl</div>
|
|
69
|
+
<div className="hidden lg:block xl:hidden">lg</div>
|
|
70
|
+
<div className="hidden md:block lg:hidden">md</div>
|
|
71
|
+
<div className="hidden sm:block md:hidden">sm</div>
|
|
72
|
+
<div className="hidden xs:block sm:hidden">xs</div>
|
|
73
|
+
</div> */}
|
|
67
74
|
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
68
75
|
<div className="container mx-auto flex h-16 items-center justify-between px-2 md:px-6">
|
|
69
76
|
<div className="flex items-center gap-2">
|
|
@@ -30,7 +30,10 @@ const PrefetchPageLink = ({
|
|
|
30
30
|
|
|
31
31
|
useEffect(() => {
|
|
32
32
|
if (inView) {
|
|
33
|
-
const
|
|
33
|
+
const link = href === "/" ? "landing" : href.slice(1)
|
|
34
|
+
if (!link) return
|
|
35
|
+
const pageName = link.split("?")[0]
|
|
36
|
+
|
|
34
37
|
import(`@/pages/${pageName}.tsx`).catch((error) => {
|
|
35
38
|
console.error(`Failed to prefetch page module ${pageName}:`, error)
|
|
36
39
|
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { lazy, Suspense } from "react"
|
|
2
|
+
|
|
3
|
+
const RunFrame = lazy(async () => {
|
|
4
|
+
const { RunFrame } = await import("@tscircuit/runframe/runner")
|
|
5
|
+
return { default: RunFrame }
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
export const SuspenseRunFrame = (
|
|
9
|
+
props: React.ComponentProps<typeof RunFrame>,
|
|
10
|
+
) => {
|
|
11
|
+
return (
|
|
12
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
13
|
+
<RunFrame {...props} />
|
|
14
|
+
</Suspense>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { Button } from "../ui/button"
|
|
1
|
+
import { useAxios } from "@/hooks/use-axios"
|
|
2
|
+
import { useDebounce } from "@/hooks/use-debounce"
|
|
3
|
+
import type { Snippet } from "fake-snippets-api/lib/db/schema"
|
|
5
4
|
import { useState } from "react"
|
|
6
5
|
import { useQuery } from "react-query"
|
|
7
|
-
import {
|
|
6
|
+
import { Button } from "../ui/button"
|
|
7
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog"
|
|
8
|
+
import { Input } from "../ui/input"
|
|
8
9
|
import { createUseDialog } from "./create-use-dialog"
|
|
9
10
|
|
|
10
11
|
export const ImportSnippetDialog = ({
|
|
@@ -17,15 +18,18 @@ export const ImportSnippetDialog = ({
|
|
|
17
18
|
onSnippetSelected: (snippet: Snippet) => any
|
|
18
19
|
}) => {
|
|
19
20
|
const [searchText, setSearchText] = useState("")
|
|
21
|
+
const debouncedSearch = useDebounce(searchText, 300)
|
|
20
22
|
const axios = useAxios()
|
|
21
23
|
const { data: snippets, isLoading } = useQuery(
|
|
22
|
-
["snippetSearch",
|
|
24
|
+
["snippetSearch", debouncedSearch],
|
|
23
25
|
async () => {
|
|
24
|
-
const response = await axios.get(
|
|
26
|
+
const response = await axios.get(
|
|
27
|
+
`/snippets/search?q=${encodeURIComponent(debouncedSearch)}`,
|
|
28
|
+
)
|
|
25
29
|
return response.data.snippets.slice(0, 12)
|
|
26
30
|
},
|
|
27
31
|
{
|
|
28
|
-
enabled:
|
|
32
|
+
enabled: debouncedSearch.length > 0,
|
|
29
33
|
},
|
|
30
34
|
)
|
|
31
35
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useEffect, useState } from "react"
|
|
2
|
+
|
|
3
|
+
export function useDebounce<T>(value: T, delay: number): T {
|
|
4
|
+
const [debouncedValue, setDebouncedValue] = useState<T>(value)
|
|
5
|
+
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const handler = setTimeout(() => {
|
|
8
|
+
setDebouncedValue(value)
|
|
9
|
+
}, delay)
|
|
10
|
+
|
|
11
|
+
return () => {
|
|
12
|
+
clearTimeout(handler)
|
|
13
|
+
}
|
|
14
|
+
}, [value, delay])
|
|
15
|
+
|
|
16
|
+
return debouncedValue
|
|
17
|
+
}
|
|
@@ -10,6 +10,8 @@ export type Store = {
|
|
|
10
10
|
} | null
|
|
11
11
|
setSession: (session: Store["session"]) => any
|
|
12
12
|
should_onboarding_tips_be_closed: boolean
|
|
13
|
+
should_use_webworker_for_run?: boolean
|
|
14
|
+
setShouldUseWebworkerForRun: (should_use_webworker_for_run: boolean) => any
|
|
13
15
|
setOnboardingTipsClosed: (closed: boolean) => any
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -17,6 +19,9 @@ export const useGlobalStore = create<Store>()(
|
|
|
17
19
|
persist(
|
|
18
20
|
(set) => ({
|
|
19
21
|
session: null,
|
|
22
|
+
should_use_webworker_for_run: false,
|
|
23
|
+
setShouldUseWebworkerForRun: (should_use_webworker_for_run: boolean) =>
|
|
24
|
+
set({ should_use_webworker_for_run }),
|
|
20
25
|
setSession: (session) => set({ session }),
|
|
21
26
|
should_onboarding_tips_be_closed: false,
|
|
22
27
|
setOnboardingTipsClosed: (closed) =>
|
|
@@ -108,6 +108,7 @@ export const useRunTsx = ({
|
|
|
108
108
|
}
|
|
109
109
|
;(globalThis as any).__tscircuit_require = __tscircuit_require
|
|
110
110
|
preSuppliedImports["@tscircuit/core"] = tscircuitCore
|
|
111
|
+
preSuppliedImports["tscircuit"] = tscircuitCore
|
|
111
112
|
preSuppliedImports["@tscircuit/math-utils"] = tscircuitMathUtils
|
|
112
113
|
preSuppliedImports["react"] = React
|
|
113
114
|
preSuppliedImports["jscad-fiber"] = jscadFiber
|
package/src/pages/landing.tsx
CHANGED
|
@@ -41,7 +41,7 @@ export function LandingPage() {
|
|
|
41
41
|
</Helmet>
|
|
42
42
|
<Header2 />
|
|
43
43
|
<main className="flex-1">
|
|
44
|
-
<section className="w-full py-
|
|
44
|
+
<section className="w-full py-8 md:py-12 lg:py-20 xl:py-36">
|
|
45
45
|
<div className="container px-4 md:px-6 mx-auto">
|
|
46
46
|
<div className="container mx-auto max-w-7xl">
|
|
47
47
|
<div className="grid gap-6 lg:grid-cols-[1fr_400px] lg:gap-12 xl:grid-cols-[1fr_600px]">
|
|
@@ -116,7 +116,7 @@ export function LandingPage() {
|
|
|
116
116
|
<div className="w-full aspect-video relative">
|
|
117
117
|
<OptimizedImage
|
|
118
118
|
alt="Product preview"
|
|
119
|
-
className="mx-auto overflow-hidden rounded-xl object-cover object-center absolute inset-0 w-full h-full"
|
|
119
|
+
className="mx-auto overflow-hidden rounded-xl object-cover object-center absolute inset-0 w-full h-full mt-8 lg:mt-0"
|
|
120
120
|
src="/assets/editor_example_1_more_square.webp"
|
|
121
121
|
priority={true}
|
|
122
122
|
/>
|
package/src/pages/preview.tsx
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import { CircuitToSvgWithMouseControl } from "@/components/CircuitToSvgWithMouseControl"
|
|
2
1
|
import { useSnippet } from "@/hooks/use-snippet"
|
|
3
2
|
import { useUrlParams } from "@/hooks/use-url-params"
|
|
4
|
-
import {
|
|
5
|
-
import { PCBViewer } from "@tscircuit/pcb-viewer"
|
|
3
|
+
import { CircuitJsonPreview } from "@tscircuit/runframe"
|
|
6
4
|
import { Loader2 } from "lucide-react"
|
|
7
5
|
|
|
8
6
|
export const PreviewPage = () => {
|
|
9
7
|
const urlParams = useUrlParams()
|
|
10
8
|
const snippetId = urlParams.snippet_id
|
|
11
|
-
const view = urlParams.view || "pcb"
|
|
12
9
|
const { data: snippet, isLoading, error } = useSnippet(snippetId)
|
|
13
10
|
|
|
14
11
|
if (isLoading) {
|
|
@@ -43,28 +40,5 @@ export const PreviewPage = () => {
|
|
|
43
40
|
)
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
if (!validViews.includes(view)) {
|
|
48
|
-
return (
|
|
49
|
-
<div className="w-full h-screen">
|
|
50
|
-
{view === "pcb" && (
|
|
51
|
-
<PCBViewer soup={snippet.circuit_json} height={window.innerHeight} />
|
|
52
|
-
)}
|
|
53
|
-
</div>
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<div className="w-full h-screen">
|
|
59
|
-
{view === "pcb" && (
|
|
60
|
-
<PCBViewer soup={snippet.circuit_json} height={window.innerHeight} />
|
|
61
|
-
)}
|
|
62
|
-
{view === "3d" && <CadViewer soup={snippet.circuit_json as any} />}
|
|
63
|
-
{view === "schematic" && (
|
|
64
|
-
<CircuitToSvgWithMouseControl
|
|
65
|
-
circuitJson={snippet.circuit_json as any}
|
|
66
|
-
/>
|
|
67
|
-
)}
|
|
68
|
-
</div>
|
|
69
|
-
)
|
|
43
|
+
return <CircuitJsonPreview circuitJson={snippet.circuit_json as any} />
|
|
70
44
|
}
|
package/vite.config.ts
CHANGED
package/bun.lockb
DELETED
|
Binary file
|