@dfosco/storyboard-core 4.2.0-beta.3 → 4.2.0

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 (419) hide show
  1. package/commandpalette.config.json +109 -24
  2. package/dist/storyboard-ui.css +1 -1
  3. package/dist/storyboard-ui.js +16711 -27239
  4. package/dist/storyboard-ui.js.map +1 -1
  5. package/dist/tailwind.css +1 -1
  6. package/package.json +5 -2
  7. package/scaffold/agents/prompt-agent.agent.md +181 -0
  8. package/scaffold/agents/terminal-agent.agent.md +351 -0
  9. package/scaffold/codex/config.toml +246 -0
  10. package/scaffold/manifest.json +5 -10
  11. package/scaffold/skills/canvas/SKILL.md +5 -4
  12. package/scaffold/skills/ship/SKILL.md +1 -1
  13. package/scaffold/storyboard.config.json +11 -1
  14. package/src/ActionMenuButton.jsx +103 -0
  15. package/src/AutosyncMenuButton.css +67 -0
  16. package/src/AutosyncMenuButton.jsx +242 -0
  17. package/src/BranchSelect.jsx +29 -0
  18. package/src/BranchSelect.module.css +30 -0
  19. package/src/CanvasAgentsMenu.jsx +89 -0
  20. package/src/CanvasCreateMenu.jsx +611 -0
  21. package/src/CanvasSnap.css +27 -0
  22. package/src/CanvasSnap.jsx +51 -0
  23. package/src/CanvasUndoRedo.css +36 -0
  24. package/src/CanvasUndoRedo.jsx +62 -0
  25. package/src/CanvasZoomControl.css +53 -0
  26. package/src/CanvasZoomControl.jsx +49 -0
  27. package/src/CanvasZoomToFit.css +18 -0
  28. package/src/CanvasZoomToFit.jsx +26 -0
  29. package/src/CommandMenu.css +8 -0
  30. package/src/CommandMenu.jsx +287 -0
  31. package/src/CommandPalette.jsx +35 -0
  32. package/src/CommandPaletteTrigger.jsx +25 -0
  33. package/src/CommentsMenuButton.jsx +40 -0
  34. package/src/CoreUIBar.css +47 -0
  35. package/src/CoreUIBar.jsx +858 -0
  36. package/src/CreateMenuButton.jsx +117 -0
  37. package/src/HideChromeTrigger.jsx +40 -0
  38. package/src/InspectorPanel.css +109 -0
  39. package/src/InspectorPanel.jsx +632 -0
  40. package/src/PwaInstallBanner.css +42 -0
  41. package/src/PwaInstallBanner.jsx +124 -0
  42. package/src/SidePanel.jsx +261 -0
  43. package/src/ThemeMenuButton.jsx +139 -0
  44. package/src/autosync/server.js +202 -5
  45. package/src/autosync/server.test.js +111 -0
  46. package/src/canvas/__tests__/agent-integration.test.js +596 -0
  47. package/src/canvas/__tests__/helpers/browser.js +95 -0
  48. package/src/canvas/__tests__/helpers/canvas-api.js +129 -0
  49. package/src/canvas/__tests__/helpers/perf.js +118 -0
  50. package/src/canvas/__tests__/helpers/setup.js +176 -0
  51. package/src/canvas/__tests__/helpers/tmux.js +130 -0
  52. package/src/canvas/__tests__/helpers/transcript.js +132 -0
  53. package/src/canvas/__tests__/terminal-integration.test.js +177 -0
  54. package/src/canvas/hot-pool.js +756 -0
  55. package/src/canvas/materializer.js +31 -0
  56. package/src/canvas/materializer.test.js +56 -0
  57. package/src/canvas/selectedWidgets.js +65 -7
  58. package/src/canvas/server.js +1802 -22
  59. package/src/canvas/server.test.js +239 -0
  60. package/src/canvas/terminal-config.js +330 -0
  61. package/src/canvas/terminal-registry.js +41 -3
  62. package/src/canvas/terminal-server.js +1098 -37
  63. package/src/canvas/writeGuard.js +51 -3
  64. package/src/canvasConfig.js +67 -1
  65. package/src/canvasConfig.test.js +79 -1
  66. package/src/cli/agent.js +85 -0
  67. package/src/cli/branch.js +232 -0
  68. package/src/cli/canvasAdd.js +61 -14
  69. package/src/cli/canvasBatch.js +98 -0
  70. package/src/cli/canvasBounds.js +1 -1
  71. package/src/cli/canvasRead.js +1 -1
  72. package/src/cli/canvasUpdate.js +179 -0
  73. package/src/cli/compact.js +0 -2
  74. package/src/cli/create.js +40 -16
  75. package/src/cli/dev.js +158 -84
  76. package/src/cli/exit.js +23 -24
  77. package/src/cli/index.js +55 -2
  78. package/src/cli/proxy.js +96 -37
  79. package/src/cli/schemas.js +22 -4
  80. package/src/cli/server.js +149 -26
  81. package/src/cli/serverUrl.js +8 -3
  82. package/src/cli/sessions.js +133 -7
  83. package/src/cli/setup.js +138 -12
  84. package/src/cli/terminal-commands.js +20 -9
  85. package/src/cli/terminal-messaging.js +231 -0
  86. package/src/cli/terminal-welcome.js +449 -34
  87. package/src/cli/updateVersion.js +1 -1
  88. package/src/commandActions.js +1 -0
  89. package/src/commandPaletteConfig.js +9 -0
  90. package/src/comments/auth.js +2 -1
  91. package/src/comments/ui/AuthModal.jsx +114 -0
  92. package/src/comments/ui/CommentWindow.jsx +329 -0
  93. package/src/comments/ui/CommentsDrawer.jsx +102 -0
  94. package/src/comments/ui/Composer.jsx +64 -0
  95. package/src/comments/ui/authModal.test.js +1 -1
  96. package/src/comments/ui/commentWindow.js +16 -17
  97. package/src/comments/ui/commentsDrawer.js +25 -26
  98. package/src/comments/ui/composer.js +23 -24
  99. package/src/comments/ui/index.js +2 -3
  100. package/src/configSchema.js +59 -1
  101. package/src/configStore.js +161 -0
  102. package/src/core-ui-colors.css +12 -0
  103. package/src/devtools.js +17 -19
  104. package/src/devtools.test.js +18 -9
  105. package/src/featureFlags.js +12 -5
  106. package/src/fuzzySearch.test.js +10 -0
  107. package/src/index.js +15 -3
  108. package/src/lib/components/ui/alert/alert-action.jsx +11 -0
  109. package/src/lib/components/ui/alert/alert-description.jsx +11 -0
  110. package/src/lib/components/ui/alert/alert-title.jsx +11 -0
  111. package/src/lib/components/ui/alert/alert.jsx +25 -0
  112. package/src/lib/components/ui/alert/index.js +15 -15
  113. package/src/lib/components/ui/avatar/avatar-badge.jsx +22 -0
  114. package/src/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
  115. package/src/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
  116. package/src/lib/components/ui/avatar/avatar-group.jsx +19 -0
  117. package/src/lib/components/ui/avatar/avatar-image.jsx +15 -0
  118. package/src/lib/components/ui/avatar/avatar.jsx +19 -0
  119. package/src/lib/components/ui/avatar/index.js +20 -20
  120. package/src/lib/components/ui/badge/badge.jsx +31 -0
  121. package/src/lib/components/ui/badge/index.js +2 -2
  122. package/src/lib/components/ui/button/button.jsx +100 -0
  123. package/src/lib/components/ui/button/index.js +9 -9
  124. package/src/lib/components/ui/card/card-action.jsx +11 -0
  125. package/src/lib/components/ui/card/card-content.jsx +11 -0
  126. package/src/lib/components/ui/card/card-description.jsx +11 -0
  127. package/src/lib/components/ui/card/card-footer.jsx +11 -0
  128. package/src/lib/components/ui/card/card-header.jsx +19 -0
  129. package/src/lib/components/ui/card/card-title.jsx +11 -0
  130. package/src/lib/components/ui/card/card.jsx +17 -0
  131. package/src/lib/components/ui/card/index.js +23 -23
  132. package/src/lib/components/ui/checkbox/checkbox.jsx +29 -0
  133. package/src/lib/components/ui/checkbox/index.js +5 -5
  134. package/src/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
  135. package/src/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
  136. package/src/lib/components/ui/collapsible/collapsible.jsx +7 -0
  137. package/src/lib/components/ui/collapsible/index.js +11 -11
  138. package/src/lib/components/ui/dialog/dialog-close.jsx +7 -0
  139. package/src/lib/components/ui/dialog/dialog-content.jsx +34 -0
  140. package/src/lib/components/ui/dialog/dialog-description.jsx +15 -0
  141. package/src/lib/components/ui/dialog/dialog-footer.jsx +23 -0
  142. package/src/lib/components/ui/dialog/dialog-header.jsx +11 -0
  143. package/src/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
  144. package/src/lib/components/ui/dialog/dialog-portal.jsx +4 -0
  145. package/src/lib/components/ui/dialog/dialog-title.jsx +15 -0
  146. package/src/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
  147. package/src/lib/components/ui/dialog/dialog.jsx +4 -0
  148. package/src/lib/components/ui/dialog/index.js +32 -32
  149. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
  150. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
  151. package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
  152. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
  153. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
  154. package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
  155. package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
  156. package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
  157. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
  158. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
  159. package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
  160. package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
  161. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
  162. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
  163. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
  164. package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
  165. package/src/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
  166. package/src/lib/components/ui/dropdown-menu/index.js +52 -52
  167. package/src/lib/components/ui/input/index.js +5 -5
  168. package/src/lib/components/ui/input/input.jsx +19 -0
  169. package/src/lib/components/ui/label/index.js +5 -5
  170. package/src/lib/components/ui/label/label.jsx +19 -0
  171. package/src/lib/components/ui/panel/index.js +21 -21
  172. package/src/lib/components/ui/panel/panel-body.jsx +11 -0
  173. package/src/lib/components/ui/panel/panel-close.jsx +16 -0
  174. package/src/lib/components/ui/panel/panel-content.jsx +29 -0
  175. package/src/lib/components/ui/panel/panel-footer.jsx +11 -0
  176. package/src/lib/components/ui/panel/panel-header.jsx +11 -0
  177. package/src/lib/components/ui/panel/panel-title.jsx +12 -0
  178. package/src/lib/components/ui/panel/panel.jsx +4 -0
  179. package/src/lib/components/ui/popover/index.js +26 -26
  180. package/src/lib/components/ui/popover/popover-close.jsx +7 -0
  181. package/src/lib/components/ui/popover/popover-content.jsx +22 -0
  182. package/src/lib/components/ui/popover/popover-description.jsx +11 -0
  183. package/src/lib/components/ui/popover/popover-header.jsx +11 -0
  184. package/src/lib/components/ui/popover/popover-portal.jsx +4 -0
  185. package/src/lib/components/ui/popover/popover-title.jsx +11 -0
  186. package/src/lib/components/ui/popover/popover-trigger.jsx +8 -0
  187. package/src/lib/components/ui/popover/popover.jsx +4 -0
  188. package/src/lib/components/ui/searchable-list.jsx +160 -0
  189. package/src/lib/components/ui/select/index.js +35 -35
  190. package/src/lib/components/ui/select/select-content.jsx +30 -0
  191. package/src/lib/components/ui/select/select-group-heading.jsx +17 -0
  192. package/src/lib/components/ui/select/select-group.jsx +15 -0
  193. package/src/lib/components/ui/select/select-item.jsx +26 -0
  194. package/src/lib/components/ui/select/select-label.jsx +11 -0
  195. package/src/lib/components/ui/select/select-portal.jsx +4 -0
  196. package/src/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
  197. package/src/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
  198. package/src/lib/components/ui/select/select-separator.jsx +15 -0
  199. package/src/lib/components/ui/select/select-trigger.jsx +25 -0
  200. package/src/lib/components/ui/select/select.jsx +4 -0
  201. package/src/lib/components/ui/separator/index.js +5 -5
  202. package/src/lib/components/ui/separator/separator.jsx +22 -0
  203. package/src/lib/components/ui/sheet/index.js +32 -32
  204. package/src/lib/components/ui/sheet/sheet-close.jsx +7 -0
  205. package/src/lib/components/ui/sheet/sheet-content.jsx +35 -0
  206. package/src/lib/components/ui/sheet/sheet-description.jsx +15 -0
  207. package/src/lib/components/ui/sheet/sheet-footer.jsx +11 -0
  208. package/src/lib/components/ui/sheet/sheet-header.jsx +11 -0
  209. package/src/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
  210. package/src/lib/components/ui/sheet/sheet-portal.jsx +4 -0
  211. package/src/lib/components/ui/sheet/sheet-title.jsx +15 -0
  212. package/src/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
  213. package/src/lib/components/ui/sheet/sheet.jsx +4 -0
  214. package/src/lib/components/ui/textarea/index.js +5 -5
  215. package/src/lib/components/ui/textarea/textarea.jsx +18 -0
  216. package/src/lib/components/ui/toggle/index.js +6 -9
  217. package/src/lib/components/ui/toggle/toggle.jsx +36 -0
  218. package/src/lib/components/ui/toggle-group/index.js +8 -8
  219. package/src/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
  220. package/src/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
  221. package/src/lib/components/ui/tooltip/index.js +3 -3
  222. package/src/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
  223. package/src/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
  224. package/src/lib/components/ui/tooltip/tooltip.jsx +11 -0
  225. package/src/lib/components/ui/trigger-button/index.js +3 -3
  226. package/src/lib/components/ui/trigger-button/trigger-button.css +38 -0
  227. package/src/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
  228. package/src/logger/devLogger.js +238 -0
  229. package/src/logger/devLogger.test.js +193 -0
  230. package/src/modes.test.js +4 -4
  231. package/src/mountStoryboardCore.js +133 -35
  232. package/src/paletteProviders.js +3 -0
  233. package/src/paletteProviders.test.js +2 -2
  234. package/src/server/index.js +104 -40
  235. package/src/sidepanel.css +214 -0
  236. package/src/smoothCorners.js +1 -1
  237. package/src/styles/tailwind.css +1 -1
  238. package/src/svelte-plugin-ui/__tests__/ModeSwitch.test.ts +8 -8
  239. package/src/svelte-plugin-ui/__tests__/ToolbarShell.test.ts +11 -10
  240. package/src/svelte-plugin-ui/components/Icon.css +11 -0
  241. package/src/svelte-plugin-ui/components/Icon.jsx +281 -0
  242. package/src/svelte-plugin-ui/components/ModeSwitch.css +90 -0
  243. package/src/svelte-plugin-ui/components/ModeSwitch.jsx +47 -0
  244. package/src/svelte-plugin-ui/components/ToolbarShell.css +80 -0
  245. package/src/svelte-plugin-ui/components/ToolbarShell.jsx +84 -0
  246. package/src/svelte-plugin-ui/components/Viewfinder.css +412 -0
  247. package/src/svelte-plugin-ui/components/Viewfinder.jsx +513 -0
  248. package/src/svelte-plugin-ui/mount.ts +12 -16
  249. package/src/toolRegistry.js +4 -4
  250. package/src/toolbarConfigStore.js +30 -0
  251. package/src/tools/handlers/autosync.js +1 -1
  252. package/src/tools/handlers/canvasAddWidget.js +1 -1
  253. package/src/tools/handlers/canvasAgents.js +20 -0
  254. package/src/tools/handlers/canvasToolbar.js +8 -8
  255. package/src/tools/handlers/commandPalette.js +9 -0
  256. package/src/tools/handlers/comments.js +2 -2
  257. package/src/tools/handlers/create.js +1 -1
  258. package/src/tools/handlers/devtools.js +19 -3
  259. package/src/tools/handlers/devtools.test.js +38 -0
  260. package/src/tools/handlers/featureFlags.js +1 -1
  261. package/src/tools/handlers/flows.js +3 -3
  262. package/src/tools/handlers/hideChrome.js +9 -0
  263. package/src/tools/handlers/paletteTheme.js +35 -0
  264. package/src/tools/handlers/theme.js +1 -1
  265. package/src/tools/registry.js +4 -1
  266. package/src/tools/surfaces/commandList.js +3 -3
  267. package/src/tools/surfaces/mainToolbar.js +3 -3
  268. package/src/tools/surfaces/registry.js +4 -4
  269. package/src/ui/design-modes.ts +2 -2
  270. package/src/ui/viewfinder.ts +1 -1
  271. package/src/vite/server-plugin.js +243 -61
  272. package/src/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
  273. package/src/workshop/features/createCanvas/index.js +1 -1
  274. package/src/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
  275. package/src/workshop/features/createFlow/index.js +1 -1
  276. package/src/workshop/features/createPage/CreatePageForm.jsx +304 -0
  277. package/src/workshop/features/createPage/index.js +1 -1
  278. package/src/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
  279. package/src/workshop/features/createPrototype/index.js +1 -1
  280. package/src/workshop/features/createPrototype/server.js +98 -0
  281. package/src/workshop/features/createStory/CreateStoryForm.jsx +208 -0
  282. package/src/workshop/features/createStory/index.js +1 -1
  283. package/src/workshop/ui/WorkshopPanel.jsx +98 -0
  284. package/src/workshop/ui/mount.ts +1 -1
  285. package/src/worktree/port.js +48 -0
  286. package/src/worktree/serverRegistry.js +120 -0
  287. package/toolbar.config.json +93 -42
  288. package/widgets.config.json +580 -12
  289. package/scaffold/commandpalette.config.json +0 -4
  290. package/scaffold/toolbar.config.json +0 -4
  291. package/src/ActionMenuButton.svelte +0 -119
  292. package/src/AutosyncMenuButton.svelte +0 -397
  293. package/src/CanvasCreateMenu.svelte +0 -295
  294. package/src/CanvasSnap.svelte +0 -87
  295. package/src/CanvasUndoRedo.svelte +0 -108
  296. package/src/CanvasZoomControl.svelte +0 -111
  297. package/src/CanvasZoomToFit.svelte +0 -52
  298. package/src/CommandMenu.svelte +0 -249
  299. package/src/CommandPalette.svelte +0 -33
  300. package/src/CommentsMenuButton.svelte +0 -53
  301. package/src/CoreUIBar.svelte +0 -847
  302. package/src/CreateMenuButton.svelte +0 -133
  303. package/src/DocPanel.svelte +0 -299
  304. package/src/InspectorPanel.svelte +0 -745
  305. package/src/PwaInstallBanner.svelte +0 -124
  306. package/src/SidePanel.svelte +0 -480
  307. package/src/ThemeMenuButton.svelte +0 -132
  308. package/src/comments/ui/AuthModal.svelte +0 -108
  309. package/src/comments/ui/CommentWindow.svelte +0 -333
  310. package/src/comments/ui/CommentsDrawer.svelte +0 -96
  311. package/src/comments/ui/Composer.svelte +0 -65
  312. package/src/lib/components/ui/alert/alert-action.svelte +0 -19
  313. package/src/lib/components/ui/alert/alert-description.svelte +0 -22
  314. package/src/lib/components/ui/alert/alert-title.svelte +0 -22
  315. package/src/lib/components/ui/alert/alert.svelte +0 -38
  316. package/src/lib/components/ui/avatar/avatar-badge.svelte +0 -25
  317. package/src/lib/components/ui/avatar/avatar-fallback.svelte +0 -20
  318. package/src/lib/components/ui/avatar/avatar-group-count.svelte +0 -22
  319. package/src/lib/components/ui/avatar/avatar-group.svelte +0 -22
  320. package/src/lib/components/ui/avatar/avatar-image.svelte +0 -17
  321. package/src/lib/components/ui/avatar/avatar.svelte +0 -24
  322. package/src/lib/components/ui/badge/badge.svelte +0 -44
  323. package/src/lib/components/ui/button/button.svelte +0 -108
  324. package/src/lib/components/ui/card/card-action.svelte +0 -21
  325. package/src/lib/components/ui/card/card-content.svelte +0 -19
  326. package/src/lib/components/ui/card/card-description.svelte +0 -19
  327. package/src/lib/components/ui/card/card-footer.svelte +0 -18
  328. package/src/lib/components/ui/card/card-header.svelte +0 -21
  329. package/src/lib/components/ui/card/card-title.svelte +0 -14
  330. package/src/lib/components/ui/card/card.svelte +0 -21
  331. package/src/lib/components/ui/checkbox/checkbox.svelte +0 -39
  332. package/src/lib/components/ui/collapsible/collapsible-content.svelte +0 -7
  333. package/src/lib/components/ui/collapsible/collapsible-trigger.svelte +0 -7
  334. package/src/lib/components/ui/collapsible/collapsible.svelte +0 -11
  335. package/src/lib/components/ui/dialog/dialog-close.svelte +0 -11
  336. package/src/lib/components/ui/dialog/dialog-content.svelte +0 -42
  337. package/src/lib/components/ui/dialog/dialog-description.svelte +0 -17
  338. package/src/lib/components/ui/dialog/dialog-footer.svelte +0 -29
  339. package/src/lib/components/ui/dialog/dialog-header.svelte +0 -19
  340. package/src/lib/components/ui/dialog/dialog-overlay.svelte +0 -17
  341. package/src/lib/components/ui/dialog/dialog-portal.svelte +0 -7
  342. package/src/lib/components/ui/dialog/dialog-title.svelte +0 -17
  343. package/src/lib/components/ui/dialog/dialog-trigger.svelte +0 -11
  344. package/src/lib/components/ui/dialog/dialog.svelte +0 -7
  345. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +0 -16
  346. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -40
  347. package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -27
  348. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -18
  349. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
  350. package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -24
  351. package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -20
  352. package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +0 -7
  353. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
  354. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -34
  355. package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
  356. package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -19
  357. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -17
  358. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -27
  359. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +0 -7
  360. package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
  361. package/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +0 -7
  362. package/src/lib/components/ui/input/input.svelte +0 -40
  363. package/src/lib/components/ui/label/label.svelte +0 -20
  364. package/src/lib/components/ui/panel/panel-body.svelte +0 -13
  365. package/src/lib/components/ui/panel/panel-close.svelte +0 -16
  366. package/src/lib/components/ui/panel/panel-content.svelte +0 -33
  367. package/src/lib/components/ui/panel/panel-footer.svelte +0 -13
  368. package/src/lib/components/ui/panel/panel-header.svelte +0 -16
  369. package/src/lib/components/ui/panel/panel-title.svelte +0 -14
  370. package/src/lib/components/ui/panel/panel.svelte +0 -15
  371. package/src/lib/components/ui/popover/popover-close.svelte +0 -7
  372. package/src/lib/components/ui/popover/popover-content.svelte +0 -27
  373. package/src/lib/components/ui/popover/popover-description.svelte +0 -19
  374. package/src/lib/components/ui/popover/popover-header.svelte +0 -19
  375. package/src/lib/components/ui/popover/popover-portal.svelte +0 -7
  376. package/src/lib/components/ui/popover/popover-title.svelte +0 -19
  377. package/src/lib/components/ui/popover/popover-trigger.svelte +0 -17
  378. package/src/lib/components/ui/popover/popover.svelte +0 -7
  379. package/src/lib/components/ui/select/select-content.svelte +0 -40
  380. package/src/lib/components/ui/select/select-group-heading.svelte +0 -19
  381. package/src/lib/components/ui/select/select-group.svelte +0 -17
  382. package/src/lib/components/ui/select/select-item.svelte +0 -38
  383. package/src/lib/components/ui/select/select-label.svelte +0 -18
  384. package/src/lib/components/ui/select/select-portal.svelte +0 -7
  385. package/src/lib/components/ui/select/select-scroll-down-button.svelte +0 -20
  386. package/src/lib/components/ui/select/select-scroll-up-button.svelte +0 -20
  387. package/src/lib/components/ui/select/select-separator.svelte +0 -17
  388. package/src/lib/components/ui/select/select-trigger.svelte +0 -27
  389. package/src/lib/components/ui/select/select.svelte +0 -11
  390. package/src/lib/components/ui/separator/separator.svelte +0 -23
  391. package/src/lib/components/ui/sheet/sheet-close.svelte +0 -7
  392. package/src/lib/components/ui/sheet/sheet-content.svelte +0 -43
  393. package/src/lib/components/ui/sheet/sheet-description.svelte +0 -17
  394. package/src/lib/components/ui/sheet/sheet-footer.svelte +0 -18
  395. package/src/lib/components/ui/sheet/sheet-header.svelte +0 -19
  396. package/src/lib/components/ui/sheet/sheet-overlay.svelte +0 -17
  397. package/src/lib/components/ui/sheet/sheet-portal.svelte +0 -7
  398. package/src/lib/components/ui/sheet/sheet-title.svelte +0 -17
  399. package/src/lib/components/ui/sheet/sheet-trigger.svelte +0 -7
  400. package/src/lib/components/ui/sheet/sheet.svelte +0 -7
  401. package/src/lib/components/ui/textarea/textarea.svelte +0 -21
  402. package/src/lib/components/ui/toggle/toggle.svelte +0 -45
  403. package/src/lib/components/ui/toggle-group/toggle-group-item.svelte +0 -35
  404. package/src/lib/components/ui/toggle-group/toggle-group.svelte +0 -63
  405. package/src/lib/components/ui/tooltip/tooltip-content.svelte +0 -24
  406. package/src/lib/components/ui/tooltip/tooltip-trigger.svelte +0 -27
  407. package/src/lib/components/ui/tooltip/tooltip.svelte +0 -9
  408. package/src/lib/components/ui/trigger-button/trigger-button.svelte +0 -106
  409. package/src/svelte-plugin-ui/components/Icon.svelte +0 -181
  410. package/src/svelte-plugin-ui/components/ModeSwitch.svelte +0 -121
  411. package/src/svelte-plugin-ui/components/ToolbarShell.svelte +0 -150
  412. package/src/svelte-plugin-ui/components/Viewfinder.svelte +0 -1001
  413. package/src/tools/handlers/docs.js +0 -11
  414. package/src/workshop/features/createCanvas/CreateCanvasForm.svelte +0 -139
  415. package/src/workshop/features/createFlow/CreateFlowForm.svelte +0 -314
  416. package/src/workshop/features/createPage/CreatePageForm.svelte +0 -249
  417. package/src/workshop/features/createPrototype/CreatePrototypeForm.svelte +0 -287
  418. package/src/workshop/features/createStory/CreateStoryForm.svelte +0 -161
  419. package/src/workshop/ui/WorkshopPanel.svelte +0 -97
