@tscircuit/fake-snippets 0.0.44 → 0.0.45
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 +43 -11
- package/dist/bundle.js +405 -335
- package/fake-snippets-api/routes/api/_fake/received_quotes.ts +66 -0
- package/fake-snippets-api/routes/api/package_releases/update.ts +25 -18
- package/package.json +2 -2
- package/src/components/CodeAndPreview.tsx +0 -1
- package/src/components/CodeEditor.tsx +0 -1
- package/src/components/CodeEditorHeader.tsx +0 -25
- package/src/components/EditorNav.tsx +10 -8
- package/src/components/ErrorOutline.tsx +35 -0
- package/src/components/FileSidebar.tsx +46 -16
- package/src/components/NotFound.tsx +37 -0
- package/src/components/PreviewContent.tsx +0 -6
- package/src/components/TrendingSnippetCarousel.tsx +1 -1
- package/src/components/ViewPackagePage/components/package-header.tsx +24 -3
- package/src/components/ViewPackagePage/utils/is-hidden-file.ts +0 -1
- package/src/components/dialogs/package-visibility-settings-dialog.tsx +10 -1
- package/src/components/dialogs/view-ts-files-dialog.tsx +0 -6
- package/src/components/package-port/CodeAndPreview.tsx +10 -8
- package/src/components/package-port/CodeEditor.tsx +26 -38
- package/src/components/package-port/CodeEditorHeader.tsx +117 -39
- package/src/components/package-port/EditorNav.tsx +10 -8
- package/src/components/ui/tree-view.tsx +5 -1
- package/src/{prettier.ts → lib/types.ts} +3 -1
- package/src/lib/utils/findTargetFile.ts +62 -0
- package/src/lib/utils/load-prettier.ts +3 -0
- package/src/pages/404.tsx +2 -33
- package/src/pages/package-editor.tsx +14 -3
- package/src/pages/user-profile.tsx +66 -27
- package/src/components/FootprintDialog.tsx +0 -339
- package/src/components/ParametersEditor.tsx +0 -140
- package/src/lib/utils/parseFootprintParams.ts +0 -52
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { withRouteSpec } from "fake-snippets-api/lib/middleware/with-winter-spec"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
import { orderQuoteSchema } from "fake-snippets-api/lib/db/schema"
|
|
4
|
+
|
|
5
|
+
export default withRouteSpec({
|
|
6
|
+
methods: ["POST"],
|
|
7
|
+
auth: "session",
|
|
8
|
+
jsonBody: z.object({
|
|
9
|
+
order_quote_id: z.string(),
|
|
10
|
+
}),
|
|
11
|
+
jsonResponse: z.object({
|
|
12
|
+
order_quote: orderQuoteSchema.optional(),
|
|
13
|
+
error: z.string().optional(),
|
|
14
|
+
}),
|
|
15
|
+
})(async (req, ctx) => {
|
|
16
|
+
const { order_quote_id } = req.jsonBody
|
|
17
|
+
|
|
18
|
+
return ctx.json({
|
|
19
|
+
order_quote: {
|
|
20
|
+
order_quote_id,
|
|
21
|
+
account_id: "123",
|
|
22
|
+
package_release_id: "123",
|
|
23
|
+
is_completed: true,
|
|
24
|
+
is_processing: false,
|
|
25
|
+
vendor_name: "JLCPCB",
|
|
26
|
+
error: null,
|
|
27
|
+
has_error: false,
|
|
28
|
+
created_at: "2025-04-21",
|
|
29
|
+
updated_at: "2025-04-21",
|
|
30
|
+
completed_at: "2025-04-21",
|
|
31
|
+
quoted_components: [
|
|
32
|
+
{
|
|
33
|
+
manufacturer_part_number: "123",
|
|
34
|
+
supplier_part_number: "123",
|
|
35
|
+
quantity: 1,
|
|
36
|
+
unit_price: 100,
|
|
37
|
+
total_price: 100,
|
|
38
|
+
available: true,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
manufacturer_part_number: "1234",
|
|
42
|
+
supplier_part_number: "1234",
|
|
43
|
+
quantity: 1,
|
|
44
|
+
unit_price: 200,
|
|
45
|
+
total_price: 200,
|
|
46
|
+
available: true,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
bare_pcb_cost: 300,
|
|
50
|
+
shipping_options: [
|
|
51
|
+
{
|
|
52
|
+
carrier: "DHL",
|
|
53
|
+
service: "Express",
|
|
54
|
+
cost: 100,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
carrier: "FedEx",
|
|
58
|
+
service: "Express",
|
|
59
|
+
cost: 200,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
// TODO: shipping cost can vary so do the total cost calculation
|
|
63
|
+
total_cost: 100,
|
|
64
|
+
},
|
|
65
|
+
})
|
|
66
|
+
})
|
|
@@ -67,28 +67,35 @@ export default withRouteSpec({
|
|
|
67
67
|
})
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
.filter(
|
|
74
|
-
(pr) =>
|
|
75
|
-
pr.package_id === release.package_id &&
|
|
76
|
-
pr.package_release_id !== releaseId &&
|
|
77
|
-
pr.is_latest,
|
|
78
|
-
)
|
|
79
|
-
.forEach((pr) => {
|
|
80
|
-
pr.is_latest = false
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Update the release
|
|
85
|
-
Object.assign(release, {
|
|
70
|
+
// Create updated release object
|
|
71
|
+
const updatedRelease = {
|
|
72
|
+
...release,
|
|
86
73
|
...(is_locked !== undefined && { is_locked }),
|
|
87
74
|
...(is_latest !== undefined && { is_latest }),
|
|
88
75
|
...(license !== undefined && { license }),
|
|
89
|
-
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Handle is_latest updates atomically
|
|
79
|
+
if (is_latest !== undefined && is_latest) {
|
|
80
|
+
// Get all releases for this package that are currently marked as latest
|
|
81
|
+
const otherLatestReleases = ctx.db.packageReleases.filter(
|
|
82
|
+
(pr) =>
|
|
83
|
+
pr.package_id === release.package_id &&
|
|
84
|
+
pr.package_release_id !== releaseId &&
|
|
85
|
+
pr.is_latest,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
// Update all releases in a single operation
|
|
89
|
+
for (const latestRelease of otherLatestReleases) {
|
|
90
|
+
ctx.db.updatePackageRelease({
|
|
91
|
+
...latestRelease,
|
|
92
|
+
is_latest: false,
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
}
|
|
90
96
|
|
|
91
|
-
|
|
97
|
+
// Update the target release
|
|
98
|
+
ctx.db.updatePackageRelease(updatedRelease)
|
|
92
99
|
|
|
93
100
|
return ctx.json({
|
|
94
101
|
ok: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/fake-snippets",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.45",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
"@playwright/test": "^1.48.0",
|
|
137
137
|
"@tscircuit/core": "^0.0.370",
|
|
138
138
|
"@tscircuit/prompt-benchmarks": "^0.0.28",
|
|
139
|
-
"@tscircuit/runframe": "^0.0.
|
|
139
|
+
"@tscircuit/runframe": "^0.0.357",
|
|
140
140
|
"@types/babel__standalone": "^7.1.7",
|
|
141
141
|
"@types/bun": "^1.1.10",
|
|
142
142
|
"@types/country-list": "^2.1.4",
|
|
@@ -10,7 +10,6 @@ import { decodeUrlHashToText } from "@/lib/decodeUrlHashToText"
|
|
|
10
10
|
import { getSnippetTemplate } from "@/lib/get-snippet-template"
|
|
11
11
|
import { cn } from "@/lib/utils"
|
|
12
12
|
import { parseJsonOrNull } from "@/lib/utils/parseJsonOrNull"
|
|
13
|
-
import "@/prettier"
|
|
14
13
|
import type { Snippet } from "fake-snippets-api/lib/db/schema"
|
|
15
14
|
import { Loader2 } from "lucide-react"
|
|
16
15
|
import { useEffect, useMemo, useState } from "react"
|
|
@@ -8,8 +8,6 @@ import {
|
|
|
8
8
|
} from "@/components/ui/select"
|
|
9
9
|
import { useImportSnippetDialog } from "./dialogs/import-snippet-dialog"
|
|
10
10
|
import { useToast } from "@/hooks/use-toast"
|
|
11
|
-
import { FootprintDialog } from "./FootprintDialog"
|
|
12
|
-
import { useState } from "react"
|
|
13
11
|
import {
|
|
14
12
|
DropdownMenu,
|
|
15
13
|
DropdownMenuContent,
|
|
@@ -27,7 +25,6 @@ interface CodeEditorHeaderProps {
|
|
|
27
25
|
files: Record<FileName, string>
|
|
28
26
|
handleFileChange: (filename: FileName) => void
|
|
29
27
|
updateFileContent: (filename: FileName, content: string) => void
|
|
30
|
-
cursorPosition: number | null
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
export const CodeEditorHeader = ({
|
|
@@ -35,11 +32,9 @@ export const CodeEditorHeader = ({
|
|
|
35
32
|
files,
|
|
36
33
|
handleFileChange,
|
|
37
34
|
updateFileContent,
|
|
38
|
-
cursorPosition,
|
|
39
35
|
}: CodeEditorHeaderProps) => {
|
|
40
36
|
const { Dialog: ImportSnippetDialog, openDialog: openImportDialog } =
|
|
41
37
|
useImportSnippetDialog()
|
|
42
|
-
const [footprintDialogOpen, setFootprintDialogOpen] = useState(false)
|
|
43
38
|
const { toast } = useToast()
|
|
44
39
|
|
|
45
40
|
const formatCurrentFile = () => {
|
|
@@ -120,18 +115,6 @@ export const CodeEditorHeader = ({
|
|
|
120
115
|
</DropdownMenuContent>
|
|
121
116
|
</DropdownMenu>
|
|
122
117
|
)}
|
|
123
|
-
<DropdownMenu>
|
|
124
|
-
<DropdownMenuTrigger asChild>
|
|
125
|
-
<Button size="sm" variant="ghost">
|
|
126
|
-
Insert
|
|
127
|
-
</Button>
|
|
128
|
-
</DropdownMenuTrigger>
|
|
129
|
-
<DropdownMenuContent>
|
|
130
|
-
<DropdownMenuItem onClick={() => setFootprintDialogOpen(true)}>
|
|
131
|
-
Chip
|
|
132
|
-
</DropdownMenuItem>
|
|
133
|
-
</DropdownMenuContent>
|
|
134
|
-
</DropdownMenu>
|
|
135
118
|
<Button size="sm" variant="ghost" onClick={() => openImportDialog()}>
|
|
136
119
|
Import
|
|
137
120
|
</Button>
|
|
@@ -145,14 +128,6 @@ export const CodeEditorHeader = ({
|
|
|
145
128
|
updateFileContent(currentFile, newContent)
|
|
146
129
|
}}
|
|
147
130
|
/>
|
|
148
|
-
<FootprintDialog
|
|
149
|
-
currentFile={currentFile}
|
|
150
|
-
open={footprintDialogOpen}
|
|
151
|
-
onOpenChange={setFootprintDialogOpen}
|
|
152
|
-
updateFileContent={updateFileContent}
|
|
153
|
-
files={files}
|
|
154
|
-
cursorPosition={cursorPosition}
|
|
155
|
-
/>
|
|
156
131
|
</div>
|
|
157
132
|
)
|
|
158
133
|
}
|
|
@@ -195,14 +195,16 @@ export default function EditorNav({
|
|
|
195
195
|
{snippet && (
|
|
196
196
|
<>
|
|
197
197
|
<SnippetLink snippet={snippet} />
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
198
|
+
{snippet?.owner_name === session?.github_username && (
|
|
199
|
+
<Button
|
|
200
|
+
variant="ghost"
|
|
201
|
+
size="icon"
|
|
202
|
+
className="h-6 w-6 ml-2"
|
|
203
|
+
onClick={() => openRenameDialog()}
|
|
204
|
+
>
|
|
205
|
+
<Pencil className="h-3 w-3 text-gray-700" />
|
|
206
|
+
</Button>
|
|
207
|
+
)}
|
|
206
208
|
{isPrivate && (
|
|
207
209
|
<div className="relative group">
|
|
208
210
|
<LockClosedIcon className="h-3 w-3 text-gray-700" />
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AlertCircle } from "lucide-react"
|
|
2
|
+
|
|
3
|
+
export function ErrorOutline({
|
|
4
|
+
error,
|
|
5
|
+
description,
|
|
6
|
+
}: { error?: Error; description?: string; children?: React.ReactNode }) {
|
|
7
|
+
return (
|
|
8
|
+
<div className="flex items-center justify-center p-4">
|
|
9
|
+
<div className="max-w-lg w-full mx-auto p-6 sm:p-8 bg-red-100/80 rounded-xl shadow-lg border border-red-500">
|
|
10
|
+
<div className="flex flex-col items-center text-center">
|
|
11
|
+
<AlertCircle className="h-10 w-10 text-red-700 mb-4" />
|
|
12
|
+
<h2 className="text-xl sm:text-2xl font-bold text-red-700 mb-3">
|
|
13
|
+
Something strange happened
|
|
14
|
+
</h2>
|
|
15
|
+
<p className="text-red-600 font-medium mb-6 text-sm sm:text-base">
|
|
16
|
+
{description ||
|
|
17
|
+
"An unexpected error occurred while processing your request."}{" "}
|
|
18
|
+
<br />
|
|
19
|
+
Please try again or contact support if the problem persists.
|
|
20
|
+
</p>
|
|
21
|
+
{error?.message && (
|
|
22
|
+
<details className="w-full text-left bg-red-50 p-3 rounded-md border border-red-200">
|
|
23
|
+
<summary className="text-sm font-medium text-red-800 cursor-pointer hover:text-red-900">
|
|
24
|
+
Show Error Details
|
|
25
|
+
</summary>
|
|
26
|
+
<pre className="mt-2 text-xs text-red-700 bg-transparent p-0 rounded overflow-auto whitespace-pre-wrap break-words">
|
|
27
|
+
{error.message}
|
|
28
|
+
</pre>
|
|
29
|
+
</details>
|
|
30
|
+
)}
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -2,6 +2,7 @@ import React, { useState } from "react"
|
|
|
2
2
|
import { cn } from "@/lib/utils"
|
|
3
3
|
import { File, Folder, PanelRightOpen } from "lucide-react"
|
|
4
4
|
import { TreeView, TreeDataItem } from "@/components/ui/tree-view"
|
|
5
|
+
import { isHiddenFile } from "./ViewPackagePage/utils/is-hidden-file"
|
|
5
6
|
|
|
6
7
|
type FileName = string
|
|
7
8
|
|
|
@@ -24,35 +25,63 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
|
|
|
24
25
|
const transformFilesToTreeData = (
|
|
25
26
|
files: Record<FileName, string>,
|
|
26
27
|
): TreeDataItem[] => {
|
|
27
|
-
|
|
28
|
+
type TreeNode = Omit<TreeDataItem, "children"> & {
|
|
29
|
+
children?: Record<string, TreeNode>
|
|
30
|
+
}
|
|
31
|
+
const root: Record<string, TreeNode> = {}
|
|
28
32
|
|
|
29
33
|
Object.keys(files).forEach((path) => {
|
|
30
|
-
const
|
|
34
|
+
const startsWithSlash = path.startsWith("/")
|
|
35
|
+
const parts = (startsWithSlash ? path.slice(1) : path).trim().split("/")
|
|
31
36
|
let current = root
|
|
32
37
|
|
|
33
|
-
let currentPath = ""
|
|
34
38
|
parts.forEach((part, index) => {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
const isFile = index === parts.length - 1
|
|
40
|
+
const parentPath = parts.slice(0, index).join("/")
|
|
41
|
+
const currentPath = parentPath ? `${parentPath}/${part}` : part
|
|
42
|
+
const evaluatedFilePath = startsWithSlash
|
|
43
|
+
? `/${currentPath}`
|
|
44
|
+
: currentPath
|
|
45
|
+
if (
|
|
46
|
+
!current[part] &&
|
|
47
|
+
(!isHiddenFile(currentPath) ||
|
|
48
|
+
isHiddenFile(
|
|
49
|
+
currentFile.startsWith("/") ? currentFile.slice(1) : currentFile,
|
|
50
|
+
))
|
|
51
|
+
) {
|
|
40
52
|
current[part] = {
|
|
41
|
-
id:
|
|
42
|
-
name: part,
|
|
53
|
+
id: currentPath,
|
|
54
|
+
name: isFile ? part : part,
|
|
43
55
|
icon: isFile ? File : Folder,
|
|
44
|
-
onClick: isFile ? () => onFileSelect(
|
|
56
|
+
onClick: isFile ? () => onFileSelect(evaluatedFilePath) : undefined,
|
|
57
|
+
draggable: isFile,
|
|
58
|
+
droppable: !isFile,
|
|
59
|
+
children: isFile ? undefined : {},
|
|
45
60
|
}
|
|
46
61
|
}
|
|
47
|
-
|
|
62
|
+
|
|
63
|
+
if (!isFile && current[part].children) {
|
|
64
|
+
current = current[part].children
|
|
65
|
+
}
|
|
48
66
|
})
|
|
49
67
|
})
|
|
50
68
|
|
|
51
|
-
|
|
69
|
+
// Convert the nested object structure to array structure
|
|
70
|
+
const convertToArray = (
|
|
71
|
+
items: Record<string, TreeNode>,
|
|
72
|
+
): TreeDataItem[] => {
|
|
73
|
+
return Object.values(items).map((item) => ({
|
|
74
|
+
...item,
|
|
75
|
+
children: item.children ? convertToArray(item.children) : undefined,
|
|
76
|
+
}))
|
|
77
|
+
}
|
|
78
|
+
return convertToArray(root).filter((x) => {
|
|
79
|
+
if (x.children?.length === 0) return false
|
|
80
|
+
return true
|
|
81
|
+
})
|
|
52
82
|
}
|
|
53
83
|
|
|
54
84
|
const treeData = transformFilesToTreeData(files)
|
|
55
|
-
|
|
56
85
|
return (
|
|
57
86
|
<div
|
|
58
87
|
className={cn(
|
|
@@ -63,11 +92,12 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
|
|
|
63
92
|
>
|
|
64
93
|
<button
|
|
65
94
|
onClick={() => setSidebarOpen(!sidebarOpen)}
|
|
66
|
-
className={`z-[99] mt-2 ml-2 text-
|
|
95
|
+
className={`z-[99] mt-2 ml-2 text-gray-400 scale-90 transition-opacity duration-200 ${
|
|
96
|
+
!sidebarOpen ? "opacity-0 pointer-events-none" : "opacity-100"
|
|
97
|
+
}`}
|
|
67
98
|
>
|
|
68
99
|
<PanelRightOpen />
|
|
69
100
|
</button>
|
|
70
|
-
|
|
71
101
|
<TreeView
|
|
72
102
|
data={treeData}
|
|
73
103
|
initialSelectedItemId={currentFile}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Button } from "@/components/ui/button"
|
|
2
|
+
import { PrefetchPageLink } from "@/components/PrefetchPageLink"
|
|
3
|
+
|
|
4
|
+
export function NotFound({ heading = "Page not found" }: { heading?: string }) {
|
|
5
|
+
return (
|
|
6
|
+
<section className="flex-1 flex items-center justify-center min-h-[90vh]">
|
|
7
|
+
<div className="container px-4 md:px-6 py-12 flex flex-col items-center text-center max-w-3xl">
|
|
8
|
+
<div className="mb-8 flex flex-col items-center justify-center">
|
|
9
|
+
<div className="mb-2">
|
|
10
|
+
<span className="text-3xl font-bold text-white bg-blue-500 px-4 py-2 rounded-md shadow-md inline-block">
|
|
11
|
+
404
|
|
12
|
+
</span>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
<h1 className="text-4xl font-extrabold tracking-tight lg:text-5xl mb-4">
|
|
16
|
+
{heading}
|
|
17
|
+
</h1>
|
|
18
|
+
<p className="text-xl text-muted-foreground mb-8">
|
|
19
|
+
The page you're looking for doesn't exist or has been moved to another
|
|
20
|
+
address.
|
|
21
|
+
</p>
|
|
22
|
+
<div className="flex flex-col sm:flex-row gap-4">
|
|
23
|
+
<PrefetchPageLink href="/">
|
|
24
|
+
<Button size="lg" className="bg-blue-500 hover:bg-blue-600">
|
|
25
|
+
Return Home
|
|
26
|
+
</Button>
|
|
27
|
+
</PrefetchPageLink>
|
|
28
|
+
<PrefetchPageLink href="/search">
|
|
29
|
+
<Button size="lg" variant="outline">
|
|
30
|
+
Search Packages
|
|
31
|
+
</Button>
|
|
32
|
+
</PrefetchPageLink>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</section>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
@@ -55,12 +55,6 @@ export interface PreviewContentProps {
|
|
|
55
55
|
onManualEditsFileContentChange?: (newmanualEditsFileContent: string) => void
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
declare global {
|
|
59
|
-
interface Window {
|
|
60
|
-
TSCIRCUIT_3D_OBJECT_REF: any
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
58
|
export const PreviewContent = ({
|
|
65
59
|
code,
|
|
66
60
|
triggerRunTsx,
|
|
@@ -32,7 +32,7 @@ export const TrendingSnippetCarousel = () => {
|
|
|
32
32
|
{trendingSnippets?.length ? (
|
|
33
33
|
<>
|
|
34
34
|
<div className="container mx-auto px-4">
|
|
35
|
-
<h2 className="text-2xl font-semibold mb-6">Trending
|
|
35
|
+
<h2 className="text-2xl font-semibold mb-6">Trending Packages</h2>
|
|
36
36
|
</div>
|
|
37
37
|
<div
|
|
38
38
|
className="flex gap-6 overflow-x-hidden relative"
|
|
@@ -8,8 +8,9 @@ import {
|
|
|
8
8
|
} from "@/hooks/use-package-stars"
|
|
9
9
|
import { LockClosedIcon } from "@radix-ui/react-icons"
|
|
10
10
|
import { GitFork, Star } from "lucide-react"
|
|
11
|
-
import { useToast } from "@/hooks/use-toast"
|
|
12
11
|
import { Link } from "wouter"
|
|
12
|
+
import { useOrderDialog } from "@tscircuit/runframe"
|
|
13
|
+
import { useEffect } from "react"
|
|
13
14
|
|
|
14
15
|
interface PackageInfo {
|
|
15
16
|
name: string
|
|
@@ -37,8 +38,7 @@ export default function PackageHeader({
|
|
|
37
38
|
const author = packageInfo?.owner_github_username
|
|
38
39
|
const packageName = packageInfo?.unscoped_name
|
|
39
40
|
|
|
40
|
-
const {
|
|
41
|
-
|
|
41
|
+
const { OrderDialog, isOpen, open, close, stage, setStage } = useOrderDialog()
|
|
42
42
|
const { data: starData, isLoading: isStarDataLoading } =
|
|
43
43
|
usePackageStarsByName(packageInfo?.name ?? null)
|
|
44
44
|
const { addStar, removeStar } = usePackageStarMutationByName(
|
|
@@ -66,6 +66,12 @@ export default function PackageHeader({
|
|
|
66
66
|
const isStarLoading =
|
|
67
67
|
isStarDataLoading || addStar.isLoading || removeStar.isLoading
|
|
68
68
|
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
window.TSCIRCUIT_REGISTRY_API_BASE_URL =
|
|
71
|
+
import.meta.env.VITE_TSCIRCUIT_REGISTRY_API_URL ??
|
|
72
|
+
`${window.location.origin}/api`
|
|
73
|
+
}, [])
|
|
74
|
+
|
|
69
75
|
return (
|
|
70
76
|
<header className="bg-white border-b border-gray-200 py-4">
|
|
71
77
|
<div className="max-w-[1200px] mx-auto px-4">
|
|
@@ -103,6 +109,15 @@ export default function PackageHeader({
|
|
|
103
109
|
)}
|
|
104
110
|
</div>
|
|
105
111
|
<div className="items-center space-x-2 hidden md:flex">
|
|
112
|
+
{/* WIP: add order button */}
|
|
113
|
+
{/* <Button
|
|
114
|
+
size="sm"
|
|
115
|
+
variant="default"
|
|
116
|
+
className="bg-blue-600 hover:bg-blue-700"
|
|
117
|
+
onClick={open}
|
|
118
|
+
>
|
|
119
|
+
Place Order
|
|
120
|
+
</Button> */}
|
|
106
121
|
<Button
|
|
107
122
|
variant="outline"
|
|
108
123
|
size="sm"
|
|
@@ -165,6 +180,12 @@ export default function PackageHeader({
|
|
|
165
180
|
</div>
|
|
166
181
|
</div>
|
|
167
182
|
</div>
|
|
183
|
+
<OrderDialog
|
|
184
|
+
isOpen={isOpen}
|
|
185
|
+
onClose={close}
|
|
186
|
+
stage={stage}
|
|
187
|
+
setStage={setStage}
|
|
188
|
+
/>
|
|
168
189
|
</header>
|
|
169
190
|
)
|
|
170
191
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { useState } from "react"
|
|
2
2
|
import { Button } from "../ui/button"
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Dialog,
|
|
5
|
+
DialogContent,
|
|
6
|
+
DialogHeader,
|
|
7
|
+
DialogTitle,
|
|
8
|
+
DialogDescription,
|
|
9
|
+
} from "../ui/dialog"
|
|
4
10
|
import { Label } from "../ui/label"
|
|
5
11
|
import { RadioGroup, RadioGroupItem } from "../ui/radio-group"
|
|
6
12
|
import { createUseDialog } from "./create-use-dialog"
|
|
@@ -23,6 +29,9 @@ export const PackageVisibilitySettingsDialog = ({
|
|
|
23
29
|
<DialogContent>
|
|
24
30
|
<DialogHeader>
|
|
25
31
|
<DialogTitle>Package Privacy Settings</DialogTitle>
|
|
32
|
+
<DialogDescription>
|
|
33
|
+
Control whether your package is publicly visible or private.
|
|
34
|
+
</DialogDescription>
|
|
26
35
|
</DialogHeader>
|
|
27
36
|
<div className="py-1">
|
|
28
37
|
<RadioGroup
|
|
@@ -13,12 +13,6 @@ interface ViewTsFilesDialogProps {
|
|
|
13
13
|
onOpenChange: (open: boolean) => void
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
declare global {
|
|
17
|
-
interface Window {
|
|
18
|
-
__DEBUG_CODE_EDITOR_FS_MAP: Map<string, string>
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
16
|
export const ViewTsFilesDialog: React.FC<ViewTsFilesDialogProps> = ({
|
|
23
17
|
open,
|
|
24
18
|
onOpenChange,
|
|
@@ -9,7 +9,6 @@ import { decodeUrlHashToText } from "@/lib/decodeUrlHashToText"
|
|
|
9
9
|
import { getSnippetTemplate } from "@/lib/get-snippet-template"
|
|
10
10
|
import { cn } from "@/lib/utils"
|
|
11
11
|
import { parseJsonOrNull } from "@/lib/utils/parseJsonOrNull"
|
|
12
|
-
import "@/prettier"
|
|
13
12
|
import type { Package } from "fake-snippets-api/lib/db/schema"
|
|
14
13
|
import { Loader2 } from "lucide-react"
|
|
15
14
|
import { useEffect, useMemo, useState } from "react"
|
|
@@ -23,12 +22,13 @@ import { useCreatePackageReleaseMutation } from "@/hooks/use-create-package-rele
|
|
|
23
22
|
import { useUpdatePackageFilesMutation } from "@/hooks/useUpdatePackageFilesMutation"
|
|
24
23
|
import { useUpdatePackageMutation } from "@/hooks/useUpdatePackageMutation"
|
|
25
24
|
import { usePackageFilesLoader } from "@/hooks/usePackageFilesLoader"
|
|
25
|
+
import { findTargetFile } from "@/lib/utils/findTargetFile"
|
|
26
26
|
|
|
27
27
|
interface Props {
|
|
28
28
|
pkg?: Package
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
interface PackageFile {
|
|
31
|
+
export interface PackageFile {
|
|
32
32
|
path: string
|
|
33
33
|
content: string
|
|
34
34
|
}
|
|
@@ -94,6 +94,8 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
94
94
|
const [isPrivate, setIsPrivate] = useState(false)
|
|
95
95
|
|
|
96
96
|
const entryPointCode = useMemo(() => {
|
|
97
|
+
const entryPointFile = findTargetFile(pkgFilesWithContent, null)
|
|
98
|
+
if (entryPointFile && entryPointFile.content) return entryPointFile.content
|
|
97
99
|
return (
|
|
98
100
|
pkgFilesWithContent.find((x) => x.path === "index.tsx")?.content ??
|
|
99
101
|
defaultCode
|
|
@@ -147,6 +149,10 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
147
149
|
const { data: loadedFiles, isLoading: isLoadingFiles } =
|
|
148
150
|
usePackageFilesLoader(pkg)
|
|
149
151
|
|
|
152
|
+
const [pkgFilesLoaded, setPkgFilesLoaded] = useState<boolean>(
|
|
153
|
+
urlParams.package_id ? false : true,
|
|
154
|
+
)
|
|
155
|
+
|
|
150
156
|
useEffect(() => {
|
|
151
157
|
if (!pkgFiles.data?.length) {
|
|
152
158
|
if (pkg && pkgFilesWithContent.length === 0) {
|
|
@@ -171,6 +177,7 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
171
177
|
}
|
|
172
178
|
|
|
173
179
|
setPkgFilesWithContent(processedResults)
|
|
180
|
+
setPkgFilesLoaded(true)
|
|
174
181
|
setInitialFilesLoad(processedResults)
|
|
175
182
|
setLastRunCode(
|
|
176
183
|
processedResults.find((x) => x.path === "index.tsx")?.content ??
|
|
@@ -185,12 +192,6 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
185
192
|
defaultCode,
|
|
186
193
|
])
|
|
187
194
|
|
|
188
|
-
// useEffect(() => {
|
|
189
|
-
// if (pkg && pkgFiles.data) {
|
|
190
|
-
// loadPkgFiles()
|
|
191
|
-
// }
|
|
192
|
-
// }, [pkg, pkgFiles.data])
|
|
193
|
-
|
|
194
195
|
const createPackageMutation = useCreatePackageMutation()
|
|
195
196
|
|
|
196
197
|
const { mutate: createRelease, isLoading: isCreatingRelease } =
|
|
@@ -355,6 +356,7 @@ export function CodeAndPreview({ pkg }: Props) {
|
|
|
355
356
|
)
|
|
356
357
|
}}
|
|
357
358
|
onDtsChange={setDts}
|
|
359
|
+
pkgFilesLoaded={pkgFilesLoaded}
|
|
358
360
|
/>
|
|
359
361
|
</div>
|
|
360
362
|
{showPreview && (
|