@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
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import React, { useState } from "react"
|
|
2
|
+
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
|
3
|
+
import { Button } from "@/components/ui/button"
|
|
4
|
+
import { Building2, Users, Package, Lock, Globe2, Settings } from "lucide-react"
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
import { PublicOrgSchema } from "fake-snippets-api/lib/db/schema"
|
|
7
|
+
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
8
|
+
import { useLocation } from "wouter"
|
|
9
|
+
import { useOrganization } from "@/hooks/use-organization"
|
|
10
|
+
|
|
11
|
+
interface OrganizationHeaderProps {
|
|
12
|
+
organization: PublicOrgSchema
|
|
13
|
+
isCurrentUserOrganization?: boolean
|
|
14
|
+
className?: string
|
|
15
|
+
showActions?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const OrganizationHeader: React.FC<OrganizationHeaderProps> = ({
|
|
19
|
+
organization,
|
|
20
|
+
className,
|
|
21
|
+
showActions = true,
|
|
22
|
+
}) => {
|
|
23
|
+
const session = useGlobalStore((s) => s.session)
|
|
24
|
+
const [, navigate] = useLocation()
|
|
25
|
+
const canManageOrg =
|
|
26
|
+
organization.user_permissions?.can_manage_org ||
|
|
27
|
+
organization.owner_account_id === session?.account_id
|
|
28
|
+
|
|
29
|
+
const { membersCount, packagesCount, isLoading } = useOrganization({
|
|
30
|
+
orgId: organization.org_id,
|
|
31
|
+
orgName: organization.name!,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const handleSettingsClick = () => {
|
|
35
|
+
navigate(`/${organization.name}/settings`)
|
|
36
|
+
}
|
|
37
|
+
return (
|
|
38
|
+
<div className={cn("bg-white border-b border-gray-200", className)}>
|
|
39
|
+
<div className="container mx-auto px-6 py-6">
|
|
40
|
+
{/* Mobile Layout */}
|
|
41
|
+
<div className="block sm:hidden">
|
|
42
|
+
<div className="flex flex-col items-center text-center space-y-4">
|
|
43
|
+
<Avatar className="border-4 border-gray-100 shadow-sm size-16 md:size-20 lg:size-24">
|
|
44
|
+
<AvatarImage
|
|
45
|
+
src={`https://github.com/${organization.name}.png`}
|
|
46
|
+
alt={`${organization.name} avatar`}
|
|
47
|
+
className="object-cover"
|
|
48
|
+
/>
|
|
49
|
+
<AvatarFallback className="bg-blue-100 text-blue-600 font-bold text-xl md:text-2xl lg:text-3xl">
|
|
50
|
+
{(organization.name || "")
|
|
51
|
+
.split(" ")
|
|
52
|
+
.map((word) => word[0])
|
|
53
|
+
.join("")
|
|
54
|
+
.toUpperCase()
|
|
55
|
+
.slice(0, 2)}
|
|
56
|
+
</AvatarFallback>
|
|
57
|
+
</Avatar>
|
|
58
|
+
|
|
59
|
+
<div>
|
|
60
|
+
<div className="flex flex-col items-center gap-3 mb-3">
|
|
61
|
+
<h1 className="font-bold text-gray-900 text-xl">
|
|
62
|
+
{organization.name}
|
|
63
|
+
</h1>
|
|
64
|
+
{canManageOrg && showActions && (
|
|
65
|
+
<Button
|
|
66
|
+
variant="outline"
|
|
67
|
+
size="sm"
|
|
68
|
+
onClick={handleSettingsClick}
|
|
69
|
+
>
|
|
70
|
+
<Settings className="mr-2 h-4 w-4" />
|
|
71
|
+
Settings
|
|
72
|
+
</Button>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div className="grid grid-cols-2 md:flex flex-wrap justify-center gap-4 text-sm">
|
|
77
|
+
<div className="flex items-center gap-1.5 text-gray-600">
|
|
78
|
+
<Users className="h-3.5 w-3.5" />
|
|
79
|
+
<span className="font-medium">
|
|
80
|
+
{isLoading ? "..." : membersCount}
|
|
81
|
+
</span>
|
|
82
|
+
<span>members</span>
|
|
83
|
+
</div>
|
|
84
|
+
<div className="flex items-center gap-1.5 text-gray-600">
|
|
85
|
+
<Package className="h-3.5 w-3.5" />
|
|
86
|
+
<span className="font-medium">
|
|
87
|
+
{isLoading ? "..." : packagesCount}
|
|
88
|
+
</span>
|
|
89
|
+
<span>packages</span>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
{/* Desktop Layout */}
|
|
97
|
+
<div className="hidden sm:block">
|
|
98
|
+
<div className="flex items-center gap-6">
|
|
99
|
+
<Avatar className="border-4 border-gray-100 shadow-sm size-16 md:size-20 lg:size-24 flex-shrink-0">
|
|
100
|
+
<AvatarImage
|
|
101
|
+
src={`https://github.com/${organization.name}.png`}
|
|
102
|
+
alt={`${organization.name} avatar`}
|
|
103
|
+
className="object-cover"
|
|
104
|
+
/>
|
|
105
|
+
<AvatarFallback className="bg-blue-100 text-blue-600 font-bold text-xl md:text-2xl lg:text-3xl">
|
|
106
|
+
{(organization.name || "")
|
|
107
|
+
.split(" ")
|
|
108
|
+
.map((word) => word[0])
|
|
109
|
+
.join("")
|
|
110
|
+
.toUpperCase()
|
|
111
|
+
.slice(0, 2)}
|
|
112
|
+
</AvatarFallback>
|
|
113
|
+
</Avatar>
|
|
114
|
+
|
|
115
|
+
<div className="flex-1 min-w-0">
|
|
116
|
+
<div className="flex items-center justify-between mb-3">
|
|
117
|
+
<h1 className="font-bold text-gray-900 text-2xl md:text-3xl truncate">
|
|
118
|
+
{organization.name}
|
|
119
|
+
</h1>
|
|
120
|
+
{canManageOrg && showActions && (
|
|
121
|
+
<Button variant="outline" onClick={handleSettingsClick}>
|
|
122
|
+
<Settings className="mr-2 h-4 w-4" />
|
|
123
|
+
Settings
|
|
124
|
+
</Button>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<div className="flex flex-wrap items-center gap-6 text-sm text-gray-600">
|
|
129
|
+
<div className="flex items-center gap-2">
|
|
130
|
+
<Users className="h-4 w-4" />
|
|
131
|
+
<span className="font-medium text-gray-900">
|
|
132
|
+
{isLoading ? "..." : membersCount}
|
|
133
|
+
</span>
|
|
134
|
+
<span>members</span>
|
|
135
|
+
</div>
|
|
136
|
+
<div className="flex items-center gap-2">
|
|
137
|
+
<Package className="h-4 w-4" />
|
|
138
|
+
<span className="font-medium text-gray-900">
|
|
139
|
+
{isLoading ? "..." : packagesCount}
|
|
140
|
+
</span>
|
|
141
|
+
<span>packages</span>
|
|
142
|
+
</div>
|
|
143
|
+
<div className="flex items-center gap-2">
|
|
144
|
+
<Building2 className="h-4 w-4" />
|
|
145
|
+
<span>Organization</span>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
)
|
|
154
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { Link } from "wouter"
|
|
3
|
+
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
|
4
|
+
import { Badge } from "@/components/ui/badge"
|
|
5
|
+
import { Button } from "@/components/ui/button"
|
|
6
|
+
import { Users, Crown, Shield, User, Loader2 } from "lucide-react"
|
|
7
|
+
import { timeAgo } from "@/lib/utils/timeAgo"
|
|
8
|
+
import { cn } from "@/lib/utils"
|
|
9
|
+
import { Account } from "fake-snippets-api/lib/db/schema"
|
|
10
|
+
import { useListOrgMembers } from "@/hooks/use-list-org-members"
|
|
11
|
+
|
|
12
|
+
interface OrganizationMembersProps {
|
|
13
|
+
orgId: string
|
|
14
|
+
className?: string
|
|
15
|
+
}
|
|
16
|
+
type MemberRole = "owner" | "admin" | "member" //todo
|
|
17
|
+
const getRoleIcon = (role: MemberRole) => {
|
|
18
|
+
switch (role) {
|
|
19
|
+
case "owner":
|
|
20
|
+
return <Crown className="h-3 w-3" />
|
|
21
|
+
case "admin":
|
|
22
|
+
return <Shield className="h-3 w-3" />
|
|
23
|
+
case "member":
|
|
24
|
+
return <User className="h-3 w-3" />
|
|
25
|
+
default:
|
|
26
|
+
return <User className="h-3 w-3" />
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const getRoleColor = (role: MemberRole) => {
|
|
31
|
+
switch (role) {
|
|
32
|
+
case "owner":
|
|
33
|
+
return "bg-yellow-100 text-yellow-800 border-yellow-200"
|
|
34
|
+
case "admin":
|
|
35
|
+
return "bg-purple-100 text-purple-800 border-purple-200"
|
|
36
|
+
case "member":
|
|
37
|
+
return "bg-gray-100 text-gray-800 border-gray-200"
|
|
38
|
+
default:
|
|
39
|
+
return "bg-gray-100 text-gray-800 border-gray-200"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const OrganizationMembers: React.FC<OrganizationMembersProps> = ({
|
|
44
|
+
orgId,
|
|
45
|
+
className,
|
|
46
|
+
}) => {
|
|
47
|
+
const { data: members = [], isLoading } = useListOrgMembers({ orgId })
|
|
48
|
+
|
|
49
|
+
if (isLoading) {
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
className={cn(
|
|
53
|
+
"bg-white rounded-lg border border-gray-200 p-4 sm:p-6",
|
|
54
|
+
className,
|
|
55
|
+
)}
|
|
56
|
+
>
|
|
57
|
+
<div className="mb-4">
|
|
58
|
+
<h2 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
|
|
59
|
+
Members
|
|
60
|
+
</h2>
|
|
61
|
+
</div>
|
|
62
|
+
<div className="text-center py-20 text-gray-500 grid place-items-center">
|
|
63
|
+
<Loader2 className="w-8 h-8 text-blue-600 dark:text-blue-400 animate-spin" />
|
|
64
|
+
<p className="mt-2 text-sm select-none">Loading members...</p>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
return (
|
|
70
|
+
<div
|
|
71
|
+
className={cn(
|
|
72
|
+
"bg-white rounded-lg border border-gray-200 p-4 py-20 sm:p-6",
|
|
73
|
+
className,
|
|
74
|
+
)}
|
|
75
|
+
>
|
|
76
|
+
<div className="mb-4">
|
|
77
|
+
<h2 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
|
|
78
|
+
Members ({members.length})
|
|
79
|
+
</h2>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div className="space-y-2 sm:space-y-3">
|
|
83
|
+
{members.map((member) => (
|
|
84
|
+
<Link
|
|
85
|
+
key={member.account_id || member.github_username}
|
|
86
|
+
href={`/${member.github_username}`}
|
|
87
|
+
className="block"
|
|
88
|
+
>
|
|
89
|
+
<div className="flex items-center justify-between p-3 rounded-lg hover:bg-gray-50 transition-colors cursor-pointer">
|
|
90
|
+
<div className="flex items-center gap-3 min-w-0 flex-1">
|
|
91
|
+
<Avatar className="h-10 w-10 sm:h-12 sm:w-12 flex-shrink-0">
|
|
92
|
+
<AvatarImage
|
|
93
|
+
src={`https://github.com/${member.github_username}.png`}
|
|
94
|
+
alt={`${member.github_username} avatar`}
|
|
95
|
+
/>
|
|
96
|
+
<AvatarFallback className="text-sm font-medium">
|
|
97
|
+
{member.github_username
|
|
98
|
+
.split(" ")
|
|
99
|
+
.map((word) => word[0])
|
|
100
|
+
.join("")
|
|
101
|
+
.toUpperCase()
|
|
102
|
+
.slice(0, 2)}
|
|
103
|
+
</AvatarFallback>
|
|
104
|
+
</Avatar>
|
|
105
|
+
|
|
106
|
+
<div className="min-w-0 flex-1">
|
|
107
|
+
<div className="flex items-center gap-2 mb-1">
|
|
108
|
+
<h3 className="font-medium text-gray-900 truncate">
|
|
109
|
+
{member.github_username}
|
|
110
|
+
</h3>
|
|
111
|
+
<Badge
|
|
112
|
+
variant="outline"
|
|
113
|
+
className={cn(
|
|
114
|
+
"text-xs flex items-center gap-1 flex-shrink-0",
|
|
115
|
+
getRoleColor("admin"),
|
|
116
|
+
)}
|
|
117
|
+
>
|
|
118
|
+
{getRoleIcon("admin")}
|
|
119
|
+
{"admin"}
|
|
120
|
+
</Badge>
|
|
121
|
+
</div>
|
|
122
|
+
<p className="text-sm text-gray-500 truncate">
|
|
123
|
+
@{member.github_username}
|
|
124
|
+
</p>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<div className="text-right flex-shrink-0 hidden sm:block">
|
|
129
|
+
<p className="text-xs text-gray-500">
|
|
130
|
+
Joined {timeAgo(new Date())}
|
|
131
|
+
</p>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</Link>
|
|
135
|
+
))}
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
{members.length === 0 && (
|
|
139
|
+
<div className="text-center py-6 sm:py-8 text-gray-500">
|
|
140
|
+
<Users className="h-10 w-10 sm:h-12 sm:w-12 mx-auto mb-3 text-gray-300" />
|
|
141
|
+
<p className="text-sm sm:text-base">No members found</p>
|
|
142
|
+
</div>
|
|
143
|
+
)}
|
|
144
|
+
</div>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { CodeEditor } from "@/components/package-port/CodeEditor"
|
|
2
|
-
import { usePackageVisibilitySettingsDialog } from "@/components/dialogs/package-visibility-settings-dialog"
|
|
3
2
|
import { useConfirmDiscardChangesDialog } from "@/components/dialogs/confirm-discard-changes-dialog"
|
|
4
3
|
import { useToast } from "@/hooks/use-toast"
|
|
5
4
|
import { useUrlParams } from "@/hooks/use-url-params"
|
|
@@ -7,7 +6,6 @@ import useWarnUserOnPageChange from "@/hooks/use-warn-user-on-page-change"
|
|
|
7
6
|
import { getSnippetTemplate } from "@/lib/get-snippet-template"
|
|
8
7
|
import { cn } from "@/lib/utils"
|
|
9
8
|
import type { Package } from "fake-snippets-api/lib/db/schema"
|
|
10
|
-
import { Loader2 } from "lucide-react"
|
|
11
9
|
import { useMemo, useState } from "react"
|
|
12
10
|
import EditorNav from "@/components/package-port/EditorNav"
|
|
13
11
|
import { SuspenseRunFrame } from "../SuspenseRunFrame"
|
|
@@ -15,8 +13,8 @@ import { applyEditEventsToManualEditsFile } from "@tscircuit/core"
|
|
|
15
13
|
import { toastManualEditConflicts } from "@/lib/utils/toastManualEditConflicts"
|
|
16
14
|
import { ManualEditEvent } from "@tscircuit/props"
|
|
17
15
|
import { useFileManagement } from "@/hooks/useFileManagement"
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
16
|
+
import { isHiddenFile } from "../ViewPackagePage/utils/is-hidden-file"
|
|
17
|
+
import { useNewPackageSavePromptDialog } from "../dialogs/new-package-save-prompt-dialog"
|
|
20
18
|
|
|
21
19
|
interface Props {
|
|
22
20
|
pkg?: Package
|
|
@@ -39,13 +37,13 @@ export interface CodeAndPreviewState {
|
|
|
39
37
|
|
|
40
38
|
export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
41
39
|
const { toast } = useToast()
|
|
42
|
-
const session = useGlobalStore((s) => s.session)
|
|
43
40
|
const urlParams = useUrlParams()
|
|
44
41
|
|
|
45
42
|
const templateFromUrl = useMemo(
|
|
46
43
|
() => (urlParams.template ? getSnippetTemplate(urlParams.template) : null),
|
|
47
44
|
[urlParams.template],
|
|
48
45
|
)
|
|
46
|
+
|
|
49
47
|
const [state, setState] = useState<CodeAndPreviewState>({
|
|
50
48
|
showPreview: true,
|
|
51
49
|
fullScreen: false,
|
|
@@ -59,7 +57,7 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
59
57
|
pkg?.snippet_type ?? templateFromUrl?.type ?? urlParams.snippet_type
|
|
60
58
|
|
|
61
59
|
const { Dialog: NewPackageSaveDialog, openDialog: openNewPackageSaveDialog } =
|
|
62
|
-
|
|
60
|
+
useNewPackageSavePromptDialog()
|
|
63
61
|
|
|
64
62
|
const { Dialog: DiscardChangesDialog, openDialog: openDiscardChangesDialog } =
|
|
65
63
|
useConfirmDiscardChangesDialog()
|
|
@@ -69,20 +67,26 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
69
67
|
isSaving,
|
|
70
68
|
currentFile,
|
|
71
69
|
fsMap,
|
|
70
|
+
priorityFileFetched,
|
|
72
71
|
isLoading,
|
|
73
72
|
createFile,
|
|
73
|
+
mainComponentPath,
|
|
74
74
|
deleteFile,
|
|
75
|
+
isFullyLoaded,
|
|
75
76
|
onFileSelect,
|
|
77
|
+
totalFilesCount,
|
|
76
78
|
saveFiles,
|
|
77
79
|
setLocalFiles,
|
|
80
|
+
loadedFilesCount,
|
|
78
81
|
localFiles,
|
|
82
|
+
currentFileCode,
|
|
79
83
|
initialFiles,
|
|
80
84
|
renameFile,
|
|
81
85
|
packageFilesMeta,
|
|
82
86
|
} = useFileManagement({
|
|
83
87
|
templateCode: templateFromUrl?.code,
|
|
84
88
|
currentPackage: pkg,
|
|
85
|
-
|
|
89
|
+
urlParams,
|
|
86
90
|
openNewPackageSaveDialog,
|
|
87
91
|
updateLastUpdated: () => {
|
|
88
92
|
setState((prev) => ({ ...prev, lastSavedAt: Date.now() }))
|
|
@@ -94,6 +98,7 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
94
98
|
(!isSaving &&
|
|
95
99
|
Date.now() - state.lastSavedAt > 1000 &&
|
|
96
100
|
localFiles.some((file) => {
|
|
101
|
+
if (isHiddenFile(file.path)) return false
|
|
97
102
|
const initialFile = initialFiles.find((x) => x.path === file.path)
|
|
98
103
|
return initialFile?.content !== file.content
|
|
99
104
|
})) ||
|
|
@@ -101,31 +106,6 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
101
106
|
[localFiles, initialFiles, isSaving, state.lastSavedAt],
|
|
102
107
|
)
|
|
103
108
|
|
|
104
|
-
useWarnUserOnPageChange({ hasUnsavedChanges })
|
|
105
|
-
|
|
106
|
-
const currentFileCode = useMemo(
|
|
107
|
-
() =>
|
|
108
|
-
localFiles.find((x) => x.path === currentFile)?.content ??
|
|
109
|
-
state.defaultComponentFile ??
|
|
110
|
-
DEFAULT_CODE,
|
|
111
|
-
[localFiles, currentFile],
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
const mainComponentPath = useMemo(() => {
|
|
115
|
-
const isReactComponentExported =
|
|
116
|
-
/export function\s+\w+/.test(currentFileCode) ||
|
|
117
|
-
/export const\s+\w+\s*=/.test(currentFileCode) ||
|
|
118
|
-
/export default\s+\w+/.test(currentFileCode) ||
|
|
119
|
-
/export default\s+function\s*(\w*)\s*\(/.test(currentFileCode) ||
|
|
120
|
-
/export default\s*\(\s*\)\s*=>/.test(currentFileCode)
|
|
121
|
-
|
|
122
|
-
return (currentFile?.endsWith(".tsx") || currentFile?.endsWith(".ts")) &&
|
|
123
|
-
!!localFiles.some((x) => x.path == currentFile) &&
|
|
124
|
-
isReactComponentExported
|
|
125
|
-
? currentFile
|
|
126
|
-
: state.defaultComponentFile
|
|
127
|
-
}, [currentFile, localFiles, currentFileCode])
|
|
128
|
-
|
|
129
109
|
const handleEditEvent = (event: ManualEditEvent) => {
|
|
130
110
|
const parsedManualEdits = JSON.parse(
|
|
131
111
|
localFiles.find((x) => x.path === "manual-edits.json")?.content || "{}",
|
|
@@ -171,19 +151,13 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
171
151
|
})
|
|
172
152
|
}
|
|
173
153
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<div className="text-lg text-gray-500 mb-4">Loading</div>
|
|
179
|
-
<Loader2 className="w-16 h-16 animate-spin text-gray-400" />
|
|
180
|
-
</div>
|
|
181
|
-
</div>
|
|
182
|
-
)
|
|
183
|
-
}
|
|
154
|
+
useWarnUserOnPageChange({
|
|
155
|
+
hasUnsavedChanges: Boolean(hasUnsavedChanges),
|
|
156
|
+
isPackageThere: Boolean(pkg),
|
|
157
|
+
})
|
|
184
158
|
|
|
185
159
|
return (
|
|
186
|
-
<div className="flex flex-col
|
|
160
|
+
<div className="flex flex-col h-full">
|
|
187
161
|
<EditorNav
|
|
188
162
|
circuitJson={state.circuitJson}
|
|
189
163
|
pkg={pkg}
|
|
@@ -202,7 +176,9 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
202
176
|
packageFilesMeta={packageFilesMeta}
|
|
203
177
|
/>
|
|
204
178
|
<div
|
|
205
|
-
className={`flex
|
|
179
|
+
className={`flex flex-1 min-h-0 ${
|
|
180
|
+
state.showPreview ? "flex-col md:flex-row" : ""
|
|
181
|
+
}`}
|
|
206
182
|
>
|
|
207
183
|
<div
|
|
208
184
|
className={cn(
|
|
@@ -213,8 +189,14 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
213
189
|
<CodeEditor
|
|
214
190
|
isSaving={isSaving}
|
|
215
191
|
handleCreateFile={createFile}
|
|
192
|
+
totalFilesCount={totalFilesCount}
|
|
193
|
+
loadedFilesCount={loadedFilesCount}
|
|
194
|
+
isFullyLoaded={isFullyLoaded}
|
|
216
195
|
handleDeleteFile={deleteFile}
|
|
217
196
|
handleRenameFile={renameFile}
|
|
197
|
+
isPriorityFileFetched={
|
|
198
|
+
!priorityFileFetched && Boolean(urlParams.package_id)
|
|
199
|
+
}
|
|
218
200
|
pkg={pkg}
|
|
219
201
|
currentFile={currentFile}
|
|
220
202
|
onFileSelect={onFileSelect}
|
|
@@ -234,7 +216,7 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
234
216
|
</div>
|
|
235
217
|
<div
|
|
236
218
|
className={cn(
|
|
237
|
-
"flex p-0 flex-col
|
|
219
|
+
"flex p-0 flex-col overflow-y-hidden",
|
|
238
220
|
state.fullScreen
|
|
239
221
|
? "fixed inset-0 z-50 bg-white p-4 overflow-hidden"
|
|
240
222
|
: "w-full md:w-1/2",
|
|
@@ -242,8 +224,10 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
242
224
|
)}
|
|
243
225
|
>
|
|
244
226
|
<SuspenseRunFrame
|
|
227
|
+
showFileMenu={false}
|
|
245
228
|
showRunButton
|
|
246
229
|
forceLatestEvalVersion
|
|
230
|
+
isLoadingFiles={isLoading}
|
|
247
231
|
onRenderStarted={() =>
|
|
248
232
|
setState((prev) => ({ ...prev, lastRunCode: currentFileCode }))
|
|
249
233
|
}
|
|
@@ -255,7 +239,7 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
255
239
|
onEditEvent={(event) => {
|
|
256
240
|
handleEditEvent(event)
|
|
257
241
|
}}
|
|
258
|
-
fsMap={fsMap
|
|
242
|
+
fsMap={fsMap}
|
|
259
243
|
projectUrl={projectUrl}
|
|
260
244
|
/>
|
|
261
245
|
</div>
|
|
@@ -265,3 +249,5 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
265
249
|
</div>
|
|
266
250
|
)
|
|
267
251
|
}
|
|
252
|
+
|
|
253
|
+
export default CodeAndPreview
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
createSystem,
|
|
24
24
|
createVirtualTypeScriptEnvironment,
|
|
25
25
|
} from "@typescript/vfs"
|
|
26
|
-
import { loadDefaultLibMap } from "@/lib/ts-lib-cache"
|
|
26
|
+
import { loadDefaultLibMap, fetchWithPackageCaching } from "@/lib/ts-lib-cache"
|
|
27
27
|
import { tsAutocomplete, tsFacet, tsSync } from "@valtown/codemirror-ts"
|
|
28
28
|
import { getLints } from "@valtown/codemirror-ts"
|
|
29
29
|
import { EditorView } from "codemirror"
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
import { isHiddenFile } from "../ViewPackagePage/utils/is-hidden-file"
|
|
51
51
|
import { inlineCopilot } from "codemirror-copilot"
|
|
52
52
|
import { useViewTsFilesDialog } from "@/components/dialogs/view-ts-files-dialog"
|
|
53
|
+
import { Loader2 } from "lucide-react"
|
|
53
54
|
|
|
54
55
|
const defaultImports = `
|
|
55
56
|
import React from "@types/react/jsx-runtime"
|
|
@@ -59,6 +60,7 @@ import type { CommonLayoutProps } from "@tscircuit/props"
|
|
|
59
60
|
|
|
60
61
|
export const CodeEditor = ({
|
|
61
62
|
onCodeChange,
|
|
63
|
+
isPriorityFileFetched,
|
|
62
64
|
readOnly = false,
|
|
63
65
|
files = [],
|
|
64
66
|
isSaving = false,
|
|
@@ -72,9 +74,13 @@ export const CodeEditor = ({
|
|
|
72
74
|
handleCreateFile,
|
|
73
75
|
handleDeleteFile,
|
|
74
76
|
pkg,
|
|
77
|
+
isFullyLoaded = false,
|
|
78
|
+
totalFilesCount = 0,
|
|
79
|
+
loadedFilesCount = 0,
|
|
75
80
|
}: {
|
|
76
81
|
onCodeChange: (code: string, filename?: string) => void
|
|
77
82
|
files: PackageFile[]
|
|
83
|
+
isPriorityFileFetched: boolean
|
|
78
84
|
isSaving?: boolean
|
|
79
85
|
handleCreateFile: (props: ICreateFileProps) => ICreateFileResult
|
|
80
86
|
handleDeleteFile: (props: IDeleteFileProps) => IDeleteFileResult
|
|
@@ -87,6 +93,9 @@ export const CodeEditor = ({
|
|
|
87
93
|
onFileContentChanged?: (path: string, content: string) => void
|
|
88
94
|
currentFile: string | null
|
|
89
95
|
onFileSelect: (path: string, lineNumber?: number) => void
|
|
96
|
+
isFullyLoaded?: boolean
|
|
97
|
+
totalFilesCount?: number
|
|
98
|
+
loadedFilesCount?: number
|
|
90
99
|
}) => {
|
|
91
100
|
const editorRef = useRef<HTMLDivElement>(null)
|
|
92
101
|
const viewRef = useRef<EditorView | null>(null)
|
|
@@ -112,7 +121,7 @@ export const CodeEditor = ({
|
|
|
112
121
|
useViewTsFilesDialog()
|
|
113
122
|
|
|
114
123
|
const entryPointFileName = useMemo(() => {
|
|
115
|
-
const entryPointFile = findTargetFile(files, null)
|
|
124
|
+
const entryPointFile = findTargetFile({ files, filePathFromUrl: null })
|
|
116
125
|
if (entryPointFile?.path) return entryPointFile.path
|
|
117
126
|
return files.find((x) => x.path === "index.tsx")?.path || "index.tsx"
|
|
118
127
|
}, [files])
|
|
@@ -120,11 +129,14 @@ export const CodeEditor = ({
|
|
|
120
129
|
const [sidebarOpen, setSidebarOpen] = useState(false)
|
|
121
130
|
const [isCreatingFile, setIsCreatingFile] = useState(false)
|
|
122
131
|
|
|
123
|
-
// Set current file on component mount
|
|
132
|
+
// Set current file on component mount - only when explicitly requested via URL
|
|
124
133
|
useEffect(() => {
|
|
125
134
|
if (files.length === 0 || !pkgFilesLoaded || currentFile) return
|
|
126
135
|
|
|
127
|
-
|
|
136
|
+
// Only run this if there's an explicit file_path in URL - don't auto-select files
|
|
137
|
+
if (!filePathFromUrl) return
|
|
138
|
+
|
|
139
|
+
const targetFile = findTargetFile({ files, filePathFromUrl })
|
|
128
140
|
if (targetFile) {
|
|
129
141
|
const lineNumber = lineNumberFromUrl
|
|
130
142
|
? parseInt(lineNumberFromUrl, 10)
|
|
@@ -207,33 +219,7 @@ export const CodeEditor = ({
|
|
|
207
219
|
projectName: "my-project",
|
|
208
220
|
typescript: tsModule,
|
|
209
221
|
logger: console,
|
|
210
|
-
fetcher:
|
|
211
|
-
const registryPrefixes = [
|
|
212
|
-
"https://data.jsdelivr.com/v1/package/resolve/npm/@tsci/",
|
|
213
|
-
"https://data.jsdelivr.com/v1/package/npm/@tsci/",
|
|
214
|
-
"https://cdn.jsdelivr.net/npm/@tsci/",
|
|
215
|
-
]
|
|
216
|
-
if (
|
|
217
|
-
typeof input === "string" &&
|
|
218
|
-
registryPrefixes.some((prefix) => input.startsWith(prefix))
|
|
219
|
-
) {
|
|
220
|
-
const fullPackageName = input
|
|
221
|
-
.replace(registryPrefixes[0], "")
|
|
222
|
-
.replace(registryPrefixes[1], "")
|
|
223
|
-
.replace(registryPrefixes[2], "")
|
|
224
|
-
const packageName = fullPackageName.split("/")[0].replace(/\./, "/")
|
|
225
|
-
const pathInPackage = fullPackageName.split("/").slice(1).join("/")
|
|
226
|
-
const jsdelivrPath = `${packageName}${
|
|
227
|
-
pathInPackage ? `/${pathInPackage}` : ""
|
|
228
|
-
}`
|
|
229
|
-
return fetch(
|
|
230
|
-
`${apiUrl}/snippets/download?jsdelivr_resolve=${input.includes(
|
|
231
|
-
"/resolve/",
|
|
232
|
-
)}&jsdelivr_path=${encodeURIComponent(jsdelivrPath)}`,
|
|
233
|
-
)
|
|
234
|
-
}
|
|
235
|
-
return fetch(input, init)
|
|
236
|
-
}) as typeof fetch,
|
|
222
|
+
fetcher: fetchWithPackageCaching as typeof fetch,
|
|
237
223
|
delegate: {
|
|
238
224
|
started: () => {
|
|
239
225
|
const manualEditsTypeDeclaration = `
|
|
@@ -825,10 +811,15 @@ export const CodeEditor = ({
|
|
|
825
811
|
isCreatingFile={isCreatingFile}
|
|
826
812
|
setIsCreatingFile={setIsCreatingFile}
|
|
827
813
|
pkg={pkg}
|
|
814
|
+
isLoadingFiles={!isFullyLoaded}
|
|
815
|
+
loadingProgress={
|
|
816
|
+
totalFilesCount > 0 ? `${loadedFilesCount}/${totalFilesCount}` : null
|
|
817
|
+
}
|
|
828
818
|
/>
|
|
829
819
|
<div className="flex flex-col flex-1 w-full min-w-0 h-full">
|
|
830
820
|
{showImportAndFormatButtons && (
|
|
831
821
|
<CodeEditorHeader
|
|
822
|
+
isLoadingFiles={!isFullyLoaded}
|
|
832
823
|
entrypointFileName={entryPointFileName}
|
|
833
824
|
appendNewFile={(path: string, content: string) => {
|
|
834
825
|
onFileContentChanged?.(path, content)
|
|
@@ -854,7 +845,13 @@ export const CodeEditor = ({
|
|
|
854
845
|
className={
|
|
855
846
|
"flex-1 overflow-auto [&_.cm-editor]:h-full [&_.cm-scroller]:!h-full"
|
|
856
847
|
}
|
|
848
|
+
style={{ display: isPriorityFileFetched ? "none" : "block" }}
|
|
857
849
|
/>
|
|
850
|
+
{isPriorityFileFetched && (
|
|
851
|
+
<div className="grid place-items-center h-full">
|
|
852
|
+
<Loader2 className="w-16 h-16 animate-spin text-gray-400" />
|
|
853
|
+
</div>
|
|
854
|
+
)}
|
|
858
855
|
</div>
|
|
859
856
|
{showQuickOpen && (
|
|
860
857
|
<QuickOpen
|