@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.
- 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 +26 -75
- 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 -4
- package/src/App.tsx +0 -11
- package/src/ContextProviders.tsx +2 -0
- package/src/components/CmdKMenu.tsx +19 -19
- package/src/components/DownloadButtonAndMenu.tsx +1 -4
- package/src/components/FAQ.tsx +3 -1
- package/src/components/FileSidebar.tsx +50 -1
- package/src/components/Footer.tsx +5 -2
- package/src/components/Header2.tsx +20 -9
- package/src/components/HeaderLogin.tsx +37 -54
- package/src/components/ImageWithFallback.tsx +37 -0
- package/src/components/JLCPCBImportDialog.tsx +45 -29
- 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/important-files-view.tsx +1 -1
- 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 +7 -2
- package/src/components/dialogs/confirm-delete-package-dialog.tsx +8 -0
- package/src/components/dialogs/edit-package-details-dialog.tsx +145 -138
- package/src/components/package-port/CodeAndPreview.tsx +40 -19
- package/src/components/package-port/CodeEditor.tsx +21 -37
- package/src/components/package-port/CodeEditorHeader.tsx +1 -1
- package/src/components/package-port/EditorNav.tsx +3 -13
- package/src/hooks/use-global-store.ts +1 -0
- package/src/hooks/use-shiki-highlighter.ts +13 -6
- package/src/hooks/useFileManagement.ts +59 -0
- 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/lib/utils/isValidFileName.ts +5 -0
- package/src/pages/dashboard.tsx +4 -4
- package/src/pages/editor.tsx +20 -14
- package/src/pages/latest.tsx +25 -26
- package/src/pages/quickstart.tsx +5 -5
- package/src/pages/search.tsx +121 -20
- package/src/pages/trending.tsx +14 -58
- package/src/pages/user-profile.tsx +14 -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/OrderPreviewContent.tsx +0 -61
- package/src/components/PreviewContent.tsx +0 -372
- package/src/components/SnippetCard.tsx +0 -159
- package/src/components/SnippetList.tsx +0 -71
- package/src/components/ViewSnippetSidebar.tsx +0 -162
- package/src/components/dialogs/create-order-dialog.tsx +0 -146
- 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/preview.tsx +0 -44
- package/src/pages/view-order.tsx +0 -111
- package/src/pages/view-snippet.tsx +0 -166
|
@@ -27,6 +27,8 @@ export function JLCPCBImportDialog({
|
|
|
27
27
|
const [partNumber, setPartNumber] = useState("")
|
|
28
28
|
const [isLoading, setIsLoading] = useState(false)
|
|
29
29
|
const [error, setError] = useState<string | null>(null)
|
|
30
|
+
const [hasBeenImportedToAccountAlready, setHasBeenImportedToAccountAlready] =
|
|
31
|
+
useState<boolean>(false)
|
|
30
32
|
const axios = useAxios()
|
|
31
33
|
const { toast } = useToast()
|
|
32
34
|
const [, navigate] = useLocation()
|
|
@@ -45,29 +47,18 @@ export function JLCPCBImportDialog({
|
|
|
45
47
|
|
|
46
48
|
setIsLoading(true)
|
|
47
49
|
setError(null)
|
|
50
|
+
setHasBeenImportedToAccountAlready(false)
|
|
51
|
+
|
|
48
52
|
try {
|
|
49
|
-
|
|
50
|
-
const existingSnippetRes = await axios.get(
|
|
51
|
-
`/snippets/get?owner_name=${session?.github_username}&unscoped_name=${partNumber}`,
|
|
52
|
-
{
|
|
53
|
-
validateStatus: (status) => true,
|
|
54
|
-
},
|
|
55
|
-
)
|
|
53
|
+
const apiUrl = `/snippets/get?owner_name=${session?.github_username}&unscoped_name=${partNumber}`
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
href={`/editor?package_id=${existingSnippetRes.data.snippet.snippet_id}`}
|
|
65
|
-
>
|
|
66
|
-
View {partNumber}
|
|
67
|
-
</PrefetchPageLink>
|
|
68
|
-
</div>
|
|
69
|
-
),
|
|
70
|
-
})
|
|
55
|
+
const existingPackageRes = await axios.get(apiUrl, {
|
|
56
|
+
validateStatus: (status) => true,
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
if (existingPackageRes.status !== 404) {
|
|
60
|
+
setHasBeenImportedToAccountAlready(true)
|
|
61
|
+
setIsLoading(false)
|
|
71
62
|
return
|
|
72
63
|
}
|
|
73
64
|
|
|
@@ -76,16 +67,20 @@ export function JLCPCBImportDialog({
|
|
|
76
67
|
jlcpcb_part_number: partNumber,
|
|
77
68
|
})
|
|
78
69
|
.catch((e) => e)
|
|
70
|
+
|
|
79
71
|
const { snippet, error } = response.data
|
|
72
|
+
|
|
80
73
|
if (error) {
|
|
81
74
|
setError(error.message)
|
|
82
75
|
setIsLoading(false)
|
|
83
76
|
return
|
|
84
77
|
}
|
|
78
|
+
|
|
85
79
|
toast({
|
|
86
80
|
title: "Import Successful",
|
|
87
81
|
description: "JLCPCB component has been imported successfully.",
|
|
88
82
|
})
|
|
83
|
+
|
|
89
84
|
onOpenChange(false)
|
|
90
85
|
navigate(`/editor?package_id=${snippet.snippet_id}`)
|
|
91
86
|
} catch (error) {
|
|
@@ -121,10 +116,17 @@ export function JLCPCBImportDialog({
|
|
|
121
116
|
className="mt-3"
|
|
122
117
|
placeholder="Enter JLCPCB part number (e.g., C46749)"
|
|
123
118
|
value={partNumber}
|
|
124
|
-
onChange={(e) =>
|
|
119
|
+
onChange={(e) => {
|
|
120
|
+
setPartNumber(e.target.value)
|
|
121
|
+
setError(null)
|
|
122
|
+
setHasBeenImportedToAccountAlready(false)
|
|
123
|
+
}}
|
|
125
124
|
/>
|
|
126
|
-
{error &&
|
|
127
|
-
|
|
125
|
+
{error && !hasBeenImportedToAccountAlready && (
|
|
126
|
+
<p className="bg-red-100 p-2 mt-2 pre-wrap">{error}</p>
|
|
127
|
+
)}
|
|
128
|
+
|
|
129
|
+
{error && !hasBeenImportedToAccountAlready && (
|
|
128
130
|
<div className="flex justify-end mt-2">
|
|
129
131
|
<Button
|
|
130
132
|
variant="default"
|
|
@@ -132,21 +134,35 @@ export function JLCPCBImportDialog({
|
|
|
132
134
|
const issueTitle = `[${partNumber}] Failed to import from JLCPCB`
|
|
133
135
|
const issueBody = `I tried to import the part number ${partNumber} from JLCPCB, but it failed. Here's the error I got:\n\`\`\`\n${error}\n\`\`\`\n\nCould be an issue in \`fetchEasyEDAComponent\` or \`convertRawEasyEdaToTs\``
|
|
134
136
|
const issueLabels = "snippets,good first issue"
|
|
135
|
-
const url = `https://github.com/tscircuit/easyeda-converter/issues/new?title=${encodeURIComponent(
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
const url = `https://github.com/tscircuit/easyeda-converter/issues/new?title=${encodeURIComponent(
|
|
138
|
+
issueTitle,
|
|
139
|
+
)}&body=${encodeURIComponent(
|
|
140
|
+
issueBody,
|
|
141
|
+
)}&labels=${encodeURIComponent(issueLabels)}`
|
|
138
142
|
window.open(url, "_blank")
|
|
139
143
|
}}
|
|
140
144
|
>
|
|
141
|
-
File Issue on
|
|
145
|
+
File Issue on GitHub (prefilled)
|
|
142
146
|
</Button>
|
|
143
147
|
</div>
|
|
144
148
|
)}
|
|
149
|
+
|
|
150
|
+
{hasBeenImportedToAccountAlready && (
|
|
151
|
+
<p className="p-2 mt-2 pre-wrap text-md text-green-600">
|
|
152
|
+
This part number has already been imported to your profile.{" "}
|
|
153
|
+
<PrefetchPageLink
|
|
154
|
+
className="text-blue-500 hover:underline"
|
|
155
|
+
href={`/${session?.github_username}/${partNumber}`}
|
|
156
|
+
>
|
|
157
|
+
View it here
|
|
158
|
+
</PrefetchPageLink>
|
|
159
|
+
</p>
|
|
160
|
+
)}
|
|
145
161
|
</div>
|
|
146
162
|
<DialogFooter>
|
|
147
163
|
<Button onClick={handleImport} disabled={isLoading || !isLoggedIn}>
|
|
148
164
|
{!isLoggedIn
|
|
149
|
-
? "
|
|
165
|
+
? "You must be logged in to import from JLCPCB"
|
|
150
166
|
: isLoading
|
|
151
167
|
? "Importing..."
|
|
152
168
|
: "Import"}
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
DropdownMenuItem,
|
|
11
11
|
DropdownMenuTrigger,
|
|
12
12
|
} from "@/components/ui/dropdown-menu"
|
|
13
|
-
import { OptimizedImage } from "./OptimizedImage"
|
|
14
13
|
import { SnippetType, SnippetTypeIcon } from "./SnippetTypeIcon"
|
|
15
14
|
import { timeAgo } from "@/lib/utils/timeAgo"
|
|
16
15
|
import { useGetFsMapHashForPackage } from "@/hooks/use-get-fsmap-hash-for-package"
|
|
16
|
+
import { ImageWithFallback } from "./ImageWithFallback"
|
|
17
17
|
|
|
18
18
|
export interface PackageCardProps {
|
|
19
19
|
/** The package data to display */
|
|
@@ -69,7 +69,7 @@ export const PackageCard: React.FC<PackageCardProps> = ({
|
|
|
69
69
|
<div
|
|
70
70
|
className={`${imageSize} flex-shrink-0 rounded-md overflow-hidden`}
|
|
71
71
|
>
|
|
72
|
-
<
|
|
72
|
+
<ImageWithFallback
|
|
73
73
|
src={`${baseUrl}/packages/images/${pkg.owner_github_username}/${pkg.unscoped_name}/pcb.svg?${new URLSearchParams(
|
|
74
74
|
{
|
|
75
75
|
fs_sha: fsMapHash ?? "",
|
|
@@ -1,35 +1,27 @@
|
|
|
1
1
|
import { Link } from "wouter"
|
|
2
2
|
import { Star } from "lucide-react"
|
|
3
|
+
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
3
4
|
|
|
4
|
-
export const
|
|
5
|
-
snippet,
|
|
6
|
-
}: {
|
|
7
|
-
snippet: {
|
|
8
|
-
owner_name: string
|
|
9
|
-
name: string
|
|
10
|
-
unscoped_name: string
|
|
11
|
-
star_count?: number
|
|
12
|
-
}
|
|
13
|
-
}) => {
|
|
5
|
+
export const PackageLink = (pkg: Package) => {
|
|
14
6
|
return (
|
|
15
7
|
<>
|
|
16
8
|
<Link
|
|
17
9
|
className="text-blue-500 font-semibold hover:underline"
|
|
18
|
-
href={`/${
|
|
10
|
+
href={`/${pkg.owner_github_username}`}
|
|
19
11
|
>
|
|
20
|
-
{
|
|
12
|
+
{pkg.owner_github_username}
|
|
21
13
|
</Link>
|
|
22
14
|
<span className="px-0.5 text-gray-500">/</span>
|
|
23
15
|
<Link
|
|
24
16
|
className="text-blue-500 font-semibold hover:underline"
|
|
25
|
-
href={`/${
|
|
17
|
+
href={`/${pkg.unscoped_name}`}
|
|
26
18
|
>
|
|
27
|
-
{
|
|
19
|
+
{pkg.unscoped_name}
|
|
28
20
|
</Link>
|
|
29
|
-
{
|
|
21
|
+
{pkg.star_count !== undefined && (
|
|
30
22
|
<span className="ml-2 text-gray-500 text-xs flex items-center">
|
|
31
23
|
<Star className="w-3 h-3 mr-1" />
|
|
32
|
-
{
|
|
24
|
+
{pkg.star_count}
|
|
33
25
|
</span>
|
|
34
26
|
)}
|
|
35
27
|
</>
|
|
@@ -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) {
|
|
@@ -65,7 +65,7 @@ export default function ImportantFilesView({
|
|
|
65
65
|
setActiveFilePath(importantFiles[0].file_path)
|
|
66
66
|
setActiveTab("file")
|
|
67
67
|
}
|
|
68
|
-
}, [aiDescription, aiUsageInstructions, hasAiContent])
|
|
68
|
+
}, [aiDescription, aiUsageInstructions, hasAiContent, importantFiles])
|
|
69
69
|
|
|
70
70
|
// Get file name from path
|
|
71
71
|
const getFileName = (path: string) => {
|
|
@@ -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,12 @@ 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
|
+
packageReleaseId: packageInfo?.latest_package_release_id ?? "",
|
|
49
|
+
})
|
|
44
50
|
const { data: starData, isLoading: isStarDataLoading } =
|
|
45
51
|
usePackageStarsByName(packageInfo?.name ?? null)
|
|
46
52
|
const { addStar, removeStar } = usePackageStarMutationByName(
|
|
@@ -254,7 +260,6 @@ export default function PackageHeader({
|
|
|
254
260
|
onClose={close}
|
|
255
261
|
stage={stage}
|
|
256
262
|
setStage={setStage}
|
|
257
|
-
packageReleaseId={packageInfo?.latest_package_release_id ?? ""}
|
|
258
263
|
/>
|
|
259
264
|
</header>
|
|
260
265
|
)
|
|
@@ -2,24 +2,32 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog"
|
|
|
2
2
|
import { Button } from "../ui/button"
|
|
3
3
|
import { createUseDialog } from "./create-use-dialog"
|
|
4
4
|
import { useDeletePackage } from "@/hooks/use-delete-package"
|
|
5
|
+
import { useQueryClient } from "react-query"
|
|
5
6
|
|
|
6
7
|
export const ConfirmDeletePackageDialog = ({
|
|
7
8
|
open,
|
|
8
9
|
onOpenChange,
|
|
9
10
|
packageId,
|
|
10
11
|
packageName,
|
|
12
|
+
packageOwner,
|
|
11
13
|
refetchUserPackages,
|
|
12
14
|
}: {
|
|
13
15
|
open: boolean
|
|
14
16
|
onOpenChange: (open: boolean) => void
|
|
15
17
|
packageId: string
|
|
16
18
|
packageName: string
|
|
19
|
+
packageOwner: string
|
|
17
20
|
refetchUserPackages?: () => void
|
|
18
21
|
}) => {
|
|
22
|
+
const queryClient = useQueryClient()
|
|
23
|
+
|
|
19
24
|
const { mutate: deletePackage, isLoading } = useDeletePackage({
|
|
20
25
|
onSuccess: () => {
|
|
21
26
|
onOpenChange(false)
|
|
22
27
|
refetchUserPackages?.()
|
|
28
|
+
queryClient.invalidateQueries({
|
|
29
|
+
queryKey: ["userPackages", packageOwner],
|
|
30
|
+
})
|
|
23
31
|
},
|
|
24
32
|
})
|
|
25
33
|
|