@dfosco/storyboard-core 4.2.0-beta.2 → 4.2.0-beta.21

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