@tscircuit/fake-snippets 0.0.109 → 0.0.111

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 (185) hide show
  1. package/.github/workflows/bun-formatcheck.yml +2 -2
  2. package/.github/workflows/bun-pver-release.yml +3 -3
  3. package/.github/workflows/bun-test.yml +1 -1
  4. package/.github/workflows/bun-typecheck.yml +2 -2
  5. package/.github/workflows/update-snapshots.yml +1 -1
  6. package/README.md +4 -0
  7. package/api/generated-index.js +37 -3
  8. package/biome.json +2 -1
  9. package/bun-tests/fake-snippets-api/fixtures/get-test-server.ts +32 -3
  10. package/bun-tests/fake-snippets-api/fixtures/preload.ts +18 -0
  11. package/bun-tests/fake-snippets-api/routes/orgs/add_member.test.ts +26 -0
  12. package/bun-tests/fake-snippets-api/routes/orgs/create.test.ts +37 -0
  13. package/bun-tests/fake-snippets-api/routes/orgs/get.test.ts +52 -0
  14. package/bun-tests/fake-snippets-api/routes/orgs/list.test.ts +17 -0
  15. package/bun-tests/fake-snippets-api/routes/orgs/list_members.test.ts +23 -0
  16. package/bun-tests/fake-snippets-api/routes/orgs/remove_member.test.ts +81 -0
  17. package/bun-tests/fake-snippets-api/routes/orgs/update.test.ts +151 -0
  18. package/bun-tests/fake-snippets-api/routes/package_builds/get.test.ts +1 -1
  19. package/bun-tests/fake-snippets-api/routes/package_files/create.test.ts +15 -13
  20. package/bun-tests/fake-snippets-api/routes/package_files/create_or_update.test.ts +26 -24
  21. package/bun-tests/fake-snippets-api/routes/package_files/delete.test.ts +9 -9
  22. package/bun-tests/fake-snippets-api/routes/package_files/download.test.ts +4 -4
  23. package/bun-tests/fake-snippets-api/routes/package_files/get.test.ts +38 -28
  24. package/bun-tests/fake-snippets-api/routes/package_files/list.test.ts +23 -15
  25. package/bun-tests/fake-snippets-api/routes/package_releases/create.test.ts +33 -0
  26. package/bun-tests/fake-snippets-api/routes/package_releases/get.test.ts +4 -4
  27. package/bun-tests/fake-snippets-api/routes/package_releases/get_image_generation_fields.test.ts +38 -0
  28. package/bun-tests/fake-snippets-api/routes/packages/create.test.ts +19 -0
  29. package/bun-tests/fake-snippets-api/routes/packages/fork.test.ts +3 -4
  30. package/bun-tests/fake-snippets-api/routes/packages/get.test.ts +30 -0
  31. package/bun-tests/fake-snippets-api/routes/packages/images.test.ts +4 -2
  32. package/bun-tests/fake-snippets-api/routes/packages/list-1.test.ts +34 -0
  33. package/bun.lock +361 -453
  34. package/bunfig.toml +2 -1
  35. package/dist/bundle.js +1313 -639
  36. package/dist/index.d.ts +313 -6
  37. package/dist/index.js +328 -24
  38. package/dist/schema.d.ts +290 -1
  39. package/dist/schema.js +54 -1
  40. package/fake-snippets-api/lib/db/autoload-dev-packages.ts +31 -20
  41. package/fake-snippets-api/lib/db/db-client.ts +219 -4
  42. package/fake-snippets-api/lib/db/schema.ts +63 -1
  43. package/fake-snippets-api/lib/db/seed.ts +100 -0
  44. package/fake-snippets-api/lib/middleware/with-session-auth.ts +60 -8
  45. package/fake-snippets-api/lib/package_file/get-package-file-id-from-file-descriptor.ts +2 -2
  46. package/fake-snippets-api/lib/public-mapping/public-map-org.ts +33 -0
  47. package/fake-snippets-api/lib/public-mapping/public-map-package-build.ts +10 -0
  48. package/fake-snippets-api/lib/public-mapping/public-map-package-release.ts +17 -0
  49. package/fake-snippets-api/routes/api/orgs/add_member.ts +52 -0
  50. package/fake-snippets-api/routes/api/orgs/create.ts +48 -0
  51. package/fake-snippets-api/routes/api/orgs/get.ts +39 -0
  52. package/fake-snippets-api/routes/api/orgs/list.ts +31 -0
  53. package/fake-snippets-api/routes/api/orgs/list_members.ts +60 -0
  54. package/fake-snippets-api/routes/api/orgs/remove_member.ts +46 -0
  55. package/fake-snippets-api/routes/api/orgs/update.ts +118 -0
  56. package/fake-snippets-api/routes/api/package_files/get.ts +3 -6
  57. package/fake-snippets-api/routes/api/package_files/list.ts +7 -4
  58. package/fake-snippets-api/routes/api/packages/create.ts +57 -10
  59. package/fake-snippets-api/routes/api/packages/get.ts +23 -0
  60. package/fake-snippets-api/routes/api/packages/images/[owner_github_username]/[unscoped_name]/[view_format].ts +13 -11
  61. package/fake-snippets-api/routes/api/packages/list.ts +29 -2
  62. package/fake-snippets-api/routes/api/packages/update_ai_description.ts +37 -0
  63. package/package.json +25 -19
  64. package/renovate.json +1 -1
  65. package/scripts/generate-sitemap.ts +1 -1
  66. package/src/App.tsx +27 -8
  67. package/src/ContextProviders.tsx +25 -2
  68. package/src/components/CircuitJsonImportDialog.tsx +1 -1
  69. package/src/components/CmdKMenu.tsx +281 -247
  70. package/src/components/DownloadButtonAndMenu.tsx +17 -5
  71. package/src/components/FileSidebar.tsx +11 -17
  72. package/src/components/Footer.tsx +8 -9
  73. package/src/components/Header.tsx +19 -32
  74. package/src/components/Header2.tsx +16 -32
  75. package/src/components/HeaderDropdown.tsx +13 -8
  76. package/src/components/HeaderLogin.tsx +43 -15
  77. package/src/components/NotFound.tsx +5 -5
  78. package/src/components/PackageBreadcrumb.tsx +6 -12
  79. package/src/components/PackageSearchResults.tsx +1 -1
  80. package/src/components/PrefetchPageLink.tsx +7 -1
  81. package/src/components/ProfileRouter.tsx +32 -0
  82. package/src/components/SearchComponent.tsx +12 -8
  83. package/src/components/SentryNotFoundReporter.tsx +44 -0
  84. package/src/components/UserCard.tsx +80 -0
  85. package/src/components/ViewPackagePage/components/build-status.tsx +1 -1
  86. package/src/components/ViewPackagePage/components/important-files-view.tsx +105 -34
  87. package/src/components/ViewPackagePage/components/main-content-header.tsx +10 -6
  88. package/src/components/ViewPackagePage/components/main-content-view-selector.tsx +1 -1
  89. package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +54 -19
  90. package/src/components/ViewPackagePage/components/package-header.tsx +25 -33
  91. package/src/components/ViewPackagePage/components/preview-image-squares.tsx +11 -18
  92. package/src/components/ViewPackagePage/components/repo-page-content.tsx +12 -5
  93. package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +16 -10
  94. package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +11 -11
  95. package/src/components/ViewPackagePage/components/tab-views/pcb-view.tsx +1 -2
  96. package/src/components/ViewPackagePage/components/tab-views/schematic-view.tsx +2 -1
  97. package/src/components/dialogs/GitHubRepositorySelector.tsx +56 -49
  98. package/src/components/dialogs/edit-package-details-dialog.tsx +5 -6
  99. package/src/components/dialogs/import-component-dialog.tsx +16 -9
  100. package/src/components/dialogs/import-package-dialog.tsx +3 -2
  101. package/src/components/dialogs/new-package-save-prompt-dialog.tsx +190 -0
  102. package/src/components/organization/OrganizationCard.tsx +206 -0
  103. package/src/components/organization/OrganizationCardSkeleton.tsx +55 -0
  104. package/src/components/organization/OrganizationHeader.tsx +154 -0
  105. package/src/components/organization/OrganizationMembers.tsx +146 -0
  106. package/src/components/package-port/CodeAndPreview.tsx +15 -12
  107. package/src/components/package-port/CodeEditor.tsx +4 -30
  108. package/src/components/package-port/CodeEditorHeader.tsx +123 -61
  109. package/src/components/package-port/EditorNav.tsx +32 -49
  110. package/src/components/preview/ConnectedPackagesList.tsx +8 -8
  111. package/src/components/preview/ConnectedRepoOverview.tsx +102 -2
  112. package/src/components/preview/PackageReleasesDashboard.tsx +23 -11
  113. package/src/components/ui/tree-view.tsx +6 -3
  114. package/src/hooks/use-add-org-member-mutation.ts +51 -0
  115. package/src/hooks/use-create-org-mutation.ts +38 -0
  116. package/src/hooks/use-create-package-mutation.ts +3 -0
  117. package/src/hooks/use-current-package-release.ts +4 -3
  118. package/src/hooks/use-download-zip.ts +2 -2
  119. package/src/hooks/use-global-store.ts +6 -4
  120. package/src/hooks/use-hydration.ts +30 -0
  121. package/src/hooks/use-jlcpcb-component-import.tsx +164 -0
  122. package/src/hooks/use-list-org-members.ts +27 -0
  123. package/src/hooks/use-list-user-orgs.ts +25 -0
  124. package/src/hooks/use-org-by-github-handle.ts +26 -0
  125. package/src/hooks/use-org.ts +24 -0
  126. package/src/hooks/use-organization.ts +42 -0
  127. package/src/hooks/use-package-as-snippet.ts +4 -2
  128. package/src/hooks/use-package-builds.ts +6 -2
  129. package/src/hooks/use-package-files.ts +5 -3
  130. package/src/hooks/use-package-release-by-id-or-version.ts +29 -20
  131. package/src/hooks/use-package-release-images.ts +105 -0
  132. package/src/hooks/use-package-release.ts +2 -2
  133. package/src/hooks/use-package-stars.ts +80 -4
  134. package/src/hooks/use-preview-images.ts +6 -3
  135. package/src/hooks/use-remove-org-member-mutation.ts +32 -0
  136. package/src/hooks/use-update-ai-description-mutation.ts +42 -0
  137. package/src/hooks/use-update-org-mutation.ts +41 -0
  138. package/src/hooks/use-warn-user-on-page-change.ts +71 -4
  139. package/src/hooks/useFileManagement.ts +51 -22
  140. package/src/hooks/useOptimizedPackageFilesLoader.ts +11 -24
  141. package/src/hooks/usePackageFilesLoader.ts +2 -2
  142. package/src/hooks/useUpdatePackageFilesMutation.ts +13 -1
  143. package/src/lib/download-fns/download-gltf-from-circuit-json.ts +1 -1
  144. package/src/lib/download-fns/download-kicad-files.ts +22 -11
  145. package/src/lib/download-fns/download-step.ts +12 -0
  146. package/src/lib/normalize-svg-for-tile.ts +50 -0
  147. package/src/lib/posthog.ts +11 -9
  148. package/src/lib/react-query-api-failure-tracking.ts +148 -0
  149. package/src/lib/sentry.ts +14 -0
  150. package/src/lib/templates/blank-circuit-board-template.ts +0 -4
  151. package/src/lib/ts-lib-cache.ts +122 -7
  152. package/src/lib/utils/checkIfManualEditsImported.ts +4 -4
  153. package/src/lib/utils/findTargetFile.ts +45 -10
  154. package/src/lib/utils/isComponentExported.ts +2 -1
  155. package/src/main.tsx +2 -1
  156. package/src/pages/create-organization.tsx +169 -0
  157. package/src/pages/dashboard.tsx +38 -6
  158. package/src/pages/datasheet.tsx +1 -1
  159. package/src/pages/datasheets.tsx +3 -3
  160. package/src/pages/editor.tsx +4 -6
  161. package/src/pages/landing.tsx +6 -6
  162. package/src/pages/latest.tsx +3 -0
  163. package/src/pages/organization-profile.tsx +199 -0
  164. package/src/pages/organization-settings.tsx +569 -0
  165. package/src/pages/package-editor.tsx +21 -21
  166. package/src/pages/preview-release.tsx +75 -145
  167. package/src/pages/quickstart.tsx +159 -123
  168. package/src/pages/release-detail.tsx +119 -31
  169. package/src/pages/search.tsx +197 -57
  170. package/src/pages/settings-redirect.tsx +44 -0
  171. package/src/pages/trending.tsx +29 -20
  172. package/src/pages/user-profile.tsx +58 -7
  173. package/src/pages/user-settings.tsx +161 -0
  174. package/src/pages/view-package.tsx +30 -16
  175. package/vite.config.ts +9 -0
  176. package/fake-snippets-api/routes/api/autocomplete/create_autocomplete.ts +0 -133
  177. package/src/components/JLCPCBImportDialog.tsx +0 -280
  178. package/src/components/PackageBuildsPage/LogContent.tsx +0 -72
  179. package/src/components/PackageBuildsPage/PackageBuildDetailsPage.tsx +0 -113
  180. package/src/components/PackageBuildsPage/build-preview-content.tsx +0 -56
  181. package/src/components/PackageBuildsPage/collapsible-section.tsx +0 -63
  182. package/src/components/PackageBuildsPage/package-build-details-panel.tsx +0 -166
  183. package/src/components/PackageBuildsPage/package-build-header.tsx +0 -79
  184. package/src/components/PageSearchComponent.tsx +0 -148
  185. package/src/pages/package-builds.tsx +0 -33
