@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,61 @@
1
+ import React from "react"
2
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
3
+ import { PCBViewer } from "@tscircuit/pcb-viewer"
4
+ import { CadViewer } from "@tscircuit/3d-viewer"
5
+ import { CircuitJsonTableViewer } from "./TableViewer/CircuitJsonTableViewer"
6
+ import { AnyCircuitElement } from "circuit-json"
7
+
8
+ interface OrderPreviewContentProps {
9
+ circuitJson: AnyCircuitElement[] | null
10
+ className?: string
11
+ }
12
+
13
+ export const OrderPreviewContent: React.FC<OrderPreviewContentProps> = ({
14
+ circuitJson,
15
+ className,
16
+ }) => {
17
+ return (
18
+ <div className={className}>
19
+ <Tabs defaultValue="pcb" className="w-full">
20
+ <TabsList>
21
+ <TabsTrigger value="pcb">PCB</TabsTrigger>
22
+ <TabsTrigger value="cad">3D</TabsTrigger>
23
+ <TabsTrigger value="json-table">JSON</TabsTrigger>
24
+ </TabsList>
25
+ <TabsContent value="pcb">
26
+ <div className="h-[500px] shadow overflow-hidden sm:rounded-lg mb-6">
27
+ {circuitJson ? (
28
+ <PCBViewer height={500} soup={circuitJson} />
29
+ ) : (
30
+ <div className="flex items-center justify-center h-full bg-gray-100">
31
+ No PCB data available
32
+ </div>
33
+ )}
34
+ </div>
35
+ </TabsContent>
36
+ <TabsContent value="cad">
37
+ <div className="h-[500px] shadow overflow-hidden sm:rounded-lg mb-6">
38
+ {circuitJson ? (
39
+ <CadViewer soup={circuitJson as any} />
40
+ ) : (
41
+ <div className="flex items-center justify-center h-full bg-gray-100">
42
+ No 3D data available
43
+ </div>
44
+ )}
45
+ </div>
46
+ </TabsContent>
47
+ <TabsContent value="json-table">
48
+ <div className="h-[500px] shadow overflow-hidden sm:rounded-lg mb-6">
49
+ {circuitJson ? (
50
+ <CircuitJsonTableViewer elements={circuitJson} />
51
+ ) : (
52
+ <div className="flex items-center justify-center h-full bg-gray-100">
53
+ No JSON data available
54
+ </div>
55
+ )}
56
+ </div>
57
+ </TabsContent>
58
+ </Tabs>
59
+ </div>
60
+ )
61
+ }
@@ -0,0 +1,140 @@
1
+ import { Input } from "./ui/input"
2
+
3
+ interface ParametersEditorProps {
4
+ params: Record<string, any>
5
+ updateParam: (
6
+ key: string,
7
+ value: string | number | boolean | string[],
8
+ ) => void
9
+ paramNames: Record<string, string>
10
+ }
11
+
12
+ const ParametersEditor = ({
13
+ params,
14
+ updateParam,
15
+ paramNames,
16
+ }: ParametersEditorProps) => {
17
+ const renderStringInput = (key: string, value: string) => {
18
+ if (key === "grid") {
19
+ let rows = "",
20
+ cols = ""
21
+ if (typeof value === "string") {
22
+ ;[rows = "", cols = ""] = value.split("x").map(String)
23
+ } else if (typeof value === "number") {
24
+ rows = cols = String(value)
25
+ } else if (value && typeof value === "object") {
26
+ const grid = value as { x: number; y: number }
27
+ rows = String(grid.x || "")
28
+ cols = String(grid.y || "")
29
+ }
30
+ return (
31
+ <div className="flex gap-2 flex-1">
32
+ <Input
33
+ type="number"
34
+ value={rows || ""}
35
+ onChange={(e) => {
36
+ const newRows = e.target.value || "0"
37
+ const newCols = cols || "0"
38
+ updateParam(key, `${newRows}x${newCols}`)
39
+ }}
40
+ placeholder="Rows"
41
+ className="flex-1"
42
+ />
43
+ <span className="flex items-center">×</span>
44
+ <Input
45
+ type="number"
46
+ value={cols || ""}
47
+ onChange={(e) => {
48
+ const newRows = rows || "0"
49
+ const newCols = e.target.value || "0"
50
+ updateParam(key, `${newRows}x${newCols}`)
51
+ }}
52
+ placeholder="Cols"
53
+ className="flex-1"
54
+ />
55
+ </div>
56
+ )
57
+ }
58
+
59
+ if (key === "missing") {
60
+ const missingArray = Array.isArray(value) ? value : []
61
+ return (
62
+ <div className="flex flex-wrap gap-2 items-center">
63
+ {missingArray.map((item, index) => (
64
+ <Input
65
+ key={index}
66
+ type="number"
67
+ value={item}
68
+ onChange={(e) => {
69
+ if (!e.target.value) {
70
+ const newArray = missingArray.filter((_, i) => i !== index)
71
+ updateParam(key, newArray)
72
+ return
73
+ }
74
+ const newArray = [...missingArray]
75
+ newArray[index] = e.target.value
76
+ updateParam(key, newArray)
77
+ }}
78
+ className="w-16 h-8 text-center p-1"
79
+ />
80
+ ))}
81
+ <button
82
+ onClick={() => {
83
+ updateParam(key, [...missingArray, "0"])
84
+ }}
85
+ className="w-8 h-8 flex items-center justify-center rounded border border-gray-200 hover:bg-gray-50"
86
+ >
87
+ +
88
+ </button>
89
+ </div>
90
+ )
91
+ }
92
+
93
+ return (
94
+ <Input
95
+ type="text"
96
+ value={value}
97
+ onChange={(e) => updateParam(key, e.target.value)}
98
+ className="flex-1"
99
+ />
100
+ )
101
+ }
102
+
103
+ return (
104
+ <div className="space-y-2">
105
+ <label className="text-sm font-medium">Parameters</label>
106
+ {Object.entries(params)
107
+ .filter(
108
+ ([key]) => key !== "fn" && (key !== "num_pins" || !key.match(/\d/)),
109
+ )
110
+ .map(([key, value]) => {
111
+ return (
112
+ <div key={key} className="flex gap-2 items-center">
113
+ <label className="text-sm">
114
+ {paramNames[key] ? `${paramNames[key]} (${key})` : key}:
115
+ </label>
116
+ {typeof value === "boolean" ? (
117
+ <input
118
+ type="checkbox"
119
+ checked={value}
120
+ onChange={(e) => updateParam(key, e.target.checked)}
121
+ className="h-4 w-4"
122
+ />
123
+ ) : typeof value === "number" ? (
124
+ <Input
125
+ type="number"
126
+ value={value}
127
+ onChange={(e) => updateParam(key, e.target.value)}
128
+ className="flex-1"
129
+ />
130
+ ) : (
131
+ renderStringInput(key, value)
132
+ )}
133
+ </div>
134
+ )
135
+ })}
136
+ </div>
137
+ )
138
+ }
139
+
140
+ export default ParametersEditor
@@ -0,0 +1,47 @@
1
+ import React, { useRef, useState, useLayoutEffect } from "react"
2
+ import { PCBViewer } from "@tscircuit/pcb-viewer"
3
+
4
+ export const PcbViewerWithContainerHeight = ({
5
+ containerClassName,
6
+ ...props
7
+ }: {
8
+ containerClassName?: string
9
+ } & React.ComponentProps<typeof PCBViewer>) => {
10
+ const containerRef = useRef<HTMLDivElement>(null)
11
+ const [computedHeight, setComputedHeight] = useState(620)
12
+
13
+ useLayoutEffect(() => {
14
+ const updateHeight = () => {
15
+ if (containerRef.current) {
16
+ const containerHeight = containerRef.current.clientHeight
17
+ const screenHeight = window.innerHeight
18
+ setComputedHeight(
19
+ Math.min(Math.max(containerHeight, 620), screenHeight),
20
+ )
21
+ }
22
+ }
23
+
24
+ // Immediate synchronous calculation
25
+ updateHeight()
26
+
27
+ // Resize listener for dynamic changes
28
+ const resizeObserver = new ResizeObserver(updateHeight)
29
+ if (containerRef.current) {
30
+ resizeObserver.observe(containerRef.current)
31
+ }
32
+
33
+ // Fallback for window resize
34
+ window.addEventListener("resize", updateHeight)
35
+
36
+ return () => {
37
+ resizeObserver.disconnect()
38
+ window.removeEventListener("resize", updateHeight)
39
+ }
40
+ }, [])
41
+
42
+ return (
43
+ <div ref={containerRef} className={containerClassName || "w-full h-full"}>
44
+ <PCBViewer {...props} height={computedHeight} />
45
+ </div>
46
+ )
47
+ }
@@ -0,0 +1,45 @@
1
+ import { Link } from "wouter"
2
+ import { useEffect } from "react"
3
+ import { useInView } from "react-intersection-observer"
4
+
5
+ export /**
6
+ * PrefetchPageLink component that loads page components when links become visible.
7
+ * Routes are automatically mapped to their corresponding page components under @/pages.
8
+ * The href path is used to determine which page to load:
9
+ *
10
+ * Example:
11
+ * - href="/editor" -> loads "@/pages/editor.tsx"
12
+ * - href="/" -> loads "@/pages/landing.tsx"
13
+ * - href="/my-orders" -> loads "@/pages/my-orders.tsx"
14
+ */
15
+ const PrefetchPageLink = ({
16
+ href,
17
+ children,
18
+ className,
19
+ ...props
20
+ }: {
21
+ href: string
22
+ children: React.ReactNode
23
+ className?: string
24
+ [key: string]: any
25
+ }) => {
26
+ const { ref, inView } = useInView({
27
+ triggerOnce: true,
28
+ threshold: 0,
29
+ })
30
+
31
+ useEffect(() => {
32
+ if (inView) {
33
+ const pageName = href === "/" ? "landing" : href.slice(1)
34
+ import(`@/pages/${pageName}.tsx`).catch((error) => {
35
+ console.error(`Failed to prefetch page module ${pageName}:`, error)
36
+ })
37
+ }
38
+ }, [inView, href])
39
+
40
+ return (
41
+ <Link {...props} href={href} className={className} ref={ref}>
42
+ {children}
43
+ </Link>
44
+ )
45
+ }
@@ -0,0 +1,375 @@
1
+ import { CodeEditor } from "@/components/CodeEditor"
2
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
3
+ import { cn } from "@/lib/utils"
4
+ import { applyPcbEditEvents } from "@/lib/utils/pcbManualEditEventHandler"
5
+ import { CadViewer } from "@tscircuit/3d-viewer"
6
+ import { PCBViewer } from "@tscircuit/pcb-viewer"
7
+ import { Schematic } from "@tscircuit/schematic-viewer"
8
+ import { useEffect, useRef, useState } from "react"
9
+ import { ErrorFallback } from "./ErrorFallback"
10
+ import { ErrorBoundary } from "react-error-boundary"
11
+ import { ErrorTabContent } from "./ErrorTabContent"
12
+ import PreviewEmptyState from "./PreviewEmptyState"
13
+ import { RunButton } from "./RunButton"
14
+ import { CircuitJsonTableViewer } from "./TableViewer/CircuitJsonTableViewer"
15
+ import { CircuitToSvgWithMouseControl } from "./CircuitToSvgWithMouseControl"
16
+ import { BomTable } from "./BomTable"
17
+ import {
18
+ CheckIcon,
19
+ EllipsisIcon,
20
+ EllipsisVerticalIcon,
21
+ FullscreenIcon,
22
+ MinimizeIcon,
23
+ } from "lucide-react"
24
+ import {
25
+ DropdownMenu,
26
+ DropdownMenuContent,
27
+ DropdownMenuItem,
28
+ DropdownMenuTrigger,
29
+ } from "./ui/dropdown-menu"
30
+ import { Button } from "./ui/button"
31
+ import { PcbViewerWithContainerHeight } from "./PcbViewerWithContainerHeight"
32
+ import { useGlobalStore } from "@/hooks/use-global-store"
33
+
34
+ export interface PreviewContentProps {
35
+ code: string
36
+ readOnly?: boolean
37
+ triggerRunTsx: () => void
38
+ tsxRunTriggerCount: number
39
+ errorMessage: string | null
40
+ circuitJson: any
41
+ circuitJsonKey?: string
42
+ className?: string
43
+ showCodeTab?: boolean
44
+ showJsonTab?: boolean
45
+ showImportAndFormatButtons?: boolean
46
+ headerClassName?: string
47
+ leftHeaderContent?: React.ReactNode
48
+ isRunningCode?: boolean
49
+ isStreaming?: boolean
50
+ onToggleFullScreen?: () => void
51
+ isFullScreen?: boolean
52
+ onCodeChange?: (code: string) => void
53
+ onDtsChange?: (dts: string) => void
54
+ manualEditsFileContent?: string
55
+ onManualEditsFileContentChange?: (newmanualEditsFileContent: string) => void
56
+ }
57
+
58
+ declare global {
59
+ interface Window {
60
+ TSCIRCUIT_3D_OBJECT_REF: any
61
+ }
62
+ }
63
+
64
+ export const PreviewContent = ({
65
+ code,
66
+ triggerRunTsx,
67
+ tsxRunTriggerCount,
68
+ errorMessage,
69
+ circuitJsonKey = "",
70
+ circuitJson,
71
+ showCodeTab = false,
72
+ showJsonTab = true,
73
+ showImportAndFormatButtons = true,
74
+ className,
75
+ headerClassName,
76
+ leftHeaderContent,
77
+ readOnly,
78
+ isStreaming,
79
+ onToggleFullScreen,
80
+ isFullScreen,
81
+ isRunningCode,
82
+ onCodeChange,
83
+ onDtsChange,
84
+ manualEditsFileContent,
85
+ onManualEditsFileContentChange,
86
+ }: PreviewContentProps) => {
87
+ const [activeTab, setActiveTab] = useState(showCodeTab ? "code" : "pcb")
88
+ const [lastRunHash, setLastRunHash] = useState("")
89
+ const threeJsObjectRef = useRef<any>(null)
90
+
91
+ useEffect(() => {
92
+ window.TSCIRCUIT_3D_OBJECT_REF = threeJsObjectRef
93
+ }, [])
94
+
95
+ const currentCodeHash = code + "\n" + manualEditsFileContent
96
+ const hasCodeChangedSinceLastRun = lastRunHash !== currentCodeHash
97
+
98
+ useEffect(() => {
99
+ if (tsxRunTriggerCount === 0) return
100
+ setLastRunHash(currentCodeHash)
101
+ }, [tsxRunTriggerCount])
102
+
103
+ useEffect(() => {
104
+ if (errorMessage) {
105
+ setActiveTab("error")
106
+ }
107
+ }, [errorMessage])
108
+
109
+ useEffect(() => {
110
+ if (activeTab === "code" && circuitJson && !errorMessage) {
111
+ setActiveTab("pcb")
112
+ }
113
+ }, [circuitJson])
114
+
115
+ return (
116
+ <div className={cn("flex flex-col relative", className)}>
117
+ <div className="md:sticky md:top-2">
118
+ <Tabs
119
+ value={activeTab}
120
+ onValueChange={setActiveTab}
121
+ className="flex-grow flex flex-col"
122
+ >
123
+ <div className={cn("flex items-center gap-2", headerClassName)}>
124
+ {leftHeaderContent}
125
+ {leftHeaderContent && <div className="flex-grow" />}
126
+ <RunButton
127
+ onClick={() => triggerRunTsx()}
128
+ disabled={!hasCodeChangedSinceLastRun && tsxRunTriggerCount !== 0}
129
+ isRunningCode={isRunningCode}
130
+ />
131
+ {!leftHeaderContent && <div className="flex-grow" />}
132
+ <TabsList>
133
+ {showCodeTab && <TabsTrigger value="code">Code</TabsTrigger>}
134
+ <TabsTrigger value="pcb" className="whitespace-nowrap">
135
+ {circuitJson && (
136
+ <span
137
+ className={cn(
138
+ "inline-flex items-center justify-center w-2 h-2 mr-1 text-xs font-bold text-white rounded-full",
139
+ !hasCodeChangedSinceLastRun
140
+ ? "bg-blue-500"
141
+ : "bg-gray-500",
142
+ )}
143
+ />
144
+ )}
145
+ PCB
146
+ </TabsTrigger>
147
+ <TabsTrigger value="schematic" className="whitespace-nowrap">
148
+ {circuitJson && (
149
+ <span
150
+ className={cn(
151
+ "inline-flex items-center justify-center w-2 h-2 mr-1 text-xs font-bold text-white rounded-full",
152
+ !hasCodeChangedSinceLastRun
153
+ ? "bg-blue-500"
154
+ : "bg-gray-500",
155
+ )}
156
+ />
157
+ )}
158
+ Schematic
159
+ </TabsTrigger>
160
+ <TabsTrigger value="cad">
161
+ {circuitJson && (
162
+ <span
163
+ className={cn(
164
+ "inline-flex items-center justify-center w-2 h-2 mr-1 text-xs font-bold text-white rounded-full",
165
+ !hasCodeChangedSinceLastRun
166
+ ? "bg-blue-500"
167
+ : "bg-gray-500",
168
+ )}
169
+ />
170
+ )}
171
+ 3D
172
+ </TabsTrigger>
173
+ <DropdownMenu>
174
+ <DropdownMenuTrigger asChild>
175
+ <div className="whitespace-nowrap p-2 mr-1 cursor-pointer relative">
176
+ <EllipsisIcon className="w-4 h-4" />
177
+ {errorMessage && (
178
+ <span className="inline-flex absolute top-[6px] right-[4px] items-center justify-center w-1 h-1 ml-2 text-[8px] font-bold text-white bg-red-500 rounded-full" />
179
+ )}
180
+ </div>
181
+ </DropdownMenuTrigger>
182
+ <DropdownMenuContent className="*:text-xs">
183
+ <DropdownMenuItem
184
+ onSelect={() => setActiveTab("error")}
185
+ className="flex"
186
+ >
187
+ <CheckIcon
188
+ className={cn(
189
+ "w-3 h-3 mr-2",
190
+ activeTab !== "error" && "invisible",
191
+ )}
192
+ />
193
+ <div className="flex-grow">Errors</div>
194
+ {errorMessage && (
195
+ <span className="inline-flex items-center justify-center w-3 h-3 ml-2 text-[8px] font-bold text-white bg-red-500 rounded-full">
196
+ 1
197
+ </span>
198
+ )}
199
+ </DropdownMenuItem>
200
+ <DropdownMenuItem onSelect={() => setActiveTab("bom")}>
201
+ <CheckIcon
202
+ className={cn(
203
+ "w-3 h-3 mr-2",
204
+ activeTab !== "bom" && "invisible",
205
+ )}
206
+ />
207
+ Bill of Materials
208
+ </DropdownMenuItem>
209
+ <DropdownMenuItem
210
+ onSelect={() => setActiveTab("circuitjson")}
211
+ >
212
+ <CheckIcon
213
+ className={cn(
214
+ "w-3 h-3 mr-2",
215
+ activeTab !== "circuitjson" && "invisible",
216
+ )}
217
+ />
218
+ JSON
219
+ </DropdownMenuItem>
220
+ </DropdownMenuContent>
221
+ </DropdownMenu>
222
+ </TabsList>
223
+ {onToggleFullScreen && (
224
+ <Button onClick={onToggleFullScreen} variant="ghost">
225
+ {isFullScreen ? (
226
+ <MinimizeIcon size={16} />
227
+ ) : (
228
+ <FullscreenIcon size={16} />
229
+ )}
230
+ </Button>
231
+ )}
232
+ </div>
233
+ {showCodeTab && (
234
+ <TabsContent value="code" className="flex-grow overflow-hidden">
235
+ <div className="h-full">
236
+ <CodeEditor
237
+ initialCode={code}
238
+ manualEditsFileContent={manualEditsFileContent ?? ""}
239
+ isStreaming={isStreaming}
240
+ onCodeChange={onCodeChange!}
241
+ onDtsChange={onDtsChange!}
242
+ readOnly={readOnly}
243
+ showImportAndFormatButtons={showImportAndFormatButtons}
244
+ />
245
+ </div>
246
+ </TabsContent>
247
+ )}
248
+
249
+ <TabsContent value="pcb">
250
+ <div
251
+ className={cn(
252
+ "mt-4 overflow-hidden",
253
+ isFullScreen ? "h-[calc(100vh-96px)]" : "h-[620px]",
254
+ )}
255
+ >
256
+ <ErrorBoundary fallback={<div>Error loading PCB viewer</div>}>
257
+ {circuitJson ? (
258
+ <PcbViewerWithContainerHeight
259
+ key={circuitJsonKey}
260
+ soup={circuitJson}
261
+ containerClassName={cn(
262
+ "h-full w-full",
263
+ isFullScreen
264
+ ? "min-h-[calc(100vh-240px)]"
265
+ : "min-h-[620px]",
266
+ )}
267
+ onEditEventsChanged={(editEvents) => {
268
+ if (editEvents.some((editEvent) => editEvent.in_progress))
269
+ return
270
+ // Update state with new edit events
271
+ const newManualEditsFileContent = applyPcbEditEvents({
272
+ editEvents,
273
+ circuitJson,
274
+ manualEditsFileContent,
275
+ })
276
+ onManualEditsFileContentChange?.(
277
+ JSON.stringify(newManualEditsFileContent, null, 2),
278
+ )
279
+ }}
280
+ />
281
+ ) : (
282
+ <PreviewEmptyState triggerRunTsx={triggerRunTsx} />
283
+ )}
284
+ </ErrorBoundary>
285
+ </div>
286
+ </TabsContent>
287
+
288
+ <TabsContent value="schematic">
289
+ <div
290
+ className={cn(
291
+ "mt-4 overflow-auto",
292
+ isFullScreen ? "h-[calc(100vh-96px)]" : "h-[620px]",
293
+ )}
294
+ >
295
+ <ErrorBoundary fallback={<div>Error loading Schematic</div>}>
296
+ {circuitJson ? (
297
+ <CircuitToSvgWithMouseControl
298
+ key={tsxRunTriggerCount}
299
+ circuitJson={circuitJson}
300
+ />
301
+ // Waiting for Schematic Viewer to stablize
302
+ // <Schematic
303
+ // style={{ height: "500px" }}
304
+ // key={tsxRunTriggerCount}
305
+ // soup={circuitJson}
306
+ // />
307
+ ) : (
308
+ <PreviewEmptyState triggerRunTsx={triggerRunTsx} />
309
+ )}
310
+ </ErrorBoundary>
311
+ </div>
312
+ </TabsContent>
313
+
314
+ <TabsContent value="cad">
315
+ <div
316
+ className={cn(
317
+ "mt-4 overflow-auto",
318
+ isFullScreen ? "h-[calc(100vh-96px)]" : "h-[620px]",
319
+ )}
320
+ >
321
+ <ErrorBoundary FallbackComponent={ErrorFallback}>
322
+ {circuitJson ? (
323
+ <CadViewer soup={circuitJson as any} ref={threeJsObjectRef} />
324
+ ) : (
325
+ <PreviewEmptyState triggerRunTsx={triggerRunTsx} />
326
+ )}
327
+ </ErrorBoundary>
328
+ </div>
329
+ </TabsContent>
330
+
331
+ <TabsContent value="bom">
332
+ <div
333
+ className={cn(
334
+ "mt-4 overflow-auto",
335
+ isFullScreen ? "h-[calc(100vh-96px)]" : "h-[620px]",
336
+ )}
337
+ >
338
+ <ErrorBoundary fallback={<div>Error loading BOM</div>}>
339
+ {circuitJson ? (
340
+ <BomTable circuitJson={circuitJson} />
341
+ ) : (
342
+ <PreviewEmptyState triggerRunTsx={triggerRunTsx} />
343
+ )}
344
+ </ErrorBoundary>
345
+ </div>
346
+ </TabsContent>
347
+
348
+ <TabsContent value="circuitjson">
349
+ <div
350
+ className={cn(
351
+ "mt-4 overflow-auto",
352
+ isFullScreen ? "h-[calc(100vh-96px)]" : "h-[620px]",
353
+ )}
354
+ >
355
+ <ErrorBoundary fallback={<div>Error loading JSON viewer</div>}>
356
+ {circuitJson ? (
357
+ <CircuitJsonTableViewer elements={circuitJson as any} />
358
+ ) : (
359
+ <PreviewEmptyState triggerRunTsx={triggerRunTsx} />
360
+ )}
361
+ </ErrorBoundary>
362
+ </div>
363
+ </TabsContent>
364
+ <TabsContent value="error">
365
+ {circuitJson || errorMessage ? (
366
+ <ErrorTabContent code={code} errorMessage={errorMessage} />
367
+ ) : (
368
+ <PreviewEmptyState triggerRunTsx={triggerRunTsx} />
369
+ )}
370
+ </TabsContent>
371
+ </Tabs>
372
+ </div>
373
+ </div>
374
+ )
375
+ }
@@ -0,0 +1,16 @@
1
+ import { Button } from "@/components/ui/button"
2
+ import { PlayIcon } from "lucide-react"
3
+
4
+ const PreviewEmptyState = ({
5
+ triggerRunTsx,
6
+ }: { triggerRunTsx: () => void }) => (
7
+ <div className="flex items-center gap-3 bg-gray-100 text-center justify-center py-10">
8
+ No circuit json loaded
9
+ <Button className="bg-blue-600 hover:bg-blue-500" onClick={triggerRunTsx}>
10
+ Run Code
11
+ <PlayIcon className="w-3 h-3 ml-2" />
12
+ </Button>
13
+ </div>
14
+ )
15
+
16
+ export default PreviewEmptyState