@digithings-ai/ui 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 (424) hide show
  1. package/README.md +48 -2
  2. package/package.json +143 -4
  3. package/src/components/NavShell.tsx +776 -0
  4. package/src/components/SocialRow.tsx +87 -0
  5. package/src/components/Spinner.tsx +27 -0
  6. package/src/components/StackLogo.tsx +40 -0
  7. package/src/components/Terminal.tsx +110 -0
  8. package/src/components/TerminalManifest.tsx +212 -0
  9. package/src/components/ThemeProvider.tsx +271 -0
  10. package/src/components/account/AuthCard.tsx +309 -0
  11. package/src/components/assistant-ui/elements/mermaid-diagram.aui.tsx +63 -0
  12. package/src/components/assistant-ui/elements/mermaid-diagram.tsx +340 -0
  13. package/src/components/brand/BrandWordmark.tsx +32 -0
  14. package/src/components/changelog/ReleaseRail.tsx +81 -0
  15. package/src/components/changelog/index.ts +1 -0
  16. package/src/components/chat/ChatCodeBlock.tsx +67 -0
  17. package/src/components/chat/ChatMarkdown.tsx +66 -0
  18. package/src/components/chat/ChatMarkdownSource.tsx +203 -0
  19. package/src/components/chat/ChatMermaidBlock.tsx +202 -0
  20. package/src/components/chat/ChatMessage.tsx +77 -0
  21. package/src/components/chat/ChatPlayback.tsx +422 -0
  22. package/src/components/chat/ChatStreamCursor.tsx +25 -0
  23. package/src/components/chat/ChatThinking.tsx +113 -0
  24. package/src/components/chat/ChatToolCall.tsx +190 -0
  25. package/src/components/chat/ChatTranscript.tsx +60 -0
  26. package/src/components/chat/ChatWidgetFrame.tsx +107 -0
  27. package/src/components/chat/DigichatBootLoader.tsx +683 -0
  28. package/src/components/chat/DigichatLauncher.tsx +361 -0
  29. package/src/components/chat/DigichatThread.tsx +118 -0
  30. package/src/components/chat/DigichatThreadList.tsx +54 -0
  31. package/src/components/chat/DigichatWordmark.tsx +24 -0
  32. package/src/components/chat/DotMatrix.tsx +650 -0
  33. package/src/components/chat/boot-lab.tsx +766 -0
  34. package/src/components/chat/boot-signal.ts +144 -0
  35. package/src/components/chat/chat-surfaces.ts +52 -0
  36. package/src/components/chat/connection-status.ts +40 -0
  37. package/src/components/chat/digichat-wordmark.ts +355 -0
  38. package/src/components/chat/disclosure-chevron.tsx +49 -0
  39. package/src/components/chat/followable-href.ts +9 -0
  40. package/src/components/chat/gallery-thread/action-icons.tsx +25 -0
  41. package/src/components/chat/gallery-thread/attachment.aui.tsx +262 -0
  42. package/src/components/chat/gallery-thread/block-caret.tsx +439 -0
  43. package/src/components/chat/gallery-thread/cn.ts +1 -0
  44. package/src/components/chat/gallery-thread/composer-keyboard.ts +106 -0
  45. package/src/components/chat/gallery-thread/composer-trigger-popover.aui.tsx +235 -0
  46. package/src/components/chat/gallery-thread/css.d.ts +6 -0
  47. package/src/components/chat/gallery-thread/file.tsx +238 -0
  48. package/src/components/chat/gallery-thread/follow-up-suggestions.aui.tsx +92 -0
  49. package/src/components/chat/gallery-thread/format-json-dump.ts +112 -0
  50. package/src/components/chat/gallery-thread/hooks/use-attachment-src.ts +46 -0
  51. package/src/components/chat/gallery-thread/hooks/use-copy-to-clipboard.ts +9 -0
  52. package/src/components/chat/gallery-thread/image.tsx +519 -0
  53. package/src/components/chat/gallery-thread/markdown-text.tsx +278 -0
  54. package/src/components/chat/gallery-thread/message-error.aui.tsx +105 -0
  55. package/src/components/chat/gallery-thread/message-timing.aui.tsx +143 -0
  56. package/src/components/chat/gallery-thread/private-work-step.tsx +188 -0
  57. package/src/components/chat/gallery-thread/reasoning.tsx +332 -0
  58. package/src/components/chat/gallery-thread/scroll-mode.ts +174 -0
  59. package/src/components/chat/gallery-thread/source.tsx +76 -0
  60. package/src/components/chat/gallery-thread/thread.aui.tsx +1619 -0
  61. package/src/components/chat/gallery-thread/tooltip-icon-button.tsx +53 -0
  62. package/src/components/chat/gallery-thread/typed-welcome-copy.tsx +18 -0
  63. package/src/components/chat/gallery-thread/ui/tooltip.tsx +22 -0
  64. package/src/components/chat/gallery-thread/work-chain-summary.tsx +48 -0
  65. package/src/components/chat/gallery-thread/work-chain.tsx +110 -0
  66. package/src/components/chat/gallery-thread/work-status.ts +66 -0
  67. package/src/components/chat/overlay-scrollbar.tsx +86 -0
  68. package/src/components/chat/sanitize-mermaid-svg.ts +38 -0
  69. package/src/components/chat/skins/SOURCE.md +36 -0
  70. package/src/components/chat/skins/base/attachment.aui.tsx +287 -0
  71. package/src/components/chat/skins/base/aui-default/README.md +45 -0
  72. package/src/components/chat/skins/base/aui-default/collapsible-root.tsx +19 -0
  73. package/src/components/chat/skins/base/aui-default/collapsible.tsx +21 -0
  74. package/src/components/chat/skins/base/aui-default/reasoning.aui.tsx +120 -0
  75. package/src/components/chat/skins/base/aui-default/reasoning.tsx +331 -0
  76. package/src/components/chat/skins/base/aui-default/surfaces.ts +7 -0
  77. package/src/components/chat/skins/base/aui-default/tool-fallback.aui.tsx +772 -0
  78. package/src/components/chat/skins/base/aui-default/tool-group.aui.tsx +241 -0
  79. package/src/components/chat/skins/base/docs-model-options.ts +6 -0
  80. package/src/components/chat/skins/base/elements/assistant-trace.aui.tsx +169 -0
  81. package/src/components/chat/skins/base/elements/composer-trigger-popover.aui.tsx +271 -0
  82. package/src/components/chat/skins/base/elements/directive-text.aui.tsx +29 -0
  83. package/src/components/chat/skins/base/elements/directive-text.tsx +76 -0
  84. package/src/components/chat/skins/base/elements/message-timing.aui.tsx +104 -0
  85. package/src/components/chat/skins/base/elements/model-selector.aui.tsx +140 -0
  86. package/src/components/chat/skins/base/elements/model-selector.tsx +720 -0
  87. package/src/components/chat/skins/base/elements/quote.aui.tsx +290 -0
  88. package/src/components/chat/skins/base/elements/work-chain.tsx +100 -0
  89. package/src/components/chat/skins/base/markdown-text.tsx +294 -0
  90. package/src/components/chat/skins/base/model.ts +1 -0
  91. package/src/components/chat/skins/base/thread.tsx +1050 -0
  92. package/src/components/chat/skins/base/tooltip-icon-button.tsx +56 -0
  93. package/src/components/chat/skins/base/ui/avatar.tsx +115 -0
  94. package/src/components/chat/skins/base/ui/badge.tsx +51 -0
  95. package/src/components/chat/skins/base/ui/button.tsx +67 -0
  96. package/src/components/chat/skins/base/ui/command.tsx +185 -0
  97. package/src/components/chat/skins/base/ui/dialog.tsx +168 -0
  98. package/src/components/chat/skins/base/ui/dot-matrix.tsx +267 -0
  99. package/src/components/chat/skins/base/ui/popover.tsx +97 -0
  100. package/src/components/chat/skins/base/ui/skeleton.tsx +20 -0
  101. package/src/components/chat/skins/base/ui/textarea.tsx +24 -0
  102. package/src/components/chat/skins/base/ui/tooltip.tsx +73 -0
  103. package/src/components/chat/skins/base-assistant-ui/config-provider.tsx +90 -0
  104. package/src/components/chat/skins/base-assistant-ui/defaults.ts +419 -0
  105. package/src/components/chat/skins/base-assistant-ui/index.tsx +44 -0
  106. package/src/components/chat/skins/chatgpt.tsx +448 -0
  107. package/src/components/chat/skins/claude.tsx +380 -0
  108. package/src/components/chat/skins/digichat-composer-toolbar.tsx +151 -0
  109. package/src/components/chat/skins/digichat-context-meter-shares.ts +158 -0
  110. package/src/components/chat/skins/digichat-context-meter.tsx +243 -0
  111. package/src/components/chat/skins/digichat-meter-tone.ts +26 -0
  112. package/src/components/chat/skins/digichat-usage-meter.tsx +103 -0
  113. package/src/components/chat/skins/digichat.tsx +144 -0
  114. package/src/components/chat/skins/expo-react-native.tsx +29 -0
  115. package/src/components/chat/skins/gemini.tsx +322 -0
  116. package/src/components/chat/skins/grok-icon.tsx +34 -0
  117. package/src/components/chat/skins/grok.tsx +369 -0
  118. package/src/components/chat/skins/index.ts +46 -0
  119. package/src/components/chat/skins/perplexity.tsx +462 -0
  120. package/src/components/chat/skins/product-page-assistant/assistant-modal.tsx +73 -0
  121. package/src/components/chat/skins/product-page-assistant/index.tsx +19 -0
  122. package/src/components/chat/skins/product-page-assistant/product-dashboard.tsx +164 -0
  123. package/src/components/chat/skins/react-ink.tsx +97 -0
  124. package/src/components/chat/skins/thread-skin-host-contract.ts +102 -0
  125. package/src/components/chat/skins/thread-skin-view.tsx +156 -0
  126. package/src/components/chat/skins/thread-skins.ts +143 -0
  127. package/src/components/chat/skins/tooltip-icon-button.tsx +35 -0
  128. package/src/components/chat/skins/ui/dropdown-menu.tsx +272 -0
  129. package/src/components/chat/skins/webpage-assistant/assistant-config.ts +238 -0
  130. package/src/components/chat/skins/webpage-assistant/assistant-modal.tsx +78 -0
  131. package/src/components/chat/skins/webpage-assistant/config-provider.tsx +132 -0
  132. package/src/components/chat/skins/webpage-assistant/docs-app.tsx +106 -0
  133. package/src/components/chat/skins/webpage-assistant/docs-article.tsx +109 -0
  134. package/src/components/chat/skins/webpage-assistant/docs-assistant.tsx +73 -0
  135. package/src/components/chat/skins/webpage-assistant/docs-nav.tsx +81 -0
  136. package/src/components/chat/skins/webpage-assistant/host-ui.ts +79 -0
  137. package/src/components/chat/skins/webpage-assistant/index.tsx +12 -0
  138. package/src/components/chat/skins/webpage-assistant/markdown-page.tsx +11 -0
  139. package/src/components/chat/skins/webpage-assistant/pages.ts +9 -0
  140. package/src/components/chat/skins/webpage-assistant/types.ts +178 -0
  141. package/src/components/chat/skins/webpage-assistant/use-mobile.ts +19 -0
  142. package/src/components/chat/stock/SOURCE.md +90 -0
  143. package/src/components/chat/stock/artifacts-panel.tsx +305 -0
  144. package/src/components/chat/stock/attachment.aui.tsx +280 -0
  145. package/src/components/chat/stock/chat-notice.tsx +143 -0
  146. package/src/components/chat/stock/chat-private-mode.tsx +64 -0
  147. package/src/components/chat/stock/deploy-ui-context.tsx +89 -0
  148. package/src/components/chat/stock/embed-chat-prefs.tsx +471 -0
  149. package/src/components/chat/stock/file.tsx +265 -0
  150. package/src/components/chat/stock/follow-up-suggestions.aui.tsx +83 -0
  151. package/src/components/chat/stock/image.tsx +531 -0
  152. package/src/components/chat/stock/index.ts +129 -0
  153. package/src/components/chat/stock/json-view.tsx +140 -0
  154. package/src/components/chat/stock/markdown-text.tsx +319 -0
  155. package/src/components/chat/stock/message-error.aui.tsx +96 -0
  156. package/src/components/chat/stock/message-export-menu.tsx +156 -0
  157. package/src/components/chat/stock/palette-row-preview.tsx +26 -0
  158. package/src/components/chat/stock/reasoning.aui.tsx +120 -0
  159. package/src/components/chat/stock/reasoning.tsx +335 -0
  160. package/src/components/chat/stock/skin-chrome.tsx +81 -0
  161. package/src/components/chat/stock/skin-credit.tsx +63 -0
  162. package/src/components/chat/stock/skin-palette-bridge.tsx +235 -0
  163. package/src/components/chat/stock/skin-palette-context.ts +16 -0
  164. package/src/components/chat/stock/skin-runtime.tsx +52 -0
  165. package/src/components/chat/stock/skin-slash-palette.tsx +393 -0
  166. package/src/components/chat/stock/skin-types.ts +217 -0
  167. package/src/components/chat/stock/stock-chat-prefs-host.tsx +501 -0
  168. package/src/components/chat/stock/stock-send-gate.tsx +94 -0
  169. package/src/components/chat/stock/stock-shape.tsx +39 -0
  170. package/src/components/chat/stock/thread.aui.tsx +645 -0
  171. package/src/components/chat/stock/tool-display.ts +6 -0
  172. package/src/components/chat/stock/tool-fallback.aui.tsx +866 -0
  173. package/src/components/chat/stock/tool-group.aui.tsx +244 -0
  174. package/src/components/chat/stock/tool-surface.ts +120 -0
  175. package/src/components/chat/stock/tooltip-icon-button.tsx +49 -0
  176. package/src/components/chat/stock/ui/avatar.tsx +108 -0
  177. package/src/components/chat/stock/ui/button.tsx +81 -0
  178. package/src/components/chat/stock/ui/collapsible.tsx +21 -0
  179. package/src/components/chat/stock/ui/dialog.tsx +163 -0
  180. package/src/components/chat/stock/ui/skeleton.tsx +13 -0
  181. package/src/components/chat/stock/ui/textarea.tsx +20 -0
  182. package/src/components/chat/stock/ui/tooltip.tsx +68 -0
  183. package/src/components/chat/stock/use-attachment-src.ts +42 -0
  184. package/src/components/chat/stock/use-copy-to-clipboard.ts +29 -0
  185. package/src/components/chat/strip-model-boilerplate.ts +42 -0
  186. package/src/components/chat/suggestion-cycle.tsx +230 -0
  187. package/src/components/chat/suggestion-scroll-row.tsx +81 -0
  188. package/src/components/chat/trace-grouping/chain-group-by.ts +44 -0
  189. package/src/components/chat/trace-grouping/chain-state.ts +141 -0
  190. package/src/components/chat/trace-grouping/index.ts +32 -0
  191. package/src/components/chat/trace-grouping/tool-row.ts +74 -0
  192. package/src/components/chat/trace-grouping/use-deploy-work-disclosure.ts +35 -0
  193. package/src/components/chat/trace-grouping/use-work-chain.ts +103 -0
  194. package/src/components/chat/trace-i18n/core.ts +48 -0
  195. package/src/components/chat/trace-i18n/index.tsx +23 -0
  196. package/src/components/chat/trace-i18n/locales/en.ts +24 -0
  197. package/src/components/chat/trace-i18n/locales/fr.ts +28 -0
  198. package/src/components/chat/trace-i18n/types.ts +35 -0
  199. package/src/components/chat/trace-spacing.ts +249 -0
  200. package/src/components/chat/transcript/activity-view.ts +375 -0
  201. package/src/components/chat/transcript/chat-export.ts +133 -0
  202. package/src/components/chat/transcript/index.ts +10 -0
  203. package/src/components/chat/transcript/save-file.ts +209 -0
  204. package/src/components/chat/transcript/transcript-markdown.ts +428 -0
  205. package/src/components/chat/transcript/types.ts +81 -0
  206. package/src/components/chat/turn-outcome.ts +52 -0
  207. package/src/components/chat/use-warmup-phase.ts +18 -0
  208. package/src/components/chat/work-status-lead.tsx +49 -0
  209. package/src/components/chrome.tsx +264 -0
  210. package/src/components/command-palette/CommandPalette.tsx +404 -0
  211. package/src/components/command-palette/index.ts +6 -0
  212. package/src/components/contact/ContactMailto.tsx +112 -0
  213. package/src/components/contact/index.ts +5 -0
  214. package/src/components/conviction/ConvictionMeter.tsx +40 -0
  215. package/src/components/conviction/SignedConvictionBadge.tsx +26 -0
  216. package/src/components/conviction/index.ts +7 -0
  217. package/src/components/data-layout/BentoGrid.tsx +52 -0
  218. package/src/components/data-layout/CardRail.tsx +150 -0
  219. package/src/components/data-layout/DotMatrixStat.tsx +65 -0
  220. package/src/components/data-layout/FeatureCell.tsx +80 -0
  221. package/src/components/data-layout/MediaFrame.tsx +125 -0
  222. package/src/components/data-layout/ModuleGrid.tsx +735 -0
  223. package/src/components/data-layout/Odometer.tsx +149 -0
  224. package/src/components/data-layout/ProductFrame.tsx +79 -0
  225. package/src/components/data-layout/TestimonialWall.tsx +139 -0
  226. package/src/components/data-layout/index.ts +19 -0
  227. package/src/components/data-layout/treemap.ts +368 -0
  228. package/src/components/deck/DeckStack.tsx +243 -0
  229. package/src/components/desk/DataTable.tsx +373 -0
  230. package/src/components/desk/KpiGrid.tsx +80 -0
  231. package/src/components/desk/Sparkline.tsx +63 -0
  232. package/src/components/desk/StateBlock.tsx +132 -0
  233. package/src/components/desk/index.ts +18 -0
  234. package/src/components/diagrams/ArchitectureDiagram.tsx +350 -0
  235. package/src/components/diagrams/ArchitectureTour.tsx +912 -0
  236. package/src/components/diagrams/TerminalSchematic.tsx +192 -0
  237. package/src/components/diagrams/architecture-svg.tsx +384 -0
  238. package/src/components/diagrams/index.ts +30 -0
  239. package/src/components/diagrams/mermaid-theme.ts +115 -0
  240. package/src/components/diagrams/tour-camera.ts +171 -0
  241. package/src/components/docs/CodeTabs.tsx +90 -0
  242. package/src/components/docs/CopyCommand.tsx +151 -0
  243. package/src/components/docs/DocsLayout.tsx +197 -0
  244. package/src/components/docs/DocsSearch.tsx +97 -0
  245. package/src/components/docs/Endpoint.tsx +135 -0
  246. package/src/components/document/DocumentFrame.tsx +43 -0
  247. package/src/components/document/GlyphList.tsx +51 -0
  248. package/src/components/document/PageTitle.tsx +44 -0
  249. package/src/components/document/Prose.tsx +38 -0
  250. package/src/components/document/Section.tsx +55 -0
  251. package/src/components/document/index.ts +13 -0
  252. package/src/components/effects-chrome/AnnouncementBar.tsx +88 -0
  253. package/src/components/effects-chrome/HorizontalScrollTrack.tsx +461 -0
  254. package/src/components/effects-chrome/Pipeline.tsx +226 -0
  255. package/src/components/effects-chrome/RotatingPrompts.tsx +116 -0
  256. package/src/components/effects-chrome/StackingPanels.tsx +101 -0
  257. package/src/components/effects-chrome/TabStrip.tsx +232 -0
  258. package/src/components/effects-chrome/ToastStack.tsx +201 -0
  259. package/src/components/effects-chrome/horizontal-track-core.ts +70 -0
  260. package/src/components/effects-chrome/index.ts +35 -0
  261. package/src/components/emblems.tsx +188 -0
  262. package/src/components/faviconTheme.ts +23 -0
  263. package/src/components/figure/Figure.tsx +38 -0
  264. package/src/components/figure/index.ts +2 -0
  265. package/src/components/finance-charts/DrawdownPlot.tsx +76 -0
  266. package/src/components/finance-charts/EquityCurve.tsx +71 -0
  267. package/src/components/finance-charts/PriceChart.tsx +119 -0
  268. package/src/components/finance-charts/chart-host.tsx +236 -0
  269. package/src/components/finance-charts/chart-scale.ts +93 -0
  270. package/src/components/finance-charts/demo-data.ts +88 -0
  271. package/src/components/finance-charts/index.ts +46 -0
  272. package/src/components/finance-charts/lw-chart.tsx +292 -0
  273. package/src/components/finance-composites/MarketBar.tsx +243 -0
  274. package/src/components/finance-composites/OrderBook.tsx +133 -0
  275. package/src/components/finance-composites/PerformanceDashboard.tsx +185 -0
  276. package/src/components/finance-composites/SortableTable.tsx +144 -0
  277. package/src/components/finance-composites/StockTicker.tsx +65 -0
  278. package/src/components/finance-composites/SyncedTearsheet.tsx +226 -0
  279. package/src/components/finance-composites/index.ts +28 -0
  280. package/src/components/finance-tearsheet/KpiStrip.tsx +49 -0
  281. package/src/components/finance-tearsheet/LiveBadge.tsx +29 -0
  282. package/src/components/finance-tearsheet/ReturnsMatrix.tsx +321 -0
  283. package/src/components/finance-tearsheet/StrategyTearsheet.tsx +99 -0
  284. package/src/components/finance-tearsheet/TearsheetCard.tsx +54 -0
  285. package/src/components/finance-tearsheet/TradeLogTable.tsx +73 -0
  286. package/src/components/finance-tearsheet/charts.tsx +2624 -0
  287. package/src/components/finance-tearsheet/demo-data.ts +177 -0
  288. package/src/components/finance-tearsheet/format.ts +41 -0
  289. package/src/components/finance-tearsheet/index.ts +120 -0
  290. package/src/components/finance-tearsheet/print.ts +52 -0
  291. package/src/components/finance-tearsheet/risk-bands.ts +48 -0
  292. package/src/components/finance-tearsheet/stats.ts +35 -0
  293. package/src/components/finance-tearsheet/strategy-sheet-model.ts +238 -0
  294. package/src/components/finance-tearsheet/types.ts +58 -0
  295. package/src/components/footer/FooterCells.tsx +109 -0
  296. package/src/components/footer/index.ts +6 -0
  297. package/src/components/graph.tsx +158 -0
  298. package/src/components/icons.tsx +98 -0
  299. package/src/components/landing/PixelWordmark.tsx +36 -0
  300. package/src/components/logos.ts +39 -0
  301. package/src/components/marquee/Marquee.tsx +204 -0
  302. package/src/components/metrics/PerfMetrics.tsx +68 -0
  303. package/src/components/metrics/StatCounter.tsx +104 -0
  304. package/src/components/page-geometry.tsx +177 -0
  305. package/src/components/pricing/Pricing.tsx +174 -0
  306. package/src/components/pricing/PricingMatrix.tsx +219 -0
  307. package/src/components/prose/index.ts +2 -0
  308. package/src/components/prose/prose.tsx +86 -0
  309. package/src/components/repo-activity/RepoActivity.tsx +599 -0
  310. package/src/components/repo-activity/RepoHeatmap.tsx +225 -0
  311. package/src/components/repo-activity/demo.ts +201 -0
  312. package/src/components/repo-activity/fetch.ts +211 -0
  313. package/src/components/repo-activity/heatmap.ts +123 -0
  314. package/src/components/repo-activity/index.ts +28 -0
  315. package/src/components/repo-activity/types.ts +99 -0
  316. package/src/components/stages/NumberedStages.tsx +116 -0
  317. package/src/components/symbols/marks.tsx +116 -0
  318. package/src/components/symbols/terminal-lockup.tsx +136 -0
  319. package/src/components/symbols/terminal-marks.tsx +226 -0
  320. package/src/components/terminal/ChatResponseLoader.tsx +67 -0
  321. package/src/components/terminal/ContainerBootLoader.tsx +82 -0
  322. package/src/components/terminal/TerminalStepCaret.tsx +202 -0
  323. package/src/components/themeInit.ts +24 -0
  324. package/src/components/typography/MotionReveal.tsx +108 -0
  325. package/src/components/typography/TypewriterReveal.tsx +101 -0
  326. package/src/components/typography/WordReveal.tsx +143 -0
  327. package/src/data/modules.ts +378 -0
  328. package/src/data/subsystems.ts +101 -0
  329. package/src/index.ts +587 -0
  330. package/src/lib/base-path.ts +60 -0
  331. package/src/lib/cx.ts +25 -0
  332. package/src/lib/gloomberb.ts +69 -0
  333. package/src/lib/record.ts +19 -0
  334. package/src/lib/stub-payload.ts +183 -0
  335. package/src/lib/useBodyScrollLock.ts +44 -0
  336. package/src/lib/utils.ts +6 -0
  337. package/src/motion/primitives.tsx +105 -0
  338. package/src/motion/scroll-glide.ts +62 -0
  339. package/src/motion/scrolly-core.ts +38 -0
  340. package/src/motion/scrolly.tsx +95 -0
  341. package/src/navigation/HashScrollManager.tsx +167 -0
  342. package/src/navigation/hashScroll.ts +78 -0
  343. package/src/replay/browser.ts +280 -0
  344. package/src/replay/chat-export-run.ts +121 -0
  345. package/src/replay/export-format.ts +25 -0
  346. package/src/replay/export-mount.ts +32 -0
  347. package/src/replay/filename.ts +54 -0
  348. package/src/replay/index.ts +21 -0
  349. package/src/replay/redact-dom.ts +178 -0
  350. package/src/replay/redact.ts +113 -0
  351. package/src/replay/snapshot.ts +659 -0
  352. package/src/styles/account-auth.css +339 -0
  353. package/src/styles/brand-wordmark.css +11 -0
  354. package/src/styles/card-rail.css +120 -0
  355. package/src/styles/chat-aui.css +1143 -0
  356. package/src/styles/chat-core.css +469 -0
  357. package/src/styles/chat-digichat.css +2531 -0
  358. package/src/styles/chat-math.css +70 -0
  359. package/src/styles/chat-skin-palette.css +138 -0
  360. package/src/styles/chat-stock-menu.css +37 -0
  361. package/src/styles/chat-widgets.css +190 -0
  362. package/src/styles/command-palette.css +372 -0
  363. package/src/styles/controls-core.css +2261 -0
  364. package/src/styles/controls-overlay.css +603 -0
  365. package/src/styles/data-layout.css +288 -0
  366. package/src/styles/deck.css +141 -0
  367. package/src/styles/diagrams.css +1860 -0
  368. package/src/styles/digichat-app-theme.css +250 -0
  369. package/src/styles/digichat-boot-loader.css +487 -0
  370. package/src/styles/digichat-launcher.css +377 -0
  371. package/src/styles/docs.css +165 -0
  372. package/src/styles/effects-chrome.css +888 -0
  373. package/src/styles/finance-composites.css +214 -0
  374. package/src/styles/finance-tearsheet-overlay.css +90 -0
  375. package/src/styles/finance-tearsheet.css +945 -0
  376. package/src/styles/marquee.css +168 -0
  377. package/src/styles/metrics.css +82 -0
  378. package/src/styles/nav-shell.css +551 -0
  379. package/src/styles/pricing.css +79 -0
  380. package/src/styles/repo-activity.css +575 -0
  381. package/src/styles/stages.css +69 -0
  382. package/src/styles/terminal-loaders.css +122 -0
  383. package/src/styles/terminal-manifest.css +228 -0
  384. package/src/styles/web-theme.css +1007 -0
  385. package/src/styles/word-reveal.css +204 -0
  386. package/src/theme/apply-theme.ts +214 -0
  387. package/src/theme/index.ts +27 -0
  388. package/src/theme/palette-registry.ts +855 -0
  389. package/src/theme/tui-prefs.ts +64 -0
  390. package/src/ui/alert.tsx +78 -0
  391. package/src/ui/avatar.tsx +104 -0
  392. package/src/ui/badge.tsx +75 -0
  393. package/src/ui/breadcrumb.tsx +61 -0
  394. package/src/ui/button.tsx +67 -0
  395. package/src/ui/card.tsx +139 -0
  396. package/src/ui/checkbox.tsx +27 -0
  397. package/src/ui/collapsible.tsx +32 -0
  398. package/src/ui/date-pager.tsx +325 -0
  399. package/src/ui/dialog.tsx +157 -0
  400. package/src/ui/dropdown-menu.tsx +267 -0
  401. package/src/ui/empty-state.tsx +165 -0
  402. package/src/ui/field.tsx +104 -0
  403. package/src/ui/form.tsx +36 -0
  404. package/src/ui/icon-button.tsx +36 -0
  405. package/src/ui/index.ts +34 -0
  406. package/src/ui/input.tsx +33 -0
  407. package/src/ui/kbd.tsx +30 -0
  408. package/src/ui/label.tsx +32 -0
  409. package/src/ui/pager.tsx +119 -0
  410. package/src/ui/pagination.tsx +126 -0
  411. package/src/ui/radio-group.tsx +51 -0
  412. package/src/ui/search-bar.tsx +85 -0
  413. package/src/ui/segmented-control.tsx +76 -0
  414. package/src/ui/select.tsx +257 -0
  415. package/src/ui/separator.tsx +24 -0
  416. package/src/ui/sheet.tsx +141 -0
  417. package/src/ui/skeleton.tsx +76 -0
  418. package/src/ui/slider.tsx +76 -0
  419. package/src/ui/switch.tsx +31 -0
  420. package/src/ui/table.tsx +179 -0
  421. package/src/ui/tabs.tsx +89 -0
  422. package/src/ui/tags-input.tsx +168 -0
  423. package/src/ui/textarea.tsx +17 -0
  424. package/src/ui/tooltip.tsx +71 -0
