@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
|
@@ -12,10 +12,7 @@ import { Lock, Globe } from "lucide-react"
|
|
|
12
12
|
import { GitFork, Package, Star } from "lucide-react"
|
|
13
13
|
|
|
14
14
|
import { useForkPackageMutation } from "@/hooks/use-fork-package-mutation"
|
|
15
|
-
import {
|
|
16
|
-
usePackageStarMutationByName,
|
|
17
|
-
usePackageStarsByName,
|
|
18
|
-
} from "@/hooks/use-package-stars"
|
|
15
|
+
import { usePackageStarringByName } from "@/hooks/use-package-stars"
|
|
19
16
|
import { useOrderDialog } from "@tscircuit/runframe"
|
|
20
17
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
21
18
|
import { Package as PackageType } from "fake-snippets-api/lib/db/schema"
|
|
@@ -32,7 +29,7 @@ export default function PackageHeader({
|
|
|
32
29
|
isPrivate = false,
|
|
33
30
|
isCurrentUserAuthor = false,
|
|
34
31
|
}: PackageHeaderProps) {
|
|
35
|
-
const
|
|
32
|
+
const accountName = packageInfo?.owner_github_username
|
|
36
33
|
const packageName = packageInfo?.unscoped_name
|
|
37
34
|
const sessionToken = useGlobalStore((s) => s.session?.token)
|
|
38
35
|
const isOwner =
|
|
@@ -45,10 +42,9 @@ export default function PackageHeader({
|
|
|
45
42
|
isLoggedIn,
|
|
46
43
|
packageReleaseId: packageInfo?.latest_package_release_id ?? "",
|
|
47
44
|
})
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
packageInfo?.name ?? "",
|
|
45
|
+
|
|
46
|
+
const { isStarred, starCount, toggleStar } = usePackageStarringByName(
|
|
47
|
+
packageInfo?.name ?? null,
|
|
52
48
|
)
|
|
53
49
|
|
|
54
50
|
const { mutateAsync: forkPackage, isLoading: isForkLoading } =
|
|
@@ -56,12 +52,7 @@ export default function PackageHeader({
|
|
|
56
52
|
|
|
57
53
|
const handleStarClick = async () => {
|
|
58
54
|
if (!packageInfo?.name || !isLoggedIn) return
|
|
59
|
-
|
|
60
|
-
if (starData?.is_starred) {
|
|
61
|
-
await removeStar.mutateAsync()
|
|
62
|
-
} else {
|
|
63
|
-
await addStar.mutateAsync()
|
|
64
|
-
}
|
|
55
|
+
await toggleStar()
|
|
65
56
|
}
|
|
66
57
|
|
|
67
58
|
const handleForkClick = async () => {
|
|
@@ -69,9 +60,6 @@ export default function PackageHeader({
|
|
|
69
60
|
await forkPackage(packageInfo.package_id)
|
|
70
61
|
}
|
|
71
62
|
|
|
72
|
-
const isStarLoading =
|
|
73
|
-
isStarDataLoading || addStar.isLoading || removeStar.isLoading
|
|
74
|
-
|
|
75
63
|
useEffect(() => {
|
|
76
64
|
window.TSCIRCUIT_REGISTRY_API_BASE_URL =
|
|
77
65
|
import.meta.env.VITE_TSCIRCUIT_REGISTRY_API_URL ??
|
|
@@ -86,18 +74,18 @@ export default function PackageHeader({
|
|
|
86
74
|
<div className="max-w-[1200px] mx-auto px-4">
|
|
87
75
|
<div className="flex items-center justify-between flex-wrap gap-y-2">
|
|
88
76
|
<div className="flex items-center min-w-0 flex-wrap">
|
|
89
|
-
{
|
|
77
|
+
{accountName && packageName ? (
|
|
90
78
|
<>
|
|
91
79
|
<h1 className="text-lg md:text-xl font-bold mr-2 break-words">
|
|
92
80
|
<Link
|
|
93
|
-
href={`/${
|
|
81
|
+
href={`/${accountName}`}
|
|
94
82
|
className="text-blue-600 hover:underline"
|
|
95
83
|
>
|
|
96
|
-
{
|
|
84
|
+
{accountName}
|
|
97
85
|
</Link>
|
|
98
86
|
<span className="px-1 text-gray-500">/</span>
|
|
99
87
|
<Link
|
|
100
|
-
href={`/${
|
|
88
|
+
href={`/${accountName}/${packageName}`}
|
|
101
89
|
className="text-blue-600 hover:underline"
|
|
102
90
|
>
|
|
103
91
|
{packageName}
|
|
@@ -131,7 +119,12 @@ export default function PackageHeader({
|
|
|
131
119
|
</div>
|
|
132
120
|
|
|
133
121
|
<div className="hidden md:flex items-center space-x-2">
|
|
134
|
-
<Button
|
|
122
|
+
<Button
|
|
123
|
+
variant="outline"
|
|
124
|
+
size="sm"
|
|
125
|
+
onClick={open}
|
|
126
|
+
disabled={!packageInfo?.latest_package_release_id}
|
|
127
|
+
>
|
|
135
128
|
<Package className="w-4 h-4 mr-2" />
|
|
136
129
|
Order
|
|
137
130
|
</Button>
|
|
@@ -149,21 +142,17 @@ export default function PackageHeader({
|
|
|
149
142
|
: ""
|
|
150
143
|
}
|
|
151
144
|
onClick={handleStarClick}
|
|
152
|
-
disabled={
|
|
153
|
-
isStarLoading || !packageInfo?.name || !isLoggedIn
|
|
154
|
-
}
|
|
145
|
+
disabled={!packageInfo?.name || !isLoggedIn}
|
|
155
146
|
>
|
|
156
147
|
<Star
|
|
157
148
|
className={`w-4 h-4 mr-2 ${
|
|
158
|
-
|
|
159
|
-
? "fill-yellow-500 text-yellow-500"
|
|
160
|
-
: ""
|
|
149
|
+
isStarred ? "fill-yellow-500 text-yellow-500" : ""
|
|
161
150
|
}`}
|
|
162
151
|
/>
|
|
163
|
-
{
|
|
164
|
-
{(
|
|
152
|
+
{isStarred ? "Starred" : "Star"}
|
|
153
|
+
{(starCount ?? 0) > 0 && (
|
|
165
154
|
<span className="ml-1.5 bg-gray-100 text-gray-700 rounded-full px-1.5 py-0.5 text-xs font-medium">
|
|
166
|
-
{
|
|
155
|
+
{starCount}
|
|
167
156
|
</span>
|
|
168
157
|
)}
|
|
169
158
|
</Button>
|
|
@@ -225,17 +214,17 @@ export default function PackageHeader({
|
|
|
225
214
|
: ""
|
|
226
215
|
}
|
|
227
216
|
onClick={handleStarClick}
|
|
228
|
-
disabled={
|
|
217
|
+
disabled={!packageInfo?.name || !isLoggedIn}
|
|
229
218
|
>
|
|
230
219
|
<Star
|
|
231
220
|
className={`w-4 h-4 mr-2 ${
|
|
232
|
-
|
|
221
|
+
isStarred ? "fill-yellow-500 text-yellow-500" : ""
|
|
233
222
|
}`}
|
|
234
223
|
/>
|
|
235
|
-
{
|
|
236
|
-
{(
|
|
224
|
+
{isStarred ? "Starred" : "Star"}
|
|
225
|
+
{(starCount ?? 0) > 0 && (
|
|
237
226
|
<span className="ml-1.5 bg-gray-100 text-gray-700 rounded-full px-1.5 py-0.5 text-xs font-medium">
|
|
238
|
-
{
|
|
227
|
+
{starCount}
|
|
239
228
|
</span>
|
|
240
229
|
)}
|
|
241
230
|
</Button>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
import { Skeleton } from "@/components/ui/skeleton"
|
|
3
1
|
import { usePreviewImages } from "@/hooks/use-preview-images"
|
|
4
2
|
import type { Package } from "fake-snippets-api/lib/db/schema"
|
|
5
3
|
|
|
6
4
|
interface ViewPlaceholdersProps {
|
|
7
|
-
packageInfo?: Pick<
|
|
5
|
+
packageInfo?: Pick<
|
|
6
|
+
Package,
|
|
7
|
+
"name" | "latest_package_release_fs_sha" | "latest_package_release_id"
|
|
8
|
+
>
|
|
8
9
|
onViewChange?: (view: "3d" | "pcb" | "schematic") => void
|
|
9
10
|
}
|
|
10
11
|
|
|
@@ -16,7 +17,6 @@ export default function PreviewImageSquares({
|
|
|
16
17
|
packageName: packageInfo?.name,
|
|
17
18
|
fsMapHash: packageInfo?.latest_package_release_fs_sha ?? "",
|
|
18
19
|
})
|
|
19
|
-
|
|
20
20
|
const handleViewClick = (viewId: string) => {
|
|
21
21
|
onViewChange?.(viewId as "3d" | "pcb" | "schematic")
|
|
22
22
|
}
|
|
@@ -26,24 +26,16 @@ export default function PreviewImageSquares({
|
|
|
26
26
|
{availableViews.map((view) => (
|
|
27
27
|
<button
|
|
28
28
|
key={view.id}
|
|
29
|
-
className={`aspect-square bg-
|
|
29
|
+
className={`aspect-square ${view.status == "loading" ? "bg-slate-900/10 animate-pulse" : (view.backgroundClass ?? "bg-gray-100")} rounded-lg border border-gray-200 dark:border-[#30363d] flex items-center justify-center transition-colors overflow-hidden mb-6`}
|
|
30
30
|
onClick={() => handleViewClick(view.id)}
|
|
31
31
|
>
|
|
32
32
|
{view.imageUrl && (
|
|
33
|
-
|
|
34
|
-
{view.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
alt={view.label}
|
|
40
|
-
className={`w-full h-full object-cover rounded-lg ${
|
|
41
|
-
view.status === "loaded" ? "block" : "hidden"
|
|
42
|
-
}`}
|
|
43
|
-
onLoad={view.onLoad}
|
|
44
|
-
onError={view.onError}
|
|
45
|
-
/>
|
|
46
|
-
</>
|
|
33
|
+
<img
|
|
34
|
+
src={view.imageUrl}
|
|
35
|
+
className="w-full h-full object-cover rounded-lg"
|
|
36
|
+
onLoad={view.onLoad}
|
|
37
|
+
onError={view.onError}
|
|
38
|
+
/>
|
|
47
39
|
)}
|
|
48
40
|
</button>
|
|
49
41
|
))}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
1
|
import { useState, useEffect, useMemo } from "react"
|
|
4
2
|
import MainContentHeader from "./main-content-header"
|
|
5
3
|
import Sidebar from "./sidebar"
|
|
@@ -20,21 +18,19 @@ import Header from "@/components/Header"
|
|
|
20
18
|
import Footer from "@/components/Footer"
|
|
21
19
|
import PackageHeader from "./package-header"
|
|
22
20
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
import type {
|
|
22
|
+
Package,
|
|
23
|
+
PackageFile as ApiPackageFile,
|
|
24
|
+
} from "fake-snippets-api/lib/db/schema"
|
|
26
25
|
import { useRequestAiReviewMutation } from "@/hooks/use-request-ai-review-mutation"
|
|
26
|
+
import { useUpdateAiDescriptionMutation } from "@/hooks/use-update-ai-description-mutation"
|
|
27
27
|
import { useAiReview } from "@/hooks/use-ai-review"
|
|
28
28
|
import { useQueryClient } from "react-query"
|
|
29
29
|
import SidebarReleasesSection from "./sidebar-releases-section"
|
|
30
30
|
|
|
31
|
-
interface PackageFile {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
file_path: string
|
|
35
|
-
file_content: string
|
|
36
|
-
content_text?: string // Keep for backward compatibility
|
|
37
|
-
created_at: string // iso-8601
|
|
31
|
+
interface PackageFile extends ApiPackageFile {
|
|
32
|
+
file_content?: string
|
|
33
|
+
content_text?: string | null // Keep for backward compatibility
|
|
38
34
|
}
|
|
39
35
|
|
|
40
36
|
interface RepoPageContentProps {
|
|
@@ -44,10 +40,12 @@ interface RepoPageContentProps {
|
|
|
44
40
|
packageRelease?: import("fake-snippets-api/lib/db/schema").PackageRelease
|
|
45
41
|
onFileClicked?: (file: PackageFile) => void
|
|
46
42
|
onEditClicked?: () => void
|
|
43
|
+
arePackageFilesFetched?: boolean
|
|
47
44
|
}
|
|
48
45
|
|
|
49
46
|
export default function RepoPageContent({
|
|
50
47
|
packageFiles,
|
|
48
|
+
arePackageFilesFetched = false,
|
|
51
49
|
packageInfo,
|
|
52
50
|
packageRelease,
|
|
53
51
|
onFileClicked,
|
|
@@ -70,8 +68,12 @@ export default function RepoPageContent({
|
|
|
70
68
|
}
|
|
71
69
|
}, [aiReview?.ai_review_text, queryClient])
|
|
72
70
|
const session = useGlobalStore((s) => s.session)
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
|
|
72
|
+
// Check if circuit.json exists without downloading it
|
|
73
|
+
const circuitJsonExists = useMemo(() => {
|
|
74
|
+
return packageFiles?.some((file) => file.file_path === "dist/circuit.json")
|
|
75
|
+
}, [packageFiles])
|
|
76
|
+
|
|
75
77
|
const { mutate: requestAiReview, isLoading: isRequestingAiReview } =
|
|
76
78
|
useRequestAiReviewMutation({
|
|
77
79
|
onSuccess: (_packageRelease, aiReview) => {
|
|
@@ -79,6 +81,9 @@ export default function RepoPageContent({
|
|
|
79
81
|
},
|
|
80
82
|
})
|
|
81
83
|
|
|
84
|
+
const { mutate: updateAiDescription, isLoading: isUpdatingAiDescription } =
|
|
85
|
+
useUpdateAiDescriptionMutation()
|
|
86
|
+
|
|
82
87
|
const aiReviewRequested =
|
|
83
88
|
Boolean(packageRelease?.ai_review_requested) ||
|
|
84
89
|
Boolean(pendingAiReviewId) ||
|
|
@@ -91,13 +96,12 @@ export default function RepoPageContent({
|
|
|
91
96
|
|
|
92
97
|
// Handle initial view selection and hash-based view changes
|
|
93
98
|
useEffect(() => {
|
|
94
|
-
if (
|
|
95
|
-
if (!packageInfo) return
|
|
99
|
+
if (!packageInfo || !arePackageFilesFetched) return
|
|
96
100
|
const hash = window.location.hash.slice(1)
|
|
97
101
|
const validViews = ["files", "3d", "pcb", "schematic", "bom"]
|
|
98
102
|
const circuitDependentViews = ["3d", "pcb", "schematic", "bom"]
|
|
99
103
|
|
|
100
|
-
const availableViews =
|
|
104
|
+
const availableViews = circuitJsonExists
|
|
101
105
|
? validViews
|
|
102
106
|
: validViews.filter((view) => !circuitDependentViews.includes(view))
|
|
103
107
|
|
|
@@ -115,7 +119,7 @@ export default function RepoPageContent({
|
|
|
115
119
|
window.location.hash = "files"
|
|
116
120
|
}
|
|
117
121
|
}
|
|
118
|
-
}, [packageInfo?.default_view,
|
|
122
|
+
}, [packageInfo?.default_view, circuitJsonExists])
|
|
119
123
|
|
|
120
124
|
const importantFilePaths = packageFiles
|
|
121
125
|
?.filter((pf) => isPackageFileImportant(pf.file_path))
|
|
@@ -146,7 +150,7 @@ export default function RepoPageContent({
|
|
|
146
150
|
return (
|
|
147
151
|
<FilesView
|
|
148
152
|
packageFiles={packageFiles}
|
|
149
|
-
|
|
153
|
+
arePackageFilesFetched={arePackageFilesFetched}
|
|
150
154
|
onFileClicked={onFileClicked}
|
|
151
155
|
/>
|
|
152
156
|
)
|
|
@@ -162,7 +166,7 @@ export default function RepoPageContent({
|
|
|
162
166
|
return (
|
|
163
167
|
<FilesView
|
|
164
168
|
packageFiles={packageFiles}
|
|
165
|
-
|
|
169
|
+
arePackageFilesFetched={arePackageFilesFetched}
|
|
166
170
|
onFileClicked={onFileClicked}
|
|
167
171
|
/>
|
|
168
172
|
)
|
|
@@ -211,15 +215,12 @@ export default function RepoPageContent({
|
|
|
211
215
|
|
|
212
216
|
{/* Dynamic Content based on active view */}
|
|
213
217
|
{renderContent()}
|
|
214
|
-
|
|
215
218
|
{/* Important Files View - Always shown */}
|
|
216
219
|
<ImportantFilesView
|
|
217
220
|
importantFiles={importantFiles}
|
|
218
|
-
|
|
221
|
+
isFetched={arePackageFilesFetched}
|
|
222
|
+
pkg={packageInfo}
|
|
219
223
|
onEditClicked={onEditClicked}
|
|
220
|
-
packageAuthorOwner={packageInfo?.owner_github_username}
|
|
221
|
-
aiDescription={packageInfo?.ai_description ?? ""}
|
|
222
|
-
aiUsageInstructions={packageInfo?.ai_usage_instructions ?? ""}
|
|
223
224
|
aiReviewText={packageRelease?.ai_review_text ?? null}
|
|
224
225
|
aiReviewRequested={aiReviewRequested}
|
|
225
226
|
onRequestAiReview={() => {
|
|
@@ -229,6 +230,13 @@ export default function RepoPageContent({
|
|
|
229
230
|
})
|
|
230
231
|
}
|
|
231
232
|
}}
|
|
233
|
+
onRequestAiDescriptionUpdate={() => {
|
|
234
|
+
if (packageInfo) {
|
|
235
|
+
updateAiDescription({
|
|
236
|
+
package_id: packageInfo.package_id,
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
}}
|
|
232
240
|
onLicenseFileRequested={licenseFileRequested}
|
|
233
241
|
/>
|
|
234
242
|
</div>
|
|
@@ -2,12 +2,12 @@ import { Badge } from "@/components/ui/badge"
|
|
|
2
2
|
import { GitFork, Star, Settings, LinkIcon, Github, Plus } from "lucide-react"
|
|
3
3
|
import { Skeleton } from "@/components/ui/skeleton"
|
|
4
4
|
import { useCurrentPackageInfo } from "@/hooks/use-current-package-info"
|
|
5
|
-
import {
|
|
5
|
+
import { useCurrentPackageRelease } from "@/hooks/use-current-package-release"
|
|
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
9
|
import { useState, useEffect, useMemo } from "react"
|
|
10
|
-
import {
|
|
10
|
+
import { usePackageFileById, usePackageFiles } from "@/hooks/use-package-files"
|
|
11
11
|
import { getLicenseFromLicenseContent } from "@/lib/getLicenseFromLicenseContent"
|
|
12
12
|
import { PackageInfo } from "@/lib/types"
|
|
13
13
|
|
|
@@ -21,23 +21,29 @@ export default function SidebarAboutSection({
|
|
|
21
21
|
onLicenseClick,
|
|
22
22
|
}: SidebarAboutSectionProps = {}) {
|
|
23
23
|
const { packageInfo, refetch: refetchPackageInfo } = useCurrentPackageInfo()
|
|
24
|
-
const {
|
|
24
|
+
const { packageRelease } = useCurrentPackageRelease({
|
|
25
|
+
include_ai_review: true,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const { data: releaseFiles } = usePackageFiles(
|
|
25
29
|
packageInfo?.latest_package_release_id,
|
|
26
30
|
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
const licenseFileId = useMemo(() => {
|
|
32
|
+
return (
|
|
33
|
+
releaseFiles?.find((f) => f.file_path === "LICENSE")?.package_file_id ||
|
|
34
|
+
null
|
|
35
|
+
)
|
|
36
|
+
}, [releaseFiles])
|
|
37
|
+
const { data: licenseFileMeta } = usePackageFileById(licenseFileId)
|
|
32
38
|
const currentLicense = useMemo(() => {
|
|
33
39
|
if (packageInfo?.latest_license) {
|
|
34
40
|
return packageInfo?.latest_license
|
|
35
41
|
}
|
|
36
42
|
if (licenseFileMeta?.content_text) {
|
|
37
|
-
return getLicenseFromLicenseContent(licenseFileMeta
|
|
43
|
+
return getLicenseFromLicenseContent(licenseFileMeta.content_text)
|
|
38
44
|
}
|
|
39
45
|
return null
|
|
40
|
-
}, [licenseFileMeta])
|
|
46
|
+
}, [licenseFileMeta, packageInfo?.latest_license])
|
|
41
47
|
const topics = packageInfo?.is_package ? ["Package"] : ["Board"]
|
|
42
48
|
const isLoading = !packageInfo || !packageRelease
|
|
43
49
|
const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Tag, Clock } from "lucide-react"
|
|
2
2
|
import { Skeleton } from "@/components/ui/skeleton"
|
|
3
3
|
import { useCurrentPackageInfo } from "@/hooks/use-current-package-info"
|
|
4
|
-
import {
|
|
4
|
+
import { useCurrentPackageRelease } from "@/hooks/use-current-package-release"
|
|
5
5
|
import { timeAgo } from "@/lib/utils/timeAgo"
|
|
6
6
|
import { BuildStatus, BuildStep } from "./build-status"
|
|
7
7
|
import type { PackageRelease } from "fake-snippets-api/lib/db/schema"
|
|
8
8
|
import { getBuildStatus, StatusIcon } from "@/components/preview"
|
|
9
|
-
import {
|
|
9
|
+
import { Link } from "wouter"
|
|
10
10
|
import { usePackageBuild } from "@/hooks/use-package-builds"
|
|
11
11
|
|
|
12
12
|
function getTranspilationStatus(
|
|
@@ -39,9 +39,9 @@ function getCircuitJsonStatus(pr?: PackageRelease | null): BuildStep["status"] {
|
|
|
39
39
|
|
|
40
40
|
export default function SidebarReleasesSection() {
|
|
41
41
|
const { packageInfo } = useCurrentPackageInfo()
|
|
42
|
-
const {
|
|
43
|
-
|
|
44
|
-
)
|
|
42
|
+
const { packageRelease } = useCurrentPackageRelease({
|
|
43
|
+
include_ai_review: true,
|
|
44
|
+
})
|
|
45
45
|
const { data: latestBuild } = usePackageBuild(
|
|
46
46
|
packageRelease?.latest_package_build_id ?? null,
|
|
47
47
|
)
|
|
@@ -80,21 +80,21 @@ export default function SidebarReleasesSection() {
|
|
|
80
80
|
return (
|
|
81
81
|
<div className="mb-6">
|
|
82
82
|
<h2 className="text-lg font-semibold mb-2">
|
|
83
|
-
<
|
|
83
|
+
<Link
|
|
84
84
|
href={`/${packageInfo?.owner_github_username}/${packageInfo?.unscoped_name}/releases`}
|
|
85
85
|
className="hover:underline"
|
|
86
86
|
>
|
|
87
87
|
Releases
|
|
88
|
-
</
|
|
88
|
+
</Link>
|
|
89
89
|
</h2>
|
|
90
90
|
<div className="flex flex-col space-y-2">
|
|
91
|
-
<
|
|
91
|
+
<Link
|
|
92
92
|
href={`/${packageInfo?.owner_github_username}/${packageInfo?.unscoped_name}/releases`}
|
|
93
93
|
className="flex items-center hover:underline"
|
|
94
94
|
>
|
|
95
95
|
<Tag className="h-4 w-4 mr-2 text-gray-500 dark:text-[#8b949e]" />
|
|
96
96
|
<span className="text-sm font-medium">v{packageRelease.version}</span>
|
|
97
|
-
</
|
|
97
|
+
</Link>
|
|
98
98
|
<div className="flex items-center">
|
|
99
99
|
<Clock className="h-4 w-4 mr-2 text-gray-500 dark:text-[#8b949e]" />
|
|
100
100
|
<span className="text-sm text-gray-500 dark:text-[#8b949e]">
|
|
@@ -109,13 +109,13 @@ export default function SidebarReleasesSection() {
|
|
|
109
109
|
/>
|
|
110
110
|
))}
|
|
111
111
|
{latestBuild && (
|
|
112
|
-
<
|
|
112
|
+
<Link
|
|
113
113
|
href={`/${packageInfo?.name}/releases`}
|
|
114
114
|
className="flex items-center gap-2 text-sm text-gray-500 dark:text-[#8b949e]"
|
|
115
115
|
>
|
|
116
116
|
<StatusIcon status={status} />
|
|
117
117
|
<span>Package Preview {label}</span>
|
|
118
|
-
</
|
|
118
|
+
</Link>
|
|
119
119
|
)}
|
|
120
120
|
</div>
|
|
121
121
|
{/* <a href="#" className="text-blue-600 dark:text-[#58a6ff] hover:underline text-sm">
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
1
|
import { Skeleton } from "@/components/ui/skeleton"
|
|
4
2
|
import { FileText, Folder } from "lucide-react"
|
|
5
3
|
import { useMemo, useState } from "react"
|
|
6
4
|
import { isHiddenFile } from "../../utils/is-hidden-file"
|
|
7
5
|
import { isWithinDirectory } from "../../utils/is-within-directory"
|
|
8
6
|
import HiddenFilesDropdown from "@/components/HiddenFilesDropdown"
|
|
7
|
+
import type { PackageFile as ApiPackageFile } from "fake-snippets-api/lib/db/schema"
|
|
9
8
|
|
|
10
9
|
interface Directory {
|
|
11
10
|
type: "directory"
|
|
@@ -21,24 +20,20 @@ interface File {
|
|
|
21
20
|
created_at: string
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
interface PackageFile {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
file_path: string
|
|
28
|
-
file_content: string
|
|
29
|
-
content_text?: string // Keep for backward compatibility
|
|
30
|
-
created_at: string // iso-8601
|
|
23
|
+
interface PackageFile extends ApiPackageFile {
|
|
24
|
+
file_content?: string
|
|
25
|
+
content_text?: string | null // Keep for backward compatibility
|
|
31
26
|
}
|
|
32
27
|
|
|
33
28
|
interface FilesViewProps {
|
|
34
29
|
packageFiles?: PackageFile[]
|
|
35
|
-
isLoading?: boolean
|
|
36
30
|
onFileClicked?: (file: PackageFile) => void
|
|
31
|
+
arePackageFilesFetched?: boolean
|
|
37
32
|
}
|
|
38
33
|
|
|
39
34
|
export default function FilesView({
|
|
40
35
|
packageFiles = [],
|
|
41
|
-
|
|
36
|
+
arePackageFilesFetched = false,
|
|
42
37
|
onFileClicked,
|
|
43
38
|
}: FilesViewProps) {
|
|
44
39
|
const [activeDir, setActiveDir] = useState("")
|
|
@@ -106,12 +101,19 @@ export default function FilesView({
|
|
|
106
101
|
}, [packageFiles, showHiddenFiles])
|
|
107
102
|
// Format date for display
|
|
108
103
|
const formatDate = (dateString: string) => {
|
|
109
|
-
const
|
|
104
|
+
const parsedDate = new Date(dateString)
|
|
105
|
+
if (Number.isNaN(parsedDate.getTime())) return ""
|
|
106
|
+
|
|
110
107
|
const now = new Date()
|
|
111
|
-
const
|
|
112
|
-
const
|
|
108
|
+
const diffMs = now.getTime() - parsedDate.getTime()
|
|
109
|
+
const oneDayMs = 1000 * 60 * 60 * 24
|
|
110
|
+
|
|
111
|
+
// Treat future dates as today
|
|
112
|
+
if (diffMs <= 0) return "today"
|
|
113
113
|
|
|
114
|
-
if (
|
|
114
|
+
if (diffMs < oneDayMs) return "today"
|
|
115
|
+
|
|
116
|
+
const diffDays = Math.floor(diffMs / oneDayMs)
|
|
115
117
|
if (diffDays === 1) return "yesterday"
|
|
116
118
|
if (diffDays < 7) return `${diffDays} days ago`
|
|
117
119
|
if (diffDays < 30) return `${Math.floor(diffDays / 7)} weeks ago`
|
|
@@ -160,7 +162,7 @@ export default function FilesView({
|
|
|
160
162
|
|
|
161
163
|
const toggleHiddenFiles = () => setShowHiddenFiles((prev) => !prev)
|
|
162
164
|
|
|
163
|
-
if (
|
|
165
|
+
if (!arePackageFilesFetched) {
|
|
164
166
|
return (
|
|
165
167
|
<div className="mb-4 border border-gray-200 dark:border-[#30363d] rounded-md overflow-hidden">
|
|
166
168
|
<div className="flex items-center px-4 py-2 md:py-3 bg-gray-100 dark:bg-[#161b22] border-b border-gray-200 dark:border-[#30363d]">
|
|
@@ -225,7 +227,6 @@ export default function FilesView({
|
|
|
225
227
|
</div>
|
|
226
228
|
</div>
|
|
227
229
|
</div>
|
|
228
|
-
|
|
229
230
|
{/* Files and Directories */}
|
|
230
231
|
<div className="bg-white dark:bg-[#0d1117]">
|
|
231
232
|
{items.length === 0 && !activeDir ? (
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { usePackageFile, usePackageFileByPath } from "@/hooks/use-package-files"
|
|
2
1
|
import { PcbViewerWithContainerHeight } from "@/components/PcbViewerWithContainerHeight"
|
|
3
|
-
import { useEffect, useState } from "react"
|
|
4
2
|
import { useCurrentPackageCircuitJson } from "../../hooks/use-current-package-circuit-json"
|
|
5
3
|
|
|
6
4
|
export default function PCBView() {
|
|
@@ -27,6 +25,7 @@ export default function PCBView() {
|
|
|
27
25
|
return (
|
|
28
26
|
<div className="border border-gray-200 dark:border-[#30363d] rounded-md p-4 mb-4 bg-white dark:bg-[#0d1117]">
|
|
29
27
|
<PcbViewerWithContainerHeight
|
|
28
|
+
disablePcbGroups
|
|
30
29
|
clickToInteractEnabled
|
|
31
30
|
circuitJson={circuitJson}
|
|
32
31
|
containerClassName="w-full h-[620px]"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCurrentPackageCircuitJson } from "../../hooks/use-current-package-circuit-json"
|
|
2
|
-
import { SchematicViewer } from "@tscircuit/
|
|
2
|
+
import { SchematicViewer } from "@tscircuit/schematic-viewer"
|
|
3
3
|
|
|
4
4
|
export default function SchematicView() {
|
|
5
5
|
const { circuitJson, isLoading, error } = useCurrentPackageCircuitJson()
|
|
@@ -26,6 +26,7 @@ export default function SchematicView() {
|
|
|
26
26
|
return (
|
|
27
27
|
<div className="h-[620px]">
|
|
28
28
|
<SchematicViewer
|
|
29
|
+
disableGroups
|
|
29
30
|
clickToInteractEnabled
|
|
30
31
|
circuitJson={circuitJson}
|
|
31
32
|
containerStyle={{
|