@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,226 @@
1
+ /**
2
+ * Terminal brand marks — the `digi` prompt lockup and the hairline wordmark.
3
+ *
4
+ * The house identity reads as a terminal line caught mid-prompt: the module
5
+ * name followed by a filled block cursor. The cursor is not a new shape — it is
6
+ * the `.term-cursor` geometry from @digithings-ai/design (site.css), 0.6em wide by
7
+ * 1.05em tall sitting at vertical-align -0.16em. 0.6em is exactly one Geist Mono
8
+ * advance, so the cursor occupies one character cell and the lockup sits on the
9
+ * mono grid without fudging.
10
+ *
11
+ * Three exports, each matching the weight of the surface it imitates:
12
+ *
13
+ * - TerminalMark: outlined `digi` + cursor, filled in currentColor. Geist Mono
14
+ * 400 — the weight terminal text actually renders at, since .term-body /
15
+ * .cmdline / .app-input-field set no font-weight and inherit
16
+ * body{font-weight:400}. Outlined rather than text because this same artwork
17
+ * is the favicon source and must not depend on a loaded font. `variant`
18
+ * selects the full `digi` lockup or the compact `d` reduction; use compact
19
+ * below ~64px, where the full lockup's five character cells close up.
20
+ * - TerminalWordmark: the default wordmark. Deliberately TEXT, not outlined —
21
+ * it is plain mono at tracking 0 with no overlapping contours to preserve, so
22
+ * outlining would ship ~9KB of path data for a glyph-identical result
23
+ * wherever Geist Mono is loaded. Carries token-backed utilities, so consumers
24
+ * need an `@source "<path-to>/packages/ui/src/components/symbols"` line.
25
+ * Deliberately ONE TONE — `text-ink`, never `--accent` — regardless of any
26
+ * surrounding `.accent-<module>` livery scope: it reads as a real shell
27
+ * prompt, and real terminal output does not recolor by module (`.term-body`
28
+ * is one ink color throughout). See terminal-marks.render.test.tsx's "does
29
+ * not dress the suffix in the accent" case.
30
+ * - HairlineWordmark: the display cut, replicating the footer colophon's
31
+ * `.colo-word` — stroke 0.538% of the em (a 1px line on a ~186px glyph),
32
+ * ink at 30%, tracking -0.05em, Geist Mono 500. FULL-BLEED ONLY. The stroke
33
+ * scales with the art, so the floor is on the em, not on the rendered width:
34
+ * below an em of ~173px it goes sub-pixel and greys out. For `digithings`
35
+ * (10 cells at 0.6em) that means a rendered width of ~1036px before the
36
+ * stroke reaches one device pixel; ~933px for `digiquant`. This is the
37
+ * colophon's own scale — `.colo-word` is `clamp(3rem, 15.5vw, 15rem)`, i.e.
38
+ * ~186px em and a ~1116px word at a 1200px viewport. Anywhere narrower, use
39
+ * TerminalWordmark instead; do not shrink this one to fit.
40
+ *
41
+ * The hairline paths are outlined from the VARIABLE font, contours left
42
+ * overlapping and un-booleaned. That is load-bearing, not an oversight: stroked,
43
+ * those overlaps are what give the `t` its crossing grid and the `d` and `i`
44
+ * their stem spurs. Never run a boolean union / "remove overlap" / SVG
45
+ * "simplify paths" pass over this data, and never regenerate it from a static
46
+ * cut — the static `t` has one merged contour where the variable font has two,
47
+ * and the crossings vanish silently.
48
+ *
49
+ * No CSS ships with this family; TerminalMark and HairlineWordmark are pure
50
+ * SVG in currentColor, so whatever sets `color` in the ancestor chain dresses
51
+ * them — note an `.accent-<module>` scope alone does NOT: it only exposes
52
+ * `--accent` as a custom property, it does not set `color` itself, so a
53
+ * consumer wanting the livery effect must set `color: var(--accent)`
54
+ * explicitly somewhere between the scope and the mark (see symbols.css's
55
+ * `.sym-hairline--accent` for this reference site's opt-in pattern).
56
+ * TerminalWordmark is the deliberate exception — it never reads --accent at
57
+ * all, see its own bullet above.
58
+ */
59
+ import type { ReactNode } from "react";
60
+
61
+ /** Cursor geometry, in em.
62
+ *
63
+ * `w: 0.6` is one Geist Mono advance — exactly one character cell — and is taken
64
+ * straight from `.term-cursor` (@digithings-ai/design site.css).
65
+ *
66
+ * `h` deliberately DIVERGES from `.term-cursor`, which is 1.05em. That is the
67
+ * full line height, correct for a caret sitting in running terminal text, but
68
+ * wrong for a two-element logo: beside a lowercase `d` (0.71em) a 1.05em block
69
+ * is 1.48x taller than the letter, so at favicon sizes the pair stops reading as
70
+ * "letter + cursor" and becomes "a letter and a grey box". Matching the cursor to
71
+ * the ascender puts them at 1:1 and the mark reads at 16px.
72
+ *
73
+ * `.term-cursor` itself is unchanged — actual terminal UI still wants 1.05em. */
74
+ const CURSOR = { w: 0.6, h: 0.71, v: 0 } as const;
75
+
76
+ const MARK_FULL = [
77
+ "M14.654 58.084Q12.647333333333332 58.084 11.185333333333332 57.10933333333334Q9.723333333333333 56.13466666666667 8.934999999999999 54.35733333333333Q8.146666666666667 52.58 8.146666666666667 50.14333333333334Q8.146666666666667 47.70666666666667 8.934999999999999 45.92933333333333Q9.723333333333333 44.152 11.185333333333332 43.17733333333334Q12.647333333333332 42.20266666666667 14.654 42.20266666666667Q15.886666666666667 42.20266666666667 16.875666666666667 42.66133333333334Q17.864666666666665 43.120000000000005 18.538333333333334 43.80800000000001Q19.212 44.496 19.47 45.21266666666667L19.212 45.81466666666667V37.38666666666667H21.619999999999997V57.74H19.441333333333333L19.298000000000002 54.300000000000004L19.67066666666667 54.730000000000004Q19.326666666666668 55.762 18.595666666666666 56.52166666666667Q17.864666666666665 57.281333333333336 16.861333333333334 57.68266666666667Q15.858 58.084 14.654 58.084ZM14.797333333333334 55.79066666666667Q16.173333333333332 55.79066666666667 17.162333333333333 55.102666666666664Q18.151333333333334 54.41466666666667 18.681666666666665 53.139Q19.212 51.86333333333334 19.212 50.14333333333334Q19.212 48.366 18.681666666666665 47.10466666666667Q18.151333333333334 45.843333333333334 17.148 45.16966666666667Q16.144666666666666 44.496 14.74 44.496Q12.876666666666667 44.496 11.773 46.001000000000005Q10.669333333333334 47.506 10.669333333333334 50.14333333333334Q10.669333333333334 52.752 11.773 54.27133333333333Q12.876666666666667 55.79066666666667 14.797333333333334 55.79066666666667Z",
78
+ "M26.493333333333332 57.74V55.61866666666667H32.599333333333334V43.492666666666665L33.77466666666667 44.668000000000006H26.78V42.54666666666667H35.007333333333335V55.61866666666667H40.25333333333333V57.74H35.007333333333335H32.599333333333334ZM32.37 40.16733333333333V37.358000000000004H34.89266666666666V40.16733333333333Z",
79
+ "M49.914 62.384Q48.28 62.384 46.96133333333333 61.839333333333336Q45.64266666666666 61.29466666666667 44.754 60.29133333333334Q43.86533333333333 59.288000000000004 43.55 57.96933333333334L46.07266666666666 57.797333333333334Q46.416666666666664 58.858000000000004 47.291 59.474333333333334Q48.16533333333333 60.09066666666667 49.914 60.09066666666667Q51.977999999999994 60.09066666666667 53.08166666666666 59.25933333333334Q54.18533333333333 58.428000000000004 54.18533333333333 56.76533333333334V54.300000000000004Q53.64066666666666 55.504000000000005 52.43666666666667 56.22066666666667Q51.23266666666667 56.937333333333335 49.742 56.937333333333335Q47.82133333333333 56.937333333333335 46.31633333333333 55.99133333333333Q44.81133333333333 55.04533333333333 43.965666666666664 53.382666666666665Q43.12 51.72 43.12 49.57Q43.12 47.391333333333336 43.95133333333333 45.743Q44.782666666666664 44.09466666666667 46.259 43.14866666666667Q47.73533333333333 42.20266666666667 49.62733333333333 42.20266666666667Q51.23266666666667 42.20266666666667 52.50833333333333 42.94800000000001Q53.784 43.693333333333335 54.3 44.95466666666667V42.54666666666667H56.593333333333334V56.708Q56.593333333333334 58.48533333333334 55.79066666666667 59.761Q54.988 61.03666666666667 53.49733333333333 61.71033333333334Q52.00666666666667 62.384 49.914 62.384ZM49.85666666666667 54.644000000000005Q51.806 54.644000000000005 52.98133333333333 53.28233333333334Q54.156666666666666 51.92066666666667 54.18533333333333 49.57Q54.214 47.99333333333334 53.68366666666667 46.861000000000004Q53.153333333333336 45.72866666666667 52.16433333333333 45.11233333333334Q51.175333333333334 44.496 49.85666666666667 44.496Q47.85 44.496 46.74633333333333 45.857666666666674Q45.64266666666666 47.21933333333334 45.64266666666666 49.57Q45.64266666666666 51.92066666666667 46.775 53.28233333333334Q47.907333333333334 54.644000000000005 49.85666666666667 54.644000000000005Z",
80
+ "M60.89333333333333 57.74V55.61866666666667H66.99933333333333V43.492666666666665L68.17466666666667 44.668000000000006H61.17999999999999V42.54666666666667H69.40733333333333V55.61866666666667H74.65333333333334V57.74H69.40733333333333H66.99933333333333ZM66.77 40.16733333333333V37.358000000000004H69.29266666666666V40.16733333333333Z",
81
+ ] as const;
82
+
83
+ const MARK_COMPACT = [
84
+ "M26.135 70.21Q21.118333333333332 70.21 17.46333333333333 67.77333333333333Q13.808333333333334 65.33666666666666 11.8375 60.89333333333333Q9.866666666666667 56.449999999999996 9.866666666666667 50.35833333333333Q9.866666666666667 44.26666666666666 11.8375 39.82333333333332Q13.808333333333334 35.379999999999995 17.46333333333333 32.94333333333333Q21.118333333333332 30.50666666666666 26.135 30.50666666666666Q29.21666666666667 30.50666666666666 31.68916666666667 31.653333333333325Q34.16166666666667 32.79999999999999 35.84583333333333 34.519999999999996Q37.53 36.239999999999995 38.175 38.03166666666666L37.53 39.53666666666666V18.46666666666666H43.550000000000004V69.35H38.10333333333334L37.745000000000005 60.74999999999999L38.67666666666667 61.824999999999996Q37.81666666666666 64.405 35.98916666666666 66.30416666666667Q34.16166666666667 68.20333333333333 31.653333333333336 69.20666666666666Q29.145 70.21 26.135 70.21ZM26.493333333333336 64.47666666666666Q29.933333333333334 64.47666666666666 32.405833333333334 62.75666666666666Q34.87833333333333 61.03666666666666 36.204166666666666 57.8475Q37.53 54.658333333333324 37.53 50.35833333333333Q37.53 45.91499999999999 36.204166666666666 42.761666666666656Q34.87833333333333 39.60833333333333 32.37 37.924166666666665Q29.861666666666668 36.239999999999995 26.35 36.239999999999995Q21.69166666666667 36.239999999999995 18.9325 40.0025Q16.173333333333332 43.76499999999999 16.173333333333332 50.35833333333333Q16.173333333333332 56.879999999999995 18.9325 60.67833333333333Q21.69166666666667 64.47666666666666 26.493333333333336 64.47666666666666Z",
85
+ ] as const;
86
+
87
+ /** Cursor rects, pre-solved so the ink fits a circular crop (avatars). */
88
+ const MARK_CURSOR = {
89
+ full: { x: 75.80, y: 37.39, width: 17.20, height: 20.35 },
90
+ compact: { x: 50.00, y: 18.47, width: 43.00, height: 50.88 },
91
+ } as const;
92
+
93
+ export interface TerminalMarkProps {
94
+ /** Rendered square size in px. Default 22. */
95
+ size?: number;
96
+ className?: string;
97
+ /** Accessible name (renders a `<title>` + role="img"); omitted → decorative. */
98
+ title?: string;
99
+ /** `full` = `digi` + cursor; `compact` = `d` + cursor. Use compact below ~64px. */
100
+ variant?: "full" | "compact";
101
+ }
102
+
103
+ export function TerminalMark({
104
+ size = 22,
105
+ className,
106
+ title,
107
+ variant = "full",
108
+ }: TerminalMarkProps) {
109
+ const paths = variant === "compact" ? MARK_COMPACT : MARK_FULL;
110
+ const cursor = MARK_CURSOR[variant];
111
+ return (
112
+ <svg
113
+ width={size}
114
+ height={size}
115
+ viewBox="0 0 100 100"
116
+ fill="currentColor"
117
+ role={title ? "img" : undefined}
118
+ aria-hidden={title ? undefined : "true"}
119
+ focusable="false"
120
+ className={["terminal-mark", className].filter(Boolean).join(" ")}
121
+ >
122
+ {title ? <title>{title}</title> : null}
123
+ {paths.map((d) => (
124
+ <path key={d.slice(0, 24)} d={d} />
125
+ ))}
126
+ <rect {...cursor} />
127
+ </svg>
128
+ );
129
+ }
130
+
131
+ export interface TerminalWordmarkProps {
132
+ /** The module suffix after `digi` — e.g. "things", "quant". */
133
+ suffix: ReactNode;
134
+ /** Defaults to `digi`. */
135
+ prefix?: ReactNode;
136
+ className?: string;
137
+ }
138
+
139
+ export function TerminalWordmark({
140
+ suffix,
141
+ prefix = "digi",
142
+ className,
143
+ }: TerminalWordmarkProps) {
144
+ return (
145
+ <span
146
+ className={[
147
+ "terminal-wordmark",
148
+ "font-mono text-[1.25rem] font-normal tracking-normal text-ink",
149
+ className,
150
+ ]
151
+ .filter(Boolean)
152
+ .join(" ")}
153
+ >
154
+ {prefix}
155
+ {suffix}
156
+ </span>
157
+ );
158
+ }
159
+
160
+ const HAIRLINE = {
161
+ things: {
162
+ viewBox: "-29.38 -779.38 5569.75 1006.75",
163
+ paths: [
164
+ "M258.0 12.0Q190.0 12.0 140.0 -21.5Q90.0 -55.0 63.0 -117.5Q36.0 -180.0 36.0 -266.0Q36.0 -352.0 63.0 -414.5Q90.0 -477.0 140.0 -510.5Q190.0 -544.0 258.0 -544.0Q302.0 -544.0 337.0 -528.0Q372.0 -512.0 395.0 -487.0Q418.0 -462.0 427.0 -433.0L417.0 -412.0V-710.0H518.0V0.0H424.0L419.0 -127.0L432.0 -110.0Q421.0 -74.0 396.5 -46.0Q372.0 -18.0 337.0 -3.0Q302.0 12.0 258.0 12.0ZM275.0 -81.0Q319.0 -81.0 350.5 -103.5Q382.0 -126.0 399.5 -167.5Q417.0 -209.0 417.0 -266.0Q417.0 -325.0 399.5 -366.0Q382.0 -407.0 350.0 -429.0Q318.0 -451.0 273.0 -451.0Q212.0 -451.0 177.0 -402.0Q142.0 -353.0 142.0 -266.0Q142.0 -180.0 177.0 -130.5Q212.0 -81.0 275.0 -81.0Z",
165
+ "M626.0 0.0V-85.0H834.0V-493.0L881.0 -447.0H636.0V-532.0H936.0V-85.0H1114.0V0.0H936.0H834.0ZM828.0 -609.0V-714.0H932.0V-609.0Z",
166
+ "M1397.0 162.0Q1337.0 162.0 1290.0 143.0Q1243.0 124.0 1212.5 89.0Q1182.0 54.0 1170.0 8.0L1276.0 1.0Q1287.0 34.0 1315.0 53.0Q1343.0 72.0 1397.0 72.0Q1464.0 72.0 1499.5 44.0Q1535.0 16.0 1535.0 -39.0V-117.0Q1516.0 -76.0 1475.5 -52.0Q1435.0 -28.0 1382.0 -28.0Q1316.0 -28.0 1264.0 -61.0Q1212.0 -94.0 1183.0 -151.5Q1154.0 -209.0 1154.0 -284.0Q1154.0 -362.0 1182.5 -420.0Q1211.0 -478.0 1262.0 -511.0Q1313.0 -544.0 1378.0 -544.0Q1434.0 -544.0 1476.5 -518.5Q1519.0 -493.0 1538.0 -449.0L1539.0 -532.0H1636.0V-46.0Q1636.0 21.0 1607.0 67.5Q1578.0 114.0 1524.5 138.0Q1471.0 162.0 1397.0 162.0ZM1396.0 -118.0Q1458.0 -118.0 1496.0 -162.0Q1534.0 -206.0 1535.0 -285.0Q1536.0 -339.0 1518.5 -376.5Q1501.0 -414.0 1469.5 -434.0Q1438.0 -454.0 1396.0 -454.0Q1331.0 -454.0 1295.5 -409.5Q1260.0 -365.0 1260.0 -285.0Q1260.0 -206.0 1296.5 -162.0Q1333.0 -118.0 1396.0 -118.0Z",
167
+ "M1726.0 0.0V-85.0H1934.0V-493.0L1981.0 -447.0H1736.0V-532.0H2036.0V-85.0H2214.0V0.0H2036.0H1934.0ZM1928.0 -609.0V-714.0H2032.0V-609.0Z",
168
+ "M2576.0 0.0Q2495.0 0.0 2455.5 -37.5Q2416.0 -75.0 2416.0 -153.0V-657.0H2517.0V-158.0Q2517.0 -121.0 2534.5 -103.0Q2552.0 -85.0 2587.0 -85.0H2724.0V0.0ZM2248.0 -447.0V-532.0H2724.0V-447.0Z",
169
+ "M2843.0 0.0V-710.0H2944.0V-416.0L2934.0 -420.0Q2944.0 -463.0 2968.0 -490.5Q2992.0 -518.0 3026.0 -531.0Q3060.0 -544.0 3101.0 -544.0Q3157.0 -544.0 3195.5 -518.5Q3234.0 -493.0 3253.5 -447.5Q3273.0 -402.0 3273.0 -343.0V0.0H3172.0V-317.0Q3172.0 -389.0 3146.5 -422.5Q3121.0 -456.0 3071.0 -456.0Q3014.0 -456.0 2979.0 -420.0Q2944.0 -384.0 2944.0 -314.0V0.0Z",
170
+ "M3376.0 0.0V-85.0H3584.0V-493.0L3631.0 -447.0H3386.0V-532.0H3686.0V-85.0H3864.0V0.0H3686.0H3584.0ZM3578.0 -609.0V-714.0H3682.0V-609.0Z",
171
+ "M3930.0 0.0V-532.0H4023.0L4026.0 -393.0L4015.0 -401.0Q4025.0 -450.0 4050.5 -481.5Q4076.0 -513.0 4113.0 -528.5Q4150.0 -544.0 4192.0 -544.0Q4252.0 -544.0 4291.0 -517.5Q4330.0 -491.0 4350.0 -445.5Q4370.0 -400.0 4370.0 -343.0V0.0H4269.0V-317.0Q4269.0 -386.0 4242.5 -421.0Q4216.0 -456.0 4163.0 -456.0Q4126.0 -456.0 4096.5 -440.0Q4067.0 -424.0 4049.0 -392.5Q4031.0 -361.0 4031.0 -315.0V0.0Z",
172
+ "M4697.0 162.0Q4637.0 162.0 4590.0 143.0Q4543.0 124.0 4512.5 89.0Q4482.0 54.0 4470.0 8.0L4576.0 1.0Q4587.0 34.0 4615.0 53.0Q4643.0 72.0 4697.0 72.0Q4764.0 72.0 4799.5 44.0Q4835.0 16.0 4835.0 -39.0V-117.0Q4816.0 -76.0 4775.5 -52.0Q4735.0 -28.0 4682.0 -28.0Q4616.0 -28.0 4564.0 -61.0Q4512.0 -94.0 4483.0 -151.5Q4454.0 -209.0 4454.0 -284.0Q4454.0 -362.0 4482.5 -420.0Q4511.0 -478.0 4562.0 -511.0Q4613.0 -544.0 4678.0 -544.0Q4734.0 -544.0 4776.5 -518.5Q4819.0 -493.0 4838.0 -449.0L4839.0 -532.0H4936.0V-46.0Q4936.0 21.0 4907.0 67.5Q4878.0 114.0 4824.5 138.0Q4771.0 162.0 4697.0 162.0ZM4696.0 -118.0Q4758.0 -118.0 4796.0 -162.0Q4834.0 -206.0 4835.0 -285.0Q4836.0 -339.0 4818.5 -376.5Q4801.0 -414.0 4769.5 -434.0Q4738.0 -454.0 4696.0 -454.0Q4631.0 -454.0 4595.5 -409.5Q4560.0 -365.0 4560.0 -285.0Q4560.0 -206.0 4596.5 -162.0Q4633.0 -118.0 4696.0 -118.0Z",
173
+ "M5258.0 12.0Q5187.0 12.0 5136.0 -12.0Q5085.0 -36.0 5057.0 -76.5Q5029.0 -117.0 5025.0 -167.0L5128.0 -173.0Q5136.0 -130.0 5168.0 -104.5Q5200.0 -79.0 5259.0 -79.0Q5314.0 -79.0 5343.0 -94.0Q5372.0 -109.0 5372.0 -141.0Q5372.0 -161.0 5362.0 -174.5Q5352.0 -188.0 5324.5 -197.5Q5297.0 -207.0 5244.0 -217.0Q5165.0 -232.0 5120.5 -252.5Q5076.0 -273.0 5057.0 -304.5Q5038.0 -336.0 5038.0 -381.0Q5038.0 -427.0 5061.5 -464.0Q5085.0 -501.0 5131.0 -522.5Q5177.0 -544.0 5245.0 -544.0Q5316.0 -544.0 5362.0 -519.5Q5408.0 -495.0 5434.0 -456.0Q5460.0 -417.0 5467.0 -371.0L5364.0 -365.0Q5358.0 -391.0 5343.0 -410.5Q5328.0 -430.0 5303.0 -441.5Q5278.0 -453.0 5245.0 -453.0Q5192.0 -453.0 5167.0 -432.0Q5142.0 -411.0 5142.0 -381.0Q5142.0 -357.0 5154.0 -342.5Q5166.0 -328.0 5194.0 -318.5Q5222.0 -309.0 5270.0 -300.0Q5351.0 -287.0 5395.0 -266.5Q5439.0 -246.0 5457.0 -216.0Q5475.0 -186.0 5475.0 -142.0Q5475.0 -94.0 5447.5 -59.5Q5420.0 -25.0 5371.5 -6.5Q5323.0 12.0 5258.0 12.0Z",
174
+ ],
175
+ },
176
+ quant: {
177
+ viewBox: "-29.38 -779.38 5018.75 1006.75",
178
+ paths: [
179
+ "M258.0 12.0Q190.0 12.0 140.0 -21.5Q90.0 -55.0 63.0 -117.5Q36.0 -180.0 36.0 -266.0Q36.0 -352.0 63.0 -414.5Q90.0 -477.0 140.0 -510.5Q190.0 -544.0 258.0 -544.0Q302.0 -544.0 337.0 -528.0Q372.0 -512.0 395.0 -487.0Q418.0 -462.0 427.0 -433.0L417.0 -412.0V-710.0H518.0V0.0H424.0L419.0 -127.0L432.0 -110.0Q421.0 -74.0 396.5 -46.0Q372.0 -18.0 337.0 -3.0Q302.0 12.0 258.0 12.0ZM275.0 -81.0Q319.0 -81.0 350.5 -103.5Q382.0 -126.0 399.5 -167.5Q417.0 -209.0 417.0 -266.0Q417.0 -325.0 399.5 -366.0Q382.0 -407.0 350.0 -429.0Q318.0 -451.0 273.0 -451.0Q212.0 -451.0 177.0 -402.0Q142.0 -353.0 142.0 -266.0Q142.0 -180.0 177.0 -130.5Q212.0 -81.0 275.0 -81.0Z",
180
+ "M626.0 0.0V-85.0H834.0V-493.0L881.0 -447.0H636.0V-532.0H936.0V-85.0H1114.0V0.0H936.0H834.0ZM828.0 -609.0V-714.0H932.0V-609.0Z",
181
+ "M1397.0 162.0Q1337.0 162.0 1290.0 143.0Q1243.0 124.0 1212.5 89.0Q1182.0 54.0 1170.0 8.0L1276.0 1.0Q1287.0 34.0 1315.0 53.0Q1343.0 72.0 1397.0 72.0Q1464.0 72.0 1499.5 44.0Q1535.0 16.0 1535.0 -39.0V-117.0Q1516.0 -76.0 1475.5 -52.0Q1435.0 -28.0 1382.0 -28.0Q1316.0 -28.0 1264.0 -61.0Q1212.0 -94.0 1183.0 -151.5Q1154.0 -209.0 1154.0 -284.0Q1154.0 -362.0 1182.5 -420.0Q1211.0 -478.0 1262.0 -511.0Q1313.0 -544.0 1378.0 -544.0Q1434.0 -544.0 1476.5 -518.5Q1519.0 -493.0 1538.0 -449.0L1539.0 -532.0H1636.0V-46.0Q1636.0 21.0 1607.0 67.5Q1578.0 114.0 1524.5 138.0Q1471.0 162.0 1397.0 162.0ZM1396.0 -118.0Q1458.0 -118.0 1496.0 -162.0Q1534.0 -206.0 1535.0 -285.0Q1536.0 -339.0 1518.5 -376.5Q1501.0 -414.0 1469.5 -434.0Q1438.0 -454.0 1396.0 -454.0Q1331.0 -454.0 1295.5 -409.5Q1260.0 -365.0 1260.0 -285.0Q1260.0 -206.0 1296.5 -162.0Q1333.0 -118.0 1396.0 -118.0Z",
182
+ "M1726.0 0.0V-85.0H1934.0V-493.0L1981.0 -447.0H1736.0V-532.0H2036.0V-85.0H2214.0V0.0H2036.0H1934.0ZM1928.0 -609.0V-714.0H2032.0V-609.0Z",
183
+ "M2728.0 150.0H2627.0V-116.0L2640.0 -102.0Q2629.0 -66.0 2604.5 -40.5Q2580.0 -15.0 2545.0 -1.5Q2510.0 12.0 2469.0 12.0Q2393.0 12.0 2343.5 -26.5Q2294.0 -65.0 2270.0 -128.0Q2246.0 -191.0 2246.0 -266.0Q2246.0 -341.0 2270.0 -404.0Q2294.0 -467.0 2343.5 -505.5Q2393.0 -544.0 2469.0 -544.0Q2532.0 -544.0 2577.5 -511.5Q2623.0 -479.0 2642.0 -417.0L2630.0 -411.0L2632.0 -532.0H2728.0ZM2488.0 -81.0Q2531.0 -81.0 2562.0 -101.5Q2593.0 -122.0 2610.0 -163.0Q2627.0 -204.0 2627.0 -266.0Q2627.0 -328.0 2609.5 -369.0Q2592.0 -410.0 2561.0 -430.5Q2530.0 -451.0 2488.0 -451.0Q2424.0 -451.0 2388.0 -403.0Q2352.0 -355.0 2352.0 -266.0Q2352.0 -177.0 2388.0 -129.0Q2424.0 -81.0 2488.0 -81.0Z",
184
+ "M3004.0 12.0Q2927.0 12.0 2881.0 -40.5Q2835.0 -93.0 2835.0 -188.0V-532.0H2936.0V-214.0Q2936.0 -142.0 2961.0 -109.0Q2986.0 -76.0 3037.0 -76.0Q3092.0 -76.0 3125.5 -113.0Q3159.0 -150.0 3159.0 -218.0V-532.0H3260.0V0.0H3165.0L3164.0 -139.0L3178.0 -133.0Q3164.0 -64.0 3119.0 -26.0Q3074.0 12.0 3004.0 12.0Z",
185
+ "M3528.0 12.0Q3478.0 12.0 3438.0 -6.0Q3398.0 -24.0 3374.5 -57.0Q3351.0 -90.0 3351.0 -134.0Q3351.0 -202.0 3392.5 -240.0Q3434.0 -278.0 3518.0 -294.0L3690.0 -330.0Q3690.0 -392.0 3663.0 -423.0Q3636.0 -454.0 3582.0 -454.0Q3532.0 -454.0 3504.0 -431.0Q3476.0 -408.0 3466.0 -367.0L3360.0 -374.0Q3375.0 -450.0 3433.0 -497.0Q3491.0 -544.0 3582.0 -544.0Q3684.0 -544.0 3737.5 -486.0Q3791.0 -428.0 3791.0 -326.0V-116.0Q3791.0 -98.0 3799.0 -90.5Q3807.0 -83.0 3822.0 -83.0H3852.0V0.0Q3846.0 1.0 3832.5 2.0Q3819.0 3.0 3806.0 3.0Q3770.0 3.0 3745.0 -9.0Q3720.0 -21.0 3707.5 -46.5Q3695.0 -72.0 3693.0 -111.0H3709.0Q3703.0 -76.0 3678.0 -48.0Q3653.0 -20.0 3614.0 -4.0Q3575.0 12.0 3528.0 12.0ZM3543.0 -71.0Q3591.0 -71.0 3624.0 -88.0Q3657.0 -105.0 3673.5 -136.0Q3690.0 -167.0 3690.0 -209.0V-250.0L3542.0 -220.0Q3494.0 -211.0 3475.0 -192.0Q3456.0 -173.0 3456.0 -142.0Q3456.0 -109.0 3479.0 -90.0Q3502.0 -71.0 3543.0 -71.0Z",
186
+ "M3930.0 0.0V-532.0H4023.0L4026.0 -393.0L4015.0 -401.0Q4025.0 -450.0 4050.5 -481.5Q4076.0 -513.0 4113.0 -528.5Q4150.0 -544.0 4192.0 -544.0Q4252.0 -544.0 4291.0 -517.5Q4330.0 -491.0 4350.0 -445.5Q4370.0 -400.0 4370.0 -343.0V0.0H4269.0V-317.0Q4269.0 -386.0 4242.5 -421.0Q4216.0 -456.0 4163.0 -456.0Q4126.0 -456.0 4096.5 -440.0Q4067.0 -424.0 4049.0 -392.5Q4031.0 -361.0 4031.0 -315.0V0.0Z",
187
+ "M4776.0 0.0Q4695.0 0.0 4655.5 -37.5Q4616.0 -75.0 4616.0 -153.0V-657.0H4717.0V-158.0Q4717.0 -121.0 4734.5 -103.0Q4752.0 -85.0 4787.0 -85.0H4924.0V0.0ZM4448.0 -447.0V-532.0H4924.0V-447.0Z",
188
+ ],
189
+ },
190
+ } as const;
191
+
192
+ /** Stroke as a fraction of the em — a 1px line on a ~186px glyph (site.css). */
193
+ const HAIRLINE_STROKE_RATIO = 1 / 186;
194
+ const HAIRLINE_EM = 1000;
195
+
196
+ export interface HairlineWordmarkProps {
197
+ /** Which wordmark to draw. */
198
+ word: keyof typeof HAIRLINE;
199
+ className?: string;
200
+ /** Accessible name (renders a `<title>` + role="img"); omitted → decorative. */
201
+ title?: string;
202
+ }
203
+
204
+ export function HairlineWordmark({ word, className, title }: HairlineWordmarkProps) {
205
+ const spec = HAIRLINE[word];
206
+ return (
207
+ <svg
208
+ viewBox={spec.viewBox}
209
+ fill="none"
210
+ stroke="currentColor"
211
+ strokeOpacity={0.3}
212
+ strokeWidth={HAIRLINE_STROKE_RATIO * HAIRLINE_EM}
213
+ role={title ? "img" : undefined}
214
+ aria-hidden={title ? undefined : "true"}
215
+ focusable="false"
216
+ className={["hairline-wordmark", className].filter(Boolean).join(" ")}
217
+ >
218
+ {title ? <title>{title}</title> : null}
219
+ {spec.paths.map((d) => (
220
+ <path key={d.slice(0, 24)} d={d} />
221
+ ))}
222
+ </svg>
223
+ );
224
+ }
225
+
226
+ export { CURSOR as TERMINAL_CURSOR };
@@ -0,0 +1,67 @@
1
+ "use client";
2
+
3
+ import { ChatMessage } from "../chat/ChatMessage";
4
+ import { TerminalStepCaret } from "./TerminalStepCaret";
5
+
6
+ /**
7
+ * Chat response loader — the wait between sending a message and the first
8
+ * token of the answer. It occupies the assistant turn it is about to become:
9
+ * a <ChatMessage role="assistant"> row, so the `▸` marker, the
10
+ * `1.25rem minmax(0,1fr)` grid and the body ink are the transcript's own
11
+ * (canon §16) and nothing shifts when the real turn replaces it. The body is
12
+ * the house type-out — the running step types out at the block cursor, holds,
13
+ * deletes, and the next one follows — so the same caret that will stream the
14
+ * answer is already blinking while it is being written.
15
+ *
16
+ * The step labels are a promise about what is happening, so drive them from
17
+ * what IS happening wherever the transport can say: pass `activeIndex` from
18
+ * the stream's stage events or tool-call names and the caret erases and
19
+ * retypes on each change. Uncontrolled, it cycles the default path — which is
20
+ * honest for the first second and vague after that, so prefer real steps.
21
+ *
22
+ * Snappier than the boot loader by design (900ms dwell, cycling): this one is
23
+ * usually replaced within a second or two, and a slow hold there reads as a
24
+ * stall rather than as work.
25
+ *
26
+ * One motion moment: the caret. `prefers-reduced-motion` shows the active
27
+ * step's label whole with the caret still — which uncontrolled is the first,
28
+ * since the internal clock never starts; see <TerminalStepCaret>.
29
+ */
30
+ export type ChatResponseLoaderProps = {
31
+ /** Stages, in order. Defaults to the common path. */
32
+ steps?: string[];
33
+ /** Caller-driven stage; omit to cycle on the internal clock. */
34
+ activeIndex?: number;
35
+ className?: string;
36
+ };
37
+
38
+ /** The common path. Illustrative — feed the real stages where you have them. */
39
+ const RESPONSE_STEPS = [
40
+ "thinking",
41
+ "routing through digigraph",
42
+ "gathering context",
43
+ "composing the answer",
44
+ ];
45
+
46
+ /**
47
+ * Snappier than the boot loader's 1200ms. Exported because a surface that
48
+ * already owns its assistant row (digichat's `.dc-msg`, which predates canon
49
+ * §16) renders <TerminalStepCaret> directly rather than nesting this component
50
+ * inside its own row and doubling the marker — it still has to wait at the
51
+ * same cadence, and a second literal is how the two drift apart.
52
+ */
53
+ const RESPONSE_HOLD_MS = 900;
54
+
55
+ export function ChatResponseLoader({
56
+ steps = RESPONSE_STEPS,
57
+ activeIndex,
58
+ className,
59
+ }: ChatResponseLoaderProps) {
60
+ return (
61
+ <ChatMessage role="assistant" tone="mute" className={className}>
62
+ <TerminalStepCaret steps={steps} activeIndex={activeIndex} holdMs={RESPONSE_HOLD_MS} />
63
+ </ChatMessage>
64
+ );
65
+ }
66
+
67
+ export { RESPONSE_STEPS as CHAT_RESPONSE_STEPS, RESPONSE_HOLD_MS as CHAT_RESPONSE_HOLD_MS };
@@ -0,0 +1,82 @@
1
+ "use client";
2
+
3
+ import type { ReactNode } from "react";
4
+
5
+ import { TerminalStepCaret } from "./TerminalStepCaret";
6
+
7
+ /**
8
+ * Container-boot loader — the full-surface wait shown while the app's
9
+ * container is still coming up. A scale-to-zero container answers its first
10
+ * request in 15–25s, and a spinner spends all of it saying nothing; this says
11
+ * which phase is running, in the house type-out: the step label types out at
12
+ * the brand's block cursor, holds, deletes, and the next one follows.
13
+ *
14
+ * The composition is a terminal line caught mid-prompt — wordmark, hairline,
15
+ * the typing step, and one quiet note setting the expectation — left-aligned
16
+ * on a mono grid and centred in the surface. It carries **no** mark before the
17
+ * label: word plus block cursor is the lockup itself, and the mark is what
18
+ * makes this read as the brand rather than as a progress widget.
19
+ *
20
+ * The steps are a script, not telemetry: nothing can report progress from
21
+ * inside a container that has not started. So they default to the phases of an
22
+ * ordinary cold start and the last one HOLDS (`loop={false}`) — a boot screen
23
+ * that loops back to step one reads as stuck. Pass `steps` to name the real
24
+ * phases, or `activeIndex` once something outside the container can report
25
+ * them (a health-check poller, a readiness probe).
26
+ *
27
+ * One motion moment: the caret. No spinner, no progress rail, no counter.
28
+ * `prefers-reduced-motion` shows the active step's label whole with the caret
29
+ * still — which for an uncontrolled loader is the first, since its clock never
30
+ * starts; see <TerminalStepCaret>. Frame styles: `.tl-boot*` in
31
+ * `@digithings-ai/ui/styles/terminal-loaders.css`.
32
+ */
33
+ export type ContainerBootLoaderProps = {
34
+ /** Boot phases, in order. Defaults to an ordinary cold start. */
35
+ steps?: string[];
36
+ /** Caller-driven phase; omit to run the script on the internal clock. */
37
+ activeIndex?: number;
38
+ /** Brand line above the rule — typically a wordmark. Omit for none. */
39
+ title?: ReactNode;
40
+ /** The expectation-setting line under the caret. Pass `null` to drop it. */
41
+ note?: ReactNode;
42
+ /** Pin to the viewport — the usual mode, over a not-yet-rendered app. */
43
+ fullscreen?: boolean;
44
+ className?: string;
45
+ };
46
+
47
+ /** The phases of an ordinary cold start. Illustrative — name your own. */
48
+ const BOOT_STEPS = [
49
+ "waking the container",
50
+ "booting the chat surface",
51
+ "linking digigraph",
52
+ "restoring your session",
53
+ "warming the model runtime",
54
+ ];
55
+
56
+ const BOOT_NOTE = "cold start · the container sleeps when idle";
57
+
58
+ export function ContainerBootLoader({
59
+ steps = BOOT_STEPS,
60
+ activeIndex,
61
+ title,
62
+ note = BOOT_NOTE,
63
+ fullscreen = false,
64
+ className,
65
+ }: ContainerBootLoaderProps) {
66
+ return (
67
+ <div
68
+ className={["tl-boot", fullscreen ? "is-fixed" : "", className ?? ""]
69
+ .filter(Boolean)
70
+ .join(" ")}
71
+ >
72
+ <div className="tl-boot-inner">
73
+ {title ? <p className="tl-boot-title">{title}</p> : null}
74
+ <hr className="tl-boot-rule" />
75
+ <TerminalStepCaret steps={steps} activeIndex={activeIndex} loop={false} />
76
+ {note ? <p className="tl-note">{note}</p> : null}
77
+ </div>
78
+ </div>
79
+ );
80
+ }
81
+
82
+ export { BOOT_STEPS as CONTAINER_BOOT_STEPS };
@@ -0,0 +1,202 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef, useState, type ReactNode } from "react";
4
+ import { useReducedMotion } from "motion/react";
5
+
6
+ import { ChatStreamCursor } from "../chat/ChatStreamCursor";
7
+
8
+ /**
9
+ * Step caret — the house type-out, applied to waiting. The label of the step
10
+ * currently running types out at the blinking block cursor, holds long enough
11
+ * to read, deletes, and the next step follows: the same grammar the animated
12
+ * brand lockup uses to cycle module names (`AnimatedLockup`, symbols family),
13
+ * which is why a loader built on it reads as the mark rather than as chrome.
14
+ *
15
+ * The caret is not redrawn — it is <ChatStreamCursor> (canon §16), so the
16
+ * glyph-metric-free 7×14 accent block, the steps(1) blink and the
17
+ * reduced-motion still all come from chat-core.css and never drift.
18
+ *
19
+ * Two things are load-bearing:
20
+ *
21
+ * - **Typing is priced per character, not per step.** A fixed slot makes a
22
+ * short label type at twice the speed of a long one and the rhythm limps —
23
+ * the lockup's rule, and the reason the cadence constants are per-char.
24
+ * Cadence diverges from the lockup's 140ms/char, which is tuned for 5-letter
25
+ * suffixes; a step label is a phrase, so it runs at 58ms. Keep labels under
26
+ * ~30 characters — the line does not wrap (the caret has to trail the text,
27
+ * and a wrapped caret lands in the margin), and 30 is what the boot surface
28
+ * holds on a 375px viewport.
29
+ * - **The label is written straight to the DOM, not re-rendered.** A character
30
+ * is not a state change; `shownRef` tracks what is on screen so a step swap
31
+ * erases what was actually there. That also keeps the typed node out of the
32
+ * a11y tree — a live region on it would announce every keystroke — so what a
33
+ * screen reader gets comes from a visually-hidden `role="status"` sibling.
34
+ * That sibling narrates the STEP only when `activeIndex` is supplied, since
35
+ * only then does a step mean progress; left to cycle its own script it
36
+ * announces `waitingLabel` once instead of reciting invented phrases on a
37
+ * ~10s loop for the length of the wait.
38
+ *
39
+ * Steps advance on the internal clock, or pass `activeIndex` to drive them
40
+ * from real progress (a stream's tool-call names, a health-check phase) and
41
+ * the caret erases and retypes on each change.
42
+ *
43
+ * `prefers-reduced-motion` renders the final state — the active step's label
44
+ * whole, no typing, no deleting, the caret still — and the internal clock
45
+ * never starts, so an uncontrolled caret holds its first step. A caller-driven
46
+ * `activeIndex` still swaps the label: that is information, not decoration.
47
+ * With scripts off the first step renders from `<noscript>`.
48
+ *
49
+ * Frame styles: `.tl-*` in `@digithings-ai/ui/styles/terminal-loaders.css`.
50
+ */
51
+ export type TerminalStepCaretProps = {
52
+ /** The steps, in order. The first is the reduced-motion / no-JS state. */
53
+ steps: string[];
54
+ /** Caller-driven step; omit to advance on the internal clock. */
55
+ activeIndex?: number;
56
+ /** When self-advancing: cycle (default), or stop on the last step. */
57
+ loop?: boolean;
58
+ /** Prompt mark before the label. Omit when the surface owns the marker. */
59
+ mark?: ReactNode;
60
+ /** Per-character type / erase cadence, and the beats between, in ms. */
61
+ typeMs?: number;
62
+ eraseMs?: number;
63
+ holdMs?: number;
64
+ restMs?: number;
65
+ /** What a screen reader hears while the steps are the internal script. */
66
+ waitingLabel?: string;
67
+ className?: string;
68
+ };
69
+
70
+ /** Per-character cadence. `erase/type` holds the lockup's 90/140 ratio. */
71
+ const TYPE_MS = 58;
72
+ const ERASE_MS = 37;
73
+ /** Dwell on a finished label, and the beat between erasing and typing. */
74
+ const HOLD_MS = 1200;
75
+ const REST_MS = 220;
76
+
77
+ /** Announced once while the steps are the internal script. See the a11y note. */
78
+ const WAITING_LABEL = "Working…";
79
+
80
+ export function TerminalStepCaret({
81
+ steps,
82
+ activeIndex,
83
+ loop = true,
84
+ mark,
85
+ typeMs = TYPE_MS,
86
+ eraseMs = ERASE_MS,
87
+ holdMs = HOLD_MS,
88
+ restMs = REST_MS,
89
+ waitingLabel = WAITING_LABEL,
90
+ className,
91
+ }: TerminalStepCaretProps) {
92
+ const reduced = useReducedMotion();
93
+ const labelRef = useRef<HTMLSpanElement | null>(null);
94
+ /** What is on screen right now — the DOM is written to, not re-rendered. */
95
+ const shownRef = useRef("");
96
+ const [ownIndex, setOwnIndex] = useState(0);
97
+
98
+ const controlled = activeIndex !== undefined;
99
+ const count = steps.length;
100
+ const index = count === 0 ? 0 : (((controlled ? activeIndex : ownIndex) % count) + count) % count;
101
+ const word = steps[index] ?? "";
102
+
103
+ useEffect(() => {
104
+ const node = labelRef.current;
105
+ if (!node) return;
106
+
107
+ const write = (text: string) => {
108
+ shownRef.current = text;
109
+ node.textContent = text;
110
+ };
111
+
112
+ let timer = 0;
113
+
114
+ // Reduced motion writes the label whole and stops.
115
+ if (reduced) {
116
+ write(word);
117
+ return;
118
+ }
119
+ // No steps at all: nothing to type and nothing to advance to. Falling
120
+ // through would schedule `setOwnIndex(i => (i + 1) % 0)` — NaN, which is
121
+ // absorbing: `steps[NaN]` is undefined forever after, and since
122
+ // Object.is(NaN, NaN) React bails out of both the state update and the
123
+ // effect, so the caret never recovers even once real steps arrive.
124
+ if (count === 0) {
125
+ write("");
126
+ return;
127
+ }
128
+ // An empty label must still advance. Returning early here (as the reduced
129
+ // branch does) skipped scheduling the next step, so one blank label — a
130
+ // stream handing over a nameless tool — froze the loader on an empty line
131
+ // forever. Same advance rule as the settled case in `type` below.
132
+ if (!word) {
133
+ write("");
134
+ if (controlled) return;
135
+ if (!loop && index >= count - 1) return;
136
+ timer = window.setTimeout(() => setOwnIndex((i) => (i + 1) % count), holdMs);
137
+ return () => window.clearTimeout(timer);
138
+ }
139
+
140
+ const from = shownRef.current;
141
+ let cut = from.length;
142
+ let typed = 0;
143
+
144
+ const type = () => {
145
+ if (typed < word.length) {
146
+ typed += 1;
147
+ write(word.slice(0, typed));
148
+ timer = window.setTimeout(type, typeMs);
149
+ return;
150
+ }
151
+ // Settled. A controlled caret waits for the caller; an unlooped one
152
+ // holds the last step for as long as the wait lasts.
153
+ if (controlled) return;
154
+ if (!loop && index >= count - 1) return;
155
+ timer = window.setTimeout(() => setOwnIndex((i) => (i + 1) % count), holdMs);
156
+ };
157
+
158
+ const erase = () => {
159
+ if (cut > 0) {
160
+ cut -= 1;
161
+ write(from.slice(0, cut));
162
+ timer = window.setTimeout(erase, eraseMs);
163
+ return;
164
+ }
165
+ timer = window.setTimeout(type, restMs);
166
+ };
167
+
168
+ erase();
169
+ return () => window.clearTimeout(timer);
170
+ }, [word, index, count, controlled, loop, reduced, typeMs, eraseMs, holdMs, restMs]);
171
+
172
+ return (
173
+ <span className={["tl-line", className ?? ""].filter(Boolean).join(" ")}>
174
+ {mark ? (
175
+ <span className="tl-mark" aria-hidden="true">
176
+ {mark}
177
+ </span>
178
+ ) : null}
179
+ {/* Typed imperatively — empty on the server so the first paint is the
180
+ start of the type-out, not a frame of finished text that clears. */}
181
+ <span className="tl-label" ref={labelRef} aria-hidden="true" />
182
+ <noscript>
183
+ <span className="tl-label">{steps[0] ?? ""}</span>
184
+ </noscript>
185
+ <ChatStreamCursor />
186
+ {/* `.tl-sr` and not Tailwind's `.sr-only`: a utility only exists in an app
187
+ whose own source happens to use it, and digithings.ai's does not — so
188
+ the shared component shipped a screen-reader span that rendered as
189
+ ordinary visible text, duplicating the label beside itself. A
190
+ component's a11y must not depend on the consumer's build config.
191
+
192
+ Announce the STEP only when a caller drives it, because only then is
193
+ it progress. The self-cycling script is invented — narrating it to a
194
+ screen reader repeats four fabricated phrases every ~10s for as long
195
+ as the wait lasts, which is worse than the one static line it
196
+ replaced. */}
197
+ <span className="tl-sr" role="status">
198
+ {controlled ? word : waitingLabel}
199
+ </span>
200
+ </span>
201
+ );
202
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The pre-paint theme script, as a plain string module.
3
+ *
4
+ * It must NOT live in a "use client" file. Root layouts are server
5
+ * components; importing a non-component value from a client module gives
6
+ * them a client reference instead of the string. The HTML still rendered the
7
+ * script, but the RSC payload carried a lazy module reference in the root
8
+ * layout's <head> props, so hydration had to load that chunk first. When the
9
+ * chunk arrived after the document had parsed, the root hydrated out of step
10
+ * with the streamed metadata outlet and React threw #418, re-rendered the root
11
+ * from the server default (data-theme="dark"), and light-theme readers flipped
12
+ * to dark.
13
+ *
14
+ * Generated by scripts/generate_platform_palettes.py — do not edit the
15
+ * script body. The theme-color hexes are read by the browser and OS chrome,
16
+ * never by the page cascade, so a CSS token is unavailable here.
17
+ *
18
+ * `dt-theme` is light, dark, or absent (auto / follow the OS).
19
+ * `dt-palette` is a palette id or absent (default). The palette key is
20
+ * never written by the dashboard, and this script never writes storage.
21
+ */
22
+ /** Inline in <head> before paint: <script dangerouslySetInnerHTML={{__html: themeInitScript}}/> */
23
+ export const themeInitScript =
24
+ "try{var s=localStorage.getItem('dt-theme');var t=(s==='light'||s==='dark')?s:(matchMedia('(prefers-color-scheme: light)').matches?'light':'dark');var e=document.documentElement;e.setAttribute('data-theme',t);var P={'aura':{d:'#15141b',l:'#f5f0ff'},'ayu':{d:'#0f1419',l:'#fdfaf4'},'catppuccin':{d:'#1e1e2e',l:'#f5e0dc'},'catppuccin-frappe':{d:'#303446',l:'#303446'},'catppuccin-macchiato':{d:'#24273a',l:'#24273a'},'cobalt2':{d:'#193549',l:'#ffffff'},'cursor':{d:'#181818',l:'#fcfcfc'},'dracula':{d:'#1d1e28',l:'#f8f8f2'},'everforest':{d:'#2d353b',l:'#fdf6e3'},'flexoki':{d:'#100F0F',l:'#FFFCF0'},'github':{d:'#0d1117',l:'#ffffff'},'gruvbox':{d:'#282828',l:'#fbf1c7'},'kanagawa':{d:'#1F1F28',l:'#F2E9DE'},'material':{d:'#263238',l:'#fafafa'},'matrix':{d:'#0a0e0a',l:'#eef3ea'},'mercury':{d:'#171721',l:'#ffffff'},'monokai':{d:'#272822',l:'#fdf8ec'},'nightowl':{d:'#011627',l:'#f0f0f0'},'nord':{d:'#2e3440',l:'#eceff4'},'one-dark':{d:'#282c34',l:'#fafafa'},'osaka-jade':{d:'#111c18',l:'#F6F5DD'},'orng':{d:'#0a0a0a',l:'#ffffff'},'lucent-orng':{d:'#2a1a15',l:'#fff5f0'},'palenight':{d:'#292d3e',l:'#fafafa'},'rosepine':{d:'#191724',l:'#faf4ed'},'solarized':{d:'#002b36',l:'#fdf6e3'},'synthwave84':{d:'#262335',l:'#fafafa'},'tokyonight':{d:'#1a1b26',l:'#e1e2e7'},'vesper':{d:'#101010',l:'#F0F0F0'},'vercel':{d:'#000000',l:'#FFFFFF'},'zenburn':{d:'#3f3f3f',l:'#ffffef'},'carbonfox':{d:'#393939',l:'#8e8e8e'}};var p=localStorage.getItem('dt-palette');var c=t==='light'?'#FBFBF9':'#0A0E0C';if(p&&p!=='default'&&Object.prototype.hasOwnProperty.call(P,p)){e.setAttribute('data-palette',p);c=t==='light'?P[p].l:P[p].d;}else{e.removeAttribute('data-palette');}var m=document.querySelector('meta[name=\"theme-color\"]');if(!m){m=document.createElement('meta');m.setAttribute('name','theme-color');document.head.appendChild(m);}m.setAttribute('content',c);}catch(err){document.documentElement.setAttribute('data-theme','dark');}";