@@ -0,0 +1,599 @@
1
+ "use client";
2
+
3
+ /**
4
+ * RepoActivity — snapshot-first public GitHub velocity, compact or detailed.
5
+ * Renders the committed snapshot on the server; an optional live refresh runs
6
+ * after hydration and replaces every figure atomically, or is ignored so the
7
+ * snapshot never blanks. Stars/forks/watchers are not collected. 30-day
8
+ * velocity and the current backlog are labeled as different measurements.
9
+ *
10
+ * The detailed contribution grid shortens as its column narrows rather than
11
+ * scrolling horizontally (`weeks`, below).
12
+ *
13
+ * Wiring (in the consuming app):
14
+ * globals.css @import "@digithings-ai/ui/styles/repo-activity.css";
15
+ * @source "<path-to>/packages/ui/src/components/repo-activity";
16
+ */
17
+ import { useEffect, useRef, useState, type RefObject } from "react";
18
+
19
+ import { GitHubGlyph } from "../icons";
20
+ import { fetchRepoActivityLive } from "./fetch";
21
+ import { RepoHeatmap } from "./RepoHeatmap";
22
+ import {
23
+ cloneParts,
24
+ grouped,
25
+ isoDay,
26
+ type RepoActivityLiveConfig,
27
+ type RepoActivitySnapshot,
28
+ type RepoIssueItem,
29
+ type RepoPullItem,
30
+ } from "./types";
31
+
32
+ /**
33
+ * One module's current version, for the activity variant's release rail.
34
+ * `name` is the module (digichat, digigraph, …); `version` is the tag as it
35
+ * should be read, without the module prefix repeated.
36
+ *
37
+ * `title` and `date` are the optional live layer. A host that has fetched the
38
+ * module's newest GitHub release fills them with that release's call-out line
39
+ * and publish date, and points `url` at the tag. A module with no release of
40
+ * its own leaves them out rather than inventing a feature line — the declared
41
+ * `version` is the fallback for exactly those modules, because release-please
42
+ * only cuts releases for digichat and digiskills, so most of the rail is the
43
+ * version each module declares for itself
44
+ * (see apps/digithings-web/lib/moduleCounts.ts).
45
+ */
46
+ export type RepoModuleRelease = {
47
+ name: string;
48
+ version: string;
49
+ url?: string;
50
+ /** The newest release's call-out line, when a release exists. */
51
+ title?: string;
52
+ /** ISO publish stamp of that release (`2026-09-21T12:38:12Z`). */
53
+ date?: string;
54
+ };
55
+
56
+ /** The maintainer behind the repo, credited under the activity variant. */
57
+ export type RepoContributor = {
58
+ name: string;
59
+ role?: string;
60
+ /** Avatar URL; a monogram is drawn when it is absent. */
61
+ avatarUrl?: string;
62
+ url?: string;
63
+ };
64
+
65
+ export type RepoActivityProps = {
66
+ variant: "compact" | "detailed" | "activity";
67
+ snapshot: RepoActivitySnapshot;
68
+ repoUrl: string;
69
+ /** When set, fetch public GitHub data after mount; keep snapshot on any failure. */
70
+ live?: RepoActivityLiveConfig;
71
+ cloneCommand?: string;
72
+ contributingUrl?: string;
73
+ /**
74
+ * Weeks of contribution history to request, for the detailed variant. The
75
+ * grid never exceeds this, but it is measured down when the column is too
76
+ * narrow for it (see `weeksThatFit`), so the history shortens instead of
77
+ * scrolling. Defaults to 53 — a full year, GitHub-style.
78
+ */
79
+ weeks?: number;
80
+ /** Activity variant: the maintainer credited under the ledger. */
81
+ contributor?: RepoContributor;
82
+ /** Build the contribution grid left to right when it scrolls into view. */
83
+ heatBuild?: boolean;
84
+ className?: string;
85
+ };
86
+
87
+ export function RepoActivity({
88
+ variant,
89
+ snapshot,
90
+ repoUrl,
91
+ live,
92
+ cloneCommand,
93
+ contributingUrl,
94
+ weeks = 53,
95
+ contributor,
96
+ heatBuild = false,
97
+ className,
98
+ }: RepoActivityProps) {
99
+ const [data, setData] = useState(snapshot);
100
+ const [source, setSource] = useState<"snapshot" | "live">("snapshot");
101
+ const heatRef = useRef<HTMLDivElement | null>(null);
102
+ /** Measured fit; null until a browser measures, so SSR keeps `weeks`. */
103
+ const [fitWeeks, setFitWeeks] = useState<number | null>(null);
104
+
105
+ useEffect(() => {
106
+ if (!live) return;
107
+ let cancelled = false;
108
+ fetchRepoActivityLive(live).then(
109
+ (next) => {
110
+ if (cancelled) return;
111
+ setData(applyLive(snapshot, next));
112
+ setSource("live");
113
+ },
114
+ () => {
115
+ /* keep snapshot — no loading or error surface */
116
+ },
117
+ );
118
+ return () => {
119
+ cancelled = true;
120
+ };
121
+ // Mount-only: the static snapshot is the SSR contract; live is a one-shot enhance.
122
+ // eslint-disable-next-line react-hooks/exhaustive-deps
123
+ }, []);
124
+
125
+ // Shorten the grid to the column instead of letting it scroll. Guarded on
126
+ // ResizeObserver so the server and jsdom keep rendering exactly `weeks`, which
127
+ // is what every existing snapshot assertion expects.
128
+ //
129
+ // The width is read from the element, and the element can measure 0 on the
130
+ // first pass (before the parent grid has laid out, or on a route where the
131
+ // band is still below the fold). Feeding that 0 to `weeksThatFit` would floor
132
+ // the result at MIN_HEAT_WEEKS and then the effect's own `[weeks]` dep would
133
+ // keep re-clamping to the shortened value, so the graph stayed at 12 weeks
134
+ // even after the column reached full width. Two guards: skip a zero-width
135
+ // measurement so the default (`weeks`) holds, and re-measure once on the next
136
+ // frame, because a ResizeObserver only fires on a size *change* and will not
137
+ // report a width that was already correct by the time it attached.
138
+ useEffect(() => {
139
+ const el = heatRef.current;
140
+ if (!el || typeof ResizeObserver === "undefined") return;
141
+ const measure = () => {
142
+ const width = el.clientWidth;
143
+ if (width <= 0) return;
144
+ setFitWeeks(weeksThatFit(width, weeks));
145
+ };
146
+ measure();
147
+ const frame = requestAnimationFrame(measure);
148
+ const observer = new ResizeObserver(measure);
149
+ observer.observe(el);
150
+ return () => {
151
+ cancelAnimationFrame(frame);
152
+ observer.disconnect();
153
+ };
154
+ }, [weeks]);
155
+
156
+ const heatWeeks = fitWeeks ?? weeks;
157
+ // RepoHeatmap labels the window from `weeks` but totals EVERY cell it is
158
+ // handed, so the series has to be cut to the same window or the heading would
159
+ // count weeks the grid does not draw.
160
+ const heatData = data.dailyContributions
161
+ ? data.dailyContributions.slice(-heatWeeks * 7)
162
+ : undefined;
163
+
164
+ const cls = [
165
+ "ra",
166
+ variant === "compact" ? "ra-compact" : variant === "activity" ? "ra-activity" : "ra-detailed",
167
+ className ?? "",
168
+ ]
169
+ .filter(Boolean)
170
+ .join(" ");
171
+
172
+ return (
173
+ <article
174
+ className={cls}
175
+ data-variant={variant}
176
+ data-source={source}
177
+ aria-label="Repository activity"
178
+ >
179
+ {variant === "compact" ? (
180
+ <Compact data={data} repoUrl={repoUrl} source={source} />
181
+ ) : variant === "activity" ? (
182
+ <Activity
183
+ data={data}
184
+ repoUrl={repoUrl}
185
+ heatRef={heatRef}
186
+ heatWeeks={heatWeeks}
187
+ heatData={heatData}
188
+ heatBuild={heatBuild}
189
+ contributor={contributor}
190
+ />
191
+ ) : (
192
+ <Detailed
193
+ data={data}
194
+ repoUrl={repoUrl}
195
+ source={source}
196
+ cloneCommand={cloneCommand}
197
+ contributingUrl={contributingUrl}
198
+ heatRef={heatRef}
199
+ heatWeeks={heatWeeks}
200
+ heatData={heatData}
201
+ heatBuild={heatBuild}
202
+ />
203
+ )}
204
+ </article>
205
+ );
206
+ }
207
+
208
+ /**
209
+ * The detailed grid is a fixed 10px cell with a 3px gap, sitting after a 1.65rem
210
+ * day rail and a 0.45rem gap (`repo-activity.css`), so a W-week frame measures
211
+ * `33.6 + 13W` px. Past the container it would scroll horizontally
212
+ * (`.ra-heat-body { overflow-x: auto }`), which reads as a cut-off history; the
213
+ * owner asked for the history to shorten instead. So the width picks the week
214
+ * count — 53 at a desktop frame (~720px of grid), fewer as the column narrows,
215
+ * and never below a quarter so the graph stays readable.
216
+ */
217
+ /* The measured fit cell is 10.4px because the 7-row day rail and the cell's
218
+ 1:1 aspect ratio set a 10.4px min-content width. Budget the real floor, not
219
+ 10px, or the last column overhangs by a few pixels at some widths. */
220
+ const HEAT_CELL = 10.4;
221
+ const HEAT_CELL_GAP = 3;
222
+ const HEAT_RAIL = 26.4 + 7.2;
223
+ const MIN_HEAT_WEEKS = 12;
224
+
225
+ function weeksThatFit(columnWidth: number, ceiling: number): number {
226
+ // An unmeasured column is not a narrow one: shorten nothing until a real
227
+ // width exists. The caller already skips zero-width reads, so this is the
228
+ // belt to that braces.
229
+ if (!Number.isFinite(columnWidth) || columnWidth <= 0) return ceiling;
230
+ const columns = Math.floor(
231
+ (columnWidth - HEAT_RAIL + HEAT_CELL_GAP) / (HEAT_CELL + HEAT_CELL_GAP),
232
+ );
233
+ // The grid draws calendar weeks, so a W-week span can occupy W+1 columns when
234
+ // the range starts or ends mid-week. Reserve that column — without it the
235
+ // frame overruns the body by one cell and the body scrolls after all, which
236
+ // is the behaviour this exists to remove.
237
+ const weeks = columns - 1;
238
+ return Math.max(Math.min(MIN_HEAT_WEEKS, ceiling), Math.min(ceiling, weeks));
239
+ }
240
+
241
+ function applyLive(
242
+ snapshot: RepoActivitySnapshot,
243
+ live: Omit<RepoActivitySnapshot, "features" | "modules">,
244
+ ): RepoActivitySnapshot {
245
+ return {
246
+ ...snapshot,
247
+ ...live,
248
+ features: snapshot.features,
249
+ modules: snapshot.modules,
250
+ };
251
+ }
252
+
253
+ function Compact({
254
+ data,
255
+ repoUrl,
256
+ source,
257
+ }: {
258
+ data: RepoActivitySnapshot;
259
+ repoUrl: string;
260
+ source: "snapshot" | "live";
261
+ }) {
262
+ const pulls = (data.mergedPulls ?? []).slice(0, 3);
263
+ return (
264
+ <>
265
+ <header className="ra-head">
266
+ <p className="ra-kicker">{`// last ${data.windowDays} days on ${data.branch}`}</p>
267
+ <Stamp source={source} at={data.generatedAt} />
268
+ </header>
269
+ <ul className="ra-metrics" role="list">
270
+ <Metric n={data.commits} label="commits" />
271
+ <Metric n={data.pullsMerged} label="PRs merged" />
272
+ <Metric n={data.issuesClosed} label="issues closed" />
273
+ </ul>
274
+ <div className="ra-meta">
275
+ <ReleaseLink release={data.latestRelease} />
276
+ <RepoLink href={repoUrl} />
277
+ </div>
278
+ {pulls.length ? (
279
+ <ol className="ra-list" role="list">
280
+ {pulls.map((p) => (
281
+ <PullRow key={p.number} item={p} stamp={p.mergedAt} />
282
+ ))}
283
+ </ol>
284
+ ) : null}
285
+ </>
286
+ );
287
+ }
288
+
289
+ /**
290
+ * The in-between variant: summary metrics beside the contribution grid, then a
291
+ * horizontal rail of every module's current version and the maintainer.
292
+ *
293
+ * The detailed variant answers "what is happening" with two ledgers (merged
294
+ * recently, open issues); the compact one answers "is this alive" with three
295
+ * counts. This one answers "is this alive, and what has shipped" — the metrics
296
+ * and the graph are kept, the ledgers are dropped for the version ledger, and
297
+ * the graph is asked to fit (`fit`) so it fills its column instead of scrolling
298
+ * and its squares scale with the width.
299
+ *
300
+ * The grid sits in the right column because it is the widest element and the
301
+ * metrics are narrow: putting the counts left and the graph right is what keeps
302
+ * the first rows from being mostly empty, and the graph then expands into
303
+ * whatever width is left. Below 900px it stacks.
304
+ *
305
+ * No latest-release line and no snapshot stamp here — the owner called that
306
+ * "ai slop like the latest digichat v1.5 snapshot date ... isn't necessary" and
307
+ * the version rail already carries every module's release. The repo link moves
308
+ * to the foot's bottom-right corner, where "browse the repo" belongs.
309
+ */
310
+ function Activity({
311
+ data,
312
+ repoUrl,
313
+ heatRef,
314
+ heatWeeks,
315
+ heatData,
316
+ heatBuild,
317
+ contributor,
318
+ }: {
319
+ data: RepoActivitySnapshot;
320
+ repoUrl: string;
321
+ heatRef: RefObject<HTMLDivElement | null>;
322
+ heatWeeks: number;
323
+ heatData: RepoActivitySnapshot["dailyContributions"];
324
+ heatBuild?: boolean;
325
+ contributor?: RepoContributor;
326
+ }) {
327
+ return (
328
+ <>
329
+ <div className="ra-activity-top">
330
+ <div className="ra-activity-metrics">
331
+ <div className="ra-group">
332
+ <p className="ra-kicker">{`// last ${data.windowDays} days on ${data.branch}`}</p>
333
+ <ul className="ra-metrics" role="list">
334
+ <Metric n={data.commits} label="commits" />
335
+ <Metric n={data.pullsMerged} label="PRs merged" />
336
+ <Metric n={data.issuesClosed} label="issues closed" />
337
+ </ul>
338
+ </div>
339
+ <div className="ra-group">
340
+ <p className="ra-kicker">{"// current backlog"}</p>
341
+ <ul className="ra-metrics" role="list">
342
+ <Metric n={data.pullsOpen} label="PRs open" />
343
+ <Metric n={data.issuesOpen} label="issues open" />
344
+ </ul>
345
+ </div>
346
+ </div>
347
+ <div className="ra-group ra-activity-heat" ref={heatRef}>
348
+ <p className="ra-kicker">{`// contributions — ${
349
+ heatWeeks >= 50 ? "last year" : `last ${heatWeeks} weeks`
350
+ }`}</p>
351
+ <RepoHeatmap
352
+ pulls={data.mergedPulls}
353
+ data={heatData}
354
+ weeks={heatWeeks}
355
+ fit
356
+ build={heatBuild}
357
+ />
358
+ </div>
359
+ </div>
360
+
361
+ {contributor ? (
362
+ <div className="ra-activity-foot">
363
+ <div className="ra-contributor">
364
+ <p className="ra-kicker">{"// maintainer"}</p>
365
+ <div className="ra-contributor-body">
366
+ <ContributorAvatar contributor={contributor} />
367
+ <div>
368
+ {contributor.url ? (
369
+ <a href={contributor.url} target="_blank" rel="noreferrer">
370
+ {contributor.name}
371
+ </a>
372
+ ) : (
373
+ <span>{contributor.name}</span>
374
+ )}
375
+ {contributor.role ? (
376
+ <span className="ra-contributor-role">{contributor.role}</span>
377
+ ) : null}
378
+ </div>
379
+ </div>
380
+ </div>
381
+ <div className="ra-meta">
382
+ <RepoLink href={repoUrl} />
383
+ </div>
384
+ </div>
385
+ ) : null}
386
+ </>
387
+ );
388
+ }
389
+
390
+ function ContributorAvatar({ contributor }: { contributor: RepoContributor }) {
391
+ if (contributor.avatarUrl) {
392
+ return (
393
+ // Plain <img>: the kit ships no next/image dependency and the avatar is a
394
+ // single fixed-size square (no next lint plugin runs on packages).
395
+ <img
396
+ className="ra-avatar"
397
+ src={contributor.avatarUrl}
398
+ alt=""
399
+ width={36}
400
+ height={36}
401
+ loading="lazy"
402
+ />
403
+ );
404
+ }
405
+ const initial = contributor.name.trim().charAt(0).toUpperCase();
406
+ return (
407
+ <span className="ra-avatar ra-avatar--mono" aria-hidden="true">
408
+ {initial}
409
+ </span>
410
+ );
411
+ }
412
+
413
+ function Detailed({
414
+ data,
415
+ repoUrl,
416
+ source,
417
+ cloneCommand,
418
+ contributingUrl,
419
+ heatRef,
420
+ heatWeeks,
421
+ heatData,
422
+ heatBuild,
423
+ }: {
424
+ data: RepoActivitySnapshot;
425
+ repoUrl: string;
426
+ source: "snapshot" | "live";
427
+ cloneCommand?: string;
428
+ contributingUrl?: string;
429
+ heatRef: RefObject<HTMLDivElement | null>;
430
+ heatWeeks: number;
431
+ heatData: RepoActivitySnapshot["dailyContributions"];
432
+ heatBuild?: boolean;
433
+ }) {
434
+ const pulls = (data.mergedPulls ?? []).slice(0, 6);
435
+ const issues = (data.openIssues ?? []).slice(0, 6);
436
+ const [cloneHead, cloneTail] = cloneCommand ? cloneParts(cloneCommand) : ["", ""];
437
+
438
+ return (
439
+ <>
440
+ <div className="ra-group">
441
+ <p className="ra-kicker">{`// last ${data.windowDays} days on ${data.branch}`}</p>
442
+ <ul className="ra-metrics" role="list">
443
+ <Metric n={data.commits} label="commits" />
444
+ <Metric n={data.pullsMerged} label="PRs merged" />
445
+ <Metric n={data.issuesClosed} label="issues closed" />
446
+ </ul>
447
+ </div>
448
+ <div className="ra-group">
449
+ <p className="ra-kicker">{"// current backlog"}</p>
450
+ <ul className="ra-metrics" role="list">
451
+ <Metric n={data.pullsOpen} label="PRs open" />
452
+ <Metric n={data.issuesOpen} label="issues open" />
453
+ </ul>
454
+ </div>
455
+ <div className="ra-group" ref={heatRef}>
456
+ <p className="ra-kicker">{`// contributions — ${
457
+ heatWeeks >= 50 ? "last year" : `last ${heatWeeks} weeks`
458
+ }`}</p>
459
+ <RepoHeatmap pulls={data.mergedPulls} data={heatData} weeks={heatWeeks} build={heatBuild} />
460
+ </div>
461
+ <div className="ra-meta">
462
+ <ReleaseLink release={data.latestRelease} />
463
+ <Stamp source={source} at={data.generatedAt} />
464
+ <RepoLink href={repoUrl} />
465
+ </div>
466
+ {cloneCommand || contributingUrl ? (
467
+ <div className="ra-actions">
468
+ {cloneCommand ? (
469
+ <div className="ra-clone">
470
+ <code>
471
+ {cloneHead}
472
+ <wbr />
473
+ {cloneTail}
474
+ </code>
475
+ <CopyButton text={cloneCommand} />
476
+ </div>
477
+ ) : null}
478
+ {contributingUrl ? (
479
+ <div className="ra-cta">
480
+ <a href={contributingUrl} target="_blank" rel="noreferrer">
481
+ Contributing guide <span aria-hidden="true">→</span>
482
+ </a>
483
+ <a href={`${repoUrl}/issues`} target="_blank" rel="noreferrer">
484
+ <GitHubGlyph width={14} height={14} />
485
+ Open issues
486
+ </a>
487
+ </div>
488
+ ) : null}
489
+ </div>
490
+ ) : null}
491
+ <div className="ra-cols">
492
+ <div>
493
+ <p className="ra-kicker">{"// merged recently"}</p>
494
+ {pulls.length ? (
495
+ <ol className="ra-list" role="list">
496
+ {pulls.map((p) => (
497
+ <PullRow key={p.number} item={p} stamp={p.mergedAt} />
498
+ ))}
499
+ </ol>
500
+ ) : null}
501
+ </div>
502
+ <div>
503
+ <p className="ra-kicker">{"// open issues"}</p>
504
+ {issues.length ? (
505
+ <ol className="ra-list" role="list">
506
+ {issues.map((issue) => (
507
+ <IssueRow key={issue.number} item={issue} />
508
+ ))}
509
+ </ol>
510
+ ) : null}
511
+ </div>
512
+ </div>
513
+ </>
514
+ );
515
+ }
516
+
517
+ function Metric({ n, label }: { n: number; label: string }) {
518
+ return (
519
+ <li className="ra-metric">
520
+ <span className="ra-n">{grouped(n)}</span>
521
+ <span className="ra-l">{label}</span>
522
+ </li>
523
+ );
524
+ }
525
+
526
+ function Stamp({ source, at }: { source: "snapshot" | "live"; at: string }) {
527
+ return (
528
+ <p className="ra-stamp">
529
+ {source} {isoDay(at)}
530
+ </p>
531
+ );
532
+ }
533
+
534
+ function ReleaseLink({ release }: { release: RepoActivitySnapshot["latestRelease"] }) {
535
+ if (!release) return null;
536
+ return (
537
+ <p className="ra-release">
538
+ latest{" "}
539
+ <a href={release.url} target="_blank" rel="noreferrer">
540
+ {release.tag}
541
+ </a>
542
+ </p>
543
+ );
544
+ }
545
+
546
+ function RepoLink({ href }: { href: string }) {
547
+ return (
548
+ <a className="ra-repo" href={href} target="_blank" rel="noreferrer">
549
+ <GitHubGlyph width={13} height={13} />
550
+ browse the repo <span aria-hidden="true">→</span>
551
+ </a>
552
+ );
553
+ }
554
+
555
+ function PullRow({ item, stamp }: { item: RepoPullItem; stamp: string | null }) {
556
+ return (
557
+ <li className="ra-row">
558
+ <a className="ra-num" href={item.url} target="_blank" rel="noreferrer">
559
+ #{item.number}
560
+ </a>
561
+ <span className="ra-title">{item.title}</span>
562
+ <span className="ra-date">{isoDay(stamp)}</span>
563
+ </li>
564
+ );
565
+ }
566
+
567
+ function IssueRow({ item }: { item: RepoIssueItem }) {
568
+ return (
569
+ <li className="ra-row">
570
+ <a className="ra-num" href={item.url} target="_blank" rel="noreferrer">
571
+ #{item.number}
572
+ </a>
573
+ <span className="ra-title">{item.title}</span>
574
+ <span className="ra-date">{isoDay(item.updatedAt)}</span>
575
+ </li>
576
+ );
577
+ }
578
+
579
+ function CopyButton({ text }: { text: string }) {
580
+ const [copied, setCopied] = useState(false);
581
+ return (
582
+ <button
583
+ type="button"
584
+ className="ra-copy"
585
+ aria-label="Copy the clone command"
586
+ onClick={() => {
587
+ void navigator.clipboard?.writeText(text).then(
588
+ () => {
589
+ setCopied(true);
590
+ window.setTimeout(() => setCopied(false), 1200);
591
+ },
592
+ () => {},
593
+ );
594
+ }}
595
+ >
596
+ {copied ? "copied" : "copy"}
597
+ </button>
598
+ );
599
+ }