@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,123 @@
|
|
|
1
|
+
import type { RepoPullItem } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* One UTC day of contribution history. `count` is the total; the three source
|
|
5
|
+
* fields are the split behind it, present only when the caller bucketed them
|
|
6
|
+
* (`bucketContributions`). The heat cell's `title` reads the split so hovering a
|
|
7
|
+
* square says where the day's work came from, not just how much there was.
|
|
8
|
+
*/
|
|
9
|
+
export type HeatDay = {
|
|
10
|
+
date: string;
|
|
11
|
+
count: number;
|
|
12
|
+
pulls?: number;
|
|
13
|
+
commits?: number;
|
|
14
|
+
issues?: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const DAY_MS = 86_400_000;
|
|
18
|
+
|
|
19
|
+
/** Stamp → UTC calendar day (`2026-08-21T00:30:00+02:00` → `2026-08-20`); "" when absent. */
|
|
20
|
+
function dayOf(stamp: string | null | undefined): string {
|
|
21
|
+
if (!stamp) return "";
|
|
22
|
+
const ms = Date.parse(stamp);
|
|
23
|
+
return Number.isNaN(ms) ? "" : isoOf(ms);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function toUtcMidnight(d: Date): number {
|
|
27
|
+
return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isoOf(ms: number): string {
|
|
31
|
+
return new Date(ms).toISOString().slice(0, 10);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Bucket merged-PR merge dates into consecutive UTC days, oldest → newest.
|
|
36
|
+
* `weeks * 7` cells ending at `end` (default today). Pulls outside the window
|
|
37
|
+
* or without a date are ignored. Pure — safe for SSR and tests.
|
|
38
|
+
*/
|
|
39
|
+
export function bucketDaily(
|
|
40
|
+
pulls: RepoPullItem[],
|
|
41
|
+
weeks = 16,
|
|
42
|
+
end: Date = new Date(),
|
|
43
|
+
): HeatDay[] {
|
|
44
|
+
const safeWeeks = Math.max(1, Math.floor(weeks));
|
|
45
|
+
const endMs = toUtcMidnight(end);
|
|
46
|
+
const total = safeWeeks * 7;
|
|
47
|
+
const startMs = endMs - (total - 1) * DAY_MS;
|
|
48
|
+
const counts = new Map<string, number>();
|
|
49
|
+
for (const p of pulls) {
|
|
50
|
+
const day = dayOf(p.mergedAt);
|
|
51
|
+
if (!day) continue;
|
|
52
|
+
const ms = Date.parse(`${day}T00:00:00Z`);
|
|
53
|
+
if (Number.isNaN(ms) || ms < startMs || ms > endMs) continue;
|
|
54
|
+
counts.set(day, (counts.get(day) ?? 0) + 1);
|
|
55
|
+
}
|
|
56
|
+
const days: HeatDay[] = [];
|
|
57
|
+
for (let i = 0; i < total; i++) {
|
|
58
|
+
const date = isoOf(startMs + i * DAY_MS);
|
|
59
|
+
days.push({ date, count: counts.get(date) ?? 0 });
|
|
60
|
+
}
|
|
61
|
+
return days;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Bucket repo-level contributions (GitHub profile-graph style) into
|
|
66
|
+
* consecutive UTC days, oldest → newest. Sums merged PRs + commits +
|
|
67
|
+
* closed issues per day so the heat tracks contributions, not merges alone.
|
|
68
|
+
* Each source is an ISO timestamp (or null); undated or out-of-window
|
|
69
|
+
* entries are ignored. Pure — safe for SSR and tests.
|
|
70
|
+
*/
|
|
71
|
+
export function bucketContributions(
|
|
72
|
+
pulls: RepoPullItem[],
|
|
73
|
+
commits: Array<string | null | undefined> = [],
|
|
74
|
+
closedIssues: Array<string | null | undefined> = [],
|
|
75
|
+
weeks = 53,
|
|
76
|
+
end: Date = new Date(),
|
|
77
|
+
): HeatDay[] {
|
|
78
|
+
const safeWeeks = Math.max(1, Math.floor(weeks));
|
|
79
|
+
const endMs = toUtcMidnight(end);
|
|
80
|
+
const total = safeWeeks * 7;
|
|
81
|
+
const startMs = endMs - (total - 1) * DAY_MS;
|
|
82
|
+
const counts = new Map<string, number>();
|
|
83
|
+
const split = {
|
|
84
|
+
pulls: new Map<string, number>(),
|
|
85
|
+
commits: new Map<string, number>(),
|
|
86
|
+
issues: new Map<string, number>(),
|
|
87
|
+
};
|
|
88
|
+
const bump = (bucket: Map<string, number>, day: string) =>
|
|
89
|
+
bucket.set(day, (bucket.get(day) ?? 0) + 1);
|
|
90
|
+
const add = (bucket: Map<string, number>, stamp: string | null | undefined) => {
|
|
91
|
+
const day = dayOf(stamp);
|
|
92
|
+
if (!day) return;
|
|
93
|
+
const ms = Date.parse(`${day}T00:00:00Z`);
|
|
94
|
+
if (Number.isNaN(ms) || ms < startMs || ms > endMs) return;
|
|
95
|
+
counts.set(day, (counts.get(day) ?? 0) + 1);
|
|
96
|
+
bump(bucket, day);
|
|
97
|
+
};
|
|
98
|
+
for (const p of pulls) add(split.pulls, p.mergedAt);
|
|
99
|
+
for (const c of commits) add(split.commits, c);
|
|
100
|
+
for (const i of closedIssues) add(split.issues, i);
|
|
101
|
+
const days: HeatDay[] = [];
|
|
102
|
+
for (let i = 0; i < total; i++) {
|
|
103
|
+
const date = isoOf(startMs + i * DAY_MS);
|
|
104
|
+
days.push({
|
|
105
|
+
date,
|
|
106
|
+
count: counts.get(date) ?? 0,
|
|
107
|
+
pulls: split.pulls.get(date) ?? 0,
|
|
108
|
+
commits: split.commits.get(date) ?? 0,
|
|
109
|
+
issues: split.issues.get(date) ?? 0,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return days;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Accent step for a cell: 0 when empty, otherwise 1–4. Small maxima map
|
|
117
|
+
* 1:1; larger ones use quartiles so a single busy day cannot flatten the rest.
|
|
118
|
+
*/
|
|
119
|
+
export function levelFor(count: number, max: number): 0 | 1 | 2 | 3 | 4 {
|
|
120
|
+
if (count <= 0) return 0;
|
|
121
|
+
if (max <= 4) return Math.min(4, count) as 1 | 2 | 3 | 4;
|
|
122
|
+
return Math.min(4, Math.max(1, Math.ceil((count / max) * 4))) as 1 | 2 | 3 | 4;
|
|
123
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export {
|
|
2
|
+
RepoActivity,
|
|
3
|
+
type RepoActivityProps,
|
|
4
|
+
type RepoContributor,
|
|
5
|
+
type RepoModuleRelease,
|
|
6
|
+
} from "./RepoActivity";
|
|
7
|
+
export { RepoHeatmap, type RepoHeatmapProps } from "./RepoHeatmap";
|
|
8
|
+
export { bucketContributions, bucketDaily, levelFor, type HeatDay } from "./heatmap";
|
|
9
|
+
export { fetchRepoActivityLive, type FetchRepoActivityLiveOptions } from "./fetch";
|
|
10
|
+
export {
|
|
11
|
+
REPO_ACTIVITY_DEMO,
|
|
12
|
+
REPO_ACTIVITY_DEMO_CLONE,
|
|
13
|
+
REPO_ACTIVITY_DEMO_CONTRIBUTING,
|
|
14
|
+
REPO_ACTIVITY_DEMO_URL,
|
|
15
|
+
} from "./demo";
|
|
16
|
+
export {
|
|
17
|
+
cloneParts,
|
|
18
|
+
DEFAULT_LIVE_TIMEOUT_MS,
|
|
19
|
+
grouped,
|
|
20
|
+
isoDay,
|
|
21
|
+
type RepoActivityLiveConfig,
|
|
22
|
+
type RepoActivitySnapshot,
|
|
23
|
+
type RepoFeature,
|
|
24
|
+
type RepoIssueItem,
|
|
25
|
+
type RepoModuleActivity,
|
|
26
|
+
type RepoPullItem,
|
|
27
|
+
type RepoRelease,
|
|
28
|
+
} from "./types";
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot-first repository activity — the shared data contract for compact
|
|
3
|
+
* and detailed views. Velocity figures are windowed; backlog figures are not.
|
|
4
|
+
* Stars, forks and watchers are deliberately absent.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { HeatDay } from "./heatmap";
|
|
8
|
+
|
|
9
|
+
export type RepoRelease = {
|
|
10
|
+
tag: string;
|
|
11
|
+
name: string | null;
|
|
12
|
+
publishedAt: string;
|
|
13
|
+
url: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type RepoPullItem = {
|
|
17
|
+
number: number;
|
|
18
|
+
title: string;
|
|
19
|
+
url: string;
|
|
20
|
+
/** Merge time when known; closed_at is an acceptable proxy from Search. */
|
|
21
|
+
mergedAt: string | null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type RepoIssueItem = {
|
|
25
|
+
number: number;
|
|
26
|
+
title: string;
|
|
27
|
+
url: string;
|
|
28
|
+
updatedAt: string | null;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type RepoFeature = {
|
|
32
|
+
scope: string | null;
|
|
33
|
+
summary: string;
|
|
34
|
+
pr: number;
|
|
35
|
+
date: string | null;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type RepoModuleActivity = {
|
|
39
|
+
path: string;
|
|
40
|
+
lastCommit: string | null;
|
|
41
|
+
files: number;
|
|
42
|
+
lines: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* One snapshot object both variants render. `commits` / `pullsMerged` /
|
|
47
|
+
* `issuesClosed` cover `windowDays` on `branch`. `pullsOpen` / `issuesOpen`
|
|
48
|
+
* are the current backlog (unwindowed). `modules` and `features` are optional
|
|
49
|
+
* extras for hosts that already generate them; the views do not require them.
|
|
50
|
+
*/
|
|
51
|
+
export type RepoActivitySnapshot = {
|
|
52
|
+
generatedAt: string;
|
|
53
|
+
windowDays: number;
|
|
54
|
+
branch: string;
|
|
55
|
+
commits: number;
|
|
56
|
+
pullsMerged: number;
|
|
57
|
+
issuesClosed: number;
|
|
58
|
+
pullsOpen: number;
|
|
59
|
+
issuesOpen: number;
|
|
60
|
+
latestRelease: RepoRelease | null;
|
|
61
|
+
mergedPulls: RepoPullItem[];
|
|
62
|
+
openIssues: RepoIssueItem[];
|
|
63
|
+
/** Pre-bucketed per-day contributions for the heatmap (oldest → newest).
|
|
64
|
+
* Emitted by scripts/fetch_repo_activity.py; absent in older snapshots. */
|
|
65
|
+
dailyContributions?: HeatDay[];
|
|
66
|
+
features?: RepoFeature[];
|
|
67
|
+
modules?: Record<string, RepoModuleActivity | undefined>;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/** Live GitHub refresh — all-or-nothing; the component keeps the snapshot on any failure. */
|
|
71
|
+
export type RepoActivityLiveConfig = {
|
|
72
|
+
owner: string;
|
|
73
|
+
repo: string;
|
|
74
|
+
branch?: string;
|
|
75
|
+
windowDays?: number;
|
|
76
|
+
timeoutMs?: number;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const DEFAULT_LIVE_TIMEOUT_MS = 8_000;
|
|
80
|
+
|
|
81
|
+
/** `2026-08-06T12:34:56Z` → `2026-08-06`; empty string when absent. */
|
|
82
|
+
export function isoDay(stamp: string | null | undefined): string {
|
|
83
|
+
return stamp ? stamp.slice(0, 10) : "";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Thousands-separated, locale-stable so SSR and the browser cannot drift. */
|
|
87
|
+
export function grouped(n: number): string {
|
|
88
|
+
return n.toLocaleString("en-US");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Split a clone command at its last slash so a `<wbr/>` can sit after the org.
|
|
93
|
+
* Rejoining the halves must equal the copied payload.
|
|
94
|
+
*/
|
|
95
|
+
export function cloneParts(command: string): [string, string] {
|
|
96
|
+
const cut = command.lastIndexOf("/") + 1;
|
|
97
|
+
if (cut <= 0) return [command, ""];
|
|
98
|
+
return [command.slice(0, cut), command.slice(cut)];
|
|
99
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { m, useMotionSafe, EASE } from "../../motion/primitives";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* NumberedStages — the sequential-stage grammar promoted from the design
|
|
6
|
+
* reference (layout-patterns/numbered-stages): a numbered spine where each
|
|
7
|
+
* step is one move in the flow — big mono index badge, an optional mono
|
|
8
|
+
* micro-caps tag, a serif title, one sentence of mechanism. A hairline spine
|
|
9
|
+
* (`.ns-stage::before`, styles/stages.css) runs through the badge column and
|
|
10
|
+
* stops at the last stage; each stage may scope its own module livery via
|
|
11
|
+
* `livery` (`accent-<module>` — declared in @digithings-ai/design/tokens.css),
|
|
12
|
+
* which re-tints the badge's two-color color-mix and the tag/index text.
|
|
13
|
+
*
|
|
14
|
+
* Scroll cadence (#1450): stages fill the pipeline one at a time — each row
|
|
15
|
+
* rises in on its own whileInView with an index-staggered delay, so on a
|
|
16
|
+
* normal scroll the spine reads 01 → 02 → 03 → 04 in order. `animated={false}`
|
|
17
|
+
* opts a consumer out; reduced motion (useMotionSafe) and no-JS
|
|
18
|
+
* (html.no-js [data-motion]) render every stage visible with no animation.
|
|
19
|
+
*
|
|
20
|
+
* Alignment: the badge pill is 2rem tall; an untagged title's first line is
|
|
21
|
+
* flex-centered against that height so pill and title read as one row. With a
|
|
22
|
+
* `tag`, the tag takes the pill-aligned slot and the title stacks under it.
|
|
23
|
+
*
|
|
24
|
+
* Client component (Motion m.li under the app's MotionProvider). Wiring (in
|
|
25
|
+
* the consuming app):
|
|
26
|
+
* globals.css @import "@digithings-ai/ui/styles/stages.css";
|
|
27
|
+
* @source "<path-to>/packages/ui/src/components/stages";
|
|
28
|
+
*/
|
|
29
|
+
export type NumberedStage = {
|
|
30
|
+
/** Big mono index rendered in the spine badge — "1.0", "01", "a" … */
|
|
31
|
+
num: string;
|
|
32
|
+
/** Serif stage title. */
|
|
33
|
+
title: string;
|
|
34
|
+
/** One sentence of mechanism under the title. */
|
|
35
|
+
mech: string;
|
|
36
|
+
/** Optional mono micro-caps tag above the title (module name, phase …). */
|
|
37
|
+
tag?: string;
|
|
38
|
+
/** Optional module livery scope — suffix of an `accent-<module>` class. */
|
|
39
|
+
livery?: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export function NumberedStages({
|
|
43
|
+
stages,
|
|
44
|
+
className,
|
|
45
|
+
animated = true,
|
|
46
|
+
}: {
|
|
47
|
+
stages: NumberedStage[];
|
|
48
|
+
className?: string;
|
|
49
|
+
/** Sequential scroll fill (default). Pass false for a static spine. */
|
|
50
|
+
animated?: boolean;
|
|
51
|
+
}) {
|
|
52
|
+
const safe = useMotionSafe();
|
|
53
|
+
const fill = animated && safe;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<ol className={["grid list-none gap-0 p-0", className].filter(Boolean).join(" ")}>
|
|
57
|
+
{stages.map((s, i) => {
|
|
58
|
+
// Utilities live in clean string literals on purpose: a template hole
|
|
59
|
+
// butted against a candidate (`pb-[…]${`) hides it from Tailwind's
|
|
60
|
+
// scanner, so the utility is silently never generated — the original
|
|
61
|
+
// pb-[1.8rem] shipped un-compiled and the stages rendered with no
|
|
62
|
+
// inter-stage padding at all (#1450 round 3). 2.8rem is the ruled
|
|
63
|
+
// breathing room between a stage's blurb and the next stage's title;
|
|
64
|
+
// the spine ::before spans the padded box (styles/stages.css), so the
|
|
65
|
+
// connector stays continuous, and :last-child zeroes the trailing pad.
|
|
66
|
+
const liClass = [
|
|
67
|
+
"ns-stage relative grid grid-cols-[3.4rem_1fr] gap-[1.1rem] pb-[2.8rem]",
|
|
68
|
+
s.livery ? `accent-${s.livery}` : "",
|
|
69
|
+
]
|
|
70
|
+
.filter(Boolean)
|
|
71
|
+
.join(" ");
|
|
72
|
+
const content = (
|
|
73
|
+
<>
|
|
74
|
+
<span className="ns-node" aria-hidden="true">
|
|
75
|
+
{s.num}
|
|
76
|
+
</span>
|
|
77
|
+
<div className={s.tag ? "pt-[0.4rem]" : undefined}>
|
|
78
|
+
{s.tag ? (
|
|
79
|
+
<p className="font-mono text-[0.6rem] uppercase tracking-[0.12em] text-accent">
|
|
80
|
+
{s.tag}
|
|
81
|
+
</p>
|
|
82
|
+
) : null}
|
|
83
|
+
<h3
|
|
84
|
+
className={`${
|
|
85
|
+
s.tag ? "mt-[0.25rem]" : "flex min-h-[2rem] items-center"
|
|
86
|
+
} font-display font-normal text-[clamp(1.2rem,2.4vw,1.5rem)] leading-[1.25] tracking-[-0.013em] text-ink`}
|
|
87
|
+
>
|
|
88
|
+
{s.title}
|
|
89
|
+
</h3>
|
|
90
|
+
<p className="mt-[0.35rem] max-w-[52ch] text-[0.9rem] leading-[1.55] text-ink-soft">
|
|
91
|
+
{s.mech}
|
|
92
|
+
</p>
|
|
93
|
+
</div>
|
|
94
|
+
</>
|
|
95
|
+
);
|
|
96
|
+
return fill ? (
|
|
97
|
+
<m.li
|
|
98
|
+
key={s.num}
|
|
99
|
+
className={liClass}
|
|
100
|
+
data-motion=""
|
|
101
|
+
initial={{ opacity: 0, y: 14 }}
|
|
102
|
+
whileInView={{ opacity: 1, y: 0 }}
|
|
103
|
+
viewport={{ once: true, margin: "0px 0px -12% 0px" }}
|
|
104
|
+
transition={{ duration: 0.55, ease: EASE, delay: i * 0.28 }}
|
|
105
|
+
>
|
|
106
|
+
{content}
|
|
107
|
+
</m.li>
|
|
108
|
+
) : (
|
|
109
|
+
<li key={s.num} className={liClass}>
|
|
110
|
+
{content}
|
|
111
|
+
</li>
|
|
112
|
+
);
|
|
113
|
+
})}
|
|
114
|
+
</ol>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Brand marks — promoted from the design reference (symbols/marks) as pure,
|
|
5
|
+
* props-driven components. The four-stroke digiquant signature was previously
|
|
6
|
+
* copied verbatim in four places (dashboard-mark.tsx + DashboardLoader.tsx,
|
|
7
|
+
* digiquant-web's DigiquantMark, the reference specimen) — this file is the
|
|
8
|
+
* canonical copy. Everything draws in currentColor so a mark inherits the
|
|
9
|
+
* ink/accent of its livery scope. No CSS ships with this family: the marks
|
|
10
|
+
* are pure SVG/text; stroke-draw loader animations stay in the consuming
|
|
11
|
+
* app's CSS, targeted through `strokeClassPrefix`. Default hooks are
|
|
12
|
+
* `dq-mark` / `dq-stroke`.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export type DigiquantMarkProps = {
|
|
16
|
+
size?: number;
|
|
17
|
+
className?: string;
|
|
18
|
+
/** Accessible name (renders a <title> + role="img"); omitted → decorative. */
|
|
19
|
+
title?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Per-path class hook for stroke-draw animations: each stroke gets
|
|
22
|
+
* `${prefix} ${prefix}-N` (N = 1..4, outer arc last). The dashboard
|
|
23
|
+
* loader keys its draw keyframes off "research-loader-stroke";
|
|
24
|
+
* the reference / landing hover replay uses the default
|
|
25
|
+
* "dq-stroke".
|
|
26
|
+
*/
|
|
27
|
+
strokeClassPrefix?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function DigiquantMark({
|
|
31
|
+
size = 22,
|
|
32
|
+
className,
|
|
33
|
+
title,
|
|
34
|
+
strokeClassPrefix = "dq-stroke",
|
|
35
|
+
}: DigiquantMarkProps) {
|
|
36
|
+
const strokeClass = (n: number) => `${strokeClassPrefix} ${strokeClassPrefix}-${n}`;
|
|
37
|
+
return (
|
|
38
|
+
<svg
|
|
39
|
+
width={size}
|
|
40
|
+
height={size}
|
|
41
|
+
viewBox="0 0 48 48"
|
|
42
|
+
fill="none"
|
|
43
|
+
role={title ? "img" : undefined}
|
|
44
|
+
aria-hidden={title ? undefined : "true"}
|
|
45
|
+
focusable="false"
|
|
46
|
+
className={["dq-mark", className].filter(Boolean).join(" ")}
|
|
47
|
+
>
|
|
48
|
+
{title ? <title>{title}</title> : null}
|
|
49
|
+
<path
|
|
50
|
+
className={strokeClass(1)}
|
|
51
|
+
stroke="currentColor"
|
|
52
|
+
strokeWidth="2.2"
|
|
53
|
+
strokeLinecap="round"
|
|
54
|
+
strokeLinejoin="round"
|
|
55
|
+
d="M4.2774,32.5293a11.6485,11.6485,0,0,1,23.2219,1.32h0c0,3.2166.0022,11.6479.0022,11.6479"
|
|
56
|
+
/>
|
|
57
|
+
<path
|
|
58
|
+
className={strokeClass(2)}
|
|
59
|
+
stroke="currentColor"
|
|
60
|
+
strokeWidth="2.2"
|
|
61
|
+
strokeLinecap="round"
|
|
62
|
+
strokeLinejoin="round"
|
|
63
|
+
d="M3.3047,29.8574q-.0277-.4816-.0279-.97a16.61,16.61,0,1,1,33.2209,0v0c0,4.5869.0031,16.6095.0031,16.6095"
|
|
64
|
+
/>
|
|
65
|
+
<circle
|
|
66
|
+
className={strokeClass(3)}
|
|
67
|
+
stroke="currentColor"
|
|
68
|
+
strokeWidth="2"
|
|
69
|
+
cx="16.5007"
|
|
70
|
+
cy="33.4992"
|
|
71
|
+
r="5.0328"
|
|
72
|
+
/>
|
|
73
|
+
<path
|
|
74
|
+
className={strokeClass(4)}
|
|
75
|
+
stroke="currentColor"
|
|
76
|
+
strokeWidth="2.2"
|
|
77
|
+
strokeLinecap="round"
|
|
78
|
+
strokeLinejoin="round"
|
|
79
|
+
d="M45.5,24A21.5,21.5,0,1,0,24,45.5H45.5Z"
|
|
80
|
+
/>
|
|
81
|
+
</svg>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type WordmarkProps = {
|
|
86
|
+
/**
|
|
87
|
+
* Suffix after the prefix — "things", "quant". Wears var(--accent), so a
|
|
88
|
+
* livery scope (e.g. `.accent-digiquant`) dresses it automatically.
|
|
89
|
+
*/
|
|
90
|
+
suffix: ReactNode;
|
|
91
|
+
/** Lockup prefix, in ink (default "digi"). */
|
|
92
|
+
prefix?: ReactNode;
|
|
93
|
+
className?: string;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Wordmark — the text lockup grammar shared with the footer colophon:
|
|
98
|
+
* `digi` in ink, the suffix wearing var(--accent). Mono, weight 500.
|
|
99
|
+
* Carries token-backed utilities — consumers need an
|
|
100
|
+
* `@source "<path-to>/packages/ui/src/components/symbols"` line.
|
|
101
|
+
*/
|
|
102
|
+
export function Wordmark({ suffix, prefix = "digi", className }: WordmarkProps) {
|
|
103
|
+
return (
|
|
104
|
+
<span
|
|
105
|
+
className={[
|
|
106
|
+
"font-mono text-[1.25rem] font-medium tracking-[-0.01em] text-ink",
|
|
107
|
+
className,
|
|
108
|
+
]
|
|
109
|
+
.filter(Boolean)
|
|
110
|
+
.join(" ")}
|
|
111
|
+
>
|
|
112
|
+
{prefix}
|
|
113
|
+
<em className="not-italic text-accent">{suffix}</em>
|
|
114
|
+
</span>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animated brand lockup — `digi` and a cursor that types each module in turn.
|
|
3
|
+
*
|
|
4
|
+
* The identity as a live terminal line: `digi` holds, the cursor blinks, then a
|
|
5
|
+
* module suffix types in character by character, holds long enough to read,
|
|
6
|
+
* deletes, and the next one follows. Pure CSS, no JavaScript and no state — so it
|
|
7
|
+
* renders identically on the server and degrades correctly.
|
|
8
|
+
*
|
|
9
|
+
* Suffixes default to the real module registry (`data/modules`) with the shared
|
|
10
|
+
* `digi` prefix stripped, so the animation cannot drift out of sync with the
|
|
11
|
+
* stack the way a hardcoded list would.
|
|
12
|
+
*
|
|
13
|
+
* Two implementation details that are load-bearing:
|
|
14
|
+
*
|
|
15
|
+
* - **Keyframe offsets must be unique and strictly increasing, and every segment
|
|
16
|
+
* needs its own `animation-timing-function`.** Browsers merge duplicate-offset
|
|
17
|
+
* keyframes and silently drop the timing function — which turns the
|
|
18
|
+
* character-by-character type-in into a smooth width slide with no error
|
|
19
|
+
* anywhere. That is why the offsets are computed rather than hand-written.
|
|
20
|
+
* - **Typing is priced per character, not per slot.** A fixed slot makes a
|
|
21
|
+
* 3-letter module type at 2x the speed of a 6-letter one and the rhythm limps.
|
|
22
|
+
* Constant cadence means unequal slots, so the shared cycle is built from
|
|
23
|
+
* cumulative times.
|
|
24
|
+
*
|
|
25
|
+
* The keyframes are emitted as a scoped `<style>` rather than shipped in a family
|
|
26
|
+
* sheet because they are derived from the word list: a static sheet would have to
|
|
27
|
+
* hardcode a module count, and would go stale the moment the registry changes.
|
|
28
|
+
*
|
|
29
|
+
* `prefers-reduced-motion` renders the final state — `digi` + the first module,
|
|
30
|
+
* cursor still — per the canon's one-motion-moment rule.
|
|
31
|
+
*/
|
|
32
|
+
"use client";
|
|
33
|
+
|
|
34
|
+
import { useId } from "react";
|
|
35
|
+
import { modules } from "../../data/modules";
|
|
36
|
+
|
|
37
|
+
/** Module suffixes, `digi` stripped: ["graph", "quant", …]. */
|
|
38
|
+
export const MODULE_SUFFIXES: string[] = modules
|
|
39
|
+
.map((m) => m.id)
|
|
40
|
+
.filter((id) => id.startsWith("digi"))
|
|
41
|
+
.map((id) => id.slice(4));
|
|
42
|
+
|
|
43
|
+
/** Seconds. Typing is per character so every module types at one cadence. */
|
|
44
|
+
const TYPE_S = 0.14;
|
|
45
|
+
const ERASE_S = 0.09;
|
|
46
|
+
const HOLD_S = 2.4;
|
|
47
|
+
const REST_S = 1.2;
|
|
48
|
+
|
|
49
|
+
type Phase = { word: string; type: number; hold: number; erase: number; rest: number };
|
|
50
|
+
|
|
51
|
+
function plan(words: string[]): { phases: Phase[]; total: number } {
|
|
52
|
+
let t = 0;
|
|
53
|
+
const phases: Phase[] = [];
|
|
54
|
+
for (const word of words) {
|
|
55
|
+
const n = word.length;
|
|
56
|
+
const type = t;
|
|
57
|
+
const hold = type + n * TYPE_S;
|
|
58
|
+
const erase = hold + HOLD_S;
|
|
59
|
+
const rest = erase + n * ERASE_S;
|
|
60
|
+
phases.push({ word, type, hold, erase, rest });
|
|
61
|
+
t = rest + REST_S;
|
|
62
|
+
}
|
|
63
|
+
return { phases, total: t };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function keyframes(scope: string, words: string[]): string {
|
|
67
|
+
const { phases, total } = plan(words);
|
|
68
|
+
const pct = (s: number) => ((s / total) * 100).toFixed(4);
|
|
69
|
+
return phases
|
|
70
|
+
.map(({ word, type, hold, erase, rest }, i) => {
|
|
71
|
+
const n = word.length;
|
|
72
|
+
const rows: string[] = [];
|
|
73
|
+
if (type > 0) {
|
|
74
|
+
rows.push(`0%{width:0;animation-timing-function:linear}`);
|
|
75
|
+
rows.push(`${pct(type)}%{width:0;animation-timing-function:steps(${n},end)}`);
|
|
76
|
+
} else {
|
|
77
|
+
rows.push(`0%{width:0;animation-timing-function:steps(${n},end)}`);
|
|
78
|
+
}
|
|
79
|
+
rows.push(`${pct(hold)}%{width:${n}ch;animation-timing-function:linear}`);
|
|
80
|
+
rows.push(`${pct(erase)}%{width:${n}ch;animation-timing-function:steps(${n},end)}`);
|
|
81
|
+
rows.push(`${pct(rest)}%{width:0;animation-timing-function:linear}`);
|
|
82
|
+
if (rest < total) rows.push(`100%{width:0}`);
|
|
83
|
+
return `@keyframes ${scope}-t${i}{${rows.join("")}}`;
|
|
84
|
+
})
|
|
85
|
+
.join("");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface AnimatedLockupProps {
|
|
89
|
+
/** Suffixes to cycle. Defaults to the module registry. */
|
|
90
|
+
suffixes?: string[];
|
|
91
|
+
/** Text before the typed suffix. */
|
|
92
|
+
prefix?: string;
|
|
93
|
+
className?: string;
|
|
94
|
+
/** Accessible name. The typed suffixes are decorative — one name for the whole. */
|
|
95
|
+
title?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function AnimatedLockup({
|
|
99
|
+
suffixes = MODULE_SUFFIXES,
|
|
100
|
+
prefix = "digi",
|
|
101
|
+
className,
|
|
102
|
+
title = "digithings",
|
|
103
|
+
}: AnimatedLockupProps) {
|
|
104
|
+
// useId keeps the keyframe names unique if the lockup is ever mounted twice.
|
|
105
|
+
const scope = `dtl${useId().replace(/[^a-zA-Z0-9]/g, "")}`;
|
|
106
|
+
const { total } = plan(suffixes);
|
|
107
|
+
const css = [
|
|
108
|
+
`.${scope}{font-family:var(--font-mono);font-weight:400;line-height:1.05;`,
|
|
109
|
+
`letter-spacing:0;white-space:nowrap;display:inline-block;user-select:none}`,
|
|
110
|
+
`.${scope} i{font-style:normal;display:inline-block;overflow:hidden;width:0;`,
|
|
111
|
+
`vertical-align:bottom;animation-duration:${total.toFixed(2)}s;`,
|
|
112
|
+
`animation-iteration-count:infinite;animation-fill-mode:both}`,
|
|
113
|
+
suffixes.map((_, i) => `.${scope} i:nth-child(${i + 1}){animation-name:${scope}-t${i}}`).join(""),
|
|
114
|
+
`.${scope} u{display:inline-block;width:.6em;height:.71em;background:currentColor;`,
|
|
115
|
+
`text-decoration:none;animation:${scope}-blink 1.05s steps(1) infinite}`,
|
|
116
|
+
`@keyframes ${scope}-blink{50%{opacity:0}}`,
|
|
117
|
+
keyframes(scope, suffixes),
|
|
118
|
+
`@media (prefers-reduced-motion:reduce){`,
|
|
119
|
+
`.${scope} u{animation:none}`,
|
|
120
|
+
`.${scope} i{animation:none;width:0}`,
|
|
121
|
+
`.${scope} i:nth-child(1){width:${suffixes[0]?.length ?? 0}ch}}`,
|
|
122
|
+
].join("");
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<span className={[scope, className].filter(Boolean).join(" ")} role="img" aria-label={title}>
|
|
126
|
+
<style>{css}</style>
|
|
127
|
+
{prefix}
|
|
128
|
+
<span aria-hidden="true">
|
|
129
|
+
{suffixes.map((w) => (
|
|
130
|
+
<i key={w}>{w}</i>
|
|
131
|
+
))}
|
|
132
|
+
</span>
|
|
133
|
+
<u aria-hidden="true" />
|
|
134
|
+
</span>
|
|
135
|
+
);
|
|
136
|
+
}
|