@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,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KpiStrip + Kpi (#1463) — the tearsheet KPI card grammar promoted from the
|
|
3
|
+
* inline `Kpi` in apps/digiquant-web/components/tearsheet/tearsheet-view.tsx
|
|
4
|
+
* and the dashboard PerformanceTearsheetView. Values are ReactNodes so consumers tone
|
|
5
|
+
* them with the money classes (`is-pos` / `is-neg` via `toneClass`); the
|
|
6
|
+
* gradient card surface, the 6-up `primary` strip (3-up ≤1100px, 2-up
|
|
7
|
+
* ≤640px), and the `break-inside: avoid` print rules live in
|
|
8
|
+
* styles/finance-tearsheet.css. Server component — no state, no effects.
|
|
9
|
+
*/
|
|
10
|
+
import type { ReactNode } from "react";
|
|
11
|
+
|
|
12
|
+
export interface KpiProps {
|
|
13
|
+
label: string;
|
|
14
|
+
value: ReactNode;
|
|
15
|
+
/** Small soft line under the value (e.g. "since inception"). */
|
|
16
|
+
sub?: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function Kpi({ label, value, sub }: KpiProps) {
|
|
20
|
+
return (
|
|
21
|
+
<div className="ts-kpi">
|
|
22
|
+
<span className="ts-kpi-label">{label}</span>
|
|
23
|
+
<span className="ts-kpi-value">{value}</span>
|
|
24
|
+
{sub != null ? <span className="ts-kpi-sub">{sub}</span> : null}
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface KpiStripProps {
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
/** The headline 6-up strip (`.ts-kpis-primary`); omit for the auto-fit grid. */
|
|
32
|
+
primary?: boolean;
|
|
33
|
+
/** Names the strip for AT (e.g. "Headline performance"). */
|
|
34
|
+
ariaLabel?: string;
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function KpiStrip({ children, primary = false, ariaLabel, className }: KpiStripProps) {
|
|
39
|
+
return (
|
|
40
|
+
<section
|
|
41
|
+
className={
|
|
42
|
+
"ts-kpis" + (primary ? " ts-kpis-primary" : "") + (className ? ` ${className}` : "")
|
|
43
|
+
}
|
|
44
|
+
aria-label={ariaLabel}
|
|
45
|
+
>
|
|
46
|
+
{children}
|
|
47
|
+
</section>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LiveBadge (#1463) — the pulsing-dot live indicator promoted from
|
|
3
|
+
* apps/digiquant-web/components/tearsheet/live-metrics.tsx. The accent
|
|
4
|
+
* dot pulse (`@keyframes ts-live-pulse`) lives in
|
|
5
|
+
* styles/finance-tearsheet.css; in print the badge is hidden (live-ness is
|
|
6
|
+
* meaningless on paper). Whether the badge shows at all (e.g. only when a
|
|
7
|
+
* nightly pipeline stamped `generated_at`) is consumer data wiring. Server
|
|
8
|
+
* component — no state, no effects.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export interface LiveBadgeProps {
|
|
12
|
+
/** Badge copy — lowercase by grammar (the dress lowercases regardless). */
|
|
13
|
+
label?: string;
|
|
14
|
+
/** AT description; the pulse itself is decorative. */
|
|
15
|
+
ariaLabel?: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function LiveBadge({ label = "live", ariaLabel = "Live metrics", className }: LiveBadgeProps) {
|
|
20
|
+
return (
|
|
21
|
+
<span
|
|
22
|
+
className={"ts-live-badge" + (className ? ` ${className}` : "")}
|
|
23
|
+
aria-label={ariaLabel}
|
|
24
|
+
>
|
|
25
|
+
<span className="ts-live-dot" aria-hidden="true" />
|
|
26
|
+
<span className="ts-live-label">{label}</span>
|
|
27
|
+
</span>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReturnsMatrix (#1463) — the period matrix promoted verbatim from
|
|
3
|
+
* apps/digiquant-web/components/tearsheet/charts.tsx: 3 metrics
|
|
4
|
+
* (return / drawdown / volatility) x 3 granularities (monthly / quarterly /
|
|
5
|
+
* annual), derived from the equity curve (returns, vol) or the drawdown
|
|
6
|
+
* curve (max DD per slot). Cells tint by data-driven max-abs magnitude on
|
|
7
|
+
* the money tokens; returns format as signed compact % so crypto-scale
|
|
8
|
+
* figures (hundreds / thousands of %) fit the narrow cells; the trailing
|
|
9
|
+
* Year column compounds. This is THE matrix grammar — the former
|
|
10
|
+
* finance-charts MonthlyReturns (fixed-peak tint, unsigned 1-dp cells,
|
|
11
|
+
* arithmetic-sum totals) was deprecated into it (monthly slice =
|
|
12
|
+
* `period="monthly" metric="return"`).
|
|
13
|
+
*/
|
|
14
|
+
import { fmtCompact } from "./format";
|
|
15
|
+
import { annualizedVolPct, dailyReturnsFromEquity } from "./stats";
|
|
16
|
+
import { type TearsheetSeriesPoint } from "./types";
|
|
17
|
+
|
|
18
|
+
export type ReturnsPeriod = "monthly" | "quarterly" | "annual";
|
|
19
|
+
export type MatrixMetric = "return" | "drawdown" | "volatility";
|
|
20
|
+
|
|
21
|
+
const MONTH_LABELS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
22
|
+
const QUARTER_LABELS = ["Q1", "Q2", "Q3", "Q4"];
|
|
23
|
+
|
|
24
|
+
/** A single rendered cell value (or null = no data in that slot). */
|
|
25
|
+
interface MatrixCell {
|
|
26
|
+
value: number | null;
|
|
27
|
+
}
|
|
28
|
+
interface MatrixRow {
|
|
29
|
+
year: number;
|
|
30
|
+
cells: MatrixCell[];
|
|
31
|
+
yearValue: number | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Number of columns per granularity (the trailing Year column is separate). */
|
|
35
|
+
function colCount(period: ReturnsPeriod): number {
|
|
36
|
+
return period === "monthly" ? 12 : period === "quarterly" ? 4 : 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function slotOf(month: number, period: ReturnsPeriod): number {
|
|
40
|
+
return period === "monthly" ? month : period === "quarterly" ? Math.floor(month / 3) : 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function bucketEquityBySlot(points: TearsheetSeriesPoint[], period: ReturnsPeriod) {
|
|
44
|
+
const lastInSlot = new Map<string, number>();
|
|
45
|
+
const pointsInSlot = new Map<string, TearsheetSeriesPoint[]>();
|
|
46
|
+
const yearLast = new Map<number, number>();
|
|
47
|
+
let minYear = Infinity;
|
|
48
|
+
let maxYear = -Infinity;
|
|
49
|
+
|
|
50
|
+
for (const p of points) {
|
|
51
|
+
const d = new Date(p.t);
|
|
52
|
+
const year = d.getUTCFullYear();
|
|
53
|
+
const slot = slotOf(d.getUTCMonth(), period);
|
|
54
|
+
const key = `${year}:${slot}`;
|
|
55
|
+
lastInSlot.set(key, p.v);
|
|
56
|
+
const bucket = pointsInSlot.get(key) ?? [];
|
|
57
|
+
bucket.push(p);
|
|
58
|
+
pointsInSlot.set(key, bucket);
|
|
59
|
+
yearLast.set(year, p.v);
|
|
60
|
+
if (year < minYear) minYear = year;
|
|
61
|
+
if (year > maxYear) maxYear = year;
|
|
62
|
+
}
|
|
63
|
+
return { lastInSlot, pointsInSlot, yearLast, minYear, maxYear };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function bucketDrawdownBySlot(points: TearsheetSeriesPoint[], period: ReturnsPeriod) {
|
|
67
|
+
const minInSlot = new Map<string, number>();
|
|
68
|
+
const yearMin = new Map<number, number>();
|
|
69
|
+
let minYear = Infinity;
|
|
70
|
+
let maxYear = -Infinity;
|
|
71
|
+
|
|
72
|
+
for (const p of points) {
|
|
73
|
+
const d = new Date(p.t);
|
|
74
|
+
const year = d.getUTCFullYear();
|
|
75
|
+
const slot = slotOf(d.getUTCMonth(), period);
|
|
76
|
+
const key = `${year}:${slot}`;
|
|
77
|
+
const prev = minInSlot.get(key);
|
|
78
|
+
minInSlot.set(key, prev === undefined ? p.v : Math.min(prev, p.v));
|
|
79
|
+
const yPrev = yearMin.get(year);
|
|
80
|
+
yearMin.set(year, yPrev === undefined ? p.v : Math.min(yPrev, p.v));
|
|
81
|
+
if (year < minYear) minYear = year;
|
|
82
|
+
if (year > maxYear) maxYear = year;
|
|
83
|
+
}
|
|
84
|
+
return { minInSlot, yearMin, minYear, maxYear };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Period matrix from equity (returns, vol) or drawdown curve (max DD per slot).
|
|
89
|
+
*/
|
|
90
|
+
function buildMatrixRows(
|
|
91
|
+
equity: TearsheetSeriesPoint[],
|
|
92
|
+
drawdown: TearsheetSeriesPoint[] | undefined,
|
|
93
|
+
period: ReturnsPeriod,
|
|
94
|
+
metric: MatrixMetric,
|
|
95
|
+
): MatrixRow[] {
|
|
96
|
+
if (!equity || equity.length === 0) return [];
|
|
97
|
+
const cols = colCount(period);
|
|
98
|
+
|
|
99
|
+
if (metric === "drawdown") {
|
|
100
|
+
if (!drawdown || drawdown.length === 0) return [];
|
|
101
|
+
const { minInSlot, yearMin, minYear, maxYear } = bucketDrawdownBySlot(drawdown, period);
|
|
102
|
+
if (!Number.isFinite(minYear)) return [];
|
|
103
|
+
const rows: MatrixRow[] = [];
|
|
104
|
+
for (let year = minYear; year <= maxYear; year++) {
|
|
105
|
+
const cells: MatrixCell[] = [];
|
|
106
|
+
for (let s = 0; s < cols; s++) {
|
|
107
|
+
const v = minInSlot.get(`${year}:${s}`);
|
|
108
|
+
cells.push({ value: v === undefined ? null : v });
|
|
109
|
+
}
|
|
110
|
+
const yv = yearMin.get(year);
|
|
111
|
+
rows.push({ year, cells, yearValue: yv === undefined ? null : yv });
|
|
112
|
+
}
|
|
113
|
+
return rows;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const { lastInSlot, pointsInSlot, yearLast, minYear, maxYear } = bucketEquityBySlot(
|
|
117
|
+
equity,
|
|
118
|
+
period,
|
|
119
|
+
);
|
|
120
|
+
if (!Number.isFinite(minYear)) return [];
|
|
121
|
+
|
|
122
|
+
const pointsByYear = new Map<number, TearsheetSeriesPoint[]>();
|
|
123
|
+
for (const p of equity) {
|
|
124
|
+
const y = new Date(p.t).getUTCFullYear();
|
|
125
|
+
const bucket = pointsByYear.get(y) ?? [];
|
|
126
|
+
bucket.push(p);
|
|
127
|
+
pointsByYear.set(y, bucket);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (metric === "volatility") {
|
|
131
|
+
const rows: MatrixRow[] = [];
|
|
132
|
+
for (let year = minYear; year <= maxYear; year++) {
|
|
133
|
+
const cells: MatrixCell[] = [];
|
|
134
|
+
for (let s = 0; s < cols; s++) {
|
|
135
|
+
const pts = pointsInSlot.get(`${year}:${s}`);
|
|
136
|
+
const vol =
|
|
137
|
+
pts && pts.length >= 2 ? annualizedVolPct(dailyReturnsFromEquity(pts)) : null;
|
|
138
|
+
cells.push({ value: vol });
|
|
139
|
+
}
|
|
140
|
+
const yearPts = pointsByYear.get(year) ?? [];
|
|
141
|
+
const yearVol =
|
|
142
|
+
yearPts.length >= 2 ? annualizedVolPct(dailyReturnsFromEquity(yearPts)) : null;
|
|
143
|
+
rows.push({ year, cells, yearValue: yearVol });
|
|
144
|
+
}
|
|
145
|
+
return rows;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const opening = equity[0].v;
|
|
149
|
+
const rows: MatrixRow[] = [];
|
|
150
|
+
let prevClose = opening;
|
|
151
|
+
|
|
152
|
+
for (let year = minYear; year <= maxYear; year++) {
|
|
153
|
+
const cells: MatrixCell[] = [];
|
|
154
|
+
for (let s = 0; s < cols; s++) {
|
|
155
|
+
const close = lastInSlot.get(`${year}:${s}`);
|
|
156
|
+
if (close === undefined) {
|
|
157
|
+
cells.push({ value: null });
|
|
158
|
+
} else {
|
|
159
|
+
const ret = prevClose > 0 ? (close / prevClose - 1) * 100 : null;
|
|
160
|
+
cells.push({ value: ret });
|
|
161
|
+
prevClose = close;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const last = yearLast.get(year);
|
|
165
|
+
const yearStart = prevCloseAtYearStart(year, minYear, opening, yearLast);
|
|
166
|
+
const yearValue =
|
|
167
|
+
last !== undefined && yearStart > 0 ? (last / yearStart - 1) * 100 : null;
|
|
168
|
+
rows.push({ year, cells, yearValue: yearValue });
|
|
169
|
+
}
|
|
170
|
+
return rows;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Equity carried into `year`: the prior year's last close, or the opening for the
|
|
174
|
+
* first year. Keeps the Year column consistent with the chained cell logic. */
|
|
175
|
+
function prevCloseAtYearStart(year: number, minYear: number, opening: number, yearLast: Map<number, number>): number {
|
|
176
|
+
if (year === minYear) return opening;
|
|
177
|
+
// Walk back to the most recent prior year that actually has data.
|
|
178
|
+
for (let y = year - 1; y >= minYear; y--) {
|
|
179
|
+
const v = yearLast.get(y);
|
|
180
|
+
if (v !== undefined) return v;
|
|
181
|
+
}
|
|
182
|
+
return opening;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Inline cell background: tone-coloured with alpha scaled by |value| relative to max-abs. */
|
|
186
|
+
function cellBg(value: number | null, maxAbs: number, metric: MatrixMetric): string {
|
|
187
|
+
if (value === null) return "transparent";
|
|
188
|
+
if (value === 0 && metric === "return") return "transparent";
|
|
189
|
+
const tone =
|
|
190
|
+
metric === "drawdown" || metric === "volatility"
|
|
191
|
+
? "var(--down)"
|
|
192
|
+
: value > 0
|
|
193
|
+
? "var(--up)"
|
|
194
|
+
: "var(--down)";
|
|
195
|
+
const mag = maxAbs > 0 ? Math.abs(value) / maxAbs : 0;
|
|
196
|
+
const pct = Math.round(14 + Math.min(1, mag) * 58);
|
|
197
|
+
return `color-mix(in srgb, ${tone} ${pct}%, transparent)`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** True when the up-tone wash is bright enough that the default cell ink
|
|
201
|
+
* cannot clear AA on it: `.ts-matrix-cell.is-strong` then reads
|
|
202
|
+
* --heat-ink-strong. Matches the pct>=57 branch in finance-tearsheet.css;
|
|
203
|
+
* the down tone never needs it (its wash stays dark through the range). */
|
|
204
|
+
function cellStrong(value: number | null, maxAbs: number, metric: MatrixMetric): boolean {
|
|
205
|
+
if (value === null || metric !== "return" || value <= 0) return false;
|
|
206
|
+
const mag = maxAbs > 0 ? Math.abs(value) / maxAbs : 0;
|
|
207
|
+
return Math.round(14 + Math.min(1, mag) * 58) >= 57;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Compact cell % — sheds decimals as magnitude grows so wide crypto returns
|
|
211
|
+
* (hundreds / thousands of %) fit the narrow grid cells without truncation. */
|
|
212
|
+
function fmtCellPct(v: number): string {
|
|
213
|
+
const a = Math.abs(v);
|
|
214
|
+
if (a >= 1000) return fmtCompact(v) + "%";
|
|
215
|
+
if (a >= 100) return v.toFixed(0) + "%";
|
|
216
|
+
return v.toFixed(1) + "%";
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function fmtCellValue(v: number | null, metric: MatrixMetric): string {
|
|
220
|
+
if (v === null) return "";
|
|
221
|
+
if (metric === "volatility") return v.toFixed(1) + "%";
|
|
222
|
+
return fmtCellPct(v);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Calendar heatmap of period returns derived from the equity curve. Rows = years,
|
|
227
|
+
* columns = months / quarters / a single annual cell, plus a trailing compounded
|
|
228
|
+
* "Year" column. Pure CSS-grid table (no SVG) so it reflows and scrolls on mobile.
|
|
229
|
+
*/
|
|
230
|
+
export function ReturnsMatrix({
|
|
231
|
+
points,
|
|
232
|
+
drawdown,
|
|
233
|
+
period,
|
|
234
|
+
metric = "return",
|
|
235
|
+
}: {
|
|
236
|
+
points: TearsheetSeriesPoint[];
|
|
237
|
+
drawdown?: TearsheetSeriesPoint[];
|
|
238
|
+
period: ReturnsPeriod;
|
|
239
|
+
metric?: MatrixMetric;
|
|
240
|
+
}) {
|
|
241
|
+
const rows = buildMatrixRows(points, drawdown, period, metric);
|
|
242
|
+
if (rows.length === 0) {
|
|
243
|
+
return (
|
|
244
|
+
<div className="ts-status">
|
|
245
|
+
{metric === "drawdown" && !drawdown?.length ? "drawdown data unavailable" : "no data"}
|
|
246
|
+
</div>
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const cols = colCount(period);
|
|
251
|
+
const labels = period === "monthly" ? MONTH_LABELS : period === "quarterly" ? QUARTER_LABELS : ["Year"];
|
|
252
|
+
const showYearCol = period !== "annual";
|
|
253
|
+
|
|
254
|
+
let maxAbs = 0;
|
|
255
|
+
for (const r of rows) {
|
|
256
|
+
for (const c of r.cells) if (c.value !== null) maxAbs = Math.max(maxAbs, Math.abs(c.value));
|
|
257
|
+
if (showYearCol && r.yearValue !== null) maxAbs = Math.max(maxAbs, Math.abs(r.yearValue));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const gridTemplate = `minmax(3rem, auto) repeat(${cols + (showYearCol ? 1 : 0)}, minmax(0, 1fr))`;
|
|
261
|
+
const metricLabel = metric === "return" ? "returns" : metric === "drawdown" ? "drawdown" : "volatility";
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<div className="ts-table-wrap ts-matrix-wrap">
|
|
265
|
+
<div
|
|
266
|
+
className="ts-matrix ts-matrix-fill"
|
|
267
|
+
style={{ gridTemplateColumns: gridTemplate }}
|
|
268
|
+
role="table"
|
|
269
|
+
aria-label={`${period} ${metricLabel}`}
|
|
270
|
+
>
|
|
271
|
+
<div className="ts-matrix-corner" role="columnheader" />
|
|
272
|
+
{labels.map((l) => (
|
|
273
|
+
<div key={l} className="ts-matrix-head" role="columnheader">{l}</div>
|
|
274
|
+
))}
|
|
275
|
+
{showYearCol ? <div className="ts-matrix-head ts-matrix-year-head" role="columnheader">Year</div> : null}
|
|
276
|
+
{rows.map((r) => (
|
|
277
|
+
<div key={r.year} className="ts-matrix-row" role="row" style={{ display: "contents" }}>
|
|
278
|
+
<div className="ts-matrix-rowlabel" role="rowheader">{r.year}</div>
|
|
279
|
+
{r.cells.map((c, i) => (
|
|
280
|
+
<div
|
|
281
|
+
key={i}
|
|
282
|
+
className={
|
|
283
|
+
"ts-matrix-cell" +
|
|
284
|
+
(c.value === null ? " is-empty" : "") +
|
|
285
|
+
(cellStrong(c.value, maxAbs, metric) ? " is-strong" : "")
|
|
286
|
+
}
|
|
287
|
+
style={{ background: cellBg(c.value, maxAbs, metric) }}
|
|
288
|
+
role="cell"
|
|
289
|
+
title={
|
|
290
|
+
c.value === null
|
|
291
|
+
? "no data"
|
|
292
|
+
: `${labels[i]} ${r.year}: ${fmtCellValue(c.value, metric)}`
|
|
293
|
+
}
|
|
294
|
+
>
|
|
295
|
+
{fmtCellValue(c.value, metric)}
|
|
296
|
+
</div>
|
|
297
|
+
))}
|
|
298
|
+
{showYearCol ? (
|
|
299
|
+
<div
|
|
300
|
+
className={
|
|
301
|
+
"ts-matrix-cell ts-matrix-year" +
|
|
302
|
+
(r.yearValue === null ? " is-empty" : "") +
|
|
303
|
+
(cellStrong(r.yearValue, maxAbs, metric) ? " is-strong" : "")
|
|
304
|
+
}
|
|
305
|
+
style={{ background: cellBg(r.yearValue, maxAbs, metric) }}
|
|
306
|
+
role="cell"
|
|
307
|
+
title={
|
|
308
|
+
r.yearValue === null
|
|
309
|
+
? "no data"
|
|
310
|
+
: `${r.year} total: ${fmtCellValue(r.yearValue, metric)}`
|
|
311
|
+
}
|
|
312
|
+
>
|
|
313
|
+
{fmtCellValue(r.yearValue, metric)}
|
|
314
|
+
</div>
|
|
315
|
+
) : null}
|
|
316
|
+
</div>
|
|
317
|
+
))}
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
);
|
|
321
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { CandlestickChart, TimeSeries } from "./charts";
|
|
2
|
+
import { Kpi, KpiStrip } from "./KpiStrip";
|
|
3
|
+
import { TradeLogTable } from "./TradeLogTable";
|
|
4
|
+
import type { StrategySheetMetric, StrategySheetModel } from "./strategy-sheet-model";
|
|
5
|
+
|
|
6
|
+
const DASH = "—";
|
|
7
|
+
|
|
8
|
+
function Figure({ metric }: { metric: StrategySheetMetric }) {
|
|
9
|
+
const tone = metric.tone === "pos" ? "is-pos" : metric.tone === "neg" ? "is-neg" : undefined;
|
|
10
|
+
return <span className={tone}>{metric.value ?? DASH}</span>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* One strategy tear sheet. Unpublished figures are an em dash. A chart is
|
|
15
|
+
* mounted only when the model already kept a series of two or more values.
|
|
16
|
+
* No status sentence and no backtest chips.
|
|
17
|
+
*/
|
|
18
|
+
export function StrategyTearsheet({ model }: { model: StrategySheetModel }) {
|
|
19
|
+
return (
|
|
20
|
+
<div className="ts-print-root" data-strategy-tearsheet="">
|
|
21
|
+
<header className="ts-header">
|
|
22
|
+
<div className="ts-header-main">
|
|
23
|
+
<h2 className="ts-h1">{model.title}</h2>
|
|
24
|
+
{model.symbol ? <p className="ts-meta-text m-0">{model.symbol}</p> : null}
|
|
25
|
+
</div>
|
|
26
|
+
</header>
|
|
27
|
+
|
|
28
|
+
<section className="ts-position" aria-label="Current position">
|
|
29
|
+
<div className="ts-position-head">
|
|
30
|
+
<span className="ts-panel-label">Current position</span>
|
|
31
|
+
</div>
|
|
32
|
+
<dl className="m-0 grid grid-cols-2 gap-px border border-hair bg-hair sm:grid-cols-4">
|
|
33
|
+
{model.position.map((item) => (
|
|
34
|
+
<div key={item.label} className="bg-surface px-3 py-2">
|
|
35
|
+
<dt className="font-mono text-[0.6rem] uppercase tracking-[0.08em] text-ink-mute">{item.label}</dt>
|
|
36
|
+
<dd className="m-0 mt-1 font-mono text-[0.9rem] leading-none text-ink">
|
|
37
|
+
<Figure metric={item} />
|
|
38
|
+
</dd>
|
|
39
|
+
</div>
|
|
40
|
+
))}
|
|
41
|
+
</dl>
|
|
42
|
+
</section>
|
|
43
|
+
|
|
44
|
+
<KpiStrip primary ariaLabel="Headline performance">
|
|
45
|
+
{model.metrics.map((item) => (
|
|
46
|
+
<Kpi key={item.label} label={item.label} value={<Figure metric={item} />} />
|
|
47
|
+
))}
|
|
48
|
+
</KpiStrip>
|
|
49
|
+
|
|
50
|
+
{model.price ? (
|
|
51
|
+
<section className="ts-panel" aria-label="Price">
|
|
52
|
+
<h3 className="ts-panel-label">Price</h3>
|
|
53
|
+
<div className="ts-chart">
|
|
54
|
+
<CandlestickChart
|
|
55
|
+
bars={model.price}
|
|
56
|
+
trades={[]}
|
|
57
|
+
height={320}
|
|
58
|
+
ariaLabel={`${model.symbol || model.title} price`}
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
61
|
+
</section>
|
|
62
|
+
) : null}
|
|
63
|
+
|
|
64
|
+
{model.equity ? (
|
|
65
|
+
<section className="ts-panel" aria-label="Performance">
|
|
66
|
+
<h3 className="ts-panel-label">Performance</h3>
|
|
67
|
+
<div className="ts-chart">
|
|
68
|
+
<TimeSeries points={model.equity} height={280} ariaLabel={`${model.title} equity`} />
|
|
69
|
+
</div>
|
|
70
|
+
</section>
|
|
71
|
+
) : null}
|
|
72
|
+
|
|
73
|
+
{model.drawdown ? (
|
|
74
|
+
<section className="ts-panel" aria-label="Drawdown">
|
|
75
|
+
<h3 className="ts-panel-label">Drawdown</h3>
|
|
76
|
+
<div className="ts-chart">
|
|
77
|
+
<TimeSeries
|
|
78
|
+
points={model.drawdown}
|
|
79
|
+
height={220}
|
|
80
|
+
tone="down"
|
|
81
|
+
ariaLabel={`${model.title} drawdown`}
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
</section>
|
|
85
|
+
) : null}
|
|
86
|
+
|
|
87
|
+
<section className="ts-panel" aria-label="Entries and exits">
|
|
88
|
+
<h3 className="ts-panel-label">Entries and exits</h3>
|
|
89
|
+
<TradeLogTable
|
|
90
|
+
ariaLabel="Entries and exits"
|
|
91
|
+
columns={(model.trades?.columns ?? ["Direction", "Entry date", "Entry", "Exit date", "Exit", "Return"]).map(
|
|
92
|
+
(label, index) => ({ label, numeric: index >= 2 }),
|
|
93
|
+
)}
|
|
94
|
+
rows={(model.trades?.rows ?? []).map((cells, index) => ({ key: index, cells }))}
|
|
95
|
+
/>
|
|
96
|
+
</section>
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TearsheetCard (#1463) — the strategy-library card dress promoted from
|
|
3
|
+
* apps/digiquant-web/components/tearsheet/strategy-card.tsx, closing the
|
|
4
|
+
* gap recorded against the promoted controls Card (anchor/render composition
|
|
5
|
+
* plus a tearsheet dress): the whole card is a link, with hover-lift +
|
|
6
|
+
* accent-border transition over the gradient surface (`.ts-card` in
|
|
7
|
+
* styles/finance-tearsheet.css; `break-inside: avoid` in print). Head/title
|
|
8
|
+
* markup stays consumer-composed on the shared classes (`.ts-card-head`,
|
|
9
|
+
* `.ts-card-title`, `.ts-card-name` …); the KPI grid grammar ships as
|
|
10
|
+
* TearsheetCardKpis / TearsheetCardKpi. Server components — no state.
|
|
11
|
+
*/
|
|
12
|
+
import type { AnchorHTMLAttributes, ReactNode } from "react";
|
|
13
|
+
|
|
14
|
+
export interface TearsheetCardProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
15
|
+
/** Renders an anchor when set; a plain div card otherwise. */
|
|
16
|
+
href?: string;
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function TearsheetCard({ href, className, children, ...rest }: TearsheetCardProps) {
|
|
21
|
+
const cls = "ts-card" + (className ? ` ${className}` : "");
|
|
22
|
+
if (href) {
|
|
23
|
+
return (
|
|
24
|
+
<a className={cls} href={href} {...rest}>
|
|
25
|
+
{children}
|
|
26
|
+
</a>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return <div className={cls}>{children}</div>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The 2-column KPI grid inside a card (`.ts-card-kpis`). */
|
|
33
|
+
export function TearsheetCardKpis({
|
|
34
|
+
children,
|
|
35
|
+
className,
|
|
36
|
+
}: {
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
className?: string;
|
|
39
|
+
}) {
|
|
40
|
+
return (
|
|
41
|
+
<div className={"ts-card-kpis" + (className ? ` ${className}` : "")}>{children}</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** One label-over-value cell in the card KPI grid. Values are ReactNodes so
|
|
46
|
+
* consumers tone them with the money classes (`toneClass`). */
|
|
47
|
+
export function TearsheetCardKpi({ label, value }: { label: string; value: ReactNode }) {
|
|
48
|
+
return (
|
|
49
|
+
<div className="ts-card-kpi">
|
|
50
|
+
<span className="ts-card-kpi-label">{label}</span>
|
|
51
|
+
<span className="ts-card-kpi-value">{value}</span>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TradeLogTable + DirectionPill (#1463) — the tearsheet table grammar
|
|
3
|
+
* promoted from the inline TradeLogTable in
|
|
4
|
+
* apps/digiquant-web/components/tearsheet/tearsheet-view.tsx, generalized
|
|
5
|
+
* to ReactNode cells so consumers keep their own cell wiring (unrealized-mark
|
|
6
|
+
* cells, toned figures, conviction badges …). The dress is the shared
|
|
7
|
+
* `.ts-table` grammar: sticky mono thead inside a scroll clamp on screen; in
|
|
8
|
+
* print the clamp opens (`max-height: none`), the head goes static, and rows
|
|
9
|
+
* carry `break-inside: avoid` (styles/finance-tearsheet.css). An `open` row
|
|
10
|
+
* wears `.ts-trade-open` — the accent-washed live-position state. Server
|
|
11
|
+
* component — no state, no effects.
|
|
12
|
+
*/
|
|
13
|
+
import type { ReactNode } from "react";
|
|
14
|
+
|
|
15
|
+
export interface TradeLogColumn {
|
|
16
|
+
label: ReactNode;
|
|
17
|
+
/** Right-aligned numeric column (`.ts-num`). */
|
|
18
|
+
numeric?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface TradeLogRow {
|
|
22
|
+
key: string | number;
|
|
23
|
+
/** Live open position — row wears the `.ts-trade-open` state. */
|
|
24
|
+
open?: boolean;
|
|
25
|
+
/** One ReactNode per column, in column order. */
|
|
26
|
+
cells: ReactNode[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface TradeLogTableProps {
|
|
30
|
+
columns: TradeLogColumn[];
|
|
31
|
+
rows: TradeLogRow[];
|
|
32
|
+
/** Extra classes on the scroll wrapper. */
|
|
33
|
+
className?: string;
|
|
34
|
+
/** Accessible name for the table — no visible <caption> is used by
|
|
35
|
+
* design (the page's own heading carries that role), so this becomes
|
|
36
|
+
* the table's aria-label. */
|
|
37
|
+
ariaLabel?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function TradeLogTable({ columns, rows, className, ariaLabel = "Trade log" }: TradeLogTableProps) {
|
|
41
|
+
return (
|
|
42
|
+
<div className={"ts-table-wrap ts-table-scroll" + (className ? ` ${className}` : "")}>
|
|
43
|
+
<table className="ts-table ts-trades" aria-label={ariaLabel}>
|
|
44
|
+
<thead>
|
|
45
|
+
<tr>
|
|
46
|
+
{columns.map((c, i) => (
|
|
47
|
+
<th key={i} scope="col" className={c.numeric ? "ts-num" : undefined}>
|
|
48
|
+
{c.label}
|
|
49
|
+
</th>
|
|
50
|
+
))}
|
|
51
|
+
</tr>
|
|
52
|
+
</thead>
|
|
53
|
+
<tbody>
|
|
54
|
+
{rows.map((r) => (
|
|
55
|
+
<tr key={r.key} className={r.open ? "ts-trade-open" : undefined}>
|
|
56
|
+
{r.cells.map((cell, i) => (
|
|
57
|
+
<td key={i} className={columns[i]?.numeric ? "ts-num" : undefined}>
|
|
58
|
+
{cell}
|
|
59
|
+
</td>
|
|
60
|
+
))}
|
|
61
|
+
</tr>
|
|
62
|
+
))}
|
|
63
|
+
</tbody>
|
|
64
|
+
</table>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Long/short direction pill (`.ts-dir`) — long wears --up, short --down.
|
|
70
|
+
* Copy is always lowercase (long / short, not LONG). */
|
|
71
|
+
export function DirectionPill({ direction }: { direction: "long" | "short" }) {
|
|
72
|
+
return <span className={`ts-dir ts-dir-${direction}`}>{direction}</span>;
|
|
73
|
+
}
|