@@ -0,0 +1,632 @@
1
+ /**
2
+ * InspectorPanel — Inspector tab for the side panel.
3
+ * Select DOM elements and view their React component information.
4
+ * Uses mouseMode for element selection and fiberWalker for component introspection.
5
+ */
6
+
7
+ import './InspectorPanel.css'
8
+ import { useState, useEffect, useRef, useMemo, useCallback } from 'react'
9
+ import octicons from '@primer/octicons'
10
+ import { inspectElement, inspectElementChain } from './inspector/fiberWalker.js'
11
+ import { createMouseMode } from './inspector/mouseMode.js'
12
+ import { getColors, createInspectorHighlighter } from './inspector/highlighter.js'
13
+
14
+ // ── Inline icon helpers ─────────────────────────────────────────
15
+
16
+ function OcticonSvg({ name, size = 16, className, style }) {
17
+ const icon = octicons[name]
18
+ if (!icon) return null
19
+ const svg = icon.toSVG({ width: size, height: size }).replace('<svg ', '<svg fill="currentColor" ')
20
+ return <span className={className} style={{ display: 'inline-flex', alignItems: 'center', ...style }} dangerouslySetInnerHTML={{ __html: svg }} />
21
+ }
22
+
23
+ function IconoirSquareDashed({ size = 48 }) {
24
+ return (
25
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round">
26
+ <path d="M7 2H5a3 3 0 00-3 3v2M17 2h2a3 3 0 013 3v2M17 22h2a3 3 0 003-3v-2M7 22H5a3 3 0 01-3-3v-2" />
27
+ </svg>
28
+ )
29
+ }
30
+
31
+ // ── Constants ───────────────────────────────────────────────────
32
+
33
+ const _isLocalDev = typeof window !== 'undefined' && window.__SB_LOCAL_DEV__ === true && !new URLSearchParams(window.location.search).has('prodMode')
34
+ const _basePath = (typeof window !== 'undefined' && window.__STORYBOARD_BASE_PATH__) || '/'
35
+
36
+ // ── URL state helpers ───────────────────────────────────────────
37
+
38
+ function generateSelector(el) {
39
+ if (!(el instanceof Element)) return null
40
+ if (el.id) return `#${CSS.escape(el.id)}`
41
+
42
+ const testId = el.getAttribute('data-testid')
43
+ if (testId) return `[data-testid="${CSS.escape(testId)}"]`
44
+
45
+ const parts = []
46
+ let cur = el
47
+ while (cur && cur !== document.body && cur !== document.documentElement) {
48
+ let seg = cur.tagName.toLowerCase()
49
+ if (cur.id) {
50
+ parts.unshift(`#${CSS.escape(cur.id)}`)
51
+ break
52
+ }
53
+ const parent = cur.parentElement
54
+ if (parent) {
55
+ const siblings = Array.from(parent.children)
56
+ const idx = siblings.indexOf(cur) + 1
57
+ seg += `:nth-child(${idx})`
58
+ }
59
+ parts.unshift(seg)
60
+ cur = parent
61
+ }
62
+ return parts.length ? parts.join(' > ') : null
63
+ }
64
+
65
+ function getInspectParam() {
66
+ try {
67
+ return new URL(window.location.href).searchParams.get('inspect')
68
+ } catch { return null }
69
+ }
70
+
71
+ function setInspectParam(selector) {
72
+ try {
73
+ const url = new URL(window.location.href)
74
+ if (selector) {
75
+ url.searchParams.set('inspect', selector)
76
+ } else {
77
+ url.searchParams.delete('inspect')
78
+ }
79
+ history.replaceState(history.state, '', url.toString())
80
+ } catch { /* ignore */ }
81
+ }
82
+
83
+ // ── Source file helpers ─────────────────────────────────────────
84
+
85
+ let staticInspectorData = null
86
+
87
+ async function loadStaticData() {
88
+ if (staticInspectorData) return staticInspectorData
89
+ try {
90
+ const basePath = window.__STORYBOARD_BASE_PATH__ || '/'
91
+ const res = await fetch(`${basePath}_storyboard/inspector.json`)
92
+ if (res.ok) {
93
+ staticInspectorData = await res.json()
94
+ return staticInspectorData
95
+ }
96
+ } catch { /* ignore */ }
97
+ return null
98
+ }
99
+
100
+ async function fetchSourceContent(filePath) {
101
+ if (_isLocalDev) {
102
+ try {
103
+ const res = await fetch(`${_basePath.replace(/\/$/, '')}/_storyboard/docs/source?path=${encodeURIComponent(filePath)}`)
104
+ if (res.ok) {
105
+ const json = await res.json()
106
+ return json?.content || ''
107
+ }
108
+ } catch { /* ignore */ }
109
+ }
110
+ const data = await loadStaticData()
111
+ return data?.sources?.[filePath] || ''
112
+ }
113
+
114
+ function getLang(filePath) {
115
+ if (filePath.endsWith('.tsx')) return 'tsx'
116
+ if (filePath.endsWith('.jsx')) return 'jsx'
117
+ if (filePath.endsWith('.ts')) return 'typescript'
118
+ return 'javascript'
119
+ }
120
+
121
+ function findComponentLine(code, info) {
122
+ if (!code || !info?.name) return -1
123
+
124
+ const lines = code.split('\n')
125
+ const name = info.name
126
+ const props = info.props || {}
127
+
128
+ const propSignatures = []
129
+ for (const [key, val] of Object.entries(props)) {
130
+ if (key === 'children') continue
131
+ if (typeof val === 'string') {
132
+ propSignatures.push(`"${val}"`, `'${val}'`, `\`${val}\``, `="${val}"`, `='${val}'`)
133
+ } else if (typeof val === 'number' || typeof val === 'boolean') {
134
+ propSignatures.push(`{${val}}`, `=${val}`)
135
+ }
136
+ }
137
+
138
+ const tagPattern = new RegExp(`<${name}[\\s/>]`)
139
+ const candidates = []
140
+ for (let i = 0; i < lines.length; i++) {
141
+ if (tagPattern.test(lines[i])) {
142
+ candidates.push(i)
143
+ }
144
+ }
145
+
146
+ if (candidates.length === 0) return -1
147
+ if (candidates.length === 1) return candidates[0] + 1
148
+
149
+ let bestLine = candidates[0]
150
+ let bestScore = -1
151
+
152
+ for (const lineIdx of candidates) {
153
+ const windowSlice = lines.slice(lineIdx, lineIdx + 6).join(' ')
154
+ let score = 0
155
+ for (const sig of propSignatures) {
156
+ if (windowSlice.includes(sig)) score++
157
+ }
158
+ if (score > bestScore) {
159
+ bestScore = score
160
+ bestLine = lineIdx
161
+ }
162
+ }
163
+
164
+ return bestLine + 1
165
+ }
166
+
167
+ function resolveSourceFile(info, knownFiles) {
168
+ if (info?.source?.fileName) {
169
+ const cleanName = info.source.fileName.split('?')[0]
170
+ const srcIndex = cleanName.indexOf('/src/')
171
+ if (srcIndex !== -1) return cleanName.slice(srcIndex + 1)
172
+ if (cleanName.startsWith('src/')) return cleanName
173
+ }
174
+
175
+ const pageFile = resolvePageFile(knownFiles)
176
+ if (pageFile) return pageFile
177
+
178
+ const name = info?.name
179
+ if (name && name !== 'Anonymous' && name !== 'Unknown') {
180
+ const match = knownFiles.find(f => {
181
+ const base = f.split('/').pop()?.replace(/\.(jsx|tsx|js|ts)$/, '')
182
+ return base === name
183
+ })
184
+ if (match) return match
185
+ }
186
+
187
+ return null
188
+ }
189
+
190
+ function resolvePageFile(knownFiles) {
191
+ if (knownFiles.length === 0) return null
192
+
193
+ let pathname = window.location.pathname
194
+ if (pathname.startsWith('/')) pathname = pathname.slice(1)
195
+ pathname = pathname.replace(/\/$/, '')
196
+
197
+ const normalizedFiles = knownFiles.map(f => ({
198
+ original: f,
199
+ normalized: f
200
+ .replace(/^src\/prototypes\//, '')
201
+ .replace(/[^/]*\.folder\//g, '')
202
+ .replace(/\.(jsx|tsx|js|ts)$/, ''),
203
+ }))
204
+
205
+ const segments = pathname.split('/').filter(Boolean)
206
+ for (let start = 0; start < segments.length; start++) {
207
+ const routeEnd = segments.slice(start).join('/')
208
+ if (!routeEnd) continue
209
+
210
+ for (const { original, normalized } of normalizedFiles) {
211
+ const withoutIndex = normalized.replace(/\/index$/, '')
212
+ if (withoutIndex === routeEnd || normalized === routeEnd) return original
213
+ }
214
+ }
215
+
216
+ if (!pathname || segments.length === 0) {
217
+ const idx = knownFiles.find(f => /^src\/prototypes\/index\.(jsx|tsx|js|ts)$/.test(f))
218
+ if (idx) return idx
219
+ }
220
+
221
+ return null
222
+ }
223
+
224
+ // ── Component ───────────────────────────────────────────────────
225
+
226
+ export default function InspectorPanel() {
227
+ const [componentInfo, setComponentInfo] = useState(null)
228
+ const [componentChain, setComponentChain] = useState([])
229
+ const [inspecting, setInspecting] = useState(false)
230
+ const [sourceCode, setSourceCode] = useState('')
231
+ const [sourceLoading, setSourceLoading] = useState(false)
232
+ const [sourcePath, setSourcePath] = useState('')
233
+ const [matchedLine, setMatchedLine] = useState(-1)
234
+ const [highlightedHtml, setHighlightedHtml] = useState('')
235
+ const [codeTheme, setCodeTheme] = useState(getColors)
236
+ const [repoInfo, setRepoInfo] = useState(null)
237
+
238
+ const sourceContainerRef = useRef(null)
239
+ const mouseModeRef = useRef(null)
240
+ const knownFilesRef = useRef([])
241
+ const highlighterRef = useRef(null)
242
+
243
+ const hasSelection = componentInfo !== null
244
+
245
+ const gitBranch = useMemo(() => {
246
+ const m = window.location.pathname.match(/\/branch--([^/]+)/)
247
+ if (m) return m[1].replace(/-/g, '/')
248
+ return 'main'
249
+ }, [])
250
+
251
+ const githubUrl = useMemo(() => {
252
+ if (!repoInfo || !sourcePath) return null
253
+ const base = `https://github.com/${repoInfo.owner}/${repoInfo.name}/blob/${gitBranch}/${sourcePath}`
254
+ const line = matchedLine > 0 ? matchedLine : componentInfo?.source?.lineNumber
255
+ return line ? `${base}#L${line}` : base
256
+ }, [repoInfo, sourcePath, gitBranch, matchedLine, componentInfo])
257
+
258
+ async function getHighlighter() {
259
+ if (highlighterRef.current) return highlighterRef.current
260
+ highlighterRef.current = await createInspectorHighlighter()
261
+ return highlighterRef.current
262
+ }
263
+
264
+ const rehighlight = useCallback(async () => {
265
+ setCodeTheme(getColors())
266
+ }, [])
267
+
268
+ // Handle element selection
269
+ const _handleSelect = useCallback((el) => {
270
+ const info = inspectElement(el)
271
+ const chain = inspectElementChain(el)
272
+ setComponentInfo(info)
273
+ setComponentChain(chain)
274
+ setInspecting(false)
275
+ mouseModeRef.current?.showHighlight(el)
276
+ setInspectParam(generateSelector(el))
277
+ }, [])
278
+
279
+ const _handleDeactivate = useCallback(() => {
280
+ setInspecting(false)
281
+ }, [])
282
+ void _handleSelect
283
+ void _handleDeactivate
284
+
285
+ const startInspecting = useCallback(() => {
286
+ mouseModeRef.current?.hideHighlight()
287
+ mouseModeRef.current?.activate()
288
+ setInspecting(true)
289
+ setInspectParam(null)
290
+ }, [])
291
+
292
+ const stopInspecting = useCallback(() => {
293
+ mouseModeRef.current?.deactivate()
294
+ setInspecting(false)
295
+ }, [])
296
+
297
+ // Mount: create mouse mode, fetch files, restore selection
298
+ useEffect(() => {
299
+ const mouseMode = createMouseMode({
300
+ onSelect: (el) => {
301
+ const info = inspectElement(el)
302
+ const chain = inspectElementChain(el)
303
+ setComponentInfo(info)
304
+ setComponentChain(chain)
305
+ setInspecting(false)
306
+ mouseMode.showHighlight(el)
307
+ setInspectParam(generateSelector(el))
308
+ },
309
+ onDeactivate: () => setInspecting(false),
310
+ })
311
+ mouseModeRef.current = mouseMode
312
+
313
+ document.addEventListener('storyboard:theme:changed', rehighlight)
314
+
315
+ ;(async () => {
316
+ let filesLoaded = false
317
+ if (_isLocalDev) {
318
+ try {
319
+ const [filesRes, repoRes] = await Promise.all([
320
+ fetch(`${_basePath.replace(/\/$/, '')}/_storyboard/docs/files`),
321
+ fetch(`${_basePath.replace(/\/$/, '')}/_storyboard/docs/repo`),
322
+ ])
323
+ if (filesRes.ok) {
324
+ const data = await filesRes.json()
325
+ knownFilesRef.current = data.files || []
326
+ filesLoaded = true
327
+ }
328
+ if (repoRes.ok) {
329
+ setRepoInfo(await repoRes.json())
330
+ }
331
+ } catch { /* ignore */ }
332
+ }
333
+
334
+ if (!filesLoaded) {
335
+ const data = await loadStaticData()
336
+ if (data) {
337
+ knownFilesRef.current = data.files || []
338
+ setRepoInfo(data.repo || null)
339
+ }
340
+ }
341
+
342
+ // Restore inspector selection from URL param
343
+ const savedSelector = getInspectParam()
344
+ let restored = false
345
+ if (savedSelector) {
346
+ for (let attempt = 0; attempt < 5 && !restored; attempt++) {
347
+ if (attempt > 0) await new Promise(r => setTimeout(r, 300))
348
+ try {
349
+ const el = document.querySelector(savedSelector)
350
+ if (el) {
351
+ const info = inspectElement(el)
352
+ const chain = inspectElementChain(el)
353
+ setComponentInfo(info)
354
+ setComponentChain(chain)
355
+ mouseMode.showHighlight(el)
356
+ restored = true
357
+ }
358
+ } catch {
359
+ break
360
+ }
361
+ }
362
+ if (!restored) setInspectParam(null)
363
+ }
364
+
365
+ if (!restored) {
366
+ mouseMode.hideHighlight()
367
+ mouseMode.activate()
368
+ setInspecting(true)
369
+ setInspectParam(null)
370
+ }
371
+ })()
372
+
373
+ return () => {
374
+ mouseMode.deactivate()
375
+ mouseMode.hideHighlight()
376
+ setInspectParam(null)
377
+ document.removeEventListener('storyboard:theme:changed', rehighlight)
378
+ }
379
+ }, []) // eslint-disable-line react-hooks/exhaustive-deps
380
+
381
+ // Load source when componentInfo changes
382
+ useEffect(() => {
383
+ if (!componentInfo) {
384
+ // eslint-disable-next-line react-hooks/set-state-in-effect
385
+ setSourceCode('')
386
+ setSourcePath('')
387
+ setHighlightedHtml('')
388
+ return
389
+ }
390
+
391
+ const path = resolveSourceFile(componentInfo, knownFilesRef.current)
392
+ if (!path) {
393
+ setSourceCode('')
394
+ setSourcePath('')
395
+ setHighlightedHtml('')
396
+ return
397
+ }
398
+
399
+ let cancelled = false
400
+ setSourceLoading(true)
401
+ setSourcePath(path)
402
+ setHighlightedHtml('')
403
+
404
+ fetchSourceContent(path)
405
+ .then(async (content) => {
406
+ if (cancelled) return
407
+ setSourceCode(content)
408
+ let line = findComponentLine(content, componentInfo)
409
+ if (line < 0 && componentChain.length > 0) {
410
+ for (const ancestor of componentChain) {
411
+ line = findComponentLine(content, { name: ancestor.name, props: {} })
412
+ if (line > 0) break
413
+ }
414
+ }
415
+ setMatchedLine(line)
416
+
417
+ if (content) {
418
+ try {
419
+ const hl = await getHighlighter()
420
+ if (cancelled) return
421
+ const html = hl.codeToHtml(content, {
422
+ lang: getLang(path),
423
+ theme: 'github-dark',
424
+ lineNumbers: false,
425
+ decorations: line > 0
426
+ ? [{ start: { line: line - 1, character: 0 }, end: { line: line - 1, character: Infinity }, properties: { class: 'highlighted-line' } }]
427
+ : [],
428
+ })
429
+ setHighlightedHtml(html)
430
+ } catch {
431
+ setHighlightedHtml('')
432
+ }
433
+ }
434
+ setSourceLoading(false)
435
+ })
436
+ .catch(() => {
437
+ if (!cancelled) {
438
+ setSourceCode('')
439
+ setHighlightedHtml('')
440
+ setMatchedLine(-1)
441
+ setSourceLoading(false)
442
+ }
443
+ })
444
+
445
+ return () => { cancelled = true }
446
+ }, [componentInfo, componentChain])
447
+
448
+ // Scroll to highlighted line
449
+ useEffect(() => {
450
+ if (sourceContainerRef.current && highlightedHtml) {
451
+ requestAnimationFrame(() => {
452
+ const el = sourceContainerRef.current?.querySelector('.highlighted-line')
453
+ if (el) {
454
+ const targetTop = Math.max(el.offsetTop - 24, 0)
455
+ sourceContainerRef.current.scrollTo({ top: targetTop, behavior: 'smooth' })
456
+ } else if (sourceContainerRef.current) {
457
+ sourceContainerRef.current.scrollTop = 0
458
+ }
459
+ })
460
+ }
461
+ }, [highlightedHtml])
462
+
463
+ // Re-highlight when theme changes
464
+ useEffect(() => {
465
+ if (!sourceCode || !sourcePath) return
466
+ ;(async () => {
467
+ try {
468
+ const hl = await getHighlighter()
469
+ const html = hl.codeToHtml(sourceCode, {
470
+ lang: getLang(sourcePath),
471
+ theme: 'github-dark',
472
+ lineNumbers: false,
473
+ decorations: matchedLine > 0
474
+ ? [{ start: { line: matchedLine - 1, character: 0 }, end: { line: matchedLine - 1, character: Infinity }, properties: { class: 'highlighted-line' } }]
475
+ : [],
476
+ })
477
+ setHighlightedHtml(html)
478
+ } catch { /* ignore */ }
479
+ })()
480
+ }, [codeTheme]) // eslint-disable-line react-hooks/exhaustive-deps
481
+
482
+ const currentCodeTheme = codeTheme
483
+
484
+ return (
485
+ <div className="flex flex-col h-full" data-inspector-panel="">
486
+ <div className="flex-1 overflow-y-auto min-h-0 flex flex-col">
487
+ {/* Empty state */}
488
+ {!hasSelection && !inspecting && (
489
+ <div className="flex flex-col items-center justify-center h-full gap-3 px-6 py-12 text-center">
490
+ <span style={{ color: 'var(--fgColor-muted)', opacity: 0.4 }}>
491
+ <IconoirSquareDashed size={48} />
492
+ </span>
493
+ <p className="text-sm font-medium m-0" style={{ color: 'var(--fgColor-default)' }}>
494
+ Select an element to start
495
+ </p>
496
+ <p className="text-xs m-0" style={{ color: 'var(--fgColor-muted)' }}>
497
+ Click the inspect button to enter selection mode
498
+ </p>
499
+ <button
500
+ className="mt-2 px-4 py-1.5 text-xs font-medium rounded-md border-none cursor-pointer transition-colors"
501
+ style={{ background: 'var(--sb--color-purple, #7655a4)', color: '#fff' }}
502
+ onClick={startInspecting}
503
+ >
504
+ Start inspecting
505
+ </button>
506
+ </div>
507
+ )}
508
+
509
+ {/* Inspecting state */}
510
+ {inspecting && (
511
+ <div className="flex flex-col items-center justify-center h-full gap-3 px-6 py-12 text-center">
512
+ <div className="flex items-center gap-2">
513
+ <span className="inspector-pulse-dot" />
514
+ <p className="text-sm m-0" style={{ color: 'var(--fgColor-default)' }}>
515
+ Click any element on the page to inspect it
516
+ </p>
517
+ </div>
518
+ <button
519
+ className="mt-2 px-4 py-1.5 text-xs font-medium rounded-md border cursor-pointer transition-colors"
520
+ style={{
521
+ background: 'transparent',
522
+ color: 'var(--fgColor-muted)',
523
+ borderColor: 'var(--borderColor-default, var(--sb--color-border, #d1d9e0))',
524
+ }}
525
+ onClick={stopInspecting}
526
+ >
527
+ Cancel
528
+ </button>
529
+ </div>
530
+ )}
531
+
532
+ {/* Selected state */}
533
+ {hasSelection && !inspecting && (
534
+ <div className="flex flex-col flex-1 min-h-0 p-3 pt-0 gap-3">
535
+ {/* Component name */}
536
+ <div>
537
+ <h3 className="text-base font-bold m-0 inspector-mono" style={{ color: 'var(--sb--color-purple, #7655a4)' }}>
538
+ {componentInfo.name}
539
+ </h3>
540
+ </div>
541
+
542
+ {/* Source code */}
543
+ {sourcePath && (
544
+ <div
545
+ className="border rounded-md overflow-hidden flex-1 min-h-0 flex flex-col"
546
+ style={{ background: currentCodeTheme.bg, borderColor: currentCodeTheme.border }}
547
+ >
548
+ <div
549
+ className="flex items-center justify-between w-full px-3 py-1.5 text-xs font-semibold shrink-0"
550
+ style={{
551
+ background: currentCodeTheme.headerBg,
552
+ color: currentCodeTheme.headerFg,
553
+ borderBottom: `1px solid ${currentCodeTheme.border}`,
554
+ }}
555
+ >
556
+ <span className="flex items-center gap-1.5 min-w-0">
557
+ <OcticonSvg name="file-code" size={12} />
558
+ <span className="truncate">{sourcePath}</span>
559
+ </span>
560
+ {githubUrl && (
561
+ <a
562
+ href={githubUrl}
563
+ target="_blank"
564
+ rel="noopener noreferrer"
565
+ className="flex items-center gap-1 shrink-0 text-xs no-underline hover:underline inspector-mono inspector-code-link"
566
+ style={{ color: currentCodeTheme.headerFg }}
567
+ >
568
+ <OcticonSvg name="mark-github" size={14} />
569
+ <span>GitHub</span>
570
+ </a>
571
+ )}
572
+ </div>
573
+
574
+ <div className="border-t flex-1 min-h-0 flex flex-col" style={{ borderColor: currentCodeTheme.border }}>
575
+ {sourceLoading ? (
576
+ <div className="px-3 py-4 text-xs text-center" style={{ color: currentCodeTheme.headerFg }}>
577
+ Loading source…
578
+ </div>
579
+ ) : sourceCode ? (
580
+ <div
581
+ className="flex-1 min-h-0 overflow-y-auto source-scroll-container"
582
+ ref={sourceContainerRef}
583
+ style={{
584
+ '--inspector-line-num-color': currentCodeTheme.comment,
585
+ '--inspector-line-hover': currentCodeTheme.lineHighlight,
586
+ }}
587
+ >
588
+ {highlightedHtml ? (
589
+ <div className="code-wrapper line-numbers" dangerouslySetInnerHTML={{ __html: highlightedHtml }} />
590
+ ) : (
591
+ <pre
592
+ className="m-0 text-xs leading-relaxed inspector-mono source-pre line-numbers"
593
+ style={{ background: currentCodeTheme.bg, color: currentCodeTheme.fg }}
594
+ >
595
+ <code>
596
+ {sourceCode.split('\n').map((line, i) => (
597
+ <span
598
+ key={i}
599
+ className={`line${matchedLine > 0 && i + 1 === matchedLine ? ' highlighted-line' : ''}`}
600
+ >
601
+ {line}
602
+ {i < sourceCode.split('\n').length - 1 ? '\n' : ''}
603
+ </span>
604
+ ))}
605
+ </code>
606
+ </pre>
607
+ )}
608
+ </div>
609
+ ) : (
610
+ <div className="px-3 py-4 text-xs text-center" style={{ color: currentCodeTheme.headerFg }}>
611
+ Unable to load source
612
+ </div>
613
+ )}
614
+ </div>
615
+ </div>
616
+ )}
617
+
618
+ {/* Re-select button */}
619
+ <button
620
+ className="flex items-center justify-center gap-1.5 w-full px-3 py-1.5 text-xs font-medium rounded-md border-none cursor-pointer transition-colors shrink-0"
621
+ style={{ background: 'var(--sb--color-purple, #7655a4)', color: '#fff' }}
622
+ onClick={startInspecting}
623
+ >
624
+ <OcticonSvg name="search" size={12} />
625
+ Re-select
626
+ </button>
627
+ </div>
628
+ )}
629
+ </div>
630
+ </div>
631
+ )
632
+ }
@@ -0,0 +1,42 @@
1
+ .pwa-banner {
2
+ position: fixed;
3
+ bottom: 5rem;
4
+ left: 1rem;
5
+ right: 1rem;
6
+ z-index: 10000;
7
+ display: flex;
8
+ align-items: center;
9
+ gap: 0.5rem;
10
+ padding: 0.75rem 1rem;
11
+ background: var(--bgColor-default, #0d1117);
12
+ color: var(--fgColor-default, #e6edf3);
13
+ border: 1px solid var(--borderColor-default, #30363d);
14
+ border-radius: 0.75rem;
15
+ font-family: "Mona Sans", -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
16
+ font-size: 0.8125rem;
17
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
18
+ }
19
+
20
+ .pwa-banner-text {
21
+ flex: 1;
22
+ }
23
+
24
+ .pwa-banner-btn {
25
+ border: none;
26
+ border-radius: 0.375rem;
27
+ padding: 0.375rem 0.75rem;
28
+ font-size: 0.8125rem;
29
+ cursor: pointer;
30
+ font-weight: 500;
31
+ }
32
+
33
+ .pwa-banner-btn.install {
34
+ background: var(--button-primary-bgColor-rest, #238636);
35
+ color: #fff;
36
+ }
37
+
38
+ .pwa-banner-btn.dismiss {
39
+ background: transparent;
40
+ color: var(--fgColor-muted, #8d96a0);
41
+ padding: 0.375rem;
42
+ }