@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,766 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// The boot styles (.dboot-overlay included) ship with the loader, not with one
|
|
4
|
+
// skin: a host on any skin mounts this overlay, and without them it renders
|
|
5
|
+
// unpositioned at the top of the page with the wordmark clipped.
|
|
6
|
+
import "../../styles/digichat-boot-loader.css";
|
|
7
|
+
import { useEffect, useMemo, useRef, useState, type CSSProperties } from "react";
|
|
8
|
+
import { DIGICHAT } from "@digithings-ai/hero-banner/definitions";
|
|
9
|
+
import { HeroBanner } from "@digithings-ai/hero-banner/web";
|
|
10
|
+
import { DisclosureChevron } from "./disclosure-chevron";
|
|
11
|
+
import { DotMatrix } from "./DotMatrix";
|
|
12
|
+
import {
|
|
13
|
+
DIGI_CHAT_BOOT_STEP_EVENT,
|
|
14
|
+
DIGI_CHAT_READY_EVENT,
|
|
15
|
+
digichatBootClockMs,
|
|
16
|
+
digichatBootSteps,
|
|
17
|
+
hasDigichatReady,
|
|
18
|
+
signalDigichatReady,
|
|
19
|
+
} from "./boot-signal";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Boot-lab variants: short local loaders used to iterate on the universal
|
|
23
|
+
* boot animation. `?boot=<variant>` selects one at runtime; the server can
|
|
24
|
+
* also thread it so first paint never shows the classic loader (the outline
|
|
25
|
+
* bleed the classic pass caused).
|
|
26
|
+
*
|
|
27
|
+
* The tool-chain family (`toolchain`, `tooltask`, `toolreason`, `toolfull`)
|
|
28
|
+
* is the skin-proof one: simulated tool calls drawn with the chat's own
|
|
29
|
+
* DotMatrix states and row anatomy (`aui-tool-fallback-trigger`,
|
|
30
|
+
* `tool-group-trigger`, `reasoning-trigger`), so whatever skin dresses the
|
|
31
|
+
* chat dresses the boot too. After the simulated commands finish a
|
|
32
|
+
* `connect to digichat` row keeps ticking until the app's real ready signal
|
|
33
|
+
* lands, which keeps 30-60s cold starts honest; `?bootdelay=<seconds>`
|
|
34
|
+
* emulates a slow container locally.
|
|
35
|
+
*
|
|
36
|
+
* `banner` is the standard boot for every digichat deployment: the digichat
|
|
37
|
+
* hero banner's LOADING pass, the same cover the digithings.ai site shell
|
|
38
|
+
* (ChatEmbedShell) has always shown — no copy, no spinner. `classic` opts
|
|
39
|
+
* back into the pre-banner welcome loader (`DigichatBootLoader`).
|
|
40
|
+
*/
|
|
41
|
+
export type BootLabVariant =
|
|
42
|
+
| "banner"
|
|
43
|
+
| "terminal"
|
|
44
|
+
| "waking"
|
|
45
|
+
| "booting"
|
|
46
|
+
| "spinner"
|
|
47
|
+
| "spinneronly"
|
|
48
|
+
| "dots"
|
|
49
|
+
| "bootlog"
|
|
50
|
+
| "scramble"
|
|
51
|
+
| "toolchain"
|
|
52
|
+
| "tooltask"
|
|
53
|
+
| "toolreason"
|
|
54
|
+
| "toolfull";
|
|
55
|
+
|
|
56
|
+
const VARIANTS: readonly BootLabVariant[] = [
|
|
57
|
+
"banner",
|
|
58
|
+
"terminal",
|
|
59
|
+
"waking",
|
|
60
|
+
"booting",
|
|
61
|
+
"spinner",
|
|
62
|
+
"spinneronly",
|
|
63
|
+
"dots",
|
|
64
|
+
"bootlog",
|
|
65
|
+
"scramble",
|
|
66
|
+
"toolchain",
|
|
67
|
+
"tooltask",
|
|
68
|
+
"toolreason",
|
|
69
|
+
"toolfull",
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
/** Copy per variant; null = the variant draws its own rows. */
|
|
73
|
+
const LABELS: Record<BootLabVariant, string | null> = {
|
|
74
|
+
banner: null,
|
|
75
|
+
terminal: "loading",
|
|
76
|
+
waking: "waking up…",
|
|
77
|
+
booting: "booting up…",
|
|
78
|
+
spinner: "loading",
|
|
79
|
+
spinneronly: null,
|
|
80
|
+
dots: "loading",
|
|
81
|
+
bootlog: "digichat --boot",
|
|
82
|
+
scramble: "loading",
|
|
83
|
+
toolchain: null,
|
|
84
|
+
tooltask: null,
|
|
85
|
+
toolreason: null,
|
|
86
|
+
toolfull: null,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/** Variants whose label types itself in (the terminal DNA). */
|
|
90
|
+
const TYPED: ReadonlySet<BootLabVariant> = new Set([
|
|
91
|
+
"terminal",
|
|
92
|
+
"waking",
|
|
93
|
+
"booting",
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
const TYPE_MS = 46;
|
|
97
|
+
const SETTLE_HOLD_MS = 180;
|
|
98
|
+
|
|
99
|
+
/** Facts the deployment actually reports; rows without facts stay detail-less. */
|
|
100
|
+
export type BootFacts = {
|
|
101
|
+
starters?: number;
|
|
102
|
+
model?: string;
|
|
103
|
+
models?: number;
|
|
104
|
+
toolLabels?: readonly string[];
|
|
105
|
+
mcpServers?: number;
|
|
106
|
+
backend?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Sleep-on-idle services the host wakes before revealing the chat. When
|
|
109
|
+
* set, a "wake up services" row waits on the real `services` boot step.
|
|
110
|
+
*/
|
|
111
|
+
services?: readonly string[];
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/** Real milestones the app reports while the container comes up. */
|
|
115
|
+
type BootMilestone =
|
|
116
|
+
| "image"
|
|
117
|
+
| "config"
|
|
118
|
+
| "runtime"
|
|
119
|
+
| "loop"
|
|
120
|
+
| "services"
|
|
121
|
+
| "backend";
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Container/agent commands; one row each, in order. Rows adapt to the facts
|
|
125
|
+
* the deployment actually reports (and only those) - extra rows appear when
|
|
126
|
+
* the deployment carries tools or MCP servers, so different deployments show
|
|
127
|
+
* different steps and numbers. Never invent counts. Each row carries the real
|
|
128
|
+
* milestone that completes it (`ms` is the beat it keeps before that milestone
|
|
129
|
+
* lands, and the cap when no signal ever does).
|
|
130
|
+
*/
|
|
131
|
+
export function toolChainRows(
|
|
132
|
+
facts?: BootFacts,
|
|
133
|
+
): readonly {
|
|
134
|
+
label: string;
|
|
135
|
+
detail?: string;
|
|
136
|
+
milestone: BootMilestone;
|
|
137
|
+
ms: number;
|
|
138
|
+
}[] {
|
|
139
|
+
const rows: {
|
|
140
|
+
label: string;
|
|
141
|
+
detail?: string;
|
|
142
|
+
milestone: BootMilestone;
|
|
143
|
+
ms: number;
|
|
144
|
+
}[] = [
|
|
145
|
+
{ label: "pull digichat image", milestone: "image", ms: 1320 },
|
|
146
|
+
{
|
|
147
|
+
label: "mount deployment configuration",
|
|
148
|
+
milestone: "config",
|
|
149
|
+
ms: 640,
|
|
150
|
+
detail: facts?.starters ? `${facts.starters} starters` : undefined,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
label: "warm up chat runtime",
|
|
154
|
+
milestone: "runtime",
|
|
155
|
+
ms: 880,
|
|
156
|
+
detail: facts?.model
|
|
157
|
+
? facts.model
|
|
158
|
+
: facts?.models
|
|
159
|
+
? `${facts.models} models`
|
|
160
|
+
: undefined,
|
|
161
|
+
},
|
|
162
|
+
];
|
|
163
|
+
if (facts?.toolLabels?.length) {
|
|
164
|
+
rows.push({
|
|
165
|
+
label: "wire in the tools",
|
|
166
|
+
milestone: "loop",
|
|
167
|
+
ms: 760,
|
|
168
|
+
detail: facts.toolLabels.join(", "),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (facts?.mcpServers) {
|
|
172
|
+
rows.push({
|
|
173
|
+
label: "attach mcp servers",
|
|
174
|
+
milestone: "loop",
|
|
175
|
+
ms: 720,
|
|
176
|
+
detail: `${facts.mcpServers} servers`,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
if (facts?.services) {
|
|
180
|
+
rows.push({
|
|
181
|
+
label: "wake up services",
|
|
182
|
+
milestone: "services",
|
|
183
|
+
ms: 0,
|
|
184
|
+
detail: facts.services.length ? facts.services.join(", ") : undefined,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
rows.push({
|
|
188
|
+
label: "wire in the backend",
|
|
189
|
+
milestone: "backend",
|
|
190
|
+
ms: 1402,
|
|
191
|
+
detail: facts?.backend ? `${facts.backend} backend` : undefined,
|
|
192
|
+
});
|
|
193
|
+
return rows;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** The tool-chain family shares the long-load behaviour below. */
|
|
197
|
+
const TOOLCHAIN_VARIANTS: ReadonlySet<BootLabVariant> = new Set([
|
|
198
|
+
"toolchain",
|
|
199
|
+
"tooltask",
|
|
200
|
+
"toolreason",
|
|
201
|
+
"toolfull",
|
|
202
|
+
]);
|
|
203
|
+
|
|
204
|
+
const REASONING_LABEL = "waking up the container";
|
|
205
|
+
/** Readiness cap: embedded surfaces wait for the app handshake; standalone
|
|
206
|
+
* surfaces never send one, so they settle on their own sooner. Embedded
|
|
207
|
+
* surfaces that pass the cap surface a failure + retry instead of settling. */
|
|
208
|
+
const EMBEDDED_CAP_MS = 120_000;
|
|
209
|
+
const STANDALONE_CAP_MS = 3_000;
|
|
210
|
+
/** Same-window failure signal: the app may dispatch it when the boot dies.
|
|
211
|
+
* The embed does not emit it yet; `?bootfail=<seconds>` demos it locally. */
|
|
212
|
+
const BOOT_FAILED_EVENT = "digichat:boot-failed";
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* The standard boot animation for every digichat deployment: the digichat
|
|
216
|
+
* hero banner's LOADING pass.
|
|
217
|
+
*/
|
|
218
|
+
export const DEFAULT_BOOT_LAB_VARIANT: BootLabVariant = "banner";
|
|
219
|
+
|
|
220
|
+
/** `?boot=classic` opts back into the pre-banner welcome loader. */
|
|
221
|
+
const CLASSIC_BOOT = "classic";
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Resolve the lab variant: an explicit value (the `bootLabVariant` prop,
|
|
225
|
+
* threaded from a deployment's `chrome.loading` or the embed's `?boot=`)
|
|
226
|
+
* wins; otherwise fall back to `?boot=` on the URL; otherwise the standard
|
|
227
|
+
* banner. A deployment that names nothing gets the banner, never the old
|
|
228
|
+
* tool-chain lab default. `null` means the classic loader on purpose
|
|
229
|
+
* (`?boot=classic`).
|
|
230
|
+
*/
|
|
231
|
+
export function resolveBootLabVariant(
|
|
232
|
+
explicit?: string | null,
|
|
233
|
+
): BootLabVariant | null {
|
|
234
|
+
const value =
|
|
235
|
+
explicit != null
|
|
236
|
+
? explicit
|
|
237
|
+
: typeof window === "undefined"
|
|
238
|
+
? null
|
|
239
|
+
: new URL(window.location.href).searchParams.get("boot");
|
|
240
|
+
if (value == null) return DEFAULT_BOOT_LAB_VARIANT;
|
|
241
|
+
if (value === CLASSIC_BOOT) return null;
|
|
242
|
+
return (VARIANTS as readonly string[]).includes(value)
|
|
243
|
+
? (value as BootLabVariant)
|
|
244
|
+
: DEFAULT_BOOT_LAB_VARIANT;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** `?bootdelay=<seconds>`: emulate a slow container locally (lab only). */
|
|
248
|
+
function resolveBootDelayMs(): number {
|
|
249
|
+
if (typeof window === "undefined") return 0;
|
|
250
|
+
const raw = new URL(window.location.href).searchParams.get("bootdelay");
|
|
251
|
+
const seconds = raw == null ? 0 : Number(raw);
|
|
252
|
+
return Number.isFinite(seconds) && seconds > 0
|
|
253
|
+
? Math.min(seconds, 300) * 1000
|
|
254
|
+
: 0;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** `?bootfail=<seconds>`: force the boot into its failed state (lab only). */
|
|
258
|
+
function resolveBootFailMs(): number {
|
|
259
|
+
if (typeof window === "undefined") return 0;
|
|
260
|
+
const raw = new URL(window.location.href).searchParams.get("bootfail");
|
|
261
|
+
const seconds = raw == null ? 0 : Number(raw);
|
|
262
|
+
return Number.isFinite(seconds) && seconds > 0
|
|
263
|
+
? Math.min(seconds, 300) * 1000
|
|
264
|
+
: 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function useReducedMotion(): boolean {
|
|
268
|
+
const [reduced, setReduced] = useState(false);
|
|
269
|
+
useEffect(() => {
|
|
270
|
+
const query = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
271
|
+
setReduced(query.matches);
|
|
272
|
+
const onChange = (event: MediaQueryListEvent) => setReduced(event.matches);
|
|
273
|
+
query.addEventListener("change", onChange);
|
|
274
|
+
return () => query.removeEventListener("change", onChange);
|
|
275
|
+
}, []);
|
|
276
|
+
return reduced;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function useSettle(ready: boolean, onSettled: () => void) {
|
|
280
|
+
const settledRef = useRef(false);
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
if (!ready || settledRef.current) return;
|
|
283
|
+
settledRef.current = true;
|
|
284
|
+
const timer = setTimeout(() => {
|
|
285
|
+
signalDigichatReady();
|
|
286
|
+
onSettled();
|
|
287
|
+
}, SETTLE_HOLD_MS);
|
|
288
|
+
return () => clearTimeout(timer);
|
|
289
|
+
}, [ready, onSettled]);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* The app's real ready signal: the embed dispatches it once the runtime is
|
|
294
|
+
* up. Standalone surfaces never send one, so they fall back to a short cap.
|
|
295
|
+
*/
|
|
296
|
+
function useAppReady(enabled: boolean): { ready: boolean; timedOut: boolean } {
|
|
297
|
+
const [ready, setReady] = useState(false);
|
|
298
|
+
const [timedOut, setTimedOut] = useState(false);
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
if (!enabled) return;
|
|
301
|
+
if (hasDigichatReady()) {
|
|
302
|
+
setReady(true);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const onReady = () => setReady(true);
|
|
306
|
+
window.addEventListener(DIGI_CHAT_READY_EVENT, onReady, { once: true });
|
|
307
|
+
const standalone = window.parent === window;
|
|
308
|
+
// Standalone surfaces never receive the handshake, so they settle on
|
|
309
|
+
// their own; embedded surfaces that time out surface a failure + retry.
|
|
310
|
+
const cap = setTimeout(() => {
|
|
311
|
+
if (standalone) setReady(true);
|
|
312
|
+
else setTimedOut(true);
|
|
313
|
+
}, standalone ? STANDALONE_CAP_MS : EMBEDDED_CAP_MS);
|
|
314
|
+
return () => {
|
|
315
|
+
window.removeEventListener(DIGI_CHAT_READY_EVENT, onReady);
|
|
316
|
+
clearTimeout(cap);
|
|
317
|
+
};
|
|
318
|
+
}, [enabled]);
|
|
319
|
+
return { ready, timedOut };
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** The boot failed: the app dispatched `digichat:boot-failed` (or the lab
|
|
323
|
+
* knob forced it); `failAfterMs` also demos the state locally. */
|
|
324
|
+
function useAppFailure(enabled: boolean, failAfterMs: number): boolean {
|
|
325
|
+
const [failed, setFailed] = useState(false);
|
|
326
|
+
useEffect(() => {
|
|
327
|
+
if (!enabled) return;
|
|
328
|
+
const onFailed = () => setFailed(true);
|
|
329
|
+
window.addEventListener(BOOT_FAILED_EVENT, onFailed);
|
|
330
|
+
const timer =
|
|
331
|
+
failAfterMs > 0 ? setTimeout(onFailed, failAfterMs) : undefined;
|
|
332
|
+
return () => {
|
|
333
|
+
window.removeEventListener(BOOT_FAILED_EVENT, onFailed);
|
|
334
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
335
|
+
};
|
|
336
|
+
}, [enabled, failAfterMs]);
|
|
337
|
+
return failed;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** Hold `value` back by `delayMs` after it flips true (the lab knob). */
|
|
341
|
+
function useDelayedTrue(value: boolean, delayMs: number): boolean {
|
|
342
|
+
const [delayed, setDelayed] = useState(false);
|
|
343
|
+
useEffect(() => {
|
|
344
|
+
if (!value) {
|
|
345
|
+
setDelayed(false);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (delayMs === 0) {
|
|
349
|
+
setDelayed(true);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const timer = setTimeout(() => setDelayed(true), delayMs);
|
|
353
|
+
return () => clearTimeout(timer);
|
|
354
|
+
}, [value, delayMs]);
|
|
355
|
+
return delayed;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function TypedLabel({ text, instant }: { text: string; instant: boolean }) {
|
|
359
|
+
const [count, setCount] = useState(instant ? text.length : 0);
|
|
360
|
+
useEffect(() => {
|
|
361
|
+
if (instant) {
|
|
362
|
+
setCount(text.length);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const interval = setInterval(() => {
|
|
366
|
+
setCount((current) => {
|
|
367
|
+
if (current >= text.length) {
|
|
368
|
+
clearInterval(interval);
|
|
369
|
+
return current;
|
|
370
|
+
}
|
|
371
|
+
return current + 1;
|
|
372
|
+
});
|
|
373
|
+
}, TYPE_MS);
|
|
374
|
+
return () => clearInterval(interval);
|
|
375
|
+
}, [text, instant]);
|
|
376
|
+
return <>{text.slice(0, count)}</>;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function SpinnerLine({ label }: { label?: string | null }) {
|
|
380
|
+
return (
|
|
381
|
+
<span className="dboot-lab-line dboot-lab-spin">
|
|
382
|
+
<DotMatrix state="loading" decorative className="!size-3" />
|
|
383
|
+
{label ? <span>{label}</span> : null}
|
|
384
|
+
</span>
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function DotsLine() {
|
|
389
|
+
const [count, setCount] = useState(0);
|
|
390
|
+
useEffect(() => {
|
|
391
|
+
const interval = setInterval(() => setCount((c) => (c + 1) % 4), 420);
|
|
392
|
+
return () => clearInterval(interval);
|
|
393
|
+
}, []);
|
|
394
|
+
return (
|
|
395
|
+
<span className="dboot-lab-line">
|
|
396
|
+
loading<span className="dboot-lab-dots" aria-hidden="true">{".".repeat(count)}</span>
|
|
397
|
+
</span>
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function BootLog() {
|
|
402
|
+
const [step, setStep] = useState(0);
|
|
403
|
+
useEffect(() => {
|
|
404
|
+
const timers = [
|
|
405
|
+
setTimeout(() => setStep(1), 620),
|
|
406
|
+
setTimeout(() => setStep(2), 1240),
|
|
407
|
+
];
|
|
408
|
+
return () => timers.forEach(clearTimeout);
|
|
409
|
+
}, []);
|
|
410
|
+
return (
|
|
411
|
+
<span className="dboot-lab-lines">
|
|
412
|
+
<span className="dboot-lab-line">$ digichat --boot</span>
|
|
413
|
+
{step > 0 ? (
|
|
414
|
+
<span className="dboot-lab-line dboot-lab-muted">ok</span>
|
|
415
|
+
) : null}
|
|
416
|
+
</span>
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const SCRAMBLE_GLYPHS = "▚▞█▓▒░<>/\\|=+*";
|
|
421
|
+
|
|
422
|
+
function ScrambleLine({ text, instant }: { text: string; instant: boolean }) {
|
|
423
|
+
const [display, setDisplay] = useState(instant ? text : "");
|
|
424
|
+
useEffect(() => {
|
|
425
|
+
if (instant) {
|
|
426
|
+
setDisplay(text);
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
let frame = 0;
|
|
430
|
+
const total = text.length * 2;
|
|
431
|
+
const interval = setInterval(() => {
|
|
432
|
+
frame += 1;
|
|
433
|
+
const reveal = Math.floor((frame / total) * text.length);
|
|
434
|
+
setDisplay(
|
|
435
|
+
text.slice(0, reveal) +
|
|
436
|
+
Array.from(
|
|
437
|
+
{ length: text.length - reveal },
|
|
438
|
+
(_, index) =>
|
|
439
|
+
SCRAMBLE_GLYPHS[(frame + index) % SCRAMBLE_GLYPHS.length],
|
|
440
|
+
).join(""),
|
|
441
|
+
);
|
|
442
|
+
if (frame >= total) {
|
|
443
|
+
clearInterval(interval);
|
|
444
|
+
setDisplay(text);
|
|
445
|
+
}
|
|
446
|
+
}, 40);
|
|
447
|
+
return () => clearInterval(interval);
|
|
448
|
+
}, [text, instant]);
|
|
449
|
+
return <span className="dboot-lab-line">{display}</span>;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/** Live elapsed ms while `active` (the running tool duration the chat shows). */
|
|
453
|
+
function useLiveMs(active: boolean): number {
|
|
454
|
+
const [ms, setMs] = useState(0);
|
|
455
|
+
useEffect(() => {
|
|
456
|
+
if (!active) return;
|
|
457
|
+
const started = Date.now();
|
|
458
|
+
const interval = setInterval(() => setMs(Date.now() - started), 120);
|
|
459
|
+
return () => clearInterval(interval);
|
|
460
|
+
}, [active]);
|
|
461
|
+
return ms;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* One simulated tool call: the same row anatomy as the message tool calls
|
|
466
|
+
* (`aui-tool-fallback-trigger` + DotMatrix states), so any skin styles it.
|
|
467
|
+
*/
|
|
468
|
+
function ToolChainRow({
|
|
469
|
+
label,
|
|
470
|
+
detail,
|
|
471
|
+
durationMs,
|
|
472
|
+
done,
|
|
473
|
+
shown = true,
|
|
474
|
+
failed = false,
|
|
475
|
+
}: {
|
|
476
|
+
label: string;
|
|
477
|
+
detail?: string;
|
|
478
|
+
durationMs: number;
|
|
479
|
+
done: boolean;
|
|
480
|
+
shown?: boolean;
|
|
481
|
+
failed?: boolean;
|
|
482
|
+
}) {
|
|
483
|
+
const liveMs = useLiveMs(shown && !done && !failed);
|
|
484
|
+
const ms = done ? durationMs : liveMs;
|
|
485
|
+
return (
|
|
486
|
+
<div
|
|
487
|
+
className="aui-tool-fallback-trigger group/trigger text-muted-foreground flex w-full items-center gap-2 py-1.5 text-xs"
|
|
488
|
+
data-slot="tool-fallback-trigger"
|
|
489
|
+
data-visible={shown ? "true" : "false"}
|
|
490
|
+
>
|
|
491
|
+
<DotMatrix
|
|
492
|
+
state={failed ? "error" : done ? "success" : "tool"}
|
|
493
|
+
decorative
|
|
494
|
+
className="aui-tool-fallback-trigger-icon !size-3 shrink-0"
|
|
495
|
+
/>
|
|
496
|
+
<span
|
|
497
|
+
className="aui-tool-fallback-trigger-label-wrapper min-w-0 flex-1 truncate text-start leading-none"
|
|
498
|
+
data-slot="tool-fallback-trigger-label"
|
|
499
|
+
>
|
|
500
|
+
{label}
|
|
501
|
+
{detail ? <span className="ml-1 opacity-60">· {detail}</span> : null}
|
|
502
|
+
</span>
|
|
503
|
+
<span className="aui-tool-fallback-duration text-muted-foreground text-xs tabular-nums">
|
|
504
|
+
{(ms / 1000).toFixed(1)}s
|
|
505
|
+
</span>
|
|
506
|
+
</div>
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/** A reasoning row above the calls (the reasoning trigger anatomy). */
|
|
511
|
+
function ReasoningRow({
|
|
512
|
+
active,
|
|
513
|
+
durationMs,
|
|
514
|
+
}: {
|
|
515
|
+
active: boolean;
|
|
516
|
+
durationMs: number;
|
|
517
|
+
}) {
|
|
518
|
+
return (
|
|
519
|
+
<div
|
|
520
|
+
className="aui-reasoning-trigger group/trigger text-muted-foreground flex w-full items-center gap-2 py-1.5 text-xs"
|
|
521
|
+
data-slot="reasoning-trigger"
|
|
522
|
+
>
|
|
523
|
+
<span
|
|
524
|
+
className="aui-reasoning-trigger-icon inline-flex size-3 shrink-0 items-center justify-center"
|
|
525
|
+
data-slot="reasoning-trigger-icon"
|
|
526
|
+
>
|
|
527
|
+
<DotMatrix
|
|
528
|
+
state={active ? "thinking" : "thought"}
|
|
529
|
+
decorative
|
|
530
|
+
className="!size-3"
|
|
531
|
+
/>
|
|
532
|
+
</span>
|
|
533
|
+
<span
|
|
534
|
+
className={
|
|
535
|
+
"aui-reasoning-trigger-label-wrapper min-w-0 flex-1 truncate text-start leading-none tabular-nums" +
|
|
536
|
+
(active ? " shimmer motion-reduce:animate-none" : "")
|
|
537
|
+
}
|
|
538
|
+
data-slot="reasoning-trigger-label"
|
|
539
|
+
>
|
|
540
|
+
{REASONING_LABEL}
|
|
541
|
+
{active ? "" : ` (${(durationMs / 1000).toFixed(1)}s)`}
|
|
542
|
+
</span>
|
|
543
|
+
<DisclosureChevron />
|
|
544
|
+
</div>
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function useBootSteps(): ReadonlySet<string> {
|
|
549
|
+
const [steps, setSteps] = useState<ReadonlySet<string>>(
|
|
550
|
+
() => new Set(digichatBootSteps()),
|
|
551
|
+
);
|
|
552
|
+
useEffect(() => {
|
|
553
|
+
const onStep = () => setSteps(new Set(digichatBootSteps()));
|
|
554
|
+
window.addEventListener(DIGI_CHAT_BOOT_STEP_EVENT, onStep);
|
|
555
|
+
return () => window.removeEventListener(DIGI_CHAT_BOOT_STEP_EVENT, onStep);
|
|
556
|
+
}, []);
|
|
557
|
+
return steps;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function ToolChain({
|
|
561
|
+
instant,
|
|
562
|
+
ready,
|
|
563
|
+
failed,
|
|
564
|
+
showReasoning,
|
|
565
|
+
facts,
|
|
566
|
+
onDone,
|
|
567
|
+
}: {
|
|
568
|
+
instant: boolean;
|
|
569
|
+
ready: boolean;
|
|
570
|
+
failed: boolean;
|
|
571
|
+
showReasoning: boolean;
|
|
572
|
+
facts?: BootFacts;
|
|
573
|
+
onDone: () => void;
|
|
574
|
+
}) {
|
|
575
|
+
const rows = useMemo(() => toolChainRows(facts), [facts]);
|
|
576
|
+
const steps = useBootSteps();
|
|
577
|
+
const mountClock = useRef(digichatBootClockMs());
|
|
578
|
+
const [doneAt, setDoneAt] = useState<(number | null)[]>(() =>
|
|
579
|
+
rows.map(() => (instant ? mountClock.current : null)),
|
|
580
|
+
);
|
|
581
|
+
const [tick, setTick] = useState(0);
|
|
582
|
+
const pending = doneAt.some((value) => value === null);
|
|
583
|
+
const firstPending = doneAt.findIndex((value) => value === null);
|
|
584
|
+
const chainDone = !pending;
|
|
585
|
+
// Poll while rows are open: each row flips when its real milestone lands.
|
|
586
|
+
// Image rows and tool/MCP rows keep a short beat so the chain stays
|
|
587
|
+
// readable, config/runtime fall back to a cap so a missed signal cannot
|
|
588
|
+
// wedge the boot, and the backend row waits for the app's real ready edge.
|
|
589
|
+
useEffect(() => {
|
|
590
|
+
if (instant || !pending) return;
|
|
591
|
+
const interval = setInterval(() => setTick((value) => value + 1), 250);
|
|
592
|
+
return () => clearInterval(interval);
|
|
593
|
+
}, [instant, pending]);
|
|
594
|
+
useEffect(() => {
|
|
595
|
+
if (instant || !pending) return;
|
|
596
|
+
setDoneAt((current) => {
|
|
597
|
+
const index = current.findIndex((value) => value === null);
|
|
598
|
+
if (index === -1) return current;
|
|
599
|
+
const row = rows[index];
|
|
600
|
+
if (row === undefined) return current;
|
|
601
|
+
const previousDone = index === 0 ? mountClock.current : current[index - 1];
|
|
602
|
+
if (previousDone === null || previousDone === undefined) return current;
|
|
603
|
+
const now = digichatBootClockMs();
|
|
604
|
+
const reached =
|
|
605
|
+
row.milestone === "backend"
|
|
606
|
+
? ready
|
|
607
|
+
: row.milestone === "services"
|
|
608
|
+
? // No timed fallback: only the host's real edge completes it.
|
|
609
|
+
steps.has("services") || ready
|
|
610
|
+
: row.milestone === "config" || row.milestone === "runtime"
|
|
611
|
+
? steps.has(row.milestone) || now - previousDone >= row.ms * 2
|
|
612
|
+
: now - previousDone >= row.ms;
|
|
613
|
+
if (!reached) return current;
|
|
614
|
+
const next = [...current];
|
|
615
|
+
next[index] = now;
|
|
616
|
+
return next;
|
|
617
|
+
});
|
|
618
|
+
}, [tick, instant, pending, ready, rows, steps]);
|
|
619
|
+
useEffect(() => {
|
|
620
|
+
if (chainDone) onDone();
|
|
621
|
+
}, [chainDone, onDone]);
|
|
622
|
+
// The last row waits on the real ready edge - that is the honest "connect"
|
|
623
|
+
// beat; a failed boot leaves its X up instead of settling.
|
|
624
|
+
const completedMs =
|
|
625
|
+
chainDone && doneAt[rows.length - 1] != null
|
|
626
|
+
? doneAt[rows.length - 1]! - mountClock.current
|
|
627
|
+
: 0;
|
|
628
|
+
return (
|
|
629
|
+
<span className="dboot-lab-tools">
|
|
630
|
+
{showReasoning ? (
|
|
631
|
+
<ReasoningRow active={!chainDone && !failed} durationMs={completedMs} />
|
|
632
|
+
) : null}
|
|
633
|
+
{rows.map((row, index) => {
|
|
634
|
+
const done = doneAt[index] != null;
|
|
635
|
+
const start =
|
|
636
|
+
index === 0
|
|
637
|
+
? mountClock.current
|
|
638
|
+
: doneAt[index - 1] ?? mountClock.current;
|
|
639
|
+
// Every row mounts with the chain; unseen rows only hide their paint
|
|
640
|
+
// (visibility), so the block keeps its final height from the first
|
|
641
|
+
// frame and new steps appear below the last one without nudging the
|
|
642
|
+
// rows above.
|
|
643
|
+
const shown = firstPending === -1 || index <= firstPending;
|
|
644
|
+
return (
|
|
645
|
+
<ToolChainRow
|
|
646
|
+
key={row.label}
|
|
647
|
+
label={row.label}
|
|
648
|
+
detail={row.detail}
|
|
649
|
+
durationMs={done ? doneAt[index]! - start : 0}
|
|
650
|
+
done={done}
|
|
651
|
+
shown={shown}
|
|
652
|
+
failed={
|
|
653
|
+
failed &&
|
|
654
|
+
index === (firstPending === -1 ? rows.length - 1 : firstPending)
|
|
655
|
+
}
|
|
656
|
+
/>
|
|
657
|
+
);
|
|
658
|
+
})}
|
|
659
|
+
</span>
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* The standard boot cover: the digichat hero banner alone, centered both
|
|
665
|
+
* ways, exactly as the site shell draws it (ChatEmbedShell) — no copy and no
|
|
666
|
+
* spinner. The wrapper is what gives the canvas a width; HeroBanner sizes
|
|
667
|
+
* itself to its container. `replayLoading` plays the definition's LOADING
|
|
668
|
+
* pass on mount; under reduced motion it stays off and HeroBanner paints the
|
|
669
|
+
* settled mark without starting a timer.
|
|
670
|
+
*/
|
|
671
|
+
function BootBanner({ replayLoading }: { replayLoading: boolean }) {
|
|
672
|
+
return (
|
|
673
|
+
<div
|
|
674
|
+
style={{
|
|
675
|
+
display: "flex",
|
|
676
|
+
alignItems: "center",
|
|
677
|
+
justifyContent: "center",
|
|
678
|
+
width: "100%",
|
|
679
|
+
height: "100%",
|
|
680
|
+
}}
|
|
681
|
+
>
|
|
682
|
+
<div style={{ width: "min(560px, 72vw)" }}>
|
|
683
|
+
<HeroBanner def={DIGICHAT} replayLoading={replayLoading} />
|
|
684
|
+
</div>
|
|
685
|
+
<span className="sr-only">Loading chat…</span>
|
|
686
|
+
</div>
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
export function BootLabOverlay({
|
|
691
|
+
variant,
|
|
692
|
+
ready,
|
|
693
|
+
onSettled,
|
|
694
|
+
accent,
|
|
695
|
+
facts,
|
|
696
|
+
readyEdge,
|
|
697
|
+
}: {
|
|
698
|
+
variant: BootLabVariant;
|
|
699
|
+
ready: boolean;
|
|
700
|
+
onSettled: () => void;
|
|
701
|
+
accent?: string;
|
|
702
|
+
facts?: BootFacts;
|
|
703
|
+
/**
|
|
704
|
+
* The real ready edge when the app runs in another document (an iframe
|
|
705
|
+
* host): this document's ready event never fires there and the standalone
|
|
706
|
+
* self-settle would flip the backend row on its cap instead of the honest
|
|
707
|
+
* beat, so the host passes its own signal (the embed's postMessage) here.
|
|
708
|
+
*/
|
|
709
|
+
readyEdge?: boolean;
|
|
710
|
+
}) {
|
|
711
|
+
const reduced = useReducedMotion();
|
|
712
|
+
const isToolchain = TOOLCHAIN_VARIANTS.has(variant);
|
|
713
|
+
const [chainDone, setChainDone] = useState(!isToolchain);
|
|
714
|
+
const [bootDelayMs] = useState(resolveBootDelayMs);
|
|
715
|
+
const [failAfterMs] = useState(resolveBootFailMs);
|
|
716
|
+
const hostOwnsReady = readyEdge !== undefined;
|
|
717
|
+
// `?bootfail` forces the failure demo: ignore the real ready signal so the
|
|
718
|
+
// boot cannot settle before the forced failure lands.
|
|
719
|
+
const app = useAppReady(isToolchain && failAfterMs === 0 && !hostOwnsReady);
|
|
720
|
+
const delayedReady = useDelayedTrue(app.ready, bootDelayMs);
|
|
721
|
+
const appReady = hostOwnsReady ? (readyEdge as boolean) : delayedReady;
|
|
722
|
+
const appFailed = useAppFailure(isToolchain && !hostOwnsReady, failAfterMs);
|
|
723
|
+
const failed = isToolchain && !hostOwnsReady && (appFailed || app.timedOut);
|
|
724
|
+
// The tool chain runs to completion and then waits for the real ready
|
|
725
|
+
// signal, so long cold starts keep a live row instead of looking done.
|
|
726
|
+
// A failed boot never settles: the overlay keeps the error + retry up.
|
|
727
|
+
const active = isToolchain ? ready && chainDone && appReady && !failed : ready;
|
|
728
|
+
useSettle(active, onSettled);
|
|
729
|
+
const label = LABELS[variant];
|
|
730
|
+
return (
|
|
731
|
+
<div
|
|
732
|
+
className="dboot-lab"
|
|
733
|
+
data-digichat-boot=""
|
|
734
|
+
data-variant={variant}
|
|
735
|
+
role="status"
|
|
736
|
+
style={accent ? ({ "--dboot-caret": accent } as CSSProperties) : undefined}
|
|
737
|
+
>
|
|
738
|
+
{variant === "banner" ? <BootBanner replayLoading={!reduced} /> : null}
|
|
739
|
+
{variant === "spinner" ? <SpinnerLine label={label} /> : null}
|
|
740
|
+
{variant === "spinneronly" ? <SpinnerLine /> : null}
|
|
741
|
+
{variant === "dots" ? <DotsLine /> : null}
|
|
742
|
+
{variant === "bootlog" ? <BootLog /> : null}
|
|
743
|
+
{variant === "scramble" && label ? (
|
|
744
|
+
<ScrambleLine text={label} instant={reduced} />
|
|
745
|
+
) : null}
|
|
746
|
+
{isToolchain ? (
|
|
747
|
+
<ToolChain
|
|
748
|
+
instant={reduced}
|
|
749
|
+
ready={appReady}
|
|
750
|
+
failed={failed}
|
|
751
|
+
showReasoning={variant === "toolreason" || variant === "toolfull"}
|
|
752
|
+
facts={facts}
|
|
753
|
+
onDone={() => setChainDone(true)}
|
|
754
|
+
/>
|
|
755
|
+
) : null}
|
|
756
|
+
{TYPED.has(variant) && label ? (
|
|
757
|
+
<span className="dboot-lab-line">
|
|
758
|
+
<span>
|
|
759
|
+
<TypedLabel text={label} instant={reduced} />
|
|
760
|
+
</span>
|
|
761
|
+
<span className="dboot-lab-caret" aria-hidden="true" />
|
|
762
|
+
</span>
|
|
763
|
+
) : null}
|
|
764
|
+
</div>
|
|
765
|
+
);
|
|
766
|
+
}
|