@tscircuit/fake-snippets 0.0.107 → 0.0.109
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/api/generated-index.js +82 -22
- package/biome.json +7 -1
- package/bun-tests/fake-snippets-api/routes/package_builds/get.test.ts +0 -15
- package/bun-tests/fake-snippets-api/routes/package_builds/list.test.ts +0 -12
- package/bun.lock +62 -19
- package/dist/bundle.js +25 -24
- package/dist/index.d.ts +26 -15
- package/dist/index.js +19 -18
- package/dist/schema.d.ts +32 -24
- package/dist/schema.js +7 -6
- package/fake-snippets-api/lib/db/db-client.ts +10 -1
- package/fake-snippets-api/lib/db/schema.ts +4 -3
- package/fake-snippets-api/lib/db/seed.ts +6 -9
- package/fake-snippets-api/lib/public-mapping/public-map-package-build.ts +0 -3
- package/fake-snippets-api/lib/public-mapping/public-map-package-release.ts +3 -0
- package/package.json +7 -8
- package/src/App.tsx +12 -11
- package/src/components/DownloadButtonAndMenu.tsx +133 -35
- package/src/components/FileSidebar.tsx +45 -193
- package/src/components/Footer.tsx +0 -1
- package/src/components/HeaderLogin.tsx +1 -1
- package/src/components/HiddenFilesDropdown.tsx +0 -2
- package/src/components/PackageBreadcrumb.tsx +1 -1
- package/src/components/PackageBuildsPage/PackageBuildDetailsPage.tsx +0 -2
- package/src/components/PackageBuildsPage/build-preview-content.tsx +34 -5
- package/src/components/PackageCard.tsx +0 -1
- package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +20 -11
- package/src/components/ViewPackagePage/components/important-files-view.tsx +75 -59
- package/src/components/ViewPackagePage/components/main-content-header.tsx +4 -4
- package/src/components/ViewPackagePage/components/main-content-view-selector.tsx +0 -1
- package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +1 -2
- package/src/components/ViewPackagePage/components/package-header.tsx +14 -17
- package/src/components/ViewPackagePage/components/preview-image-squares.tsx +0 -1
- package/src/components/ViewPackagePage/components/repo-page-content.tsx +21 -20
- package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +18 -2
- package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +1 -1
- package/src/components/ViewPackagePage/components/sidebar.tsx +0 -2
- package/src/components/ViewPackagePage/components/tab-views/files-view.tsx +18 -17
- package/src/components/ViewPackagePage/components/theme-toggle.tsx +0 -2
- package/src/components/ViewPackagePage/hooks/use-toast.tsx +0 -1
- package/src/components/package-port/CodeAndPreview.tsx +23 -40
- package/src/components/package-port/CodeEditor.tsx +24 -1
- package/src/components/package-port/CodeEditorHeader.tsx +5 -2
- package/src/components/preview/BuildsList.tsx +20 -9
- package/src/components/preview/ConnectedPackagesList.tsx +73 -60
- package/src/components/preview/ConnectedRepoOverview.tsx +160 -154
- package/src/components/preview/PackageReleasesDashboard.tsx +41 -30
- package/src/components/preview/index.tsx +16 -153
- package/src/hooks/use-current-package-id.ts +5 -30
- package/src/hooks/use-current-package-info.ts +29 -5
- package/src/hooks/use-global-store.ts +1 -1
- package/src/hooks/useFileManagement.ts +153 -34
- package/src/hooks/useOptimizedPackageFilesLoader.ts +149 -0
- package/src/hooks/useUpdatePackageFilesMutation.ts +2 -0
- package/src/index.css +24 -0
- package/src/lib/download-fns/download-circuit-png.ts +11 -3
- package/src/lib/download-fns/download-gltf-from-circuit-json.ts +44 -0
- package/src/lib/utils/isComponentExported.ts +9 -0
- package/src/lib/utils/transformFilesToTreeData.tsx +195 -0
- package/src/pages/404.tsx +3 -5
- package/src/pages/authorize.tsx +0 -2
- package/src/pages/landing.tsx +0 -1
- package/src/pages/preview-release.tsx +279 -0
- package/src/pages/release-builds.tsx +0 -8
- package/src/pages/release-detail.tsx +17 -15
- package/src/pages/releases.tsx +5 -1
- package/src/pages/view-package.tsx +14 -13
- package/src/components/Footer2.tsx +0 -100
- package/src/components/ShippingInformationForm.tsx +0 -423
- package/src/components/StaticViewSnippetHeader.tsx +0 -70
- package/src/components/ViewPackagePage/components/file-explorer.tsx +0 -67
- package/src/components/ViewPackagePage/components/readme-view.tsx +0 -58
- package/src/components/ViewPackagePage/components/repo-header-button.tsx +0 -36
- package/src/components/ViewPackagePage/components/repo-header.tsx +0 -4
- package/src/components/ViewPackagePage/components/sidebar-contributors-section.tsx +0 -31
- package/src/components/ViewSnippetHeader.tsx +0 -181
- package/src/components/ui/input-otp.tsx +0 -69
- package/src/hooks/use-snippets-base-api-url.ts +0 -3
- package/src/pages/preview-build.tsx +0 -380
- package/src/pages/settings.tsx +0 -25
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { TypeBadge } from "@/components/TypeBadge"
|
|
2
|
-
import { Button } from "@/components/ui/button"
|
|
3
|
-
import { useAxios } from "@/hooks/use-axios"
|
|
4
|
-
import { useCurrentSnippet } from "@/hooks/use-current-snippet"
|
|
5
|
-
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
6
|
-
import { toast, useToast } from "@/hooks/use-toast"
|
|
7
|
-
import { LockClosedIcon } from "@radix-ui/react-icons"
|
|
8
|
-
import { Snippet } from "fake-snippets-api/lib/db/schema"
|
|
9
|
-
import { ChevronLeft, Eye, GitFork, Star } from "lucide-react"
|
|
10
|
-
import { useEffect, useState } from "react"
|
|
11
|
-
import { useMutation, useQueryClient } from "react-query"
|
|
12
|
-
import { Link } from "wouter"
|
|
13
|
-
import { navigate } from "wouter/use-browser-location"
|
|
14
|
-
|
|
15
|
-
export default function ViewSnippetHeader() {
|
|
16
|
-
const { snippet } = useCurrentSnippet()
|
|
17
|
-
const axios = useAxios()
|
|
18
|
-
const qc = useQueryClient()
|
|
19
|
-
const session = useGlobalStore((s) => s.session)
|
|
20
|
-
const [isStarred, setIsStarred] = useState(snippet?.is_starred || false)
|
|
21
|
-
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
setIsStarred(snippet?.is_starred || false)
|
|
24
|
-
}, [snippet?.is_starred])
|
|
25
|
-
|
|
26
|
-
const useForkSnippetMutation = ({
|
|
27
|
-
snippet,
|
|
28
|
-
onSuccess,
|
|
29
|
-
}: {
|
|
30
|
-
snippet: Snippet
|
|
31
|
-
onSuccess?: (forkedSnippet: Snippet) => void
|
|
32
|
-
}) => {
|
|
33
|
-
const axios = useAxios()
|
|
34
|
-
const session = useGlobalStore((s) => s.session)
|
|
35
|
-
|
|
36
|
-
return useMutation(
|
|
37
|
-
["createForkSnippet"],
|
|
38
|
-
async () => {
|
|
39
|
-
if (!session) throw new Error("No session")
|
|
40
|
-
if (!snippet) throw new Error("No snippet to fork")
|
|
41
|
-
|
|
42
|
-
const { data } = await axios.post("/snippets/create", {
|
|
43
|
-
unscoped_name: snippet.unscoped_name,
|
|
44
|
-
snippet_type: snippet.snippet_type,
|
|
45
|
-
owner_name: session.github_username,
|
|
46
|
-
code: snippet.code,
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
if (!data.ok) {
|
|
50
|
-
throw new Error(
|
|
51
|
-
data.error || "Unknown error occurred while forking snippet.",
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return data.snippet
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
onSuccess: (forkedSnippet: Snippet) => {
|
|
59
|
-
toast({
|
|
60
|
-
title: `Forked snippet`,
|
|
61
|
-
description: `You have successfully forked the snippet. Redirecting...`,
|
|
62
|
-
})
|
|
63
|
-
onSuccess?.(forkedSnippet)
|
|
64
|
-
},
|
|
65
|
-
onError: (error: any) => {
|
|
66
|
-
const message =
|
|
67
|
-
error?.data?.error?.message ||
|
|
68
|
-
error.message ||
|
|
69
|
-
"Failed to fork snippet. Please try again."
|
|
70
|
-
if (message.includes("already forked")) {
|
|
71
|
-
toast({
|
|
72
|
-
title: "Snippet already exists",
|
|
73
|
-
description: message,
|
|
74
|
-
variant: "destructive",
|
|
75
|
-
})
|
|
76
|
-
} else {
|
|
77
|
-
toast({
|
|
78
|
-
title: "Error",
|
|
79
|
-
description: message,
|
|
80
|
-
variant: "destructive",
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
console.error("Error forking snippet:", error)
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const { mutate: forkSnippet, isLoading: isForking } = useForkSnippetMutation({
|
|
90
|
-
snippet: snippet!,
|
|
91
|
-
onSuccess: (forkedSnippet) => {
|
|
92
|
-
navigate("/editor?snippet_id=" + forkedSnippet.snippet_id)
|
|
93
|
-
},
|
|
94
|
-
})
|
|
95
|
-
const handleStarClick = async () => {
|
|
96
|
-
try {
|
|
97
|
-
if (isStarred) {
|
|
98
|
-
await axios.post("/snippets/remove_star", {
|
|
99
|
-
snippet_id: snippet!.snippet_id,
|
|
100
|
-
})
|
|
101
|
-
setIsStarred(false)
|
|
102
|
-
toast({
|
|
103
|
-
title: "Unstarred!",
|
|
104
|
-
description: "You've unstarred this snippet",
|
|
105
|
-
})
|
|
106
|
-
} else {
|
|
107
|
-
await axios.post("/snippets/add_star", {
|
|
108
|
-
snippet_id: snippet!.snippet_id,
|
|
109
|
-
})
|
|
110
|
-
setIsStarred(true)
|
|
111
|
-
toast({
|
|
112
|
-
title: "Starred!",
|
|
113
|
-
description: "You've starred this snippet",
|
|
114
|
-
})
|
|
115
|
-
}
|
|
116
|
-
qc.invalidateQueries(["snippets", snippet!.snippet_id])
|
|
117
|
-
} catch (error: any) {
|
|
118
|
-
toast({
|
|
119
|
-
title: "Error",
|
|
120
|
-
description: `Failed to ${isStarred ? "unstar" : "star"} snippet`,
|
|
121
|
-
variant: "destructive",
|
|
122
|
-
})
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
<header className="bg-white border-b border-gray-200 py-4 px-6">
|
|
128
|
-
<div className="flex items-center justify-between">
|
|
129
|
-
<div className="flex items-center">
|
|
130
|
-
<h1 className="text-xl font-bold mr-2">
|
|
131
|
-
<Link href={`/${snippet?.owner_name}`} className="text-blue-600">
|
|
132
|
-
{snippet?.owner_name}
|
|
133
|
-
</Link>
|
|
134
|
-
<span className="px-1 text-gray-500">/</span>
|
|
135
|
-
<Link
|
|
136
|
-
className="text-blue-600"
|
|
137
|
-
href={`/${snippet?.owner_name}/${snippet?.unscoped_name}`}
|
|
138
|
-
>
|
|
139
|
-
{snippet?.unscoped_name}
|
|
140
|
-
</Link>
|
|
141
|
-
</h1>
|
|
142
|
-
{snippet?.snippet_type && <TypeBadge type={snippet.snippet_type} />}
|
|
143
|
-
{snippet?.is_private && (
|
|
144
|
-
<div className="relative group pl-2">
|
|
145
|
-
<LockClosedIcon className="h-4 w-4 text-gray-700" />
|
|
146
|
-
<span className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-1 hidden group-hover:block bg-black text-white text-xs rounded py-1 px-2">
|
|
147
|
-
private
|
|
148
|
-
</span>
|
|
149
|
-
</div>
|
|
150
|
-
)}
|
|
151
|
-
</div>
|
|
152
|
-
<div className="flex items-center space-x-2">
|
|
153
|
-
<Button variant="outline" size="sm" onClick={handleStarClick}>
|
|
154
|
-
<Star
|
|
155
|
-
className={`w-4 h-4 mr-2 ${isStarred ? "fill-yellow-500 text-yellow-500" : ""}`}
|
|
156
|
-
/>
|
|
157
|
-
{isStarred ? "Starred" : "Star"}
|
|
158
|
-
{snippet!.star_count > 0 && (
|
|
159
|
-
<span className="ml-1.5 bg-gray-100 text-gray-700 rounded-full px-1.5 py-0.5 text-xs font-medium">
|
|
160
|
-
{snippet!.star_count}
|
|
161
|
-
</span>
|
|
162
|
-
)}
|
|
163
|
-
</Button>
|
|
164
|
-
{/* <Button variant="outline" size="sm">
|
|
165
|
-
<Eye className="w-4 h-4 mr-2" />
|
|
166
|
-
Watch
|
|
167
|
-
</Button> */}
|
|
168
|
-
|
|
169
|
-
<Button variant="outline" size="sm" onClick={() => forkSnippet()}>
|
|
170
|
-
<GitFork className="w-4 h-4 mr-2" />
|
|
171
|
-
{snippet?.owner_name === session?.github_username ? "Save" : "Fork"}
|
|
172
|
-
</Button>
|
|
173
|
-
</div>
|
|
174
|
-
</div>
|
|
175
|
-
{/* <div className="mt-4 flex justify-end items-center text-sm text-gray-500">
|
|
176
|
-
<span className="mr-4">Last updated: 2 days ago</span>
|
|
177
|
-
<span>Version: 1.0.0</span>
|
|
178
|
-
</div> */}
|
|
179
|
-
</header>
|
|
180
|
-
)
|
|
181
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { DashIcon } from "@radix-ui/react-icons"
|
|
3
|
-
import { OTPInput, OTPInputContext } from "input-otp"
|
|
4
|
-
|
|
5
|
-
import { cn } from "@/lib/utils"
|
|
6
|
-
|
|
7
|
-
const InputOTP = React.forwardRef<
|
|
8
|
-
React.ElementRef<typeof OTPInput>,
|
|
9
|
-
React.ComponentPropsWithoutRef<typeof OTPInput>
|
|
10
|
-
>(({ className, containerClassName, ...props }, ref) => (
|
|
11
|
-
<OTPInput
|
|
12
|
-
ref={ref}
|
|
13
|
-
containerClassName={cn(
|
|
14
|
-
"flex items-center gap-2 has-[:disabled]:opacity-50",
|
|
15
|
-
containerClassName,
|
|
16
|
-
)}
|
|
17
|
-
className={cn("disabled:cursor-not-allowed", className)}
|
|
18
|
-
{...props}
|
|
19
|
-
/>
|
|
20
|
-
))
|
|
21
|
-
InputOTP.displayName = "InputOTP"
|
|
22
|
-
|
|
23
|
-
const InputOTPGroup = React.forwardRef<
|
|
24
|
-
React.ElementRef<"div">,
|
|
25
|
-
React.ComponentPropsWithoutRef<"div">
|
|
26
|
-
>(({ className, ...props }, ref) => (
|
|
27
|
-
<div ref={ref} className={cn("flex items-center", className)} {...props} />
|
|
28
|
-
))
|
|
29
|
-
InputOTPGroup.displayName = "InputOTPGroup"
|
|
30
|
-
|
|
31
|
-
const InputOTPSlot = React.forwardRef<
|
|
32
|
-
React.ElementRef<"div">,
|
|
33
|
-
React.ComponentPropsWithoutRef<"div"> & { index: number }
|
|
34
|
-
>(({ index, className, ...props }, ref) => {
|
|
35
|
-
const inputOTPContext = React.useContext(OTPInputContext)
|
|
36
|
-
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<div
|
|
40
|
-
ref={ref}
|
|
41
|
-
className={cn(
|
|
42
|
-
"relative flex h-9 w-9 items-center justify-center border-y border-r border-slate-200 text-sm shadow-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md dark:border-slate-800",
|
|
43
|
-
isActive && "z-10 ring-1 ring-slate-950 dark:ring-slate-300",
|
|
44
|
-
className,
|
|
45
|
-
)}
|
|
46
|
-
{...props}
|
|
47
|
-
>
|
|
48
|
-
{char}
|
|
49
|
-
{hasFakeCaret && (
|
|
50
|
-
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
51
|
-
<div className="h-4 w-px animate-caret-blink bg-slate-950 duration-1000 dark:bg-slate-50" />
|
|
52
|
-
</div>
|
|
53
|
-
)}
|
|
54
|
-
</div>
|
|
55
|
-
)
|
|
56
|
-
})
|
|
57
|
-
InputOTPSlot.displayName = "InputOTPSlot"
|
|
58
|
-
|
|
59
|
-
const InputOTPSeparator = React.forwardRef<
|
|
60
|
-
React.ElementRef<"div">,
|
|
61
|
-
React.ComponentPropsWithoutRef<"div">
|
|
62
|
-
>(({ ...props }, ref) => (
|
|
63
|
-
<div ref={ref} role="separator" {...props}>
|
|
64
|
-
<DashIcon />
|
|
65
|
-
</div>
|
|
66
|
-
))
|
|
67
|
-
InputOTPSeparator.displayName = "InputOTPSeparator"
|
|
68
|
-
|
|
69
|
-
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }
|
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
import { useState } from "react"
|
|
2
|
-
import { useParams } from "wouter"
|
|
3
|
-
import { Loader2, ChevronLeft, ChevronRight, File, Folder } from "lucide-react"
|
|
4
|
-
import Header from "@/components/Header"
|
|
5
|
-
import { SuspenseRunFrame } from "@/components/SuspenseRunFrame"
|
|
6
|
-
import { TreeView, TreeDataItem } from "@/components/ui/tree-view"
|
|
7
|
-
import { cn } from "@/lib/utils"
|
|
8
|
-
import { PrefetchPageLink } from "@/components/PrefetchPageLink"
|
|
9
|
-
import NotFoundPage from "./404"
|
|
10
|
-
import { getBuildStatus, MOCK_PACKAGE_BUILDS } from "@/components/preview"
|
|
11
|
-
|
|
12
|
-
const MOCK_DEPLOYMENT_FILES: Record<
|
|
13
|
-
string,
|
|
14
|
-
Array<{ path: string; content: string }>
|
|
15
|
-
> = {
|
|
16
|
-
pb_1a2b3c4d: [
|
|
17
|
-
{
|
|
18
|
-
path: "index.tsx",
|
|
19
|
-
content: `export default () => (
|
|
20
|
-
<board width="10mm" height="10mm">
|
|
21
|
-
<resistor
|
|
22
|
-
resistance="1k"
|
|
23
|
-
footprint="0402"
|
|
24
|
-
name="R1"
|
|
25
|
-
schX={3}
|
|
26
|
-
pcbX={3}
|
|
27
|
-
/>
|
|
28
|
-
<capacitor
|
|
29
|
-
capacitance="1000pF"
|
|
30
|
-
footprint="0402"
|
|
31
|
-
name="C1"
|
|
32
|
-
schX={-3}
|
|
33
|
-
pcbX={-3}
|
|
34
|
-
/>
|
|
35
|
-
<trace from=".R1 > .pin1" to=".C1 > .pin1" />
|
|
36
|
-
</board>
|
|
37
|
-
)`,
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
path: "components/Button.tsx",
|
|
41
|
-
content: `export default () => (
|
|
42
|
-
<board width="10mm" height="10mm">
|
|
43
|
-
<resistor
|
|
44
|
-
resistance="1k"
|
|
45
|
-
footprint="0402"
|
|
46
|
-
name="R1"
|
|
47
|
-
schX={3}
|
|
48
|
-
pcbX={3}
|
|
49
|
-
/>
|
|
50
|
-
<capacitor
|
|
51
|
-
capacitance="1000pF"
|
|
52
|
-
footprint="0402"
|
|
53
|
-
name="C1"
|
|
54
|
-
schX={-3}
|
|
55
|
-
pcbX={-3}
|
|
56
|
-
/>
|
|
57
|
-
<trace from=".R1 > .pin1" to=".C1 > .pin1" />
|
|
58
|
-
</board>
|
|
59
|
-
)`,
|
|
60
|
-
},
|
|
61
|
-
],
|
|
62
|
-
pb_9i8j7k6l: [
|
|
63
|
-
{
|
|
64
|
-
path: "index.tsx",
|
|
65
|
-
content: `export default () => (
|
|
66
|
-
<board width="10mm" height="10mm">
|
|
67
|
-
<resistor
|
|
68
|
-
resistance="1k"
|
|
69
|
-
footprint="0402"
|
|
70
|
-
name="R1"
|
|
71
|
-
schX={3}
|
|
72
|
-
pcbX={3}
|
|
73
|
-
/>
|
|
74
|
-
<capacitor
|
|
75
|
-
capacitance="1000pF"
|
|
76
|
-
footprint="0402"
|
|
77
|
-
name="C1"
|
|
78
|
-
schX={-3}
|
|
79
|
-
pcbX={-3}
|
|
80
|
-
/>
|
|
81
|
-
<trace from=".R1 > .pin1" to=".C1 > .pin1" />
|
|
82
|
-
</board>
|
|
83
|
-
)`,
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
path: "utils/helpers.ts",
|
|
87
|
-
content: `export default () => (
|
|
88
|
-
<board width="10mm" height="10mm">
|
|
89
|
-
<resistor
|
|
90
|
-
resistance="1k"
|
|
91
|
-
footprint="0402"
|
|
92
|
-
name="R1"
|
|
93
|
-
schX={3}
|
|
94
|
-
pcbX={3}
|
|
95
|
-
/>
|
|
96
|
-
<capacitor
|
|
97
|
-
capacitance="1000pF"
|
|
98
|
-
footprint="0402"
|
|
99
|
-
name="C1"
|
|
100
|
-
schX={-3}
|
|
101
|
-
pcbX={-3}
|
|
102
|
-
/>
|
|
103
|
-
<trace from=".R1 > .pin1" to=".C1 > .pin1" />
|
|
104
|
-
</board>
|
|
105
|
-
)`,
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
pb_1q2w3e4r: [
|
|
109
|
-
{
|
|
110
|
-
path: "index.tsx",
|
|
111
|
-
content: `export default () => (
|
|
112
|
-
<board width="10mm" height="10mm">
|
|
113
|
-
<resistor
|
|
114
|
-
resistance="1k"
|
|
115
|
-
footprint="0402"
|
|
116
|
-
name="R1"
|
|
117
|
-
schX={3}
|
|
118
|
-
pcbX={3}
|
|
119
|
-
/>
|
|
120
|
-
<capacitor
|
|
121
|
-
capacitance="1000pF"
|
|
122
|
-
footprint="0402"
|
|
123
|
-
name="C1"
|
|
124
|
-
schX={-3}
|
|
125
|
-
pcbX={-3}
|
|
126
|
-
/>
|
|
127
|
-
<trace from=".R1 > .pin1" to=".C1 > .pin1" />
|
|
128
|
-
</board>
|
|
129
|
-
)`,
|
|
130
|
-
},
|
|
131
|
-
],
|
|
132
|
-
pb_9o8i7u6y: [
|
|
133
|
-
{
|
|
134
|
-
path: "index.tsx",
|
|
135
|
-
content: `export default () => (
|
|
136
|
-
<board width="10mm" height="10mm">
|
|
137
|
-
<resistor
|
|
138
|
-
resistance="1k"
|
|
139
|
-
footprint="0402"
|
|
140
|
-
name="R1"
|
|
141
|
-
schX={3}
|
|
142
|
-
pcbX={3}
|
|
143
|
-
/>
|
|
144
|
-
<capacitor
|
|
145
|
-
capacitance="1000pF"
|
|
146
|
-
footprint="0402"
|
|
147
|
-
name="C1"
|
|
148
|
-
schX={-3}
|
|
149
|
-
pcbX={-3}
|
|
150
|
-
/>
|
|
151
|
-
<trace from=".R1 > .pin1" to=".C1 > .pin1" />
|
|
152
|
-
</board>
|
|
153
|
-
)`,
|
|
154
|
-
},
|
|
155
|
-
],
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const getBuildFiles = (buildId: string | null) => {
|
|
159
|
-
if (!buildId) return []
|
|
160
|
-
return MOCK_DEPLOYMENT_FILES[buildId] || []
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const getBuildFsMap = (buildId: string | null) => {
|
|
164
|
-
const files = getBuildFiles(buildId)
|
|
165
|
-
return Object.fromEntries(files.map((f) => [f.path, f.content]))
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const StatusPill = ({ status }: { status: string }) => {
|
|
169
|
-
const color =
|
|
170
|
-
status === "success"
|
|
171
|
-
? "bg-emerald-600"
|
|
172
|
-
: status === "failed"
|
|
173
|
-
? "bg-red-600"
|
|
174
|
-
: status === "building"
|
|
175
|
-
? "bg-blue-600 animate-pulse"
|
|
176
|
-
: "bg-gray-500"
|
|
177
|
-
return <span className={cn("inline-block w-2 h-2 rounded-full", color)} />
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export default function PreviewBuildPage() {
|
|
181
|
-
const params = useParams<{ buildId: string }>()
|
|
182
|
-
const buildId = params?.buildId || null
|
|
183
|
-
|
|
184
|
-
const [sidebarCollapsed, setSidebarCollapsed] = useState(false)
|
|
185
|
-
const [selectedFile, setSelectedFile] = useState<string | null>("index.tsx")
|
|
186
|
-
const [selectedItemId, setSelectedItemId] = useState<string>("")
|
|
187
|
-
|
|
188
|
-
const buildFiles = getBuildFiles(buildId)
|
|
189
|
-
const buildFsMap = getBuildFsMap(buildId)
|
|
190
|
-
|
|
191
|
-
const build = buildId
|
|
192
|
-
? MOCK_PACKAGE_BUILDS.find((d) => d.package_build_id === buildId)
|
|
193
|
-
: MOCK_PACKAGE_BUILDS[0]
|
|
194
|
-
|
|
195
|
-
if (!build) {
|
|
196
|
-
return <NotFoundPage heading="Build Not Found" />
|
|
197
|
-
}
|
|
198
|
-
const { status, label } = getBuildStatus(build)
|
|
199
|
-
const convertFilesToTreeData = (
|
|
200
|
-
files: Array<{ path: string; content: string }>,
|
|
201
|
-
): TreeDataItem[] => {
|
|
202
|
-
const tree: TreeDataItem[] = []
|
|
203
|
-
const pathMap = new Map<string, TreeDataItem>()
|
|
204
|
-
|
|
205
|
-
files.forEach((file) => {
|
|
206
|
-
const parts = file.path.split("/")
|
|
207
|
-
let currentPath = ""
|
|
208
|
-
|
|
209
|
-
parts.forEach((part, index) => {
|
|
210
|
-
const isLast = index === parts.length - 1
|
|
211
|
-
currentPath = currentPath ? `${currentPath}/${part}` : part
|
|
212
|
-
|
|
213
|
-
if (!pathMap.has(currentPath)) {
|
|
214
|
-
const item: TreeDataItem = {
|
|
215
|
-
id: currentPath,
|
|
216
|
-
name: part,
|
|
217
|
-
icon: isLast ? File : Folder,
|
|
218
|
-
children: isLast ? undefined : [],
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
pathMap.set(currentPath, item)
|
|
222
|
-
|
|
223
|
-
if (index === 0) {
|
|
224
|
-
tree.push(item)
|
|
225
|
-
} else {
|
|
226
|
-
const parentPath = parts.slice(0, index).join("/")
|
|
227
|
-
const parent = pathMap.get(parentPath)
|
|
228
|
-
if (parent && parent.children) {
|
|
229
|
-
parent.children.push(item)
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
})
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
return tree
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const treeData = convertFilesToTreeData(buildFiles)
|
|
240
|
-
|
|
241
|
-
return (
|
|
242
|
-
<>
|
|
243
|
-
<Header />
|
|
244
|
-
<div className="flex flex-col h-screen overflow-hidden !-mt-1">
|
|
245
|
-
<div className="flex flex-1 overflow-hidden">
|
|
246
|
-
<aside
|
|
247
|
-
className={cn(
|
|
248
|
-
"relative border-r border-gray-200 rounded-r-lg z-[5] h-full transition-all duration-300 ease-in-out bg-white",
|
|
249
|
-
sidebarCollapsed ? "w-3" : "w-80",
|
|
250
|
-
)}
|
|
251
|
-
>
|
|
252
|
-
<button
|
|
253
|
-
onClick={() => setSidebarCollapsed(!sidebarCollapsed)}
|
|
254
|
-
className="absolute top-4 -right-3 z-10 bg-white border border-gray-200 rounded-full p-1 hover:bg-gray-50"
|
|
255
|
-
>
|
|
256
|
-
{sidebarCollapsed ? (
|
|
257
|
-
<ChevronRight size={20} />
|
|
258
|
-
) : (
|
|
259
|
-
<ChevronLeft size={20} />
|
|
260
|
-
)}
|
|
261
|
-
</button>
|
|
262
|
-
|
|
263
|
-
{!sidebarCollapsed && (
|
|
264
|
-
<>
|
|
265
|
-
<div className="p-4 border-b border-gray-200">
|
|
266
|
-
<div className="space-y-3">
|
|
267
|
-
<div className="flex items-center justify-between">
|
|
268
|
-
<h2 className="text-lg font-semibold text-gray-900">
|
|
269
|
-
Deployment
|
|
270
|
-
</h2>
|
|
271
|
-
<StatusPill status={status} />
|
|
272
|
-
</div>
|
|
273
|
-
|
|
274
|
-
<div className="space-y-2">
|
|
275
|
-
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
|
|
276
|
-
<span className="text-xs text-gray-500 uppercase tracking-wide">
|
|
277
|
-
ID
|
|
278
|
-
</span>
|
|
279
|
-
<PrefetchPageLink
|
|
280
|
-
href={`/build/${build.package_build_id}`}
|
|
281
|
-
className="font-mono text-sm text-gray-900 bg-gray-100 px-2 py-1 rounded"
|
|
282
|
-
>
|
|
283
|
-
{build.package_build_id}
|
|
284
|
-
</PrefetchPageLink>
|
|
285
|
-
</div>
|
|
286
|
-
|
|
287
|
-
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
|
|
288
|
-
<span className="text-xs text-gray-500 uppercase tracking-wide">
|
|
289
|
-
Commit
|
|
290
|
-
</span>
|
|
291
|
-
<PrefetchPageLink
|
|
292
|
-
href={`https://github.com/${build.commit_author}/tscircuit.com/commit/${build.commit_message}`}
|
|
293
|
-
className="font-mono text-xs text-gray-600 bg-gray-50 px-2 text-right py-1 rounded line-clamp-1"
|
|
294
|
-
>
|
|
295
|
-
{build.commit_message}
|
|
296
|
-
</PrefetchPageLink>
|
|
297
|
-
</div>
|
|
298
|
-
|
|
299
|
-
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
|
|
300
|
-
<span className="text-xs text-gray-500 uppercase tracking-wide">
|
|
301
|
-
Status
|
|
302
|
-
</span>
|
|
303
|
-
<span
|
|
304
|
-
className={`text-xs font-medium px-2 py-1 rounded-full capitalize ${
|
|
305
|
-
status === "success"
|
|
306
|
-
? "bg-emerald-100 text-emerald-800"
|
|
307
|
-
: status === "failed"
|
|
308
|
-
? "bg-red-100 text-red-800"
|
|
309
|
-
: status === "building"
|
|
310
|
-
? "bg-blue-100 text-blue-800"
|
|
311
|
-
: "bg-gray-100 text-gray-800"
|
|
312
|
-
}`}
|
|
313
|
-
>
|
|
314
|
-
{status}
|
|
315
|
-
</span>
|
|
316
|
-
</div>
|
|
317
|
-
</div>
|
|
318
|
-
</div>
|
|
319
|
-
</div>
|
|
320
|
-
|
|
321
|
-
<div className="flex-1 overflow-hidden">
|
|
322
|
-
<div className="px-4 py-3 border-b border-gray-200">
|
|
323
|
-
<h3 className="text-sm font-semibold text-gray-900">
|
|
324
|
-
Files
|
|
325
|
-
</h3>
|
|
326
|
-
<p className="text-xs text-gray-500 mt-1">
|
|
327
|
-
{buildFiles.length} file
|
|
328
|
-
{buildFiles.length !== 1 ? "s" : ""}
|
|
329
|
-
</p>
|
|
330
|
-
</div>
|
|
331
|
-
<div className="px-2 py-2 overflow-y-auto select-none">
|
|
332
|
-
<TreeView
|
|
333
|
-
selectedItemId={selectedItemId || ""}
|
|
334
|
-
setSelectedItemId={(v) => setSelectedItemId(v || "")}
|
|
335
|
-
data={treeData}
|
|
336
|
-
className="w-full"
|
|
337
|
-
onSelectChange={(item) => {
|
|
338
|
-
if (item && !item.children) {
|
|
339
|
-
setSelectedFile(item.id)
|
|
340
|
-
}
|
|
341
|
-
}}
|
|
342
|
-
/>
|
|
343
|
-
</div>
|
|
344
|
-
</div>
|
|
345
|
-
</>
|
|
346
|
-
)}
|
|
347
|
-
</aside>
|
|
348
|
-
|
|
349
|
-
<main className="flex-1 overflow-y-auto">
|
|
350
|
-
<div className="flex flex-col h-full overflow-h-hidden">
|
|
351
|
-
{status === "success" ? (
|
|
352
|
-
<SuspenseRunFrame
|
|
353
|
-
fsMap={buildFsMap}
|
|
354
|
-
mainComponentPath={selectedFile ?? "index.tsx"}
|
|
355
|
-
showRunButton={false}
|
|
356
|
-
className="[&>div]:overflow-y-hidden"
|
|
357
|
-
/>
|
|
358
|
-
) : (
|
|
359
|
-
<div className="flex-1 flex items-center justify-center">
|
|
360
|
-
{status === "building" ? (
|
|
361
|
-
<div className="flex flex-col items-center gap-3 text-gray-500">
|
|
362
|
-
<Loader2 className="w-6 h-6 animate-spin" />
|
|
363
|
-
<p>Building…</p>
|
|
364
|
-
</div>
|
|
365
|
-
) : status === "failed" ? (
|
|
366
|
-
<div className="text-center">
|
|
367
|
-
<p className="text-red-600 font-medium mb-2">
|
|
368
|
-
Build Failed
|
|
369
|
-
</p>
|
|
370
|
-
</div>
|
|
371
|
-
) : null}
|
|
372
|
-
</div>
|
|
373
|
-
)}
|
|
374
|
-
</div>
|
|
375
|
-
</main>
|
|
376
|
-
</div>
|
|
377
|
-
</div>
|
|
378
|
-
</>
|
|
379
|
-
)
|
|
380
|
-
}
|
package/src/pages/settings.tsx
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import Header from "@/components/Header"
|
|
2
|
-
import Footer from "@/components/Footer"
|
|
3
|
-
import ShippingInformationForm from "@/components/ShippingInformationForm"
|
|
4
|
-
|
|
5
|
-
export const SettingsPage = () => {
|
|
6
|
-
return (
|
|
7
|
-
<div>
|
|
8
|
-
<Header />
|
|
9
|
-
<div className="container mx-auto px-4 py-8">
|
|
10
|
-
<h1 className="text-3xl font-bold mb-6">Settings</h1>
|
|
11
|
-
<div className="flex">
|
|
12
|
-
<div className="lg:w-1/2 sm:w-full pr-4">
|
|
13
|
-
<div className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
|
|
14
|
-
<h2 className="text-2xl font-semibold mb-4">
|
|
15
|
-
Shipping Information
|
|
16
|
-
</h2>
|
|
17
|
-
<ShippingInformationForm />
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
<Footer />
|
|
23
|
-
</div>
|
|
24
|
-
)
|
|
25
|
-
}
|