paseo-plugin-genui 0.0.0-stage → 0.1.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 (375) hide show
  1. package/LICENSE +202 -0
  2. package/OVERVIEW.md +21 -0
  3. package/README.md +77 -2
  4. package/assets/fonts/Excalifont-OFL.txt +109 -0
  5. package/assets/fonts/Excalifont-Regular-latin.woff2 +0 -0
  6. package/assets/icon.png +0 -0
  7. package/assets/icon.svg +1 -0
  8. package/assets/screenshot-chat.png +0 -0
  9. package/assets/screenshot-gallery.png +0 -0
  10. package/assets/screenshot-playground.png +0 -0
  11. package/client/components/content.tsx +468 -0
  12. package/client/components/data.tsx +967 -0
  13. package/client/components/dev.tsx +998 -0
  14. package/client/components/diagram.tsx +513 -0
  15. package/client/components/inputs.tsx +994 -0
  16. package/client/components/layout.tsx +239 -0
  17. package/client/components/media.tsx +428 -0
  18. package/client/components/project.tsx +641 -0
  19. package/client/components/widgets.tsx +836 -0
  20. package/client/gallery.tsx +449 -0
  21. package/client/live-ui.tsx +525 -0
  22. package/client/loaders.ts +342 -0
  23. package/client/markdown.tsx +172 -0
  24. package/client/node-renderer.tsx +149 -0
  25. package/client/render.tsx +186 -0
  26. package/client/runtime.ts +103 -0
  27. package/client/settings.tsx +57 -0
  28. package/client/web.ts +186 -0
  29. package/gallery/Acceptance-baseline.ui +1 -0
  30. package/gallery/Acceptance-checklist.ui +14 -0
  31. package/gallery/Acceptance-evidence.ui +9 -0
  32. package/gallery/Acceptance.ui +1 -0
  33. package/gallery/Badge.ui +3 -0
  34. package/gallery/Benchmark-context.ui +8 -0
  35. package/gallery/Benchmark-hyperfine.ui +1 -0
  36. package/gallery/Benchmark-runs-list.ui +9 -0
  37. package/gallery/Benchmark-runs.ui +1 -0
  38. package/gallery/Benchmark-vitest.ui +1 -0
  39. package/gallery/Benchmark.ui +9 -0
  40. package/gallery/Board-bb-tasks.ui +1 -0
  41. package/gallery/Board-gh-issues.ui +1 -0
  42. package/gallery/Board-gh-prs.ui +1 -0
  43. package/gallery/Board.ui +12 -0
  44. package/gallery/Button-destructive.ui +4 -0
  45. package/gallery/Button.ui +5 -0
  46. package/gallery/Calendar.ui +15 -0
  47. package/gallery/CalendarHeatmap-short.ui +11 -0
  48. package/gallery/CalendarHeatmap.ui +4 -0
  49. package/gallery/Callout.ui +4 -0
  50. package/gallery/Card.ui +4 -0
  51. package/gallery/Carousel.ui +8 -0
  52. package/gallery/Changes-paths.ui +1 -0
  53. package/gallery/Changes-uncommitted.ui +1 -0
  54. package/gallery/Changes.ui +1 -0
  55. package/gallery/Chart-area.ui +3 -0
  56. package/gallery/Chart-funnel.ui +3 -0
  57. package/gallery/Chart-heatmap.ui +11 -0
  58. package/gallery/Chart-pie.ui +3 -0
  59. package/gallery/Chart-radar.ui +3 -0
  60. package/gallery/Chart-scatter.ui +4 -0
  61. package/gallery/Chart-stacked.ui +5 -0
  62. package/gallery/Chart.ui +3 -0
  63. package/gallery/Checklist.ui +6 -0
  64. package/gallery/Choice.ui +8 -0
  65. package/gallery/Code.ui +3 -0
  66. package/gallery/Commits-limit.ui +1 -0
  67. package/gallery/Commits.ui +1 -0
  68. package/gallery/Compare-conditions.ui +4 -0
  69. package/gallery/Compare-three.ui +7 -0
  70. package/gallery/Compare.ui +4 -0
  71. package/gallery/Coverage-go.ui +1 -0
  72. package/gallery/Coverage-lcov.ui +1 -0
  73. package/gallery/Coverage-python.ui +1 -0
  74. package/gallery/Coverage.ui +1 -0
  75. package/gallery/DateInput.ui +5 -0
  76. package/gallery/Decision-percent.ui +10 -0
  77. package/gallery/Decision.ui +12 -0
  78. package/gallery/Dependencies-audit.ui +1 -0
  79. package/gallery/Dependencies-both.ui +1 -0
  80. package/gallery/Dependencies-list.ui +7 -0
  81. package/gallery/Dependencies-pip.ui +1 -0
  82. package/gallery/Dependencies-pnpm.ui +1 -0
  83. package/gallery/Dependencies.ui +1 -0
  84. package/gallery/Details.ui +4 -0
  85. package/gallery/Diagram-flow.ui +16 -0
  86. package/gallery/Diagram-sequence.ui +15 -0
  87. package/gallery/Diagram.ui +16 -0
  88. package/gallery/Diff.ui +3 -0
  89. package/gallery/Divider.ui +5 -0
  90. package/gallery/EditableTable.ui +9 -0
  91. package/gallery/Entity-list.ui +6 -0
  92. package/gallery/Entity.ui +8 -0
  93. package/gallery/Environments.ui +1 -0
  94. package/gallery/Estimate-points.ui +6 -0
  95. package/gallery/Estimate.ui +8 -0
  96. package/gallery/File.ui +4 -0
  97. package/gallery/Findings-biome.ui +1 -0
  98. package/gallery/Findings-eslint.ui +1 -0
  99. package/gallery/Findings-oxlint.ui +1 -0
  100. package/gallery/Findings-review.ui +1 -0
  101. package/gallery/Findings-ruff.ui +1 -0
  102. package/gallery/Findings-sarif.ui +1 -0
  103. package/gallery/Findings-ship.ui +11 -0
  104. package/gallery/Findings-tsc.ui +1 -0
  105. package/gallery/Findings.ui +7 -0
  106. package/gallery/Flashcards.ui +3 -0
  107. package/gallery/FollowUps.ui +4 -0
  108. package/gallery/Form.ui +8 -0
  109. package/gallery/Gallery-links.ui +8 -0
  110. package/gallery/Gallery-strip.ui +14 -0
  111. package/gallery/Gallery.ui +10 -0
  112. package/gallery/Gauge.ui +7 -0
  113. package/gallery/Grid.ui +8 -0
  114. package/gallery/Hotspots-photo.ui +8 -0
  115. package/gallery/Hotspots.ui +11 -0
  116. package/gallery/Icon.ui +5 -0
  117. package/gallery/Image.ui +4 -0
  118. package/gallery/ImageSearch-aspects.ui +6 -0
  119. package/gallery/ImageSearch.ui +4 -0
  120. package/gallery/Input.ui +5 -0
  121. package/gallery/Json-api.ui +1 -0
  122. package/gallery/Json.ui +8 -0
  123. package/gallery/KeyValue.ui +3 -0
  124. package/gallery/List-dots.ui +8 -0
  125. package/gallery/List.ui +8 -0
  126. package/gallery/ListEditor.ui +5 -0
  127. package/gallery/Logs-jsonl.ui +1 -0
  128. package/gallery/Logs-lines.ui +11 -0
  129. package/gallery/Logs-python.ui +1 -0
  130. package/gallery/Logs.ui +1 -0
  131. package/gallery/Map-city.ui +8 -0
  132. package/gallery/Map.ui +8 -0
  133. package/gallery/Metric.ui +3 -0
  134. package/gallery/OptionCards-multi.ui +10 -0
  135. package/gallery/OptionCards.ui +10 -0
  136. package/gallery/Pipeline-checks.ui +1 -0
  137. package/gallery/Pipeline-passed.ui +1 -0
  138. package/gallery/Pipeline-running.ui +1 -0
  139. package/gallery/Pipeline-stages.ui +13 -0
  140. package/gallery/Pipeline.ui +1 -0
  141. package/gallery/Plan.ui +9 -0
  142. package/gallery/Progress.ui +4 -0
  143. package/gallery/Provenance-deploy.ui +6 -0
  144. package/gallery/Provenance-no-receipt.ui +1 -0
  145. package/gallery/Provenance.ui +1 -0
  146. package/gallery/PullRequest.ui +1 -0
  147. package/gallery/Quiz.ui +6 -0
  148. package/gallery/Radio.ui +5 -0
  149. package/gallery/Rating.ui +5 -0
  150. package/gallery/Roadmap-sprint.ui +8 -0
  151. package/gallery/Roadmap-year.ui +9 -0
  152. package/gallery/Roadmap.ui +12 -0
  153. package/gallery/Row.ui +3 -0
  154. package/gallery/SegmentedBar-status.ui +8 -0
  155. package/gallery/SegmentedBar.ui +8 -0
  156. package/gallery/Select.ui +5 -0
  157. package/gallery/Slider.ui +7 -0
  158. package/gallery/Snippet.ui +3 -0
  159. package/gallery/Sources-chips.ui +4 -0
  160. package/gallery/Sources.ui +8 -0
  161. package/gallery/Sparkline.ui +6 -0
  162. package/gallery/Stack.ui +7 -0
  163. package/gallery/StackTrace-aggregate.ui +1 -0
  164. package/gallery/StackTrace-browser.ui +1 -0
  165. package/gallery/StackTrace-go.ui +1 -0
  166. package/gallery/StackTrace-java.ui +1 -0
  167. package/gallery/StackTrace-python.ui +1 -0
  168. package/gallery/StackTrace-rust.ui +1 -0
  169. package/gallery/StackTrace.ui +1 -0
  170. package/gallery/Status.ui +9 -0
  171. package/gallery/Stepper.ui +5 -0
  172. package/gallery/Steps.ui +8 -0
  173. package/gallery/Swatches-long-names.ui +4 -0
  174. package/gallery/Swatches-picker.ui +5 -0
  175. package/gallery/Swatches.ui +10 -0
  176. package/gallery/Table.ui +7 -0
  177. package/gallery/Tabs.ui +8 -0
  178. package/gallery/Tests-junit.ui +1 -0
  179. package/gallery/Tests-vitest-junit.ui +1 -0
  180. package/gallery/Tests-vitest.ui +1 -0
  181. package/gallery/Tests.ui +9 -0
  182. package/gallery/Text.ui +4 -0
  183. package/gallery/TextArea.ui +5 -0
  184. package/gallery/Threads-ids.ui +1 -0
  185. package/gallery/Threads.ui +1 -0
  186. package/gallery/Timeline.ui +8 -0
  187. package/gallery/Timer.ui +4 -0
  188. package/gallery/Toggle.ui +5 -0
  189. package/gallery/Transcript-text.ui +1 -0
  190. package/gallery/Transcript-untimed.ui +1 -0
  191. package/gallery/Transcript-whisper.ui +1 -0
  192. package/gallery/Transcript.ui +1 -0
  193. package/gallery/Tree.ui +3 -0
  194. package/gallery/Treemap-du.ui +1 -0
  195. package/gallery/Treemap-esbuild.ui +1 -0
  196. package/gallery/Treemap-tree.ui +7 -0
  197. package/gallery/Treemap.ui +18 -0
  198. package/gallery/Walkthrough.ui +9 -0
  199. package/gallery/Waterfall-har.ui +1 -0
  200. package/gallery/Waterfall-trace.ui +1 -0
  201. package/gallery/Waterfall.ui +11 -0
  202. package/gallery/data/acceptance/coil/viewport-lifecycle.json +25 -0
  203. package/gallery/data/acceptance/coil-gate.json +153 -0
  204. package/gallery/data/acceptance/orbit-baseline.json +163 -0
  205. package/gallery/data/acceptance/shots/gate-cell-opened.png +0 -0
  206. package/gallery/data/acceptance/shots/gate-light.png +0 -0
  207. package/gallery/data/acceptance/shots/gate-phone-dark.png +0 -0
  208. package/gallery/data/activity.json +1 -0
  209. package/gallery/data/bb-tasks-orb.json +420 -0
  210. package/gallery/data/biome.json +229 -0
  211. package/gallery/data/compare/status-after.png +0 -0
  212. package/gallery/data/compare/status-before.png +0 -0
  213. package/gallery/data/compare/status-dark-2x.png +0 -0
  214. package/gallery/data/compare/status-rerender.png +0 -0
  215. package/gallery/data/coverage-py.json +1 -0
  216. package/gallery/data/coverage-summary.json +1 -0
  217. package/gallery/data/coverage.out +23 -0
  218. package/gallery/data/deploys.json +1 -0
  219. package/gallery/data/device-runs.json +285 -0
  220. package/gallery/data/du-node-modules.txt +359 -0
  221. package/gallery/data/esbuild-meta.json +292 -0
  222. package/gallery/data/eslint.json +266 -0
  223. package/gallery/data/eslint.sarif +343 -0
  224. package/gallery/data/findings-review.json +76 -0
  225. package/gallery/data/gh-issues-nextjs.json +293 -0
  226. package/gallery/data/gh-pr-checks.json +272 -0
  227. package/gallery/data/gh-prs-nextjs.json +419 -0
  228. package/gallery/data/gh-run-failed.json +1 -0
  229. package/gallery/data/gh-run-passed.json +1 -0
  230. package/gallery/data/gh-run-running.json +1 -0
  231. package/gallery/data/github-release.json +57 -0
  232. package/gallery/data/hyperfine-startup.json +187 -0
  233. package/gallery/data/lcov.info +234 -0
  234. package/gallery/data/logs/media-sync.log +127 -0
  235. package/gallery/data/logs/thumbnailer.jsonl +17 -0
  236. package/gallery/data/logs/vitest-run.log +89 -0
  237. package/gallery/data/npm-audit.json +672 -0
  238. package/gallery/data/npm-outdated.json +179 -0
  239. package/gallery/data/oxlint.json +156 -0
  240. package/gallery/data/pip-outdated.json +68 -0
  241. package/gallery/data/pnpm-outdated.json +58 -0
  242. package/gallery/data/provenance/devicectl-install.json +35 -0
  243. package/gallery/data/provenance/install-timeout.log +4 -0
  244. package/gallery/data/provenance/iphone-install.json +72 -0
  245. package/gallery/data/provenance/iphone-no-receipt.json +57 -0
  246. package/gallery/data/provenance/live-home.jpg +0 -0
  247. package/gallery/data/provenance/live-probe.txt +10 -0
  248. package/gallery/data/provenance/xcodebuild-2811.log +19 -0
  249. package/gallery/data/provenance/xcodebuild-4712.log +19 -0
  250. package/gallery/data/pytest-junit.xml +64 -0
  251. package/gallery/data/python-org-trace.json +35 -0
  252. package/gallery/data/python-org.har +31 -0
  253. package/gallery/data/retry.ts +13 -0
  254. package/gallery/data/ruff.json +261 -0
  255. package/gallery/data/src/durations.py +63 -0
  256. package/gallery/data/src/json-logic.ts +156 -0
  257. package/gallery/data/src/mapMath.ts +135 -0
  258. package/gallery/data/src/semver/bump.go +73 -0
  259. package/gallery/data/traces/browser-error.json +5 -0
  260. package/gallery/data/traces/go/main.go +27 -0
  261. package/gallery/data/traces/go-panic.txt +16 -0
  262. package/gallery/data/traces/java-caused-by.txt +15 -0
  263. package/gallery/data/traces/node-aggregate.txt +30 -0
  264. package/gallery/data/traces/node-cause.txt +21 -0
  265. package/gallery/data/traces/py/deploy.json +5 -0
  266. package/gallery/data/traces/py/deploy.py +17 -0
  267. package/gallery/data/traces/py/settings.py +19 -0
  268. package/gallery/data/traces/python-chain.txt +30 -0
  269. package/gallery/data/traces/rust/main.rs +11 -0
  270. package/gallery/data/traces/rust-panic.txt +16 -0
  271. package/gallery/data/traces/shop/cart.mjs +19 -0
  272. package/gallery/data/traces/shop/pricing.mjs +12 -0
  273. package/gallery/data/traces/shop/status.mjs +9 -0
  274. package/gallery/data/traces/web/app.js +11 -0
  275. package/gallery/data/traces/web/index.html +1 -0
  276. package/gallery/data/traces/web/search.js +10 -0
  277. package/gallery/data/transcript/call-noisy.wav +0 -0
  278. package/gallery/data/transcript/call.json +362 -0
  279. package/gallery/data/transcript/call.wav +0 -0
  280. package/gallery/data/transcript/mlx-whisper-tiny.en-noisy.json +1 -0
  281. package/gallery/data/transcript/whisper-cpp-base.en-noisy.json +658 -0
  282. package/gallery/data/transcript/whisper-cpp-base.en.json +658 -0
  283. package/gallery/data/transcript/whisper-cpp-base.en.srt +16 -0
  284. package/gallery/data/transcript/whisper-cpp-tiny.en-noisy.json +619 -0
  285. package/gallery/data/tsc.txt +4 -0
  286. package/gallery/data/vitest-bench.json +119 -0
  287. package/gallery/data/vitest-junit.xml +133 -0
  288. package/gallery/data/vitest-report.json +612 -0
  289. package/gallery/images/bell.svg +10 -0
  290. package/gallery/images/bike.svg +47 -0
  291. package/gallery/images/footer-planet.webp +0 -0
  292. package/gallery/images/front-light.svg +13 -0
  293. package/gallery/images/golden-hour.webp +0 -0
  294. package/gallery/images/option-flowers.webp +0 -0
  295. package/gallery/images/option-hilltop.webp +0 -0
  296. package/gallery/images/option-meadow.webp +0 -0
  297. package/gallery/images/option-sky.webp +0 -0
  298. package/gallery/images/u-lock.svg +10 -0
  299. package/index.client.tsx +164 -0
  300. package/index.server.ts +216 -0
  301. package/package.json +50 -4
  302. package/paseo-plugin.json +14 -0
  303. package/server/data-source.ts +407 -0
  304. package/server/project.ts +981 -0
  305. package/server/web/address.ts +57 -0
  306. package/server/web/cache.ts +85 -0
  307. package/server/web/commons.ts +126 -0
  308. package/server/web/geocode.ts +40 -0
  309. package/server/web/image.ts +35 -0
  310. package/server/web/lookups.ts +248 -0
  311. package/server/web/net.ts +210 -0
  312. package/shared/core/acceptance.ts +744 -0
  313. package/shared/core/ast.ts +76 -0
  314. package/shared/core/benchmark.ts +743 -0
  315. package/shared/core/catalog.ts +733 -0
  316. package/shared/core/compare.ts +225 -0
  317. package/shared/core/coverage.ts +456 -0
  318. package/shared/core/data.ts +334 -0
  319. package/shared/core/decisions.ts +527 -0
  320. package/shared/core/dependencies.ts +604 -0
  321. package/shared/core/diagnostics.ts +24 -0
  322. package/shared/core/environments.ts +212 -0
  323. package/shared/core/evaluate.ts +737 -0
  324. package/shared/core/fields.ts +66 -0
  325. package/shared/core/findings.ts +1172 -0
  326. package/shared/core/form.ts +69 -0
  327. package/shared/core/index.ts +44 -0
  328. package/shared/core/junit.ts +252 -0
  329. package/shared/core/lexer.ts +275 -0
  330. package/shared/core/logs.ts +496 -0
  331. package/shared/core/markdown.ts +2374 -0
  332. package/shared/core/parser.ts +355 -0
  333. package/shared/core/perf-units.ts +228 -0
  334. package/shared/core/pipeline.ts +679 -0
  335. package/shared/core/project.ts +472 -0
  336. package/shared/core/provenance.ts +725 -0
  337. package/shared/core/stack-trace.ts +718 -0
  338. package/shared/core/streaming.ts +136 -0
  339. package/shared/core/test-results.ts +562 -0
  340. package/shared/core/thread-activity.ts +203 -0
  341. package/shared/core/tracking.ts +887 -0
  342. package/shared/core/transcript.ts +1364 -0
  343. package/shared/core/treemap.ts +446 -0
  344. package/shared/core/types.ts +70 -0
  345. package/shared/core/validate.ts +574 -0
  346. package/shared/core/waterfall.ts +536 -0
  347. package/shared/diagram/flowchart.ts +205 -0
  348. package/shared/diagram/layout.ts +440 -0
  349. package/shared/diagram/markdown.ts +135 -0
  350. package/shared/diagram/sequence.ts +122 -0
  351. package/shared/diagram/zoom.ts +114 -0
  352. package/shared/fallback.ts +120 -0
  353. package/shared/genui.test.ts +122 -0
  354. package/shared/instructions.ts +144 -0
  355. package/shared/logic/calendarMath.ts +130 -0
  356. package/shared/logic/chartMath.ts +289 -0
  357. package/shared/logic/choose-logic.ts +196 -0
  358. package/shared/logic/compare-logic.ts +270 -0
  359. package/shared/logic/content-model.ts +227 -0
  360. package/shared/logic/environments-logic.ts +53 -0
  361. package/shared/logic/explain-logic.ts +315 -0
  362. package/shared/logic/fieldLogic.ts +138 -0
  363. package/shared/logic/gallery-search.ts +71 -0
  364. package/shared/logic/icons.ts +322 -0
  365. package/shared/logic/json-logic.ts +153 -0
  366. package/shared/logic/mapMath.ts +133 -0
  367. package/shared/logic/project-logic.ts +39 -0
  368. package/shared/logic/references-model.ts +201 -0
  369. package/shared/logic/sketch.ts +165 -0
  370. package/shared/logic/supersession.ts +77 -0
  371. package/shared/logic/values.ts +133 -0
  372. package/shared/logic/widget-logic.ts +163 -0
  373. package/shared/rpc.ts +252 -0
  374. package/shared/segment.ts +81 -0
  375. package/shared/settings.ts +12 -0
