@tscircuit/fake-snippets 0.0.1

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 (396) hide show
  1. package/.github/CODEOWNERS +1 -0
  2. package/.github/workflows/bun-formatcheck.yml +26 -0
  3. package/.github/workflows/bun-test.yml +28 -0
  4. package/.github/workflows/bun-typecheck.yml +26 -0
  5. package/.github/workflows/bundle-size-analysis.yml +79 -0
  6. package/.github/workflows/playwright-test.yml +37 -0
  7. package/.github/workflows/stale.yml +40 -0
  8. package/.github/workflows/update-snapshots.yml +49 -0
  9. package/CONTRIBUTING.md +59 -0
  10. package/LICENSE +21 -0
  11. package/README.md +113 -0
  12. package/biome.json +60 -0
  13. package/bun-tests/fake-snippets-api/fixtures/get-circuit-json.ts +148 -0
  14. package/bun-tests/fake-snippets-api/fixtures/get-test-server.ts +96 -0
  15. package/bun-tests/fake-snippets-api/fixtures/start-server.ts +44 -0
  16. package/bun-tests/fake-snippets-api/routes/accounts/get_account_balance.test.ts +18 -0
  17. package/bun-tests/fake-snippets-api/routes/health.test.ts +9 -0
  18. package/bun-tests/fake-snippets-api/routes/order_files/get.test.ts +48 -0
  19. package/bun-tests/fake-snippets-api/routes/order_files/upload.test.ts +77 -0
  20. package/bun-tests/fake-snippets-api/routes/orders/create.test.ts +19 -0
  21. package/bun-tests/fake-snippets-api/routes/orders/get.test.ts +38 -0
  22. package/bun-tests/fake-snippets-api/routes/orders/list.test.ts +30 -0
  23. package/bun-tests/fake-snippets-api/routes/orders/update.test.ts +46 -0
  24. package/bun-tests/fake-snippets-api/routes/snippets/add_star.test.ts +114 -0
  25. package/bun-tests/fake-snippets-api/routes/snippets/create.test.ts +28 -0
  26. package/bun-tests/fake-snippets-api/routes/snippets/delete.test.ts +106 -0
  27. package/bun-tests/fake-snippets-api/routes/snippets/download.test.ts +90 -0
  28. package/bun-tests/fake-snippets-api/routes/snippets/generate_from_jlcpcb.test.ts +25 -0
  29. package/bun-tests/fake-snippets-api/routes/snippets/get_image.test.ts +113 -0
  30. package/bun-tests/fake-snippets-api/routes/snippets/images.test.ts +112 -0
  31. package/bun-tests/fake-snippets-api/routes/snippets/list.test.ts +62 -0
  32. package/bun-tests/fake-snippets-api/routes/snippets/list_newest.test.ts +48 -0
  33. package/bun-tests/fake-snippets-api/routes/snippets/list_trending.test.ts +69 -0
  34. package/bun-tests/fake-snippets-api/routes/snippets/remove_star.test.ts +110 -0
  35. package/bun-tests/fake-snippets-api/routes/snippets/search.test.ts +75 -0
  36. package/bun-tests/fake-snippets-api/routes/snippets/star-count.test.ts +44 -0
  37. package/bun-tests/fake-snippets-api/routes/snippets/update.test.ts +116 -0
  38. package/bun-tests/parts-engine.test.ts +18 -0
  39. package/bun.lockb +0 -0
  40. package/bunfig.toml +2 -0
  41. package/components.json +20 -0
  42. package/dist/assets/editor_example_1-1000w.webp +0 -0
  43. package/dist/assets/editor_example_1-1200w.webp +0 -0
  44. package/dist/assets/editor_example_1-1600w.webp +0 -0
  45. package/dist/assets/editor_example_1-2000w.webp +0 -0
  46. package/dist/assets/editor_example_1-400w.webp +0 -0
  47. package/dist/assets/editor_example_1-600w.webp +0 -0
  48. package/dist/assets/editor_example_1-800w.webp +0 -0
  49. package/dist/assets/editor_example_1_more_square-1000w.webp +0 -0
  50. package/dist/assets/editor_example_1_more_square-1200w.webp +0 -0
  51. package/dist/assets/editor_example_1_more_square-1600w.webp +0 -0
  52. package/dist/assets/editor_example_1_more_square-2000w.webp +0 -0
  53. package/dist/assets/editor_example_1_more_square-400w.webp +0 -0
  54. package/dist/assets/editor_example_1_more_square-600w.webp +0 -0
  55. package/dist/assets/editor_example_1_more_square-800w.webp +0 -0
  56. package/dist/assets/editor_example_2-1000w.webp +0 -0
  57. package/dist/assets/editor_example_2-1200w.webp +0 -0
  58. package/dist/assets/editor_example_2-1600w.webp +0 -0
  59. package/dist/assets/editor_example_2-2000w.webp +0 -0
  60. package/dist/assets/editor_example_2-400w.webp +0 -0
  61. package/dist/assets/editor_example_2-600w.webp +0 -0
  62. package/dist/assets/editor_example_2-800w.webp +0 -0
  63. package/dist/assets/example_schematic-1000w.webp +0 -0
  64. package/dist/assets/example_schematic-1200w.webp +0 -0
  65. package/dist/assets/example_schematic-1600w.webp +0 -0
  66. package/dist/assets/example_schematic-2000w.webp +0 -0
  67. package/dist/assets/example_schematic-400w.webp +0 -0
  68. package/dist/assets/example_schematic-600w.webp +0 -0
  69. package/dist/assets/example_schematic-800w.webp +0 -0
  70. package/dist/bundle.js +3270 -0
  71. package/dist/robots.txt +9 -0
  72. package/dist/sitemap.xml +118 -0
  73. package/docs/CIRCUIT_JSON_SOURCE_COMPONENT_OVERVIEW.md +151 -0
  74. package/fake-snippets-api/README.md +6 -0
  75. package/fake-snippets-api/biome.json +47 -0
  76. package/fake-snippets-api/bun.lockb +0 -0
  77. package/fake-snippets-api/lib/db/autoload-dev-snippets.ts +84 -0
  78. package/fake-snippets-api/lib/db/autoload-snippets.json +24 -0
  79. package/fake-snippets-api/lib/db/db-client.ts +343 -0
  80. package/fake-snippets-api/lib/db/schema.ts +112 -0
  81. package/fake-snippets-api/lib/db/seed.ts +1608 -0
  82. package/fake-snippets-api/lib/middleware/with-ctx-error.ts +26 -0
  83. package/fake-snippets-api/lib/middleware/with-db.ts +15 -0
  84. package/fake-snippets-api/lib/middleware/with-error-handling.ts +24 -0
  85. package/fake-snippets-api/lib/middleware/with-optional-session-auth.ts +34 -0
  86. package/fake-snippets-api/lib/middleware/with-request-logging.ts +54 -0
  87. package/fake-snippets-api/lib/middleware/with-session-auth.ts +39 -0
  88. package/fake-snippets-api/lib/middleware/with-winter-spec.ts +24 -0
  89. package/fake-snippets-api/next-env.d.ts +5 -0
  90. package/fake-snippets-api/routes/api/accounts/get.ts +21 -0
  91. package/fake-snippets-api/routes/api/accounts/get_account_balance.ts +22 -0
  92. package/fake-snippets-api/routes/api/accounts/update.ts +32 -0
  93. package/fake-snippets-api/routes/api/ai/[...anyroute].ts +31 -0
  94. package/fake-snippets-api/routes/api/ai.ts +2 -0
  95. package/fake-snippets-api/routes/api/aistream/[...anyroute].ts +65 -0
  96. package/fake-snippets-api/routes/api/health.ts +9 -0
  97. package/fake-snippets-api/routes/api/internal/sessions/create_without_auth.ts +63 -0
  98. package/fake-snippets-api/routes/api/order_files/get.ts +28 -0
  99. package/fake-snippets-api/routes/api/order_files/upload.ts +43 -0
  100. package/fake-snippets-api/routes/api/orders/create.ts +41 -0
  101. package/fake-snippets-api/routes/api/orders/get.ts +28 -0
  102. package/fake-snippets-api/routes/api/orders/list.ts +15 -0
  103. package/fake-snippets-api/routes/api/orders/update.ts +50 -0
  104. package/fake-snippets-api/routes/api/snippets/add_star.ts +42 -0
  105. package/fake-snippets-api/routes/api/snippets/create.ts +55 -0
  106. package/fake-snippets-api/routes/api/snippets/delete.ts +41 -0
  107. package/fake-snippets-api/routes/api/snippets/download.ts +148 -0
  108. package/fake-snippets-api/routes/api/snippets/generate_from_jlcpcb.ts +55 -0
  109. package/fake-snippets-api/routes/api/snippets/get.ts +50 -0
  110. package/fake-snippets-api/routes/api/snippets/get_image.ts +65 -0
  111. package/fake-snippets-api/routes/api/snippets/images/[author]/[snippet_name]/[typeFormat].ts +74 -0
  112. package/fake-snippets-api/routes/api/snippets/list.ts +28 -0
  113. package/fake-snippets-api/routes/api/snippets/list_newest.ts +13 -0
  114. package/fake-snippets-api/routes/api/snippets/list_trending.ts +21 -0
  115. package/fake-snippets-api/routes/api/snippets/remove_star.ts +42 -0
  116. package/fake-snippets-api/routes/api/snippets/search.ts +18 -0
  117. package/fake-snippets-api/routes/api/snippets/update.ts +86 -0
  118. package/favicon.ico +0 -0
  119. package/index.html +23 -0
  120. package/landing.html +23 -0
  121. package/package.json +164 -0
  122. package/playwright-tests/ai-page.spec.ts +19 -0
  123. package/playwright-tests/cmd-click.spec.ts +43 -0
  124. package/playwright-tests/dashboard-page.spec.ts +10 -0
  125. package/playwright-tests/editor-page.spec.ts +15 -0
  126. package/playwright-tests/files-dialog.spec.ts +19 -0
  127. package/playwright-tests/footprint-dialog/footprint-dialog.spec.ts +27 -0
  128. package/playwright-tests/footprint-dialog/footprint-insertion.spec.ts +38 -0
  129. package/playwright-tests/footprint-dialog/footprint-preview.spec.ts +34 -0
  130. package/playwright-tests/footprint-dialog/footprint-selection.spec.ts +29 -0
  131. package/playwright-tests/handle-manual-edits.spec.ts +55 -0
  132. package/playwright-tests/home-page.spec.ts +10 -0
  133. package/playwright-tests/images.spec.ts +17 -0
  134. package/playwright-tests/manual-edits.spec.ts +89 -0
  135. package/playwright-tests/preview-page.spec.ts +14 -0
  136. package/playwright-tests/quickstart-page.spec.ts +10 -0
  137. package/playwright-tests/search-links.spec.ts +21 -0
  138. package/playwright-tests/search.spec.ts +27 -0
  139. package/playwright-tests/snapshots/ai-page.spec.ts-AI-Page-lg.png +0 -0
  140. package/playwright-tests/snapshots/ai-page.spec.ts-AI-Page-md.png +0 -0
  141. package/playwright-tests/snapshots/ai-page.spec.ts-AI-Page-xs.png +0 -0
  142. package/playwright-tests/snapshots/cmd-click.spec.ts-underlined-imports.png +0 -0
  143. package/playwright-tests/snapshots/dashboard-page.spec.ts-Dashboard-page-lg.png +0 -0
  144. package/playwright-tests/snapshots/dashboard-page.spec.ts-Dashboard-page-md.png +0 -0
  145. package/playwright-tests/snapshots/dashboard-page.spec.ts-Dashboard-page-xs.png +0 -0
  146. package/playwright-tests/snapshots/editor-page.spec.ts-editor-with-snippet.png +0 -0
  147. package/playwright-tests/snapshots/error-fallback.spec.ts-error-fallback-lg.png +0 -0
  148. package/playwright-tests/snapshots/error-fallback.spec.ts-error-fallback-md.png +0 -0
  149. package/playwright-tests/snapshots/error-fallback.spec.ts-error-fallback-xs.png +0 -0
  150. package/playwright-tests/snapshots/files-dialog.spec.ts-view-snippet-files.png +0 -0
  151. package/playwright-tests/snapshots/footprint-dialog/footprint-dialog.spec.ts-footprint-preview-lg.png +0 -0
  152. package/playwright-tests/snapshots/footprint-dialog/footprint-dialog.spec.ts-footprint-preview-md.png +0 -0
  153. package/playwright-tests/snapshots/footprint-dialog/footprint-dialog.spec.ts-footprint-preview-xs.png +0 -0
  154. package/playwright-tests/snapshots/footprint-dialog/footprint-insertion.spec.ts-footprint-insertion-lg.png +0 -0
  155. package/playwright-tests/snapshots/footprint-dialog/footprint-insertion.spec.ts-footprint-insertion-md.png +0 -0
  156. package/playwright-tests/snapshots/footprint-dialog/footprint-insertion.spec.ts-footprint-insertion-xs.png +0 -0
  157. package/playwright-tests/snapshots/footprint-dialog/footprint-preview.spec.ts-footprint-preview-lg.png +0 -0
  158. package/playwright-tests/snapshots/footprint-dialog/footprint-preview.spec.ts-footprint-preview-md.png +0 -0
  159. package/playwright-tests/snapshots/footprint-dialog/footprint-preview.spec.ts-footprint-preview-xs.png +0 -0
  160. package/playwright-tests/snapshots/footprint-dialog/footprint-selection.spec.ts-footprint-preview-lg.png +0 -0
  161. package/playwright-tests/snapshots/footprint-dialog/footprint-selection.spec.ts-footprint-preview-md.png +0 -0
  162. package/playwright-tests/snapshots/footprint-dialog/footprint-selection.spec.ts-footprint-preview-xs.png +0 -0
  163. package/playwright-tests/snapshots/handle-manual-edits.spec.ts-handle-manual-edits.png +0 -0
  164. package/playwright-tests/snapshots/home-page.spec.ts-Home-page-lg.png +0 -0
  165. package/playwright-tests/snapshots/home-page.spec.ts-Home-page-md.png +0 -0
  166. package/playwright-tests/snapshots/home-page.spec.ts-Home-page-xs.png +0 -0
  167. package/playwright-tests/snapshots/images.spec.ts-pcb-image.png +0 -0
  168. package/playwright-tests/snapshots/images.spec.ts-schematic-image.png +0 -0
  169. package/playwright-tests/snapshots/manual-edits.spec.ts-editor-manual-edits.png +0 -0
  170. package/playwright-tests/snapshots/manual-edits.spec.ts-manual-edits-view.png +0 -0
  171. package/playwright-tests/snapshots/preview-page.spec.ts-preview-snippet-pcb.png +0 -0
  172. package/playwright-tests/snapshots/preview-page.spec.ts-preview-snippet-schematic.png +0 -0
  173. package/playwright-tests/snapshots/quickstart-page.spec.ts-Quickstart-Pagelg.png +0 -0
  174. package/playwright-tests/snapshots/quickstart-page.spec.ts-Quickstart-Pagemd.png +0 -0
  175. package/playwright-tests/snapshots/quickstart-page.spec.ts-Quickstart-Pagexs.png +0 -0
  176. package/playwright-tests/snapshots/search-links.spec.ts-search-links.png +0 -0
  177. package/playwright-tests/snapshots/search.spec.ts-search-lg.png +0 -0
  178. package/playwright-tests/snapshots/search.spec.ts-search-md.png +0 -0
  179. package/playwright-tests/snapshots/search.spec.ts-search-xs.png +0 -0
  180. package/playwright-tests/snapshots/star.spec.ts-remove-star-button.png +0 -0
  181. package/playwright-tests/snapshots/star.spec.ts-star-button.png +0 -0
  182. package/playwright-tests/snapshots/update-description.spec.ts-update-description.png +0 -0
  183. package/playwright-tests/snapshots/view-snippet.spec.ts-view-snippet-after-lg.png +0 -0
  184. package/playwright-tests/snapshots/view-snippet.spec.ts-view-snippet-after-md.png +0 -0
  185. package/playwright-tests/snapshots/view-snippet.spec.ts-view-snippet-after-xs.png +0 -0
  186. package/playwright-tests/snapshots/view-snippet.spec.ts-view-snippet-before-lg.png +0 -0
  187. package/playwright-tests/snapshots/view-snippet.spec.ts-view-snippet-before-md.png +0 -0
  188. package/playwright-tests/snapshots/view-snippet.spec.ts-view-snippet-before-xs.png +0 -0
  189. package/playwright-tests/snapshots/view-snippet.spec.ts-view-snippet-files.png +0 -0
  190. package/playwright-tests/star.spec.ts +40 -0
  191. package/playwright-tests/update-description.spec.ts +18 -0
  192. package/playwright-tests/view-snippet.spec.ts +35 -0
  193. package/playwright-tests/viewports.ts +5 -0
  194. package/playwright.config.ts +27 -0
  195. package/postcss.config.js +6 -0
  196. package/public/robots.txt +9 -0
  197. package/renovate.json +24 -0
  198. package/scripts/generate-image-sizes.ts +58 -0
  199. package/scripts/generate-sitemap.ts +103 -0
  200. package/scripts/generate_bundle_stats.js +192 -0
  201. package/scripts/snapshot.ts +35 -0
  202. package/src/App.tsx +113 -0
  203. package/src/ContextProviders.tsx +9 -0
  204. package/src/assets/originals/editor_example_1.webp +0 -0
  205. package/src/assets/originals/editor_example_1_more_square.webp +0 -0
  206. package/src/assets/originals/editor_example_2.webp +0 -0
  207. package/src/assets/originals/example_schematic.webp +0 -0
  208. package/src/components/AiChatInterface.tsx +221 -0
  209. package/src/components/AiChatMessage.tsx +86 -0
  210. package/src/components/Analytics.tsx +30 -0
  211. package/src/components/BomTable.tsx +69 -0
  212. package/src/components/ChatInput.tsx +53 -0
  213. package/src/components/CircuitToSvgWithMouseControl.tsx +78 -0
  214. package/src/components/CmdKMenu.tsx +301 -0
  215. package/src/components/CodeAndPreview.tsx +258 -0
  216. package/src/components/CodeEditor.tsx +460 -0
  217. package/src/components/CodeEditorHeader.tsx +160 -0
  218. package/src/components/CreateNewSnippetWithAiHero.tsx +77 -0
  219. package/src/components/DownloadButtonAndMenu.tsx +212 -0
  220. package/src/components/EditorNav.tsx +428 -0
  221. package/src/components/ErrorFallback.tsx +25 -0
  222. package/src/components/ErrorTabContent.tsx +122 -0
  223. package/src/components/FAQ.tsx +113 -0
  224. package/src/components/Footer.tsx +134 -0
  225. package/src/components/Footer2.tsx +100 -0
  226. package/src/components/FootprintDialog.tsx +342 -0
  227. package/src/components/Header.tsx +187 -0
  228. package/src/components/Header2.tsx +135 -0
  229. package/src/components/HeaderDropdown.tsx +83 -0
  230. package/src/components/HeaderLogin.tsx +94 -0
  231. package/src/components/JLCPCBImportDialog.tsx +155 -0
  232. package/src/components/LandingHero.tsx +175 -0
  233. package/src/components/LatestSnippets.tsx +39 -0
  234. package/src/components/OptimizedImage.tsx +96 -0
  235. package/src/components/OrderPreviewContent.tsx +61 -0
  236. package/src/components/ParametersEditor.tsx +140 -0
  237. package/src/components/PcbViewerWithContainerHeight.tsx +47 -0
  238. package/src/components/PrefetchPageLink.tsx +45 -0
  239. package/src/components/PreviewContent.tsx +375 -0
  240. package/src/components/PreviewEmptyState.tsx +16 -0
  241. package/src/components/RunButton.tsx +27 -0
  242. package/src/components/SearchComponent.tsx +163 -0
  243. package/src/components/ShippingInformationForm.tsx +423 -0
  244. package/src/components/SnippetLink.tsx +37 -0
  245. package/src/components/StaticPreviewContent.tsx +89 -0
  246. package/src/components/StaticViewSnippetHeader.tsx +70 -0
  247. package/src/components/StaticViewSnippetSidebar.tsx +100 -0
  248. package/src/components/TableViewer/CircuitJsonTableViewer.tsx +316 -0
  249. package/src/components/TableViewer/ClickableText.tsx +21 -0
  250. package/src/components/TableViewer/HeaderCell.tsx +27 -0
  251. package/src/components/TableViewer/Modal.tsx +39 -0
  252. package/src/components/TrendingSnippetCarousel.tsx +77 -0
  253. package/src/components/TypeBadge.tsx +31 -0
  254. package/src/components/ViewSnippetHeader.tsx +144 -0
  255. package/src/components/ViewSnippetSidebar.tsx +162 -0
  256. package/src/components/dialogs/confirm-delete-snippet-dialog.tsx +80 -0
  257. package/src/components/dialogs/create-order-dialog.tsx +146 -0
  258. package/src/components/dialogs/create-use-dialog.tsx +34 -0
  259. package/src/components/dialogs/edit-description-dialog.tsx +96 -0
  260. package/src/components/dialogs/files-dialog.tsx +70 -0
  261. package/src/components/dialogs/import-snippet-dialog.tsx +84 -0
  262. package/src/components/dialogs/rename-snippet-dialog.tsx +81 -0
  263. package/src/components/dialogs/view-ts-files-dialog.tsx +89 -0
  264. package/src/components/ui/accordion.tsx +55 -0
  265. package/src/components/ui/alert-dialog.tsx +139 -0
  266. package/src/components/ui/alert.tsx +59 -0
  267. package/src/components/ui/aspect-ratio.tsx +5 -0
  268. package/src/components/ui/avatar.tsx +48 -0
  269. package/src/components/ui/badge.tsx +36 -0
  270. package/src/components/ui/breadcrumb.tsx +118 -0
  271. package/src/components/ui/button.tsx +58 -0
  272. package/src/components/ui/calendar.tsx +73 -0
  273. package/src/components/ui/card.tsx +76 -0
  274. package/src/components/ui/carousel.tsx +260 -0
  275. package/src/components/ui/chart.tsx +363 -0
  276. package/src/components/ui/checkbox.tsx +28 -0
  277. package/src/components/ui/collapsible.tsx +9 -0
  278. package/src/components/ui/combobox.tsx +178 -0
  279. package/src/components/ui/command.tsx +151 -0
  280. package/src/components/ui/context-menu.tsx +202 -0
  281. package/src/components/ui/dialog.tsx +120 -0
  282. package/src/components/ui/drawer.tsx +116 -0
  283. package/src/components/ui/dropdown-menu.tsx +203 -0
  284. package/src/components/ui/form.tsx +182 -0
  285. package/src/components/ui/hover-card.tsx +27 -0
  286. package/src/components/ui/input-otp.tsx +69 -0
  287. package/src/components/ui/input.tsx +25 -0
  288. package/src/components/ui/label.tsx +24 -0
  289. package/src/components/ui/menubar.tsx +238 -0
  290. package/src/components/ui/navigation-menu.tsx +129 -0
  291. package/src/components/ui/pagination.tsx +121 -0
  292. package/src/components/ui/popover.tsx +31 -0
  293. package/src/components/ui/progress.tsx +26 -0
  294. package/src/components/ui/radio-group.tsx +42 -0
  295. package/src/components/ui/resizable.tsx +43 -0
  296. package/src/components/ui/scroll-area.tsx +46 -0
  297. package/src/components/ui/searchable-select.tsx +94 -0
  298. package/src/components/ui/select.tsx +162 -0
  299. package/src/components/ui/separator.tsx +29 -0
  300. package/src/components/ui/sheet.tsx +141 -0
  301. package/src/components/ui/skeleton.tsx +18 -0
  302. package/src/components/ui/slider.tsx +26 -0
  303. package/src/components/ui/sonner.tsx +30 -0
  304. package/src/components/ui/switch.tsx +27 -0
  305. package/src/components/ui/table.tsx +120 -0
  306. package/src/components/ui/tabs.tsx +53 -0
  307. package/src/components/ui/textarea.tsx +24 -0
  308. package/src/components/ui/toast.tsx +128 -0
  309. package/src/components/ui/toaster.tsx +33 -0
  310. package/src/components/ui/toggle-group.tsx +59 -0
  311. package/src/components/ui/toggle.tsx +43 -0
  312. package/src/components/ui/tooltip.tsx +28 -0
  313. package/src/entry-server.tsx +12 -0
  314. package/src/hooks/use-account-balance.ts +24 -0
  315. package/src/hooks/use-ai-api.ts +35 -0
  316. package/src/hooks/use-axios.ts +20 -0
  317. package/src/hooks/use-code-completion-ai-api.ts +11 -0
  318. package/src/hooks/use-compiled-tsx.ts +37 -0
  319. package/src/hooks/use-copy-to-clipboard.ts +26 -0
  320. package/src/hooks/use-create-snippet-mutation.ts +62 -0
  321. package/src/hooks/use-current-snippet-id.ts +75 -0
  322. package/src/hooks/use-current-snippet.ts +24 -0
  323. package/src/hooks/use-global-store.ts +33 -0
  324. package/src/hooks/use-is-using-fake-api.ts +3 -0
  325. package/src/hooks/use-run-tsx/construct-circuit.tsx +64 -0
  326. package/src/hooks/use-run-tsx/eval-compiled-js.ts +9 -0
  327. package/src/hooks/use-run-tsx/index.tsx +251 -0
  328. package/src/hooks/use-save-snippet.ts +66 -0
  329. package/src/hooks/use-sign-in.ts +22 -0
  330. package/src/hooks/use-snippet-by-name.ts +25 -0
  331. package/src/hooks/use-snippet.ts +23 -0
  332. package/src/hooks/use-snippets-base-api-url.ts +3 -0
  333. package/src/hooks/use-toast.tsx +208 -0
  334. package/src/hooks/use-typecheck.ts +54 -0
  335. package/src/hooks/use-url-params.ts +31 -0
  336. package/src/hooks/use-warn-user-on-page-change.ts +23 -0
  337. package/src/hooks/useForkSnippetMutation.ts +52 -0
  338. package/src/index.css +21 -0
  339. package/src/lib/__tests__/constants.test.ts +66 -0
  340. package/src/lib/base64ToBytes.ts +5 -0
  341. package/src/lib/bytesToBase64.ts +4 -0
  342. package/src/lib/codemirror/basic-setup.ts +51 -0
  343. package/src/lib/constants.ts +12 -0
  344. package/src/lib/decodeUrlHashToText.ts +15 -0
  345. package/src/lib/defaultCodeForBlankCode.tsx +7 -0
  346. package/src/lib/download-fns/createBlobURL.ts +4 -0
  347. package/src/lib/download-fns/download-assembly-svg.ts +12 -0
  348. package/src/lib/download-fns/download-circuit-json-fn.ts +12 -0
  349. package/src/lib/download-fns/download-dsn-file-fn.ts +12 -0
  350. package/src/lib/download-fns/download-fabrication-files.ts +233 -0
  351. package/src/lib/download-fns/download-gltf.ts +49 -0
  352. package/src/lib/download-fns/download-kicad-files.ts +27 -0
  353. package/src/lib/download-fns/download-readable-netlist.ts +12 -0
  354. package/src/lib/download-fns/download-schematic-svg.ts +12 -0
  355. package/src/lib/download-fns/download-simple-route-json.ts +17 -0
  356. package/src/lib/encodeTextToUrlHash.ts +17 -0
  357. package/src/lib/get-snippet-template.ts +26 -0
  358. package/src/lib/handleManualEditsImport.tsx +65 -0
  359. package/src/lib/jlc-parts-engine.ts +69 -0
  360. package/src/lib/templates/blank-3d-model-template.ts +12 -0
  361. package/src/lib/templates/blank-circuit-board-template.ts +24 -0
  362. package/src/lib/templates/blank-footprint-template.ts +29 -0
  363. package/src/lib/templates/blank-package-template.ts +22 -0
  364. package/src/lib/templates/blinking-led-board-template.ts +63 -0
  365. package/src/lib/templates/manual-edits-template.ts +5 -0
  366. package/src/lib/templates/usb-c-led-flashlight-template.ts +22 -0
  367. package/src/lib/utils/checkIfManualEditsImported.ts +6 -0
  368. package/src/lib/utils/getSyntaxError.ts +13 -0
  369. package/src/lib/utils/index.ts +6 -0
  370. package/src/lib/utils/load-prettier.ts +18 -0
  371. package/src/lib/utils/parseFootprintParams.ts +52 -0
  372. package/src/lib/utils/parseJsonOrNull.ts +8 -0
  373. package/src/lib/utils/pcbManualEditEventHandler.ts +156 -0
  374. package/src/main.tsx +10 -0
  375. package/src/pages/ai.tsx +92 -0
  376. package/src/pages/authorize.tsx +54 -0
  377. package/src/pages/dashboard.tsx +165 -0
  378. package/src/pages/dev-login.tsx +68 -0
  379. package/src/pages/editor.tsx +28 -0
  380. package/src/pages/landing.tsx +236 -0
  381. package/src/pages/my-orders.tsx +54 -0
  382. package/src/pages/newest.tsx +16 -0
  383. package/src/pages/preview.tsx +70 -0
  384. package/src/pages/quickstart.tsx +198 -0
  385. package/src/pages/search.tsx +26 -0
  386. package/src/pages/settings.tsx +25 -0
  387. package/src/pages/user-profile.tsx +97 -0
  388. package/src/pages/view-order.tsx +123 -0
  389. package/src/pages/view-snippet.tsx +149 -0
  390. package/src/prettier.ts +9 -0
  391. package/src/vite-env.d.ts +1 -0
  392. package/tailwind.config.js +47 -0
  393. package/tsconfig.json +30 -0
  394. package/vercel.json +50 -0
  395. package/vite.config.ts +146 -0
  396. package/winterspec.config.ts +6 -0
