@tscircuit/fake-snippets 0.0.108 → 0.0.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/bun-formatcheck.yml +2 -2
- package/.github/workflows/bun-pver-release.yml +3 -3
- package/.github/workflows/bun-test.yml +1 -1
- package/.github/workflows/bun-typecheck.yml +2 -2
- package/.github/workflows/update-snapshots.yml +1 -1
- package/README.md +4 -0
- package/api/generated-index.js +37 -3
- package/biome.json +2 -1
- package/bun-tests/fake-snippets-api/fixtures/get-test-server.ts +31 -3
- package/bun-tests/fake-snippets-api/fixtures/preload.ts +18 -0
- package/bun-tests/fake-snippets-api/routes/orgs/add_member.test.ts +26 -0
- package/bun-tests/fake-snippets-api/routes/orgs/create.test.ts +37 -0
- package/bun-tests/fake-snippets-api/routes/orgs/get.test.ts +52 -0
- package/bun-tests/fake-snippets-api/routes/orgs/list.test.ts +17 -0
- package/bun-tests/fake-snippets-api/routes/orgs/list_members.test.ts +23 -0
- package/bun-tests/fake-snippets-api/routes/orgs/remove_member.test.ts +81 -0
- package/bun-tests/fake-snippets-api/routes/orgs/update.test.ts +99 -0
- package/bun-tests/fake-snippets-api/routes/package_builds/get.test.ts +1 -1
- package/bun-tests/fake-snippets-api/routes/package_files/create.test.ts +15 -13
- package/bun-tests/fake-snippets-api/routes/package_files/create_or_update.test.ts +26 -24
- package/bun-tests/fake-snippets-api/routes/package_files/delete.test.ts +9 -9
- package/bun-tests/fake-snippets-api/routes/package_files/download.test.ts +4 -4
- package/bun-tests/fake-snippets-api/routes/package_files/get.test.ts +38 -28
- package/bun-tests/fake-snippets-api/routes/package_files/list.test.ts +23 -15
- package/bun-tests/fake-snippets-api/routes/package_releases/create.test.ts +33 -0
- package/bun-tests/fake-snippets-api/routes/package_releases/get.test.ts +4 -4
- package/bun-tests/fake-snippets-api/routes/package_releases/get_image_generation_fields.test.ts +38 -0
- package/bun-tests/fake-snippets-api/routes/packages/create.test.ts +19 -0
- package/bun-tests/fake-snippets-api/routes/packages/fork.test.ts +3 -4
- package/bun-tests/fake-snippets-api/routes/packages/get.test.ts +30 -0
- package/bun-tests/fake-snippets-api/routes/packages/images.test.ts +4 -2
- package/bun-tests/fake-snippets-api/routes/packages/list-1.test.ts +34 -0
- package/bun.lock +389 -450
- package/bunfig.toml +2 -1
- package/dist/bundle.js +1255 -625
- package/dist/index.d.ts +296 -4
- package/dist/index.js +325 -24
- package/dist/schema.d.ts +282 -1
- package/dist/schema.js +54 -2
- package/fake-snippets-api/lib/db/autoload-dev-packages.ts +31 -20
- package/fake-snippets-api/lib/db/db-client.ts +214 -3
- package/fake-snippets-api/lib/db/schema.ts +62 -0
- package/fake-snippets-api/lib/db/seed.ts +100 -0
- package/fake-snippets-api/lib/middleware/with-session-auth.ts +1 -1
- package/fake-snippets-api/lib/package_file/get-package-file-id-from-file-descriptor.ts +2 -2
- package/fake-snippets-api/lib/public-mapping/public-map-org.ts +32 -0
- package/fake-snippets-api/lib/public-mapping/public-map-package-build.ts +10 -0
- package/fake-snippets-api/lib/public-mapping/public-map-package-release.ts +17 -0
- package/fake-snippets-api/routes/api/orgs/add_member.ts +52 -0
- package/fake-snippets-api/routes/api/orgs/create.ts +46 -0
- package/fake-snippets-api/routes/api/orgs/get.ts +39 -0
- package/fake-snippets-api/routes/api/orgs/list.ts +31 -0
- package/fake-snippets-api/routes/api/orgs/list_members.ts +67 -0
- package/fake-snippets-api/routes/api/orgs/remove_member.ts +46 -0
- package/fake-snippets-api/routes/api/orgs/update.ts +93 -0
- package/fake-snippets-api/routes/api/package_files/get.ts +3 -6
- package/fake-snippets-api/routes/api/package_files/list.ts +7 -4
- package/fake-snippets-api/routes/api/packages/create.ts +54 -10
- package/fake-snippets-api/routes/api/packages/get.ts +23 -0
- package/fake-snippets-api/routes/api/packages/images/[owner_github_username]/[unscoped_name]/[view_format].ts +13 -11
- package/fake-snippets-api/routes/api/packages/list.ts +29 -2
- package/fake-snippets-api/routes/api/packages/update_ai_description.ts +37 -0
- package/package.json +27 -24
- package/renovate.json +1 -1
- package/scripts/generate-sitemap.ts +1 -1
- package/src/App.tsx +29 -10
- package/src/ContextProviders.tsx +25 -2
- package/src/components/CircuitJsonImportDialog.tsx +1 -1
- package/src/components/CmdKMenu.tsx +281 -247
- package/src/components/DownloadButtonAndMenu.tsx +133 -36
- package/src/components/FileSidebar.tsx +41 -50
- package/src/components/Footer.tsx +8 -10
- package/src/components/Header.tsx +19 -32
- package/src/components/Header2.tsx +16 -32
- package/src/components/HeaderDropdown.tsx +13 -8
- package/src/components/HeaderLogin.tsx +44 -16
- package/src/components/HiddenFilesDropdown.tsx +0 -2
- package/src/components/NotFound.tsx +5 -5
- package/src/components/PackageBreadcrumb.tsx +6 -12
- package/src/components/PackageCard.tsx +0 -1
- package/src/components/PackageSearchResults.tsx +1 -1
- package/src/components/PrefetchPageLink.tsx +7 -1
- package/src/components/ProfileRouter.tsx +32 -0
- package/src/components/SearchComponent.tsx +12 -8
- package/src/components/UserCard.tsx +80 -0
- package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +20 -11
- package/src/components/ViewPackagePage/components/build-status.tsx +1 -1
- package/src/components/ViewPackagePage/components/important-files-view.tsx +174 -87
- package/src/components/ViewPackagePage/components/main-content-header.tsx +8 -4
- package/src/components/ViewPackagePage/components/main-content-view-selector.tsx +1 -2
- package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +54 -20
- package/src/components/ViewPackagePage/components/package-header.tsx +26 -37
- package/src/components/ViewPackagePage/components/preview-image-squares.tsx +11 -19
- package/src/components/ViewPackagePage/components/repo-page-content.tsx +33 -25
- package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +16 -10
- package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +11 -11
- 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/tab-views/pcb-view.tsx +1 -2
- package/src/components/ViewPackagePage/components/tab-views/schematic-view.tsx +2 -1
- package/src/components/ViewPackagePage/components/theme-toggle.tsx +0 -2
- package/src/components/ViewPackagePage/hooks/use-toast.tsx +0 -1
- package/src/components/dialogs/GitHubRepositorySelector.tsx +56 -49
- package/src/components/dialogs/edit-package-details-dialog.tsx +5 -6
- package/src/components/dialogs/import-component-dialog.tsx +16 -9
- package/src/components/dialogs/import-package-dialog.tsx +3 -2
- package/src/components/dialogs/new-package-save-prompt-dialog.tsx +190 -0
- package/src/components/organization/OrganizationCard.tsx +204 -0
- package/src/components/organization/OrganizationCardSkeleton.tsx +55 -0
- package/src/components/organization/OrganizationHeader.tsx +154 -0
- package/src/components/organization/OrganizationMembers.tsx +146 -0
- package/src/components/package-port/CodeAndPreview.tsx +32 -46
- package/src/components/package-port/CodeEditor.tsx +28 -31
- package/src/components/package-port/CodeEditorHeader.tsx +128 -63
- package/src/components/package-port/EditorNav.tsx +32 -49
- package/src/components/preview/ConnectedPackagesList.tsx +8 -8
- package/src/components/preview/ConnectedRepoOverview.tsx +102 -2
- package/src/components/preview/PackageReleasesDashboard.tsx +53 -36
- package/src/components/ui/tree-view.tsx +6 -3
- package/src/hooks/use-add-org-member-mutation.ts +51 -0
- package/src/hooks/use-create-org-mutation.ts +38 -0
- package/src/hooks/use-create-package-mutation.ts +3 -0
- package/src/hooks/use-current-package-id.ts +5 -30
- package/src/hooks/use-current-package-info.ts +29 -5
- package/src/hooks/use-current-package-release.ts +4 -3
- package/src/hooks/use-download-zip.ts +2 -2
- package/src/hooks/use-global-store.ts +6 -4
- package/src/hooks/use-jlcpcb-component-import.tsx +164 -0
- package/src/hooks/use-list-org-members.ts +27 -0
- package/src/hooks/use-list-user-orgs.ts +25 -0
- package/src/hooks/use-org-by-github-handle.ts +26 -0
- package/src/hooks/use-org.ts +24 -0
- package/src/hooks/use-organization.ts +42 -0
- package/src/hooks/use-package-as-snippet.ts +4 -2
- package/src/hooks/use-package-builds.ts +6 -2
- package/src/hooks/use-package-files.ts +5 -3
- package/src/hooks/use-package-release-by-id-or-version.ts +29 -20
- package/src/hooks/use-package-release-images.ts +105 -0
- package/src/hooks/use-package-release.ts +2 -2
- package/src/hooks/use-package-stars.ts +80 -4
- package/src/hooks/use-preview-images.ts +6 -3
- package/src/hooks/use-remove-org-member-mutation.ts +32 -0
- package/src/hooks/use-update-ai-description-mutation.ts +42 -0
- package/src/hooks/use-update-org-mutation.ts +41 -0
- package/src/hooks/use-warn-user-on-page-change.ts +71 -4
- package/src/hooks/useFileManagement.ts +183 -35
- package/src/hooks/useOptimizedPackageFilesLoader.ts +136 -0
- package/src/hooks/usePackageFilesLoader.ts +2 -2
- package/src/hooks/useUpdatePackageFilesMutation.ts +15 -1
- 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/download-fns/download-kicad-files.ts +12 -11
- package/src/lib/normalize-svg-for-tile.ts +50 -0
- package/src/lib/posthog.ts +11 -9
- package/src/lib/react-query-api-failure-tracking.ts +148 -0
- package/src/lib/sentry.ts +14 -0
- package/src/lib/templates/blank-circuit-board-template.ts +0 -4
- package/src/lib/ts-lib-cache.ts +122 -7
- package/src/lib/utils/checkIfManualEditsImported.ts +4 -4
- package/src/lib/utils/findTargetFile.ts +45 -10
- package/src/lib/utils/isComponentExported.ts +10 -0
- package/src/main.tsx +2 -1
- package/src/pages/authorize.tsx +0 -2
- package/src/pages/create-organization.tsx +168 -0
- package/src/pages/dashboard.tsx +38 -6
- package/src/pages/datasheet.tsx +1 -1
- package/src/pages/datasheets.tsx +3 -3
- package/src/pages/editor.tsx +4 -6
- package/src/pages/landing.tsx +6 -7
- package/src/pages/latest.tsx +3 -0
- package/src/pages/organization-profile.tsx +199 -0
- package/src/pages/organization-settings.tsx +566 -0
- package/src/pages/package-editor.tsx +21 -21
- package/src/pages/preview-release.tsx +76 -136
- package/src/pages/quickstart.tsx +159 -123
- package/src/pages/release-detail.tsx +119 -31
- package/src/pages/search.tsx +192 -57
- package/src/pages/settings-redirect.tsx +44 -0
- package/src/pages/trending.tsx +29 -20
- package/src/pages/user-profile.tsx +58 -7
- package/src/pages/view-package.tsx +21 -26
- package/vite.config.ts +9 -0
- package/fake-snippets-api/routes/api/autocomplete/create_autocomplete.ts +0 -133
- package/src/components/Footer2.tsx +0 -100
- package/src/components/JLCPCBImportDialog.tsx +0 -280
- package/src/components/PackageBuildsPage/LogContent.tsx +0 -72
- package/src/components/PackageBuildsPage/PackageBuildDetailsPage.tsx +0 -115
- package/src/components/PackageBuildsPage/build-preview-content.tsx +0 -27
- package/src/components/PackageBuildsPage/collapsible-section.tsx +0 -63
- package/src/components/PackageBuildsPage/package-build-details-panel.tsx +0 -166
- package/src/components/PackageBuildsPage/package-build-header.tsx +0 -79
- package/src/components/PageSearchComponent.tsx +0 -148
- 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/pages/package-builds.tsx +0 -33
- package/src/pages/settings.tsx +0 -25
|
@@ -18,18 +18,22 @@ import { usePcbDownloadDialog } from "@/components/dialogs/pcb-download-dialog"
|
|
|
18
18
|
import { downloadKicadFiles } from "@/lib/download-fns/download-kicad-files"
|
|
19
19
|
import { AnyCircuitElement } from "circuit-json"
|
|
20
20
|
import { ChevronDown, Download, Hammer } from "lucide-react"
|
|
21
|
-
import {
|
|
21
|
+
import { downloadGltfFromCircuitJson } from "@/lib/download-fns/download-gltf-from-circuit-json"
|
|
22
22
|
import { downloadPngImage } from "@/lib/download-fns/download-png-utils"
|
|
23
23
|
import { ImageFormat } from "@/lib/download-fns/download-circuit-png"
|
|
24
24
|
import { CubeIcon } from "@radix-ui/react-icons"
|
|
25
|
+
import { useState } from "react"
|
|
26
|
+
import { useAxios } from "@/hooks/use-axios"
|
|
27
|
+
import { useCurrentPackageId } from "@/hooks/use-current-package-id"
|
|
25
28
|
|
|
26
29
|
interface DownloadButtonAndMenuProps {
|
|
27
30
|
className?: string
|
|
28
31
|
unscopedName?: string
|
|
29
32
|
author?: string
|
|
30
|
-
|
|
33
|
+
hasCircuitJson?: boolean
|
|
31
34
|
desiredImageType?: string
|
|
32
35
|
offerMultipleImageFormats?: boolean
|
|
36
|
+
circuitJson?: AnyCircuitElement[] | null
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
export function DownloadButtonAndMenu({
|
|
@@ -37,14 +41,51 @@ export function DownloadButtonAndMenu({
|
|
|
37
41
|
unscopedName,
|
|
38
42
|
author,
|
|
39
43
|
desiredImageType = "pcb",
|
|
40
|
-
|
|
44
|
+
hasCircuitJson,
|
|
41
45
|
offerMultipleImageFormats = false,
|
|
46
|
+
circuitJson,
|
|
42
47
|
}: DownloadButtonAndMenuProps) {
|
|
43
48
|
const notImplemented = useNotImplementedToast()
|
|
44
49
|
const { Dialog: PcbDownloadDialog, openDialog: openPcbDownloadDialog } =
|
|
45
50
|
usePcbDownloadDialog()
|
|
51
|
+
const axios = useAxios()
|
|
52
|
+
const { packageId } = useCurrentPackageId()
|
|
53
|
+
const [fetchedCircuitJson, setFetchedCircuitJson] = useState<
|
|
54
|
+
AnyCircuitElement[] | null
|
|
55
|
+
>(null)
|
|
56
|
+
const [isFetchingCircuitJson, setIsFetchingCircuitJson] = useState(false)
|
|
57
|
+
|
|
58
|
+
const canDownload = Boolean(
|
|
59
|
+
hasCircuitJson || (circuitJson && circuitJson.length),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
const getCircuitJson = async (): Promise<AnyCircuitElement[]> => {
|
|
63
|
+
if (circuitJson && circuitJson.length) return circuitJson
|
|
64
|
+
if (fetchedCircuitJson && fetchedCircuitJson.length)
|
|
65
|
+
return fetchedCircuitJson
|
|
66
|
+
setIsFetchingCircuitJson(true)
|
|
67
|
+
try {
|
|
68
|
+
const { data } = await axios.get("/package_files/get", {
|
|
69
|
+
params: { package_id: packageId, file_path: "dist/circuit.json" },
|
|
70
|
+
})
|
|
71
|
+
const content = data?.package_file?.content_text
|
|
72
|
+
if (!content) throw new Error("Circuit JSON not found")
|
|
73
|
+
const parsed = JSON.parse(content)
|
|
74
|
+
setFetchedCircuitJson(parsed)
|
|
75
|
+
return parsed
|
|
76
|
+
} catch (error: any) {
|
|
77
|
+
toast({
|
|
78
|
+
title: "Failed to fetch Circuit JSON",
|
|
79
|
+
description: error?.message || error?.toString?.() || "Unknown error",
|
|
80
|
+
variant: "destructive",
|
|
81
|
+
})
|
|
82
|
+
throw error
|
|
83
|
+
} finally {
|
|
84
|
+
setIsFetchingCircuitJson(false)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
46
87
|
|
|
47
|
-
if (!
|
|
88
|
+
if (!canDownload) {
|
|
48
89
|
return (
|
|
49
90
|
<div className={className}>
|
|
50
91
|
<Button
|
|
@@ -66,7 +107,7 @@ export function DownloadButtonAndMenu({
|
|
|
66
107
|
<DropdownMenuTrigger asChild>
|
|
67
108
|
<Button
|
|
68
109
|
size="sm"
|
|
69
|
-
className="bg-white shadow-none text-gray-900 hover:bg-gray-100 border border-gray-300 px-1 pl-2"
|
|
110
|
+
className="bg-white shadow-none text-gray-900 hover:bg-gray-100 border border-gray-300 px-1 pl-2 select-none"
|
|
70
111
|
>
|
|
71
112
|
<Download className="w-4 h-4 mr-2" />
|
|
72
113
|
Download
|
|
@@ -76,11 +117,9 @@ export function DownloadButtonAndMenu({
|
|
|
76
117
|
<DropdownMenuContent className="!z-[101]">
|
|
77
118
|
<DropdownMenuItem
|
|
78
119
|
className="text-xs"
|
|
79
|
-
onSelect={() => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
unscopedName || "circuit" + ".json",
|
|
83
|
-
)
|
|
120
|
+
onSelect={async () => {
|
|
121
|
+
const cj = await getCircuitJson()
|
|
122
|
+
downloadCircuitJson(cj, unscopedName || "circuit" + ".json")
|
|
84
123
|
}}
|
|
85
124
|
>
|
|
86
125
|
<Download className="mr-1 h-3 w-3" />
|
|
@@ -93,7 +132,12 @@ export function DownloadButtonAndMenu({
|
|
|
93
132
|
className="text-xs"
|
|
94
133
|
onClick={async () => {
|
|
95
134
|
try {
|
|
96
|
-
await
|
|
135
|
+
const cj = await getCircuitJson()
|
|
136
|
+
await downloadGltfFromCircuitJson(
|
|
137
|
+
cj,
|
|
138
|
+
unscopedName || "circuit",
|
|
139
|
+
{ format: "glb", boardTextureResolution: 2048 },
|
|
140
|
+
)
|
|
97
141
|
} catch (error: any) {
|
|
98
142
|
toast({
|
|
99
143
|
title: "Error Downloading 3D Model",
|
|
@@ -112,8 +156,34 @@ export function DownloadButtonAndMenu({
|
|
|
112
156
|
<DropdownMenuItem
|
|
113
157
|
className="text-xs"
|
|
114
158
|
onClick={async () => {
|
|
159
|
+
try {
|
|
160
|
+
const cj = await getCircuitJson()
|
|
161
|
+
await downloadGltfFromCircuitJson(
|
|
162
|
+
cj,
|
|
163
|
+
unscopedName || "circuit",
|
|
164
|
+
{ format: "gltf", boardTextureResolution: 2048 },
|
|
165
|
+
)
|
|
166
|
+
} catch (error: any) {
|
|
167
|
+
toast({
|
|
168
|
+
title: "Error Downloading 3D Model (GLTF)",
|
|
169
|
+
description: error.toString(),
|
|
170
|
+
variant: "destructive",
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
}}
|
|
174
|
+
>
|
|
175
|
+
<CubeIcon className="mr-1 h-3 w-3" />
|
|
176
|
+
<span className="flex-grow mr-6">3D Model</span>
|
|
177
|
+
<span className="text-[0.6rem] bg-green-500 opacity-80 text-white font-mono rounded-md px-1 text-center py-0.5 mr-1">
|
|
178
|
+
gltf
|
|
179
|
+
</span>
|
|
180
|
+
</DropdownMenuItem>
|
|
181
|
+
<DropdownMenuItem
|
|
182
|
+
className="text-xs"
|
|
183
|
+
onClick={async () => {
|
|
184
|
+
const cj = await getCircuitJson()
|
|
115
185
|
await downloadFabricationFiles({
|
|
116
|
-
circuitJson,
|
|
186
|
+
circuitJson: cj,
|
|
117
187
|
snippetUnscopedName: unscopedName || "snippet",
|
|
118
188
|
}).catch((error) => {
|
|
119
189
|
console.error(error)
|
|
@@ -144,8 +214,9 @@ export function DownloadButtonAndMenu({
|
|
|
144
214
|
</DropdownMenuItem>
|
|
145
215
|
<DropdownMenuItem
|
|
146
216
|
className="text-xs"
|
|
147
|
-
onSelect={() => {
|
|
148
|
-
|
|
217
|
+
onSelect={async () => {
|
|
218
|
+
const cj = await getCircuitJson()
|
|
219
|
+
downloadKicadFiles(cj, unscopedName || "kicad_project")
|
|
149
220
|
}}
|
|
150
221
|
>
|
|
151
222
|
<Download className="mr-1 h-3 w-3" />
|
|
@@ -157,8 +228,9 @@ export function DownloadButtonAndMenu({
|
|
|
157
228
|
|
|
158
229
|
<DropdownMenuItem
|
|
159
230
|
className="text-xs"
|
|
160
|
-
onSelect={() => {
|
|
161
|
-
|
|
231
|
+
onSelect={async () => {
|
|
232
|
+
const cj = await getCircuitJson()
|
|
233
|
+
downloadSchematicSvg(cj, unscopedName || "circuit")
|
|
162
234
|
}}
|
|
163
235
|
>
|
|
164
236
|
<Download className="mr-1 h-3 w-3" />
|
|
@@ -169,8 +241,9 @@ export function DownloadButtonAndMenu({
|
|
|
169
241
|
</DropdownMenuItem>
|
|
170
242
|
<DropdownMenuItem
|
|
171
243
|
className="text-xs"
|
|
172
|
-
onSelect={() => {
|
|
173
|
-
|
|
244
|
+
onSelect={async () => {
|
|
245
|
+
const cj = await getCircuitJson()
|
|
246
|
+
downloadAssemblySvg(cj, unscopedName || "circuit")
|
|
174
247
|
}}
|
|
175
248
|
>
|
|
176
249
|
<Download className="mr-1 h-3 w-3" />
|
|
@@ -181,7 +254,9 @@ export function DownloadButtonAndMenu({
|
|
|
181
254
|
</DropdownMenuItem>
|
|
182
255
|
<DropdownMenuItem
|
|
183
256
|
className="text-xs"
|
|
184
|
-
onSelect={() => {
|
|
257
|
+
onSelect={async () => {
|
|
258
|
+
const cj = await getCircuitJson()
|
|
259
|
+
setFetchedCircuitJson(cj)
|
|
185
260
|
openPcbDownloadDialog()
|
|
186
261
|
}}
|
|
187
262
|
>
|
|
@@ -193,8 +268,9 @@ export function DownloadButtonAndMenu({
|
|
|
193
268
|
</DropdownMenuItem>
|
|
194
269
|
<DropdownMenuItem
|
|
195
270
|
className="text-xs"
|
|
196
|
-
onSelect={() => {
|
|
197
|
-
|
|
271
|
+
onSelect={async () => {
|
|
272
|
+
const cj = await getCircuitJson()
|
|
273
|
+
downloadDsnFile(cj, unscopedName || "circuit")
|
|
198
274
|
}}
|
|
199
275
|
>
|
|
200
276
|
<Download className="mr-1 h-3 w-3" />
|
|
@@ -205,8 +281,9 @@ export function DownloadButtonAndMenu({
|
|
|
205
281
|
</DropdownMenuItem>
|
|
206
282
|
<DropdownMenuItem
|
|
207
283
|
className="text-xs"
|
|
208
|
-
onClick={() => {
|
|
209
|
-
|
|
284
|
+
onClick={async () => {
|
|
285
|
+
const cj = await getCircuitJson()
|
|
286
|
+
downloadReadableNetlist(cj, unscopedName || "circuit")
|
|
210
287
|
}}
|
|
211
288
|
>
|
|
212
289
|
<Download className="mr-1 h-3 w-3" />
|
|
@@ -217,8 +294,9 @@ export function DownloadButtonAndMenu({
|
|
|
217
294
|
</DropdownMenuItem>
|
|
218
295
|
<DropdownMenuItem
|
|
219
296
|
className="text-xs"
|
|
220
|
-
onSelect={() => {
|
|
221
|
-
|
|
297
|
+
onSelect={async () => {
|
|
298
|
+
const cj = await getCircuitJson()
|
|
299
|
+
downloadSpiceFile(cj, unscopedName || "circuit")
|
|
222
300
|
}}
|
|
223
301
|
>
|
|
224
302
|
<Download className="mr-1 h-3 w-3" />
|
|
@@ -229,8 +307,9 @@ export function DownloadButtonAndMenu({
|
|
|
229
307
|
</DropdownMenuItem>
|
|
230
308
|
<DropdownMenuItem
|
|
231
309
|
className="text-xs"
|
|
232
|
-
onSelect={() => {
|
|
233
|
-
|
|
310
|
+
onSelect={async () => {
|
|
311
|
+
const cj = await getCircuitJson()
|
|
312
|
+
downloadSimpleRouteJson(cj, unscopedName || "circuit")
|
|
234
313
|
}}
|
|
235
314
|
>
|
|
236
315
|
<Download className="mr-1 h-3 w-3" />
|
|
@@ -243,7 +322,7 @@ export function DownloadButtonAndMenu({
|
|
|
243
322
|
{!offerMultipleImageFormats && (
|
|
244
323
|
<DropdownMenuItem
|
|
245
324
|
className="text-xs"
|
|
246
|
-
onClick={() => {
|
|
325
|
+
onClick={async () => {
|
|
247
326
|
const desiredImageFormat = [
|
|
248
327
|
"pcb",
|
|
249
328
|
"schematic",
|
|
@@ -252,8 +331,9 @@ export function DownloadButtonAndMenu({
|
|
|
252
331
|
].includes(desiredImageType)
|
|
253
332
|
? desiredImageType
|
|
254
333
|
: "pcb"
|
|
334
|
+
const cj = await getCircuitJson()
|
|
255
335
|
downloadPngImage({
|
|
256
|
-
circuitJson,
|
|
336
|
+
circuitJson: cj,
|
|
257
337
|
unscopedName,
|
|
258
338
|
author,
|
|
259
339
|
format: desiredImageFormat as ImageFormat,
|
|
@@ -271,9 +351,9 @@ export function DownloadButtonAndMenu({
|
|
|
271
351
|
<>
|
|
272
352
|
<DropdownMenuItem
|
|
273
353
|
className="text-xs"
|
|
274
|
-
onClick={() =>
|
|
354
|
+
onClick={async () =>
|
|
275
355
|
downloadPngImage({
|
|
276
|
-
circuitJson,
|
|
356
|
+
circuitJson: await getCircuitJson(),
|
|
277
357
|
unscopedName,
|
|
278
358
|
author,
|
|
279
359
|
format: "schematic",
|
|
@@ -288,9 +368,9 @@ export function DownloadButtonAndMenu({
|
|
|
288
368
|
</DropdownMenuItem>
|
|
289
369
|
<DropdownMenuItem
|
|
290
370
|
className="text-xs"
|
|
291
|
-
onClick={() =>
|
|
371
|
+
onClick={async () =>
|
|
292
372
|
downloadPngImage({
|
|
293
|
-
circuitJson,
|
|
373
|
+
circuitJson: await getCircuitJson(),
|
|
294
374
|
unscopedName,
|
|
295
375
|
author,
|
|
296
376
|
format: "pcb",
|
|
@@ -305,9 +385,9 @@ export function DownloadButtonAndMenu({
|
|
|
305
385
|
</DropdownMenuItem>
|
|
306
386
|
<DropdownMenuItem
|
|
307
387
|
className="text-xs"
|
|
308
|
-
onClick={() =>
|
|
388
|
+
onClick={async () =>
|
|
309
389
|
downloadPngImage({
|
|
310
|
-
circuitJson,
|
|
390
|
+
circuitJson: await getCircuitJson(),
|
|
311
391
|
unscopedName,
|
|
312
392
|
author,
|
|
313
393
|
format: "assembly",
|
|
@@ -320,12 +400,29 @@ export function DownloadButtonAndMenu({
|
|
|
320
400
|
png
|
|
321
401
|
</span>
|
|
322
402
|
</DropdownMenuItem>
|
|
403
|
+
<DropdownMenuItem
|
|
404
|
+
className="text-xs"
|
|
405
|
+
onClick={async () =>
|
|
406
|
+
downloadPngImage({
|
|
407
|
+
circuitJson: await getCircuitJson(),
|
|
408
|
+
unscopedName,
|
|
409
|
+
author,
|
|
410
|
+
format: "3d",
|
|
411
|
+
})
|
|
412
|
+
}
|
|
413
|
+
>
|
|
414
|
+
<Download className="mr-1 h-3 w-3" />
|
|
415
|
+
<span className="flex-grow mr-6">3D PNG</span>
|
|
416
|
+
<span className="text-[0.6rem] opacity-80 bg-teal-600 text-white font-mono rounded-md px-1 text-center py-0.5 mr-1">
|
|
417
|
+
png
|
|
418
|
+
</span>
|
|
419
|
+
</DropdownMenuItem>
|
|
323
420
|
</>
|
|
324
421
|
)}
|
|
325
422
|
</DropdownMenuContent>
|
|
326
423
|
</DropdownMenu>
|
|
327
424
|
<PcbDownloadDialog
|
|
328
|
-
circuitJson={circuitJson}
|
|
425
|
+
circuitJson={fetchedCircuitJson || circuitJson || []}
|
|
329
426
|
fileName={unscopedName || "circuit"}
|
|
330
427
|
/>
|
|
331
428
|
</div>
|
|
@@ -1,25 +1,9 @@
|
|
|
1
|
-
import React, { useState } from "react"
|
|
1
|
+
import React, { useMemo, useState } from "react"
|
|
2
2
|
import { cn } from "@/lib/utils"
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
Folder,
|
|
6
|
-
MoreVertical,
|
|
7
|
-
PanelRightOpen,
|
|
8
|
-
Plus,
|
|
9
|
-
Trash2,
|
|
10
|
-
Pencil,
|
|
11
|
-
} from "lucide-react"
|
|
12
|
-
import { TreeView, TreeDataItem } from "@/components/ui/tree-view"
|
|
13
|
-
import { isHiddenFile } from "./ViewPackagePage/utils/is-hidden-file"
|
|
3
|
+
import { PanelRightOpen, Plus, Loader2 } from "lucide-react"
|
|
4
|
+
import { TreeView } from "@/components/ui/tree-view"
|
|
14
5
|
import { Input } from "@/components/ui/input"
|
|
15
6
|
import { transformFilesToTreeData } from "@/lib/utils/transformFilesToTreeData"
|
|
16
|
-
import {
|
|
17
|
-
DropdownMenu,
|
|
18
|
-
DropdownMenuContent,
|
|
19
|
-
DropdownMenuGroup,
|
|
20
|
-
DropdownMenuItem,
|
|
21
|
-
DropdownMenuTrigger,
|
|
22
|
-
} from "./ui/dropdown-menu"
|
|
23
7
|
import type {
|
|
24
8
|
ICreateFileProps,
|
|
25
9
|
ICreateFileResult,
|
|
@@ -28,8 +12,6 @@ import type {
|
|
|
28
12
|
IRenameFileProps,
|
|
29
13
|
IRenameFileResult,
|
|
30
14
|
} from "@/hooks/useFileManagement"
|
|
31
|
-
import { useToast } from "@/hooks/use-toast"
|
|
32
|
-
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
33
15
|
import type { Package } from "fake-snippets-api/lib/db/schema"
|
|
34
16
|
type FileName = string
|
|
35
17
|
|
|
@@ -45,6 +27,8 @@ interface FileSidebarProps {
|
|
|
45
27
|
isCreatingFile: boolean
|
|
46
28
|
setIsCreatingFile: React.Dispatch<React.SetStateAction<boolean>>
|
|
47
29
|
pkg?: Package
|
|
30
|
+
isLoadingFiles?: boolean
|
|
31
|
+
loadingProgress?: string | null
|
|
48
32
|
}
|
|
49
33
|
|
|
50
34
|
const FileSidebar: React.FC<FileSidebarProps> = ({
|
|
@@ -58,6 +42,9 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
|
|
|
58
42
|
handleRenameFile,
|
|
59
43
|
isCreatingFile,
|
|
60
44
|
setIsCreatingFile,
|
|
45
|
+
pkg,
|
|
46
|
+
isLoadingFiles = true,
|
|
47
|
+
loadingProgress = null,
|
|
61
48
|
}) => {
|
|
62
49
|
const [sidebarOpen, setSidebarOpen] = fileSidebarState
|
|
63
50
|
const [newFileName, setNewFileName] = useState("")
|
|
@@ -66,11 +53,8 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
|
|
|
66
53
|
const [selectedFolderForCreation, setSelectedFolderForCreation] = useState<
|
|
67
54
|
string | null
|
|
68
55
|
>(null)
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
)
|
|
72
|
-
const { toast } = useToast()
|
|
73
|
-
const canModifyFiles = true
|
|
56
|
+
const selectedItemId = useMemo(() => currentFile || "", [currentFile])
|
|
57
|
+
const canModifyFiles = Boolean(pkg) && !isLoadingFiles
|
|
74
58
|
|
|
75
59
|
const onFolderSelect = (folderPath: string) => {
|
|
76
60
|
setSelectedFolderForCreation(folderPath)
|
|
@@ -152,7 +136,6 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
|
|
|
152
136
|
setNewFileName("")
|
|
153
137
|
setErrorMessage("")
|
|
154
138
|
onFileSelect(finalFileName)
|
|
155
|
-
setSelectedItemId(finalFileName)
|
|
156
139
|
setSelectedFolderForCreation(null)
|
|
157
140
|
}
|
|
158
141
|
}
|
|
@@ -184,19 +167,31 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
|
|
|
184
167
|
className,
|
|
185
168
|
)}
|
|
186
169
|
>
|
|
187
|
-
<
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
170
|
+
<div className="flex items-center justify-between px-2 py-2">
|
|
171
|
+
<button
|
|
172
|
+
onClick={toggleSidebar}
|
|
173
|
+
className={`text-gray-400 scale-90 transition-opacity duration-200 ${!sidebarOpen ? "opacity-0 pointer-events-none" : "opacity-100"}`}
|
|
174
|
+
>
|
|
175
|
+
<PanelRightOpen />
|
|
176
|
+
</button>
|
|
177
|
+
<div className="flex items-center gap-2">
|
|
178
|
+
{isLoadingFiles && (
|
|
179
|
+
<div className="flex items-center gap-1">
|
|
180
|
+
<Loader2 className="w-3 h-3 animate-spin text-gray-400" />
|
|
181
|
+
{loadingProgress && (
|
|
182
|
+
<span className="text-xs text-gray-400">{loadingProgress}</span>
|
|
183
|
+
)}
|
|
184
|
+
</div>
|
|
185
|
+
)}
|
|
186
|
+
<button
|
|
187
|
+
onClick={() => setIsCreatingFile(true)}
|
|
188
|
+
className="text-gray-400 hover:text-gray-600"
|
|
189
|
+
aria-label="Create new file"
|
|
190
|
+
>
|
|
191
|
+
<Plus className="w-5 h-5" />
|
|
192
|
+
</button>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
200
195
|
{isCreatingFile && (
|
|
201
196
|
<div className="p-2">
|
|
202
197
|
<Input
|
|
@@ -253,18 +248,14 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
|
|
|
253
248
|
</div>
|
|
254
249
|
</div>
|
|
255
250
|
)}
|
|
256
|
-
<div
|
|
257
|
-
onClick={(e) => {
|
|
258
|
-
if (e.target === e.currentTarget) {
|
|
259
|
-
setSelectedFolderForCreation(null)
|
|
260
|
-
setSelectedItemId("")
|
|
261
|
-
}
|
|
262
|
-
}}
|
|
263
|
-
className="flex-1 border-2 h-full"
|
|
264
|
-
>
|
|
251
|
+
<div className="flex-1 border-t h-full">
|
|
265
252
|
<TreeView
|
|
266
253
|
data={treeData}
|
|
267
|
-
setSelectedItemId={(value) =>
|
|
254
|
+
setSelectedItemId={(value) => {
|
|
255
|
+
if (value && files[value]) {
|
|
256
|
+
onFileSelect(value)
|
|
257
|
+
}
|
|
258
|
+
}}
|
|
268
259
|
selectedItemId={selectedItemId}
|
|
269
260
|
onSelectChange={(item) => {
|
|
270
261
|
if (item?.onClick) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
2
2
|
import { CircuitBoard } from "lucide-react"
|
|
3
3
|
import { Link } from "wouter"
|
|
4
|
-
import { PrefetchPageLink } from "./PrefetchPageLink"
|
|
5
4
|
|
|
6
5
|
export default function Footer() {
|
|
7
6
|
const session = useGlobalStore((s) => s.session)
|
|
@@ -31,17 +30,16 @@ export default function Footer() {
|
|
|
31
30
|
href: `/${session?.github_username}`,
|
|
32
31
|
hidden: !isLoggedIn,
|
|
33
32
|
},
|
|
34
|
-
{ name: "Settings", href: "/settings" },
|
|
35
33
|
]
|
|
36
34
|
.filter((item) => !item.hidden)
|
|
37
35
|
.map((item) => (
|
|
38
|
-
<
|
|
36
|
+
<Link
|
|
39
37
|
key={item.name}
|
|
40
38
|
href={item.href}
|
|
41
39
|
className="hover:underline"
|
|
42
40
|
>
|
|
43
41
|
{item.name}
|
|
44
|
-
</
|
|
42
|
+
</Link>
|
|
45
43
|
))}
|
|
46
44
|
<a
|
|
47
45
|
href="https://chat.tscircuit.com"
|
|
@@ -56,15 +54,15 @@ export default function Footer() {
|
|
|
56
54
|
<div className="space-y-4">
|
|
57
55
|
<h3 className="font-semibold uppercase">Explore</h3>
|
|
58
56
|
<footer className="flex flex-col space-y-2">
|
|
59
|
-
<
|
|
57
|
+
<Link href="/latest" className="hover:underline">
|
|
60
58
|
Latest Packages
|
|
61
|
-
</
|
|
62
|
-
<
|
|
59
|
+
</Link>
|
|
60
|
+
<Link href="/trending" className="hover:underline">
|
|
63
61
|
Trending Packages
|
|
64
|
-
</
|
|
65
|
-
<
|
|
62
|
+
</Link>
|
|
63
|
+
<Link href="/search" className="hover:underline">
|
|
66
64
|
Search Packages
|
|
67
|
-
</
|
|
65
|
+
</Link>
|
|
68
66
|
<a href="https://docs.tscircuit.com" className="hover:underline">
|
|
69
67
|
Docs
|
|
70
68
|
</a>
|
|
@@ -6,7 +6,7 @@ import { GitHubLogoIcon, DiscordLogoIcon } from "@radix-ui/react-icons"
|
|
|
6
6
|
import { Menu, X } from "lucide-react"
|
|
7
7
|
import React, { useEffect, useState } from "react"
|
|
8
8
|
import { useLocation } from "wouter"
|
|
9
|
-
import {
|
|
9
|
+
import { Link } from "wouter"
|
|
10
10
|
import CmdKMenu from "./CmdKMenu"
|
|
11
11
|
import HeaderDropdown from "./HeaderDropdown"
|
|
12
12
|
import SearchComponent from "./SearchComponent"
|
|
@@ -27,23 +27,23 @@ const HeaderButton = ({
|
|
|
27
27
|
|
|
28
28
|
if (location === href || location === alsoHighlightForUrl) {
|
|
29
29
|
return (
|
|
30
|
-
<
|
|
30
|
+
<Link className={cn("header-button", className)} href={href}>
|
|
31
31
|
<Button
|
|
32
32
|
variant="ghost"
|
|
33
33
|
className={`border-b-2 rounded-none border-blue-600 header-button ${className}`}
|
|
34
34
|
>
|
|
35
35
|
{children}
|
|
36
36
|
</Button>
|
|
37
|
-
</
|
|
37
|
+
</Link>
|
|
38
38
|
)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
|
-
<
|
|
42
|
+
<Link className={cn("header-button", className)} href={href}>
|
|
43
43
|
<Button className={className} variant="ghost">
|
|
44
44
|
{children}
|
|
45
45
|
</Button>
|
|
46
|
-
</
|
|
46
|
+
</Link>
|
|
47
47
|
)
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -59,14 +59,14 @@ export default function Header() {
|
|
|
59
59
|
return (
|
|
60
60
|
<header className="px-4 py-3">
|
|
61
61
|
<div className="flex items-center">
|
|
62
|
-
<
|
|
62
|
+
<Link
|
|
63
63
|
href="/"
|
|
64
|
-
className="text-lg font-semibold whitespace-nowrap"
|
|
64
|
+
className="text-lg font-semibold whitespace-nowrap select-none"
|
|
65
65
|
>
|
|
66
66
|
<span className="bg-blue-500 px-2 py-1 rounded-md text-white">
|
|
67
67
|
tscircuit
|
|
68
68
|
</span>
|
|
69
|
-
</
|
|
69
|
+
</Link>
|
|
70
70
|
<div className="hidden md:flex items-center space-x-4">
|
|
71
71
|
<nav>
|
|
72
72
|
<ul className="flex items-center gap-2 ml-2">
|
|
@@ -80,9 +80,6 @@ export default function Header() {
|
|
|
80
80
|
Editor
|
|
81
81
|
</HeaderButton>
|
|
82
82
|
</li>
|
|
83
|
-
<li>
|
|
84
|
-
<HeaderButton href="/datasheets">Datasheets</HeaderButton>
|
|
85
|
-
</li>
|
|
86
83
|
<li>
|
|
87
84
|
<a href="https://chat.tscircuit.com">
|
|
88
85
|
<Button variant="ghost">AI</Button>
|
|
@@ -93,28 +90,26 @@ export default function Header() {
|
|
|
93
90
|
<Button variant="ghost">Docs</Button>
|
|
94
91
|
</a>
|
|
95
92
|
</li>
|
|
96
|
-
<li>
|
|
97
|
-
<a
|
|
98
|
-
href="https://tscircuit.com/join"
|
|
99
|
-
target="_blank"
|
|
100
|
-
className="mr-2"
|
|
101
|
-
>
|
|
102
|
-
<Button variant="ghost">
|
|
103
|
-
<DiscordLogoIcon className="text-gray-400 hover:text-gray-600 transition-colors w-4 h-4" />
|
|
104
|
-
</Button>
|
|
105
|
-
</a>
|
|
106
|
-
</li>
|
|
107
93
|
</ul>
|
|
108
94
|
</nav>
|
|
109
95
|
</div>
|
|
110
96
|
<div className="flex-grow"></div>
|
|
97
|
+
<a
|
|
98
|
+
href="https://tscircuit.com/join"
|
|
99
|
+
target="_blank"
|
|
100
|
+
className="lg:mr-2"
|
|
101
|
+
>
|
|
102
|
+
<Button variant="ghost">
|
|
103
|
+
<DiscordLogoIcon className="text-gray-400 hidden lg:block hover:text-gray-600 transition-colors w-4 h-4" />
|
|
104
|
+
</Button>
|
|
105
|
+
</a>
|
|
111
106
|
<a
|
|
112
107
|
href="https://github.com/tscircuit/tscircuit"
|
|
113
108
|
target="_blank"
|
|
114
|
-
className="mr-4"
|
|
109
|
+
className="lg:mr-4"
|
|
115
110
|
aria-label="View TSCircuit on GitHub"
|
|
116
111
|
>
|
|
117
|
-
<GitHubLogoIcon className="text-gray-400 hover:text-gray-600 transition-colors" />
|
|
112
|
+
<GitHubLogoIcon className="hidden lg:block text-gray-400 hover:text-gray-600 transition-colors" />
|
|
118
113
|
</a>
|
|
119
114
|
{/* <a href="https://tscircuit.com/join" target="_blank" className="mr-2">
|
|
120
115
|
<DiscordLogoIcon className="text-gray-400 hover:text-gray-600 transition-colors" />
|
|
@@ -155,14 +150,6 @@ export default function Header() {
|
|
|
155
150
|
Editor
|
|
156
151
|
</HeaderButton>
|
|
157
152
|
</li>
|
|
158
|
-
<li>
|
|
159
|
-
<HeaderButton
|
|
160
|
-
className="w-full justify-start"
|
|
161
|
-
href="/datasheets"
|
|
162
|
-
>
|
|
163
|
-
Datasheets
|
|
164
|
-
</HeaderButton>
|
|
165
|
-
</li>
|
|
166
153
|
<li>
|
|
167
154
|
<HeaderButton
|
|
168
155
|
className="w-full justify-start"
|