@@ -0,0 +1,322 @@
1
+ // BB's built-in icon names, vendored from BB's shared-ui (`CORE_ICON_MAP` keys
2
+ // in components/ui/icon.tsx and `EXTENDED_ICON_NAMES` in icon-registry.ts).
3
+ // BB draws any other name as its Zap fallback, so names a spec writes are
4
+ // resolved here first: models write lucide/heroicons names in any case.
5
+
6
+ const BB_ICON_NAMES = [
7
+ // CORE_ICON_MAP
8
+ "AlertCircle",
9
+ "AlertTriangle",
10
+ "Archive",
11
+ "Bot",
12
+ "Bug",
13
+ "Check",
14
+ "ChevronDown",
15
+ "ChevronLeft",
16
+ "ChevronRight",
17
+ "Circle",
18
+ "CircleCheck",
19
+ "CircleQuestion",
20
+ "CircleX",
21
+ "ClosePluginPane",
22
+ "CloseThreadPane",
23
+ "Code",
24
+ "ComputerTerminal01",
25
+ "Copy",
26
+ "Download",
27
+ "Edit",
28
+ "Filter",
29
+ "FilterHorizontal",
30
+ "Folder",
31
+ "FolderExport",
32
+ "FolderGit",
33
+ "FolderPlus",
34
+ "FolderSync",
35
+ "FolderUnknown",
36
+ "Folder02",
37
+ "Home",
38
+ "Info",
39
+ "ListTodo",
40
+ "Loading",
41
+ "MessageQuestion",
42
+ "MessageCirclePlus",
43
+ "MessageSquarePlus",
44
+ "MessageSquare",
45
+ "MoreHorizontal",
46
+ "PanelLeft",
47
+ "Search",
48
+ "SectionAdd",
49
+ "SectionMove",
50
+ "Settings",
51
+ "SlidersHorizontal",
52
+ "Spinner",
53
+ "Target",
54
+ "Terminal",
55
+ "Toolbox",
56
+ "ToolCase",
57
+ "Trash2",
58
+ "Unavailable",
59
+ "UserRoundPlus",
60
+ "Workflow",
61
+ "X",
62
+ "Zap",
63
+ // EXTENDED_ICON_NAMES
64
+ "AiBrain01",
65
+ "AiBrowser",
66
+ "AiContentGenerator01",
67
+ "AlignLeft",
68
+ "AppWindow",
69
+ "ArchiveRestore",
70
+ "ArrowDown",
71
+ "ArrowLeft",
72
+ "ArrowRight",
73
+ "ArrowReloadHorizontal",
74
+ "ArrowUp",
75
+ "ArrowUpDown",
76
+ "ArrowTurnBackward",
77
+ "ArrowTurnForward",
78
+ "ArrowUpRight",
79
+ "Beaker",
80
+ "BellDot",
81
+ "Browser",
82
+ "Brain",
83
+ "Calendar",
84
+ "CalendarCheckOut02",
85
+ "ChartColumn",
86
+ "ChevronUp",
87
+ "ChevronsDown",
88
+ "ChevronsUp",
89
+ "CircleArrowShrink",
90
+ "Clean",
91
+ "Clock",
92
+ "ClockArrowUp",
93
+ "ClockArrowDown",
94
+ "Cloud",
95
+ "CloudOff",
96
+ "ComputerCloud",
97
+ "Coffee",
98
+ "Columns2",
99
+ "CornerDownLeft",
100
+ "CornerDownRight",
101
+ "DiffAdded",
102
+ "DiffConflict",
103
+ "DiffModified",
104
+ "DiffRemoved",
105
+ "DiffRenamed",
106
+ "Discord",
107
+ "DiscordLogo",
108
+ "DateTime",
109
+ "Github",
110
+ "GithubLogo",
111
+ "DragDropHorizontal",
112
+ "DragDropVertical",
113
+ "EditFile",
114
+ "ElectricPlugs",
115
+ "Eye",
116
+ "EyeOff",
117
+ "Explore",
118
+ "ExternalLink",
119
+ "FileDiff",
120
+ "File",
121
+ "FileAttachment",
122
+ "FileQuestion",
123
+ "FileText",
124
+ "FolderOpen",
125
+ "FolderEdit",
126
+ "FolderMinus",
127
+ "Fork",
128
+ "GitBranch",
129
+ "GitMerge",
130
+ "GitPullRequest",
131
+ "GitPullRequestArrow",
132
+ "GitPullRequestClosed",
133
+ "GitPullRequestDraft",
134
+ "Globe",
135
+ "GridView",
136
+ "Keyboard",
137
+ "Laptop",
138
+ "Layers",
139
+ "Limitation",
140
+ "Link",
141
+ "ListEnd",
142
+ "ListView",
143
+ "Lock",
144
+ "Mail",
145
+ "MailOpen",
146
+ "Maximize2",
147
+ "Mic",
148
+ "Minus",
149
+ "Minimize2",
150
+ "MoveTo",
151
+ "NewTab",
152
+ "News01",
153
+ "PackageReceive",
154
+ "Palette",
155
+ "PanelBottom",
156
+ "PanelRight",
157
+ "Paperclip",
158
+ "Pause",
159
+ "Pin",
160
+ "PinOff",
161
+ "Play",
162
+ "Plug02",
163
+ "Plus",
164
+ "Puzzle",
165
+ "Repeat",
166
+ "RotateCcw",
167
+ "Rows2",
168
+ "SecurityCheck",
169
+ "Sent",
170
+ "SideChat",
171
+ "Smartphone",
172
+ "Sort",
173
+ "SortingAZ02",
174
+ "SortingZA01",
175
+ "SortingOneNine",
176
+ "SortingNineOne",
177
+ "Square",
178
+ "SquareUnlock02",
179
+ "Star",
180
+ "TextWrap",
181
+ "TimeSchedule",
182
+ "UserRound",
183
+ "ZoomIn",
184
+ "ZoomOut",
185
+ ] as const;
186
+
187
+ export type BbIconName = (typeof BB_ICON_NAMES)[number];
188
+
189
+ /** Every BB name keyed with case and separators dropped: "git-branch", "git_branch" and "gitBranch" all key as "gitbranch". */
190
+ const BY_KEY: ReadonlyMap<string, BbIconName> = new Map(
191
+ BB_ICON_NAMES.map((name) => [name.toLowerCase(), name]),
192
+ );
193
+
194
+ /**
195
+ * Common lucide and heroicons names that BB spells differently, keyed the
196
+ * same way. Real BB names win over these (`x` is BB's X).
197
+ */
198
+ const ALIASES: Record<string, BbIconName> = {
199
+ trash: "Trash2",
200
+ trashcan: "Trash2",
201
+ delete: "Trash2",
202
+ bin: "Trash2",
203
+ close: "CircleX",
204
+ cancel: "CircleX",
205
+ xcircle: "CircleX",
206
+ xmark: "X",
207
+ xmarkcircle: "CircleX",
208
+ checkmark: "Check",
209
+ tick: "Check",
210
+ checkcircle: "CircleCheck",
211
+ checkcircle2: "CircleCheck",
212
+ circlecheckbig: "CircleCheck",
213
+ warning: "AlertTriangle",
214
+ alert: "AlertTriangle",
215
+ trianglealert: "AlertTriangle",
216
+ exclamationtriangle: "AlertTriangle",
217
+ circlealert: "AlertCircle",
218
+ exclamationcircle: "AlertCircle",
219
+ information: "Info",
220
+ informationcircle: "Info",
221
+ circleinfo: "Info",
222
+ help: "CircleQuestion",
223
+ helpcircle: "CircleQuestion",
224
+ circlehelp: "CircleQuestion",
225
+ question: "CircleQuestion",
226
+ questionmarkcircle: "CircleQuestion",
227
+ external: "ExternalLink",
228
+ squarearrowoutupright: "ExternalLink",
229
+ arrowtoprightonsquare: "ExternalLink",
230
+ refresh: "ArrowReloadHorizontal",
231
+ reload: "ArrowReloadHorizontal",
232
+ refreshcw: "ArrowReloadHorizontal",
233
+ refreshccw: "ArrowReloadHorizontal",
234
+ rotatecw: "ArrowReloadHorizontal",
235
+ arrowpath: "ArrowReloadHorizontal",
236
+ undo: "ArrowTurnBackward",
237
+ undo2: "ArrowTurnBackward",
238
+ redo: "ArrowTurnForward",
239
+ redo2: "ArrowTurnForward",
240
+ pencil: "Edit",
241
+ pen: "Edit",
242
+ pencilline: "Edit",
243
+ squarepen: "Edit",
244
+ pencilsquare: "Edit",
245
+ cog: "Settings",
246
+ gear: "Settings",
247
+ cog6tooth: "Settings",
248
+ clipboard: "Copy",
249
+ documentduplicate: "Copy",
250
+ arrowdowntray: "Download",
251
+ send: "Sent",
252
+ sendhorizontal: "Sent",
253
+ paperairplane: "Sent",
254
+ add: "Plus",
255
+ pluscircle: "Plus",
256
+ circleplus: "Plus",
257
+ magnifyingglass: "Search",
258
+ branch: "GitBranch",
259
+ merge: "GitMerge",
260
+ pullrequest: "GitPullRequest",
261
+ console: "Terminal",
262
+ commandline: "Terminal",
263
+ squareterminal: "Terminal",
264
+ stop: "Square",
265
+ view: "Eye",
266
+ unlock: "SquareUnlock02",
267
+ lockopen: "SquareUnlock02",
268
+ chain: "Link",
269
+ date: "Calendar",
270
+ time: "Clock",
271
+ email: "Mail",
272
+ envelope: "Mail",
273
+ document: "FileText",
274
+ house: "Home",
275
+ favorite: "Star",
276
+ world: "Globe",
277
+ restore: "ArchiveRestore",
278
+ more: "MoreHorizontal",
279
+ ellipsis: "MoreHorizontal",
280
+ chat: "MessageSquare",
281
+ message: "MessageSquare",
282
+ comment: "MessageSquare",
283
+ user: "UserRound",
284
+ person: "UserRound",
285
+ robot: "Bot",
286
+ loader: "Loading",
287
+ loader2: "Loading",
288
+ phone: "Smartphone",
289
+ mobile: "Smartphone",
290
+ microphone: "Mic",
291
+ grid: "GridView",
292
+ list: "ListView",
293
+ columns: "Columns2",
294
+ rows: "Rows2",
295
+ plug: "Plug02",
296
+ flask: "Beaker",
297
+ bell: "BellDot",
298
+ chart: "ChartColumn",
299
+ barchart: "ChartColumn",
300
+ chartbar: "ChartColumn",
301
+ maximize: "Maximize2",
302
+ expand: "Maximize2",
303
+ minimize: "Minimize2",
304
+ collapse: "Minimize2",
305
+ attachment: "Paperclip",
306
+ bolt: "Zap",
307
+ lightning: "Zap",
308
+ };
309
+
310
+ /**
311
+ * The BB icon a spec's icon name means, or null when BB has no such icon
312
+ * (callers then draw nothing rather than BB's Zap fallback). Accepts any
313
+ * case and separator, lucide/heroicons spellings, and a trailing "Icon".
314
+ */
315
+ export function resolveIconName(name: string): string | null {
316
+ const key = name.replace(/[-_\s.]+/g, "").toLowerCase();
317
+ if (key === "") return null;
318
+ const found = BY_KEY.get(key) ?? (Object.hasOwn(ALIASES, key) ? ALIASES[key] : undefined);
319
+ if (found !== undefined) return found;
320
+ // `TrashIcon`, `trash-icon`: the component name some icon libraries export.
321
+ return key.endsWith("icon") && key.length > 4 ? resolveIconName(key.slice(0, -4)) : null;
322
+ }
@@ -0,0 +1,153 @@
1
+ // The rows `Json` shows: only open containers contribute children, and a
2
+ // container shows its first `shown` children followed by a "N more" row, so a
3
+ // thousand-item array costs a hundred rows until the user asks for more.
4
+ // Each row's id is its JSONPath (`$.items[3].name`), which is also what
5
+ // "copy path" copies. Pure: no React, no DOM.
6
+ import type { Value } from "../core/types";
7
+
8
+ export type JsonKind = "object" | "array" | "string" | "number" | "boolean" | "null";
9
+
10
+ /** Children a container shows before its "N more" row, and how many each click adds. */
11
+ export const CHILD_PAGE = 100;
12
+ /** Characters of a string shown before it is cut with an expand control. */
13
+ export const STRING_PREVIEW = 160;
14
+
15
+ export function jsonKind(value: Value): JsonKind {
16
+ if (value === null) return "null";
17
+ if (Array.isArray(value)) return "array";
18
+ switch (typeof value) {
19
+ case "string":
20
+ return "string";
21
+ case "number":
22
+ return "number";
23
+ case "boolean":
24
+ return "boolean";
25
+ default:
26
+ return "object";
27
+ }
28
+ }
29
+
30
+ const IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
31
+
32
+ /** The JSONPath of `key` under `parent`: `$.name`, `$[3]`, `$["two words"]`. */
33
+ export function childPath(parent: string, key: string | number): string {
34
+ if (typeof key === "number") return `${parent}[${key}]`;
35
+ return IDENTIFIER.test(key) ? `${parent}.${key}` : `${parent}[${JSON.stringify(key)}]`;
36
+ }
37
+
38
+ /** A container's entries in order: indexes for arrays, own keys for objects; none for scalars. */
39
+ export function entries(value: Value): readonly (readonly [string | number, Value])[] {
40
+ if (Array.isArray(value)) return value.map((item: Value, index) => [index, item] as const);
41
+ if (typeof value === "object" && value !== null) return Object.entries(value as Record<string, Value>);
42
+ return [];
43
+ }
44
+
45
+ /** `3 keys`, `1 item`, `0 items`; empty for scalars. */
46
+ export function sizeText(value: Value): string {
47
+ if (typeof value !== "object" || value === null) return "";
48
+ const array = Array.isArray(value);
49
+ const count = array ? value.length : Object.keys(value).length;
50
+ return `${count} ${array ? "item" : "key"}${count === 1 ? "" : "s"}`;
51
+ }
52
+
53
+ /** What copying a value puts on the clipboard: strings bare, other scalars as written, containers as indented JSON. */
54
+ export function copyText(value: Value): string {
55
+ if (typeof value === "string") return value;
56
+ if (value === null || typeof value !== "object") return String(value);
57
+ return JSON.stringify(value, null, 2);
58
+ }
59
+
60
+ export interface ValueRow {
61
+ readonly type: "value";
62
+ /** The JSONPath. */
63
+ readonly id: string;
64
+ readonly depth: number;
65
+ /** Null for the root of a scalar. */
66
+ readonly key: string | number | null;
67
+ readonly value: Value;
68
+ readonly kind: JsonKind;
69
+ readonly parent: string | null;
70
+ readonly position: number;
71
+ readonly siblings: number;
72
+ /** Entries of an object or array; 0 for scalars and empty containers, which do not expand. */
73
+ readonly children: number;
74
+ }
75
+
76
+ export interface MoreRow {
77
+ readonly type: "more";
78
+ readonly id: string;
79
+ readonly depth: number;
80
+ /** The container this row pages. */
81
+ readonly parent: string;
82
+ /** The children of `parent` already shown, which is where the next page starts. */
83
+ readonly shown: number;
84
+ readonly remaining: number;
85
+ }
86
+
87
+ export type JsonRow = ValueRow | MoreRow;
88
+
89
+ /**
90
+ * The rows on screen. A container root is not a row of its own (its size is
91
+ * the caption): its entries are the top level. `isOpen(id)` says whether a
92
+ * container is expanded; `shown(id)` how many of its children are on screen.
93
+ */
94
+ export function visibleRows(root: Value, isOpen: (id: string) => boolean, shown: (id: string) => number): JsonRow[] {
95
+ const rows: JsonRow[] = [];
96
+ const rootKind = jsonKind(root);
97
+ if (rootKind !== "array" && rootKind !== "object") {
98
+ rows.push({ type: "value", id: "$", depth: 0, key: null, value: root, kind: rootKind, parent: null, position: 1, siblings: 1, children: 0 });
99
+ return rows;
100
+ }
101
+ // Depth-first with an explicit stack of open containers: deep values never recurse.
102
+ interface Open {
103
+ readonly id: string;
104
+ readonly all: readonly (readonly [string | number, Value])[];
105
+ readonly limit: number;
106
+ readonly depth: number;
107
+ next: number;
108
+ }
109
+ const open = (id: string, value: Value, depth: number): Open => {
110
+ const all = entries(value);
111
+ return { id, all, limit: Math.min(all.length, Math.max(0, shown(id))), depth, next: 0 };
112
+ };
113
+ const stack: Open[] = [open("$", root, 0)];
114
+ while (stack.length > 0) {
115
+ const frame = stack[stack.length - 1];
116
+ if (frame.next >= frame.limit) {
117
+ stack.pop();
118
+ if (frame.limit < frame.all.length) {
119
+ rows.push({ type: "more", id: `${frame.id}…`, depth: frame.depth, parent: frame.id, shown: frame.limit, remaining: frame.all.length - frame.limit });
120
+ }
121
+ continue;
122
+ }
123
+ const index = frame.next++;
124
+ const [key, child] = frame.all[index];
125
+ const id = childPath(frame.id, key);
126
+ const kind = jsonKind(child);
127
+ const parent = frame.depth === 0 ? null : frame.id;
128
+ const children = Array.isArray(child) ? child.length : typeof child === "object" && child !== null ? Object.keys(child).length : 0;
129
+ rows.push({ type: "value", id, depth: frame.depth, key, value: child, kind, parent, position: index + 1, siblings: frame.all.length, children });
130
+ if (children > 0 && isOpen(id)) stack.push(open(id, child, frame.depth + 1));
131
+ }
132
+ return rows;
133
+ }
134
+
135
+ /**
136
+ * Containers open before the user touches anything. The top level always
137
+ * shows; below it a lone container entry opens, and so on down, so an
138
+ * envelope like `{data: {...}}` shows its content instead of one closed row.
139
+ */
140
+ export function defaultOpen(root: Value): ReadonlySet<string> {
141
+ const ids = new Set<string>();
142
+ let id = "$";
143
+ let current = entries(root);
144
+ while (current.length === 1) {
145
+ const [key, child] = current[0];
146
+ const kind = jsonKind(child);
147
+ if (kind !== "array" && kind !== "object") break;
148
+ id = childPath(id, key);
149
+ ids.add(id);
150
+ current = entries(child);
151
+ }
152
+ return ids;
153
+ }
@@ -0,0 +1,133 @@
1
+ // Web Mercator math for Map: places to world coordinates, the view that fits
2
+ // them, panning and zooming about a point, and the OpenStreetMap tiles a view
3
+ // needs. World coordinates run 0..1 across and down; a view is the world
4
+ // point at the viewport's centre and a fractional zoom.
5
+
6
+ export const TILE_SIZE = 256;
7
+ export const MIN_ZOOM = 1;
8
+ /** OSM serves z19, but z18 is already street level and keeps tile counts sane. */
9
+ export const MAX_ZOOM = 18;
10
+ /** Mercator's square world ends here. */
11
+ const MAX_LATITUDE = 85.05112878;
12
+
13
+ export interface Point {
14
+ readonly x: number;
15
+ readonly y: number;
16
+ }
17
+
18
+ export interface View extends Point {
19
+ readonly zoom: number;
20
+ }
21
+
22
+ export interface Size {
23
+ readonly width: number;
24
+ readonly height: number;
25
+ }
26
+
27
+ export interface Tile {
28
+ /** Tile coordinates to fetch (x wrapped around the world). */
29
+ readonly z: number;
30
+ readonly x: number;
31
+ readonly y: number;
32
+ /** Unique per drawn copy, since a wide view can show the same tile twice. */
33
+ readonly key: string;
34
+ readonly left: number;
35
+ readonly top: number;
36
+ readonly size: number;
37
+ }
38
+
39
+ function clamp(value: number, min: number, max: number): number {
40
+ return Math.min(max, Math.max(min, value));
41
+ }
42
+
43
+ /** The world's width in pixels at `zoom`. */
44
+ function worldSize(zoom: number): number {
45
+ return TILE_SIZE * 2 ** zoom;
46
+ }
47
+
48
+ /** Latitude and longitude in degrees to world coordinates. */
49
+ export function project(lat: number, lng: number): Point {
50
+ const sin = Math.sin((clamp(lat, -MAX_LATITUDE, MAX_LATITUDE) * Math.PI) / 180);
51
+ return { x: (lng + 180) / 360, y: 0.5 - Math.log((1 + sin) / (1 - sin)) / (4 * Math.PI) };
52
+ }
53
+
54
+ /** Keeps zoom in range and, where the world is taller than the viewport, the view inside it vertically. */
55
+ export function clampView(view: View, size: Size): View {
56
+ const zoom = clamp(view.zoom, MIN_ZOOM, MAX_ZOOM);
57
+ const half = size.height / 2 / worldSize(zoom);
58
+ const y = half >= 0.5 ? 0.5 : clamp(view.y, half, 1 - half);
59
+ // Longitude wraps; keep x in 0..1 so numbers stay small.
60
+ return { x: view.x - Math.floor(view.x), y, zoom };
61
+ }
62
+
63
+ /** The view showing every point with `padding` pixels to spare, zoomed in no further than `maxZoom`. */
64
+ export function fitView(points: readonly Point[], size: Size, padding: number, maxZoom: number): View {
65
+ if (points.length === 0) return clampView({ x: 0.5, y: 0.5, zoom: MIN_ZOOM }, size);
66
+ const xs = points.map((point) => point.x);
67
+ const ys = points.map((point) => point.y);
68
+ const [minX, maxX, minY, maxY] = [Math.min(...xs), Math.max(...xs), Math.min(...ys), Math.max(...ys)];
69
+ const width = Math.max(1, size.width - 2 * padding);
70
+ const height = Math.max(1, size.height - 2 * padding);
71
+ const zoomFor = (span: number, pixels: number) => (span === 0 ? maxZoom : Math.log2(pixels / (span * TILE_SIZE)));
72
+ const zoom = Math.min(maxZoom, zoomFor(maxX - minX, width), zoomFor(maxY - minY, height));
73
+ return clampView({ x: (minX + maxX) / 2, y: (minY + maxY) / 2, zoom }, size);
74
+ }
75
+
76
+ /** Where `point` sits in the viewport, using its copy of the world nearest the view's centre. */
77
+ export function toScreen(point: Point, view: View, size: Size): { readonly left: number; readonly top: number } {
78
+ const scale = worldSize(view.zoom);
79
+ const dx = point.x - view.x;
80
+ return {
81
+ left: (dx - Math.round(dx)) * scale + size.width / 2,
82
+ top: (point.y - view.y) * scale + size.height / 2,
83
+ };
84
+ }
85
+
86
+ /** The view moved by a drag of `dx`, `dy` pixels. */
87
+ export function pan(view: View, dx: number, dy: number, size: Size): View {
88
+ const scale = worldSize(view.zoom);
89
+ return clampView({ x: view.x - dx / scale, y: view.y - dy / scale, zoom: view.zoom }, size);
90
+ }
91
+
92
+ /** The view at `zoom`, with the world point under `anchor` (viewport pixels) still under it. */
93
+ export function zoomAround(view: View, zoom: number, anchor: { left: number; top: number }, size: Size): View {
94
+ const target = clamp(zoom, MIN_ZOOM, MAX_ZOOM);
95
+ const offsetX = anchor.left - size.width / 2;
96
+ const offsetY = anchor.top - size.height / 2;
97
+ const before = worldSize(view.zoom);
98
+ const after = worldSize(target);
99
+ const x = view.x + offsetX / before - offsetX / after;
100
+ const y = view.y + offsetY / before - offsetY / after;
101
+ return clampView({ x, y, zoom: target }, size);
102
+ }
103
+
104
+ /** The tile zoom level drawn for a view: the nearest whole level. */
105
+ export function tileZoom(view: View): number {
106
+ return clamp(Math.round(view.zoom), 0, MAX_ZOOM);
107
+ }
108
+
109
+ /** The tiles at level `z` (default: the view's) covering the viewport, each with its place and drawn size. */
110
+ export function visibleTiles(view: View, size: Size, z = tileZoom(view)): Tile[] {
111
+ const count = 2 ** z;
112
+ const scale = worldSize(view.zoom);
113
+ const tileSize = scale / count;
114
+ const left = view.x - size.width / 2 / scale;
115
+ const right = view.x + size.width / 2 / scale;
116
+ const top = view.y - size.height / 2 / scale;
117
+ const bottom = view.y + size.height / 2 / scale;
118
+ const tiles: Tile[] = [];
119
+ for (let ty = Math.max(0, Math.floor(top * count)); ty <= Math.min(count - 1, Math.floor(bottom * count)); ty += 1) {
120
+ for (let tx = Math.floor(left * count); tx <= Math.floor(right * count); tx += 1) {
121
+ tiles.push({
122
+ z,
123
+ x: ((tx % count) + count) % count,
124
+ y: ty,
125
+ key: `${z}/${tx}/${ty}`,
126
+ left: (tx / count - view.x) * scale + size.width / 2,
127
+ top: (ty / count - view.y) * scale + size.height / 2,
128
+ size: tileSize,
129
+ });
130
+ }
131
+ }
132
+ return tiles;
133
+ }
@@ -0,0 +1,39 @@
1
+ // Pure pieces of the Project components (projectKit.tsx and friends): the
2
+ // polling schedule and the +/− proportion blocks.
3
+
4
+ /** First wait before a live component asks BB again. */
5
+ export const POLL_START_MS = 4_000;
6
+
7
+ /** Longest wait between polls. */
8
+ export const POLL_MAX_MS = 60_000;
9
+
10
+ /**
11
+ * The wait before the next poll: doubles from POLL_START_MS with every answer
12
+ * that changed nothing, up to POLL_MAX_MS; a change starts over.
13
+ */
14
+ export function pollDelay(unchangedAnswers: number): number {
15
+ return Math.min(POLL_MAX_MS, POLL_START_MS * 2 ** Math.max(0, unchangedAnswers));
16
+ }
17
+
18
+ /** Blocks in the proportion bar beside a file's counts (GitHub's five). */
19
+ export const RATIO_BLOCKS = 5;
20
+
21
+ /**
22
+ * How many blocks are green, red and grey for a file's counts: as many
23
+ * colored blocks as changed lines up to RATIO_BLOCKS, split by share, each
24
+ * side that changed keeping at least one.
25
+ */
26
+ export function ratioBlocks(additions: number, deletions: number): { added: number; removed: number; neutral: number } {
27
+ const total = additions + deletions;
28
+ if (!(total > 0)) return { added: 0, removed: 0, neutral: RATIO_BLOCKS };
29
+ const colored = Math.min(RATIO_BLOCKS, total);
30
+ let added = Math.round((colored * additions) / total);
31
+ if (additions > 0 && added === 0) added = 1;
32
+ if (deletions > 0 && added === colored) added = colored - 1;
33
+ return { added, removed: colored - added, neutral: RATIO_BLOCKS - colored };
34
+ }
35
+
36
+ /** The answer's content without when it was read, so two reads compare equal when BB's state didn't change. */
37
+ export function answerSignature(answer: unknown): string {
38
+ return JSON.stringify(answer, (key, value: unknown) => (key === "fetchedAt" || key === "takenAt" ? undefined : value));
39
+ }