@tscircuit/fake-snippets 0.0.66 → 0.0.67
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 +15 -17
- 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 -3
- package/src/App.tsx +0 -7
- package/src/ContextProviders.tsx +2 -0
- package/src/components/DownloadButtonAndMenu.tsx +1 -4
- package/src/components/Footer.tsx +5 -2
- package/src/components/HeaderLogin.tsx +37 -54
- package/src/components/ImageWithFallback.tsx +37 -0
- package/src/components/JLCPCBImportDialog.tsx +43 -24
- 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/main-content-header.tsx +8 -8
- package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +24 -14
- package/src/components/ViewPackagePage/components/package-header.tsx +6 -1
- package/src/components/package-port/CodeEditor.tsx +13 -10
- package/src/components/package-port/CodeEditorHeader.tsx +1 -1
- package/src/components/package-port/EditorNav.tsx +2 -2
- package/src/hooks/use-global-store.ts +1 -0
- package/src/hooks/use-shiki-highlighter.ts +13 -6
- 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/pages/dashboard.tsx +3 -4
- package/src/pages/editor.tsx +20 -14
- package/src/pages/latest.tsx +25 -26
- package/src/pages/search.tsx +120 -19
- package/src/pages/trending.tsx +14 -58
- package/src/pages/user-profile.tsx +13 -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/PreviewContent.tsx +0 -372
- package/src/components/SnippetCard.tsx +0 -159
- package/src/components/SnippetList.tsx +0 -71
- 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/view-snippet.tsx +0 -166
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
3
|
+
import { PackageCardSkeleton } from "./PackageCardSkeleton"
|
|
4
|
+
import { Search } from "lucide-react"
|
|
5
|
+
import { PackageCard } from "./PackageCard"
|
|
6
|
+
|
|
7
|
+
interface PackageSearchResultsProps {
|
|
8
|
+
isLoading: boolean
|
|
9
|
+
error: unknown
|
|
10
|
+
filteredPackages: Package[] | undefined
|
|
11
|
+
apiBaseUrl: string
|
|
12
|
+
emptyStateMessage: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const PackageGrid = ({
|
|
16
|
+
packages,
|
|
17
|
+
baseUrl,
|
|
18
|
+
}: { packages: Package[]; baseUrl: string }) => (
|
|
19
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
20
|
+
{packages.map((pkg) => (
|
|
21
|
+
<PackageCard
|
|
22
|
+
key={pkg.package_id}
|
|
23
|
+
pkg={pkg}
|
|
24
|
+
baseUrl={baseUrl}
|
|
25
|
+
showOwner={true}
|
|
26
|
+
/>
|
|
27
|
+
))}
|
|
28
|
+
</div>
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const LoadingState = () => (
|
|
32
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
33
|
+
{[...Array(6)].map((_, i) => (
|
|
34
|
+
<PackageCardSkeleton key={i} />
|
|
35
|
+
))}
|
|
36
|
+
</div>
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
const ErrorState = () => (
|
|
40
|
+
<div className="bg-red-50 border border-red-200 text-red-700 p-6 rounded-xl shadow-sm max-w-2xl mx-auto">
|
|
41
|
+
<div className="flex items-start">
|
|
42
|
+
<div className="mr-4 bg-red-100 p-2 rounded-full">
|
|
43
|
+
<Search className="w-6 h-6 text-red-600" />
|
|
44
|
+
</div>
|
|
45
|
+
<div>
|
|
46
|
+
<h3 className="text-lg font-semibold mb-2">Error Loading packages</h3>
|
|
47
|
+
<p className="text-red-600">
|
|
48
|
+
We couldn't load the trending packages. Please try again later.
|
|
49
|
+
</p>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
const EmptyState = ({
|
|
56
|
+
message,
|
|
57
|
+
}: {
|
|
58
|
+
message?: string
|
|
59
|
+
}) => (
|
|
60
|
+
<div className="text-center py-12 px-4">
|
|
61
|
+
<div className="bg-slate-50 inline-flex rounded-full p-4 mb-4">
|
|
62
|
+
<Search className="w-8 h-8 text-slate-400" />
|
|
63
|
+
</div>
|
|
64
|
+
<h3 className="text-xl font-medium text-slate-900 mb-2">
|
|
65
|
+
No Matching Packages
|
|
66
|
+
</h3>
|
|
67
|
+
{message && (
|
|
68
|
+
<p className="text-slate-500 max-w-md mx-auto mb-6">{message}</p>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
const PackageSearchResults: React.FC<PackageSearchResultsProps> = ({
|
|
74
|
+
isLoading,
|
|
75
|
+
error,
|
|
76
|
+
filteredPackages,
|
|
77
|
+
apiBaseUrl,
|
|
78
|
+
emptyStateMessage,
|
|
79
|
+
}) => {
|
|
80
|
+
if (isLoading) return <LoadingState />
|
|
81
|
+
if (error) return <ErrorState />
|
|
82
|
+
if (!filteredPackages?.length)
|
|
83
|
+
return <EmptyState message={emptyStateMessage} />
|
|
84
|
+
return <PackageGrid packages={filteredPackages} baseUrl={apiBaseUrl} />
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export default PackageSearchResults
|
|
@@ -3,7 +3,7 @@ import { ChevronDown, ChevronUp, Star } from "lucide-react"
|
|
|
3
3
|
import { Link } from "wouter"
|
|
4
4
|
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
5
5
|
|
|
6
|
-
interface
|
|
6
|
+
interface PackagesListProps {
|
|
7
7
|
title: string
|
|
8
8
|
packages?: Package[]
|
|
9
9
|
showAll?: boolean
|
|
@@ -11,13 +11,13 @@ interface PackageListProps {
|
|
|
11
11
|
maxItems?: number
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export const
|
|
14
|
+
export const PackagesList = ({
|
|
15
15
|
title,
|
|
16
16
|
packages = [],
|
|
17
17
|
showAll = false,
|
|
18
18
|
onToggleShowAll,
|
|
19
19
|
maxItems = 5,
|
|
20
|
-
}:
|
|
20
|
+
}: PackagesListProps) => {
|
|
21
21
|
const displayedPackages = showAll ? packages : packages.slice(0, maxItems)
|
|
22
22
|
|
|
23
23
|
return (
|
|
@@ -5,9 +5,9 @@ import React, { useState } from "react"
|
|
|
5
5
|
import { useQuery } from "react-query"
|
|
6
6
|
import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
|
|
7
7
|
import { Search } from "lucide-react"
|
|
8
|
-
import { SnippetCard } from "./SnippetCard"
|
|
9
8
|
import { Button } from "./ui/button"
|
|
10
9
|
import { PackageCardSkeleton } from "./PackageCardSkeleton"
|
|
10
|
+
import { PackageCard } from "./PackageCard"
|
|
11
11
|
|
|
12
12
|
interface PageSearchComponentProps {
|
|
13
13
|
onResultsFetched?: (results: any[]) => void
|
|
@@ -28,16 +28,16 @@ const PageSearchComponent: React.FC<PageSearchComponentProps> = ({
|
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
const { data: searchResults, isLoading: isLoadingSearchResults } = useQuery(
|
|
31
|
-
["
|
|
31
|
+
["packageSearch", searchQuery],
|
|
32
32
|
async () => {
|
|
33
33
|
if (!searchQuery) return []
|
|
34
|
-
const { data } = await axios.get("/
|
|
34
|
+
const { data } = await axios.get("/packages/search", {
|
|
35
35
|
params: { q: searchQuery },
|
|
36
36
|
})
|
|
37
37
|
if (onResultsFetched) {
|
|
38
|
-
onResultsFetched(data.
|
|
38
|
+
onResultsFetched(data.packages)
|
|
39
39
|
}
|
|
40
|
-
return data.
|
|
40
|
+
return data.packages
|
|
41
41
|
},
|
|
42
42
|
{ enabled: Boolean(searchQuery) },
|
|
43
43
|
)
|
|
@@ -94,10 +94,10 @@ const PageSearchComponent: React.FC<PageSearchComponentProps> = ({
|
|
|
94
94
|
</div>
|
|
95
95
|
) : searchResults && searchResults.length > 0 ? (
|
|
96
96
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
97
|
-
{searchResults.map((
|
|
98
|
-
<
|
|
99
|
-
key={
|
|
100
|
-
|
|
97
|
+
{searchResults.map((pkg: any) => (
|
|
98
|
+
<PackageCard
|
|
99
|
+
key={pkg.package_id}
|
|
100
|
+
pkg={pkg}
|
|
101
101
|
baseUrl={snippetsBaseApiUrl}
|
|
102
102
|
showOwner={true}
|
|
103
103
|
withLink={true}
|
|
@@ -1,43 +1,20 @@
|
|
|
1
|
+
import { useShikiHighlighter } from "@/hooks/use-shiki-highlighter"
|
|
1
2
|
import { useEffect, useMemo } from "react"
|
|
2
3
|
import { useQuery } from "react-query"
|
|
3
|
-
import { createHighlighter, Highlighter } from "shiki"
|
|
4
|
-
|
|
5
|
-
let globalHighlighter$: any
|
|
6
|
-
let globalHighlighter: Highlighter
|
|
7
|
-
|
|
8
|
-
const fileExtensionsToLanguages = {
|
|
9
|
-
ts: "typescript",
|
|
10
|
-
tsx: "typescript",
|
|
11
|
-
js: "javascript",
|
|
12
|
-
jsx: "javascript",
|
|
13
|
-
}
|
|
14
4
|
|
|
15
5
|
export const ShikiCodeViewer = ({
|
|
16
6
|
code,
|
|
17
7
|
filePath,
|
|
18
8
|
}: { code: string; filePath: string }) => {
|
|
19
|
-
|
|
20
|
-
async function setupHighlighter() {
|
|
21
|
-
if (globalHighlighter$) return
|
|
22
|
-
globalHighlighter$ = await createHighlighter({
|
|
23
|
-
langs: ["typescript"],
|
|
24
|
-
themes: ["vitesse-light"],
|
|
25
|
-
})
|
|
26
|
-
globalHighlighter = await globalHighlighter$
|
|
27
|
-
}
|
|
28
|
-
setupHighlighter()
|
|
29
|
-
}, [])
|
|
9
|
+
const { highlighter } = useShikiHighlighter()
|
|
30
10
|
|
|
31
11
|
const html = useMemo(
|
|
32
12
|
() =>
|
|
33
|
-
|
|
34
|
-
lang:
|
|
35
|
-
fileExtensionsToLanguages[
|
|
36
|
-
filePath.split(".").pop() as keyof typeof fileExtensionsToLanguages
|
|
37
|
-
] || "typescript",
|
|
13
|
+
highlighter?.codeToHtml(code, {
|
|
14
|
+
lang: "tsx",
|
|
38
15
|
theme: "vitesse-light",
|
|
39
16
|
}),
|
|
40
|
-
[filePath, code,
|
|
17
|
+
[filePath, code, highlighter],
|
|
41
18
|
)
|
|
42
19
|
|
|
43
20
|
if (!html) {
|
|
@@ -87,14 +87,14 @@ export default function MainContentHeader({
|
|
|
87
87
|
</Button>
|
|
88
88
|
</DropdownMenuTrigger>
|
|
89
89
|
<DropdownMenuContent align="end" className="w-72">
|
|
90
|
-
<DropdownMenuItem
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
90
|
+
<DropdownMenuItem asChild>
|
|
91
|
+
<a
|
|
92
|
+
href={`/editor?package_id=${packageInfo?.package_id}`}
|
|
93
|
+
className="cursor-pointer p-2 py-4"
|
|
94
|
+
>
|
|
95
|
+
<Pencil className="h-4 w-4 mx-3" />
|
|
96
|
+
Edit Online
|
|
97
|
+
</a>
|
|
98
98
|
</DropdownMenuItem>
|
|
99
99
|
<DropdownMenuSeparator />
|
|
100
100
|
|
|
@@ -6,21 +6,20 @@ import { usePreviewImages } from "@/hooks/use-preview-images"
|
|
|
6
6
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
7
7
|
import { Button } from "@/components/ui/button"
|
|
8
8
|
import { useEditPackageDetailsDialog } from "@/components/dialogs/edit-package-details-dialog"
|
|
9
|
-
import { useState, useEffect, useMemo } from "react"
|
|
9
|
+
import React, { useState, useEffect, useMemo, useCallback } from "react"
|
|
10
10
|
import { useCurrentPackageInfo } from "@/hooks/use-current-package-info"
|
|
11
11
|
import { usePackageFile } from "@/hooks/use-package-files"
|
|
12
12
|
import { getLicenseFromLicenseContent } from "@/lib/getLicenseFromLicenseContent"
|
|
13
|
-
import { PackageInfo } from "@/lib/types"
|
|
14
13
|
|
|
15
14
|
interface MobileSidebarProps {
|
|
16
15
|
isLoading?: boolean
|
|
17
16
|
onViewChange: (view: "schematic" | "pcb" | "3d") => void
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
const MobileSidebar = ({
|
|
21
20
|
isLoading = false,
|
|
22
21
|
onViewChange,
|
|
23
|
-
}: MobileSidebarProps) {
|
|
22
|
+
}: MobileSidebarProps) => {
|
|
24
23
|
const { packageInfo, refetch: refetchPackageInfo } = useCurrentPackageInfo()
|
|
25
24
|
const { data: licenseFileMeta } = usePackageFile({
|
|
26
25
|
package_release_id: packageInfo?.latest_package_release_id ?? "",
|
|
@@ -34,8 +33,11 @@ export default function MobileSidebar({
|
|
|
34
33
|
return getLicenseFromLicenseContent(licenseFileMeta?.content_text)
|
|
35
34
|
}
|
|
36
35
|
return undefined
|
|
37
|
-
}, [licenseFileMeta?.content_text])
|
|
38
|
-
const topics =
|
|
36
|
+
}, [licenseFileMeta?.content_text, packageInfo?.latest_license])
|
|
37
|
+
const topics = useMemo(
|
|
38
|
+
() => (packageInfo?.is_package ? ["Package"] : ["Board"]),
|
|
39
|
+
[packageInfo?.is_package],
|
|
40
|
+
)
|
|
39
41
|
const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
|
|
40
42
|
const isOwner =
|
|
41
43
|
isLoggedIn &&
|
|
@@ -59,20 +61,26 @@ export default function MobileSidebar({
|
|
|
59
61
|
}
|
|
60
62
|
}, [packageInfo])
|
|
61
63
|
|
|
62
|
-
const handlePackageUpdate = (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
const handlePackageUpdate = useCallback(
|
|
65
|
+
(newDescription: string, newWebsite: string) => {
|
|
66
|
+
setLocalDescription(newDescription)
|
|
67
|
+
setLocalWebsite(newWebsite)
|
|
68
|
+
refetchPackageInfo()
|
|
69
|
+
},
|
|
70
|
+
[refetchPackageInfo],
|
|
71
|
+
)
|
|
67
72
|
|
|
68
73
|
const { availableViews } = usePreviewImages({
|
|
69
74
|
packageName: packageInfo?.name,
|
|
70
75
|
fsMapHash: packageInfo?.latest_package_release_id ?? "",
|
|
71
76
|
})
|
|
72
77
|
|
|
73
|
-
const handleViewClick = (
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
const handleViewClick = useCallback(
|
|
79
|
+
(viewId: string) => {
|
|
80
|
+
onViewChange?.(viewId as "3d" | "pcb" | "schematic")
|
|
81
|
+
},
|
|
82
|
+
[onViewChange],
|
|
83
|
+
)
|
|
76
84
|
|
|
77
85
|
if (isLoading) {
|
|
78
86
|
return (
|
|
@@ -209,6 +217,8 @@ export default function MobileSidebar({
|
|
|
209
217
|
)
|
|
210
218
|
}
|
|
211
219
|
|
|
220
|
+
export default React.memo(MobileSidebar)
|
|
221
|
+
|
|
212
222
|
function PreviewButton({
|
|
213
223
|
view,
|
|
214
224
|
onClick,
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
import { useOrderDialog } from "@tscircuit/runframe"
|
|
22
22
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
23
23
|
import { Package as PackageType } from "fake-snippets-api/lib/db/schema"
|
|
24
|
+
import { useSignIn } from "@/hooks/use-sign-in"
|
|
24
25
|
|
|
25
26
|
interface PackageHeaderProps {
|
|
26
27
|
packageInfo?: PackageType
|
|
@@ -40,7 +41,11 @@ export default function PackageHeader({
|
|
|
40
41
|
packageInfo?.owner_github_username ===
|
|
41
42
|
useGlobalStore((s) => s.session?.github_username)
|
|
42
43
|
const isLoggedIn = useGlobalStore((s) => s.session != null)
|
|
43
|
-
const
|
|
44
|
+
const signIn = useSignIn()
|
|
45
|
+
const { OrderDialog, isOpen, open, close, stage, setStage } = useOrderDialog({
|
|
46
|
+
onSignIn: signIn,
|
|
47
|
+
isLoggedIn,
|
|
48
|
+
})
|
|
44
49
|
const { data: starData, isLoading: isStarDataLoading } =
|
|
45
50
|
usePackageStarsByName(packageInfo?.name ?? null)
|
|
46
51
|
const { addStar, removeStar } = usePackageStarMutationByName(
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "@valtown/codemirror-ts"
|
|
24
24
|
import { EditorView } from "codemirror"
|
|
25
25
|
import { useEffect, useMemo, useRef, useState } from "react"
|
|
26
|
-
import
|
|
26
|
+
import tsModule from "typescript"
|
|
27
27
|
import CodeEditorHeader from "@/components/package-port/CodeEditorHeader"
|
|
28
28
|
import { useCodeCompletionApi } from "@/hooks/use-code-completion-ai-api"
|
|
29
29
|
import FileSidebar from "../FileSidebar"
|
|
@@ -134,10 +134,10 @@ export const CodeEditor = ({
|
|
|
134
134
|
;(window as any).__DEBUG_CODE_EDITOR_FS_MAP = fsMap
|
|
135
135
|
|
|
136
136
|
createDefaultMapFromCDN(
|
|
137
|
-
{ target:
|
|
137
|
+
{ target: tsModule.ScriptTarget.ES2022 },
|
|
138
138
|
"5.6.3",
|
|
139
139
|
true,
|
|
140
|
-
|
|
140
|
+
tsModule,
|
|
141
141
|
).then((defaultFsMap) => {
|
|
142
142
|
defaultFsMap.forEach((content, filename) => {
|
|
143
143
|
fsMap.set(filename, content)
|
|
@@ -145,11 +145,12 @@ export const CodeEditor = ({
|
|
|
145
145
|
})
|
|
146
146
|
|
|
147
147
|
const system = createSystem(fsMap)
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
|
|
149
|
+
const env = createVirtualTypeScriptEnvironment(system, [], tsModule, {
|
|
150
|
+
jsx: tsModule.JsxEmit.ReactJSX,
|
|
150
151
|
declaration: true,
|
|
151
152
|
allowJs: true,
|
|
152
|
-
target:
|
|
153
|
+
target: tsModule.ScriptTarget.ES2022,
|
|
153
154
|
resolveJsonModule: true,
|
|
154
155
|
})
|
|
155
156
|
|
|
@@ -160,7 +161,7 @@ export const CodeEditor = ({
|
|
|
160
161
|
// Initialize ATA
|
|
161
162
|
const ataConfig: ATABootstrapConfig = {
|
|
162
163
|
projectName: "my-project",
|
|
163
|
-
typescript:
|
|
164
|
+
typescript: tsModule,
|
|
164
165
|
logger: console,
|
|
165
166
|
fetcher: async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
166
167
|
const registryPrefixes = [
|
|
@@ -336,12 +337,14 @@ export const CodeEditor = ({
|
|
|
336
337
|
|
|
337
338
|
const start = info.textSpan.start
|
|
338
339
|
const end = start + info.textSpan.length
|
|
339
|
-
const content =
|
|
340
|
+
const content = tsModule?.displayPartsToString(
|
|
341
|
+
info.displayParts || [],
|
|
342
|
+
)
|
|
340
343
|
|
|
341
344
|
const dom = document.createElement("div")
|
|
342
345
|
if (highlighter) {
|
|
343
346
|
dom.innerHTML = highlighter.codeToHtml(content, {
|
|
344
|
-
lang: "
|
|
347
|
+
lang: "tsx",
|
|
345
348
|
themes: {
|
|
346
349
|
light: "github-light",
|
|
347
350
|
dark: "github-dark",
|
|
@@ -456,7 +459,7 @@ export const CodeEditor = ({
|
|
|
456
459
|
return () => {
|
|
457
460
|
view.destroy()
|
|
458
461
|
}
|
|
459
|
-
}, [!isStreaming, currentFile, code !== ""])
|
|
462
|
+
}, [!isStreaming, currentFile, code !== "", Boolean(highlighter)])
|
|
460
463
|
|
|
461
464
|
const updateCurrentEditorContent = (newContent: string) => {
|
|
462
465
|
if (viewRef.current) {
|
|
@@ -101,7 +101,7 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
101
101
|
markdown: "markdown",
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
const parser = parserMap[fileExtension] || "
|
|
104
|
+
const parser = parserMap[fileExtension] || "tsx"
|
|
105
105
|
const formattedCode = window.prettier.format(currentContent, {
|
|
106
106
|
semi: false,
|
|
107
107
|
parser: parser,
|
|
@@ -315,7 +315,7 @@ export default function EditorNav({
|
|
|
315
315
|
<div className="flex items-center justify-end -space-x-1">
|
|
316
316
|
<div className="flex mx-2 items-center space-x-1">
|
|
317
317
|
{pkg && <TypeBadge type={`${packageType ?? pkg.snippet_type}`} />}
|
|
318
|
-
<Button
|
|
318
|
+
{/* <Button
|
|
319
319
|
variant="ghost"
|
|
320
320
|
size="sm"
|
|
321
321
|
disabled={hasUnsavedChanges || isSaving || !pkg}
|
|
@@ -323,7 +323,7 @@ export default function EditorNav({
|
|
|
323
323
|
>
|
|
324
324
|
<Sparkles className="mr-1 h-3 w-3" />
|
|
325
325
|
Edit with AI
|
|
326
|
-
</Button>
|
|
326
|
+
</Button> */}
|
|
327
327
|
<DownloadButtonAndMenu
|
|
328
328
|
snippetUnscopedName={pkg?.unscoped_name}
|
|
329
329
|
circuitJson={circuitJson}
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import { useState, useEffect } from "react"
|
|
2
|
-
import {
|
|
2
|
+
import { createHighlighterCore, type HighlighterCore } from "shiki/core"
|
|
3
|
+
import { createOnigurumaEngine } from "shiki/engine/oniguruma"
|
|
3
4
|
|
|
4
|
-
let cachedHighlighter:
|
|
5
|
+
let cachedHighlighter: HighlighterCore | null = null
|
|
5
6
|
|
|
6
7
|
export const useShikiHighlighter = () => {
|
|
7
|
-
const [highlighter, setHighlighter] = useState<
|
|
8
|
+
const [highlighter, setHighlighter] = useState<HighlighterCore | null>(null)
|
|
8
9
|
const [isLoading, setIsLoading] = useState(true)
|
|
9
10
|
|
|
10
11
|
useEffect(() => {
|
|
11
12
|
const fetchHighlighter = async () => {
|
|
12
13
|
if (!cachedHighlighter) {
|
|
13
|
-
cachedHighlighter = await
|
|
14
|
-
themes: [
|
|
15
|
-
|
|
14
|
+
cachedHighlighter = await createHighlighterCore({
|
|
15
|
+
themes: [
|
|
16
|
+
import("@shikijs/themes/github-dark"),
|
|
17
|
+
import("@shikijs/themes/github-light"),
|
|
18
|
+
import("@shikijs/themes/vitesse-light"),
|
|
19
|
+
],
|
|
20
|
+
langs: [import("@shikijs/langs/tsx")],
|
|
21
|
+
// `shiki/wasm` contains the wasm binary inlined as base64 string.
|
|
22
|
+
engine: createOnigurumaEngine(import("shiki/wasm")),
|
|
16
23
|
})
|
|
17
24
|
}
|
|
18
25
|
setHighlighter(cachedHighlighter)
|
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
import { AnyCircuitElement } from "circuit-json"
|
|
2
|
-
import { convertCircuitJsonToAssemblySvg } from "circuit-to-svg"
|
|
3
1
|
import { GLTFExporter, type GLTFExporterOptions } from "three-stdlib"
|
|
4
2
|
import { saveAs } from "file-saver"
|
|
5
3
|
import * as THREE from "three"
|
|
6
4
|
|
|
7
|
-
export const downloadGltf = async (
|
|
8
|
-
|
|
9
|
-
fileName: string,
|
|
10
|
-
) => {
|
|
11
|
-
const threeJsObject = window.TSCIRCUIT_3D_OBJECT_REF
|
|
12
|
-
?.current as THREE.Object3D
|
|
13
|
-
|
|
5
|
+
export const downloadGltf = async (fileName: string) => {
|
|
6
|
+
const threeJsObject = window.TSCIRCUIT_3D_OBJECT_REF as THREE.Object3D
|
|
14
7
|
if (!threeJsObject) {
|
|
15
8
|
throw new Error(
|
|
16
|
-
"To download the 3D model, please open the 3D view first and run the
|
|
9
|
+
"To download the 3D model, please open the 3D view first and run the package",
|
|
17
10
|
)
|
|
18
11
|
}
|
|
19
12
|
|
package/src/lib/types.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { Object3D, Object3DEventMap } from "three"
|
|
2
|
+
|
|
1
3
|
declare global {
|
|
2
4
|
interface Window {
|
|
3
5
|
TSCIRCUIT_REGISTRY_API_BASE_URL: string
|
|
4
|
-
TSCIRCUIT_REGISTRY_TOKEN: string
|
|
6
|
+
TSCIRCUIT_REGISTRY_TOKEN: string | null
|
|
5
7
|
TSCIRCUIT_STRIPE_CHECKOUT_BASE_URL: string
|
|
6
|
-
TSCIRCUIT_3D_OBJECT_REF:
|
|
8
|
+
TSCIRCUIT_3D_OBJECT_REF: Object3D<Object3DEventMap> | undefined
|
|
7
9
|
__DEBUG_CODE_EDITOR_FS_MAP: Map<string, string>
|
|
8
10
|
prettier: {
|
|
9
11
|
format: (code: string, options: any) => string
|
package/src/pages/dashboard.tsx
CHANGED
|
@@ -9,8 +9,7 @@ import { Edit2, KeyRound } from "lucide-react"
|
|
|
9
9
|
import { Button } from "@/components/ui/button"
|
|
10
10
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
11
11
|
import { PrefetchPageLink } from "@/components/PrefetchPageLink"
|
|
12
|
-
import {
|
|
13
|
-
import { SnippetList } from "@/components/SnippetList"
|
|
12
|
+
import { PackagesList } from "@/components/PackagesList"
|
|
14
13
|
import { Helmet } from "react-helmet-async"
|
|
15
14
|
import { useSignIn } from "@/hooks/use-sign-in"
|
|
16
15
|
import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
|
|
@@ -175,14 +174,14 @@ export const DashboardPage = () => {
|
|
|
175
174
|
)}
|
|
176
175
|
</div>
|
|
177
176
|
<div className="md:w-1/4">
|
|
178
|
-
<
|
|
177
|
+
<PackagesList
|
|
179
178
|
title="Trending Packages"
|
|
180
179
|
packages={trendingPackages}
|
|
181
180
|
showAll={showAllTrending}
|
|
182
181
|
onToggleShowAll={() => setShowAllTrending(!showAllTrending)}
|
|
183
182
|
/>
|
|
184
183
|
<div className="mt-8">
|
|
185
|
-
<
|
|
184
|
+
<PackagesList
|
|
186
185
|
title="Latest Packages"
|
|
187
186
|
packages={latestPackages}
|
|
188
187
|
showAll={showAllLatest}
|
package/src/pages/editor.tsx
CHANGED
|
@@ -1,45 +1,51 @@
|
|
|
1
|
-
import { CodeAndPreview } from "@/components/CodeAndPreview"
|
|
1
|
+
import { CodeAndPreview } from "@/components/package-port/CodeAndPreview"
|
|
2
2
|
import Footer from "@/components/Footer"
|
|
3
3
|
import Header from "@/components/Header"
|
|
4
|
-
import { useCurrentSnippetId } from "@/hooks/use-current-snippet-id"
|
|
5
|
-
import { useSnippet } from "@/hooks/use-snippet"
|
|
6
4
|
import { Helmet } from "react-helmet-async"
|
|
5
|
+
import { useCurrentPackageId } from "@/hooks/use-current-package-id"
|
|
6
|
+
import { usePackage } from "@/hooks/use-package"
|
|
7
|
+
import { useGetFsMapHashForPackage } from "@/hooks/use-get-fsmap-hash-for-package"
|
|
7
8
|
|
|
8
9
|
export const EditorPage = () => {
|
|
9
|
-
const {
|
|
10
|
-
const { data:
|
|
10
|
+
const { packageId } = useCurrentPackageId()
|
|
11
|
+
const { data: pkg, isLoading, error } = usePackage(packageId)
|
|
12
|
+
const fsMapHash = useGetFsMapHashForPackage(
|
|
13
|
+
pkg?.latest_package_release_id ?? "",
|
|
14
|
+
)
|
|
11
15
|
|
|
12
16
|
return (
|
|
13
17
|
<div className="overflow-x-hidden">
|
|
14
18
|
<Helmet>
|
|
15
19
|
<title>
|
|
16
|
-
{
|
|
17
|
-
? `${snippet.unscoped_name} - tscircuit`
|
|
18
|
-
: "tscircuit editor"}
|
|
20
|
+
{pkg ? `${pkg.unscoped_name} - tscircuit` : "tscircuit editor"}
|
|
19
21
|
</title>
|
|
20
|
-
{
|
|
22
|
+
{pkg && (
|
|
21
23
|
<>
|
|
22
24
|
<meta
|
|
23
25
|
property="og:title"
|
|
24
|
-
content={`${
|
|
26
|
+
content={`${pkg.unscoped_name} - tscircuit`}
|
|
25
27
|
/>
|
|
26
28
|
<meta
|
|
27
29
|
property="og:image"
|
|
28
|
-
content={`https://registry-api.tscircuit.com/
|
|
30
|
+
content={`https://registry-api.tscircuit.com/packages/images/${pkg.owner_github_username}/${pkg.unscoped_name}/pcb.png?${new URLSearchParams(
|
|
31
|
+
{
|
|
32
|
+
fs_sha: fsMapHash ?? "",
|
|
33
|
+
},
|
|
34
|
+
).toString()}`}
|
|
29
35
|
/>
|
|
30
36
|
<meta name="twitter:card" content="summary_large_image" />
|
|
31
37
|
<meta
|
|
32
38
|
name="twitter:image"
|
|
33
|
-
content={`https://registry-api.tscircuit.com/
|
|
39
|
+
content={`https://registry-api.tscircuit.com/packages/images/${pkg.owner_github_username}/${pkg.unscoped_name}/pcb.png`}
|
|
34
40
|
/>
|
|
35
41
|
</>
|
|
36
42
|
)}
|
|
37
43
|
</Helmet>
|
|
38
44
|
<Header />
|
|
39
|
-
{!error && <CodeAndPreview
|
|
45
|
+
{!error && <CodeAndPreview pkg={pkg} />}
|
|
40
46
|
{error && error.status === 404 && (
|
|
41
47
|
<div className="w-full h-[calc(100vh-20rem)] text-xl text-center flex justify-center items-center">
|
|
42
|
-
|
|
48
|
+
Package not found
|
|
43
49
|
</div>
|
|
44
50
|
)}
|
|
45
51
|
{error && error.status !== 404 && (
|