@@ -0,0 +1,342 @@
1
+ import { Input } from "./ui/input"
2
+ import { useEffect, useMemo, useState } from "react"
3
+ import { parseFootprintParams } from "../lib/utils/parseFootprintParams"
4
+ import ParametersEditor from "./ParametersEditor"
5
+ import { convertCircuitJsonToPcbSvg } from "circuit-to-svg"
6
+ import { fp } from "@tscircuit/footprinter"
7
+ import { useToast } from "../hooks/use-toast"
8
+ import { Button } from "./ui/button"
9
+ import { FileName } from "./CodeEditorHeader"
10
+ import {
11
+ Dialog,
12
+ DialogContent,
13
+ DialogDescription,
14
+ DialogHeader,
15
+ DialogTitle,
16
+ } from "./ui/dialog"
17
+ import { Copy, Check } from "lucide-react"
18
+ import { Combobox } from "./ui/combobox"
19
+
20
+ interface FootprintDialogProps {
21
+ currentFile: FileName
22
+ open: boolean
23
+ onOpenChange: (open: boolean) => void
24
+ updateFileContent: (filename: FileName, content: string) => void
25
+ files: Record<string, string>
26
+ cursorPosition?: number | null
27
+ }
28
+
29
+ const PARAM_NAMES: any = {
30
+ p: "Pitch",
31
+ w: "Width",
32
+ num_pins: "Number of Pins",
33
+ pl: "Pad Length",
34
+ pw: "Pad Width",
35
+ id: "Inner Diameter",
36
+ od: "Outer Diameter",
37
+ }
38
+
39
+ export const FootprintDialog = ({
40
+ currentFile,
41
+ open,
42
+ onOpenChange,
43
+ updateFileContent,
44
+ files,
45
+ cursorPosition,
46
+ }: FootprintDialogProps) => {
47
+ const [footprintString, setFootprintString] = useState("")
48
+ const [footprintName, setFootprintName] = useState("")
49
+ const [previewSvg, setPreviewSvg] = useState<string | null>(null)
50
+ const [chipName, setChipName] = useState("")
51
+ const [footprintNameError, setFootprintNameError] = useState(false)
52
+ const [copied, setCopied] = useState(false)
53
+ const [error, setError] = useState<string | null>(null)
54
+ const { toast } = useToast()
55
+
56
+ const PASSIVE_COMPONENTS = ["diode", "led", "resistor", "cap", "res"]
57
+ const footprintNames = fp
58
+ .getFootprintNames()
59
+ .filter((footprintName) => !PASSIVE_COMPONENTS.includes(footprintName))
60
+
61
+ useEffect(() => {
62
+ if (copied) {
63
+ const timeout = setTimeout(() => {
64
+ setCopied(false)
65
+ }, 1000)
66
+ return () => clearTimeout(timeout)
67
+ }
68
+ }, [copied])
69
+
70
+ const params: any = useMemo(() => {
71
+ try {
72
+ return fp.string(footprintString).json()
73
+ } catch (error) {
74
+ return null
75
+ }
76
+ }, [footprintName, footprintString])
77
+
78
+ const updateFootprintString = (baseName: string, currentParams: any) => {
79
+ try {
80
+ const parsedParams = parseFootprintParams(currentParams)
81
+
82
+ if (parsedParams.missing && Array.isArray(parsedParams.missing)) {
83
+ parsedParams.missing =
84
+ parsedParams.missing.length > 0
85
+ ? `missing(${parsedParams.missing.join(",")})`
86
+ : "missing()"
87
+ }
88
+
89
+ if (
90
+ parsedParams.grid === "0x0" ||
91
+ parsedParams.grid === "0x" ||
92
+ /^(\d+x0|0x\d+)$/.test(parsedParams.grid as string)
93
+ ) {
94
+ delete parsedParams.grid
95
+ }
96
+
97
+ const paramsString = Object.entries(parsedParams)
98
+ .filter(([key]) => key !== "fn" && key !== "num_pins")
99
+ .map(([key, val]) => {
100
+ if (typeof val === "boolean") return val ? key : ""
101
+ if (key === "missing") return val
102
+ return `${key}${val}`
103
+ })
104
+ .filter((item) => item !== "")
105
+ .join("_")
106
+
107
+ const newFootprintString = paramsString
108
+ ? `${baseName}_${paramsString}`
109
+ : baseName
110
+ setFootprintString(newFootprintString)
111
+ handleFootprintPreview(newFootprintString)
112
+ } catch (error) {
113
+ console.error("Error updating footprint string:", error)
114
+ }
115
+ }
116
+
117
+ const updateParam = (
118
+ paramName: string,
119
+ value: string | number | boolean | string[],
120
+ ) => {
121
+ try {
122
+ let currentParams = parseFootprintParams({ ...params })
123
+ if (paramName === "num_pins") {
124
+ if (Number(value) < 1) value = 1
125
+ if (Number(value) > 4000) value = 4000
126
+ const baseNameWithoutNumber = footprintName.replace(/\d+$/, "")
127
+ const newName = `${baseNameWithoutNumber}${value}`
128
+ updateFootprintString(newName, currentParams)
129
+ return
130
+ }
131
+
132
+ currentParams[paramName] = value
133
+ if (currentParams.missing && Array.isArray(currentParams.missing)) {
134
+ currentParams.missing =
135
+ currentParams.missing.length > 0
136
+ ? `missing(${currentParams.missing.join(",")})`
137
+ : "missing()"
138
+ }
139
+ currentParams = parseFootprintParams(currentParams)
140
+ const pinMatch = footprintString.match(/\d+(?=(_|$))/)
141
+ const pinNumber = pinMatch ? pinMatch[0] : ""
142
+ const baseNameWithoutNumber = footprintName.replace(/\d+$/, "")
143
+ const nameWithNumber = pinNumber
144
+ ? `${baseNameWithoutNumber}${pinNumber}`
145
+ : footprintName
146
+
147
+ updateFootprintString(nameWithNumber, currentParams)
148
+ } catch (error) {
149
+ console.error("Error updating parameter:", error)
150
+ }
151
+ }
152
+
153
+ const handleFootprintPreview = async (str: string) => {
154
+ try {
155
+ const circuitJson = fp.string(str).circuitJson()
156
+ const svg = convertCircuitJsonToPcbSvg(circuitJson)
157
+ setFootprintNameError(false)
158
+ setPreviewSvg(svg)
159
+ setError(null)
160
+ } catch (error) {
161
+ setFootprintNameError(true)
162
+ setPreviewSvg(null)
163
+ setError(
164
+ error instanceof Error
165
+ ? error.message
166
+ : "Invalid footprint configuration",
167
+ )
168
+ }
169
+ }
170
+
171
+ const handleInsertFootprint = () => {
172
+ try {
173
+ const tsxCode = `\n
174
+ <chip
175
+ name="${chipName}"
176
+ footprint="${footprintString}"
177
+ />\n`
178
+ const currentContent = files[currentFile]
179
+
180
+ if (cursorPosition !== undefined && cursorPosition !== null) {
181
+ const newContent =
182
+ currentContent.slice(0, cursorPosition) +
183
+ tsxCode +
184
+ currentContent.slice(cursorPosition)
185
+ updateFileContent(currentFile, newContent)
186
+ } else {
187
+ // No cursor position, look for </board> tag
188
+ const boardClosingTagIndex = currentContent.lastIndexOf("</board>")
189
+
190
+ if (boardClosingTagIndex !== -1) {
191
+ // Insert before the closing board tag
192
+ const newContent =
193
+ currentContent.slice(0, boardClosingTagIndex) +
194
+ tsxCode +
195
+ currentContent.slice(boardClosingTagIndex)
196
+ updateFileContent(currentFile, newContent)
197
+ } else {
198
+ const lastParenIndex = currentContent.lastIndexOf(")")
199
+
200
+ if (lastParenIndex !== -1) {
201
+ const newContent =
202
+ currentContent.slice(0, lastParenIndex) +
203
+ tsxCode +
204
+ currentContent.slice(lastParenIndex)
205
+ updateFileContent(currentFile, newContent)
206
+ } else {
207
+ // If no closing parenthesis found, append to end of file
208
+ updateFileContent(currentFile, currentContent + tsxCode)
209
+ }
210
+ }
211
+ }
212
+
213
+ setChipName("")
214
+ } catch (error) {
215
+ console.error("Error inserting footprint:", error)
216
+ toast({
217
+ title: "Error",
218
+ description: "Failed to insert footprint",
219
+ variant: "destructive",
220
+ })
221
+ }
222
+ }
223
+
224
+ const handleCopyToClipboard = async () => {
225
+ try {
226
+ await navigator.clipboard.writeText(footprintString)
227
+ setCopied(true)
228
+ } catch (err) {
229
+ console.error("Failed to copy to clipboard:", err)
230
+ }
231
+ }
232
+
233
+ return (
234
+ <Dialog open={open} onOpenChange={onOpenChange}>
235
+ <DialogContent className="max-w-[1160px] h-full flex flex-col overflow-x-scroll">
236
+ <DialogHeader>
237
+ <DialogTitle>Insert Chip</DialogTitle>
238
+ <DialogDescription>
239
+ Choose a footprint type and configure its parameters. The footprint
240
+ will be inserted at your cursor position.
241
+ </DialogDescription>
242
+ </DialogHeader>
243
+ <div className="w-fit h-fit flex gap-4 pt-4">
244
+ <div className="space-y-4 min-w-[280px]">
245
+ <div>
246
+ <label className="text-sm font-medium">Chip Name</label>
247
+ <Input
248
+ value={chipName}
249
+ onChange={(e) => setChipName(e.target.value)}
250
+ placeholder="Enter chip name (e.g., U1)..."
251
+ className="mt-1"
252
+ />
253
+ </div>
254
+ <div>
255
+ <label className="text-sm font-medium">Footprint Name</label>
256
+ <Combobox
257
+ value={footprintName}
258
+ onChange={(value) => {
259
+ setFootprintName(value)
260
+ try {
261
+ let newParams = fp.string(value).json()
262
+ updateFootprintString(value, newParams)
263
+ } catch (error) {
264
+ console.error("Error updating footprint string:", error)
265
+ setFootprintString(value)
266
+ handleFootprintPreview(value)
267
+ }
268
+ }}
269
+ options={footprintNames}
270
+ placeholder="Select footprint..."
271
+ searchPlaceholder="Search footprints..."
272
+ emptyText="No footprints found."
273
+ className="mt-1"
274
+ />
275
+ </div>
276
+ <div>
277
+ <label className="text-sm font-medium">Footprint String</label>
278
+ <div className="flex items-center justify-center mt-1 gap-1">
279
+ <Input
280
+ readOnly
281
+ value={footprintString}
282
+ onChange={(e) => {
283
+ setFootprintString(e.target.value)
284
+ handleFootprintPreview(e.target.value)
285
+ }}
286
+ placeholder="Complete footprint string..."
287
+ className={`bg-gray-50 text-gray-500 ${footprintNameError && "bg-red-50 border-red-200"}`}
288
+ />
289
+ <Button
290
+ size="icon"
291
+ variant="outline"
292
+ onClick={handleCopyToClipboard}
293
+ className={`shrink-0 ${copied && "text-green-500 border-green-500"}`}
294
+ title="Copy to clipboard"
295
+ >
296
+ {copied ? (
297
+ <Check className="h-4 w-4" />
298
+ ) : (
299
+ <Copy className="h-4 w-4" />
300
+ )}
301
+ </Button>
302
+ </div>
303
+ </div>
304
+ {params && (
305
+ <ParametersEditor
306
+ params={params}
307
+ updateParam={updateParam}
308
+ paramNames={PARAM_NAMES}
309
+ />
310
+ )}
311
+ <Button
312
+ onClick={() => {
313
+ handleInsertFootprint()
314
+ onOpenChange(false)
315
+ }}
316
+ disabled={!footprintString || !chipName}
317
+ className="w-full"
318
+ >
319
+ Insert Footprint
320
+ </Button>
321
+ </div>
322
+ <div className="flex flex-col">
323
+ <div className="rounded-xl overflow-hidden w-[800px] h-[600px]">
324
+ {previewSvg && (
325
+ <div
326
+ dangerouslySetInnerHTML={{
327
+ __html: previewSvg,
328
+ }}
329
+ />
330
+ )}
331
+ </div>
332
+ {error && (
333
+ <div className="mt-2 p-2 text-sm text-red-600 bg-red-50 border border-red-200 rounded">
334
+ {error}
335
+ </div>
336
+ )}
337
+ </div>
338
+ </div>
339
+ </DialogContent>
340
+ </Dialog>
341
+ )
342
+ }
@@ -0,0 +1,187 @@
1
+ import { HeaderLogin } from "@/components/HeaderLogin"
2
+ import { Button } from "@/components/ui/button"
3
+ import { useGlobalStore } from "@/hooks/use-global-store"
4
+ import { cn } from "@/lib/utils"
5
+ import {
6
+ GitHubLogoIcon,
7
+ OpenInNewWindowIcon,
8
+ ChatBubbleIcon,
9
+ DiscordLogoIcon,
10
+ } from "@radix-ui/react-icons"
11
+ import { Menu, X } from "lucide-react"
12
+ import React, { useState } from "react"
13
+ import { useLocation } from "wouter"
14
+ import { PrefetchPageLink } from "./PrefetchPageLink"
15
+ import CmdKMenu from "./CmdKMenu"
16
+ import HeaderDropdown from "./HeaderDropdown"
17
+ import SearchComponent from "./SearchComponent"
18
+ import { Analytics } from "./Analytics"
19
+
20
+ const HeaderButton = ({
21
+ href,
22
+ children,
23
+ className,
24
+ alsoHighlightForUrl,
25
+ }: {
26
+ href: string
27
+ children: React.ReactNode
28
+ className?: string
29
+ alsoHighlightForUrl?: string
30
+ }) => {
31
+ const [location] = useLocation()
32
+
33
+ if (location === href || location === alsoHighlightForUrl) {
34
+ return (
35
+ <PrefetchPageLink className={cn("header-button", className)} href={href}>
36
+ <Button
37
+ variant="ghost"
38
+ className={`border-b-2 rounded-none border-blue-600 header-button ${className}`}
39
+ >
40
+ {children}
41
+ </Button>
42
+ </PrefetchPageLink>
43
+ )
44
+ }
45
+
46
+ return (
47
+ <PrefetchPageLink className={cn("header-button", className)} href={href}>
48
+ <Button className={className} variant="ghost">
49
+ {children}
50
+ </Button>
51
+ </PrefetchPageLink>
52
+ )
53
+ }
54
+
55
+ export default function Header() {
56
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
57
+ const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
58
+
59
+ return (
60
+ <header className="px-4 py-3">
61
+ <div className="flex items-center">
62
+ <PrefetchPageLink
63
+ href="/"
64
+ className="text-lg font-semibold whitespace-nowrap"
65
+ >
66
+ <span className="bg-blue-500 px-2 py-1 rounded-md text-white">
67
+ tscircuit
68
+ </span>
69
+ </PrefetchPageLink>
70
+ <div className="hidden md:flex items-center space-x-4">
71
+ <nav>
72
+ <ul className="flex items-center gap-2 ml-2">
73
+ {isLoggedIn && (
74
+ <li>
75
+ <HeaderButton href="/dashboard">Dashboard</HeaderButton>
76
+ </li>
77
+ )}
78
+ <li>
79
+ <HeaderButton href="/newest">Newest</HeaderButton>
80
+ </li>
81
+ <li>
82
+ <HeaderButton href="/quickstart" alsoHighlightForUrl="/editor">
83
+ Editor
84
+ </HeaderButton>
85
+ </li>
86
+ <li>
87
+ <HeaderButton href="/ai">AI</HeaderButton>
88
+ </li>
89
+ <li>
90
+ <a href="https://docs.tscircuit.com">
91
+ <Button variant="ghost">Docs</Button>
92
+ </a>
93
+ </li>
94
+ <li>
95
+ <a
96
+ href="https://tscircuit.com/join"
97
+ target="_blank"
98
+ className="mr-2"
99
+ >
100
+ <Button variant="ghost">
101
+ <DiscordLogoIcon className="text-gray-400 hover:text-gray-600 transition-colors w-4 h-4" />
102
+ </Button>
103
+ </a>
104
+ </li>
105
+ </ul>
106
+ </nav>
107
+ </div>
108
+ <div className="flex-grow"></div>
109
+ <a
110
+ href="https://github.com/tscircuit/tscircuit"
111
+ target="_blank"
112
+ className="mr-4"
113
+ aria-label="View TSCircuit on GitHub"
114
+ >
115
+ <GitHubLogoIcon className="text-gray-400 hover:text-gray-600 transition-colors" />
116
+ </a>
117
+ {/* <a href="https://tscircuit.com/join" target="_blank" className="mr-2">
118
+ <DiscordLogoIcon className="text-gray-400 hover:text-gray-600 transition-colors" />
119
+ </a> */}
120
+ <div className="hidden md:flex items-center space-x-4">
121
+ <SearchComponent />
122
+ <HeaderDropdown />
123
+ <HeaderLogin />
124
+ </div>
125
+ <button
126
+ className="md:hidden"
127
+ onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
128
+ aria-label={mobileMenuOpen ? "Close menu" : "Open menu"}
129
+ >
130
+ {mobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
131
+ </button>
132
+ </div>
133
+ {mobileMenuOpen && (
134
+ <div className="md:hidden mt-4">
135
+ <nav className="mb-4">
136
+ <ul className="flex flex-col gap-2 w-full">
137
+ {isLoggedIn && (
138
+ <li>
139
+ <HeaderButton
140
+ className="w-full justify-start"
141
+ href="/dashboard"
142
+ >
143
+ Dashboard
144
+ </HeaderButton>
145
+ </li>
146
+ )}
147
+ <li>
148
+ <HeaderButton className="w-full justify-start" href="/newest">
149
+ Newest
150
+ </HeaderButton>
151
+ </li>
152
+ <li>
153
+ <HeaderButton
154
+ className="w-full justify-start"
155
+ href="/quickstart"
156
+ alsoHighlightForUrl="/editor"
157
+ >
158
+ Editor
159
+ </HeaderButton>
160
+ </li>
161
+ <li>
162
+ <HeaderButton className="w-full justify-start" href="/ai">
163
+ AI
164
+ </HeaderButton>
165
+ </li>
166
+ <li>
167
+ <HeaderButton
168
+ className="w-full justify-start"
169
+ href="https://docs.tscircuit.com"
170
+ >
171
+ Docs
172
+ </HeaderButton>
173
+ </li>
174
+ </ul>
175
+ </nav>
176
+ <div className="flex flex-col gap-4">
177
+ <SearchComponent />
178
+ <HeaderDropdown />
179
+ <HeaderLogin />
180
+ </div>
181
+ </div>
182
+ )}
183
+ <CmdKMenu />
184
+ <Analytics />
185
+ </header>
186
+ )
187
+ }
@@ -0,0 +1,135 @@
1
+ import { Button } from "@/components/ui/button"
2
+ import { Card, CardContent } from "@/components/ui/card"
3
+ import { Badge } from "@/components/ui/badge"
4
+ import {
5
+ Accordion,
6
+ AccordionContent,
7
+ AccordionItem,
8
+ AccordionTrigger,
9
+ } from "@/components/ui/accordion"
10
+ import {
11
+ CircuitBoard,
12
+ Cpu,
13
+ Layers,
14
+ CloudLightningIcon as Lightning,
15
+ Maximize2,
16
+ Zap,
17
+ Search,
18
+ X,
19
+ } from "lucide-react"
20
+ import { Link } from "wouter"
21
+ import { PrefetchPageLink } from "./PrefetchPageLink"
22
+ import { HeaderLogin } from "./HeaderLogin"
23
+ import SearchComponent from "./SearchComponent"
24
+ import HeaderDropdown from "./HeaderDropdown"
25
+ import { useState } from "react"
26
+ import { useGlobalStore } from "@/hooks/use-global-store"
27
+ import { Analytics } from "./Analytics"
28
+
29
+ const SearchButtonComponent = () => {
30
+ const [isExpanded, setIsExpanded] = useState(false)
31
+
32
+ return (
33
+ <div className="relative">
34
+ {isExpanded ? (
35
+ <div className="flex items-center gap-2">
36
+ <div className="w-32 bg-white">
37
+ <SearchComponent />
38
+ </div>
39
+ {/* <Button
40
+ variant="ghost"
41
+ size="icon"
42
+ onClick={() => setIsExpanded(false)}
43
+ className="h-8 w-8"
44
+ >
45
+ <X className="h-4 w-4" />
46
+ </Button> */}
47
+ </div>
48
+ ) : (
49
+ <Button
50
+ variant="ghost"
51
+ size="icon"
52
+ onClick={() => setIsExpanded(true)}
53
+ className="h-8 w-8"
54
+ aria-label="Open search"
55
+ >
56
+ <Search className="h-4 w-4" />
57
+ </Button>
58
+ )}
59
+ </div>
60
+ )
61
+ }
62
+
63
+ export const Header2 = () => {
64
+ const isLoggedIn = useGlobalStore((state) => Boolean(state.session))
65
+ return (
66
+ <>
67
+ <header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
68
+ <div className="container mx-auto flex h-16 items-center justify-between px-2 md:px-6">
69
+ <div className="flex items-center gap-2">
70
+ <CircuitBoard className="h-6 w-6" />
71
+ <span className="text-lg font-bold">tscircuit</span>
72
+ </div>
73
+ <nav className="flex md:hidden">
74
+ {isLoggedIn && (
75
+ <Link
76
+ className="text-sm font-medium hover:underline underline-offset-4"
77
+ href="/dashboard"
78
+ >
79
+ Dashboard
80
+ </Link>
81
+ )}
82
+ </nav>
83
+ <nav className="hidden md:flex gap-6">
84
+ <PrefetchPageLink
85
+ className="text-sm font-medium hover:underline underline-offset-4"
86
+ href="/dashboard"
87
+ >
88
+ Dashboard
89
+ </PrefetchPageLink>
90
+ <PrefetchPageLink
91
+ className="text-sm font-medium hover:underline underline-offset-4"
92
+ href="/quickstart"
93
+ >
94
+ Editor
95
+ </PrefetchPageLink>
96
+ {/* <a
97
+ className="text-sm font-medium hover:underline underline-offset-4"
98
+ href="https://github.com/tscircuit/tscircuit"
99
+ >
100
+ Github
101
+ </a> */}
102
+ <a
103
+ className="text-sm font-medium hover:underline underline-offset-4"
104
+ href="https://docs.tscircuit.com"
105
+ >
106
+ Docs
107
+ </a>
108
+ <a
109
+ className="text-sm font-medium hover:underline underline-offset-4"
110
+ href="https://tscircuit.com/join"
111
+ >
112
+ Discord
113
+ </a>
114
+ <a
115
+ className="text-sm font-medium hover:underline underline-offset-4"
116
+ href="mailto:hello@tscircuit.com"
117
+ >
118
+ Contact
119
+ </a>
120
+ </nav>
121
+ <div className="flex items-center gap-4">
122
+ <SearchButtonComponent />
123
+ {isLoggedIn && (
124
+ <div className="hidden sm:block">
125
+ <HeaderDropdown />
126
+ </div>
127
+ )}
128
+ <HeaderLogin />
129
+ </div>
130
+ </div>
131
+ </header>
132
+ <Analytics />
133
+ </>
134
+ )
135
+ }