@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.
- package/README.md +48 -2
- package/package.json +143 -4
- package/src/components/NavShell.tsx +776 -0
- package/src/components/SocialRow.tsx +87 -0
- package/src/components/Spinner.tsx +27 -0
- package/src/components/StackLogo.tsx +40 -0
- package/src/components/Terminal.tsx +110 -0
- package/src/components/TerminalManifest.tsx +212 -0
- package/src/components/ThemeProvider.tsx +271 -0
- package/src/components/account/AuthCard.tsx +309 -0
- package/src/components/assistant-ui/elements/mermaid-diagram.aui.tsx +63 -0
- package/src/components/assistant-ui/elements/mermaid-diagram.tsx +340 -0
- package/src/components/brand/BrandWordmark.tsx +32 -0
- package/src/components/changelog/ReleaseRail.tsx +81 -0
- package/src/components/changelog/index.ts +1 -0
- package/src/components/chat/ChatCodeBlock.tsx +67 -0
- package/src/components/chat/ChatMarkdown.tsx +66 -0
- package/src/components/chat/ChatMarkdownSource.tsx +203 -0
- package/src/components/chat/ChatMermaidBlock.tsx +202 -0
- package/src/components/chat/ChatMessage.tsx +77 -0
- package/src/components/chat/ChatPlayback.tsx +422 -0
- package/src/components/chat/ChatStreamCursor.tsx +25 -0
- package/src/components/chat/ChatThinking.tsx +113 -0
- package/src/components/chat/ChatToolCall.tsx +190 -0
- package/src/components/chat/ChatTranscript.tsx +60 -0
- package/src/components/chat/ChatWidgetFrame.tsx +107 -0
- package/src/components/chat/DigichatBootLoader.tsx +683 -0
- package/src/components/chat/DigichatLauncher.tsx +361 -0
- package/src/components/chat/DigichatThread.tsx +118 -0
- package/src/components/chat/DigichatThreadList.tsx +54 -0
- package/src/components/chat/DigichatWordmark.tsx +24 -0
- package/src/components/chat/DotMatrix.tsx +650 -0
- package/src/components/chat/boot-lab.tsx +766 -0
- package/src/components/chat/boot-signal.ts +144 -0
- package/src/components/chat/chat-surfaces.ts +52 -0
- package/src/components/chat/connection-status.ts +40 -0
- package/src/components/chat/digichat-wordmark.ts +355 -0
- package/src/components/chat/disclosure-chevron.tsx +49 -0
- package/src/components/chat/followable-href.ts +9 -0
- package/src/components/chat/gallery-thread/action-icons.tsx +25 -0
- package/src/components/chat/gallery-thread/attachment.aui.tsx +262 -0
- package/src/components/chat/gallery-thread/block-caret.tsx +439 -0
- package/src/components/chat/gallery-thread/cn.ts +1 -0
- package/src/components/chat/gallery-thread/composer-keyboard.ts +106 -0
- package/src/components/chat/gallery-thread/composer-trigger-popover.aui.tsx +235 -0
- package/src/components/chat/gallery-thread/css.d.ts +6 -0
- package/src/components/chat/gallery-thread/file.tsx +238 -0
- package/src/components/chat/gallery-thread/follow-up-suggestions.aui.tsx +92 -0
- package/src/components/chat/gallery-thread/format-json-dump.ts +112 -0
- package/src/components/chat/gallery-thread/hooks/use-attachment-src.ts +46 -0
- package/src/components/chat/gallery-thread/hooks/use-copy-to-clipboard.ts +9 -0
- package/src/components/chat/gallery-thread/image.tsx +519 -0
- package/src/components/chat/gallery-thread/markdown-text.tsx +278 -0
- package/src/components/chat/gallery-thread/message-error.aui.tsx +105 -0
- package/src/components/chat/gallery-thread/message-timing.aui.tsx +143 -0
- package/src/components/chat/gallery-thread/private-work-step.tsx +188 -0
- package/src/components/chat/gallery-thread/reasoning.tsx +332 -0
- package/src/components/chat/gallery-thread/scroll-mode.ts +174 -0
- package/src/components/chat/gallery-thread/source.tsx +76 -0
- package/src/components/chat/gallery-thread/thread.aui.tsx +1619 -0
- package/src/components/chat/gallery-thread/tooltip-icon-button.tsx +53 -0
- package/src/components/chat/gallery-thread/typed-welcome-copy.tsx +18 -0
- package/src/components/chat/gallery-thread/ui/tooltip.tsx +22 -0
- package/src/components/chat/gallery-thread/work-chain-summary.tsx +48 -0
- package/src/components/chat/gallery-thread/work-chain.tsx +110 -0
- package/src/components/chat/gallery-thread/work-status.ts +66 -0
- package/src/components/chat/overlay-scrollbar.tsx +86 -0
- package/src/components/chat/sanitize-mermaid-svg.ts +38 -0
- package/src/components/chat/skins/SOURCE.md +36 -0
- package/src/components/chat/skins/base/attachment.aui.tsx +287 -0
- package/src/components/chat/skins/base/aui-default/README.md +45 -0
- package/src/components/chat/skins/base/aui-default/collapsible-root.tsx +19 -0
- package/src/components/chat/skins/base/aui-default/collapsible.tsx +21 -0
- package/src/components/chat/skins/base/aui-default/reasoning.aui.tsx +120 -0
- package/src/components/chat/skins/base/aui-default/reasoning.tsx +331 -0
- package/src/components/chat/skins/base/aui-default/surfaces.ts +7 -0
- package/src/components/chat/skins/base/aui-default/tool-fallback.aui.tsx +772 -0
- package/src/components/chat/skins/base/aui-default/tool-group.aui.tsx +241 -0
- package/src/components/chat/skins/base/docs-model-options.ts +6 -0
- package/src/components/chat/skins/base/elements/assistant-trace.aui.tsx +169 -0
- package/src/components/chat/skins/base/elements/composer-trigger-popover.aui.tsx +271 -0
- package/src/components/chat/skins/base/elements/directive-text.aui.tsx +29 -0
- package/src/components/chat/skins/base/elements/directive-text.tsx +76 -0
- package/src/components/chat/skins/base/elements/message-timing.aui.tsx +104 -0
- package/src/components/chat/skins/base/elements/model-selector.aui.tsx +140 -0
- package/src/components/chat/skins/base/elements/model-selector.tsx +720 -0
- package/src/components/chat/skins/base/elements/quote.aui.tsx +290 -0
- package/src/components/chat/skins/base/elements/work-chain.tsx +100 -0
- package/src/components/chat/skins/base/markdown-text.tsx +294 -0
- package/src/components/chat/skins/base/model.ts +1 -0
- package/src/components/chat/skins/base/thread.tsx +1050 -0
- package/src/components/chat/skins/base/tooltip-icon-button.tsx +56 -0
- package/src/components/chat/skins/base/ui/avatar.tsx +115 -0
- package/src/components/chat/skins/base/ui/badge.tsx +51 -0
- package/src/components/chat/skins/base/ui/button.tsx +67 -0
- package/src/components/chat/skins/base/ui/command.tsx +185 -0
- package/src/components/chat/skins/base/ui/dialog.tsx +168 -0
- package/src/components/chat/skins/base/ui/dot-matrix.tsx +267 -0
- package/src/components/chat/skins/base/ui/popover.tsx +97 -0
- package/src/components/chat/skins/base/ui/skeleton.tsx +20 -0
- package/src/components/chat/skins/base/ui/textarea.tsx +24 -0
- package/src/components/chat/skins/base/ui/tooltip.tsx +73 -0
- package/src/components/chat/skins/base-assistant-ui/config-provider.tsx +90 -0
- package/src/components/chat/skins/base-assistant-ui/defaults.ts +419 -0
- package/src/components/chat/skins/base-assistant-ui/index.tsx +44 -0
- package/src/components/chat/skins/chatgpt.tsx +448 -0
- package/src/components/chat/skins/claude.tsx +380 -0
- package/src/components/chat/skins/digichat-composer-toolbar.tsx +151 -0
- package/src/components/chat/skins/digichat-context-meter-shares.ts +158 -0
- package/src/components/chat/skins/digichat-context-meter.tsx +243 -0
- package/src/components/chat/skins/digichat-meter-tone.ts +26 -0
- package/src/components/chat/skins/digichat-usage-meter.tsx +103 -0
- package/src/components/chat/skins/digichat.tsx +144 -0
- package/src/components/chat/skins/expo-react-native.tsx +29 -0
- package/src/components/chat/skins/gemini.tsx +322 -0
- package/src/components/chat/skins/grok-icon.tsx +34 -0
- package/src/components/chat/skins/grok.tsx +369 -0
- package/src/components/chat/skins/index.ts +46 -0
- package/src/components/chat/skins/perplexity.tsx +462 -0
- package/src/components/chat/skins/product-page-assistant/assistant-modal.tsx +73 -0
- package/src/components/chat/skins/product-page-assistant/index.tsx +19 -0
- package/src/components/chat/skins/product-page-assistant/product-dashboard.tsx +164 -0
- package/src/components/chat/skins/react-ink.tsx +97 -0
- package/src/components/chat/skins/thread-skin-host-contract.ts +102 -0
- package/src/components/chat/skins/thread-skin-view.tsx +156 -0
- package/src/components/chat/skins/thread-skins.ts +143 -0
- package/src/components/chat/skins/tooltip-icon-button.tsx +35 -0
- package/src/components/chat/skins/ui/dropdown-menu.tsx +272 -0
- package/src/components/chat/skins/webpage-assistant/assistant-config.ts +238 -0
- package/src/components/chat/skins/webpage-assistant/assistant-modal.tsx +78 -0
- package/src/components/chat/skins/webpage-assistant/config-provider.tsx +132 -0
- package/src/components/chat/skins/webpage-assistant/docs-app.tsx +106 -0
- package/src/components/chat/skins/webpage-assistant/docs-article.tsx +109 -0
- package/src/components/chat/skins/webpage-assistant/docs-assistant.tsx +73 -0
- package/src/components/chat/skins/webpage-assistant/docs-nav.tsx +81 -0
- package/src/components/chat/skins/webpage-assistant/host-ui.ts +79 -0
- package/src/components/chat/skins/webpage-assistant/index.tsx +12 -0
- package/src/components/chat/skins/webpage-assistant/markdown-page.tsx +11 -0
- package/src/components/chat/skins/webpage-assistant/pages.ts +9 -0
- package/src/components/chat/skins/webpage-assistant/types.ts +178 -0
- package/src/components/chat/skins/webpage-assistant/use-mobile.ts +19 -0
- package/src/components/chat/stock/SOURCE.md +90 -0
- package/src/components/chat/stock/artifacts-panel.tsx +305 -0
- package/src/components/chat/stock/attachment.aui.tsx +280 -0
- package/src/components/chat/stock/chat-notice.tsx +143 -0
- package/src/components/chat/stock/chat-private-mode.tsx +64 -0
- package/src/components/chat/stock/deploy-ui-context.tsx +89 -0
- package/src/components/chat/stock/embed-chat-prefs.tsx +471 -0
- package/src/components/chat/stock/file.tsx +265 -0
- package/src/components/chat/stock/follow-up-suggestions.aui.tsx +83 -0
- package/src/components/chat/stock/image.tsx +531 -0
- package/src/components/chat/stock/index.ts +129 -0
- package/src/components/chat/stock/json-view.tsx +140 -0
- package/src/components/chat/stock/markdown-text.tsx +319 -0
- package/src/components/chat/stock/message-error.aui.tsx +96 -0
- package/src/components/chat/stock/message-export-menu.tsx +156 -0
- package/src/components/chat/stock/palette-row-preview.tsx +26 -0
- package/src/components/chat/stock/reasoning.aui.tsx +120 -0
- package/src/components/chat/stock/reasoning.tsx +335 -0
- package/src/components/chat/stock/skin-chrome.tsx +81 -0
- package/src/components/chat/stock/skin-credit.tsx +63 -0
- package/src/components/chat/stock/skin-palette-bridge.tsx +235 -0
- package/src/components/chat/stock/skin-palette-context.ts +16 -0
- package/src/components/chat/stock/skin-runtime.tsx +52 -0
- package/src/components/chat/stock/skin-slash-palette.tsx +393 -0
- package/src/components/chat/stock/skin-types.ts +217 -0
- package/src/components/chat/stock/stock-chat-prefs-host.tsx +501 -0
- package/src/components/chat/stock/stock-send-gate.tsx +94 -0
- package/src/components/chat/stock/stock-shape.tsx +39 -0
- package/src/components/chat/stock/thread.aui.tsx +645 -0
- package/src/components/chat/stock/tool-display.ts +6 -0
- package/src/components/chat/stock/tool-fallback.aui.tsx +866 -0
- package/src/components/chat/stock/tool-group.aui.tsx +244 -0
- package/src/components/chat/stock/tool-surface.ts +120 -0
- package/src/components/chat/stock/tooltip-icon-button.tsx +49 -0
- package/src/components/chat/stock/ui/avatar.tsx +108 -0
- package/src/components/chat/stock/ui/button.tsx +81 -0
- package/src/components/chat/stock/ui/collapsible.tsx +21 -0
- package/src/components/chat/stock/ui/dialog.tsx +163 -0
- package/src/components/chat/stock/ui/skeleton.tsx +13 -0
- package/src/components/chat/stock/ui/textarea.tsx +20 -0
- package/src/components/chat/stock/ui/tooltip.tsx +68 -0
- package/src/components/chat/stock/use-attachment-src.ts +42 -0
- package/src/components/chat/stock/use-copy-to-clipboard.ts +29 -0
- package/src/components/chat/strip-model-boilerplate.ts +42 -0
- package/src/components/chat/suggestion-cycle.tsx +230 -0
- package/src/components/chat/suggestion-scroll-row.tsx +81 -0
- package/src/components/chat/trace-grouping/chain-group-by.ts +44 -0
- package/src/components/chat/trace-grouping/chain-state.ts +141 -0
- package/src/components/chat/trace-grouping/index.ts +32 -0
- package/src/components/chat/trace-grouping/tool-row.ts +74 -0
- package/src/components/chat/trace-grouping/use-deploy-work-disclosure.ts +35 -0
- package/src/components/chat/trace-grouping/use-work-chain.ts +103 -0
- package/src/components/chat/trace-i18n/core.ts +48 -0
- package/src/components/chat/trace-i18n/index.tsx +23 -0
- package/src/components/chat/trace-i18n/locales/en.ts +24 -0
- package/src/components/chat/trace-i18n/locales/fr.ts +28 -0
- package/src/components/chat/trace-i18n/types.ts +35 -0
- package/src/components/chat/trace-spacing.ts +249 -0
- package/src/components/chat/transcript/activity-view.ts +375 -0
- package/src/components/chat/transcript/chat-export.ts +133 -0
- package/src/components/chat/transcript/index.ts +10 -0
- package/src/components/chat/transcript/save-file.ts +209 -0
- package/src/components/chat/transcript/transcript-markdown.ts +428 -0
- package/src/components/chat/transcript/types.ts +81 -0
- package/src/components/chat/turn-outcome.ts +52 -0
- package/src/components/chat/use-warmup-phase.ts +18 -0
- package/src/components/chat/work-status-lead.tsx +49 -0
- package/src/components/chrome.tsx +264 -0
- package/src/components/command-palette/CommandPalette.tsx +404 -0
- package/src/components/command-palette/index.ts +6 -0
- package/src/components/contact/ContactMailto.tsx +112 -0
- package/src/components/contact/index.ts +5 -0
- package/src/components/conviction/ConvictionMeter.tsx +40 -0
- package/src/components/conviction/SignedConvictionBadge.tsx +26 -0
- package/src/components/conviction/index.ts +7 -0
- package/src/components/data-layout/BentoGrid.tsx +52 -0
- package/src/components/data-layout/CardRail.tsx +150 -0
- package/src/components/data-layout/DotMatrixStat.tsx +65 -0
- package/src/components/data-layout/FeatureCell.tsx +80 -0
- package/src/components/data-layout/MediaFrame.tsx +125 -0
- package/src/components/data-layout/ModuleGrid.tsx +735 -0
- package/src/components/data-layout/Odometer.tsx +149 -0
- package/src/components/data-layout/ProductFrame.tsx +79 -0
- package/src/components/data-layout/TestimonialWall.tsx +139 -0
- package/src/components/data-layout/index.ts +19 -0
- package/src/components/data-layout/treemap.ts +368 -0
- package/src/components/deck/DeckStack.tsx +243 -0
- package/src/components/desk/DataTable.tsx +373 -0
- package/src/components/desk/KpiGrid.tsx +80 -0
- package/src/components/desk/Sparkline.tsx +63 -0
- package/src/components/desk/StateBlock.tsx +132 -0
- package/src/components/desk/index.ts +18 -0
- package/src/components/diagrams/ArchitectureDiagram.tsx +350 -0
- package/src/components/diagrams/ArchitectureTour.tsx +912 -0
- package/src/components/diagrams/TerminalSchematic.tsx +192 -0
- package/src/components/diagrams/architecture-svg.tsx +384 -0
- package/src/components/diagrams/index.ts +30 -0
- package/src/components/diagrams/mermaid-theme.ts +115 -0
- package/src/components/diagrams/tour-camera.ts +171 -0
- package/src/components/docs/CodeTabs.tsx +90 -0
- package/src/components/docs/CopyCommand.tsx +151 -0
- package/src/components/docs/DocsLayout.tsx +197 -0
- package/src/components/docs/DocsSearch.tsx +97 -0
- package/src/components/docs/Endpoint.tsx +135 -0
- package/src/components/document/DocumentFrame.tsx +43 -0
- package/src/components/document/GlyphList.tsx +51 -0
- package/src/components/document/PageTitle.tsx +44 -0
- package/src/components/document/Prose.tsx +38 -0
- package/src/components/document/Section.tsx +55 -0
- package/src/components/document/index.ts +13 -0
- package/src/components/effects-chrome/AnnouncementBar.tsx +88 -0
- package/src/components/effects-chrome/HorizontalScrollTrack.tsx +461 -0
- package/src/components/effects-chrome/Pipeline.tsx +226 -0
- package/src/components/effects-chrome/RotatingPrompts.tsx +116 -0
- package/src/components/effects-chrome/StackingPanels.tsx +101 -0
- package/src/components/effects-chrome/TabStrip.tsx +232 -0
- package/src/components/effects-chrome/ToastStack.tsx +201 -0
- package/src/components/effects-chrome/horizontal-track-core.ts +70 -0
- package/src/components/effects-chrome/index.ts +35 -0
- package/src/components/emblems.tsx +188 -0
- package/src/components/faviconTheme.ts +23 -0
- package/src/components/figure/Figure.tsx +38 -0
- package/src/components/figure/index.ts +2 -0
- package/src/components/finance-charts/DrawdownPlot.tsx +76 -0
- package/src/components/finance-charts/EquityCurve.tsx +71 -0
- package/src/components/finance-charts/PriceChart.tsx +119 -0
- package/src/components/finance-charts/chart-host.tsx +236 -0
- package/src/components/finance-charts/chart-scale.ts +93 -0
- package/src/components/finance-charts/demo-data.ts +88 -0
- package/src/components/finance-charts/index.ts +46 -0
- package/src/components/finance-charts/lw-chart.tsx +292 -0
- package/src/components/finance-composites/MarketBar.tsx +243 -0
- package/src/components/finance-composites/OrderBook.tsx +133 -0
- package/src/components/finance-composites/PerformanceDashboard.tsx +185 -0
- package/src/components/finance-composites/SortableTable.tsx +144 -0
- package/src/components/finance-composites/StockTicker.tsx +65 -0
- package/src/components/finance-composites/SyncedTearsheet.tsx +226 -0
- package/src/components/finance-composites/index.ts +28 -0
- package/src/components/finance-tearsheet/KpiStrip.tsx +49 -0
- package/src/components/finance-tearsheet/LiveBadge.tsx +29 -0
- package/src/components/finance-tearsheet/ReturnsMatrix.tsx +321 -0
- package/src/components/finance-tearsheet/StrategyTearsheet.tsx +99 -0
- package/src/components/finance-tearsheet/TearsheetCard.tsx +54 -0
- package/src/components/finance-tearsheet/TradeLogTable.tsx +73 -0
- package/src/components/finance-tearsheet/charts.tsx +2624 -0
- package/src/components/finance-tearsheet/demo-data.ts +177 -0
- package/src/components/finance-tearsheet/format.ts +41 -0
- package/src/components/finance-tearsheet/index.ts +120 -0
- package/src/components/finance-tearsheet/print.ts +52 -0
- package/src/components/finance-tearsheet/risk-bands.ts +48 -0
- package/src/components/finance-tearsheet/stats.ts +35 -0
- package/src/components/finance-tearsheet/strategy-sheet-model.ts +238 -0
- package/src/components/finance-tearsheet/types.ts +58 -0
- package/src/components/footer/FooterCells.tsx +109 -0
- package/src/components/footer/index.ts +6 -0
- package/src/components/graph.tsx +158 -0
- package/src/components/icons.tsx +98 -0
- package/src/components/landing/PixelWordmark.tsx +36 -0
- package/src/components/logos.ts +39 -0
- package/src/components/marquee/Marquee.tsx +204 -0
- package/src/components/metrics/PerfMetrics.tsx +68 -0
- package/src/components/metrics/StatCounter.tsx +104 -0
- package/src/components/page-geometry.tsx +177 -0
- package/src/components/pricing/Pricing.tsx +174 -0
- package/src/components/pricing/PricingMatrix.tsx +219 -0
- package/src/components/prose/index.ts +2 -0
- package/src/components/prose/prose.tsx +86 -0
- package/src/components/repo-activity/RepoActivity.tsx +599 -0
- package/src/components/repo-activity/RepoHeatmap.tsx +225 -0
- package/src/components/repo-activity/demo.ts +201 -0
- package/src/components/repo-activity/fetch.ts +211 -0
- package/src/components/repo-activity/heatmap.ts +123 -0
- package/src/components/repo-activity/index.ts +28 -0
- package/src/components/repo-activity/types.ts +99 -0
- package/src/components/stages/NumberedStages.tsx +116 -0
- package/src/components/symbols/marks.tsx +116 -0
- package/src/components/symbols/terminal-lockup.tsx +136 -0
- package/src/components/symbols/terminal-marks.tsx +226 -0
- package/src/components/terminal/ChatResponseLoader.tsx +67 -0
- package/src/components/terminal/ContainerBootLoader.tsx +82 -0
- package/src/components/terminal/TerminalStepCaret.tsx +202 -0
- package/src/components/themeInit.ts +24 -0
- package/src/components/typography/MotionReveal.tsx +108 -0
- package/src/components/typography/TypewriterReveal.tsx +101 -0
- package/src/components/typography/WordReveal.tsx +143 -0
- package/src/data/modules.ts +378 -0
- package/src/data/subsystems.ts +101 -0
- package/src/index.ts +587 -0
- package/src/lib/base-path.ts +60 -0
- package/src/lib/cx.ts +25 -0
- package/src/lib/gloomberb.ts +69 -0
- package/src/lib/record.ts +19 -0
- package/src/lib/stub-payload.ts +183 -0
- package/src/lib/useBodyScrollLock.ts +44 -0
- package/src/lib/utils.ts +6 -0
- package/src/motion/primitives.tsx +105 -0
- package/src/motion/scroll-glide.ts +62 -0
- package/src/motion/scrolly-core.ts +38 -0
- package/src/motion/scrolly.tsx +95 -0
- package/src/navigation/HashScrollManager.tsx +167 -0
- package/src/navigation/hashScroll.ts +78 -0
- package/src/replay/browser.ts +280 -0
- package/src/replay/chat-export-run.ts +121 -0
- package/src/replay/export-format.ts +25 -0
- package/src/replay/export-mount.ts +32 -0
- package/src/replay/filename.ts +54 -0
- package/src/replay/index.ts +21 -0
- package/src/replay/redact-dom.ts +178 -0
- package/src/replay/redact.ts +113 -0
- package/src/replay/snapshot.ts +659 -0
- package/src/styles/account-auth.css +339 -0
- package/src/styles/brand-wordmark.css +11 -0
- package/src/styles/card-rail.css +120 -0
- package/src/styles/chat-aui.css +1143 -0
- package/src/styles/chat-core.css +469 -0
- package/src/styles/chat-digichat.css +2531 -0
- package/src/styles/chat-math.css +70 -0
- package/src/styles/chat-skin-palette.css +138 -0
- package/src/styles/chat-stock-menu.css +37 -0
- package/src/styles/chat-widgets.css +190 -0
- package/src/styles/command-palette.css +372 -0
- package/src/styles/controls-core.css +2261 -0
- package/src/styles/controls-overlay.css +603 -0
- package/src/styles/data-layout.css +288 -0
- package/src/styles/deck.css +141 -0
- package/src/styles/diagrams.css +1860 -0
- package/src/styles/digichat-app-theme.css +250 -0
- package/src/styles/digichat-boot-loader.css +487 -0
- package/src/styles/digichat-launcher.css +377 -0
- package/src/styles/docs.css +165 -0
- package/src/styles/effects-chrome.css +888 -0
- package/src/styles/finance-composites.css +214 -0
- package/src/styles/finance-tearsheet-overlay.css +90 -0
- package/src/styles/finance-tearsheet.css +945 -0
- package/src/styles/marquee.css +168 -0
- package/src/styles/metrics.css +82 -0
- package/src/styles/nav-shell.css +551 -0
- package/src/styles/pricing.css +79 -0
- package/src/styles/repo-activity.css +575 -0
- package/src/styles/stages.css +69 -0
- package/src/styles/terminal-loaders.css +122 -0
- package/src/styles/terminal-manifest.css +228 -0
- package/src/styles/web-theme.css +1007 -0
- package/src/styles/word-reveal.css +204 -0
- package/src/theme/apply-theme.ts +214 -0
- package/src/theme/index.ts +27 -0
- package/src/theme/palette-registry.ts +855 -0
- package/src/theme/tui-prefs.ts +64 -0
- package/src/ui/alert.tsx +78 -0
- package/src/ui/avatar.tsx +104 -0
- package/src/ui/badge.tsx +75 -0
- package/src/ui/breadcrumb.tsx +61 -0
- package/src/ui/button.tsx +67 -0
- package/src/ui/card.tsx +139 -0
- package/src/ui/checkbox.tsx +27 -0
- package/src/ui/collapsible.tsx +32 -0
- package/src/ui/date-pager.tsx +325 -0
- package/src/ui/dialog.tsx +157 -0
- package/src/ui/dropdown-menu.tsx +267 -0
- package/src/ui/empty-state.tsx +165 -0
- package/src/ui/field.tsx +104 -0
- package/src/ui/form.tsx +36 -0
- package/src/ui/icon-button.tsx +36 -0
- package/src/ui/index.ts +34 -0
- package/src/ui/input.tsx +33 -0
- package/src/ui/kbd.tsx +30 -0
- package/src/ui/label.tsx +32 -0
- package/src/ui/pager.tsx +119 -0
- package/src/ui/pagination.tsx +126 -0
- package/src/ui/radio-group.tsx +51 -0
- package/src/ui/search-bar.tsx +85 -0
- package/src/ui/segmented-control.tsx +76 -0
- package/src/ui/select.tsx +257 -0
- package/src/ui/separator.tsx +24 -0
- package/src/ui/sheet.tsx +141 -0
- package/src/ui/skeleton.tsx +76 -0
- package/src/ui/slider.tsx +76 -0
- package/src/ui/switch.tsx +31 -0
- package/src/ui/table.tsx +179 -0
- package/src/ui/tabs.tsx +89 -0
- package/src/ui/tags-input.tsx +168 -0
- package/src/ui/textarea.tsx +17 -0
- package/src/ui/tooltip.tsx +71 -0
|
@@ -0,0 +1,1050 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ComposerAddAttachment,
|
|
5
|
+
ComposerAttachments,
|
|
6
|
+
UserMessageAttachments,
|
|
7
|
+
} from "./attachment.aui";
|
|
8
|
+
import { MarkdownText } from "./markdown-text";
|
|
9
|
+
import { useDigichatWarmupPhase } from "../../use-warmup-phase";
|
|
10
|
+
import { useSuggestionGroup } from "../../suggestion-cycle";
|
|
11
|
+
import { SuggestionScrollRow } from "../../suggestion-scroll-row";
|
|
12
|
+
import { connectionStatusText } from "../../connection-status";
|
|
13
|
+
import { MessageTiming } from "./elements/message-timing.aui";
|
|
14
|
+
import { backendNoticeOf } from "../../stock/chat-notice";
|
|
15
|
+
import { useSkinRuntime } from "../../stock/skin-runtime";
|
|
16
|
+
// assistant-ui's own trace parts (see ./aui-default/README.md), shared with
|
|
17
|
+
// the stock thread: the base skins render reasoning and tool calls as
|
|
18
|
+
// assistant-ui ships them.
|
|
19
|
+
import { AssistantTrace } from "./elements/assistant-trace.aui";
|
|
20
|
+
|
|
21
|
+
import { MessageExportMenu } from "../../stock/message-export-menu";
|
|
22
|
+
import { TooltipIconButton } from "./tooltip-icon-button";
|
|
23
|
+
import { messageHasContent } from "../../trace-grouping";
|
|
24
|
+
import { Button } from "./ui/button";
|
|
25
|
+
import { Skeleton } from "./ui/skeleton";
|
|
26
|
+
import { cn } from "../../../../lib/utils";
|
|
27
|
+
import {
|
|
28
|
+
SkinCredit,
|
|
29
|
+
useComposerCopy,
|
|
30
|
+
useSkinChrome,
|
|
31
|
+
} from "../../stock";
|
|
32
|
+
import {
|
|
33
|
+
ComposerQuotePreview,
|
|
34
|
+
QuoteBlock,
|
|
35
|
+
SelectionToolbar,
|
|
36
|
+
} from "./elements/quote.aui";
|
|
37
|
+
import { ComposerTriggerPopover } from "./elements/composer-trigger-popover.aui";
|
|
38
|
+
import { useSkinPaletteOptional } from "../../stock/skin-palette-context";
|
|
39
|
+
import { useEmbedChatPrefsOptional } from "../../stock/embed-chat-prefs";
|
|
40
|
+
import { DirectiveText } from "./elements/directive-text.aui";
|
|
41
|
+
import {
|
|
42
|
+
ActionBarPrimitive,
|
|
43
|
+
AuiIf,
|
|
44
|
+
type AssistantState,
|
|
45
|
+
BranchPickerPrimitive,
|
|
46
|
+
ComposerPrimitive,
|
|
47
|
+
ErrorPrimitive,
|
|
48
|
+
MessagePrimitive,
|
|
49
|
+
ThreadPrimitive,
|
|
50
|
+
unstable_useMentionAdapter,
|
|
51
|
+
unstable_useSlashCommandAdapter,
|
|
52
|
+
useAui,
|
|
53
|
+
useAuiState,
|
|
54
|
+
type Unstable_SlashCommand,
|
|
55
|
+
} from "@assistant-ui/react";
|
|
56
|
+
import {
|
|
57
|
+
ArrowDownIcon,
|
|
58
|
+
ArrowUpIcon,
|
|
59
|
+
ChartColumnIcon,
|
|
60
|
+
CheckIcon,
|
|
61
|
+
ChevronDownIcon,
|
|
62
|
+
ChevronLeftIcon,
|
|
63
|
+
ChevronRightIcon,
|
|
64
|
+
CloudSunIcon,
|
|
65
|
+
CodeXmlIcon,
|
|
66
|
+
CopyIcon,
|
|
67
|
+
DownloadIcon,
|
|
68
|
+
FileTextIcon,
|
|
69
|
+
GlobeIcon,
|
|
70
|
+
HelpCircleIcon,
|
|
71
|
+
LanguagesIcon,
|
|
72
|
+
LightbulbIcon,
|
|
73
|
+
MicIcon,
|
|
74
|
+
MoreHorizontalIcon,
|
|
75
|
+
PencilIcon,
|
|
76
|
+
PencilLineIcon,
|
|
77
|
+
RefreshCwIcon,
|
|
78
|
+
SlashIcon,
|
|
79
|
+
SquareIcon,
|
|
80
|
+
WrenchIcon,
|
|
81
|
+
} from "lucide-react";
|
|
82
|
+
import {
|
|
83
|
+
LexicalComposerInput,
|
|
84
|
+
type DirectiveChipProps,
|
|
85
|
+
} from "@assistant-ui/react-lexical";
|
|
86
|
+
import { useEffect, useRef, useState, type FC, type ReactNode } from "react";
|
|
87
|
+
import { ModelSelector } from "./elements/model-selector.aui";
|
|
88
|
+
import { docsModelOptions } from "./docs-model-options";
|
|
89
|
+
import { DEFAULT_MODEL_ID } from "./model";
|
|
90
|
+
|
|
91
|
+
const models = docsModelOptions();
|
|
92
|
+
|
|
93
|
+
/** Display label for a model id: the part after the vendor prefix. */
|
|
94
|
+
export function modelChipLabel(model: string): string {
|
|
95
|
+
const id = model.trim();
|
|
96
|
+
if (!id) return "auto";
|
|
97
|
+
return id.slice(id.lastIndexOf("/") + 1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Inside a host with chat prefs the chip is the real picker: it shows the
|
|
102
|
+
* session model and opens the host's models menu (the same list `/models`
|
|
103
|
+
* shows). The demo selector only renders without a host (the catalog).
|
|
104
|
+
*/
|
|
105
|
+
const ModelPicker: FC = () => {
|
|
106
|
+
const prefs = useEmbedChatPrefsOptional();
|
|
107
|
+
if (prefs) {
|
|
108
|
+
if (!prefs.showModels) return null;
|
|
109
|
+
return (
|
|
110
|
+
<div data-deploy-model-picker>
|
|
111
|
+
<Button
|
|
112
|
+
type="button"
|
|
113
|
+
variant="ghost"
|
|
114
|
+
size="sm"
|
|
115
|
+
className="aui-model-chip text-muted-foreground hover:text-foreground h-7 max-w-48 gap-1 rounded-full px-2.5 text-xs"
|
|
116
|
+
onClick={prefs.openModels}
|
|
117
|
+
aria-label="Open models"
|
|
118
|
+
title={prefs.prefs.model.trim() || "auto"}
|
|
119
|
+
>
|
|
120
|
+
<span className="truncate">{modelChipLabel(prefs.prefs.model)}</span>
|
|
121
|
+
<ChevronDownIcon className="size-3.5 shrink-0 opacity-60" />
|
|
122
|
+
</Button>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return (
|
|
127
|
+
<div data-deploy-model-picker>
|
|
128
|
+
<ModelSelector
|
|
129
|
+
models={models}
|
|
130
|
+
defaultValue={DEFAULT_MODEL_ID}
|
|
131
|
+
variant="ghost"
|
|
132
|
+
size="sm"
|
|
133
|
+
className="h-7 rounded-full"
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The tenant's chat languages, as a chip beside the model chip. It drives the
|
|
141
|
+
* same session language as `/language`, so the two always agree. Renders only
|
|
142
|
+
* when the host lists two or more languages.
|
|
143
|
+
*/
|
|
144
|
+
const LanguageChip: FC = () => {
|
|
145
|
+
const prefs = useEmbedChatPrefsOptional();
|
|
146
|
+
const [open, setOpen] = useState(false);
|
|
147
|
+
const rootRef = useRef<HTMLDivElement>(null);
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
if (!open) return;
|
|
150
|
+
const onDown = (e: PointerEvent) => {
|
|
151
|
+
if (!rootRef.current?.contains(e.target as Node)) setOpen(false);
|
|
152
|
+
};
|
|
153
|
+
const onKey = (e: KeyboardEvent) => {
|
|
154
|
+
if (e.key === "Escape") setOpen(false);
|
|
155
|
+
};
|
|
156
|
+
document.addEventListener("pointerdown", onDown);
|
|
157
|
+
document.addEventListener("keydown", onKey);
|
|
158
|
+
return () => {
|
|
159
|
+
document.removeEventListener("pointerdown", onDown);
|
|
160
|
+
document.removeEventListener("keydown", onKey);
|
|
161
|
+
};
|
|
162
|
+
}, [open]);
|
|
163
|
+
const options = prefs?.languageOptions;
|
|
164
|
+
if (!prefs || !options || options.length < 2) return null;
|
|
165
|
+
const current = prefs.prefs.language;
|
|
166
|
+
const active = options.find((o) => o.code === current);
|
|
167
|
+
return (
|
|
168
|
+
<div ref={rootRef} data-deploy-language-picker className="relative">
|
|
169
|
+
<Button
|
|
170
|
+
type="button"
|
|
171
|
+
variant="ghost"
|
|
172
|
+
size="sm"
|
|
173
|
+
className="aui-language-chip text-muted-foreground hover:text-foreground h-7 gap-1 rounded-full px-2.5 text-xs"
|
|
174
|
+
onClick={() => setOpen((v) => !v)}
|
|
175
|
+
aria-label="Chat language"
|
|
176
|
+
aria-haspopup="listbox"
|
|
177
|
+
aria-expanded={open}
|
|
178
|
+
title={active?.label ?? current}
|
|
179
|
+
>
|
|
180
|
+
<span>{active?.short ?? current.toUpperCase()}</span>
|
|
181
|
+
<ChevronDownIcon className="size-3.5 shrink-0 opacity-60" />
|
|
182
|
+
</Button>
|
|
183
|
+
{open ? (
|
|
184
|
+
<div
|
|
185
|
+
role="listbox"
|
|
186
|
+
aria-label="Chat language"
|
|
187
|
+
className="aui-language-menu bg-popover text-popover-foreground absolute bottom-full left-0 z-50 mb-1 min-w-36 rounded-xl border p-1 shadow-md"
|
|
188
|
+
>
|
|
189
|
+
{options.map((o) => (
|
|
190
|
+
<button
|
|
191
|
+
key={o.code}
|
|
192
|
+
type="button"
|
|
193
|
+
role="option"
|
|
194
|
+
aria-selected={o.code === current}
|
|
195
|
+
className="hover:bg-muted focus-visible:bg-muted focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset flex w-full items-center justify-between gap-3 rounded-lg px-2.5 py-1.5 text-left text-xs outline-none"
|
|
196
|
+
onClick={() => {
|
|
197
|
+
prefs.setLanguage(o.code);
|
|
198
|
+
setOpen(false);
|
|
199
|
+
}}
|
|
200
|
+
>
|
|
201
|
+
<span>{o.label}</span>
|
|
202
|
+
<span className="text-muted-foreground">{o.short}</span>
|
|
203
|
+
</button>
|
|
204
|
+
))}
|
|
205
|
+
</div>
|
|
206
|
+
) : null}
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// Startup exposes a loading placeholder thread; treat it as a new chat so
|
|
212
|
+
// the composer mounts centered. Loads after startup keep the docked layout.
|
|
213
|
+
const isNewChatView = (s: AssistantState) =>
|
|
214
|
+
s.thread.messages.length === 0 &&
|
|
215
|
+
(!s.thread.isLoading || s.threads.isLoading);
|
|
216
|
+
|
|
217
|
+
// A switched thread that is still fetching its history: skeleton, not welcome.
|
|
218
|
+
const isHistoryLoadingView = (s: AssistantState) =>
|
|
219
|
+
s.thread.messages.length === 0 &&
|
|
220
|
+
s.thread.isLoading &&
|
|
221
|
+
!s.thread.isDisabled &&
|
|
222
|
+
!s.threads.isLoading;
|
|
223
|
+
|
|
224
|
+
const ThreadHistorySkeleton: FC = () => (
|
|
225
|
+
<div
|
|
226
|
+
data-slot="aui_thread-history-skeleton"
|
|
227
|
+
role="status"
|
|
228
|
+
className="animate-in fade-in fill-mode-both mx-auto flex w-full max-w-(--thread-max-width) flex-col gap-y-6 [animation-delay:150ms] [animation-duration:200ms]"
|
|
229
|
+
>
|
|
230
|
+
<span className="sr-only">Loading conversation</span>
|
|
231
|
+
<Skeleton className="ml-auto h-9 w-2/5 rounded-xl motion-reduce:animate-none" />
|
|
232
|
+
<div className="flex flex-col gap-y-2">
|
|
233
|
+
<Skeleton className="h-4 w-11/12 motion-reduce:animate-none" />
|
|
234
|
+
<Skeleton className="h-4 w-4/5 motion-reduce:animate-none" />
|
|
235
|
+
<Skeleton className="h-4 w-3/5 motion-reduce:animate-none" />
|
|
236
|
+
</div>
|
|
237
|
+
<Skeleton className="ml-auto h-9 w-1/3 rounded-xl motion-reduce:animate-none" />
|
|
238
|
+
<div className="flex flex-col gap-y-2">
|
|
239
|
+
<Skeleton className="h-4 w-10/12 motion-reduce:animate-none" />
|
|
240
|
+
<Skeleton className="h-4 w-2/3 motion-reduce:animate-none" />
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const Thread: FC = () => {
|
|
246
|
+
const isEmpty = useAuiState(isNewChatView);
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<ThreadPrimitive.Root
|
|
250
|
+
className="aui-root aui-thread-root bg-background @container flex h-full flex-col"
|
|
251
|
+
style={{
|
|
252
|
+
["--thread-max-width" as string]: "44rem",
|
|
253
|
+
// `--card`, not `--color-card`: the bridge alias resolves at :root,
|
|
254
|
+
// so it would keep the page card colour instead of the brand palette
|
|
255
|
+
// the skin injects on its wrapper.
|
|
256
|
+
["--composer-bg" as string]: "var(--card)",
|
|
257
|
+
["--composer-radius" as string]: "var(--radius-thread)",
|
|
258
|
+
["--composer-padding" as string]: "8px",
|
|
259
|
+
}}
|
|
260
|
+
>
|
|
261
|
+
<ThreadPrimitive.Viewport
|
|
262
|
+
turnAnchor="top"
|
|
263
|
+
data-slot="aui_thread-viewport"
|
|
264
|
+
className={cn(
|
|
265
|
+
"relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4",
|
|
266
|
+
isEmpty && "justify-center",
|
|
267
|
+
)}
|
|
268
|
+
>
|
|
269
|
+
<AuiIf condition={isNewChatView}>
|
|
270
|
+
<ThreadWelcome />
|
|
271
|
+
</AuiIf>
|
|
272
|
+
<AuiIf condition={isHistoryLoadingView}>
|
|
273
|
+
<ThreadHistorySkeleton />
|
|
274
|
+
</AuiIf>
|
|
275
|
+
|
|
276
|
+
<div
|
|
277
|
+
data-slot="aui_message-group"
|
|
278
|
+
className="mb-14 flex flex-col gap-y-6 empty:hidden"
|
|
279
|
+
>
|
|
280
|
+
<ThreadPrimitive.Messages>
|
|
281
|
+
{({ message }) => {
|
|
282
|
+
if (message.composer.isEditing) return <EditComposer />;
|
|
283
|
+
if (message.role === "user") return <UserMessage />;
|
|
284
|
+
return <AssistantMessage />;
|
|
285
|
+
}}
|
|
286
|
+
</ThreadPrimitive.Messages>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<ThreadPrimitive.ViewportFooter
|
|
290
|
+
className={cn(
|
|
291
|
+
"aui-thread-viewport-footer bg-background mx-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible pb-2 md:pb-3",
|
|
292
|
+
!isEmpty &&
|
|
293
|
+
"sticky bottom-0 mt-auto rounded-t-(--composer-radius)",
|
|
294
|
+
)}
|
|
295
|
+
>
|
|
296
|
+
<ThreadScrollToBottom />
|
|
297
|
+
<Composer />
|
|
298
|
+
<AuiIf condition={(s) => !s.thread.isEmpty}>
|
|
299
|
+
<SkinCredit />
|
|
300
|
+
</AuiIf>
|
|
301
|
+
|
|
302
|
+
<AuiIf condition={isNewChatView}>
|
|
303
|
+
<div className="aui-thread-welcome-suggestions-shell min-h-19">
|
|
304
|
+
<AuiIf condition={(s) => s.composer.isEmpty}>
|
|
305
|
+
<ThreadSuggestions />
|
|
306
|
+
</AuiIf>
|
|
307
|
+
</div>
|
|
308
|
+
</AuiIf>
|
|
309
|
+
</ThreadPrimitive.ViewportFooter>
|
|
310
|
+
<AuiIf condition={isNewChatView}>
|
|
311
|
+
<div className="pointer-events-none absolute inset-x-0 bottom-0 px-4 pb-2">
|
|
312
|
+
<SkinCredit />
|
|
313
|
+
</div>
|
|
314
|
+
</AuiIf>
|
|
315
|
+
</ThreadPrimitive.Viewport>
|
|
316
|
+
|
|
317
|
+
<SelectionToolbar />
|
|
318
|
+
</ThreadPrimitive.Root>
|
|
319
|
+
);
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const ThreadScrollToBottom: FC = () => {
|
|
323
|
+
return (
|
|
324
|
+
<ThreadPrimitive.ScrollToBottom asChild>
|
|
325
|
+
<TooltipIconButton
|
|
326
|
+
tooltip="Scroll to bottom"
|
|
327
|
+
variant="outline"
|
|
328
|
+
className="aui-thread-scroll-to-bottom dark:border-border dark:bg-background dark:hover:bg-muted absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible"
|
|
329
|
+
>
|
|
330
|
+
<ArrowDownIcon />
|
|
331
|
+
</TooltipIconButton>
|
|
332
|
+
</ThreadPrimitive.ScrollToBottom>
|
|
333
|
+
);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const ThreadWelcome: FC = () => {
|
|
337
|
+
const chrome = useSkinChrome();
|
|
338
|
+
const { welcome } = useComposerCopy(
|
|
339
|
+
"How can I help you today?",
|
|
340
|
+
"Send a message... (@ to mention, / for commands)",
|
|
341
|
+
);
|
|
342
|
+
const headline = chrome.welcome?.trim() || welcome;
|
|
343
|
+
return (
|
|
344
|
+
<div className="aui-thread-welcome-root mx-auto mb-6 flex w-full max-w-(--thread-max-width) flex-col items-center px-4 text-center">
|
|
345
|
+
<p className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-2xl font-medium tracking-tight duration-200">
|
|
346
|
+
{headline}
|
|
347
|
+
</p>
|
|
348
|
+
</div>
|
|
349
|
+
);
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
type SuggestionGroup = {
|
|
353
|
+
label: string;
|
|
354
|
+
icon: ReactNode;
|
|
355
|
+
options: { label: string; prompt: string }[];
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const SUGGESTION_GROUPS: SuggestionGroup[] = [
|
|
359
|
+
{
|
|
360
|
+
label: "Weather",
|
|
361
|
+
icon: <CloudSunIcon />,
|
|
362
|
+
options: [
|
|
363
|
+
{
|
|
364
|
+
label: "in San Francisco",
|
|
365
|
+
prompt: "What's the weather in San Francisco?",
|
|
366
|
+
},
|
|
367
|
+
{ label: "in Singapore", prompt: "What's the weather in Singapore?" },
|
|
368
|
+
{ label: "in Tokyo", prompt: "What's the weather in Tokyo?" },
|
|
369
|
+
{ label: "in London", prompt: "What's the weather in London?" },
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
label: "Code",
|
|
374
|
+
icon: <CodeXmlIcon />,
|
|
375
|
+
options: [
|
|
376
|
+
{
|
|
377
|
+
label: "explain React hooks",
|
|
378
|
+
prompt: "Explain React hooks like useState and useEffect",
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
label: "write a debounce function",
|
|
382
|
+
prompt: "Write a debounce function in TypeScript",
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
label: "review a useEffect cleanup",
|
|
386
|
+
prompt: "Show me the right way to clean up a subscription in useEffect",
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
label: "Write",
|
|
392
|
+
icon: <PencilLineIcon />,
|
|
393
|
+
options: [
|
|
394
|
+
{
|
|
395
|
+
label: "a birthday card message",
|
|
396
|
+
prompt:
|
|
397
|
+
"Help me write a birthday card message for a friend in the notepad",
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
label: "a product announcement",
|
|
401
|
+
prompt: "Draft a short product announcement for a new dark mode",
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
label: "release notes",
|
|
405
|
+
prompt:
|
|
406
|
+
"Write release notes for a bugfix release of a React component library",
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
label: "a PR description",
|
|
410
|
+
prompt:
|
|
411
|
+
"Write a pull request description for a change that adds keyboard shortcuts",
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
label: "Analyze",
|
|
417
|
+
icon: <ChartColumnIcon />,
|
|
418
|
+
options: [
|
|
419
|
+
{
|
|
420
|
+
label: "React vs Vue vs Svelte",
|
|
421
|
+
prompt: "Compare React, Vue, and Svelte in a table",
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
label: "GDP of US, China, Japan",
|
|
425
|
+
prompt:
|
|
426
|
+
"Compare the GDP of the United States, China, and Japan in a table",
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
label: "pros and cons of SSR",
|
|
430
|
+
prompt: "What are the pros and cons of server-side rendering?",
|
|
431
|
+
},
|
|
432
|
+
],
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
label: "Brainstorm",
|
|
436
|
+
icon: <LightbulbIcon />,
|
|
437
|
+
options: [
|
|
438
|
+
{
|
|
439
|
+
label: "side project ideas",
|
|
440
|
+
prompt: "Brainstorm five side project ideas for a React developer",
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
label: "names for a dev tool",
|
|
444
|
+
prompt: "Brainstorm names for a developer tools startup",
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
label: "talk topics",
|
|
448
|
+
prompt: "Brainstorm talk topics for a React meetup",
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
},
|
|
452
|
+
];
|
|
453
|
+
|
|
454
|
+
const suggestionChipClass =
|
|
455
|
+
"aui-thread-welcome-suggestion fade-in animate-in fill-mode-both duration-(--dur) text-foreground hover:bg-muted border-border/60 h-auto gap-1.5 rounded-full border px-3.5 py-1.5 text-sm font-normal whitespace-nowrap transition-colors [&_svg]:size-4";
|
|
456
|
+
|
|
457
|
+
const ThreadSuggestions: FC = () => {
|
|
458
|
+
const aui = useAui();
|
|
459
|
+
const { suggestions } = useComposerCopy(
|
|
460
|
+
"How can I help you today?",
|
|
461
|
+
"Send a message...",
|
|
462
|
+
);
|
|
463
|
+
// Keyed by the cycle's group offset so a new group remounts and re-runs the
|
|
464
|
+
// chips' entrance fade; hover/focus handlers hold the cycle while it is read.
|
|
465
|
+
const { groupKey, handlers } = useSuggestionGroup();
|
|
466
|
+
const [expandedLabel, setExpandedLabel] = useState<string | null>(null);
|
|
467
|
+
const expandedGroup = SUGGESTION_GROUPS.find(
|
|
468
|
+
(group) => group.label === expandedLabel,
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
const sendPrompt = (prompt: string) => {
|
|
472
|
+
if (aui.thread.getState().isRunning) return;
|
|
473
|
+
aui.thread.append({
|
|
474
|
+
content: [{ type: "text", text: prompt }],
|
|
475
|
+
runConfig: aui.composer.getState().runConfig,
|
|
476
|
+
});
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
if (suggestions.length > 0) {
|
|
480
|
+
return (
|
|
481
|
+
<div
|
|
482
|
+
key={groupKey}
|
|
483
|
+
className="aui-thread-welcome-suggestions flex w-full flex-col gap-2 px-4"
|
|
484
|
+
{...handlers}
|
|
485
|
+
>
|
|
486
|
+
<SuggestionScrollRow className="w-full">
|
|
487
|
+
<div className="mx-auto flex w-max items-center gap-2">
|
|
488
|
+
{suggestions.map((prompt) => (
|
|
489
|
+
<Button
|
|
490
|
+
key={prompt}
|
|
491
|
+
variant="ghost"
|
|
492
|
+
className={suggestionChipClass}
|
|
493
|
+
onClick={() => sendPrompt(prompt)}
|
|
494
|
+
>
|
|
495
|
+
{prompt}
|
|
496
|
+
</Button>
|
|
497
|
+
))}
|
|
498
|
+
</div>
|
|
499
|
+
</SuggestionScrollRow>
|
|
500
|
+
</div>
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
return (
|
|
505
|
+
<div
|
|
506
|
+
key={groupKey}
|
|
507
|
+
className="aui-thread-welcome-suggestions flex w-full flex-col gap-2 px-4"
|
|
508
|
+
{...handlers}
|
|
509
|
+
>
|
|
510
|
+
<SuggestionScrollRow className="w-full">
|
|
511
|
+
<div className="mx-auto flex w-max items-center gap-2">
|
|
512
|
+
{SUGGESTION_GROUPS.map((group) => (
|
|
513
|
+
<Button
|
|
514
|
+
key={group.label}
|
|
515
|
+
variant="ghost"
|
|
516
|
+
className={cn(
|
|
517
|
+
suggestionChipClass,
|
|
518
|
+
group.label === expandedLabel && "bg-muted",
|
|
519
|
+
)}
|
|
520
|
+
onClick={() =>
|
|
521
|
+
setExpandedLabel(
|
|
522
|
+
group.label === expandedLabel ? null : group.label,
|
|
523
|
+
)
|
|
524
|
+
}
|
|
525
|
+
>
|
|
526
|
+
{group.icon}
|
|
527
|
+
{group.label}
|
|
528
|
+
</Button>
|
|
529
|
+
))}
|
|
530
|
+
</div>
|
|
531
|
+
</SuggestionScrollRow>
|
|
532
|
+
{expandedGroup && (
|
|
533
|
+
<SuggestionScrollRow
|
|
534
|
+
key={expandedGroup.label}
|
|
535
|
+
className="fade-in slide-in-from-top-1 animate-in w-full duration-200"
|
|
536
|
+
>
|
|
537
|
+
<div className="mx-auto flex w-max items-center gap-2">
|
|
538
|
+
{expandedGroup.options.map((option) => (
|
|
539
|
+
<Button
|
|
540
|
+
key={option.label}
|
|
541
|
+
variant="ghost"
|
|
542
|
+
className={suggestionChipClass}
|
|
543
|
+
onClick={() => sendPrompt(option.prompt)}
|
|
544
|
+
>
|
|
545
|
+
{option.label}
|
|
546
|
+
</Button>
|
|
547
|
+
))}
|
|
548
|
+
</div>
|
|
549
|
+
</SuggestionScrollRow>
|
|
550
|
+
)}
|
|
551
|
+
</div>
|
|
552
|
+
);
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
const slashCommands: readonly Unstable_SlashCommand[] = [
|
|
556
|
+
{
|
|
557
|
+
id: "summarize",
|
|
558
|
+
description: "Summarize the conversation",
|
|
559
|
+
icon: "FileText",
|
|
560
|
+
// Example only — no-op.
|
|
561
|
+
execute: () => undefined,
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
id: "translate",
|
|
565
|
+
description: "Translate text to another language",
|
|
566
|
+
icon: "Languages",
|
|
567
|
+
// Example only — no-op.
|
|
568
|
+
execute: () => undefined,
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
id: "search",
|
|
572
|
+
description: "Search the web for information",
|
|
573
|
+
icon: "Globe",
|
|
574
|
+
// Example only — no-op.
|
|
575
|
+
execute: () => undefined,
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
id: "help",
|
|
579
|
+
description: "List available commands",
|
|
580
|
+
icon: "HelpCircle",
|
|
581
|
+
// Example only — no-op.
|
|
582
|
+
execute: () => undefined,
|
|
583
|
+
},
|
|
584
|
+
];
|
|
585
|
+
|
|
586
|
+
const slashIconMap: Record<string, FC<{ className?: string }>> = {
|
|
587
|
+
FileText: FileTextIcon,
|
|
588
|
+
Languages: LanguagesIcon,
|
|
589
|
+
Globe: GlobeIcon,
|
|
590
|
+
HelpCircle: HelpCircleIcon,
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
function DirectiveChip(props: DirectiveChipProps) {
|
|
594
|
+
const { directiveId, directiveType, label } = props;
|
|
595
|
+
const showWrench = directiveType !== "command";
|
|
596
|
+
return (
|
|
597
|
+
<span
|
|
598
|
+
className="aui-directive-chip"
|
|
599
|
+
data-directive-type={directiveType}
|
|
600
|
+
data-directive-id={directiveId}
|
|
601
|
+
>
|
|
602
|
+
{showWrench && (
|
|
603
|
+
<span className="aui-directive-chip-icon">
|
|
604
|
+
<WrenchIcon className="size-3" />
|
|
605
|
+
</span>
|
|
606
|
+
)}
|
|
607
|
+
<span className="aui-directive-chip-label">{label}</span>
|
|
608
|
+
</span>
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
const Composer: FC = () => {
|
|
613
|
+
const mention = unstable_useMentionAdapter({ fallbackIcon: WrenchIcon });
|
|
614
|
+
const slash = unstable_useSlashCommandAdapter({
|
|
615
|
+
commands: slashCommands,
|
|
616
|
+
iconMap: slashIconMap,
|
|
617
|
+
fallbackIcon: SlashIcon,
|
|
618
|
+
});
|
|
619
|
+
// Host-wired product palette (SkinPaletteBridge): it owns the trigger root
|
|
620
|
+
// and the `/` and `@` menus, so the demo commands step aside. A nested root
|
|
621
|
+
// here would shadow it.
|
|
622
|
+
const productPalette = useSkinPaletteOptional();
|
|
623
|
+
const { placeholder } = useComposerCopy(
|
|
624
|
+
"How can I help you today?",
|
|
625
|
+
"Send a message... (@ to mention, / for commands)",
|
|
626
|
+
);
|
|
627
|
+
|
|
628
|
+
return (
|
|
629
|
+
<DemoTriggerRoot enabled={!productPalette}>
|
|
630
|
+
<ComposerPrimitive.Root className="aui-composer-root relative flex w-full flex-col">
|
|
631
|
+
<ComposerPrimitive.AttachmentDropzone asChild>
|
|
632
|
+
<div
|
|
633
|
+
data-slot="aui_composer-shell"
|
|
634
|
+
className="border-border/60 data-[dragging=true]:border-ring focus-within:border-border dark:border-muted-foreground/15 dark:focus-within:border-muted-foreground/30 flex w-full cursor-text flex-col gap-2 rounded-(--composer-radius) border bg-(--composer-bg) p-(--composer-padding) transition-[border-color] data-[dragging=true]:border-dashed data-[dragging=true]:bg-[color-mix(in_oklab,var(--color-accent)_50%,var(--color-background))]"
|
|
635
|
+
>
|
|
636
|
+
<ComposerQuotePreview />
|
|
637
|
+
<ComposerAttachments />
|
|
638
|
+
<LexicalComposerInput
|
|
639
|
+
directiveChip={DirectiveChip}
|
|
640
|
+
placeholder={placeholder}
|
|
641
|
+
className="aui-composer-input [&_.aui-lexical-placeholder]:text-muted-foreground/60 relative max-h-48 min-h-10 w-full resize-none bg-transparent px-2.5 py-1 text-base leading-6 outline-none [&_.aui-directive-chip]:inline-flex [&_.aui-directive-chip]:items-baseline [&_.aui-directive-chip]:gap-1 [&_.aui-directive-chip]:rounded-md [&_.aui-directive-chip]:bg-blue-100 [&_.aui-directive-chip]:px-1.5 [&_.aui-directive-chip]:py-0.5 [&_.aui-directive-chip]:text-[13px] [&_.aui-directive-chip]:leading-none [&_.aui-directive-chip]:font-medium [&_.aui-directive-chip]:text-blue-700 dark:[&_.aui-directive-chip]:bg-blue-900/50 dark:[&_.aui-directive-chip]:text-blue-300 [&_.aui-directive-chip-icon]:self-center [&_.aui-lexical-input]:min-h-lh [&_.aui-lexical-input]:outline-none [&_.aui-lexical-placeholder]:pointer-events-none [&_.aui-lexical-placeholder]:absolute [&_.aui-lexical-placeholder]:top-0 [&_.aui-lexical-placeholder]:right-0 [&_.aui-lexical-placeholder]:left-0 [&_.aui-lexical-placeholder]:truncate [&_.aui-lexical-placeholder]:px-2.5 [&_.aui-lexical-placeholder]:py-1"
|
|
642
|
+
/>
|
|
643
|
+
<ComposerAction />
|
|
644
|
+
</div>
|
|
645
|
+
</ComposerPrimitive.AttachmentDropzone>
|
|
646
|
+
|
|
647
|
+
{productPalette ? null : (
|
|
648
|
+
<ComposerTriggerPopover char="@" {...mention} />
|
|
649
|
+
)}
|
|
650
|
+
|
|
651
|
+
{productPalette ? null : (
|
|
652
|
+
<ComposerTriggerPopover
|
|
653
|
+
char="/"
|
|
654
|
+
{...slash}
|
|
655
|
+
emptyItemsLabel="No matching commands"
|
|
656
|
+
/>
|
|
657
|
+
)}
|
|
658
|
+
</ComposerPrimitive.Root>
|
|
659
|
+
</DemoTriggerRoot>
|
|
660
|
+
);
|
|
661
|
+
};
|
|
662
|
+
|
|
663
|
+
/** The demo palette's own trigger root; skipped under the product palette. */
|
|
664
|
+
const DemoTriggerRoot: FC<{ enabled: boolean; children: ReactNode }> = ({
|
|
665
|
+
enabled,
|
|
666
|
+
children,
|
|
667
|
+
}) =>
|
|
668
|
+
enabled ? (
|
|
669
|
+
<ComposerPrimitive.Unstable_TriggerPopoverRoot>
|
|
670
|
+
{children}
|
|
671
|
+
</ComposerPrimitive.Unstable_TriggerPopoverRoot>
|
|
672
|
+
) : (
|
|
673
|
+
<>{children}</>
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
const ComposerAction: FC = () => {
|
|
678
|
+
return (
|
|
679
|
+
<div className="aui-composer-action-wrapper relative flex items-center justify-between">
|
|
680
|
+
<div className="flex items-center gap-1">
|
|
681
|
+
<ComposerAddAttachment />
|
|
682
|
+
<ModelPicker />
|
|
683
|
+
<LanguageChip />
|
|
684
|
+
</div>
|
|
685
|
+
<div className="flex items-center gap-1.5">
|
|
686
|
+
<AuiIf condition={(s) => s.thread.capabilities.dictation}>
|
|
687
|
+
<AuiIf condition={(s) => s.composer.dictation == null}>
|
|
688
|
+
<ComposerPrimitive.Dictate asChild>
|
|
689
|
+
<TooltipIconButton
|
|
690
|
+
tooltip="Voice input"
|
|
691
|
+
side="bottom"
|
|
692
|
+
type="button"
|
|
693
|
+
variant="ghost"
|
|
694
|
+
size="icon"
|
|
695
|
+
className="aui-composer-dictate text-muted-foreground hover:text-foreground size-7 rounded-full"
|
|
696
|
+
aria-label="Start voice input"
|
|
697
|
+
>
|
|
698
|
+
<MicIcon className="aui-composer-dictate-icon size-4" />
|
|
699
|
+
</TooltipIconButton>
|
|
700
|
+
</ComposerPrimitive.Dictate>
|
|
701
|
+
</AuiIf>
|
|
702
|
+
<AuiIf condition={(s) => s.composer.dictation != null}>
|
|
703
|
+
<ComposerPrimitive.StopDictation asChild>
|
|
704
|
+
<TooltipIconButton
|
|
705
|
+
tooltip="Stop dictation"
|
|
706
|
+
side="bottom"
|
|
707
|
+
type="button"
|
|
708
|
+
variant="ghost"
|
|
709
|
+
size="icon"
|
|
710
|
+
className="aui-composer-stop-dictation text-destructive size-7 rounded-full"
|
|
711
|
+
aria-label="Stop voice input"
|
|
712
|
+
>
|
|
713
|
+
<SquareIcon className="aui-composer-stop-dictation-icon size-3.5 animate-pulse fill-current" />
|
|
714
|
+
</TooltipIconButton>
|
|
715
|
+
</ComposerPrimitive.StopDictation>
|
|
716
|
+
</AuiIf>
|
|
717
|
+
</AuiIf>
|
|
718
|
+
<AuiIf condition={(s) => !s.thread.isRunning}>
|
|
719
|
+
<ComposerPrimitive.Send asChild>
|
|
720
|
+
<TooltipIconButton
|
|
721
|
+
tooltip="Send message"
|
|
722
|
+
side="bottom"
|
|
723
|
+
type="button"
|
|
724
|
+
variant="default"
|
|
725
|
+
size="icon"
|
|
726
|
+
className="aui-composer-send size-7 rounded-full"
|
|
727
|
+
aria-label="Send message"
|
|
728
|
+
>
|
|
729
|
+
<ArrowUpIcon className="aui-composer-send-icon size-4" />
|
|
730
|
+
</TooltipIconButton>
|
|
731
|
+
</ComposerPrimitive.Send>
|
|
732
|
+
</AuiIf>
|
|
733
|
+
<AuiIf condition={(s) => s.thread.isRunning}>
|
|
734
|
+
<ComposerPrimitive.Cancel asChild>
|
|
735
|
+
<Button
|
|
736
|
+
type="button"
|
|
737
|
+
variant="default"
|
|
738
|
+
size="icon"
|
|
739
|
+
className="aui-composer-cancel size-7 rounded-full"
|
|
740
|
+
aria-label="Stop generating"
|
|
741
|
+
>
|
|
742
|
+
<SquareIcon className="aui-composer-cancel-icon size-3.5 fill-current" />
|
|
743
|
+
</Button>
|
|
744
|
+
</ComposerPrimitive.Cancel>
|
|
745
|
+
</AuiIf>
|
|
746
|
+
</div>
|
|
747
|
+
</div>
|
|
748
|
+
);
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* assistant-ui's own working indicator (base thread.aui.tsx, `indicator`
|
|
753
|
+
* part), verbatim. The only addition: a status line the server sent (a boot
|
|
754
|
+
* retry, a rate-limit wait, waking services) shows beside it as plain text.
|
|
755
|
+
*/
|
|
756
|
+
const AssistantWorkingIndicator: FC = () => {
|
|
757
|
+
const statusText = useAuiState((s) => connectionStatusText(s.message.parts));
|
|
758
|
+
const wakePhase = useDigichatWarmupPhase();
|
|
759
|
+
const line = statusText ?? (wakePhase === "waking" ? "Waking up services…" : null);
|
|
760
|
+
return (
|
|
761
|
+
<>
|
|
762
|
+
<span
|
|
763
|
+
data-slot="aui_assistant-message-indicator"
|
|
764
|
+
className="animate-pulse font-sans"
|
|
765
|
+
aria-label="Assistant is working"
|
|
766
|
+
>
|
|
767
|
+
{"●"}
|
|
768
|
+
</span>
|
|
769
|
+
{line ? (
|
|
770
|
+
<span
|
|
771
|
+
data-slot="aui_assistant-message-status"
|
|
772
|
+
role="status"
|
|
773
|
+
className="text-muted-foreground ms-2 text-sm"
|
|
774
|
+
>
|
|
775
|
+
{line}
|
|
776
|
+
</span>
|
|
777
|
+
) : null}
|
|
778
|
+
</>
|
|
779
|
+
);
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* assistant-ui's own MessageError (base thread.aui.tsx), verbatim markup. The
|
|
784
|
+
* message text goes through the host's error formatter when it has one, so a
|
|
785
|
+
* raw API payload never reaches the visitor.
|
|
786
|
+
*/
|
|
787
|
+
const MessageError: FC = () => {
|
|
788
|
+
const runtime = useSkinRuntime();
|
|
789
|
+
const raw = useAuiState((s) => {
|
|
790
|
+
const status = s.message.status as { type?: string; reason?: string; error?: unknown } | undefined;
|
|
791
|
+
if (status?.type !== "incomplete" || status.reason !== "error") return undefined;
|
|
792
|
+
const error = status.error;
|
|
793
|
+
if (typeof error === "string") return error;
|
|
794
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
795
|
+
const message = (error as { message: unknown }).message;
|
|
796
|
+
if (typeof message === "string") return message;
|
|
797
|
+
}
|
|
798
|
+
return error != null ? String(error) : undefined;
|
|
799
|
+
});
|
|
800
|
+
const err = raw ? new Error(raw) : undefined;
|
|
801
|
+
const friendly =
|
|
802
|
+
runtime.errorParsers?.formatError?.(err) ?? runtime.errorParsers?.parseError?.(err)?.message ?? undefined;
|
|
803
|
+
return (
|
|
804
|
+
<MessagePrimitive.Error>
|
|
805
|
+
<ErrorPrimitive.Root className="aui-message-error-root border-destructive bg-destructive/10 text-destructive dark:bg-destructive/5 mt-2 rounded-md border p-3 text-sm dark:text-red-200">
|
|
806
|
+
<ErrorPrimitive.Message className="aui-message-error-message line-clamp-2">
|
|
807
|
+
{friendly ?? undefined}
|
|
808
|
+
</ErrorPrimitive.Message>
|
|
809
|
+
</ErrorPrimitive.Root>
|
|
810
|
+
</MessagePrimitive.Error>
|
|
811
|
+
);
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* A backend notice (data-notice, or a data-status with a message). Stock
|
|
816
|
+
* assistant-ui renders only `dataRendererUI` for data parts, so these use the
|
|
817
|
+
* MessageError box above for errors and plain muted text for status lines.
|
|
818
|
+
*/
|
|
819
|
+
const DataNotice: FC<{ part: { readonly type: string; readonly name?: string; readonly data?: unknown } }> = ({
|
|
820
|
+
part,
|
|
821
|
+
}) => {
|
|
822
|
+
const notice = backendNoticeOf(part);
|
|
823
|
+
if (!notice) return null;
|
|
824
|
+
if (notice.tone === "status") {
|
|
825
|
+
return (
|
|
826
|
+
<p data-slot="chat-notice" data-tone="status" role="status" className="text-muted-foreground my-1 text-sm">
|
|
827
|
+
{notice.message}
|
|
828
|
+
</p>
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
return (
|
|
832
|
+
<div
|
|
833
|
+
data-slot="chat-notice"
|
|
834
|
+
data-tone="error"
|
|
835
|
+
role="alert"
|
|
836
|
+
className="aui-message-error-root border-destructive bg-destructive/10 text-destructive dark:bg-destructive/5 my-1 rounded-md border p-3 text-sm dark:text-red-200"
|
|
837
|
+
>
|
|
838
|
+
{notice.message}
|
|
839
|
+
</div>
|
|
840
|
+
);
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
const AssistantMessage: FC = () => {
|
|
844
|
+
const messageParts = useAuiState((s) => s.message.parts);
|
|
845
|
+
const hasContent = messageHasContent(messageParts);
|
|
846
|
+
// reserves space for action bar and compensates with `-mb` for consistent msg spacing
|
|
847
|
+
// keeps hovered action bar from shifting layout (autohide doesn't support absolute positioning well)
|
|
848
|
+
// for pt-[n] use -mb-[n + 6] & min-h-[n + 6] to preserve compensation
|
|
849
|
+
const ACTION_BAR_PT = "pt-1.5";
|
|
850
|
+
const ACTION_BAR_HEIGHT = `-mb-7.5 min-h-7.5 ${ACTION_BAR_PT}`;
|
|
851
|
+
|
|
852
|
+
return (
|
|
853
|
+
<MessagePrimitive.Root
|
|
854
|
+
data-slot="aui_assistant-message-root"
|
|
855
|
+
data-role="assistant"
|
|
856
|
+
className="fade-in slide-in-from-bottom-1 animate-in relative mx-auto w-full max-w-(--thread-max-width) duration-150"
|
|
857
|
+
>
|
|
858
|
+
<div
|
|
859
|
+
data-slot="aui_assistant-message-content"
|
|
860
|
+
className="text-foreground px-2 leading-relaxed wrap-break-word"
|
|
861
|
+
>
|
|
862
|
+
{/* The digichat skin's trace grouping and fold rules
|
|
863
|
+
(`trace-grouping`); only the look is the base skin's. */}
|
|
864
|
+
<AssistantTrace
|
|
865
|
+
renderPart={({ part }) => {
|
|
866
|
+
switch (part.type) {
|
|
867
|
+
case "text":
|
|
868
|
+
return <MarkdownText />;
|
|
869
|
+
case "indicator":
|
|
870
|
+
// One loading affordance per turn: once anything real has
|
|
871
|
+
// arrived the work chain takes over.
|
|
872
|
+
return hasContent ? null : <AssistantWorkingIndicator />;
|
|
873
|
+
case "data":
|
|
874
|
+
return part.dataRendererUI ?? <DataNotice part={part} />;
|
|
875
|
+
case "source":
|
|
876
|
+
// Citations are inline links in the answer.
|
|
877
|
+
return null;
|
|
878
|
+
default:
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
}}
|
|
882
|
+
/>
|
|
883
|
+
<MessageError />
|
|
884
|
+
</div>
|
|
885
|
+
|
|
886
|
+
<div
|
|
887
|
+
data-slot="aui_assistant-message-footer"
|
|
888
|
+
className={cn("ml-2 flex items-center", ACTION_BAR_HEIGHT)}
|
|
889
|
+
>
|
|
890
|
+
<BranchPicker />
|
|
891
|
+
<AssistantActionBar />
|
|
892
|
+
</div>
|
|
893
|
+
</MessagePrimitive.Root>
|
|
894
|
+
);
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
const AssistantActionBar: FC = () => {
|
|
898
|
+
return (
|
|
899
|
+
<ActionBarPrimitive.Root
|
|
900
|
+
hideWhenRunning
|
|
901
|
+
autohide="not-last"
|
|
902
|
+
className="aui-assistant-action-bar-root text-muted-foreground animate-in fade-in col-start-3 row-start-2 -ml-1 flex gap-1 duration-200"
|
|
903
|
+
>
|
|
904
|
+
<ActionBarPrimitive.Copy asChild>
|
|
905
|
+
<TooltipIconButton tooltip="Copy">
|
|
906
|
+
<AuiIf condition={(s) => s.message.isCopied}>
|
|
907
|
+
<CheckIcon className="animate-in zoom-in-50 fade-in duration-200 ease-out" />
|
|
908
|
+
</AuiIf>
|
|
909
|
+
<AuiIf condition={(s) => !s.message.isCopied}>
|
|
910
|
+
<CopyIcon className="animate-in zoom-in-75 fade-in duration-150" />
|
|
911
|
+
</AuiIf>
|
|
912
|
+
</TooltipIconButton>
|
|
913
|
+
</ActionBarPrimitive.Copy>
|
|
914
|
+
<ActionBarPrimitive.Reload asChild>
|
|
915
|
+
<TooltipIconButton tooltip="Refresh">
|
|
916
|
+
<RefreshCwIcon />
|
|
917
|
+
</TooltipIconButton>
|
|
918
|
+
</ActionBarPrimitive.Reload>
|
|
919
|
+
<MessageExportMenu
|
|
920
|
+
trigger={
|
|
921
|
+
<TooltipIconButton tooltip="More" className="data-[state=open]:bg-muted">
|
|
922
|
+
<MoreHorizontalIcon />
|
|
923
|
+
</TooltipIconButton>
|
|
924
|
+
}
|
|
925
|
+
icon={<DownloadIcon className="size-4" />}
|
|
926
|
+
contentClassName="aui-action-bar-more-content 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-xl border p-1.5 shadow-md"
|
|
927
|
+
itemClassName="aui-action-bar-more-item hover:bg-muted hover:text-foreground focus:bg-muted focus:text-foreground data-[state=open]:bg-muted data-[state=open]:text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset flex cursor-pointer items-center gap-2 rounded-lg px-2.5 py-1.5 text-sm outline-none select-none"
|
|
928
|
+
/>
|
|
929
|
+
<MessageTiming />
|
|
930
|
+
</ActionBarPrimitive.Root>
|
|
931
|
+
);
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
const UserMessage: FC = () => {
|
|
935
|
+
return (
|
|
936
|
+
<MessagePrimitive.Root
|
|
937
|
+
data-slot="aui_user-message-root"
|
|
938
|
+
data-role="user"
|
|
939
|
+
className="fade-in slide-in-from-bottom-1 animate-in mx-auto grid w-full max-w-(--thread-max-width) auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 duration-150 [&:where(>*)]:col-start-2"
|
|
940
|
+
>
|
|
941
|
+
<UserMessageAttachments />
|
|
942
|
+
|
|
943
|
+
<div className="aui-user-message-content-wrapper relative col-start-2 min-w-0">
|
|
944
|
+
<div className="aui-user-message-content peer bg-muted text-foreground rounded-thread px-4 py-2 wrap-break-word empty:hidden">
|
|
945
|
+
<MessagePrimitive.Quote>
|
|
946
|
+
{(quote) => <QuoteBlock {...quote} />}
|
|
947
|
+
</MessagePrimitive.Quote>
|
|
948
|
+
<MessagePrimitive.Parts components={{ Text: DirectiveText }} />
|
|
949
|
+
</div>
|
|
950
|
+
<div className="aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2 peer-empty:hidden">
|
|
951
|
+
<UserActionBar />
|
|
952
|
+
</div>
|
|
953
|
+
</div>
|
|
954
|
+
|
|
955
|
+
<BranchPicker
|
|
956
|
+
data-slot="aui_user-branch-picker"
|
|
957
|
+
className="col-span-full col-start-1 row-start-3 -mr-1 justify-end"
|
|
958
|
+
/>
|
|
959
|
+
</MessagePrimitive.Root>
|
|
960
|
+
);
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
const UserActionBar: FC = () => {
|
|
964
|
+
return (
|
|
965
|
+
<ActionBarPrimitive.Root
|
|
966
|
+
hideWhenRunning
|
|
967
|
+
autohide="not-last"
|
|
968
|
+
className="aui-user-action-bar-root flex flex-col items-end"
|
|
969
|
+
>
|
|
970
|
+
<ActionBarPrimitive.Edit asChild>
|
|
971
|
+
<TooltipIconButton tooltip="Edit" className="aui-user-action-edit">
|
|
972
|
+
<PencilIcon />
|
|
973
|
+
</TooltipIconButton>
|
|
974
|
+
</ActionBarPrimitive.Edit>
|
|
975
|
+
</ActionBarPrimitive.Root>
|
|
976
|
+
);
|
|
977
|
+
};
|
|
978
|
+
|
|
979
|
+
const EditComposer: FC = () => {
|
|
980
|
+
return (
|
|
981
|
+
<MessagePrimitive.Root
|
|
982
|
+
data-slot="aui_edit-composer-wrapper"
|
|
983
|
+
className="mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2"
|
|
984
|
+
>
|
|
985
|
+
<ComposerPrimitive.Unstable_TriggerPopoverRoot>
|
|
986
|
+
<ComposerPrimitive.Root className="aui-edit-composer-root border-border/60 dark:border-muted-foreground/15 ml-auto flex w-full max-w-[85%] cursor-text flex-col rounded-(--composer-radius) border bg-(--composer-bg)">
|
|
987
|
+
<LexicalComposerInput
|
|
988
|
+
directiveChip={DirectiveChip}
|
|
989
|
+
autoFocus
|
|
990
|
+
className="aui-edit-composer-input text-foreground min-h-14 w-full resize-none bg-transparent px-4 pt-3 pb-1 text-base outline-none [&_.aui-directive-chip]:inline-flex [&_.aui-directive-chip]:items-baseline [&_.aui-directive-chip]:gap-1 [&_.aui-directive-chip]:rounded-md [&_.aui-directive-chip]:bg-blue-100 [&_.aui-directive-chip]:px-1.5 [&_.aui-directive-chip]:py-0.5 [&_.aui-directive-chip]:text-[13px] [&_.aui-directive-chip]:leading-none [&_.aui-directive-chip]:font-medium [&_.aui-directive-chip]:text-blue-700 dark:[&_.aui-directive-chip]:bg-blue-900/50 dark:[&_.aui-directive-chip]:text-blue-300 [&_.aui-directive-chip-icon]:self-center [&_.aui-lexical-input]:min-h-lh [&_.aui-lexical-input]:outline-none"
|
|
991
|
+
/>
|
|
992
|
+
<div className="aui-edit-composer-footer mx-2.5 mb-2.5 flex items-center gap-1.5 self-end">
|
|
993
|
+
<ComposerPrimitive.Cancel asChild>
|
|
994
|
+
<Button
|
|
995
|
+
variant="ghost"
|
|
996
|
+
size="sm"
|
|
997
|
+
className="h-8 rounded-full px-3.5"
|
|
998
|
+
>
|
|
999
|
+
Cancel
|
|
1000
|
+
</Button>
|
|
1001
|
+
</ComposerPrimitive.Cancel>
|
|
1002
|
+
<ComposerPrimitive.Send asChild>
|
|
1003
|
+
<Button size="sm" className="h-8 rounded-full px-3.5">
|
|
1004
|
+
Update
|
|
1005
|
+
</Button>
|
|
1006
|
+
</ComposerPrimitive.Send>
|
|
1007
|
+
</div>
|
|
1008
|
+
</ComposerPrimitive.Root>
|
|
1009
|
+
</ComposerPrimitive.Unstable_TriggerPopoverRoot>
|
|
1010
|
+
</MessagePrimitive.Root>
|
|
1011
|
+
);
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
1015
|
+
className,
|
|
1016
|
+
...rest
|
|
1017
|
+
}) => {
|
|
1018
|
+
return (
|
|
1019
|
+
<BranchPickerPrimitive.Root
|
|
1020
|
+
hideWhenSingleBranch
|
|
1021
|
+
className={cn(
|
|
1022
|
+
"aui-branch-picker-root text-muted-foreground mr-2 -ml-2 inline-flex items-center text-xs",
|
|
1023
|
+
className,
|
|
1024
|
+
)}
|
|
1025
|
+
{...rest}
|
|
1026
|
+
>
|
|
1027
|
+
<BranchPickerPrimitive.Previous asChild>
|
|
1028
|
+
<TooltipIconButton tooltip="Previous">
|
|
1029
|
+
<ChevronLeftIcon />
|
|
1030
|
+
</TooltipIconButton>
|
|
1031
|
+
</BranchPickerPrimitive.Previous>
|
|
1032
|
+
<span className="aui-branch-picker-state font-medium">
|
|
1033
|
+
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
1034
|
+
</span>
|
|
1035
|
+
<BranchPickerPrimitive.Next asChild>
|
|
1036
|
+
<TooltipIconButton tooltip="Next">
|
|
1037
|
+
<ChevronRightIcon />
|
|
1038
|
+
</TooltipIconButton>
|
|
1039
|
+
</BranchPickerPrimitive.Next>
|
|
1040
|
+
</BranchPickerPrimitive.Root>
|
|
1041
|
+
);
|
|
1042
|
+
};
|
|
1043
|
+
|
|
1044
|
+
export function BaseThread() {
|
|
1045
|
+
return <Thread />;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
export const Base: FC = () => {
|
|
1049
|
+
return <Thread />;
|
|
1050
|
+
};
|