@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,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContactMailto — the shared Cloudflare-safe `mailto:` link, promoted from
|
|
3
|
+
* the three forks that grew one per app (`apps/digithings-web`,
|
|
4
|
+
* `apps/digiquant-web`, `apps/digichat`, issues #2220/#2226).
|
|
5
|
+
*
|
|
6
|
+
* Cloudflare's Email Address Obfuscation (Scrape Shield) rewrites any
|
|
7
|
+
* literal `mailto:` href — and any bare visible address — in the HTML it
|
|
8
|
+
* actually serves, so React's hydration payload disagrees with the real DOM.
|
|
9
|
+
* This component renders with no literal `mailto:` string or bare address in
|
|
10
|
+
* the initial HTML at all (no href server-side; the real href — and, for
|
|
11
|
+
* `showAddress`, the address text — assigned after the hydration-safe client
|
|
12
|
+
* mount flag flips), giving the edge rewriter nothing to rewrite.
|
|
13
|
+
*
|
|
14
|
+
* Real users with JS get a working mailto: link; without JS the link is
|
|
15
|
+
* inert (dimmed, aria-disabled). `showAddress` callers must still pass
|
|
16
|
+
* `children` — the server-rendered fallback text and accessible name until
|
|
17
|
+
* the mount swap. Omitting `children` entirely leaves the link empty until
|
|
18
|
+
* JS runs: acceptable only on JS-required surfaces (the digichat embed),
|
|
19
|
+
* never on static marketing pages.
|
|
20
|
+
*
|
|
21
|
+
* Utility-classed (pending dim only); consuming apps need an `@source` line
|
|
22
|
+
* for this directory (MIGRATION.md rule 3).
|
|
23
|
+
*/
|
|
24
|
+
"use client";
|
|
25
|
+
|
|
26
|
+
import { useCallback, useSyncExternalStore } from "react";
|
|
27
|
+
import type { CSSProperties, MouseEvent, ReactNode } from "react";
|
|
28
|
+
|
|
29
|
+
import { cx } from "../../lib/cx";
|
|
30
|
+
|
|
31
|
+
/** Pure so the query-string assembly is unit-testable without rendering. */
|
|
32
|
+
export function buildMailtoHref(email: string, subject?: string): string {
|
|
33
|
+
const query = subject ? `?subject=${subject}` : "";
|
|
34
|
+
return `mailto:${email}${query}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Baked into the JSX unconditionally rather than a new app-local CSS class —
|
|
38
|
+
// the frontend canon guard's family census rejects new classes in census
|
|
39
|
+
// app stylesheets; token-backed Tailwind utilities are not scanned.
|
|
40
|
+
const PENDING_CLASSES = ["opacity-50", "cursor-default"] as const;
|
|
41
|
+
|
|
42
|
+
const emptySubscribe = () => () => {};
|
|
43
|
+
const getMountedSnapshot = () => true;
|
|
44
|
+
const getServerSnapshot = () => false;
|
|
45
|
+
|
|
46
|
+
export function ContactMailto({
|
|
47
|
+
email,
|
|
48
|
+
subject,
|
|
49
|
+
showAddress = false,
|
|
50
|
+
className,
|
|
51
|
+
style,
|
|
52
|
+
ariaLabel,
|
|
53
|
+
children,
|
|
54
|
+
}: {
|
|
55
|
+
/** Appended as `?subject=<subject>` verbatim — callers pass it already
|
|
56
|
+
* URL-encoded. */
|
|
57
|
+
email: string;
|
|
58
|
+
subject?: string;
|
|
59
|
+
/** Swap `children` for the address itself once mounted, rather than
|
|
60
|
+
* passing the address as `children` directly (which would bake the bare
|
|
61
|
+
* address into the server-rendered text node). `children` is still
|
|
62
|
+
* required on static pages: the fallback text and accessible name. */
|
|
63
|
+
showAddress?: boolean;
|
|
64
|
+
className?: string;
|
|
65
|
+
style?: CSSProperties;
|
|
66
|
+
ariaLabel?: string;
|
|
67
|
+
children?: ReactNode;
|
|
68
|
+
}) {
|
|
69
|
+
// Server + first client hydration pass: false. After hydration: true.
|
|
70
|
+
// useSyncExternalStore, not setState-in-effect.
|
|
71
|
+
const mounted = useSyncExternalStore(
|
|
72
|
+
emptySubscribe,
|
|
73
|
+
getMountedSnapshot,
|
|
74
|
+
getServerSnapshot,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
if (
|
|
78
|
+
process.env.NODE_ENV !== "production" &&
|
|
79
|
+
showAddress &&
|
|
80
|
+
children == null
|
|
81
|
+
) {
|
|
82
|
+
// eslint-disable-next-line no-console
|
|
83
|
+
console.warn(
|
|
84
|
+
"ContactMailto with showAddress and no children renders an empty, " +
|
|
85
|
+
"unlabeled link until JS runs — pass fallback children on static pages.",
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const readyHref = mounted ? buildMailtoHref(email, subject) : null;
|
|
90
|
+
const addressText = mounted && showAddress ? email : null;
|
|
91
|
+
const pending = !mounted;
|
|
92
|
+
|
|
93
|
+
const onClick = useCallback(
|
|
94
|
+
(e: MouseEvent<HTMLAnchorElement>) => {
|
|
95
|
+
if (pending) e.preventDefault();
|
|
96
|
+
},
|
|
97
|
+
[pending],
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<a
|
|
102
|
+
{...(readyHref ? { href: readyHref } : {})}
|
|
103
|
+
className={cx(className, pending && PENDING_CLASSES.join(" "))}
|
|
104
|
+
style={style}
|
|
105
|
+
aria-label={ariaLabel}
|
|
106
|
+
aria-disabled={pending ? true : undefined}
|
|
107
|
+
onClick={onClick}
|
|
108
|
+
>
|
|
109
|
+
{addressText ?? children}
|
|
110
|
+
</a>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConvictionMeter — the single canonical UNSIGNED conviction encoding,
|
|
3
|
+
* promoted from `apps/dashboard/components/shared/conviction-meter.tsx`
|
|
4
|
+
* (dashboard F6 ruling, preserved verbatim): integer pips (max 3 for
|
|
5
|
+
* `positions.conviction`, max 4 for pre-scaled `theses.confidence`), filled
|
|
6
|
+
* pips `--accent`, empty pips `--hair`, accent the only color on its row
|
|
7
|
+
* (F5). Value is clamped and rounded; the redundant `aria-label` + `sr-only`
|
|
8
|
+
* pair and `data-filled` attributes are preserved for testability.
|
|
9
|
+
*
|
|
10
|
+
* Utility-classed (no family CSS); consuming apps need an `@source` line
|
|
11
|
+
* for this directory (MIGRATION.md rule 3).
|
|
12
|
+
*/
|
|
13
|
+
export function ConvictionMeter({
|
|
14
|
+
value,
|
|
15
|
+
max = 3,
|
|
16
|
+
srLabel,
|
|
17
|
+
}: {
|
|
18
|
+
value: number;
|
|
19
|
+
max?: number;
|
|
20
|
+
srLabel: string;
|
|
21
|
+
}) {
|
|
22
|
+
const filled = Math.max(0, Math.min(max, Math.round(value)));
|
|
23
|
+
return (
|
|
24
|
+
<span className="inline-flex items-center gap-1" role="img" aria-label={srLabel}>
|
|
25
|
+
{Array.from({ length: max }).map((_, i) => {
|
|
26
|
+
const isFilled = i < filled;
|
|
27
|
+
return (
|
|
28
|
+
<span
|
|
29
|
+
key={i}
|
|
30
|
+
data-filled={isFilled ? "true" : "false"}
|
|
31
|
+
className={`h-1.5 w-1.5 rounded-full ${
|
|
32
|
+
isFilled ? "bg-accent" : "bg-hair"
|
|
33
|
+
}`}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
})}
|
|
37
|
+
<span className="sr-only">{srLabel}</span>
|
|
38
|
+
</span>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SignedConvictionBadge — the SIGNED stance badge, promoted from
|
|
3
|
+
* `apps/dashboard/components/shared/signed-conviction-badge.tsx`
|
|
4
|
+
* (dashboard F6 ruling, logic verbatim): `decision_log.conviction`
|
|
5
|
+
* (−5..+5; maps to `AnalystPayload.conviction_score`, ge=-5 le=5 — render
|
|
6
|
+
* any signed int, do NOT clamp). Up-toned at zero and above, down-toned
|
|
7
|
+
* below zero: the strict signed-financial-value semantic (F5), never to be
|
|
8
|
+
* merged with the unsigned ConvictionMeter even when the two share a row.
|
|
9
|
+
* One intentional deviation from the dashboard source: `rounded-none` pins
|
|
10
|
+
* the utilitarian radius rule (visually no-op under preflight).
|
|
11
|
+
*
|
|
12
|
+
* Utility-classed (no family CSS); consuming apps need an `@source` line
|
|
13
|
+
* for this directory (MIGRATION.md rule 3).
|
|
14
|
+
*/
|
|
15
|
+
export function SignedConvictionBadge({ value }: { value: number }) {
|
|
16
|
+
const sign = value < 0 ? "−" : "+";
|
|
17
|
+
const tone = value < 0 ? "text-down border-down/35" : "text-up border-up/35";
|
|
18
|
+
return (
|
|
19
|
+
<span
|
|
20
|
+
className={`inline-flex items-center rounded-none border px-1.5 py-0.5 font-mono text-[11px] font-semibold tabular-nums ${tone}`}
|
|
21
|
+
>
|
|
22
|
+
{sign}
|
|
23
|
+
{Math.abs(value)}
|
|
24
|
+
</span>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conviction family barrel — the dashboard F6 vocabulary (unsigned meter +
|
|
3
|
+
* signed badge), promoted verbatim. Re-exported from the package barrel
|
|
4
|
+
* (src/index.ts).
|
|
5
|
+
*/
|
|
6
|
+
export { ConvictionMeter } from "./ConvictionMeter";
|
|
7
|
+
export { SignedConvictionBadge } from "./SignedConvictionBadge";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* BentoGrid + BentoCell — the asymmetric bento layout promoted from the design
|
|
5
|
+
* reference (layout-patterns/bento-grid): a 4-column grid where cell weight
|
|
6
|
+
* signals hierarchy — `hero` anchors 2×2, `wide` runs two columns, `tall` two
|
|
7
|
+
* rows, `unit` takes one. Each cell may scope a module livery (`accent-<id>`,
|
|
8
|
+
* declared in @digithings-ai/design/tokens.css) that tints the ::before hover
|
|
9
|
+
* hairline and the hero wash (styles/data-layout.css). Content is entirely
|
|
10
|
+
* children-driven — the cell only owns the frame; a heading inside a hero cell
|
|
11
|
+
* should carry the `bento-name` class to pick up the hero's larger type.
|
|
12
|
+
* Collapses to one column below 760px. Server components — no state.
|
|
13
|
+
*
|
|
14
|
+
* Wiring (in the consuming app):
|
|
15
|
+
* globals.css @import "@digithings-ai/ui/styles/data-layout.css";
|
|
16
|
+
* @source "<path-to>/packages/ui/src/components/data-layout";
|
|
17
|
+
*/
|
|
18
|
+
export type BentoSpan = "hero" | "wide" | "tall" | "unit";
|
|
19
|
+
|
|
20
|
+
export function BentoGrid({
|
|
21
|
+
children,
|
|
22
|
+
className,
|
|
23
|
+
}: {
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
className?: string;
|
|
26
|
+
}) {
|
|
27
|
+
return <div className={`bento-grid${className ? ` ${className}` : ""}`}>{children}</div>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function BentoCell({
|
|
31
|
+
span = "unit",
|
|
32
|
+
livery,
|
|
33
|
+
className,
|
|
34
|
+
children,
|
|
35
|
+
}: {
|
|
36
|
+
/** Cell weight — hero 2×2, wide 2×1, tall 1×2, unit 1×1. */
|
|
37
|
+
span?: BentoSpan;
|
|
38
|
+
/** Optional module livery scope — suffix of an `accent-<module>` class. */
|
|
39
|
+
livery?: string;
|
|
40
|
+
className?: string;
|
|
41
|
+
children: ReactNode;
|
|
42
|
+
}) {
|
|
43
|
+
return (
|
|
44
|
+
<article
|
|
45
|
+
className={`bento-cell flex flex-col justify-between rounded-none border border-hair p-[1.1rem] bento-${span}${
|
|
46
|
+
livery ? ` accent-${livery}` : ""
|
|
47
|
+
}${className ? ` ${className}` : ""}`}
|
|
48
|
+
>
|
|
49
|
+
{children}
|
|
50
|
+
</article>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Children, useCallback, useEffect, useRef, useState, type ReactNode } from "react";
|
|
4
|
+
import { IconButton } from "../../ui";
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
import { clamp, nearestIndex } from "../effects-chrome/horizontal-track-core";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* CardRail — a horizontal rail of cards on NATIVE scroll-snap: swipe, wheel,
|
|
10
|
+
* arrow keys, or the prev / next buttons (one card per press). Edge fades read
|
|
11
|
+
* the strip as continuing past the frame. No pin, no transform, no JS needed to
|
|
12
|
+
* scroll — the buttons are an enhancement over a fully working native rail.
|
|
13
|
+
*
|
|
14
|
+
* Re-authored from the design reference's changelog rail (and the refactor
|
|
15
|
+
* branch's rail) as a utilities-only part: no CSS sheet, no `.cr-*` classes.
|
|
16
|
+
* The edge fade is a mask over token stops (alpha only, no raw colour).
|
|
17
|
+
*
|
|
18
|
+
* Each child is wrapped in a `role="listitem"` snap target. The wrapper carries
|
|
19
|
+
* `data-active="true"` on the card at the leading edge (a `group/card`, so a
|
|
20
|
+
* child can style `group-data-[active=true]/card:border-accent` without the rail
|
|
21
|
+
* knowing anything about it). The wrapper is not a tab stop — put links and
|
|
22
|
+
* buttons inside the cards; focusing one scrolls the rail natively. The track
|
|
23
|
+
* itself is focusable so a keyboard user can scroll it with the arrow keys.
|
|
24
|
+
*
|
|
25
|
+
* Reveal-safe: the track carries vertical padding so a `Reveal` child's rise
|
|
26
|
+
* (translateY) is not clipped by the rail's overflow, and wrappers never
|
|
27
|
+
* transform. With no JS and under reduced motion every card is reachable.
|
|
28
|
+
*
|
|
29
|
+
* Stepping is instant under `prefers-reduced-motion` (CSS `scroll-behavior`
|
|
30
|
+
* smooth is applied only when motion is allowed).
|
|
31
|
+
*
|
|
32
|
+
* Wiring (in the consuming app):
|
|
33
|
+
* globals.css @source "<path-to>/packages/ui/src/components/data-layout";
|
|
34
|
+
*/
|
|
35
|
+
export type CardRailProps = {
|
|
36
|
+
/** The cards. Each direct child becomes one snap item. */
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
/** Accessible name for the scroll region, e.g. "Strategy tearsheets". */
|
|
39
|
+
ariaLabel: string;
|
|
40
|
+
/** Left of the prev / next buttons (a title, a count). */
|
|
41
|
+
header?: ReactNode;
|
|
42
|
+
/** Classes on each snap-item wrapper (sets the card width). */
|
|
43
|
+
itemClassName?: string;
|
|
44
|
+
/** Classes on the outermost element. */
|
|
45
|
+
className?: string;
|
|
46
|
+
/** Accessible names for the two buttons. */
|
|
47
|
+
prevLabel?: string;
|
|
48
|
+
nextLabel?: string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Alpha stops through a token — a mask reads alpha only, so no raw colour.
|
|
52
|
+
const FADE =
|
|
53
|
+
"[mask-image:linear-gradient(90deg,transparent,var(--ink)_1.5rem,var(--ink)_calc(100%_-_1.5rem),transparent)]";
|
|
54
|
+
|
|
55
|
+
function offsetsOf(track: HTMLElement): number[] {
|
|
56
|
+
const kids = Array.from(track.children).filter((c): c is HTMLElement => c instanceof HTMLElement);
|
|
57
|
+
const base = kids[0]?.offsetLeft ?? 0;
|
|
58
|
+
return kids.map((k) => k.offsetLeft - base);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function CardRail({
|
|
62
|
+
children,
|
|
63
|
+
ariaLabel,
|
|
64
|
+
header,
|
|
65
|
+
itemClassName,
|
|
66
|
+
className,
|
|
67
|
+
prevLabel = "Previous card",
|
|
68
|
+
nextLabel = "Next card",
|
|
69
|
+
}: CardRailProps) {
|
|
70
|
+
const trackRef = useRef<HTMLDivElement | null>(null);
|
|
71
|
+
const items = Children.toArray(children);
|
|
72
|
+
const [active, setActive] = useState(0);
|
|
73
|
+
const [atStart, setAtStart] = useState(true);
|
|
74
|
+
const [atEnd, setAtEnd] = useState(false);
|
|
75
|
+
|
|
76
|
+
const sync = useCallback(() => {
|
|
77
|
+
const el = trackRef.current;
|
|
78
|
+
if (!el) return;
|
|
79
|
+
setAtStart(el.scrollLeft <= 1);
|
|
80
|
+
setAtEnd(el.scrollLeft + el.clientWidth >= el.scrollWidth - 1);
|
|
81
|
+
setActive(nearestIndex(offsetsOf(el), el.scrollLeft));
|
|
82
|
+
}, []);
|
|
83
|
+
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
const el = trackRef.current;
|
|
86
|
+
if (!el) return;
|
|
87
|
+
sync();
|
|
88
|
+
el.addEventListener("scroll", sync, { passive: true });
|
|
89
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
|
|
90
|
+
observer?.observe(el);
|
|
91
|
+
return () => {
|
|
92
|
+
el.removeEventListener("scroll", sync);
|
|
93
|
+
observer?.disconnect();
|
|
94
|
+
};
|
|
95
|
+
}, [sync, items.length]);
|
|
96
|
+
|
|
97
|
+
const step = (direction: 1 | -1) => {
|
|
98
|
+
const el = trackRef.current;
|
|
99
|
+
if (!el) return;
|
|
100
|
+
const offsets = offsetsOf(el);
|
|
101
|
+
const next = clamp(active + direction, 0, offsets.length - 1);
|
|
102
|
+
el.scrollTo({ left: offsets[next] ?? 0 });
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<div className={cn("grid min-w-0 gap-3", className)} data-card-rail="">
|
|
107
|
+
<div className="flex items-end justify-between gap-4">
|
|
108
|
+
<div className="min-w-0">{header}</div>
|
|
109
|
+
<div className="flex shrink-0 gap-[0.4rem]">
|
|
110
|
+
<IconButton
|
|
111
|
+
aria-label={prevLabel}
|
|
112
|
+
onClick={() => step(-1)}
|
|
113
|
+
disabled={atStart}
|
|
114
|
+
className="border border-hair"
|
|
115
|
+
>
|
|
116
|
+
<span aria-hidden="true">{"←"}</span>
|
|
117
|
+
</IconButton>
|
|
118
|
+
<IconButton
|
|
119
|
+
aria-label={nextLabel}
|
|
120
|
+
onClick={() => step(1)}
|
|
121
|
+
disabled={atEnd}
|
|
122
|
+
className="border border-hair"
|
|
123
|
+
>
|
|
124
|
+
<span aria-hidden="true">{"→"}</span>
|
|
125
|
+
</IconButton>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
<div className={cn("min-w-0", FADE)}>
|
|
129
|
+
<div
|
|
130
|
+
ref={trackRef}
|
|
131
|
+
role="list"
|
|
132
|
+
aria-label={ariaLabel}
|
|
133
|
+
tabIndex={0}
|
|
134
|
+
className="flex snap-x snap-mandatory gap-4 overflow-x-auto scroll-ps-6 px-6 py-4 outline-none [scrollbar-width:none] motion-safe:scroll-smooth focus-visible:outline focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-accent [&::-webkit-scrollbar]:hidden"
|
|
135
|
+
>
|
|
136
|
+
{items.map((child, i) => (
|
|
137
|
+
<div
|
|
138
|
+
key={i}
|
|
139
|
+
role="listitem"
|
|
140
|
+
data-active={i === active ? "true" : undefined}
|
|
141
|
+
className={cn("group/card relative flex-none snap-start w-[min(82vw,17rem)]", itemClassName)}
|
|
142
|
+
>
|
|
143
|
+
{child}
|
|
144
|
+
</div>
|
|
145
|
+
))}
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DotMatrixStat — a single metric rendered as a hardware-style LED grid,
|
|
3
|
+
* promoted from the design reference (data/dot-matrix-stat). A cols×rows
|
|
4
|
+
* field of dots lights the first N to encode a percentage, paired with a
|
|
5
|
+
* mono label / value / note column. The lit dots wear the module accent
|
|
6
|
+
* (scope with an `accent-<module>` livery class via className) and glow.
|
|
7
|
+
* The dot field is pure CSS/DOM — no canvas — and decorative (aria-hidden);
|
|
8
|
+
* the value is real text. Server component — no state, no effects.
|
|
9
|
+
*
|
|
10
|
+
* Wiring (in the consuming app):
|
|
11
|
+
* globals.css @import "@digithings-ai/ui/styles/data-layout.css";
|
|
12
|
+
* @source "<path-to>/packages/ui/src/components/data-layout";
|
|
13
|
+
*/
|
|
14
|
+
export type DotMatrixStatProps = {
|
|
15
|
+
/** Mono micro-caps label above the value — "Signal confidence". */
|
|
16
|
+
label: string;
|
|
17
|
+
/** The figure itself, preformatted — "67%". */
|
|
18
|
+
value: string;
|
|
19
|
+
/** Percentage of the field to light, 0–100. */
|
|
20
|
+
percent: number;
|
|
21
|
+
/** One quiet sentence under the value. */
|
|
22
|
+
note?: string;
|
|
23
|
+
/** Dot columns in the LED field. */
|
|
24
|
+
cols?: number;
|
|
25
|
+
/** Dot rows in the LED field. */
|
|
26
|
+
rows?: number;
|
|
27
|
+
className?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function DotMatrixStat({
|
|
31
|
+
label,
|
|
32
|
+
value,
|
|
33
|
+
percent,
|
|
34
|
+
note,
|
|
35
|
+
cols = 12,
|
|
36
|
+
rows = 8,
|
|
37
|
+
className,
|
|
38
|
+
}: DotMatrixStatProps) {
|
|
39
|
+
const total = cols * rows;
|
|
40
|
+
const lit = Math.min(total, Math.max(0, Math.round((percent / 100) * total)));
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
className={`grid grid-cols-[180px_1fr] gap-[1.1rem] rounded-none border border-hair bg-surface p-[1.1rem] max-[900px]:grid-cols-1${
|
|
44
|
+
className ? ` ${className}` : ""
|
|
45
|
+
}`}
|
|
46
|
+
>
|
|
47
|
+
<div
|
|
48
|
+
className="dms-grid"
|
|
49
|
+
style={{ gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` }}
|
|
50
|
+
aria-hidden="true"
|
|
51
|
+
>
|
|
52
|
+
{Array.from({ length: total }, (_, i) => (
|
|
53
|
+
<span key={i} className={i < lit ? "dms-dot on" : "dms-dot"} />
|
|
54
|
+
))}
|
|
55
|
+
</div>
|
|
56
|
+
<div>
|
|
57
|
+
<p className="font-mono text-[0.72rem] uppercase tracking-[0.08em] text-ink-mute">
|
|
58
|
+
{label}
|
|
59
|
+
</p>
|
|
60
|
+
<p className="mt-[0.2rem] font-mono text-[clamp(2rem,5vw,2.8rem)]">{value}</p>
|
|
61
|
+
{note ? <p className="mt-[0.55rem] max-w-[50ch] text-ink-soft">{note}</p> : null}
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* FeatureCell — the universal feature block promoted from the design reference
|
|
5
|
+
* (layout-patterns/feature-cell), the structure that repeats across graphite /
|
|
6
|
+
* cursor / x.ai and every band we ship: eyebrow → a short outcome headline →
|
|
7
|
+
* one sentence of mechanism → a quiet link → the product visual (children —
|
|
8
|
+
* typically a <ProductFrame/>). Each cell may scope a module livery
|
|
9
|
+
* (`accent-<module>`) that tints the eyebrow and link. Stack cells as direct
|
|
10
|
+
* siblings and even-numbered ones swap copy/visual columns automatically
|
|
11
|
+
* (`:nth-child(even)` in styles/data-layout.css); everything collapses to one
|
|
12
|
+
* column below 760px. Server component — no state, no effects.
|
|
13
|
+
*
|
|
14
|
+
* Wiring (in the consuming app):
|
|
15
|
+
* globals.css @import "@digithings-ai/ui/styles/data-layout.css";
|
|
16
|
+
* @source "<path-to>/packages/ui/src/components/data-layout";
|
|
17
|
+
*/
|
|
18
|
+
export type FeatureCellProps = {
|
|
19
|
+
/** Mono micro-caps eyebrow above the headline — "research". */
|
|
20
|
+
eyebrow: string;
|
|
21
|
+
/** The outcome headline, 4–8 words. */
|
|
22
|
+
outcome: string;
|
|
23
|
+
/** One sentence of mechanism under the headline. */
|
|
24
|
+
mechanism: string;
|
|
25
|
+
/** Destination of the quiet link; omit to drop the link. */
|
|
26
|
+
href?: string;
|
|
27
|
+
/** Link copy. */
|
|
28
|
+
linkLabel?: string;
|
|
29
|
+
/** Overrides the link's accessible name — set this when two cells on the
|
|
30
|
+
* same page would otherwise share identical link text (and, as in the
|
|
31
|
+
* reference demo, an identical href): screen readers announce links by
|
|
32
|
+
* their accessible name, so two indistinguishable "Learn more" links
|
|
33
|
+
* read as one ambiguous link repeated. */
|
|
34
|
+
linkAriaLabel?: string;
|
|
35
|
+
/** Optional module livery scope — suffix of an `accent-<module>` class. */
|
|
36
|
+
livery?: string;
|
|
37
|
+
className?: string;
|
|
38
|
+
/** The product visual — typically a <ProductFrame/> crop. */
|
|
39
|
+
children?: ReactNode;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export function FeatureCell({
|
|
43
|
+
eyebrow,
|
|
44
|
+
outcome,
|
|
45
|
+
mechanism,
|
|
46
|
+
href,
|
|
47
|
+
linkLabel = "Learn more",
|
|
48
|
+
linkAriaLabel,
|
|
49
|
+
livery,
|
|
50
|
+
className,
|
|
51
|
+
children,
|
|
52
|
+
}: FeatureCellProps) {
|
|
53
|
+
return (
|
|
54
|
+
<article
|
|
55
|
+
className={`fc-cell grid grid-cols-[minmax(0,1fr)_minmax(0,1.1fr)] items-center gap-[1.6rem] rounded-none border border-hair bg-surface p-[1.6rem] max-[760px]:grid-cols-1${
|
|
56
|
+
livery ? ` accent-${livery}` : ""
|
|
57
|
+
}${className ? ` ${className}` : ""}`}
|
|
58
|
+
>
|
|
59
|
+
<div className="fc-copy">
|
|
60
|
+
<p className="font-mono text-[0.62rem] uppercase tracking-[0.12em] text-accent">
|
|
61
|
+
{eyebrow}
|
|
62
|
+
</p>
|
|
63
|
+
<h3 className="mt-[0.5rem] font-display font-normal text-[clamp(1.3rem,2.6vw,1.7rem)] tracking-[-0.013em] leading-[1.12] text-ink">
|
|
64
|
+
{outcome}
|
|
65
|
+
</h3>
|
|
66
|
+
<p className="mt-[0.6rem] max-w-[42ch] text-[0.92rem] text-ink-soft">{mechanism}</p>
|
|
67
|
+
{href ? (
|
|
68
|
+
<a
|
|
69
|
+
className="fc-link mt-[0.9rem] inline-block font-mono text-[0.72rem] text-accent no-underline"
|
|
70
|
+
href={href}
|
|
71
|
+
aria-label={linkAriaLabel}
|
|
72
|
+
>
|
|
73
|
+
{linkLabel} <span aria-hidden="true">→</span>
|
|
74
|
+
</a>
|
|
75
|
+
) : null}
|
|
76
|
+
</div>
|
|
77
|
+
{children}
|
|
78
|
+
</article>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { cn } from "../../lib/utils";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MediaFrame — a 16:9 framed artboard for a recording (video) or a still
|
|
5
|
+
* (image), wearing the terminal chrome: a title row of bracketed micro-labels,
|
|
6
|
+
* a REQUIRED honesty `badge`, the media, and a caption row. Props-driven and
|
|
7
|
+
* honest: it shows only the `src` it is given.
|
|
8
|
+
*
|
|
9
|
+
* Without `src` it renders a designed placeholder, not a bare dashed box: the
|
|
10
|
+
* title bar, a faint hairline grid, viewfinder corner ticks, a disabled play
|
|
11
|
+
* glyph, and the caller's `placeholderLabel` ("recording to come") centred. A
|
|
12
|
+
* `--:--:--` timecode stands in for a length it does not know.
|
|
13
|
+
*
|
|
14
|
+
* With `src` (kind "video", the default) it renders a native `<video>` with
|
|
15
|
+
* controls, `muted`, `playsInline`, `preload="none"` and the optional `poster`;
|
|
16
|
+
* it NEVER autoplays, so reduced motion and data-saver users get a still until
|
|
17
|
+
* they press play. kind "image" renders an `<img>` (alt = caption) instead.
|
|
18
|
+
*
|
|
19
|
+
* Utilities-only server component: no CSS sheet, no keyframes, no state, no
|
|
20
|
+
* motion. Tokens only (grid lines are `--hair`, wash is `--surface`).
|
|
21
|
+
*
|
|
22
|
+
* Wiring (in the consuming app):
|
|
23
|
+
* globals.css @source "<path-to>/packages/ui/src/components/data-layout";
|
|
24
|
+
*/
|
|
25
|
+
export type MediaFrameProps = {
|
|
26
|
+
/** Video (or image) URL. Omit for the placeholder state. */
|
|
27
|
+
src?: string;
|
|
28
|
+
/** Poster still for a video. */
|
|
29
|
+
poster?: string;
|
|
30
|
+
/** What the media shows — caption row, accessible name, image alt. */
|
|
31
|
+
caption: string;
|
|
32
|
+
/** Centred label of the placeholder state, e.g. "recording to come". */
|
|
33
|
+
placeholderLabel: string;
|
|
34
|
+
/** Title-row label, e.g. "dashboard walkthrough". */
|
|
35
|
+
title: string;
|
|
36
|
+
/** REQUIRED honesty badge in the chrome, e.g. "Placeholder · no recording yet". */
|
|
37
|
+
badge: string;
|
|
38
|
+
/** "video" (default) or "image". */
|
|
39
|
+
kind?: "video" | "image";
|
|
40
|
+
className?: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const CORNER = "pointer-events-none absolute size-3 border-ink-mute";
|
|
44
|
+
|
|
45
|
+
export function MediaFrame({
|
|
46
|
+
src,
|
|
47
|
+
poster,
|
|
48
|
+
caption,
|
|
49
|
+
placeholderLabel,
|
|
50
|
+
title,
|
|
51
|
+
badge,
|
|
52
|
+
kind = "video",
|
|
53
|
+
className,
|
|
54
|
+
}: MediaFrameProps) {
|
|
55
|
+
return (
|
|
56
|
+
<figure
|
|
57
|
+
data-slot="media-frame"
|
|
58
|
+
data-state={src ? "media" : "placeholder"}
|
|
59
|
+
className={cn("m-0 min-w-0 border border-hair bg-surface font-mono", className)}
|
|
60
|
+
>
|
|
61
|
+
<div className="flex items-center gap-3 border-b border-hair px-3 py-2 text-[0.68rem] tracking-[0.04em] text-ink-mute">
|
|
62
|
+
<span aria-hidden="true">{kind === "image" ? "[image]" : "[video]"}</span>
|
|
63
|
+
<span className="min-w-0 flex-1 truncate text-ink-soft">{title}</span>
|
|
64
|
+
<span className="shrink-0" aria-hidden="true">
|
|
65
|
+
{src ? "[ready]" : "[empty]"}
|
|
66
|
+
</span>
|
|
67
|
+
</div>
|
|
68
|
+
<div className="border-b border-hair px-3 py-1.5 text-[0.66rem] text-ink-soft" data-slot="media-frame-badge">
|
|
69
|
+
{`◇ ${badge}`}
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<div className="relative aspect-video w-full overflow-hidden bg-term-bg">
|
|
73
|
+
{src ? (
|
|
74
|
+
kind === "image" ? (
|
|
75
|
+
// Note: plain <img> is intentional — package part, no next/image dependency.
|
|
76
|
+
// (No next lint plugin runs on packages, so no disable directive here.)
|
|
77
|
+
<img src={src} alt={caption} className="absolute inset-0 size-full object-cover" />
|
|
78
|
+
) : (
|
|
79
|
+
<video
|
|
80
|
+
className="absolute inset-0 size-full object-cover"
|
|
81
|
+
src={src}
|
|
82
|
+
poster={poster}
|
|
83
|
+
controls
|
|
84
|
+
muted
|
|
85
|
+
playsInline
|
|
86
|
+
preload="none"
|
|
87
|
+
aria-label={caption}
|
|
88
|
+
/>
|
|
89
|
+
)
|
|
90
|
+
) : (
|
|
91
|
+
<div role="img" aria-label={`${placeholderLabel}: ${caption}`} className="absolute inset-0">
|
|
92
|
+
<div
|
|
93
|
+
aria-hidden="true"
|
|
94
|
+
className="absolute inset-0 opacity-50 [background-image:linear-gradient(var(--hair)_1px,transparent_1px),linear-gradient(90deg,var(--hair)_1px,transparent_1px)] [background-size:2.5rem_2.5rem]"
|
|
95
|
+
/>
|
|
96
|
+
<span aria-hidden="true" className={cn(CORNER, "start-3 top-3 border-s border-t")} />
|
|
97
|
+
<span aria-hidden="true" className={cn(CORNER, "end-3 top-3 border-e border-t")} />
|
|
98
|
+
<span aria-hidden="true" className={cn(CORNER, "bottom-3 start-3 border-b border-s")} />
|
|
99
|
+
<span aria-hidden="true" className={cn(CORNER, "bottom-3 end-3 border-b border-e")} />
|
|
100
|
+
<div aria-hidden="true" className="absolute inset-0 grid place-content-center justify-items-center gap-3">
|
|
101
|
+
<button
|
|
102
|
+
type="button"
|
|
103
|
+
disabled
|
|
104
|
+
tabIndex={-1}
|
|
105
|
+
className="grid size-12 cursor-not-allowed place-items-center border border-hair bg-surface text-[1rem] text-ink-mute opacity-80"
|
|
106
|
+
>
|
|
107
|
+
▶
|
|
108
|
+
</button>
|
|
109
|
+
<span className="border border-hair bg-surface px-3 py-1 text-[0.72rem] tracking-[0.06em] text-ink-soft">
|
|
110
|
+
{`[ ${placeholderLabel} ]`}
|
|
111
|
+
</span>
|
|
112
|
+
</div>
|
|
113
|
+
<span aria-hidden="true" className="absolute bottom-3 start-8 text-[0.62rem] tracking-[0.08em] text-ink-mute">
|
|
114
|
+
--:--:--
|
|
115
|
+
</span>
|
|
116
|
+
</div>
|
|
117
|
+
)}
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<figcaption className="border-t border-hair px-3 py-2 text-[0.72rem] leading-[1.5] text-ink-soft">
|
|
121
|
+
{caption}
|
|
122
|
+
</figcaption>
|
|
123
|
+
</figure>
|
|
124
|
+
);
|
|
125
|
+
}
|