@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,462 @@
1
+ "use client";
2
+
3
+ import { cn } from "../../../lib/utils";
4
+ import { MarkdownText } from "../stock/markdown-text";
5
+ import { MessageExportMenu } from "../stock/message-export-menu";
6
+ import { SkinCredit, useSkinChrome } from "../stock";
7
+ import {
8
+ ActionBarPrimitive,
9
+ AuiIf,
10
+ AttachmentPrimitive,
11
+ BranchPickerPrimitive,
12
+ ComposerPrimitive,
13
+ MessagePrimitive,
14
+ ThreadPrimitive,
15
+ useAuiState,
16
+ } from "@assistant-ui/react";
17
+ import {
18
+ ArrowRight,
19
+ AudioLines,
20
+ CheckIcon,
21
+ ChevronDownIcon,
22
+ ChevronLeftIcon,
23
+ ChevronRightIcon,
24
+ CopyIcon,
25
+ Download,
26
+ FileIcon,
27
+ MoreHorizontal,
28
+ PencilIcon,
29
+ Plus,
30
+ RefreshCwIcon,
31
+ Search,
32
+ Sparkles,
33
+ Square,
34
+ Telescope,
35
+ XIcon,
36
+ } from "lucide-react";
37
+ import { type FC, useState } from "react";
38
+ import { useAttachmentSrc } from "../stock/use-attachment-src";
39
+ import {
40
+ DropdownMenu,
41
+ DropdownMenuContent,
42
+ DropdownMenuItem,
43
+ DropdownMenuTrigger,
44
+ } from "./ui/dropdown-menu";
45
+
46
+
47
+ const composerPrimaryActionClassName =
48
+ "absolute inset-0 flex items-center justify-center rounded-full transition-all duration-200 ease-out";
49
+
50
+ const composerPrimaryActionColorsClassName =
51
+ "bg-[#25211c] text-[#f8f5f0] hover:bg-[#171411] dark:bg-[#f5f2ed] dark:text-[#1b1713] dark:hover:bg-white";
52
+
53
+ const messageActionClassName =
54
+ "flex size-8 items-center justify-center rounded-full text-[#7a7268] transition-colors hover:bg-[#f1ece5] hover:text-[#1f1b17] dark:text-[#9d968d] dark:hover:bg-[#2a2724] dark:hover:text-[#f5f2ed]";
55
+
56
+ export const Perplexity: FC = () => {
57
+ const chrome = useSkinChrome();
58
+ const emptyPlaceholder = chrome.placeholder?.trim() || "Ask anything...";
59
+ const followPlaceholder = chrome.placeholder?.trim() || "Ask a follow-up...";
60
+ return (
61
+ <ThreadPrimitive.Root data-export-thread=""
62
+ className="flex h-full flex-col bg-[#f6f2ec] text-[#1f1b17] dark:bg-[#171615] dark:text-[#f5f2ed]"
63
+ style={{
64
+ ["--thread-max-width" as string]: "40rem",
65
+ }}
66
+ >
67
+ <AuiIf condition={(s) => s.thread.isEmpty}>
68
+ <EmptyState placeholder={emptyPlaceholder} />
69
+ </AuiIf>
70
+
71
+ <AuiIf condition={(s) => !s.thread.isEmpty}>
72
+ <ThreadPrimitive.Viewport className="flex grow flex-col overflow-y-auto px-4 pt-12">
73
+ <ThreadPrimitive.Messages>
74
+ {() => <ChatMessage />}
75
+ </ThreadPrimitive.Messages>
76
+
77
+ <ThreadPrimitive.ViewportFooter className="sticky bottom-0 mx-auto mt-auto w-full max-w-(--thread-max-width) bg-linear-to-b from-transparent via-[#f6f2ec]/85 to-[#f6f2ec] pt-6 pb-2 dark:via-[#171615]/85 dark:to-[#171615]">
78
+ <Composer placeholder={followPlaceholder} />
79
+ <SkinCredit />
80
+ </ThreadPrimitive.ViewportFooter>
81
+ </ThreadPrimitive.Viewport>
82
+ </AuiIf>
83
+ </ThreadPrimitive.Root>
84
+ );
85
+ };
86
+
87
+ const EmptyState: FC<{ placeholder: string }> = ({ placeholder }) => {
88
+ return (
89
+ <div className="relative flex h-full flex-col justify-center px-4">
90
+ <div className="mx-auto w-full max-w-(--thread-max-width)">
91
+ <p className="font-display mb-8 text-center text-5xl leading-none tracking-[-0.06em] text-[#25211c] sm:text-[3.1rem] dark:text-[#f5f2ed]">
92
+ perplexity
93
+ </p>
94
+ <Composer placeholder={placeholder} />
95
+ </div>
96
+ <div className="pointer-events-none absolute inset-x-0 bottom-0 px-4 pb-2">
97
+ <SkinCredit />
98
+ </div>
99
+ </div>
100
+ );
101
+ };
102
+
103
+ const Composer: FC<{ placeholder: string }> = ({ placeholder }) => {
104
+ return (
105
+ <ComposerPrimitive.Root data-export-chrome="" className="group/composer mx-auto flex w-full max-w-(--thread-max-width) flex-col rounded-3xl border border-[#d7d0c5] bg-[#fcfbf8] transition-colors focus-within:border-[#b8b0a5] dark:border-[#4a433b] dark:bg-[#23211f] dark:focus-within:border-[#6a6258]">
106
+ <AuiIf condition={(s) => s.composer.attachments.length > 0}>
107
+ <div className="flex flex-wrap gap-2 px-4 pt-4">
108
+ <ComposerPrimitive.Attachments>
109
+ {() => <AttachmentPreview removable />}
110
+ </ComposerPrimitive.Attachments>
111
+ </div>
112
+ </AuiIf>
113
+
114
+ <ComposerPrimitive.Input
115
+ rows={2}
116
+ placeholder={placeholder}
117
+ className="min-h-20 w-full resize-none bg-transparent px-5 pt-4 pb-0 text-[1.05rem] leading-7 outline-none placeholder:text-[#8a8176] dark:placeholder:text-[#918a82]"
118
+ />
119
+
120
+ <div className="flex items-center justify-between gap-2 px-3 pt-0.5 pb-3">
121
+ <div className="flex min-w-0 items-center gap-1.5">
122
+ <ComposerPrimitive.AddAttachment asChild>
123
+ <button
124
+ type="button"
125
+ className="flex size-9 shrink-0 items-center justify-center rounded-full text-[#6f675d] transition-colors hover:bg-[#f2ede6] hover:text-[#1f1b17] dark:text-[#a39c93] dark:hover:bg-[#2b2825] dark:hover:text-[#f5f2ed]"
126
+ aria-label="Add attachment"
127
+ >
128
+ <Plus className="size-4.5" />
129
+ </button>
130
+ </ComposerPrimitive.AddAttachment>
131
+ <SearchModePicker />
132
+ </div>
133
+
134
+ <div className="flex items-center gap-1">
135
+ <ModelPicker />
136
+ <ComposerPrimaryAction />
137
+ </div>
138
+ </div>
139
+ </ComposerPrimitive.Root>
140
+ );
141
+ };
142
+
143
+ const ComposerPrimaryAction: FC = () => {
144
+ return (
145
+ <div className="relative size-10 shrink-0">
146
+ <AuiIf condition={(s) => s.thread.isRunning}>
147
+ <ComposerPrimitive.Cancel
148
+ className={cn(
149
+ composerPrimaryActionClassName,
150
+ composerPrimaryActionColorsClassName,
151
+ )}
152
+ >
153
+ <Square className="size-3.5 fill-current" />
154
+ </ComposerPrimitive.Cancel>
155
+ </AuiIf>
156
+
157
+ <AuiIf
158
+ condition={(s) => !s.thread.isRunning && s.composer.dictation != null}
159
+ >
160
+ <ComposerPrimitive.StopDictation
161
+ className={cn(
162
+ composerPrimaryActionClassName,
163
+ composerPrimaryActionColorsClassName,
164
+ )}
165
+ >
166
+ <Square className="size-3.5 animate-pulse fill-current" />
167
+ </ComposerPrimitive.StopDictation>
168
+ </AuiIf>
169
+
170
+ <AuiIf
171
+ condition={(s) =>
172
+ !s.thread.isRunning &&
173
+ s.composer.dictation == null &&
174
+ !s.composer.isEmpty
175
+ }
176
+ >
177
+ <ComposerPrimitive.Send
178
+ className={cn(
179
+ composerPrimaryActionClassName,
180
+ composerPrimaryActionColorsClassName,
181
+ )}
182
+ >
183
+ <ArrowRight className="size-5" />
184
+ </ComposerPrimitive.Send>
185
+ </AuiIf>
186
+
187
+ <AuiIf
188
+ condition={(s) =>
189
+ !s.thread.isRunning &&
190
+ s.composer.dictation == null &&
191
+ s.composer.isEmpty
192
+ }
193
+ >
194
+ <ComposerPrimitive.Dictate
195
+ className={cn(
196
+ composerPrimaryActionClassName,
197
+ composerPrimaryActionColorsClassName,
198
+ )}
199
+ >
200
+ <AudioLines className="size-5" />
201
+ </ComposerPrimitive.Dictate>
202
+ </AuiIf>
203
+ </div>
204
+ );
205
+ };
206
+
207
+ const SEARCH_MODES = [
208
+ {
209
+ id: "search",
210
+ name: "Search",
211
+ description: "Fast answers to everyday questions",
212
+ Icon: Search,
213
+ },
214
+ {
215
+ id: "research",
216
+ name: "Research",
217
+ description: "In-depth reports on complex topics",
218
+ Icon: Telescope,
219
+ },
220
+ {
221
+ id: "labs",
222
+ name: "Labs",
223
+ description: "Apps, slides, and dashboards",
224
+ Icon: Sparkles,
225
+ },
226
+ ];
227
+
228
+ const SearchModePicker: FC = () => {
229
+ const [mode, setMode] = useState(SEARCH_MODES[0]!.id);
230
+ const current = SEARCH_MODES.find((m) => m.id === mode) ?? SEARCH_MODES[0]!;
231
+ const CurrentIcon = current.Icon;
232
+
233
+ return (
234
+ <DropdownMenu>
235
+ <DropdownMenuTrigger className="flex h-8 items-center gap-1.5 rounded-full border border-[#e0d8cb] bg-[#f5f1eb] px-3 text-sm text-[#3a342d] transition-colors hover:bg-[#ede6dd] dark:border-[#3a342f] dark:bg-[#2a2724] dark:text-[#e6dfd5] dark:hover:bg-[#332f2c]">
236
+ <CurrentIcon className="size-3.5" />
237
+ <span>{current.name}</span>
238
+ <ChevronDownIcon className="size-3.5 opacity-70" />
239
+ </DropdownMenuTrigger>
240
+ <DropdownMenuContent align="start" className="min-w-64">
241
+ {SEARCH_MODES.map(({ id, name, description, Icon }) => (
242
+ <DropdownMenuItem
243
+ key={id}
244
+ onClick={() => setMode(id)}
245
+ className="flex items-start gap-3"
246
+ >
247
+ <span className="mt-0.5 flex size-4 items-center justify-center text-[#1f1b17] dark:text-[#f5f2ed]">
248
+ {id === mode ? <CheckIcon /> : <Icon className="size-3.5" />}
249
+ </span>
250
+ <span className="flex flex-1 flex-col">
251
+ <span className="text-foreground text-sm">{name}</span>
252
+ <span className="text-muted-foreground text-xs">
253
+ {description}
254
+ </span>
255
+ </span>
256
+ </DropdownMenuItem>
257
+ ))}
258
+ </DropdownMenuContent>
259
+ </DropdownMenu>
260
+ );
261
+ };
262
+
263
+ const PERPLEXITY_MODELS = [
264
+ { id: "best", name: "Best", description: "Auto-pick the best model" },
265
+ { id: "sonar", name: "Sonar", description: "Perplexity's fast model" },
266
+ { id: "claude", name: "Claude 4.5 Sonnet", description: "Anthropic" },
267
+ { id: "gpt-5", name: "GPT-5", description: "OpenAI" },
268
+ { id: "gemini", name: "Gemini 3 Pro", description: "Google" },
269
+ ];
270
+
271
+ const ModelPicker: FC = () => {
272
+ const [model, setModel] = useState(PERPLEXITY_MODELS[0]!.id);
273
+ const current =
274
+ PERPLEXITY_MODELS.find((m) => m.id === model) ?? PERPLEXITY_MODELS[0]!;
275
+
276
+ return (
277
+ <div data-deploy-model-picker className="contents">
278
+ <DropdownMenu>
279
+ <DropdownMenuTrigger className="hidden h-8 items-center gap-1 rounded-full px-2.5 text-sm text-[#746c62] transition-colors hover:bg-[#f2ede6] hover:text-[#1f1b17] sm:flex dark:text-[#a19a91] dark:hover:bg-[#2b2825] dark:hover:text-[#f5f2ed]">
280
+ <span>{current.name}</span>
281
+ <ChevronDownIcon className="size-4 opacity-70" />
282
+ </DropdownMenuTrigger>
283
+ <DropdownMenuContent align="end" className="min-w-60">
284
+ {PERPLEXITY_MODELS.map((m) => (
285
+ <DropdownMenuItem
286
+ key={m.id}
287
+ onClick={() => setModel(m.id)}
288
+ className="flex items-start gap-3"
289
+ >
290
+ <span className="mt-0.5 flex size-4 items-center justify-center text-[#1f1b17] dark:text-[#f5f2ed]">
291
+ {m.id === model ? <CheckIcon /> : null}
292
+ </span>
293
+ <span className="flex flex-1 flex-col">
294
+ <span className="text-foreground text-sm">{m.name}</span>
295
+ <span className="text-muted-foreground text-xs">
296
+ {m.description}
297
+ </span>
298
+ </span>
299
+ </DropdownMenuItem>
300
+ ))}
301
+ </DropdownMenuContent>
302
+ </DropdownMenu>
303
+ </div>
304
+ );
305
+ };
306
+
307
+ const ChatMessage: FC = () => {
308
+ const role = useAuiState((s) => s.message.role);
309
+ return (
310
+ <MessagePrimitive.Root data-role={role} className="group/message mx-auto flex w-full max-w-(--thread-max-width) flex-col gap-2 py-4">
311
+ <AuiIf condition={(s) => s.message.role === "user"}>
312
+ <div className="flex flex-col items-end gap-2">
313
+ <div className="flex max-w-full flex-wrap justify-end gap-2">
314
+ <MessagePrimitive.Attachments>
315
+ {() => <AttachmentPreview removable={false} />}
316
+ </MessagePrimitive.Attachments>
317
+ </div>
318
+
319
+ <div className="flex items-start gap-2">
320
+ <ActionBarPrimitive.Root data-export-chrome="" className="mt-1 flex items-center gap-0.5 opacity-0 transition-opacity group-focus-within/message:opacity-100 group-hover/message:opacity-100">
321
+ <ActionBarPrimitive.Copy className={messageActionClassName}>
322
+ <CopyIcon className="size-4" />
323
+ </ActionBarPrimitive.Copy>
324
+ <ActionBarPrimitive.Edit className={messageActionClassName}>
325
+ <PencilIcon className="size-4" />
326
+ </ActionBarPrimitive.Edit>
327
+ </ActionBarPrimitive.Root>
328
+
329
+ <div className="max-w-[85%] rounded-3xl rounded-tr-md border border-[#ddd5c9] bg-[#fcfbf8] px-4 py-3 text-[#2c2721] dark:border-[#38332e] dark:bg-[#23211f] dark:text-[#f1ede7]">
330
+ <div className="prose prose-sm dark:prose-invert prose-p:my-0 wrap-break-word">
331
+ <MessagePrimitive.Parts components={{ Text: MarkdownText }} />
332
+ </div>
333
+ </div>
334
+ </div>
335
+
336
+ <BranchPicker className="mr-3" />
337
+ </div>
338
+ </AuiIf>
339
+
340
+ <AuiIf condition={(s) => s.message.role === "assistant"}>
341
+ <div className="flex items-start gap-3">
342
+ <div className="mt-1 flex size-8 shrink-0 items-center justify-center rounded-full border border-[#ddd5c9] bg-[#fffdfa] text-[#5b534a] dark:border-[#38332e] dark:bg-[#23211f] dark:text-[#d9d2c8]">
343
+ <Search className="size-4" />
344
+ </div>
345
+
346
+ <div className="min-w-0 flex-1">
347
+ <div className="prose prose-sm dark:prose-invert prose-li:my-1 prose-p:my-2 prose-ul:my-2 wrap-break-word text-[#2c2721] dark:text-[#ece7df]">
348
+ <MessagePrimitive.Parts components={{ Text: MarkdownText }} />
349
+ </div>
350
+
351
+ <div className="mt-2 flex items-center gap-2">
352
+ <BranchPicker />
353
+ <ActionBarPrimitive.Root data-export-chrome="" className="flex items-center gap-0.5 opacity-0 transition-opacity group-focus-within/message:opacity-100 group-hover/message:opacity-100">
354
+ <ActionBarPrimitive.Reload className={messageActionClassName}>
355
+ <RefreshCwIcon className="size-4" />
356
+ </ActionBarPrimitive.Reload>
357
+ <ActionBarPrimitive.Copy className={messageActionClassName}>
358
+ <AuiIf condition={(s) => s.message.isCopied}>
359
+ <CheckIcon className="size-4" />
360
+ </AuiIf>
361
+ <AuiIf condition={(s) => !s.message.isCopied}>
362
+ <CopyIcon className="size-4" />
363
+ </AuiIf>
364
+ </ActionBarPrimitive.Copy>
365
+ <MessageExportMenu
366
+ trigger={
367
+ <button type="button" aria-label="More" className={messageActionClassName}>
368
+ <MoreHorizontal width={16} height={16} />
369
+ </button>
370
+ }
371
+ icon={<Download className="size-4" />}
372
+ align="start"
373
+ contentClassName="bg-popover text-popover-foreground data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:animate-out z-50 min-w-40 overflow-hidden rounded-xl border p-1.5 shadow-md"
374
+ itemClassName="text-muted-foreground focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-pointer items-center gap-2.5 rounded-lg px-3 py-2 text-sm outline-none select-none"
375
+ />
376
+ </ActionBarPrimitive.Root>
377
+ </div>
378
+ </div>
379
+ </div>
380
+ </AuiIf>
381
+ </MessagePrimitive.Root>
382
+ );
383
+ };
384
+
385
+ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
386
+ className,
387
+ ...props
388
+ }) => {
389
+ return (
390
+ <BranchPickerPrimitive.Root data-export-chrome=""
391
+ hideWhenSingleBranch
392
+ className={cn(
393
+ "inline-flex items-center gap-1 text-xs text-[#8a8176] dark:text-[#9f978e]",
394
+ className,
395
+ )}
396
+ {...props}
397
+ >
398
+ <BranchPickerPrimitive.Previous className={messageActionClassName}>
399
+ <ChevronLeftIcon className="size-4" />
400
+ </BranchPickerPrimitive.Previous>
401
+ <span className="min-w-9 text-center">
402
+ <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
403
+ </span>
404
+ <BranchPickerPrimitive.Next className={messageActionClassName}>
405
+ <ChevronRightIcon className="size-4" />
406
+ </BranchPickerPrimitive.Next>
407
+ </BranchPickerPrimitive.Root>
408
+ );
409
+ };
410
+
411
+ const AttachmentTypeLabel: FC = () => {
412
+ const typeLabel = useAuiState((s) => {
413
+ switch (s.attachment.type) {
414
+ case "image":
415
+ return "Image";
416
+ case "document":
417
+ return "Document";
418
+ case "file":
419
+ return "File";
420
+ default:
421
+ return s.attachment.type;
422
+ }
423
+ });
424
+
425
+ return <span>{typeLabel}</span>;
426
+ };
427
+
428
+ const AttachmentPreview: FC<{ removable: boolean }> = ({ removable }) => {
429
+ const src = useAttachmentSrc();
430
+
431
+ return (
432
+ <AttachmentPrimitive.Root className="group/attachment relative">
433
+ <div className="flex max-w-65 items-center gap-3 rounded-2xl border border-[#e3dbcf] bg-[#f5f1eb] py-2 pr-3 pl-2 transition-colors hover:bg-[#efe8de] dark:border-[#3a342f] dark:bg-[#2a2724] dark:hover:bg-[#302c29]">
434
+ <div className="flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-xl bg-[#fffdfa] text-[#6f675d] dark:bg-[#201d1b] dark:text-[#a59f96]">
435
+ {src ? (
436
+ <img
437
+ src={src}
438
+ alt="Attachment"
439
+ className="size-full object-cover"
440
+ />
441
+ ) : (
442
+ <FileIcon className="size-4" />
443
+ )}
444
+ </div>
445
+ <div className="min-w-0">
446
+ <p className="truncate text-sm leading-5 text-[#2d2822] dark:text-[#f3efe9]">
447
+ <AttachmentPrimitive.Name />
448
+ </p>
449
+ <p className="text-xs text-[#7d7469] dark:text-[#9d968d]">
450
+ <AttachmentTypeLabel />
451
+ </p>
452
+ </div>
453
+ </div>
454
+
455
+ {removable ? (
456
+ <AttachmentPrimitive.Remove className="absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full bg-[#ede6dd] text-[#5f574d] opacity-0 transition-all group-hover/attachment:opacity-100 hover:bg-[#dfd5c8] dark:bg-[#3a342f] dark:text-[#d4ccc2] dark:hover:bg-[#4a433b]">
457
+ <XIcon className="size-3.5" />
458
+ </AttachmentPrimitive.Remove>
459
+ ) : null}
460
+ </AttachmentPrimitive.Root>
461
+ );
462
+ };
@@ -0,0 +1,73 @@
1
+ "use client";
2
+
3
+ import { AssistantModalPrimitive } from "@assistant-ui/react";
4
+ import { ChevronDownIcon, LifeBuoyIcon } from "lucide-react";
5
+ import { type FC, forwardRef, type ReactNode } from "react";
6
+
7
+ import { TooltipIconButton } from "../tooltip-icon-button";
8
+
9
+ type AssistantModalProps = {
10
+ triggerLabel: string;
11
+ closeLabel: string;
12
+ defaultOpen?: boolean;
13
+ children: ReactNode;
14
+ };
15
+
16
+ export const AssistantModal: FC<AssistantModalProps> = ({
17
+ triggerLabel,
18
+ closeLabel,
19
+ defaultOpen = false,
20
+ children,
21
+ }) => {
22
+ return (
23
+ <AssistantModalPrimitive.Root defaultOpen={defaultOpen} unstable_openOnRunStart>
24
+ <AssistantModalPrimitive.Anchor className="aui-root aui-modal-anchor fixed end-4 bottom-4 z-40 size-12">
25
+ <AssistantModalPrimitive.Trigger asChild>
26
+ <AssistantModalButton triggerLabel={triggerLabel} closeLabel={closeLabel} />
27
+ </AssistantModalPrimitive.Trigger>
28
+ </AssistantModalPrimitive.Anchor>
29
+ <AssistantModalPrimitive.Content
30
+ sideOffset={16}
31
+ className="aui-root aui-modal-content data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-bottom-1/2 data-[state=closed]:slide-out-to-right-1/2 data-[state=closed]:zoom-out data-[state=open]:fade-in-0 data-[state=open]:slide-in-from-bottom-1/2 data-[state=open]:slide-in-from-right-1/2 data-[state=open]:zoom-in bg-popover text-popover-foreground data-[state=closed]:animate-out data-[state=open]:animate-in z-50 h-[min(720px,calc(100dvh-5rem))] w-[min(440px,calc(100vw-2rem))] overflow-clip overscroll-contain rounded-lg border border-slate-200 p-0 shadow-xl outline-none [&>.aui-thread-root]:bg-inherit [&>.aui-thread-root_.aui-thread-viewport-footer]:bg-inherit"
32
+ >
33
+ {children}
34
+ </AssistantModalPrimitive.Content>
35
+ </AssistantModalPrimitive.Root>
36
+ );
37
+ };
38
+
39
+ type AssistantModalButtonProps = {
40
+ "data-state"?: "open" | "closed";
41
+ triggerLabel: string;
42
+ closeLabel: string;
43
+ };
44
+
45
+ const AssistantModalButton = forwardRef<HTMLButtonElement, AssistantModalButtonProps>(
46
+ ({ "data-state": state, triggerLabel, closeLabel, ...rest }, ref) => {
47
+ const tooltip = state === "open" ? closeLabel : triggerLabel;
48
+
49
+ return (
50
+ <TooltipIconButton
51
+ variant="default"
52
+ tooltip={tooltip}
53
+ side="left"
54
+ {...rest}
55
+ className="aui-modal-button size-full rounded-full bg-primary text-primary-foreground shadow-lg transition-transform hover:scale-105 hover:bg-primary/90 active:scale-95"
56
+ ref={ref}
57
+ >
58
+ <LifeBuoyIcon
59
+ data-state={state}
60
+ className="aui-modal-button-closed-icon absolute size-6 transition-all data-[state=closed]:scale-100 data-[state=closed]:rotate-0 data-[state=open]:scale-0 data-[state=open]:rotate-90"
61
+ />
62
+
63
+ <ChevronDownIcon
64
+ data-state={state}
65
+ className="aui-modal-button-open-icon absolute size-6 transition-all data-[state=closed]:scale-0 data-[state=closed]:-rotate-90 data-[state=open]:scale-100 data-[state=open]:rotate-0"
66
+ />
67
+ <span className="aui-sr-only sr-only">{tooltip}</span>
68
+ </TooltipIconButton>
69
+ );
70
+ },
71
+ );
72
+
73
+ AssistantModalButton.displayName = "AssistantModalButton";
@@ -0,0 +1,19 @@
1
+ "use client";
2
+
3
+ import { Thread } from "../../stock/thread.aui";
4
+ import { AssistantModal } from "./assistant-modal";
5
+ import { ProductDashboard } from "./product-dashboard";
6
+ import { useComposerCopy } from "../../stock";
7
+
8
+ export function ProductPageAssistant() {
9
+ const { title } = useComposerCopy("How can I help?", "Describe the issue");
10
+ const trigger = title ? `Open ${title}` : "Open support";
11
+ return (
12
+ <div className="relative h-full">
13
+ <ProductDashboard />
14
+ <AssistantModal triggerLabel={trigger} closeLabel="Close support" defaultOpen>
15
+ <Thread />
16
+ </AssistantModal>
17
+ </div>
18
+ );
19
+ }