@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.
Files changed (30) hide show
  1. package/bun-tests/fake-snippets-api/routes/packages/update.test.ts +104 -0
  2. package/bun.lock +15 -25
  3. package/dist/bundle.js +25 -5
  4. package/dist/index.d.ts +5 -0
  5. package/dist/index.js +2 -1
  6. package/dist/schema.d.ts +8 -0
  7. package/dist/schema.js +2 -1
  8. package/fake-snippets-api/lib/db/schema.ts +4 -0
  9. package/fake-snippets-api/routes/api/packages/create.ts +1 -0
  10. package/fake-snippets-api/routes/api/packages/get.ts +12 -0
  11. package/fake-snippets-api/routes/api/packages/update.ts +11 -2
  12. package/package.json +3 -3
  13. package/src/components/CircuitJsonImportDialog.tsx +113 -52
  14. package/src/components/DownloadButtonAndMenu.tsx +1 -1
  15. package/src/components/HeaderLogin.tsx +1 -1
  16. package/src/components/ViewPackagePage/components/important-files-view.tsx +1 -1
  17. package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +1 -0
  18. package/src/components/ViewPackagePage/components/package-header.tsx +21 -11
  19. package/src/components/ViewPackagePage/components/repo-page-content.tsx +24 -7
  20. package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +1 -0
  21. package/src/components/dialogs/edit-package-details-dialog.tsx +33 -2
  22. package/src/components/package-port/CodeAndPreview.tsx +1 -1
  23. package/src/components/package-port/CodeEditorHeader.tsx +12 -4
  24. package/src/components/package-port/EditorNav.tsx +33 -8
  25. package/src/hooks/use-create-package-mutation.ts +0 -2
  26. package/src/hooks/use-package-details-form.ts +15 -1
  27. package/src/index.css +13 -0
  28. package/src/pages/package-editor.tsx +2 -1
  29. package/src/pages/quickstart.tsx +1 -1
  30. package/src/pages/view-package.tsx +13 -11
@@ -35,6 +35,7 @@ interface EditPackageDetailsDialogProps {
35
35
  currentDescription: string
36
36
  currentWebsite: string
37
37
  currentLicense?: string | null
38
+ currentDefaultView?: string
38
39
  isPrivate?: boolean
39
40
  packageName: string
40
41
  packageReleaseId: string | null
@@ -43,6 +44,7 @@ interface EditPackageDetailsDialogProps {
43
44
  newDescription: string,
44
45
  newWebsite: string,
45
46
  newLicense: string | null,
47
+ newDefaultView: string,
46
48
  ) => void
47
49
  }
48
50
 
