@tscircuit/fake-snippets 0.0.65 → 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/CONTRIBUTING.md +2 -2
- package/README.md +2 -2
- 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 +1 -16
- package/bun.lock +42 -31
- package/dist/bundle.js +34 -41
- 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/fake-snippets-api/routes/api/packages/images/[owner_github_username]/[unscoped_name]/[view_format].ts +3 -3
- package/package.json +7 -5
- package/src/App.tsx +0 -7
- package/src/ContextProviders.tsx +2 -0
- package/src/components/DownloadButtonAndMenu.tsx +1 -4
- package/src/components/ErrorTabContent.tsx +1 -1
- 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 +12 -3
- 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/ShippingInformationForm.tsx +1 -1
- package/src/components/TrendingPackagesCarousel.tsx +43 -23
- package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +5 -28
- package/src/components/ViewPackagePage/components/main-content-header.tsx +10 -22
- package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +25 -14
- package/src/components/ViewPackagePage/components/package-header.tsx +9 -4
- package/src/components/ViewPackagePage/components/preview-image-squares.tsx +6 -1
- package/src/components/ViewPackagePage/components/repo-page-content.tsx +4 -4
- package/src/components/ViewPackagePage/components/sidebar.tsx +2 -14
- package/src/components/ViewSnippetSidebar.tsx +1 -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-get-fsmap-hash-for-package.ts +19 -0
- package/src/hooks/use-global-store.ts +1 -0
- package/src/hooks/use-preview-images.ts +20 -4
- package/src/hooks/use-shiki-highlighter.ts +13 -6
- package/src/hooks/use-toast.tsx +1 -1
- 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/package-editor.tsx +14 -2
- package/src/pages/search.tsx +120 -19
- package/src/pages/trending.tsx +14 -59
- 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}
|
|
@@ -154,7 +154,7 @@ const ShippingInformationForm: React.FC = () => {
|
|
|
154
154
|
<AlertDescription>
|
|
155
155
|
Currently, only shipping to the US is supported.{" "}
|
|
156
156
|
<a
|
|
157
|
-
href={`https://github.com/tscircuit/
|
|
157
|
+
href={`https://github.com/tscircuit/tscircuit.com/issues/new?title=${encodeURIComponent("Shipping to " + form.country)}&body=${encodeURIComponent("Please add support for shipping to " + form.country + ".")}`}
|
|
158
158
|
target="_blank"
|
|
159
159
|
rel="noopener noreferrer"
|
|
160
160
|
className="font-medium underline"
|
|
@@ -2,10 +2,46 @@ import { useQuery } from "react-query"
|
|
|
2
2
|
import { useAxios } from "@/hooks/use-axios"
|
|
3
3
|
import { StarFilledIcon } from "@radix-ui/react-icons"
|
|
4
4
|
import { Link } from "wouter"
|
|
5
|
-
import { Package
|
|
6
|
-
import {
|
|
5
|
+
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
6
|
+
import { useRef, useState } from "react"
|
|
7
7
|
import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
|
|
8
|
-
import {
|
|
8
|
+
import { useGetFsMapHashForPackage } from "@/hooks/use-get-fsmap-hash-for-package"
|
|
9
|
+
|
|
10
|
+
const CarouselItem = ({
|
|
11
|
+
pkg,
|
|
12
|
+
apiBaseUrl,
|
|
13
|
+
}: { pkg: Package; apiBaseUrl: string }) => {
|
|
14
|
+
const fsMapHash = useGetFsMapHashForPackage(
|
|
15
|
+
pkg.latest_package_release_id ?? "",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Link href={`/${pkg.owner_github_username}/${pkg.unscoped_name}`}>
|
|
20
|
+
<div className="flex-shrink-0 w-[200px] bg-white p-3 py-2 rounded-lg shadow-sm border border-gray-200 hover:border-gray-300 transition-colors">
|
|
21
|
+
<div className="font-medium text-blue-600 mb-1 truncate text-sm">
|
|
22
|
+
{pkg.owner_github_username}/{pkg.unscoped_name}
|
|
23
|
+
</div>
|
|
24
|
+
<div className="mb-2 h-24 w-full bg-black rounded overflow-hidden">
|
|
25
|
+
{fsMapHash && (
|
|
26
|
+
<img
|
|
27
|
+
src={`${apiBaseUrl}/packages/images/${pkg.owner_github_username}/${pkg.unscoped_name}/pcb.svg?${new URLSearchParams(
|
|
28
|
+
{
|
|
29
|
+
fs_sha: fsMapHash,
|
|
30
|
+
},
|
|
31
|
+
).toString()}`}
|
|
32
|
+
alt="PCB preview"
|
|
33
|
+
className="w-full h-full object-contain p-2 scale-[3] rotate-45 hover:scale-[3.5] transition-transform"
|
|
34
|
+
/>
|
|
35
|
+
)}
|
|
36
|
+
</div>
|
|
37
|
+
<div className="flex items-center text-xs text-gray-500">
|
|
38
|
+
<StarFilledIcon className="w-3 h-3 mr-1" />
|
|
39
|
+
{pkg.star_count || 0} stars
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</Link>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
9
45
|
|
|
10
46
|
export const TrendingPackagesCarousel = () => {
|
|
11
47
|
const axios = useAxios()
|
|
@@ -45,27 +81,11 @@ export const TrendingPackagesCarousel = () => {
|
|
|
45
81
|
>
|
|
46
82
|
{[...(trendingPackages ?? []), ...(trendingPackages ?? [])].map(
|
|
47
83
|
(pkg, i) => (
|
|
48
|
-
<
|
|
84
|
+
<CarouselItem
|
|
49
85
|
key={`${pkg.package_id}-${i}`}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
<div className="font-medium text-blue-600 mb-1 truncate text-sm">
|
|
54
|
-
{pkg.owner_github_username}/{pkg.unscoped_name}
|
|
55
|
-
</div>
|
|
56
|
-
<div className="mb-2 h-24 w-full bg-black rounded overflow-hidden">
|
|
57
|
-
<OptimizedImage
|
|
58
|
-
src={`${apiBaseUrl}/snippets/images/${pkg.owner_github_username}/${pkg.unscoped_name}/pcb.svg`}
|
|
59
|
-
alt="PCB preview"
|
|
60
|
-
className="w-full h-full object-contain p-2 scale-[3] rotate-45 hover:scale-[3.5] transition-transform"
|
|
61
|
-
/>
|
|
62
|
-
</div>
|
|
63
|
-
<div className="flex items-center text-xs text-gray-500">
|
|
64
|
-
<StarFilledIcon className="w-3 h-3 mr-1" />
|
|
65
|
-
{pkg.star_count || 0} stars
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
</Link>
|
|
86
|
+
pkg={pkg}
|
|
87
|
+
apiBaseUrl={apiBaseUrl}
|
|
88
|
+
/>
|
|
69
89
|
),
|
|
70
90
|
)}
|
|
71
91
|
</div>
|
|
@@ -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) {
|
|
@@ -24,24 +24,12 @@ import {
|
|
|
24
24
|
import { DownloadButtonAndMenu } from "@/components/DownloadButtonAndMenu"
|
|
25
25
|
import { useCurrentPackageCircuitJson } from "../hooks/use-current-package-circuit-json"
|
|
26
26
|
import { useLocation } from "wouter"
|
|
27
|
-
|
|
28
|
-
interface PackageInfo {
|
|
29
|
-
package_id: string
|
|
30
|
-
name: string
|
|
31
|
-
unscoped_name: string
|
|
32
|
-
owner_github_username: string
|
|
33
|
-
star_count: string
|
|
34
|
-
description: string
|
|
35
|
-
ai_description: string
|
|
36
|
-
creator_account_id?: string
|
|
37
|
-
owner_org_id?: string
|
|
38
|
-
}
|
|
39
|
-
|
|
27
|
+
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
40
28
|
interface MainContentHeaderProps {
|
|
41
29
|
activeView: string
|
|
42
30
|
onViewChange: (view: string) => void
|
|
43
31
|
onExportClicked?: (exportType: string) => void
|
|
44
|
-
packageInfo?:
|
|
32
|
+
packageInfo?: Package
|
|
45
33
|
}
|
|
46
34
|
|
|
47
35
|
export default function MainContentHeader({
|
|
@@ -99,14 +87,14 @@ export default function MainContentHeader({
|
|
|
99
87
|
</Button>
|
|
100
88
|
</DropdownMenuTrigger>
|
|
101
89
|
<DropdownMenuContent align="end" className="w-72">
|
|
102
|
-
<DropdownMenuItem
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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>
|
|
110
98
|
</DropdownMenuItem>
|
|
111
99
|
<DropdownMenuSeparator />
|
|
112
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,19 +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,
|
|
75
|
+
fsMapHash: packageInfo?.latest_package_release_id ?? "",
|
|
70
76
|
})
|
|
71
77
|
|
|
72
|
-
const handleViewClick = (
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
const handleViewClick = useCallback(
|
|
79
|
+
(viewId: string) => {
|
|
80
|
+
onViewChange?.(viewId as "3d" | "pcb" | "schematic")
|
|
81
|
+
},
|
|
82
|
+
[onViewChange],
|
|
83
|
+
)
|
|
75
84
|
|
|
76
85
|
if (isLoading) {
|
|
77
86
|
return (
|
|
@@ -208,6 +217,8 @@ export default function MobileSidebar({
|
|
|
208
217
|
)
|
|
209
218
|
}
|
|
210
219
|
|
|
220
|
+
export default React.memo(MobileSidebar)
|
|
221
|
+
|
|
211
222
|
function PreviewButton({
|
|
212
223
|
view,
|
|
213
224
|
onClick,
|
|
@@ -20,10 +20,11 @@ import {
|
|
|
20
20
|
} from "@/hooks/use-package-stars"
|
|
21
21
|
import { useOrderDialog } from "@tscircuit/runframe"
|
|
22
22
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
23
|
-
import {
|
|
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
|
-
packageInfo?:
|
|
27
|
+
packageInfo?: PackageType
|
|
27
28
|
isPrivate?: boolean
|
|
28
29
|
isCurrentUserAuthor?: boolean
|
|
29
30
|
}
|
|
@@ -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(
|
|
@@ -254,7 +259,7 @@ export default function PackageHeader({
|
|
|
254
259
|
onClose={close}
|
|
255
260
|
stage={stage}
|
|
256
261
|
setStage={setStage}
|
|
257
|
-
packageReleaseId={packageInfo?.latest_package_release_id}
|
|
262
|
+
packageReleaseId={packageInfo?.latest_package_release_id ?? ""}
|
|
258
263
|
/>
|
|
259
264
|
</header>
|
|
260
265
|
)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import { Skeleton } from "@/components/ui/skeleton"
|
|
3
|
+
import { useGetFsMapHashForPackage } from "@/hooks/use-get-fsmap-hash-for-package"
|
|
3
4
|
import { usePreviewImages } from "@/hooks/use-preview-images"
|
|
4
5
|
import type { Package } from "fake-snippets-api/lib/db/schema"
|
|
5
6
|
|
|
6
7
|
interface ViewPlaceholdersProps {
|
|
7
|
-
packageInfo?: Pick<Package, "name">
|
|
8
|
+
packageInfo?: Pick<Package, "name" | "latest_package_release_id">
|
|
8
9
|
onViewChange?: (view: "3d" | "pcb" | "schematic") => void
|
|
9
10
|
}
|
|
10
11
|
|
|
@@ -12,8 +13,12 @@ export default function PreviewImageSquares({
|
|
|
12
13
|
packageInfo,
|
|
13
14
|
onViewChange,
|
|
14
15
|
}: ViewPlaceholdersProps) {
|
|
16
|
+
const fsMapHash = useGetFsMapHashForPackage(
|
|
17
|
+
packageInfo?.latest_package_release_id ?? "",
|
|
18
|
+
)
|
|
15
19
|
const { availableViews } = usePreviewImages({
|
|
16
20
|
packageName: packageInfo?.name,
|
|
21
|
+
fsMapHash: fsMapHash ?? "",
|
|
17
22
|
})
|
|
18
23
|
|
|
19
24
|
const handleViewClick = (viewId: string) => {
|
|
@@ -18,7 +18,7 @@ import Footer from "@/components/Footer"
|
|
|
18
18
|
import PackageHeader from "./package-header"
|
|
19
19
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
20
20
|
import { useLocation } from "wouter"
|
|
21
|
-
import {
|
|
21
|
+
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
22
22
|
|
|
23
23
|
interface PackageFile {
|
|
24
24
|
package_file_id: string
|
|
@@ -32,7 +32,7 @@ interface PackageFile {
|
|
|
32
32
|
interface RepoPageContentProps {
|
|
33
33
|
packageFiles?: PackageFile[]
|
|
34
34
|
importantFilePaths?: string[]
|
|
35
|
-
packageInfo?:
|
|
35
|
+
packageInfo?: Package
|
|
36
36
|
onFileClicked?: (file: PackageFile) => void
|
|
37
37
|
onEditClicked?: () => void
|
|
38
38
|
}
|
|
@@ -179,8 +179,8 @@ export default function RepoPageContent({
|
|
|
179
179
|
importantFiles={importantFiles}
|
|
180
180
|
isLoading={!packageFiles}
|
|
181
181
|
onEditClicked={onEditClicked}
|
|
182
|
-
aiDescription={packageInfo?.ai_description}
|
|
183
|
-
aiUsageInstructions={packageInfo?.ai_usage_instructions}
|
|
182
|
+
aiDescription={packageInfo?.ai_description ?? ""}
|
|
183
|
+
aiUsageInstructions={packageInfo?.ai_usage_instructions ?? ""}
|
|
184
184
|
/>
|
|
185
185
|
</div>
|
|
186
186
|
|
|
@@ -1,24 +1,12 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
4
4
|
import SidebarAboutSection from "./sidebar-about-section"
|
|
5
5
|
import SidebarReleasesSection from "./sidebar-releases-section"
|
|
6
6
|
import PreviewImageSquares from "./preview-image-squares"
|
|
7
|
-
import { PackageFile } from "fake-snippets-api/lib/db/schema"
|
|
8
|
-
|
|
9
|
-
interface PackageInfo {
|
|
10
|
-
name: string
|
|
11
|
-
unscoped_name: string
|
|
12
|
-
owner_github_username: string
|
|
13
|
-
star_count: string
|
|
14
|
-
description: string
|
|
15
|
-
ai_description: string
|
|
16
|
-
creator_account_id?: string
|
|
17
|
-
owner_org_id?: string
|
|
18
|
-
}
|
|
19
7
|
|
|
20
8
|
interface SidebarProps {
|
|
21
|
-
packageInfo?:
|
|
9
|
+
packageInfo?: Package
|
|
22
10
|
isLoading?: boolean
|
|
23
11
|
onViewChange?: (view: "3d" | "pcb" | "schematic") => void
|
|
24
12
|
}
|
|
@@ -87,7 +87,7 @@ export default function ViewSnippetSidebar({
|
|
|
87
87
|
Help us out!{" "}
|
|
88
88
|
<a
|
|
89
89
|
className="text-blue-500 hover:underline font-semibold"
|
|
90
|
-
href="https://github.com/tscircuit/
|
|
90
|
+
href="https://github.com/tscircuit/tscircuit.com"
|
|
91
91
|
>
|
|
92
92
|
Check out our Github
|
|
93
93
|
</a>
|
|
@@ -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}
|