@@ -25,6 +25,7 @@ import { CubeIcon } from "@radix-ui/react-icons"
25
25
  import { useState } from "react"
26
26
  import { useAxios } from "@/hooks/use-axios"
27
27
  import { useCurrentPackageId } from "@/hooks/use-current-package-id"
28
+ import { downloadStepFile } from "@/lib/download-fns/download-step"
28
29
 
29
30
  interface DownloadButtonAndMenuProps {
30
31
  className?: string
@@ -65,9 +66,8 @@ export function DownloadButtonAndMenu({
65
66
  return fetchedCircuitJson
66
67
  setIsFetchingCircuitJson(true)
67
68
  try {
68
- const { data } = await axios.post("/package_files/get", {
69
- package_id: packageId,
70
- file_path: "dist/circuit.json",
69
+ const { data } = await axios.get("/package_files/get", {
70
+ params: { package_id: packageId, file_path: "dist/circuit.json" },
71
71
  })
72
72
  const content = data?.package_file?.content_text
73
73
  if (!content) throw new Error("Circuit JSON not found")
@@ -108,7 +108,7 @@ export function DownloadButtonAndMenu({
108
108
  <DropdownMenuTrigger asChild>
109
109
  <Button
110
110
  size="sm"
111
- className="bg-white shadow-none text-gray-900 hover:bg-gray-100 border border-gray-300 px-1 pl-2"
111
+ className="bg-white shadow-none text-gray-900 hover:bg-gray-100 border border-gray-300 px-1 pl-2 select-none"
112
112
  >
113
113
  <Download className="w-4 h-4 mr-2" />
114
114
  Download
@@ -226,7 +226,19 @@ export function DownloadButtonAndMenu({
226
226
  kicad_*.zip
227
227
  </span>
228
228
  </DropdownMenuItem>
229
-
229
+ <DropdownMenuItem
230
+ className="text-xs"
231
+ onSelect={async () => {
232
+ const cj = await getCircuitJson()
233
+ downloadStepFile(cj, unscopedName || "step_file")
234
+ }}
235
+ >
236
+ <Download className="mr-1 h-3 w-3" />
237
+ <span className="flex-grow mr-6">Step Format</span>
238
+ <span className="text-[0.6rem] bg-emerald-500 opacity-80 text-white font-mono rounded-md px-1 text-center py-0.5 mr-1">
239
+ STEP
240
+ </span>
241
+ </DropdownMenuItem>
230
242
  <DropdownMenuItem
231
243
  className="text-xs"
232
244
  onSelect={async () => {
@@ -1,4 +1,4 @@
1
- import React, { useState } from "react"
1
+ import React, { useMemo, useState } from "react"
2
2
  import { cn } from "@/lib/utils"
3
3
  import { PanelRightOpen, Plus, Loader2 } from "lucide-react"
4
4
  import { TreeView } from "@/components/ui/tree-view"
@@ -42,6 +42,7 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
42
42
  handleRenameFile,
43
43
  isCreatingFile,
44
44
  setIsCreatingFile,
45
+ pkg,
45
46
  isLoadingFiles = true,
46
47
  loadingProgress = null,
47
48
  }) => {
@@ -52,10 +53,8 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
52
53
  const [selectedFolderForCreation, setSelectedFolderForCreation] = useState<
53
54
  string | null
54
55
  >(null)
55
- const [selectedItemId, setSelectedItemId] = React.useState<string>(
56
- currentFile || "",
57
- )
58
- const canModifyFiles = true
56
+ const selectedItemId = useMemo(() => currentFile || "", [currentFile])
57
+ const canModifyFiles = Boolean(pkg) && !isLoadingFiles
59
58
 
60
59
  const onFolderSelect = (folderPath: string) => {
61
60
  setSelectedFolderForCreation(folderPath)
@@ -137,7 +136,6 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
137
136
  setNewFileName("")
138
137
  setErrorMessage("")
139
138
  onFileSelect(finalFileName)
140
- setSelectedItemId(finalFileName)
141
139
  setSelectedFolderForCreation(null)
142
140
  }
143
141
  }
@@ -169,7 +167,7 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
169
167
  className,
170
168
  )}
171
169
  >
172
- <div className="flex items-center justify-between px-2 pt-2">
170
+ <div className="flex items-center justify-between px-2 py-2">
173
171
  <button
174
172
  onClick={toggleSidebar}
175
173
  className={`text-gray-400 scale-90 transition-opacity duration-200 ${!sidebarOpen ? "opacity-0 pointer-events-none" : "opacity-100"}`}
@@ -250,18 +248,14 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
250
248
  </div>
251
249
  </div>
252
250
  )}
253
- <div
254
- onClick={(e) => {
255
- if (e.target === e.currentTarget) {
256
- setSelectedFolderForCreation(null)
257
- setSelectedItemId("")
258
- }
259
- }}
260
- className="flex-1 border-2 h-full"
261
- >
251
+ <div className="flex-1 border-t h-full">
262
252
  <TreeView
263
253
  data={treeData}
264
- setSelectedItemId={(value) => setSelectedItemId(value || "")}
254
+ setSelectedItemId={(value) => {
255
+ if (value && files[value]) {
256
+ onFileSelect(value)
257
+ }
258
+ }}
265
259
  selectedItemId={selectedItemId}
266
260
  onSelectChange={(item) => {
267
261
  if (item?.onClick) {
@@ -1,7 +1,6 @@
1
1
  import { useGlobalStore } from "@/hooks/use-global-store"
2
2
  import { CircuitBoard } from "lucide-react"
3
3
  import { Link } from "wouter"
4
- import { PrefetchPageLink } from "./PrefetchPageLink"
5
4
 
6
5
  export default function Footer() {
7
6
  const session = useGlobalStore((s) => s.session)
@@ -34,13 +33,13 @@ export default function Footer() {
34
33
  ]
35
34
  .filter((item) => !item.hidden)
36
35
  .map((item) => (
37
- <PrefetchPageLink
36
+ <Link
38
37
  key={item.name}
39
38
  href={item.href}
40
39
  className="hover:underline"
41
40
  >
42
41
  {item.name}
43
- </PrefetchPageLink>
42
+ </Link>
44
43
  ))}
45
44
  <a
46
45
  href="https://chat.tscircuit.com"
@@ -55,15 +54,15 @@ export default function Footer() {
55
54
  <div className="space-y-4">
56
55
  <h3 className="font-semibold uppercase">Explore</h3>
57
56
  <footer className="flex flex-col space-y-2">
58
- <PrefetchPageLink href="/latest" className="hover:underline">
57
+ <Link href="/latest" className="hover:underline">
59
58
  Latest Packages
60
- </PrefetchPageLink>
61
- <PrefetchPageLink href="/trending" className="hover:underline">
59
+ </Link>
60
+ <Link href="/trending" className="hover:underline">
62
61
  Trending Packages
63
- </PrefetchPageLink>
64
- <PrefetchPageLink href="/search" className="hover:underline">
62
+ </Link>
63
+ <Link href="/search" className="hover:underline">
65
64
  Search Packages
66
- </PrefetchPageLink>
65
+ </Link>
67
66
  <a href="https://docs.tscircuit.com" className="hover:underline">
68
67
  Docs
69
68
  </a>
@@ -6,7 +6,7 @@ import { GitHubLogoIcon, DiscordLogoIcon } from "@radix-ui/react-icons"
6
6
  import { Menu, X } from "lucide-react"
7
7
  import React, { useEffect, useState } from "react"
8
8
  import { useLocation } from "wouter"
9
- import { PrefetchPageLink } from "./PrefetchPageLink"
9
+ import { Link } from "wouter"
10
10
  import CmdKMenu from "./CmdKMenu"
11
11
  import HeaderDropdown from "./HeaderDropdown"
12
12
  import SearchComponent from "./SearchComponent"
@@ -27,23 +27,23 @@ const HeaderButton = ({
27
27
 
28
28
  if (location === href || location === alsoHighlightForUrl) {
29
29
  return (
30
- <PrefetchPageLink className={cn("header-button", className)} href={href}>
30
+ <Link className={cn("header-button", className)} href={href}>
31
31
  <Button
32
32
  variant="ghost"
33
33
  className={`border-b-2 rounded-none border-blue-600 header-button ${className}`}
34
34
  >
35
35
  {children}
36
36
  </Button>
37
- </PrefetchPageLink>
37
+ </Link>
38
38
  )
39
39
  }
40
40
 
41
41
  return (
42
- <PrefetchPageLink className={cn("header-button", className)} href={href}>
42
+ <Link className={cn("header-button", className)} href={href}>
43
43
  <Button className={className} variant="ghost">
44
44
  {children}
45
45
  </Button>
46
- </PrefetchPageLink>
46
+ </Link>
47
47
  )
48
48
  }
49
49
 
@@ -59,14 +59,14 @@ export default function Header() {
59
59
  return (
60
60
  <header className="px-4 py-3">
61
61
  <div className="flex items-center">
62
- <PrefetchPageLink
62
+ <Link
63
63
  href="/"
64
- className="text-lg font-semibold whitespace-nowrap"
64
+ className="text-lg font-semibold whitespace-nowrap select-none"
65
65
  >
66
66
  <span className="bg-blue-500 px-2 py-1 rounded-md text-white">
67
67
  tscircuit
68
68
  </span>
69
- </PrefetchPageLink>
69
+ </Link>
70
70
  <div className="hidden md:flex items-center space-x-4">
71
71
  <nav>
72
72
  <ul className="flex items-center gap-2 ml-2">
@@ -80,9 +80,6 @@ export default function Header() {
80
80
  Editor
81
81
  </HeaderButton>
82
82
  </li>
83
- <li>
84
- <HeaderButton href="/datasheets">Datasheets</HeaderButton>
85
- </li>
86
83
  <li>
87
84
  <a href="https://chat.tscircuit.com">
88
85
  <Button variant="ghost">AI</Button>
@@ -93,28 +90,26 @@ export default function Header() {
93
90
  <Button variant="ghost">Docs</Button>
94
91
  </a>
95
92
  </li>
96
- <li>
97
- <a
98
- href="https://tscircuit.com/join"
99
- target="_blank"
100
- className="mr-2"
101
- >
102
- <Button variant="ghost">
103
- <DiscordLogoIcon className="text-gray-400 hover:text-gray-600 transition-colors w-4 h-4" />
104
- </Button>
105
- </a>
106
- </li>
107
93
  </ul>
108
94
  </nav>
109
95
  </div>
110
96
  <div className="flex-grow"></div>
97
+ <a
98
+ href="https://tscircuit.com/join"
99
+ target="_blank"
100
+ className="lg:mr-2"
101
+ >
102
+ <Button variant="ghost">
103
+ <DiscordLogoIcon className="text-gray-400 hidden lg:block hover:text-gray-600 transition-colors w-4 h-4" />
104
+ </Button>
105
+ </a>
111
106
  <a
112
107
  href="https://github.com/tscircuit/tscircuit"
113
108
  target="_blank"
114
- className="mr-4"
109
+ className="lg:mr-4"
115
110
  aria-label="View TSCircuit on GitHub"
116
111
  >
117
- <GitHubLogoIcon className="text-gray-400 hover:text-gray-600 transition-colors" />
112
+ <GitHubLogoIcon className="hidden lg:block text-gray-400 hover:text-gray-600 transition-colors" />
118
113
  </a>
119
114
  {/* <a href="https://tscircuit.com/join" target="_blank" className="mr-2">
120
115
  <DiscordLogoIcon className="text-gray-400 hover:text-gray-600 transition-colors" />
@@ -155,14 +150,6 @@ export default function Header() {
155
150
  Editor
156
151
  </HeaderButton>
157
152
  </li>
158
- <li>
159
- <HeaderButton
160
- className="w-full justify-start"
161
- href="/datasheets"
162
- >
163
- Datasheets
164
- </HeaderButton>
165
- </li>
166
153
  <li>
167
154
  <HeaderButton
168
155
  className="w-full justify-start"
@@ -1,7 +1,6 @@
1
1
  import { Button } from "@/components/ui/button"
2
- import { CircuitBoard, Search, Menu, X } from "lucide-react"
2
+ import { Search, Menu, X } from "lucide-react"
3
3
  import { Link } from "wouter"
4
- import { PrefetchPageLink } from "./PrefetchPageLink"
5
4
  import { HeaderLogin } from "./HeaderLogin"
6
5
  import SearchComponent from "./SearchComponent"
7
6
  import HeaderDropdown from "./HeaderDropdown"
@@ -60,36 +59,28 @@ export const Header2 = () => {
60
59
  <>
61
60
  <header className="sticky top-0 z-50 w-full border-b bg-white md:bg-white/80 md:backdrop-blur supports-[backdrop-filter]:md:bg-white/60">
62
61
  <div className="container mx-auto flex h-16 items-center justify-between px-2 md:px-6">
63
- <PrefetchPageLink
64
- href="/"
65
- className="flex select-none items-center gap-2"
66
- >
67
- <CircuitBoard className="h-6 w-6" />
68
- <span className="text-lg font-bold">tscircuit</span>
69
- </PrefetchPageLink>
62
+ <Link href="/" className="flex select-none items-center">
63
+ <span className="bg-blue-500 px-2 py-1 rounded-md text-white text-sm font-semibold sm:text-base">
64
+ tscircuit
65
+ </span>
66
+ </Link>
70
67
 
71
68
  {/* Desktop Navigation */}
72
69
  <nav className="hidden md:flex gap-6">
73
70
  {isLoggedIn && (
74
- <PrefetchPageLink
71
+ <Link
75
72
  className="text-sm font-medium hover:underline underline-offset-4"
76
73
  href="/dashboard"
77
74
  >
78
75
  Dashboard
79
- </PrefetchPageLink>
76
+ </Link>
80
77
  )}
81
- <PrefetchPageLink
78
+ <Link
82
79
  className="text-sm font-medium hover:underline underline-offset-4"
83
80
  href="/quickstart"
84
81
  >
85
82
  Editor
86
- </PrefetchPageLink>
87
- <PrefetchPageLink
88
- className="text-sm font-medium hover:underline underline-offset-4"
89
- href="/datasheets"
90
- >
91
- Datasheets
92
- </PrefetchPageLink>
83
+ </Link>
93
84
  <a
94
85
  className="text-sm font-medium hover:underline underline-offset-4"
95
86
  href="https://docs.tscircuit.com"
@@ -131,11 +122,11 @@ export const Header2 = () => {
131
122
  {isLoggedIn ? (
132
123
  <HeaderLogin />
133
124
  ) : (
134
- <PrefetchPageLink href="/quickstart">
125
+ <Link href="/quickstart">
135
126
  <Button size="sm" className="text-xs px-3 py-1">
136
127
  Get Started
137
128
  </Button>
138
- </PrefetchPageLink>
129
+ </Link>
139
130
  )}
140
131
  <button
141
132
  className="p-2"
@@ -154,28 +145,21 @@ export const Header2 = () => {
154
145
  <nav className="mb-4">
155
146
  <div className="flex flex-col items-center gap-1">
156
147
  {isLoggedIn && (
157
- <PrefetchPageLink
148
+ <Link
158
149
  className="text-sm font-medium hover:underline underline-offset-4 py-2 w-full text-center"
159
150
  href="/dashboard"
160
151
  onClick={() => setMobileMenuOpen(false)}
161
152
  >
162
153
  Dashboard
163
- </PrefetchPageLink>
154
+ </Link>
164
155
  )}
165
- <PrefetchPageLink
156
+ <Link
166
157
  className="text-sm font-medium hover:underline underline-offset-4 py-2 w-full text-center"
167
158
  href="/quickstart"
168
159
  onClick={() => setMobileMenuOpen(false)}
169
160
  >
170
161
  Editor
171
- </PrefetchPageLink>
172
- <PrefetchPageLink
173
- className="text-sm font-medium hover:underline underline-offset-4 py-2 w-full text-center"
174
- href="/datasheets"
175
- onClick={() => setMobileMenuOpen(false)}
176
- >
177
- Datasheets
178
- </PrefetchPageLink>
162
+ </Link>
179
163
  <a
180
164
  className="text-sm font-medium hover:underline underline-offset-4 py-2 w-full text-center"
181
165
  href="https://docs.tscircuit.com"
@@ -1,3 +1,4 @@
1
+ import { useState } from "react"
1
2
  import { Button } from "@/components/ui/button"
2
3
  import {
3
4
  DropdownMenu,
@@ -7,9 +8,10 @@ import {
7
8
  } from "@/components/ui/dropdown-menu"
8
9
  import { cn } from "@/lib/utils"
9
10
  import { ChevronDown, FileUp, Upload, Zap } from "lucide-react"
10
- import { PrefetchPageLink } from "./PrefetchPageLink"
11
+ import { Link } from "wouter"
11
12
 
12
13
  export default function HeaderDropdown() {
14
+ const [open, setOpen] = useState(false)
13
15
  const blankTemplates = [
14
16
  { name: "Blank Circuit Board", type: "board", badgeColor: "bg-blue-500" },
15
17
  {
@@ -32,7 +34,7 @@ export default function HeaderDropdown() {
32
34
  ]
33
35
 
34
36
  return (
35
- <DropdownMenu>
37
+ <DropdownMenu open={open} onOpenChange={setOpen}>
36
38
  <DropdownMenuTrigger asChild>
37
39
  <Button
38
40
  size="sm"
@@ -44,38 +46,41 @@ export default function HeaderDropdown() {
44
46
  </DropdownMenuTrigger>
45
47
  <DropdownMenuContent className="w-fit">
46
48
  <DropdownMenuItem asChild>
47
- <PrefetchPageLink
49
+ <Link
48
50
  href="/quickstart"
49
51
  className="flex items-center cursor-pointer"
52
+ onClick={() => setOpen(false)}
50
53
  >
51
54
  <Zap className="mr-2 h-3 w-3" />
52
55
  Quickstart Templates
53
- </PrefetchPageLink>
56
+ </Link>
54
57
  </DropdownMenuItem>
55
58
  {blankTemplates.map((template, index) => (
56
59
  <DropdownMenuItem key={index} asChild disabled={template.disabled}>
57
- <a
60
+ <Link
58
61
  href={`/editor?template=${template.name.toLowerCase().replace(/ /g, "-")}`}
59
62
  className={cn(
60
63
  "flex items-center cursor-pointer",
61
64
  template.disabled && "opacity-50 cursor-not-allowed",
62
65
  )}
66
+ onClick={() => !template.disabled && setOpen(false)}
63
67
  >
64
68
  <span
65
69
  className={`w-2 h-2 rounded-full mr-2 ${template.badgeColor}`}
66
70
  />
67
71
  {template.name}
68
- </a>
72
+ </Link>
69
73
  </DropdownMenuItem>
70
74
  ))}
71
75
  <DropdownMenuItem asChild>
72
- <PrefetchPageLink
76
+ <Link
73
77
  href="/quickstart"
74
78
  className="flex items-center cursor-pointer"
79
+ onClick={() => setOpen(false)}
75
80
  >
76
81
  <Upload className="mr-2 h-3 w-3" />
77
82
  Import Part
78
- </PrefetchPageLink>
83
+ </Link>
79
84
  </DropdownMenuItem>
80
85
  </DropdownMenuContent>
81
86
  </DropdownMenu>
@@ -1,4 +1,3 @@
1
- import React from "react"
2
1
  import { Button } from "@/components/ui/button"
3
2
  import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
4
3
  import {
@@ -9,15 +8,16 @@ import {
9
8
  } from "@/components/ui/dropdown-menu"
10
9
  import { User } from "lucide-react"
11
10
  import { useGlobalStore } from "@/hooks/use-global-store"
12
- import { useAccountBalance } from "@/hooks/use-account-balance"
13
11
  import { useSignIn } from "@/hooks/use-sign-in"
12
+ import { Link } from "wouter"
13
+ import { useState } from "react"
14
14
 
15
15
  export const HeaderLogin = () => {
16
16
  const session = useGlobalStore((s) => s.session)
17
17
  const isLoggedIn = Boolean(session)
18
18
  const setSession = useGlobalStore((s) => s.setSession)
19
19
  const signIn = useSignIn()
20
- const { data: accountBalance } = useAccountBalance()
20
+ const [isOpen, setIsOpen] = useState(false)
21
21
 
22
22
  if (!isLoggedIn) {
23
23
  return (
@@ -31,7 +31,7 @@ export const HeaderLogin = () => {
31
31
  }
32
32
 
33
33
  return (
34
- <DropdownMenu>
34
+ <DropdownMenu open={isOpen} onOpenChange={setIsOpen}>
35
35
  <DropdownMenuTrigger asChild>
36
36
  <Avatar className="w-8 h-8 login-avatar">
37
37
  <AvatarImage
@@ -44,32 +44,60 @@ export const HeaderLogin = () => {
44
44
  </Avatar>
45
45
  </DropdownMenuTrigger>
46
46
  <DropdownMenuContent className="ml-1 mr-1 md:ml-0 md:mr-1">
47
- <DropdownMenuItem asChild className="text-gray-500 text-xs" disabled>
47
+ {/* <DropdownMenuItem asChild className="text-gray-500 text-xs" disabled>
48
48
  <div>
49
49
  AI Usage $
50
50
  {accountBalance?.monthly_ai_budget_used_usd.toFixed(2) ?? "0.00"} /
51
51
  $5.00
52
52
  </div>
53
- </DropdownMenuItem>
53
+ </DropdownMenuItem> */}
54
54
  <DropdownMenuItem asChild>
55
- <a href={`/${session?.github_username}`} className="cursor-pointer">
55
+ <Link
56
+ href={`/${session?.github_username}`}
57
+ className="cursor-pointer"
58
+ onClick={() => setIsOpen(false)}
59
+ >
56
60
  My Profile
57
- </a>
61
+ </Link>
58
62
  </DropdownMenuItem>
59
63
  <DropdownMenuItem asChild>
60
- <a href="/dashboard" className="cursor-pointer">
64
+ <Link
65
+ href="/dashboard"
66
+ className="cursor-pointer"
67
+ onClick={() => setIsOpen(false)}
68
+ >
61
69
  Dashboard
62
- </a>
70
+ </Link>
63
71
  </DropdownMenuItem>
64
72
  <DropdownMenuItem asChild>
65
- <a href="/settings" className="cursor-pointer">
73
+ <Link
74
+ href={`/${session?.github_username}/settings`}
75
+ className="cursor-pointer"
76
+ onClick={() => setIsOpen(false)}
77
+ >
66
78
  Settings
67
- </a>
79
+ </Link>
80
+ </DropdownMenuItem>
81
+ <DropdownMenuItem asChild>
82
+ <Link
83
+ href="/orgs/new"
84
+ className="cursor-pointer"
85
+ onClick={() => setIsOpen(false)}
86
+ >
87
+ Create Organization
88
+ </Link>
68
89
  </DropdownMenuItem>
69
- <DropdownMenuItem asChild onClick={() => setSession(null)}>
70
- <a href="/" className="cursor-pointer">
90
+ <DropdownMenuItem asChild>
91
+ <Link
92
+ href="/"
93
+ className="cursor-pointer"
94
+ onClick={() => {
95
+ setSession(null)
96
+ setIsOpen(false)
97
+ }}
98
+ >
71
99
  Sign Out
72
- </a>
100
+ </Link>
73
101
  </DropdownMenuItem>
74
102
  </DropdownMenuContent>
75
103
  </DropdownMenu>
@@ -1,5 +1,5 @@
1
1
  import { Button } from "@/components/ui/button"
2
- import { PrefetchPageLink } from "@/components/PrefetchPageLink"
2
+ import { Link } from "wouter"
3
3
 
4
4
  export function NotFound({ heading = "Page not found" }: { heading?: string }) {
5
5
  return (
@@ -20,16 +20,16 @@ export function NotFound({ heading = "Page not found" }: { heading?: string }) {
20
20
  address.
21
21
  </p>
22
22
  <div className="flex flex-col sm:flex-row gap-4">
23
- <PrefetchPageLink href="/">
23
+ <Link href="/">
24
24
  <Button size="lg" className="bg-blue-500 hover:bg-blue-600">
25
25
  Return Home
26
26
  </Button>
27
- </PrefetchPageLink>
28
- <PrefetchPageLink href="/search">
27
+ </Link>
28
+ <Link href="/search">
29
29
  <Button size="lg" variant="outline">
30
30
  Search Packages
31
31
  </Button>
32
- </PrefetchPageLink>
32
+ </Link>
33
33
  </div>
34
34
  </div>
35
35
  </section>
@@ -1,4 +1,4 @@
1
- import { PrefetchPageLink } from "@/components/PrefetchPageLink"
1
+ import { Link } from "wouter"
2
2
  import {
3
3
  Breadcrumb,
4
4
  BreadcrumbList,
@@ -29,7 +29,7 @@ export function PackageBreadcrumb({
29
29
  {/* Author */}
30
30
  <BreadcrumbItem>
31
31
  <BreadcrumbLink asChild>
32
- <PrefetchPageLink href={`/${author}`}>{author}</PrefetchPageLink>
32
+ <Link href={`/${author}`}>{author}</Link>
33
33
  </BreadcrumbLink>
34
34
  </BreadcrumbItem>
35
35
  <BreadcrumbSeparator>
@@ -39,9 +39,7 @@ export function PackageBreadcrumb({
39
39
  {/* Package */}
40
40
  <BreadcrumbItem>
41
41
  <BreadcrumbLink asChild>
42
- <PrefetchPageLink href={`/${packageName}`}>
43
- {unscopedName || packageName}
44
- </PrefetchPageLink>
42
+ <Link href={`/${packageName}`}>{unscopedName || packageName}</Link>
45
43
  </BreadcrumbLink>
46
44
  </BreadcrumbItem>
47
45
  <BreadcrumbSeparator>
@@ -58,9 +56,7 @@ export function PackageBreadcrumb({
58
56
  <BreadcrumbPage>releases</BreadcrumbPage>
59
57
  ) : (
60
58
  <BreadcrumbLink asChild>
61
- <PrefetchPageLink href={`/${packageName}/releases`}>
62
- releases
63
- </PrefetchPageLink>
59
+ <Link href={`/${packageName}/releases`}>releases</Link>
64
60
  </BreadcrumbLink>
65
61
  )}
66
62
  </BreadcrumbItem>
@@ -76,11 +72,9 @@ export function PackageBreadcrumb({
76
72
  <BreadcrumbItem>
77
73
  {currentPage === "builds" ? (
78
74
  <BreadcrumbLink asChild>
79
- <PrefetchPageLink
80
- href={`/${packageName}/releases/${releaseVersion}`}
81
- >
75
+ <Link href={`/${packageName}/releases/${releaseVersion}`}>
82
76
  {releaseVersion}
83
- </PrefetchPageLink>
77
+ </Link>
84
78
  </BreadcrumbLink>
85
79
  ) : (
86
80
  <BreadcrumbPage>{releaseVersion}</BreadcrumbPage>
@@ -28,7 +28,7 @@ const PackageGrid = ({
28
28
  </div>
29
29
  )
30
30
 
31
- const LoadingState = () => (
31
+ export const LoadingState = () => (
32
32
  <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
33
33
  {[...Array(6)].map((_, i) => (
34
34
  <PackageCardSkeleton key={i} />
@@ -101,7 +101,13 @@ export const PrefetchPageLink = ({
101
101
  }, [inView, href])
102
102
 
103
103
  return (
104
- <Link {...props} href={href} className={className} ref={ref}>
104
+ <Link
105
+ {...props}
106
+ href={href}
107
+ className={className}
108
+ draggable={false}
109
+ ref={ref}
110
+ >
105
111
  {children}
106
112
  </Link>
107
113
  )