@tscircuit/fake-snippets 0.0.68 → 0.0.70
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-tests/fake-snippets-api/routes/packages/update.test.ts +104 -0
- package/bun.lock +15 -25
- package/dist/bundle.js +25 -5
- 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 +4 -0
- package/fake-snippets-api/routes/api/packages/create.ts +1 -0
- package/fake-snippets-api/routes/api/packages/get.ts +12 -0
- package/fake-snippets-api/routes/api/packages/update.ts +11 -2
- package/package.json +3 -3
- package/src/components/CircuitJsonImportDialog.tsx +113 -52
- package/src/components/DownloadButtonAndMenu.tsx +1 -1
- package/src/components/HeaderLogin.tsx +1 -1
- package/src/components/ViewPackagePage/components/important-files-view.tsx +1 -1
- package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +1 -0
- package/src/components/ViewPackagePage/components/package-header.tsx +21 -11
- package/src/components/ViewPackagePage/components/repo-page-content.tsx +24 -7
- package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +1 -0
- package/src/components/dialogs/edit-package-details-dialog.tsx +33 -2
- package/src/components/package-port/CodeAndPreview.tsx +1 -1
- package/src/components/package-port/CodeEditorHeader.tsx +12 -4
- package/src/components/package-port/EditorNav.tsx +33 -8
- package/src/hooks/use-create-package-mutation.ts +0 -2
- package/src/hooks/use-package-details-form.ts +15 -1
- package/src/index.css +13 -0
- package/src/pages/package-editor.tsx +2 -1
- package/src/pages/quickstart.tsx +1 -1
- package/src/pages/view-package.tsx +13 -11
package/dist/index.d.ts
CHANGED
|
@@ -508,6 +508,7 @@ declare const packageSchema: z.ZodObject<{
|
|
|
508
508
|
ai_description: z.ZodNullable<z.ZodString>;
|
|
509
509
|
latest_license: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
510
510
|
ai_usage_instructions: z.ZodNullable<z.ZodString>;
|
|
511
|
+
default_view: z.ZodOptional<z.ZodDefault<z.ZodEnum<["files", "3d", "pcb", "schematic"]>>>;
|
|
511
512
|
}, "strip", z.ZodTypeAny, {
|
|
512
513
|
name: string;
|
|
513
514
|
unscoped_name: string;
|
|
@@ -536,6 +537,7 @@ declare const packageSchema: z.ZodObject<{
|
|
|
536
537
|
ai_usage_instructions: string | null;
|
|
537
538
|
snippet_type?: "board" | "package" | "model" | "footprint" | undefined;
|
|
538
539
|
latest_license?: string | null | undefined;
|
|
540
|
+
default_view?: "files" | "3d" | "pcb" | "schematic" | undefined;
|
|
539
541
|
}, {
|
|
540
542
|
name: string;
|
|
541
543
|
unscoped_name: string;
|
|
@@ -564,6 +566,7 @@ declare const packageSchema: z.ZodObject<{
|
|
|
564
566
|
is_source_from_github?: boolean | undefined;
|
|
565
567
|
website?: string | null | undefined;
|
|
566
568
|
latest_license?: string | null | undefined;
|
|
569
|
+
default_view?: "files" | "3d" | "pcb" | "schematic" | undefined;
|
|
567
570
|
}>;
|
|
568
571
|
type Package = z.infer<typeof packageSchema>;
|
|
569
572
|
declare const jlcpcbOrderStateSchema: z.ZodObject<{
|
|
@@ -778,6 +781,7 @@ declare const createDatabase: ({ seed }?: {
|
|
|
778
781
|
ai_usage_instructions: string | null;
|
|
779
782
|
snippet_type?: "board" | "package" | "model" | "footprint" | undefined;
|
|
780
783
|
latest_license?: string | null | undefined;
|
|
784
|
+
default_view?: "files" | "3d" | "pcb" | "schematic" | undefined;
|
|
781
785
|
}[];
|
|
782
786
|
orders: {
|
|
783
787
|
error: z.objectOutputType<{
|
|
@@ -1068,6 +1072,7 @@ declare const createDatabase: ({ seed }?: {
|
|
|
1068
1072
|
ai_usage_instructions: string | null;
|
|
1069
1073
|
snippet_type?: "board" | "package" | "model" | "footprint" | undefined;
|
|
1070
1074
|
latest_license?: string | null | undefined;
|
|
1075
|
+
default_view?: "files" | "3d" | "pcb" | "schematic" | undefined;
|
|
1071
1076
|
}[];
|
|
1072
1077
|
orders: {
|
|
1073
1078
|
error: z.objectOutputType<{
|
package/dist/index.js
CHANGED
|
@@ -187,7 +187,8 @@ var packageSchema = z.object({
|
|
|
187
187
|
star_count: z.number().default(0),
|
|
188
188
|
ai_description: z.string().nullable(),
|
|
189
189
|
latest_license: z.string().nullable().optional(),
|
|
190
|
-
ai_usage_instructions: z.string().nullable()
|
|
190
|
+
ai_usage_instructions: z.string().nullable(),
|
|
191
|
+
default_view: z.enum(["files", "3d", "pcb", "schematic"]).default("files").optional()
|
|
191
192
|
});
|
|
192
193
|
var jlcpcbOrderStateSchema = z.object({
|
|
193
194
|
jlcpcb_order_state_id: z.string(),
|
package/dist/schema.d.ts
CHANGED
|
@@ -633,6 +633,7 @@ declare const packageSchema: z.ZodObject<{
|
|
|
633
633
|
ai_description: z.ZodNullable<z.ZodString>;
|
|
634
634
|
latest_license: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
635
635
|
ai_usage_instructions: z.ZodNullable<z.ZodString>;
|
|
636
|
+
default_view: z.ZodOptional<z.ZodDefault<z.ZodEnum<["files", "3d", "pcb", "schematic"]>>>;
|
|
636
637
|
}, "strip", z.ZodTypeAny, {
|
|
637
638
|
name: string;
|
|
638
639
|
unscoped_name: string;
|
|
@@ -661,6 +662,7 @@ declare const packageSchema: z.ZodObject<{
|
|
|
661
662
|
ai_usage_instructions: string | null;
|
|
662
663
|
snippet_type?: "board" | "package" | "model" | "footprint" | undefined;
|
|
663
664
|
latest_license?: string | null | undefined;
|
|
665
|
+
default_view?: "files" | "3d" | "pcb" | "schematic" | undefined;
|
|
664
666
|
}, {
|
|
665
667
|
name: string;
|
|
666
668
|
unscoped_name: string;
|
|
@@ -689,6 +691,7 @@ declare const packageSchema: z.ZodObject<{
|
|
|
689
691
|
is_source_from_github?: boolean | undefined;
|
|
690
692
|
website?: string | null | undefined;
|
|
691
693
|
latest_license?: string | null | undefined;
|
|
694
|
+
default_view?: "files" | "3d" | "pcb" | "schematic" | undefined;
|
|
692
695
|
}>;
|
|
693
696
|
type Package = z.infer<typeof packageSchema>;
|
|
694
697
|
declare const jlcpcbOrderStateSchema: z.ZodObject<{
|
|
@@ -1068,6 +1071,7 @@ declare const databaseSchema: z.ZodObject<{
|
|
|
1068
1071
|
ai_description: z.ZodNullable<z.ZodString>;
|
|
1069
1072
|
latest_license: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1070
1073
|
ai_usage_instructions: z.ZodNullable<z.ZodString>;
|
|
1074
|
+
default_view: z.ZodOptional<z.ZodDefault<z.ZodEnum<["files", "3d", "pcb", "schematic"]>>>;
|
|
1071
1075
|
}, "strip", z.ZodTypeAny, {
|
|
1072
1076
|
name: string;
|
|
1073
1077
|
unscoped_name: string;
|
|
@@ -1096,6 +1100,7 @@ declare const databaseSchema: z.ZodObject<{
|
|
|
1096
1100
|
ai_usage_instructions: string | null;
|
|
1097
1101
|
snippet_type?: "board" | "package" | "model" | "footprint" | undefined;
|
|
1098
1102
|
latest_license?: string | null | undefined;
|
|
1103
|
+
default_view?: "files" | "3d" | "pcb" | "schematic" | undefined;
|
|
1099
1104
|
}, {
|
|
1100
1105
|
name: string;
|
|
1101
1106
|
unscoped_name: string;
|
|
@@ -1124,6 +1129,7 @@ declare const databaseSchema: z.ZodObject<{
|
|
|
1124
1129
|
is_source_from_github?: boolean | undefined;
|
|
1125
1130
|
website?: string | null | undefined;
|
|
1126
1131
|
latest_license?: string | null | undefined;
|
|
1132
|
+
default_view?: "files" | "3d" | "pcb" | "schematic" | undefined;
|
|
1127
1133
|
}>, "many">>;
|
|
1128
1134
|
orders: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
1129
1135
|
order_id: z.ZodString;
|
|
@@ -1572,6 +1578,7 @@ declare const databaseSchema: z.ZodObject<{
|
|
|
1572
1578
|
ai_usage_instructions: string | null;
|
|
1573
1579
|
snippet_type?: "board" | "package" | "model" | "footprint" | undefined;
|
|
1574
1580
|
latest_license?: string | null | undefined;
|
|
1581
|
+
default_view?: "files" | "3d" | "pcb" | "schematic" | undefined;
|
|
1575
1582
|
}[];
|
|
1576
1583
|
orders: {
|
|
1577
1584
|
error: z.objectOutputType<{
|
|
@@ -1788,6 +1795,7 @@ declare const databaseSchema: z.ZodObject<{
|
|
|
1788
1795
|
is_source_from_github?: boolean | undefined;
|
|
1789
1796
|
website?: string | null | undefined;
|
|
1790
1797
|
latest_license?: string | null | undefined;
|
|
1798
|
+
default_view?: "files" | "3d" | "pcb" | "schematic" | undefined;
|
|
1791
1799
|
}[] | undefined;
|
|
1792
1800
|
orders?: {
|
|
1793
1801
|
error: z.objectInputType<{
|
package/dist/schema.js
CHANGED
|
@@ -182,7 +182,8 @@ var packageSchema = z.object({
|
|
|
182
182
|
star_count: z.number().default(0),
|
|
183
183
|
ai_description: z.string().nullable(),
|
|
184
184
|
latest_license: z.string().nullable().optional(),
|
|
185
|
-
ai_usage_instructions: z.string().nullable()
|
|
185
|
+
ai_usage_instructions: z.string().nullable(),
|
|
186
|
+
default_view: z.enum(["files", "3d", "pcb", "schematic"]).default("files").optional()
|
|
186
187
|
});
|
|
187
188
|
var jlcpcbOrderStateSchema = z.object({
|
|
188
189
|
jlcpcb_order_state_id: z.string(),
|
|
@@ -219,6 +219,10 @@ export const packageSchema = z.object({
|
|
|
219
219
|
ai_description: z.string().nullable(),
|
|
220
220
|
latest_license: z.string().nullable().optional(),
|
|
221
221
|
ai_usage_instructions: z.string().nullable(),
|
|
222
|
+
default_view: z
|
|
223
|
+
.enum(["files", "3d", "pcb", "schematic"])
|
|
224
|
+
.default("files")
|
|
225
|
+
.optional(),
|
|
222
226
|
})
|
|
223
227
|
export type Package = z.infer<typeof packageSchema>
|
|
224
228
|
|
|
@@ -55,6 +55,7 @@ export default withRouteSpec({
|
|
|
55
55
|
is_public: is_private === true ? false : true,
|
|
56
56
|
is_unlisted: is_private === true ? true : (is_unlisted ?? false),
|
|
57
57
|
ai_usage_instructions: "placeholder ai usage instructions",
|
|
58
|
+
default_view: "files",
|
|
58
59
|
})
|
|
59
60
|
|
|
60
61
|
if (!newPackage) {
|
|
@@ -34,6 +34,18 @@ export default withRouteSpec({
|
|
|
34
34
|
})
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
if (
|
|
38
|
+
foundPackage.is_private &&
|
|
39
|
+
auth?.github_username !== foundPackage.owner_github_username
|
|
40
|
+
) {
|
|
41
|
+
return ctx.error(404, {
|
|
42
|
+
error_code: "package_not_found",
|
|
43
|
+
message: `Package not found (searched using ${JSON.stringify(
|
|
44
|
+
req.commonParams,
|
|
45
|
+
)})`,
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
37
49
|
return ctx.json({
|
|
38
50
|
ok: true,
|
|
39
51
|
package: {
|
|
@@ -20,6 +20,7 @@ export default withRouteSpec({
|
|
|
20
20
|
website: z.string().optional(),
|
|
21
21
|
is_private: z.boolean().optional(),
|
|
22
22
|
is_unlisted: z.boolean().optional(),
|
|
23
|
+
default_view: z.enum(["files", "3d", "pcb", "schematic"]).optional(),
|
|
23
24
|
})
|
|
24
25
|
.transform((data) => ({
|
|
25
26
|
...data,
|
|
@@ -30,8 +31,15 @@ export default withRouteSpec({
|
|
|
30
31
|
package: packageSchema,
|
|
31
32
|
}),
|
|
32
33
|
})(async (req, ctx) => {
|
|
33
|
-
const {
|
|
34
|
-
|
|
34
|
+
const {
|
|
35
|
+
package_id,
|
|
36
|
+
name,
|
|
37
|
+
description,
|
|
38
|
+
website,
|
|
39
|
+
is_private,
|
|
40
|
+
is_unlisted,
|
|
41
|
+
default_view,
|
|
42
|
+
} = req.jsonBody
|
|
35
43
|
|
|
36
44
|
const packageIndex = ctx.db.packages.findIndex(
|
|
37
45
|
(p) => p.package_id === package_id,
|
|
@@ -77,6 +85,7 @@ export default withRouteSpec({
|
|
|
77
85
|
is_public:
|
|
78
86
|
is_private !== undefined ? !is_private : existingPackage.is_public,
|
|
79
87
|
is_unlisted: is_unlisted ?? existingPackage.is_unlisted,
|
|
88
|
+
default_view: default_view ?? existingPackage.default_view,
|
|
80
89
|
updated_at: new Date().toISOString(),
|
|
81
90
|
})
|
|
82
91
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/fake-snippets",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.70",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"@tscircuit/layout": "^0.0.29",
|
|
76
76
|
"@tscircuit/math-utils": "^0.0.10",
|
|
77
77
|
"@tscircuit/mm": "^0.0.8",
|
|
78
|
-
"@tscircuit/props": "^0.0.
|
|
78
|
+
"@tscircuit/props": "^0.0.186",
|
|
79
79
|
"@types/file-saver": "^2.0.7",
|
|
80
80
|
"@types/ms": "^0.7.34",
|
|
81
81
|
"@typescript/ata": "^0.9.7",
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"@tailwindcss/typography": "^0.5.16",
|
|
148
148
|
"@tscircuit/core": "^0.0.384",
|
|
149
149
|
"@tscircuit/prompt-benchmarks": "^0.0.28",
|
|
150
|
-
"@tscircuit/runframe": "^0.0.
|
|
150
|
+
"@tscircuit/runframe": "^0.0.494",
|
|
151
151
|
"@types/babel__standalone": "^7.1.7",
|
|
152
152
|
"@types/bun": "^1.1.10",
|
|
153
153
|
"@types/country-list": "^2.1.4",
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
DialogHeader,
|
|
6
6
|
DialogTitle,
|
|
7
7
|
DialogFooter,
|
|
8
|
+
DialogDescription,
|
|
8
9
|
} from "@/components/ui/dialog"
|
|
9
10
|
import { Button } from "@/components/ui/button"
|
|
10
11
|
import { Textarea } from "@/components/ui/textarea"
|
|
@@ -13,6 +14,10 @@ import { useToast } from "@/hooks/use-toast"
|
|
|
13
14
|
import { useLocation } from "wouter"
|
|
14
15
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
15
16
|
import { convertCircuitJsonToTscircuit } from "circuit-json-to-tscircuit"
|
|
17
|
+
import { useCreatePackageMutation } from "@/hooks/use-create-package-mutation"
|
|
18
|
+
import { generateRandomPackageName } from "./package-port/CodeAndPreview"
|
|
19
|
+
import { useCreatePackageReleaseMutation } from "@/hooks/use-create-package-release-mutation"
|
|
20
|
+
import { useCreatePackageFilesMutation } from "@/hooks/use-create-package-files-mutation"
|
|
16
21
|
|
|
17
22
|
interface CircuitJsonImportDialogProps {
|
|
18
23
|
open: boolean
|
|
@@ -36,11 +41,29 @@ export function CircuitJsonImportDialog({
|
|
|
36
41
|
const [file, setFile] = useState<File | null>(null)
|
|
37
42
|
const [isLoading, setIsLoading] = useState(false)
|
|
38
43
|
const [error, setError] = useState<string | null>(null)
|
|
39
|
-
const
|
|
44
|
+
const loggedInUser = useGlobalStore((s) => s.session)
|
|
40
45
|
const { toast } = useToast()
|
|
46
|
+
const axios = useAxios()
|
|
41
47
|
const [, navigate] = useLocation()
|
|
42
48
|
const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
|
|
43
|
-
const
|
|
49
|
+
const createPackageMutation = useCreatePackageMutation()
|
|
50
|
+
const { mutate: createRelease } = useCreatePackageReleaseMutation({
|
|
51
|
+
onSuccess: () => {
|
|
52
|
+
toast({
|
|
53
|
+
title: "Package released",
|
|
54
|
+
description: "Your package has been released successfully.",
|
|
55
|
+
})
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const createPackageFilesMutation = useCreatePackageFilesMutation({
|
|
60
|
+
onSuccess: () => {
|
|
61
|
+
toast({
|
|
62
|
+
title: "Package files created",
|
|
63
|
+
description: "Your package files have been created successfully.",
|
|
64
|
+
})
|
|
65
|
+
},
|
|
66
|
+
})
|
|
44
67
|
|
|
45
68
|
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
46
69
|
const selectedFile = e.target.files?.[0]
|
|
@@ -54,80 +77,117 @@ export function CircuitJsonImportDialog({
|
|
|
54
77
|
const handleImport = async () => {
|
|
55
78
|
let importedCircuitJson
|
|
56
79
|
|
|
57
|
-
|
|
80
|
+
const parseJson = async (jsonString: string) => {
|
|
58
81
|
try {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
setError("Error reading JSON file. Please ensure it is valid.")
|
|
63
|
-
return
|
|
82
|
+
return JSON.parse(jsonString)
|
|
83
|
+
} catch {
|
|
84
|
+
throw new Error("Invalid JSON format.")
|
|
64
85
|
}
|
|
65
|
-
} else if (isValidJSON(circuitJson)) {
|
|
66
|
-
setIsLoading(true)
|
|
67
|
-
setError(null)
|
|
68
|
-
importedCircuitJson = JSON.parse(circuitJson)
|
|
69
|
-
} else {
|
|
70
|
-
toast({
|
|
71
|
-
title: "Invalid Input",
|
|
72
|
-
description: "Please provide a valid JSON content or file.",
|
|
73
|
-
variant: "destructive",
|
|
74
|
-
})
|
|
75
|
-
return
|
|
76
86
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
tscircuit = convertCircuitJsonToTscircuit(importedCircuitJson as any, {
|
|
80
|
-
componentName: "circuit",
|
|
81
|
-
})
|
|
82
|
-
console.info(tscircuit)
|
|
83
|
-
} catch {
|
|
87
|
+
|
|
88
|
+
const handleError = (message: string) => {
|
|
84
89
|
toast({
|
|
85
90
|
title: "Import Failed",
|
|
86
|
-
description:
|
|
91
|
+
description: message,
|
|
87
92
|
variant: "destructive",
|
|
88
93
|
})
|
|
89
94
|
setIsLoading(false)
|
|
90
|
-
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const handleSuccess = (message: string) => {
|
|
98
|
+
toast({
|
|
99
|
+
title: "Success",
|
|
100
|
+
description: message,
|
|
101
|
+
})
|
|
91
102
|
}
|
|
92
103
|
|
|
93
104
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (message) {
|
|
104
|
-
setError(message)
|
|
105
|
-
setIsLoading(false)
|
|
105
|
+
if (file) {
|
|
106
|
+
const fileText = await file.text()
|
|
107
|
+
importedCircuitJson = await parseJson(fileText)
|
|
108
|
+
} else if (isValidJSON(circuitJson)) {
|
|
109
|
+
setIsLoading(true)
|
|
110
|
+
setError(null)
|
|
111
|
+
importedCircuitJson = await parseJson(circuitJson)
|
|
112
|
+
} else {
|
|
113
|
+
handleError("Please provide a valid JSON content or file.")
|
|
106
114
|
return
|
|
107
115
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
|
|
117
|
+
const tscircuitComponentContent = convertCircuitJsonToTscircuit(
|
|
118
|
+
importedCircuitJson as any,
|
|
119
|
+
{
|
|
120
|
+
componentName: "circuit",
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
console.info(tscircuitComponentContent)
|
|
124
|
+
|
|
125
|
+
await createPackageMutation.mutateAsync(
|
|
126
|
+
{
|
|
127
|
+
name: `${loggedInUser?.github_username}/${generateRandomPackageName()}`,
|
|
128
|
+
description: "Imported from Circuit JSON",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
onSuccess: (newPackage) => {
|
|
132
|
+
handleSuccess("Package has been created successfully.")
|
|
133
|
+
createRelease(
|
|
134
|
+
{
|
|
135
|
+
package_name_with_version: `${newPackage.name}@latest`,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
onSuccess: (release) => {
|
|
139
|
+
createPackageFilesMutation
|
|
140
|
+
.mutateAsync({
|
|
141
|
+
file_path: "index.tsx",
|
|
142
|
+
content_text: tscircuitComponentContent,
|
|
143
|
+
package_release_id: release.package_release_id,
|
|
144
|
+
})
|
|
145
|
+
.then(() => {
|
|
146
|
+
navigate(`/editor?package_id=${newPackage.package_id}`)
|
|
147
|
+
})
|
|
148
|
+
},
|
|
149
|
+
onError: (error) => {
|
|
150
|
+
setError(error)
|
|
151
|
+
handleError("Failed to create package release.")
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
)
|
|
155
|
+
},
|
|
156
|
+
onError: (error) => {
|
|
157
|
+
setError(error)
|
|
158
|
+
handleError("Failed to create package.")
|
|
159
|
+
},
|
|
160
|
+
onSettled: () => {
|
|
161
|
+
setIsLoading(false)
|
|
162
|
+
onOpenChange(false)
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
)
|
|
114
166
|
} catch (error) {
|
|
115
167
|
console.error("Error importing Circuit Json:", error)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
variant: "destructive",
|
|
120
|
-
})
|
|
168
|
+
handleError(
|
|
169
|
+
"The Circuit JSON appears to be invalid or malformed. Please check the format and try again.",
|
|
170
|
+
)
|
|
121
171
|
} finally {
|
|
122
172
|
setIsLoading(false)
|
|
123
173
|
}
|
|
124
174
|
}
|
|
125
175
|
|
|
176
|
+
const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
|
177
|
+
if (event.ctrlKey && event.key === "Enter") {
|
|
178
|
+
handleImport()
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
126
182
|
return (
|
|
127
183
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
128
184
|
<DialogContent>
|
|
129
185
|
<DialogHeader>
|
|
130
186
|
<DialogTitle>Import Circuit JSON</DialogTitle>
|
|
187
|
+
<DialogDescription>
|
|
188
|
+
Use this dialog to import a Circuit JSON file or paste the JSON
|
|
189
|
+
content directly.
|
|
190
|
+
</DialogDescription>
|
|
131
191
|
</DialogHeader>
|
|
132
192
|
<div className="pb-4">
|
|
133
193
|
<Textarea
|
|
@@ -135,6 +195,7 @@ export function CircuitJsonImportDialog({
|
|
|
135
195
|
placeholder="Paste the Circuit JSON."
|
|
136
196
|
value={circuitJson}
|
|
137
197
|
onChange={(e) => setcircuitJson(e.target.value)}
|
|
198
|
+
onKeyDown={handleKeyDown}
|
|
138
199
|
disabled={!!file}
|
|
139
200
|
/>
|
|
140
201
|
<div className="mt-4 flex flex-col gap-2">
|
|
@@ -150,7 +211,7 @@ export function CircuitJsonImportDialog({
|
|
|
150
211
|
type="file"
|
|
151
212
|
accept="application/json"
|
|
152
213
|
onChange={handleFileChange}
|
|
153
|
-
className="hidden"
|
|
214
|
+
className="hidden"
|
|
154
215
|
/>
|
|
155
216
|
<label
|
|
156
217
|
htmlFor="file-input"
|
|
@@ -67,7 +67,7 @@ export const HeaderLogin = () => {
|
|
|
67
67
|
</a>
|
|
68
68
|
</DropdownMenuItem>
|
|
69
69
|
<DropdownMenuItem asChild onClick={() => setSession(null)}>
|
|
70
|
-
<a href="/
|
|
70
|
+
<a href="/" className="cursor-pointer">
|
|
71
71
|
Sign out
|
|
72
72
|
</a>
|
|
73
73
|
</DropdownMenuItem>
|
|
@@ -168,7 +168,7 @@ export default function ImportantFilesView({
|
|
|
168
168
|
return (
|
|
169
169
|
<div className="mt-4 border border-gray-200 dark:border-[#30363d] rounded-md overflow-hidden">
|
|
170
170
|
<div className="flex items-center pl-2 pr-4 py-2 bg-gray-100 dark:bg-[#161b22] border-b border-gray-200 dark:border-[#30363d]">
|
|
171
|
-
<div className="flex items-center space-x-2">
|
|
171
|
+
<div className="flex items-center space-x-2 overflow-x-auto no-scrollbar">
|
|
172
172
|
{/* AI Description Tab */}
|
|
173
173
|
{hasAiContent && (
|
|
174
174
|
<button
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect } from "react"
|
|
2
2
|
import { Link } from "wouter"
|
|
3
|
-
|
|
4
|
-
import { TypeBadge } from "@/components/TypeBadge"
|
|
5
3
|
import { Button } from "@/components/ui/button"
|
|
6
4
|
import { Skeleton } from "@/components/ui/skeleton"
|
|
7
5
|
import {
|
|
@@ -10,7 +8,7 @@ import {
|
|
|
10
8
|
TooltipProvider,
|
|
11
9
|
TooltipTrigger,
|
|
12
10
|
} from "@/components/ui/tooltip"
|
|
13
|
-
import {
|
|
11
|
+
import { Lock, Globe } from "lucide-react"
|
|
14
12
|
import { GitFork, Package, Star } from "lucide-react"
|
|
15
13
|
|
|
16
14
|
import { useForkPackageMutation } from "@/hooks/use-fork-package-mutation"
|
|
@@ -106,13 +104,25 @@ export default function PackageHeader({
|
|
|
106
104
|
{packageName}
|
|
107
105
|
</Link>
|
|
108
106
|
</h1>
|
|
109
|
-
{packageInfo?.name &&
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
107
|
+
{packageInfo?.name && (
|
|
108
|
+
<div
|
|
109
|
+
className={`select-none inline-flex items-center px-2 py-1 rounded text-xs font-medium ${
|
|
110
|
+
isPrivate
|
|
111
|
+
? "bg-gray-100 text-gray-700 border border-gray-200"
|
|
112
|
+
: "bg-blue-50 text-blue-700 border border-blue-200"
|
|
113
|
+
}`}
|
|
114
|
+
>
|
|
115
|
+
{isPrivate ? (
|
|
116
|
+
<>
|
|
117
|
+
<Lock className="w-3 h-3 mr-1 flex-shrink-0" />
|
|
118
|
+
<span className="leading-none">Private</span>
|
|
119
|
+
</>
|
|
120
|
+
) : (
|
|
121
|
+
<>
|
|
122
|
+
<Globe className="w-3 h-3 mr-1 flex-shrink-0" />
|
|
123
|
+
<span className="leading-none">Public</span>
|
|
124
|
+
</>
|
|
125
|
+
)}
|
|
116
126
|
</div>
|
|
117
127
|
)}
|
|
118
128
|
</>
|
|
@@ -19,6 +19,7 @@ import PackageHeader from "./package-header"
|
|
|
19
19
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
20
20
|
import { useLocation } from "wouter"
|
|
21
21
|
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
22
|
+
import { useCurrentPackageCircuitJson } from "../hooks/use-current-package-circuit-json"
|
|
22
23
|
|
|
23
24
|
interface PackageFile {
|
|
24
25
|
package_file_id: string
|
|
@@ -43,22 +44,37 @@ export default function RepoPageContent({
|
|
|
43
44
|
onFileClicked,
|
|
44
45
|
onEditClicked,
|
|
45
46
|
}: RepoPageContentProps) {
|
|
46
|
-
const [location, setLocation] = useLocation()
|
|
47
47
|
const [activeView, setActiveView] = useState<string>("files")
|
|
48
48
|
const session = useGlobalStore((s) => s.session)
|
|
49
|
+
const { circuitJson, isLoading: isCircuitJsonLoading } =
|
|
50
|
+
useCurrentPackageCircuitJson()
|
|
49
51
|
|
|
50
|
-
// Handle hash-based view
|
|
52
|
+
// Handle initial view selection and hash-based view changes
|
|
51
53
|
useEffect(() => {
|
|
52
|
-
|
|
54
|
+
if (isCircuitJsonLoading) return
|
|
53
55
|
const hash = window.location.hash.slice(1)
|
|
54
|
-
// Valid views
|
|
55
56
|
const validViews = ["files", "3d", "pcb", "schematic", "bom"]
|
|
57
|
+
const circuitDependentViews = ["3d", "pcb", "schematic", "bom"]
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
const availableViews = circuitJson
|
|
60
|
+
? validViews
|
|
61
|
+
: validViews.filter((view) => !circuitDependentViews.includes(view))
|
|
62
|
+
|
|
63
|
+
if (hash && availableViews.includes(hash)) {
|
|
59
64
|
setActiveView(hash)
|
|
65
|
+
} else if (
|
|
66
|
+
packageInfo?.default_view &&
|
|
67
|
+
availableViews.includes(packageInfo.default_view)
|
|
68
|
+
) {
|
|
69
|
+
setActiveView(packageInfo.default_view)
|
|
70
|
+
window.location.hash = packageInfo.default_view
|
|
71
|
+
} else {
|
|
72
|
+
setActiveView("files")
|
|
73
|
+
if (!hash || !availableViews.includes(hash)) {
|
|
74
|
+
window.location.hash = "files"
|
|
75
|
+
}
|
|
60
76
|
}
|
|
61
|
-
}, [])
|
|
77
|
+
}, [packageInfo?.default_view, circuitJson, isCircuitJsonLoading])
|
|
62
78
|
|
|
63
79
|
const importantFilePaths = packageFiles
|
|
64
80
|
?.filter((pf) => isPackageFileImportant(pf.file_path))
|
|
@@ -138,6 +154,7 @@ export default function RepoPageContent({
|
|
|
138
154
|
<Header />
|
|
139
155
|
<PackageHeader
|
|
140
156
|
packageInfo={packageInfo}
|
|
157
|
+
isPrivate={packageInfo?.is_private ?? false}
|
|
141
158
|
isCurrentUserAuthor={
|
|
142
159
|
packageInfo?.creator_account_id === session?.github_username
|
|
143
160
|
}
|