@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,178 @@
|
|
|
1
|
+
export type BuiltInDocsToolId = "searchDocs" | "openPage" | "generateCodeSnippet";
|
|
2
|
+
|
|
3
|
+
export type DocsToolId = BuiltInDocsToolId | (string & {});
|
|
4
|
+
|
|
5
|
+
export type DocsToolRenderer = "sourceResults" | "pagePreview" | "codeSnippet" | "generic";
|
|
6
|
+
|
|
7
|
+
export type DemoFlowId = "auth401" | "webhooks" | "codeExample";
|
|
8
|
+
|
|
9
|
+
export type SuggestedPrompt = {
|
|
10
|
+
title: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
prompt?: string;
|
|
13
|
+
flowId?: DemoFlowId;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type DocsToolConfig = {
|
|
17
|
+
id: DocsToolId;
|
|
18
|
+
displayName: string;
|
|
19
|
+
aiDescription: string;
|
|
20
|
+
realImplementationHint: string;
|
|
21
|
+
rendererType: DocsToolRenderer;
|
|
22
|
+
inputSchema?: Record<string, unknown>;
|
|
23
|
+
outputSchema?: Record<string, unknown>;
|
|
24
|
+
mockResponse?: unknown;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type DocsPage = {
|
|
28
|
+
id: string;
|
|
29
|
+
title: string;
|
|
30
|
+
section: string;
|
|
31
|
+
description: string;
|
|
32
|
+
url: string;
|
|
33
|
+
markdown: string;
|
|
34
|
+
keywords: string[];
|
|
35
|
+
relatedPageIds: string[];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type CodeSnippet = {
|
|
39
|
+
topic: string;
|
|
40
|
+
language: "curl" | "typescript" | "python";
|
|
41
|
+
code: string;
|
|
42
|
+
notes: string[];
|
|
43
|
+
docsUrl: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type SearchResult = {
|
|
47
|
+
pageId: string;
|
|
48
|
+
title: string;
|
|
49
|
+
section: string;
|
|
50
|
+
url: string;
|
|
51
|
+
snippet: string;
|
|
52
|
+
score: number;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type SearchDocsOutput = {
|
|
56
|
+
query: string;
|
|
57
|
+
results: SearchResult[];
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type OpenPageOutput = {
|
|
61
|
+
pageId: string;
|
|
62
|
+
title: string;
|
|
63
|
+
section: string;
|
|
64
|
+
url: string;
|
|
65
|
+
description: string;
|
|
66
|
+
relatedPageIds: string[];
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export type GenerateCodeSnippetOutput = CodeSnippet;
|
|
70
|
+
|
|
71
|
+
export type DocsToolInputById = {
|
|
72
|
+
searchDocs: { query: string; limit?: number };
|
|
73
|
+
openPage: { pageId: string };
|
|
74
|
+
generateCodeSnippet: { topic: string; language?: "curl" | "typescript" | "python" };
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export type DocsToolOutputById = {
|
|
78
|
+
searchDocs: SearchDocsOutput;
|
|
79
|
+
openPage: OpenPageOutput;
|
|
80
|
+
generateCodeSnippet: GenerateCodeSnippetOutput;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type SearchDocsDemoFlowStep = {
|
|
84
|
+
id: string;
|
|
85
|
+
assistantText: string;
|
|
86
|
+
toolId: "searchDocs";
|
|
87
|
+
input: DocsToolInputById["searchDocs"];
|
|
88
|
+
output: DocsToolOutputById["searchDocs"];
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export type OpenPageDemoFlowStep = {
|
|
92
|
+
id: string;
|
|
93
|
+
assistantText: string;
|
|
94
|
+
toolId: "openPage";
|
|
95
|
+
input: DocsToolInputById["openPage"];
|
|
96
|
+
output: DocsToolOutputById["openPage"];
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export type GenerateCodeSnippetDemoFlowStep = {
|
|
100
|
+
id: string;
|
|
101
|
+
assistantText: string;
|
|
102
|
+
toolId: "generateCodeSnippet";
|
|
103
|
+
input: DocsToolInputById["generateCodeSnippet"];
|
|
104
|
+
output: DocsToolOutputById["generateCodeSnippet"];
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export type DemoFlowStep =
|
|
108
|
+
| SearchDocsDemoFlowStep
|
|
109
|
+
| OpenPageDemoFlowStep
|
|
110
|
+
| GenerateCodeSnippetDemoFlowStep
|
|
111
|
+
| {
|
|
112
|
+
id: string;
|
|
113
|
+
assistantText: string;
|
|
114
|
+
toolId: DocsToolId;
|
|
115
|
+
input: unknown;
|
|
116
|
+
output: unknown;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export type DemoFlowConfig = {
|
|
120
|
+
triggerPhrases: string[];
|
|
121
|
+
title: string;
|
|
122
|
+
steps: DemoFlowStep[];
|
|
123
|
+
finalResponse: string;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export type DocsAssistantConfig = {
|
|
127
|
+
productName: string;
|
|
128
|
+
docsName: string;
|
|
129
|
+
assistantName: string;
|
|
130
|
+
welcome: {
|
|
131
|
+
headline: string;
|
|
132
|
+
body: string;
|
|
133
|
+
};
|
|
134
|
+
labels: {
|
|
135
|
+
currentPage: string;
|
|
136
|
+
source: string;
|
|
137
|
+
relatedPages: string;
|
|
138
|
+
openPage: string;
|
|
139
|
+
headerSearch: string;
|
|
140
|
+
articleCtaTitle: string;
|
|
141
|
+
articleCtaBody: string;
|
|
142
|
+
articleCtaAction: string;
|
|
143
|
+
composerPlaceholder: string;
|
|
144
|
+
previewWarning: string;
|
|
145
|
+
};
|
|
146
|
+
suggestedPrompts: SuggestedPrompt[];
|
|
147
|
+
tools: DocsToolConfig[];
|
|
148
|
+
demoModeNotice: string;
|
|
149
|
+
demoFlows: Record<DemoFlowId, DemoFlowConfig>;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export type BrandTheme = {
|
|
153
|
+
accent: string;
|
|
154
|
+
surface: string;
|
|
155
|
+
border: string;
|
|
156
|
+
mutedText: string;
|
|
157
|
+
focusRing: string;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export type DocsNavGroup = {
|
|
161
|
+
label: string;
|
|
162
|
+
pageIds: string[];
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export type DocsHostUiSpec = {
|
|
166
|
+
version: 1;
|
|
167
|
+
root: {
|
|
168
|
+
type: "ContentShell";
|
|
169
|
+
props: {
|
|
170
|
+
productName: string;
|
|
171
|
+
docsName: string;
|
|
172
|
+
defaultPageId: string;
|
|
173
|
+
pages: DocsPage[];
|
|
174
|
+
assistantPlacement?: "sidebar" | "modal";
|
|
175
|
+
navGroups?: DocsNavGroup[];
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
const MOBILE_BREAKPOINT = 768;
|
|
4
|
+
|
|
5
|
+
export function useIsMobile() {
|
|
6
|
+
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
|
|
7
|
+
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
10
|
+
const onChange = () => {
|
|
11
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
12
|
+
};
|
|
13
|
+
mql.addEventListener("change", onChange);
|
|
14
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
15
|
+
return () => mql.removeEventListener("change", onChange);
|
|
16
|
+
}, []);
|
|
17
|
+
|
|
18
|
+
return !!isMobile;
|
|
19
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Stock assistant-ui (baseline preview)
|
|
2
|
+
|
|
3
|
+
Copies of the public assistant-ui **base** registry (`https://r.assistant-ui.com/base/…`)
|
|
4
|
+
plus the matching shadcn **base-nova** primitives those files import
|
|
5
|
+
(button, tooltip, collapsible, dialog, avatar, skeleton, textarea).
|
|
6
|
+
|
|
7
|
+
The only edits here are:
|
|
8
|
+
|
|
9
|
+
- import paths rewritten to this folder
|
|
10
|
+
- `dialog.tsx` close icon uses `lucide-react` `XIcon` instead of their
|
|
11
|
+
registry `IconPlaceholder` (that module is not in this app)
|
|
12
|
+
- `tool-fallback.aui.tsx` adds the Gloomberb attribution footer
|
|
13
|
+
(`ToolFallbackAttribution`, reading `readGloomberbAttribution` from
|
|
14
|
+
`@digithings-ai/ui`) under the Result pane — the same line the first-party
|
|
15
|
+
gallery thread renders (#4098). No other styling changes.
|
|
16
|
+
|
|
17
|
+
## Shape: the base skin's radii
|
|
18
|
+
|
|
19
|
+
Inside the stock Thread every corner follows the base skin (assistant-ui's
|
|
20
|
+
base registry, `https://r.assistant-ui.com/base/*.json`, deps
|
|
21
|
+
`@assistant-ui/react@^0.15.32`, and shadcn **base-nova**,
|
|
22
|
+
`https://ui.shadcn.com/r/styles/base-nova/*.json`): `--composer-radius: 1.5rem`
|
|
23
|
+
(composer and user bubble, the base skin's `--radius-thread`), `rounded-full` composer buttons and
|
|
24
|
+
scroll-to-bottom, `rounded-xl` more-menu / dialog / code block, `rounded-lg`
|
|
25
|
+
menu items, reasoning and tool-group, `rounded-md` suggestions, notices and
|
|
26
|
+
tooltips, base-nova button sizes. Never put a zero-radius shell back.
|
|
27
|
+
|
|
28
|
+
Some of these files (button, tooltip, textarea, markdown, notices, tool
|
|
29
|
+
fallback, reasoning, tool group, JSON view) are also used by other skins, which
|
|
30
|
+
keep their own square house radius. They read `useStockShape()` from
|
|
31
|
+
`stock-shape.tsx`; `StockShapeProvider` wraps the stock `Thread`, so only the
|
|
32
|
+
stock skin gets the rounded shapes. Pinned by `thread-defaults.source.test.ts`,
|
|
33
|
+
`stock-more-menu.source.test.ts` and `stock-shape.render.test.tsx`.
|
|
34
|
+
|
|
35
|
+
Host components passed through the Thread's `components` prop (`Welcome`,
|
|
36
|
+
`Footer`, `AssistantMessage`, `ToolFallback`, `ToolGroup`, `ReasoningGroup`)
|
|
37
|
+
render inside `StockShapeProvider` too, so any of these shared files they use
|
|
38
|
+
round the same way. Portals opened outside the provider (and every other
|
|
39
|
+
skin) keep the square default: the context defaults to `false`.
|
|
40
|
+
|
|
41
|
+
## Colour: the raised surface
|
|
42
|
+
|
|
43
|
+
The stock parts paint their raised fill (user bubble, table heads, skeletons,
|
|
44
|
+
dialog, inline code, hovers) with `bg-surface-2` and `bg-surface-2/<n>`.
|
|
45
|
+
`styles/chat-aui.css` defines that utility (`@utility bg-surface-*`) scoped to
|
|
46
|
+
the stock thread (its root carries `data-stock-thread`) and the stock portals
|
|
47
|
+
rendered from it (the dialog carries `data-stock-portal` inside
|
|
48
|
+
`StockShapeProvider`, via `stockPortalProps`). It is never page-wide and has
|
|
49
|
+
no theme colour: anywhere else the class matches no declaration, so host
|
|
50
|
+
chrome around the thread (the docs page's outline Button) and other skins that
|
|
51
|
+
reuse stock parts (markdown, tool cards) keep their own background. The "…"
|
|
52
|
+
menu gets its panel from `styles/chat-stock-menu.css`.
|
|
53
|
+
|
|
54
|
+
## Trace: the base skin's work chain
|
|
55
|
+
|
|
56
|
+
The stock Thread draws reasoning and tool calls with the base skin's trace
|
|
57
|
+
(`../skins/base/elements/assistant-trace.aui.tsx`, shared with the base
|
|
58
|
+
Thread): one collapsible work chain per turn ("Working" / "Worked", folded
|
|
59
|
+
"Used 3 tools"), a collapsible reasoning box and `N tool calls` group inside
|
|
60
|
+
it, and assistant-ui's own collapsible tool card (arguments, result) for each
|
|
61
|
+
call. Grouping and fold rules are `../trace-grouping`; the parts are
|
|
62
|
+
`../skins/base/aui-default` (see its README). Text, files, images and the
|
|
63
|
+
loading indicator stay the stock ones. A host's `ToolFallback`, `ToolGroup`
|
|
64
|
+
or `ReasoningGroup` still replaces the matching piece.
|
|
65
|
+
|
|
66
|
+
What changes for deploys that host the stock Thread (webpage assistant,
|
|
67
|
+
product page assistant, Expo preview, `/baseline`):
|
|
68
|
+
|
|
69
|
+
- Reasoning or tool calls set to "off" in the deploy's work disclosure are now
|
|
70
|
+
hidden in the stock thread too.
|
|
71
|
+
- `locked_open` now pins the work chain open, as in the base skin.
|
|
72
|
+
- The default tool card is now the base skin's (assistant-ui's collapsible
|
|
73
|
+
card), not the stock `ToolFallback`.
|
|
74
|
+
- The shape gating (`useStockShape`) in the stock `reasoning.tsx`,
|
|
75
|
+
`tool-group.aui.tsx` and `tool-fallback.aui.tsx` is no longer reached from
|
|
76
|
+
the stock thread; it still applies wherever another skin mounts those parts.
|
|
77
|
+
|
|
78
|
+
Do not restyle these files for digichat. `/baseline` mounts this Thread with no extra chrome.
|
|
79
|
+
|
|
80
|
+
Full elements catalog (what else exists upstream and how to attach it):
|
|
81
|
+
[`packages/ui/ASSISTANT_UI_ELEMENTS.md`](../../../../../../packages/ui/ASSISTANT_UI_ELEMENTS.md).
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
The assistant-ui registry files are copied from
|
|
86
|
+
[assistant-ui/assistant-ui](https://github.com/assistant-ui/assistant-ui)
|
|
87
|
+
(MIT License, Copyright (c) 2026 AgentbaseAI Inc., as in the LICENSE of
|
|
88
|
+
`@assistant-ui/react@0.15.32`) and the base-nova
|
|
89
|
+
primitives from [shadcn-ui/ui](https://github.com/shadcn-ui/ui) (MIT License,
|
|
90
|
+
Copyright (c) 2023 shadcn); both notices apply to the vendored files here.
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Session artifact surface (DIG-2882, over DIG-2784 / PR #5390).
|
|
5
|
+
*
|
|
6
|
+
* Two client surfaces live here because they answer the same question from
|
|
7
|
+
* opposite ends: `/artifacts` lists what this session produced, and a link the
|
|
8
|
+
* model embedded in a reply opens one of those rows.
|
|
9
|
+
*
|
|
10
|
+
* **Every media-type decision is the server's.** The list route answers with a
|
|
11
|
+
* `viewable` flag it computed from its own inline list; this file never
|
|
12
|
+
* re-derives it, so the browser and the `Content-Disposition` the blob route
|
|
13
|
+
* sends can never disagree about the same row.
|
|
14
|
+
*
|
|
15
|
+
* **Link lifetime is the server's too.** `bindLink` binds a token to a session
|
|
16
|
+
* and the blob route answers `410 session_expired` for a token the session no
|
|
17
|
+
* longer owns. A dead token is therefore a normal outcome here, not an error
|
|
18
|
+
* to dump at the reader - see `ArtifactLink`.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { useCallback, useEffect, useState, type ReactNode } from "react";
|
|
22
|
+
|
|
23
|
+
import { cn } from "../../../lib/utils";
|
|
24
|
+
import { p, stripBasePath } from "../../../lib/base-path";
|
|
25
|
+
import { StateBlock } from "../../desk/StateBlock";
|
|
26
|
+
|
|
27
|
+
/** The list route the server already ships (see `.../artifacts/route.ts`). */
|
|
28
|
+
export type ArtifactRow = {
|
|
29
|
+
id: string;
|
|
30
|
+
/** The token the store minted. Present on the list row, so no minting here. */
|
|
31
|
+
token: string;
|
|
32
|
+
name: string;
|
|
33
|
+
mediaType: string;
|
|
34
|
+
byteSize: number;
|
|
35
|
+
kind: string;
|
|
36
|
+
summary: string | null;
|
|
37
|
+
createdAt: string | number | Date;
|
|
38
|
+
/** Server-computed. Never recomputed client-side. */
|
|
39
|
+
viewable: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* `GET /api/conversations/[id]/artifacts` - the panel's only read.
|
|
44
|
+
*
|
|
45
|
+
* The path carries the base path the app is served under (DIG-5121): the app
|
|
46
|
+
* answers under /chat/api/conversations/… and nowhere else, so a
|
|
47
|
+
* root-absolute path would 404 the moment the app moves.
|
|
48
|
+
*/
|
|
49
|
+
export function artifactListPath(conversationId: string): string {
|
|
50
|
+
return p(`/api/conversations/${encodeURIComponent(conversationId)}/artifacts`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The link target, carrying the token the store minted. */
|
|
54
|
+
export function artifactBlobPath(conversationId: string, token: string): string {
|
|
55
|
+
return `${artifactListPath(conversationId)}/blob?token=${encodeURIComponent(token)}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const BLOB_PATH = /^\/api\/conversations\/[^/]+\/artifacts\/blob$/;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* True when an href is a session artifact link. Pure string work on the path
|
|
62
|
+
* so it runs identically in the browser and in a test - `new URL(href, base)`
|
|
63
|
+
* would make an href without a scheme host-dependent, and a link that is
|
|
64
|
+
* "maybe an artifact" depending on where it was parsed is not a predicate.
|
|
65
|
+
*
|
|
66
|
+
* The base path is stripped first: the app hands out the link already
|
|
67
|
+
* prefixed (/chat/api/conversations/…), and the predicate is about the app's
|
|
68
|
+
* own path, not about where the app happens to be served.
|
|
69
|
+
*/
|
|
70
|
+
export function isArtifactBlobHref(href: string | undefined | null): boolean {
|
|
71
|
+
if (!href) return false;
|
|
72
|
+
const path = href.split(/[?#]/, 1)[0] ?? "";
|
|
73
|
+
return BLOB_PATH.test(stripBasePath(path));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Deterministic, locale-free size label. Never used to decide anything. */
|
|
77
|
+
export function formatArtifactSize(byteSize: number): string {
|
|
78
|
+
if (!Number.isFinite(byteSize) || byteSize < 0) return "-";
|
|
79
|
+
if (byteSize < 1024) return `${Math.trunc(byteSize)} B`;
|
|
80
|
+
const units = ["KB", "MB", "GB"];
|
|
81
|
+
let value = byteSize / 1024;
|
|
82
|
+
let unit = 0;
|
|
83
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
84
|
+
value /= 1024;
|
|
85
|
+
unit += 1;
|
|
86
|
+
}
|
|
87
|
+
const rounded = Math.round(value * 10) / 10;
|
|
88
|
+
return `${rounded} ${units[unit]}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** ISO date if we can get one, else the raw value. Never throws. */
|
|
92
|
+
export function formatArtifactDate(createdAt: string | number | Date): string {
|
|
93
|
+
const d = createdAt instanceof Date ? createdAt : new Date(createdAt);
|
|
94
|
+
return Number.isNaN(d.getTime()) ? "-" : d.toISOString().slice(0, 10);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Injectable seams so tests never need a network or a real `window`. */
|
|
98
|
+
export type ArtifactIo = {
|
|
99
|
+
fetchImpl?: typeof fetch;
|
|
100
|
+
/** Opens the blob in a new tab. Return false if the browser refused. */
|
|
101
|
+
openInNewTab?: (url: string) => boolean;
|
|
102
|
+
/** Same-tab fallback when a new tab was refused or is not wanted. */
|
|
103
|
+
navigate?: (url: string) => void;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
function defaultOpenInNewTab(url: string): boolean {
|
|
107
|
+
const w = window.open(url, "_blank", "noopener,noreferrer");
|
|
108
|
+
return typeof w !== "undefined" && w !== null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function defaultNavigate(url: string): void {
|
|
112
|
+
window.location.assign(url);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function ArtifactsPanel({
|
|
116
|
+
conversationId,
|
|
117
|
+
open,
|
|
118
|
+
onClose,
|
|
119
|
+
fetchImpl,
|
|
120
|
+
openInNewTab = defaultOpenInNewTab,
|
|
121
|
+
navigate = defaultNavigate,
|
|
122
|
+
}: ArtifactIo & {
|
|
123
|
+
conversationId: string | null;
|
|
124
|
+
open: boolean;
|
|
125
|
+
onClose: () => void;
|
|
126
|
+
}) {
|
|
127
|
+
const [rows, setRows] = useState<ArtifactRow[] | null>(null);
|
|
128
|
+
const [state, setState] = useState<"idle" | "loading" | "error">("idle");
|
|
129
|
+
|
|
130
|
+
const load = useCallback(async () => {
|
|
131
|
+
if (!conversationId) {
|
|
132
|
+
setRows([]);
|
|
133
|
+
setState("idle");
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
setState("loading");
|
|
137
|
+
try {
|
|
138
|
+
const doFetch = fetchImpl ?? fetch;
|
|
139
|
+
const res = await doFetch(artifactListPath(conversationId));
|
|
140
|
+
if (!res.ok) {
|
|
141
|
+
setRows(null);
|
|
142
|
+
setState("error");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const body = (await res.json()) as { artifacts?: ArtifactRow[] };
|
|
146
|
+
const artifacts = Array.isArray(body.artifacts) ? body.artifacts : [];
|
|
147
|
+
setRows(artifacts);
|
|
148
|
+
setState("idle");
|
|
149
|
+
} catch {
|
|
150
|
+
setRows(null);
|
|
151
|
+
setState("error");
|
|
152
|
+
}
|
|
153
|
+
}, [conversationId, fetchImpl]);
|
|
154
|
+
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
if (!open) return;
|
|
157
|
+
void load();
|
|
158
|
+
}, [open, load]);
|
|
159
|
+
|
|
160
|
+
if (!open) return null;
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<div
|
|
164
|
+
className="aui-artifacts-panel border-hair bg-surface-2 fixed inset-y-0 end-0 z-50 flex w-full max-w-sm flex-col border-s"
|
|
165
|
+
data-artifacts-panel=""
|
|
166
|
+
role="dialog"
|
|
167
|
+
aria-label="Session artifacts"
|
|
168
|
+
>
|
|
169
|
+
<header className="border-hair flex items-center justify-between border-b px-4 py-3">
|
|
170
|
+
<h2 className="text-sm font-semibold">Files this session produced</h2>
|
|
171
|
+
<button
|
|
172
|
+
type="button"
|
|
173
|
+
onClick={onClose}
|
|
174
|
+
className="text-ink-mute hover:text-ink text-sm"
|
|
175
|
+
>
|
|
176
|
+
Close
|
|
177
|
+
</button>
|
|
178
|
+
</header>
|
|
179
|
+
|
|
180
|
+
{!conversationId ? (
|
|
181
|
+
<StateBlock
|
|
182
|
+
kind="withheld"
|
|
183
|
+
title="No session store."
|
|
184
|
+
reason="This chat was not opened with a conversation, so it cannot list artifacts."
|
|
185
|
+
className="m-4"
|
|
186
|
+
/>
|
|
187
|
+
) : state === "loading" ? (
|
|
188
|
+
<StateBlock
|
|
189
|
+
kind="loading"
|
|
190
|
+
title="Reading session files."
|
|
191
|
+
className="m-4"
|
|
192
|
+
/>
|
|
193
|
+
) : state === "error" ? (
|
|
194
|
+
<StateBlock
|
|
195
|
+
kind="error"
|
|
196
|
+
title="Could not load this session's files."
|
|
197
|
+
reason="The artifact route did not answer."
|
|
198
|
+
onRetry={() => void load()}
|
|
199
|
+
className="m-4"
|
|
200
|
+
/>
|
|
201
|
+
) : !rows || rows.length === 0 ? (
|
|
202
|
+
<StateBlock
|
|
203
|
+
kind="empty"
|
|
204
|
+
title="No files in this session yet."
|
|
205
|
+
reason="They appear here as the assistant produces them."
|
|
206
|
+
className="m-4"
|
|
207
|
+
/>
|
|
208
|
+
) : (
|
|
209
|
+
<ul className="flex-1 overflow-y-auto">
|
|
210
|
+
{rows.map((row) => (
|
|
211
|
+
<li key={row.id} className="border-hair border-b last:border-b-0">
|
|
212
|
+
<button
|
|
213
|
+
type="button"
|
|
214
|
+
className="flex w-full flex-col gap-1 px-4 py-3 text-start hover:bg-accent/50"
|
|
215
|
+
onClick={() => {
|
|
216
|
+
const url = artifactBlobPath(conversationId, row.token);
|
|
217
|
+
// The row decides, via the server's own flag. No media-type
|
|
218
|
+
// list is duplicated here on purpose.
|
|
219
|
+
if (row.viewable) {
|
|
220
|
+
if (!openInNewTab(url)) navigate(url);
|
|
221
|
+
} else {
|
|
222
|
+
navigate(url);
|
|
223
|
+
}
|
|
224
|
+
}}
|
|
225
|
+
>
|
|
226
|
+
<span className="text-sm font-medium">{row.name}</span>
|
|
227
|
+
<span className="text-ink-mute text-xs">
|
|
228
|
+
{row.mediaType} · {formatArtifactSize(row.byteSize)} ·{" "}
|
|
229
|
+
{formatArtifactDate(row.createdAt)}
|
|
230
|
+
</span>
|
|
231
|
+
</button>
|
|
232
|
+
</li>
|
|
233
|
+
))}
|
|
234
|
+
</ul>
|
|
235
|
+
)}
|
|
236
|
+
</div>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* The `a:` override for artifact links in an assistant reply (DoD 3).
|
|
242
|
+
*
|
|
243
|
+
* A session artifact link is clickable and carries the token the store
|
|
244
|
+
* minted. The failure case is the reason this component exists: a dead token
|
|
245
|
+
* answers `410 session_expired`, and following that link normally would show
|
|
246
|
+
* the reader a raw JSON error body. So the click is intercepted, the link is
|
|
247
|
+
* probed, and a dead one becomes a sentence in place instead.
|
|
248
|
+
*
|
|
249
|
+
* Any non-artifact href never reaches here - `markdown-text.tsx` routes on
|
|
250
|
+
* `isArtifactBlobHref` and renders its plain anchor otherwise.
|
|
251
|
+
*/
|
|
252
|
+
export function ArtifactLink({
|
|
253
|
+
href,
|
|
254
|
+
className,
|
|
255
|
+
children,
|
|
256
|
+
fetchImpl,
|
|
257
|
+
openInNewTab = defaultOpenInNewTab,
|
|
258
|
+
navigate = defaultNavigate,
|
|
259
|
+
}: ArtifactIo & {
|
|
260
|
+
href: string;
|
|
261
|
+
className?: string;
|
|
262
|
+
children?: ReactNode;
|
|
263
|
+
}) {
|
|
264
|
+
const [expired, setExpired] = useState(false);
|
|
265
|
+
|
|
266
|
+
const onClick = useCallback(
|
|
267
|
+
async (event: React.MouseEvent<HTMLAnchorElement>) => {
|
|
268
|
+
event.preventDefault();
|
|
269
|
+
setExpired(false);
|
|
270
|
+
try {
|
|
271
|
+
const doFetch = fetchImpl ?? fetch;
|
|
272
|
+
const res = await doFetch(href, { method: "GET" });
|
|
273
|
+
if (res.status === 410) {
|
|
274
|
+
setExpired(true);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
} catch {
|
|
278
|
+
// Could not probe: let the browser go to the link rather than guess.
|
|
279
|
+
}
|
|
280
|
+
if (!openInNewTab(href)) navigate(href);
|
|
281
|
+
},
|
|
282
|
+
[href, fetchImpl, openInNewTab, navigate],
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
return (
|
|
286
|
+
<>
|
|
287
|
+
<a
|
|
288
|
+
className={cn(
|
|
289
|
+
"aui-md-a text-accent hover:text-accent/80 underline underline-offset-2",
|
|
290
|
+
className,
|
|
291
|
+
)}
|
|
292
|
+
href={href}
|
|
293
|
+
onClick={onClick}
|
|
294
|
+
>
|
|
295
|
+
{children}
|
|
296
|
+
</a>
|
|
297
|
+
{expired ? (
|
|
298
|
+
<span className="aui-artifact-expired text-ink-mute ms-1 text-xs">
|
|
299
|
+
This artifact link belongs to a chat session that has ended. Open
|
|
300
|
+
/artifacts in the current chat to list this session's files.
|
|
301
|
+
</span>
|
|
302
|
+
) : null}
|
|
303
|
+
</>
|
|
304
|
+
);
|
|
305
|
+
}
|