@tscircuit/fake-snippets 0.0.108 → 0.0.109
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun.lock +62 -19
- package/dist/bundle.js +3 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.js +2 -1
- package/dist/schema.d.ts +8 -0
- package/dist/schema.js +2 -1
- package/fake-snippets-api/lib/db/schema.ts +1 -0
- package/package.json +7 -8
- package/src/App.tsx +0 -2
- package/src/components/DownloadButtonAndMenu.tsx +133 -35
- package/src/components/FileSidebar.tsx +31 -34
- package/src/components/Footer.tsx +0 -1
- package/src/components/HeaderLogin.tsx +1 -1
- package/src/components/HiddenFilesDropdown.tsx +0 -2
- package/src/components/PackageBuildsPage/PackageBuildDetailsPage.tsx +0 -2
- package/src/components/PackageBuildsPage/build-preview-content.tsx +34 -5
- package/src/components/PackageCard.tsx +0 -1
- package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +20 -11
- package/src/components/ViewPackagePage/components/important-files-view.tsx +75 -59
- package/src/components/ViewPackagePage/components/main-content-header.tsx +4 -4
- package/src/components/ViewPackagePage/components/main-content-view-selector.tsx +0 -1
- package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +0 -1
- package/src/components/ViewPackagePage/components/package-header.tsx +14 -17
- package/src/components/ViewPackagePage/components/preview-image-squares.tsx +0 -1
- package/src/components/ViewPackagePage/components/repo-page-content.tsx +21 -20
- package/src/components/ViewPackagePage/components/sidebar.tsx +0 -2
- package/src/components/ViewPackagePage/components/tab-views/files-view.tsx +18 -17
- package/src/components/ViewPackagePage/components/theme-toggle.tsx +0 -2
- package/src/components/ViewPackagePage/hooks/use-toast.tsx +0 -1
- package/src/components/package-port/CodeAndPreview.tsx +23 -40
- package/src/components/package-port/CodeEditor.tsx +24 -1
- package/src/components/package-port/CodeEditorHeader.tsx +5 -2
- package/src/components/preview/PackageReleasesDashboard.tsx +30 -25
- package/src/hooks/use-current-package-id.ts +5 -30
- package/src/hooks/use-current-package-info.ts +29 -5
- package/src/hooks/use-global-store.ts +1 -1
- package/src/hooks/useFileManagement.ts +153 -34
- package/src/hooks/useOptimizedPackageFilesLoader.ts +149 -0
- package/src/hooks/useUpdatePackageFilesMutation.ts +2 -0
- package/src/lib/download-fns/download-circuit-png.ts +11 -3
- package/src/lib/download-fns/download-gltf-from-circuit-json.ts +44 -0
- package/src/lib/utils/isComponentExported.ts +9 -0
- package/src/pages/authorize.tsx +0 -2
- package/src/pages/landing.tsx +0 -1
- package/src/pages/preview-release.tsx +14 -4
- package/src/pages/view-package.tsx +14 -13
- package/src/components/Footer2.tsx +0 -100
- package/src/components/ShippingInformationForm.tsx +0 -423
- package/src/components/StaticViewSnippetHeader.tsx +0 -70
- package/src/components/ViewPackagePage/components/file-explorer.tsx +0 -67
- package/src/components/ViewPackagePage/components/readme-view.tsx +0 -58
- package/src/components/ViewPackagePage/components/repo-header-button.tsx +0 -36
- package/src/components/ViewPackagePage/components/repo-header.tsx +0 -4
- package/src/components/ViewPackagePage/components/sidebar-contributors-section.tsx +0 -31
- package/src/components/ViewSnippetHeader.tsx +0 -181
- package/src/components/ui/input-otp.tsx +0 -69
- package/src/pages/settings.tsx +0 -25
|
@@ -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 ? (
|
|
@@ -7,7 +7,6 @@ import useWarnUserOnPageChange from "@/hooks/use-warn-user-on-page-change"
|
|
|
7
7
|
import { getSnippetTemplate } from "@/lib/get-snippet-template"
|
|
8
8
|
import { cn } from "@/lib/utils"
|
|
9
9
|
import type { Package } from "fake-snippets-api/lib/db/schema"
|
|
10
|
-
import { Loader2 } from "lucide-react"
|
|
11
10
|
import { useMemo, useState } from "react"
|
|
12
11
|
import EditorNav from "@/components/package-port/EditorNav"
|
|
13
12
|
import { SuspenseRunFrame } from "../SuspenseRunFrame"
|
|
@@ -15,8 +14,7 @@ import { applyEditEventsToManualEditsFile } from "@tscircuit/core"
|
|
|
15
14
|
import { toastManualEditConflicts } from "@/lib/utils/toastManualEditConflicts"
|
|
16
15
|
import { ManualEditEvent } from "@tscircuit/props"
|
|
17
16
|
import { useFileManagement } from "@/hooks/useFileManagement"
|
|
18
|
-
import {
|
|
19
|
-
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
17
|
+
import { isHiddenFile } from "../ViewPackagePage/utils/is-hidden-file"
|
|
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,
|
|
@@ -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
|
})) ||
|
|
@@ -103,29 +108,6 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
103
108
|
|
|
104
109
|
useWarnUserOnPageChange({ hasUnsavedChanges })
|
|
105
110
|
|
|
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
111
|
const handleEditEvent = (event: ManualEditEvent) => {
|
|
130
112
|
const parsedManualEdits = JSON.parse(
|
|
131
113
|
localFiles.find((x) => x.path === "manual-edits.json")?.content || "{}",
|
|
@@ -171,17 +153,10 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
171
153
|
})
|
|
172
154
|
}
|
|
173
155
|
|
|
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
|
-
}
|
|
184
|
-
|
|
156
|
+
const finalfsMap = useMemo(
|
|
157
|
+
() => (Object.keys(fsMap).length > 0 ? fsMap : {}),
|
|
158
|
+
[fsMap],
|
|
159
|
+
)
|
|
185
160
|
return (
|
|
186
161
|
<div className="flex flex-col min-h-[50vh]">
|
|
187
162
|
<EditorNav
|
|
@@ -213,8 +188,14 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
213
188
|
<CodeEditor
|
|
214
189
|
isSaving={isSaving}
|
|
215
190
|
handleCreateFile={createFile}
|
|
191
|
+
totalFilesCount={totalFilesCount}
|
|
192
|
+
loadedFilesCount={loadedFilesCount}
|
|
193
|
+
isFullyLoaded={isFullyLoaded}
|
|
216
194
|
handleDeleteFile={deleteFile}
|
|
217
195
|
handleRenameFile={renameFile}
|
|
196
|
+
isPriorityFileFetched={
|
|
197
|
+
!priorityFileFetched && Boolean(urlParams.package_id)
|
|
198
|
+
}
|
|
218
199
|
pkg={pkg}
|
|
219
200
|
currentFile={currentFile}
|
|
220
201
|
onFileSelect={onFileSelect}
|
|
@@ -255,7 +236,7 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
255
236
|
onEditEvent={(event) => {
|
|
256
237
|
handleEditEvent(event)
|
|
257
238
|
}}
|
|
258
|
-
fsMap={
|
|
239
|
+
fsMap={finalfsMap}
|
|
259
240
|
projectUrl={projectUrl}
|
|
260
241
|
/>
|
|
261
242
|
</div>
|
|
@@ -265,3 +246,5 @@ export function CodeAndPreview({ pkg, projectUrl }: Props) {
|
|
|
265
246
|
</div>
|
|
266
247
|
)
|
|
267
248
|
}
|
|
249
|
+
|
|
250
|
+
export default CodeAndPreview
|
|
@@ -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)
|
|
@@ -120,10 +129,13 @@ 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
|
|
|
136
|
+
// Only run this if there's an explicit file_path in URL - don't auto-select files
|
|
137
|
+
if (!filePathFromUrl) return
|
|
138
|
+
|
|
127
139
|
const targetFile = findTargetFile(files, filePathFromUrl)
|
|
128
140
|
if (targetFile) {
|
|
129
141
|
const lineNumber = lineNumberFromUrl
|
|
@@ -825,10 +837,15 @@ export const CodeEditor = ({
|
|
|
825
837
|
isCreatingFile={isCreatingFile}
|
|
826
838
|
setIsCreatingFile={setIsCreatingFile}
|
|
827
839
|
pkg={pkg}
|
|
840
|
+
isLoadingFiles={!isFullyLoaded}
|
|
841
|
+
loadingProgress={
|
|
842
|
+
totalFilesCount > 0 ? `${loadedFilesCount}/${totalFilesCount}` : null
|
|
843
|
+
}
|
|
828
844
|
/>
|
|
829
845
|
<div className="flex flex-col flex-1 w-full min-w-0 h-full">
|
|
830
846
|
{showImportAndFormatButtons && (
|
|
831
847
|
<CodeEditorHeader
|
|
848
|
+
isLoadingFiles={!isFullyLoaded}
|
|
832
849
|
entrypointFileName={entryPointFileName}
|
|
833
850
|
appendNewFile={(path: string, content: string) => {
|
|
834
851
|
onFileContentChanged?.(path, content)
|
|
@@ -854,7 +871,13 @@ export const CodeEditor = ({
|
|
|
854
871
|
className={
|
|
855
872
|
"flex-1 overflow-auto [&_.cm-editor]:h-full [&_.cm-scroller]:!h-full"
|
|
856
873
|
}
|
|
874
|
+
style={{ display: isPriorityFileFetched ? "none" : "block" }}
|
|
857
875
|
/>
|
|
876
|
+
{isPriorityFileFetched && (
|
|
877
|
+
<div className="grid place-items-center h-full">
|
|
878
|
+
<Loader2 className="w-16 h-16 animate-spin text-gray-400" />
|
|
879
|
+
</div>
|
|
880
|
+
)}
|
|
858
881
|
</div>
|
|
859
882
|
{showQuickOpen && (
|
|
860
883
|
<QuickOpen
|
|
@@ -41,6 +41,7 @@ interface CodeEditorHeaderProps {
|
|
|
41
41
|
handleFileChange: (filename: FileName) => void
|
|
42
42
|
entrypointFileName?: string
|
|
43
43
|
appendNewFile: (path: string, content: string) => void
|
|
44
|
+
isLoadingFiles: boolean
|
|
44
45
|
createFile: (props: ICreateFileProps) => ICreateFileResult
|
|
45
46
|
aiAutocompleteState: [boolean, React.Dispatch<React.SetStateAction<boolean>>]
|
|
46
47
|
}
|
|
@@ -49,8 +50,8 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
49
50
|
currentFile,
|
|
50
51
|
files,
|
|
51
52
|
updateFileContent,
|
|
52
|
-
appendNewFile,
|
|
53
53
|
fileSidebarState,
|
|
54
|
+
isLoadingFiles = true,
|
|
54
55
|
handleFileChange,
|
|
55
56
|
entrypointFileName = "index.tsx",
|
|
56
57
|
createFile,
|
|
@@ -230,7 +231,9 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
230
231
|
(filename) => !isHiddenFile(filename),
|
|
231
232
|
).length > 0
|
|
232
233
|
? "Select file"
|
|
233
|
-
:
|
|
234
|
+
: isLoadingFiles
|
|
235
|
+
? "Loading files..."
|
|
236
|
+
: "No files"
|
|
234
237
|
}
|
|
235
238
|
/>
|
|
236
239
|
</SelectTrigger>
|
|
@@ -91,8 +91,9 @@ export const PackageReleasesDashboard = ({
|
|
|
91
91
|
</div>
|
|
92
92
|
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4 mt-2 text-sm text-gray-600">
|
|
93
93
|
<div
|
|
94
|
-
className=
|
|
94
|
+
className={`flex items-center gap-1 ${pkg.github_repo_full_name ? "cursor-pointer" : ""}`}
|
|
95
95
|
onClick={() =>
|
|
96
|
+
pkg.github_repo_full_name &&
|
|
96
97
|
window?.open(
|
|
97
98
|
`https://github.com/${pkg.github_repo_full_name}/tree/${latestRelease?.branch_name || "main"}`,
|
|
98
99
|
"_blank",
|
|
@@ -121,21 +122,23 @@ export const PackageReleasesDashboard = ({
|
|
|
121
122
|
</div>
|
|
122
123
|
|
|
123
124
|
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-2">
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
125
|
+
{pkg.github_repo_full_name && (
|
|
126
|
+
<Button
|
|
127
|
+
variant="outline"
|
|
128
|
+
size="sm"
|
|
129
|
+
className="flex items-center gap-2 justify-center min-w-[120px] h-9"
|
|
130
|
+
onClick={() =>
|
|
131
|
+
window.open(
|
|
132
|
+
`https://github.com/${pkg.github_repo_full_name}`,
|
|
133
|
+
"_blank",
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
>
|
|
137
|
+
<GitHubLogoIcon className="w-4 h-4" />
|
|
138
|
+
<span className="hidden sm:inline">Repository</span>
|
|
139
|
+
<span className="sm:hidden">Repository</span>
|
|
140
|
+
</Button>
|
|
141
|
+
)}
|
|
139
142
|
{latestBuild && (
|
|
140
143
|
<Button
|
|
141
144
|
variant="outline"
|
|
@@ -164,15 +167,17 @@ export const PackageReleasesDashboard = ({
|
|
|
164
167
|
</Button>
|
|
165
168
|
</DropdownMenuTrigger>
|
|
166
169
|
<DropdownMenuContent align="end">
|
|
167
|
-
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
{pkg.github_repo_full_name && (
|
|
171
|
+
<DropdownMenuItem asChild>
|
|
172
|
+
<a
|
|
173
|
+
href={`https://github.com/${pkg.github_repo_full_name}`}
|
|
174
|
+
target="_blank"
|
|
175
|
+
rel="noopener noreferrer"
|
|
176
|
+
>
|
|
177
|
+
View Source
|
|
178
|
+
</a>
|
|
179
|
+
</DropdownMenuItem>
|
|
180
|
+
)}
|
|
176
181
|
<DropdownMenuItem asChild>
|
|
177
182
|
<a href="#" download>
|
|
178
183
|
Download Build
|
|
@@ -1,41 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useParams } from "wouter"
|
|
3
|
-
import { usePackageById } from "./use-package-by-package-id"
|
|
4
|
-
import { usePackageByName } from "./use-package-by-package-name"
|
|
5
|
-
import { useUrlParams } from "./use-url-params"
|
|
1
|
+
import { useCurrentPackageInfo } from "./use-current-package-info"
|
|
6
2
|
|
|
7
3
|
export const useCurrentPackageId = (): {
|
|
8
4
|
packageId: string | null
|
|
9
5
|
isLoading: boolean
|
|
10
6
|
error: (Error & { status: number }) | null
|
|
11
7
|
} => {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const wouter = useParams()
|
|
15
|
-
const [packageIdFromUrl, setPackageId] = useState<string | null>(urlPackageId)
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
if (urlPackageId) {
|
|
19
|
-
setPackageId(urlPackageId)
|
|
20
|
-
}
|
|
21
|
-
}, [urlPackageId])
|
|
22
|
-
|
|
23
|
-
const packageName =
|
|
24
|
-
wouter.author && wouter.packageName
|
|
25
|
-
? `${wouter.author}/${wouter.packageName}`
|
|
26
|
-
: null
|
|
27
|
-
|
|
28
|
-
const {
|
|
29
|
-
data: packageByName,
|
|
30
|
-
isLoading: isLoadingPackageByName,
|
|
31
|
-
error: errorPackageByName,
|
|
32
|
-
} = usePackageByName(packageName)
|
|
33
|
-
|
|
34
|
-
const packageId = packageIdFromUrl ?? packageByName?.package_id ?? null
|
|
8
|
+
const { packageInfo, isLoading, error } = useCurrentPackageInfo()
|
|
9
|
+
const packageId = packageInfo?.package_id ?? null
|
|
35
10
|
|
|
36
11
|
return {
|
|
37
12
|
packageId,
|
|
38
|
-
isLoading
|
|
39
|
-
error
|
|
13
|
+
isLoading,
|
|
14
|
+
error,
|
|
40
15
|
}
|
|
41
16
|
}
|
|
@@ -1,8 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useParams } from "wouter"
|
|
2
2
|
import { usePackageById } from "./use-package-by-package-id"
|
|
3
|
+
import { usePackageByName } from "./use-package-by-package-name"
|
|
4
|
+
import { useUrlParams } from "./use-url-params"
|
|
5
|
+
import type { Package } from "fake-snippets-api/lib/db/schema"
|
|
3
6
|
|
|
4
|
-
export const useCurrentPackageInfo = ()
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
export const useCurrentPackageInfo = (): {
|
|
8
|
+
packageInfo: Package | undefined
|
|
9
|
+
isLoading: boolean
|
|
10
|
+
error: (Error & { status: number }) | null
|
|
11
|
+
refetch: () => Promise<unknown>
|
|
12
|
+
} => {
|
|
13
|
+
const urlParams = useUrlParams()
|
|
14
|
+
const packageIdFromQuery = urlParams.package_id ?? null
|
|
15
|
+
|
|
16
|
+
const { author, packageName } = useParams()
|
|
17
|
+
const packageSlug = author && packageName ? `${author}/${packageName}` : null
|
|
18
|
+
|
|
19
|
+
const queryById = usePackageById(packageIdFromQuery)
|
|
20
|
+
const queryByName = usePackageByName(packageSlug)
|
|
21
|
+
|
|
22
|
+
const data = queryById.data ?? queryByName.data
|
|
23
|
+
const isLoading = queryById.isLoading || queryByName.isLoading
|
|
24
|
+
const error =
|
|
25
|
+
(queryById.error as (Error & { status: number }) | null) ??
|
|
26
|
+
(queryByName.error as (Error & { status: number }) | null) ??
|
|
27
|
+
null
|
|
28
|
+
|
|
29
|
+
const refetch = packageIdFromQuery ? queryById.refetch : queryByName.refetch
|
|
30
|
+
|
|
31
|
+
return { packageInfo: data, isLoading, error, refetch }
|
|
8
32
|
}
|
|
@@ -28,7 +28,7 @@ export const useGlobalStore = create<Store>()(
|
|
|
28
28
|
),
|
|
29
29
|
)
|
|
30
30
|
|
|
31
|
-
useGlobalStore.subscribe((state
|
|
31
|
+
useGlobalStore.subscribe((state) => {
|
|
32
32
|
;(window as any).globalStore = state
|
|
33
33
|
window.TSCIRCUIT_REGISTRY_TOKEN = state.session?.token ?? null
|
|
34
34
|
})
|