@@ -53,6 +55,7 @@ export const EditPackageDetailsDialog = ({
53
55
  currentDescription,
54
56
  currentWebsite,
55
57
  currentLicense,
58
+ currentDefaultView = "files",
56
59
  isPrivate = false,
57
60
  packageName,
58
61
  packageReleaseId,
@@ -68,12 +71,14 @@ export const EditPackageDetailsDialog = ({
68
71
  setFormData,
69
72
  websiteError,
70
73
  hasLicenseChanged,
74
+ hasDefaultViewChanged,
71
75
  hasChanges,
72
76
  isFormValid,
73
77
  } = usePackageDetailsForm({
74
78
  initialDescription: currentDescription,
75
79
  initialWebsite: currentWebsite,
76
80
  initialLicense: currentLicense || null,
81
+ initialDefaultView: currentDefaultView,
77
82
  isDialogOpen: open,
78
83
  initialVisibility: isPrivate ? "private" : "public",
79
84
  })
@@ -108,6 +113,7 @@ export const EditPackageDetailsDialog = ({
108
113
  description: formData.description,
109
114
  website: formData.website,
110
115
  is_private: formData.visibility == "private",
116
+ default_view: formData.defaultView,
111
117
  })
112
118
  const privacyUpdateResponse = await axios.post("/snippets/update", {
113
119
  snippet_id: packageId,
@@ -149,6 +155,7 @@ export const EditPackageDetailsDialog = ({
149
155
  website: formData.website,
150
156
  license: formData.license,
151
157
  visibility: formData.visibility,
158
+ defaultView: formData.defaultView,
152
159
  }
153
160
  },
154
161
  onMutate: async () => {
@@ -160,11 +167,12 @@ export const EditPackageDetailsDialog = ({
160
167
  website: formData.website,
161
168
  license: formData.license,
162
169
  is_private: formData.visibility == "private",
170
+ default_view: formData.defaultView,
163
171
  }))
164
172
  return { previous }
165
173
  },
166
174
  onSuccess: (data) => {
167
- onUpdate?.(data.description, data.website, data.license)
175
+ onUpdate?.(data.description, data.website, data.license, data.defaultView)
168
176
  onOpenChange(false)
169
177
  qc.invalidateQueries([
170
178
  "packageFile",
@@ -218,7 +226,7 @@ export const EditPackageDetailsDialog = ({
218
226
  </DialogContent>
219
227
  </Dialog>
220
228
  <Dialog open={open !== showConfirmDelete} onOpenChange={onOpenChange}>
221
- <DialogContent className="sm:max-w-[500px] lg:h-[70vh] sm:h-[90vh] overflow-y-auto w-[95vw] h-[80vh] p-6 gap-6 rounded-2xl shadow-lg">
229
+ <DialogContent className="sm:max-w-[500px] lg:h-[85vh] sm:h-[90vh] overflow-y-auto no-scrollbar w-[95vw] h-[80vh] p-6 gap-6 rounded-2xl shadow-lg">
222
230
  <div className="flex flex-col gap-10">
223
231
  <DialogHeader>
224
232
  <DialogTitle>Edit Package Details</DialogTitle>
@@ -310,6 +318,29 @@ export const EditPackageDetailsDialog = ({
310
318
  </SelectContent>
311
319
  </Select>
312
320
  </div>
321
+ <div className="space-y-1">
322
+ <Label htmlFor="defaultView">Default View</Label>
323
+ <Select
324
+ value={formData.defaultView}
325
+ onValueChange={(value) =>
326
+ setFormData((prev) => ({
327
+ ...prev,
328
+ defaultView: value,
329
+ }))
330
+ }
331
+ disabled={updatePackageDetailsMutation.isLoading}
332
+ >
333
+ <SelectTrigger className="w-full">
334
+ <SelectValue placeholder="Select default view" />
335
+ </SelectTrigger>
336
+ <SelectContent className="!z-[999]">
337
+ <SelectItem value="files">Files</SelectItem>
338
+ <SelectItem value="3d">3D</SelectItem>
339
+ <SelectItem value="pcb">PCB</SelectItem>
340
+ <SelectItem value="schematic">Schematic</SelectItem>
341
+ </SelectContent>
342
+ </Select>
343
+ </div>
313
344
  </div>
314
345
 
315
346
  <details
@@ -64,7 +64,7 @@ export default () => (
64
64
  )
65
65
  `.trim()
66
66
 
67
- const generateRandomPackageName = () =>
67
+ export const generateRandomPackageName = () =>
68
68
  `untitled-package-${Math.floor(Math.random() * 90) + 10}`
69
69
 
70
70
  export function CodeAndPreview({ pkg }: Props) {
@@ -136,16 +136,24 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
136
136
  <>
137
137
  <div className="flex items-center gap-2 px-2 border-b border-gray-200">
138
138
  <button
139
- className={`text-gray-400 scale-90 transition-opacity duration-200 ${
140
- sidebarOpen ? "opacity-0 pointer-events-none" : "opacity-100"
139
+ className={`text-gray-400 scale-90 p-0 transition-[width,opacity] duration-300 ease-in-out overflow-hidden ${
140
+ sidebarOpen
141
+ ? "w-0 pointer-events-none opacity-0"
142
+ : "w-6 opacity-100"
141
143
  }`}
142
144
  onClick={() => setSidebarOpen(true)}
143
145
  >
144
- <PanelRightClose />
146
+ <div className="w-6 h-6 flex items-center justify-center">
147
+ <PanelRightClose />
148
+ </div>
145
149
  </button>
146
150
  <div>
147
151
  <Select value={currentFile} onValueChange={handleFileChange}>
148
- <SelectTrigger className="h-7 px-3 bg-white select-none">
152
+ <SelectTrigger
153
+ className={`h-7 px-3 bg-white select-none transition-[margin] duration-300 ease-in-out ${
154
+ sidebarOpen ? "-ml-2" : "-ml-1"
155
+ }`}
156
+ >
149
157
  <SelectValue placeholder="Select file" />
150
158
  </SelectTrigger>
151
159
  <SelectContent>
@@ -324,7 +324,7 @@ export default function EditorNav({
324
324
  <DownloadButtonAndMenu
325
325
  snippetUnscopedName={pkg?.unscoped_name}
326
326
  circuitJson={circuitJson}
327
- className="hidden md:flex"
327
+ className="flex"
328
328
  />
329
329
  <Button
330
330
  variant="ghost"
@@ -464,17 +464,42 @@ export default function EditorNav({
464
464
  </div>
465
465
  </DropdownMenuTrigger>
466
466
  <DropdownMenuContent>
467
- <DropdownMenuItem className="text-xs">
468
- <Download className="mr-1 h-3 w-3" />
469
- Download
470
- </DropdownMenuItem>
471
- <DropdownMenuItem className="text-xs">
467
+ <DropdownMenuItem
468
+ className="text-xs"
469
+ onClick={() => {
470
+ if (window) {
471
+ navigator.clipboard.writeText(
472
+ new URL(window.location.href).origin + "/" + pkg?.name,
473
+ )
474
+ toast({
475
+ title: "URL copied!",
476
+ description: "The URL has been copied to your clipboard.",
477
+ })
478
+ }
479
+ }}
480
+ >
472
481
  <Share className="mr-1 h-3 w-3" />
473
482
  Copy URL
474
483
  </DropdownMenuItem>
475
- <DropdownMenuItem className="text-xs">
484
+ <DropdownMenuItem
485
+ className="text-xs"
486
+ onClick={() => {
487
+ if (
488
+ pkg &&
489
+ session?.github_username === pkg.owner_github_username
490
+ ) {
491
+ updatePackageVisibilityToPrivate(!isPrivate)
492
+ }
493
+ }}
494
+ >
476
495
  <Eye className="mr-1 h-3 w-3" />
477
- Public
496
+ {session?.github_username === pkg?.owner_github_username
497
+ ? isPrivate
498
+ ? "Make Public"
499
+ : "Make Private"
500
+ : isPrivate
501
+ ? "Private Package"
502
+ : "Public Package"}
478
503
  </DropdownMenuItem>
479
504
  </DropdownMenuContent>
480
505
  </DropdownMenu>
@@ -7,8 +7,6 @@ import { useUrlParams } from "./use-url-params"
7
7
  export const useCreatePackageMutation = ({
8
8
  onSuccess,
9
9
  }: { onSuccess?: (pkg: Package) => void } = {}) => {
10
- const urlParams = useUrlParams()
11
- const templateName = urlParams.template
12
10
  const axios = useAxios()
13
11
  const session = useGlobalStore((s) => s.session)
14
12
 
@@ -15,6 +15,7 @@ interface PackageDetailsForm {
15
15
  website: string
16
16
  license: string | null
17
17
  visibility: string
18
+ defaultView: string
18
19
  }
19
20
 
20
21
  interface UsePackageDetailsFormProps {
@@ -22,6 +23,7 @@ interface UsePackageDetailsFormProps {
22
23
  initialWebsite: string
23
24
  initialLicense: string | null
24
25
  initialVisibility: string
26
+ initialDefaultView: string
25
27
  isDialogOpen: boolean
26
28
  }
27
29
 
@@ -30,6 +32,7 @@ export const usePackageDetailsForm = ({
30
32
  initialWebsite,
31
33
  initialLicense,
32
34
  initialVisibility,
35
+ initialDefaultView,
33
36
  isDialogOpen,
34
37
  }: UsePackageDetailsFormProps) => {
35
38
  const [formData, setFormData] = useState<PackageDetailsForm>({
@@ -37,6 +40,7 @@ export const usePackageDetailsForm = ({
37
40
  website: initialWebsite,
38
41
  license: initialLicense || null,
39
42
  visibility: initialVisibility,
43
+ defaultView: initialDefaultView,
40
44
  })
41
45
  const [websiteError, setWebsiteError] = useState<string | null>(null)
42
46
 
@@ -47,6 +51,7 @@ export const usePackageDetailsForm = ({
47
51
  website: initialWebsite,
48
52
  license: initialLicense || null,
49
53
  visibility: initialVisibility,
54
+ defaultView: initialDefaultView,
50
55
  })
51
56
  setWebsiteError(null)
52
57
  }
@@ -56,6 +61,7 @@ export const usePackageDetailsForm = ({
56
61
  initialWebsite,
57
62
  initialLicense,
58
63
  initialVisibility,
64
+ initialDefaultView,
59
65
  ])
60
66
 
61
67
  useEffect(() => {
@@ -76,18 +82,25 @@ export const usePackageDetailsForm = ({
76
82
  [formData.visibility, initialVisibility],
77
83
  )
78
84
 
85
+ const hasDefaultViewChanged = useMemo(
86
+ () => formData.defaultView !== initialDefaultView,
87
+ [formData.defaultView, initialDefaultView],
88
+ )
89
+
79
90
  const hasChanges = useMemo(
80
91
  () =>
81
92
  formData.description !== initialDescription ||
82
93
  formData.website !== initialWebsite ||
83
94
  formData.license !== initialLicense ||
84
- formData.visibility !== initialVisibility,
95
+ formData.visibility !== initialVisibility ||
96
+ formData.defaultView !== initialDefaultView,
85
97
  [
86
98
  formData,
87
99
  initialDescription,
88
100
  initialWebsite,
89
101
  initialLicense,
90
102
  initialVisibility,
103
+ initialDefaultView,
91
104
  ],
92
105
  )
93
106
 
@@ -99,6 +112,7 @@ export const usePackageDetailsForm = ({
99
112
  websiteError,
100
113
  hasLicenseChanged,
101
114
  hasVisibilityChanged,
115
+ hasDefaultViewChanged,
102
116
  hasChanges,
103
117
  isFormValid,
104
118
  }
package/src/index.css CHANGED
@@ -7,6 +7,19 @@
7
7
  }
8
8
  }
9
9
 
10
+ /* add the code bellow */
11
+ @layer utilities {
12
+ /* Hide scrollbar for Chrome, Safari and Opera */
13
+ .no-scrollbar::-webkit-scrollbar {
14
+ display: none;
15
+ }
16
+ /* Hide scrollbar for IE, Edge and Firefox */
17
+ .no-scrollbar {
18
+ -ms-overflow-style: none; /* IE and Edge */
19
+ scrollbar-width: none; /* Firefox */
20
+ }
21
+ }
22
+
10
23
  .shiki {
11
24
  font-family: "Fira Code", monospace;
12
25
  font-size: 14px;
@@ -10,13 +10,14 @@ import { useGetFsMapHashForPackage } from "@/hooks/use-get-fsmap-hash-for-packag
10
10
 
11
11
  export const EditorPage = () => {
12
12
  const { packageId } = useCurrentPackageId()
13
- const { data: pkg, isLoading, error } = usePackage(packageId)
13
+ const { data: pkg, error } = usePackage(packageId)
14
14
  const fsMapHash = useGetFsMapHashForPackage(
15
15
  pkg?.latest_package_release_id ?? "",
16
16
  )
17
17
  const uuid4RegExp = new RegExp(
18
18
  /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,
19
19
  )
20
+
20
21
  return (
21
22
  <div className="overflow-x-hidden">
22
23
  <Helmet>
@@ -166,7 +166,7 @@ export const QuickstartPage = () => {
166
166
  <CardHeader className="p-4 pb-0">
167
167
  <CardTitle className="text-lg flex items-center justify-between">
168
168
  Circuit Json
169
- <TypeBadge type="module" className="ml-2" />
169
+ <TypeBadge type="package" className="ml-2" />
170
170
  </CardTitle>
171
171
  </CardHeader>
172
172
  <CardContent className="p-4 mt-auto">
@@ -1,18 +1,22 @@
1
1
  import RepoPageContent from "@/components/ViewPackagePage/components/repo-page-content"
2
- import { useCurrentPackageInfo } from "@/hooks/use-current-package-info"
3
2
  import { usePackageFiles } from "@/hooks/use-package-files"
4
3
  import { usePackageRelease } from "@/hooks/use-package-release"
5
4
  import { useLocation, useParams } from "wouter"
6
5
  import { Helmet } from "react-helmet-async"
7
6
  import { useEffect, useState } from "react"
8
7
  import NotFoundPage from "./404"
8
+ import { useCurrentPackageId } from "@/hooks/use-current-package-id"
9
+ import { usePackage } from "@/hooks/use-package"
9
10
 
10
11
  export const ViewPackagePage = () => {
11
- const { packageInfo } = useCurrentPackageInfo()
12
+ const {
13
+ packageId,
14
+ error: packageIdError,
15
+ isLoading: isLoadingPackageId,
16
+ } = useCurrentPackageId()
17
+ const { data: packageInfo } = usePackage(packageId)
12
18
  const { author, packageName } = useParams()
13
19
  const [, setLocation] = useLocation()
14
- const [isNotFound, setIsNotFound] = useState(false)
15
-
16
20
  const {
17
21
  data: packageRelease,
18
22
  error: packageReleaseError,
@@ -25,14 +29,12 @@ export const ViewPackagePage = () => {
25
29
  const { data: packageFiles } = usePackageFiles(
26
30
  packageRelease?.package_release_id,
27
31
  )
28
- useEffect(() => {
29
- if (isLoadingPackageRelease) return
30
- if (packageReleaseError?.status == 404) {
31
- setIsNotFound(true)
32
- }
33
- }, [isLoadingPackageRelease, packageReleaseError])
34
32
 
35
- if (isNotFound) {
33
+ if (!isLoadingPackageId && packageIdError) {
34
+ return <NotFoundPage heading="Package Not Found" />
35
+ }
36
+
37
+ if (!isLoadingPackageRelease && packageReleaseError?.status == 404) {
36
38
  return <NotFoundPage heading="Package Not Found" />
37
39
  }
38
40