@flamingo-stack/openframe-frontend-core 0.0.204 → 0.0.205
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/dist/{chunk-4CWSZPXH.cjs → chunk-24KCAECR.cjs} +9 -9
- package/dist/{chunk-4CWSZPXH.cjs.map → chunk-24KCAECR.cjs.map} +1 -1
- package/dist/chunk-27APPAJN.cjs +24 -0
- package/dist/chunk-27APPAJN.cjs.map +1 -0
- package/dist/{chunk-UC43NICZ.cjs → chunk-664KA5FI.cjs} +2 -35
- package/dist/chunk-664KA5FI.cjs.map +1 -0
- package/dist/chunk-6RZYJICV.cjs +24 -0
- package/dist/chunk-6RZYJICV.cjs.map +1 -0
- package/dist/chunk-7L4DWM7P.js +24 -0
- package/dist/chunk-7L4DWM7P.js.map +1 -0
- package/dist/chunk-BZFW3FOF.cjs +21 -0
- package/dist/chunk-BZFW3FOF.cjs.map +1 -0
- package/dist/{chunk-N57KWHDB.js → chunk-CIPO6DXK.js} +5 -5
- package/dist/chunk-EL5YVPD5.js +21 -0
- package/dist/chunk-EL5YVPD5.js.map +1 -0
- package/dist/{chunk-ARQ4XP64.cjs → chunk-FDCFI7YT.cjs} +40080 -31492
- package/dist/chunk-FDCFI7YT.cjs.map +1 -0
- package/dist/chunk-G7UE6RKV.cjs +121 -0
- package/dist/chunk-G7UE6RKV.cjs.map +1 -0
- package/dist/{chunk-25LVV26X.cjs → chunk-JUZGUQMX.cjs} +178 -50
- package/dist/chunk-JUZGUQMX.cjs.map +1 -0
- package/dist/{chunk-SZPJ5R5B.js → chunk-KSOOKNBG.js} +1 -34
- package/dist/chunk-KSOOKNBG.js.map +1 -0
- package/dist/{chunk-RMB5DVED.cjs → chunk-KUZGEA7U.cjs} +83 -66
- package/dist/chunk-KUZGEA7U.cjs.map +1 -0
- package/dist/chunk-LXC6P2EO.js +63 -0
- package/dist/chunk-LXC6P2EO.js.map +1 -0
- package/dist/chunk-MJNXIEV2.js +24 -0
- package/dist/chunk-MJNXIEV2.js.map +1 -0
- package/dist/{chunk-CPXLQ57U.js → chunk-MVGGXOFA.js} +37 -20
- package/dist/chunk-MVGGXOFA.js.map +1 -0
- package/dist/{chunk-LY34ORX6.js → chunk-O55ZUAX7.js} +39920 -31332
- package/dist/chunk-O55ZUAX7.js.map +1 -0
- package/dist/chunk-OHPI2HRK.js +47 -0
- package/dist/chunk-OHPI2HRK.js.map +1 -0
- package/dist/chunk-PLJLE4A4.js +121 -0
- package/dist/chunk-PLJLE4A4.js.map +1 -0
- package/dist/{chunk-XGL5FKIK.js → chunk-SCN5WFIZ.js} +148 -20
- package/dist/chunk-SCN5WFIZ.js.map +1 -0
- package/dist/chunk-WBR7H6E3.cjs +47 -0
- package/dist/chunk-WBR7H6E3.cjs.map +1 -0
- package/dist/chunk-XL4V2PYG.cjs +63 -0
- package/dist/chunk-XL4V2PYG.cjs.map +1 -0
- package/dist/components/announcement-bar.d.ts.map +1 -1
- package/dist/components/chat/chat-attachment-bar.d.ts +66 -0
- package/dist/components/chat/chat-attachment-bar.d.ts.map +1 -0
- package/dist/components/chat/chat-container.d.ts +21 -1
- package/dist/components/chat/chat-container.d.ts.map +1 -1
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
- package/dist/components/chat/chat-message-list.d.ts.map +1 -1
- package/dist/components/chat/chat-panel-context.d.ts +9 -0
- package/dist/components/chat/chat-panel-context.d.ts.map +1 -0
- package/dist/components/chat/chat-ticket-list.d.ts +1 -1
- package/dist/components/chat/chat-ticket-list.d.ts.map +1 -1
- package/dist/components/chat/embeddable-chat.d.ts +42 -0
- package/dist/components/chat/embeddable-chat.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/admin-content-card.d.ts +34 -0
- package/dist/components/chat/entity-cards/admin-content-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/block-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/blog-card.d.ts +30 -0
- package/dist/components/chat/entity-cards/blog-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/blog-image-placeholder.d.ts +26 -0
- package/dist/components/chat/entity-cards/blog-image-placeholder.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/campaign-card-admin.d.ts +33 -0
- package/dist/components/chat/entity-cards/campaign-card-admin.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/case-study-card.d.ts +20 -0
- package/dist/components/chat/entity-cards/case-study-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/chat-ticket-item.d.ts.map +1 -0
- package/dist/components/chat/{chat-video-entity-card.d.ts → entity-cards/chat-video-entity-card.d.ts} +1 -1
- package/dist/components/chat/entity-cards/chat-video-entity-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/customer-interview-card.d.ts +19 -0
- package/dist/components/chat/entity-cards/customer-interview-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/data-room-doc-card.d.ts +47 -0
- package/dist/components/chat/entity-cards/data-room-doc-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/dispatch.d.ts +119 -0
- package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/entity-author-card.d.ts +87 -0
- package/dist/components/chat/entity-cards/entity-author-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/generic-entity-card.d.ts +42 -0
- package/dist/components/chat/entity-cards/generic-entity-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/github-activity-card.d.ts +37 -0
- package/dist/components/chat/entity-cards/github-activity-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/hubspot-ticket-card.d.ts +28 -0
- package/dist/components/chat/entity-cards/hubspot-ticket-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/index.d.ts +32 -0
- package/dist/components/chat/entity-cards/index.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/investor-update-card.d.ts +19 -0
- package/dist/components/chat/entity-cards/investor-update-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/onboarding-guide-card.d.ts +20 -0
- package/dist/components/chat/entity-cards/onboarding-guide-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/product-release-card-defaults.d.ts +21 -0
- package/dist/components/chat/entity-cards/product-release-card-defaults.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/product-release-card.d.ts +12 -0
- package/dist/components/chat/entity-cards/product-release-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/program-card-defaults.d.ts +32 -0
- package/dist/components/chat/entity-cards/program-card-defaults.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/program-card.d.ts +37 -0
- package/dist/components/chat/entity-cards/program-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/roadmap-card.d.ts +28 -0
- package/dist/components/chat/entity-cards/roadmap-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/roadmap-vote-button.d.ts +12 -0
- package/dist/components/chat/entity-cards/roadmap-vote-button.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/slack-message-card.d.ts +28 -0
- package/dist/components/chat/entity-cards/slack-message-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/task-type-icon.d.ts +6 -0
- package/dist/components/chat/entity-cards/task-type-icon.d.ts.map +1 -0
- package/dist/components/chat/hooks/index.d.ts +10 -0
- package/dist/components/chat/hooks/index.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-chat-attachment-image-gallery.d.ts +5 -0
- package/dist/components/chat/hooks/use-chat-attachment-image-gallery.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-chat-attachments.d.ts +33 -0
- package/dist/components/chat/hooks/use-chat-attachments.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-chat-card-item.d.ts +7 -0
- package/dist/components/chat/hooks/use-chat-card-item.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-chat-identity.d.ts +44 -0
- package/dist/components/chat/hooks/use-chat-identity.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-chat.d.ts +30 -0
- package/dist/components/chat/hooks/use-chat.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-close-on-navigation.d.ts +2 -0
- package/dist/components/chat/hooks/use-close-on-navigation.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-embedded-chat.d.ts +174 -0
- package/dist/components/chat/hooks/use-embedded-chat.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-proxied-image-url.d.ts +18 -0
- package/dist/components/chat/hooks/use-proxied-image-url.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-slash-commands.d.ts +32 -0
- package/dist/components/chat/hooks/use-slash-commands.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-sse.d.ts +57 -0
- package/dist/components/chat/hooks/use-sse.d.ts.map +1 -0
- package/dist/components/chat/index.cjs +393 -0
- package/dist/components/chat/index.cjs.map +1 -0
- package/dist/components/chat/index.d.ts +5 -3
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +393 -0
- package/dist/components/chat/index.js.map +1 -0
- package/dist/components/chat/nav-link-anchor-via-runtime.d.ts +33 -0
- package/dist/components/chat/nav-link-anchor-via-runtime.d.ts.map +1 -0
- package/dist/components/chat/source-action-button.d.ts +39 -0
- package/dist/components/chat/source-action-button.d.ts.map +1 -0
- package/dist/components/chat/types/chat.types.d.ts +36 -0
- package/dist/components/chat/types/chat.types.d.ts.map +1 -1
- package/dist/components/chat/types/component.types.d.ts +56 -11
- package/dist/components/chat/types/component.types.d.ts.map +1 -1
- package/dist/components/chat/types/entities/blog.d.ts +14 -0
- package/dist/components/chat/types/entities/blog.d.ts.map +1 -0
- package/dist/components/chat/types/entities/case-study.d.ts +10 -0
- package/dist/components/chat/types/entities/case-study.d.ts.map +1 -0
- package/dist/components/chat/types/entities/content-ref.d.ts +23 -0
- package/dist/components/chat/types/entities/content-ref.d.ts.map +1 -0
- package/dist/components/chat/types/entities/customer-interview.d.ts +10 -0
- package/dist/components/chat/types/entities/customer-interview.d.ts.map +1 -0
- package/dist/components/chat/types/entities/data-room-doc.d.ts +37 -0
- package/dist/components/chat/types/entities/data-room-doc.d.ts.map +1 -0
- package/dist/components/chat/types/entities/github-activity.d.ts +29 -0
- package/dist/components/chat/types/entities/github-activity.d.ts.map +1 -0
- package/dist/components/chat/types/entities/hubspot-ticket.d.ts +39 -0
- package/dist/components/chat/types/entities/hubspot-ticket.d.ts.map +1 -0
- package/dist/components/chat/types/entities/index.d.ts +28 -0
- package/dist/components/chat/types/entities/index.d.ts.map +1 -0
- package/dist/components/chat/types/entities/investor-update.d.ts +83 -0
- package/dist/components/chat/types/entities/investor-update.d.ts.map +1 -0
- package/dist/components/chat/types/entities/onboarding-guide.d.ts +79 -0
- package/dist/components/chat/types/entities/onboarding-guide.d.ts.map +1 -0
- package/dist/components/chat/types/entities/program-types.d.ts +303 -0
- package/dist/components/chat/types/entities/program-types.d.ts.map +1 -0
- package/dist/components/chat/types/entities/roadmap-item.d.ts +41 -0
- package/dist/components/chat/types/entities/roadmap-item.d.ts.map +1 -0
- package/dist/components/chat/types/entities/slack-message.d.ts +28 -0
- package/dist/components/chat/types/entities/slack-message.d.ts.map +1 -0
- package/dist/components/chat/types/index.d.ts +1 -0
- package/dist/components/chat/types/index.d.ts.map +1 -1
- package/dist/components/chat/utils/agent-status-message.d.ts +18 -0
- package/dist/components/chat/utils/agent-status-message.d.ts.map +1 -0
- package/dist/components/chat/utils/auto-continuation-directive.d.ts +38 -0
- package/dist/components/chat/utils/auto-continuation-directive.d.ts.map +1 -0
- package/dist/components/chat/utils/chat-attachment-markdown.d.ts +114 -0
- package/dist/components/chat/utils/chat-attachment-markdown.d.ts.map +1 -0
- package/dist/components/chat/utils/chat-authed-fetch.d.ts +13 -0
- package/dist/components/chat/utils/chat-authed-fetch.d.ts.map +1 -0
- package/dist/components/chat/utils/chat-nav-resolution.d.ts +72 -0
- package/dist/components/chat/utils/chat-nav-resolution.d.ts.map +1 -0
- package/dist/components/chat/utils/chat-proxy-auth-storage.d.ts +43 -0
- package/dist/components/chat/utils/chat-proxy-auth-storage.d.ts.map +1 -0
- package/dist/components/chat/utils/chip-action-class.d.ts +16 -0
- package/dist/components/chat/utils/chip-action-class.d.ts.map +1 -0
- package/dist/components/chat/utils/chip-styles.d.ts +32 -0
- package/dist/components/chat/utils/chip-styles.d.ts.map +1 -0
- package/dist/components/chat/utils/clickup-task-type-utils.d.ts +38 -0
- package/dist/components/chat/utils/clickup-task-type-utils.d.ts.map +1 -0
- package/dist/components/chat/utils/compact-card-classes.d.ts +50 -0
- package/dist/components/chat/utils/compact-card-classes.d.ts.map +1 -0
- package/dist/components/chat/utils/decide-new-tab.d.ts +39 -0
- package/dist/components/chat/utils/decide-new-tab.d.ts.map +1 -0
- package/dist/components/chat/utils/external-app-urls.d.ts +14 -0
- package/dist/components/chat/utils/external-app-urls.d.ts.map +1 -0
- package/dist/components/chat/utils/flatten-assistant-content.d.ts +25 -0
- package/dist/components/chat/utils/flatten-assistant-content.d.ts.map +1 -0
- package/dist/components/chat/utils/icon-registry.d.ts +67 -0
- package/dist/components/chat/utils/icon-registry.d.ts.map +1 -0
- package/dist/components/chat/utils/index.d.ts +21 -0
- package/dist/components/chat/utils/index.d.ts.map +1 -1
- package/dist/components/chat/utils/is-cross-origin-url.d.ts +22 -0
- package/dist/components/chat/utils/is-cross-origin-url.d.ts.map +1 -0
- package/dist/components/chat/utils/nav-anchor-props.d.ts +54 -0
- package/dist/components/chat/utils/nav-anchor-props.d.ts.map +1 -0
- package/dist/components/chat/utils/nav-click-handler.d.ts +51 -0
- package/dist/components/chat/utils/nav-click-handler.d.ts.map +1 -0
- package/dist/components/chat/utils/scroll-anchor.d.ts +30 -0
- package/dist/components/chat/utils/scroll-anchor.d.ts.map +1 -0
- package/dist/components/chat/utils/slash-dispatch-utils.d.ts +109 -0
- package/dist/components/chat/utils/slash-dispatch-utils.d.ts.map +1 -0
- package/dist/components/chat/utils/source-icons.d.ts +8 -0
- package/dist/components/chat/utils/source-icons.d.ts.map +1 -0
- package/dist/components/chat/utils/source-row-cta.d.ts +111 -0
- package/dist/components/chat/utils/source-row-cta.d.ts.map +1 -0
- package/dist/components/features/figma-prototype-viewer.d.ts.map +1 -1
- package/dist/components/features/index.cjs +12 -6
- package/dist/components/features/index.cjs.map +1 -1
- package/dist/components/features/index.js +11 -5
- package/dist/components/features/video.d.ts.map +1 -1
- package/dist/components/icons/index.cjs +3 -3
- package/dist/components/icons/index.js +2 -2
- package/dist/components/index.cjs +274 -8
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +273 -7
- package/dist/components/interactive-wrapper.d.ts +3 -3
- package/dist/components/navigation/index.cjs +12 -6
- package/dist/components/navigation/index.cjs.map +1 -1
- package/dist/components/navigation/index.js +11 -5
- package/dist/components/resizable.d.ts +1 -1
- package/dist/components/shared/product-release/product-release-card-skeleton.d.ts +1 -1
- package/dist/components/shared/product-release/product-release-card-skeleton.d.ts.map +1 -1
- package/dist/components/shared/product-release/product-release-card.d.ts +19 -12
- package/dist/components/shared/product-release/product-release-card.d.ts.map +1 -1
- package/dist/components/shared/product-release/release-detail-page.d.ts +2 -4
- package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
- package/dist/components/ui/button/button.d.ts +13 -0
- package/dist/components/ui/button/button.d.ts.map +1 -1
- package/dist/components/ui/dashboard-info-card.d.ts.map +1 -1
- package/dist/components/ui/entity-image.d.ts.map +1 -1
- package/dist/components/ui/file-manager/index.cjs +71 -70
- package/dist/components/ui/file-manager/index.cjs.map +1 -1
- package/dist/components/ui/file-manager/index.js +6 -5
- package/dist/components/ui/file-manager/index.js.map +1 -1
- package/dist/components/ui/hover-dropdown.d.ts +66 -0
- package/dist/components/ui/hover-dropdown.d.ts.map +1 -0
- package/dist/components/ui/index.cjs +276 -6
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +278 -8
- package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
- package/dist/components/ui/square-avatar.d.ts.map +1 -1
- package/dist/contexts/chat-runtime-context.d.ts +109 -0
- package/dist/contexts/chat-runtime-context.d.ts.map +1 -0
- package/dist/contexts/endpoints-runtime-context.d.ts +28 -0
- package/dist/contexts/endpoints-runtime-context.d.ts.map +1 -0
- package/dist/contexts/index.cjs +30 -0
- package/dist/contexts/index.cjs.map +1 -0
- package/dist/contexts/index.d.ts +26 -0
- package/dist/contexts/index.d.ts.map +1 -0
- package/dist/contexts/index.js +30 -0
- package/dist/contexts/index.js.map +1 -0
- package/dist/contexts/use-outer-or-default.d.ts +29 -0
- package/dist/contexts/use-outer-or-default.d.ts.map +1 -0
- package/dist/embed-shims/index.cjs +51 -0
- package/dist/embed-shims/index.cjs.map +1 -0
- package/dist/embed-shims/index.d.ts +31 -0
- package/dist/embed-shims/index.d.ts.map +1 -0
- package/dist/embed-shims/index.js +51 -0
- package/dist/embed-shims/index.js.map +1 -0
- package/dist/embed-shims/next-dynamic.cjs +12 -0
- package/dist/embed-shims/next-dynamic.cjs.map +1 -0
- package/dist/embed-shims/next-dynamic.d.ts +47 -0
- package/dist/embed-shims/next-dynamic.d.ts.map +1 -0
- package/dist/embed-shims/next-dynamic.js +12 -0
- package/dist/embed-shims/next-dynamic.js.map +1 -0
- package/dist/embed-shims/next-image.cjs +12 -0
- package/dist/embed-shims/next-image.cjs.map +1 -0
- package/dist/embed-shims/next-image.d.ts +28 -0
- package/dist/embed-shims/next-image.d.ts.map +1 -0
- package/dist/embed-shims/next-image.js +12 -0
- package/dist/embed-shims/next-image.js.map +1 -0
- package/dist/embed-shims/next-link.cjs +14 -0
- package/dist/embed-shims/next-link.cjs.map +1 -0
- package/dist/embed-shims/next-link.d.ts +22 -0
- package/dist/embed-shims/next-link.d.ts.map +1 -0
- package/dist/embed-shims/next-link.js +14 -0
- package/dist/embed-shims/next-link.js.map +1 -0
- package/dist/embed-shims/next-navigation.cjs +30 -0
- package/dist/embed-shims/next-navigation.cjs.map +1 -0
- package/dist/embed-shims/next-navigation.d.ts +46 -0
- package/dist/embed-shims/next-navigation.d.ts.map +1 -0
- package/dist/embed-shims/next-navigation.js +30 -0
- package/dist/embed-shims/next-navigation.js.map +1 -0
- package/dist/hooks/index.cjs +10 -4
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +9 -3
- package/dist/hooks/use-access-code-integration.d.ts +48 -0
- package/dist/hooks/use-access-code-integration.d.ts.map +1 -0
- package/dist/hooks/use-contact-submission.d.ts.map +1 -1
- package/dist/hooks/use-og-placeholder.d.ts +31 -0
- package/dist/hooks/use-og-placeholder.d.ts.map +1 -0
- package/dist/hooks/use-toast.d.ts +1 -1
- package/dist/index.cjs +367 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +378 -18
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/access-code-client.d.ts +21 -37
- package/dist/utils/access-code-client.d.ts.map +1 -1
- package/dist/utils/cn.d.ts +0 -27
- package/dist/utils/cn.d.ts.map +1 -1
- package/dist/utils/color-analysis.d.ts +33 -0
- package/dist/utils/color-analysis.d.ts.map +1 -0
- package/dist/utils/date-formatters.d.ts +16 -5
- package/dist/utils/date-formatters.d.ts.map +1 -1
- package/dist/utils/fetch-priority.d.ts +3 -0
- package/dist/utils/fetch-priority.d.ts.map +1 -0
- package/dist/utils/format.d.ts +192 -1
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/image-proxy.d.ts +67 -2
- package/dist/utils/image-proxy.d.ts.map +1 -1
- package/dist/utils/index.cjs +1274 -155
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +19 -3
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1200 -157
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/local-storage-adapter.d.ts +46 -0
- package/dist/utils/local-storage-adapter.d.ts.map +1 -0
- package/dist/utils/source-icons.d.ts +78 -0
- package/dist/utils/source-icons.d.ts.map +1 -0
- package/package.json +29 -2
- package/src/components/announcement-bar.tsx +26 -4
- package/src/components/categories-cart.tsx +1 -1
- package/src/components/chat/chat-attachment-bar.tsx +323 -0
- package/src/components/chat/chat-container.tsx +39 -5
- package/src/components/chat/chat-input.tsx +7 -1
- package/src/components/chat/chat-message-enhanced.tsx +32 -22
- package/src/components/chat/chat-message-list.tsx +53 -4
- package/src/components/chat/chat-panel-context.tsx +37 -0
- package/src/components/chat/chat-ticket-list.tsx +1 -1
- package/src/components/chat/embeddable-chat.tsx +1106 -0
- package/src/components/chat/entity-cards/admin-content-card.tsx +155 -0
- package/src/components/chat/entity-cards/blog-card.tsx +259 -0
- package/src/components/chat/entity-cards/blog-image-placeholder.tsx +52 -0
- package/src/components/chat/entity-cards/campaign-card-admin.tsx +113 -0
- package/src/components/chat/entity-cards/case-study-card.tsx +192 -0
- package/src/components/chat/{chat-ticket-item.tsx → entity-cards/chat-ticket-item.tsx} +2 -2
- package/src/components/chat/{chat-video-entity-card.tsx → entity-cards/chat-video-entity-card.tsx} +2 -2
- package/src/components/chat/entity-cards/customer-interview-card.tsx +211 -0
- package/src/components/chat/entity-cards/data-room-doc-card.tsx +120 -0
- package/src/components/chat/entity-cards/dispatch.tsx +1093 -0
- package/src/components/chat/entity-cards/entity-author-card.tsx +193 -0
- package/src/components/chat/entity-cards/generic-entity-card.tsx +144 -0
- package/src/components/chat/entity-cards/github-activity-card.tsx +305 -0
- package/src/components/chat/entity-cards/hubspot-ticket-card.tsx +205 -0
- package/src/components/chat/entity-cards/index.ts +125 -0
- package/src/components/chat/entity-cards/investor-update-card.tsx +150 -0
- package/src/components/chat/entity-cards/onboarding-guide-card.tsx +326 -0
- package/src/components/chat/entity-cards/product-release-card-defaults.ts +57 -0
- package/src/components/chat/entity-cards/product-release-card.tsx +19 -0
- package/src/components/chat/entity-cards/program-card-defaults.ts +62 -0
- package/src/components/chat/entity-cards/program-card.tsx +451 -0
- package/src/components/chat/entity-cards/roadmap-card.tsx +356 -0
- package/src/components/chat/entity-cards/roadmap-vote-button.tsx +54 -0
- package/src/components/chat/entity-cards/slack-message-card.tsx +182 -0
- package/src/components/chat/entity-cards/task-type-icon.tsx +60 -0
- package/src/components/chat/hooks/index.ts +22 -0
- package/src/components/chat/hooks/use-chat-attachment-image-gallery.tsx +114 -0
- package/src/components/chat/hooks/use-chat-attachments.ts +429 -0
- package/src/components/chat/hooks/use-chat-card-item.ts +102 -0
- package/src/components/chat/hooks/use-chat-identity.ts +139 -0
- package/src/components/chat/hooks/use-chat.ts +501 -0
- package/src/components/chat/hooks/use-close-on-navigation.ts +87 -0
- package/src/components/chat/hooks/use-embedded-chat.ts +1023 -0
- package/src/components/chat/hooks/use-proxied-image-url.ts +31 -0
- package/src/components/chat/hooks/use-slash-commands.ts +106 -0
- package/src/components/chat/hooks/use-sse.ts +143 -0
- package/src/components/chat/index.ts +30 -4
- package/src/components/chat/nav-link-anchor-via-runtime.tsx +72 -0
- package/src/components/chat/source-action-button.tsx +120 -0
- package/src/components/chat/types/chat.types.ts +61 -0
- package/src/components/chat/types/component.types.ts +57 -11
- package/src/components/chat/types/entities/blog.ts +27 -0
- package/src/components/chat/types/entities/case-study.ts +14 -0
- package/src/components/chat/types/entities/content-ref.ts +23 -0
- package/src/components/chat/types/entities/customer-interview.ts +15 -0
- package/src/components/chat/types/entities/data-room-doc.ts +37 -0
- package/src/components/chat/types/entities/github-activity.ts +36 -0
- package/src/components/chat/types/entities/hubspot-ticket.ts +39 -0
- package/src/components/chat/types/entities/index.ts +28 -0
- package/src/components/chat/types/entities/investor-update.ts +100 -0
- package/src/components/chat/types/entities/onboarding-guide.ts +101 -0
- package/src/components/chat/types/entities/program-types.ts +433 -0
- package/src/components/chat/types/entities/roadmap-item.ts +42 -0
- package/src/components/chat/types/entities/slack-message.ts +28 -0
- package/src/components/chat/types/index.ts +1 -0
- package/src/components/chat/utils/agent-status-message.ts +52 -0
- package/src/components/chat/utils/auto-continuation-directive.ts +70 -0
- package/src/components/chat/utils/chat-attachment-markdown.ts +190 -0
- package/src/components/chat/utils/chat-authed-fetch.ts +73 -0
- package/src/components/chat/utils/chat-nav-resolution.ts +151 -0
- package/src/components/chat/utils/chat-proxy-auth-storage.ts +148 -0
- package/src/components/chat/utils/chip-action-class.ts +19 -0
- package/src/components/chat/utils/chip-styles.ts +51 -0
- package/src/components/chat/utils/clickup-task-type-utils.ts +59 -0
- package/src/components/chat/utils/compact-card-classes.ts +97 -0
- package/src/components/chat/utils/decide-new-tab.ts +57 -0
- package/src/components/chat/utils/external-app-urls.ts +19 -0
- package/src/components/chat/utils/flatten-assistant-content.ts +35 -0
- package/src/components/chat/utils/icon-registry.ts +297 -0
- package/src/components/chat/utils/index.ts +133 -0
- package/src/components/chat/utils/is-cross-origin-url.ts +28 -0
- package/src/components/chat/utils/nav-anchor-props.ts +78 -0
- package/src/components/chat/utils/nav-click-handler.ts +81 -0
- package/src/components/chat/utils/scroll-anchor.ts +35 -0
- package/src/components/chat/utils/slash-dispatch-utils.ts +183 -0
- package/src/components/chat/utils/source-icons.ts +14 -0
- package/src/components/chat/utils/source-row-cta.ts +215 -0
- package/src/components/empty-state.tsx +1 -1
- package/src/components/features/board/ticket-card.tsx +1 -1
- package/src/components/features/figma-prototype-viewer.tsx +2 -1
- package/src/components/features/media-gallery-manager.tsx +1 -1
- package/src/components/features/parallax-image-showcase.tsx +1 -1
- package/src/components/features/release-media-manager.tsx +1 -1
- package/src/components/features/seo-editor-preview.tsx +1 -1
- package/src/components/features/video.tsx +54 -3
- package/src/components/footer-waitlist-button.tsx +1 -1
- package/src/components/navigation/header.tsx +1 -1
- package/src/components/shared/onboarding/onboarding-step-card.tsx +1 -1
- package/src/components/shared/product-release/product-release-card-skeleton.tsx +8 -44
- package/src/components/shared/product-release/product-release-card.tsx +31 -116
- package/src/components/shared/product-release/release-detail-page.tsx +12 -16
- package/src/components/ui/actions-menu.tsx +1 -1
- package/src/components/ui/button/button.tsx +41 -11
- package/src/components/ui/button/split-button.tsx +1 -1
- package/src/components/ui/dashboard-info-card.tsx +2 -3
- package/src/components/ui/data-table/data-table-row.tsx +1 -1
- package/src/components/ui/entity-image.tsx +2 -8
- package/src/components/ui/hover-dropdown.tsx +258 -0
- package/src/components/ui/image-gallery-modal.tsx +1 -1
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/markdown-editor.tsx +1 -1
- package/src/components/ui/more-actions-menu.tsx +1 -1
- package/src/components/ui/organization-card.tsx +1 -1
- package/src/components/ui/simple-markdown-renderer.tsx +53 -5
- package/src/components/ui/square-avatar.tsx +3 -12
- package/src/components/ui/tab-navigation.tsx +1 -1
- package/src/components/ui/table/table-row.tsx +1 -1
- package/src/components/unified-filter-logic.tsx +1 -1
- package/src/components/unified-pagination.tsx +1 -1
- package/src/components/user-summary-stub.tsx +1 -1
- package/src/components/vendor-display-button.tsx +1 -1
- package/src/components/vendor-icon.tsx +1 -1
- package/src/contexts/chat-runtime-context.tsx +163 -0
- package/src/contexts/endpoints-runtime-context.tsx +68 -0
- package/src/contexts/index.ts +38 -0
- package/src/contexts/use-outer-or-default.ts +42 -0
- package/src/embed-shims/index.ts +42 -0
- package/src/embed-shims/next-dynamic.tsx +70 -0
- package/src/embed-shims/next-image.tsx +114 -0
- package/src/embed-shims/next-link.tsx +91 -0
- package/src/embed-shims/next-navigation.tsx +201 -0
- package/src/hooks/index.ts +9 -0
- package/src/hooks/state/use-api-params.ts +1 -1
- package/src/hooks/state/use-query-params.ts +1 -1
- package/src/hooks/use-access-code-integration.ts +107 -0
- package/src/hooks/use-contact-submission.ts +7 -3
- package/src/hooks/use-og-placeholder.ts +45 -0
- package/src/stories/OnboardingStepCard.stories.tsx +140 -0
- package/src/styles/chat-animations.css +65 -0
- package/src/styles/index.css +1 -0
- package/src/utils/access-code-client.ts +32 -75
- package/src/utils/cn.ts +0 -65
- package/src/utils/color-analysis.ts +205 -0
- package/src/utils/date-formatters.ts +54 -11
- package/src/utils/fetch-priority.ts +41 -0
- package/src/utils/format.ts +525 -1
- package/src/utils/image-proxy.ts +127 -7
- package/src/utils/index.ts +145 -5
- package/src/utils/local-storage-adapter.ts +105 -0
- package/src/utils/source-icons.ts +219 -0
- package/dist/chunk-25LVV26X.cjs.map +0 -1
- package/dist/chunk-ARQ4XP64.cjs.map +0 -1
- package/dist/chunk-CPXLQ57U.js.map +0 -1
- package/dist/chunk-LY34ORX6.js.map +0 -1
- package/dist/chunk-RMB5DVED.cjs.map +0 -1
- package/dist/chunk-SZPJ5R5B.js.map +0 -1
- package/dist/chunk-UC43NICZ.cjs.map +0 -1
- package/dist/chunk-XGL5FKIK.js.map +0 -1
- package/dist/components/chat/block-card.d.ts.map +0 -1
- package/dist/components/chat/chat-ticket-item.d.ts.map +0 -1
- package/dist/components/chat/chat-video-entity-card.d.ts.map +0 -1
- package/dist/utils/dynamic-icons.d.ts +0 -26
- package/dist/utils/dynamic-icons.d.ts.map +0 -1
- package/dist/utils/format-relative-time.d.ts +0 -21
- package/dist/utils/format-relative-time.d.ts.map +0 -1
- package/src/utils/.dynamic-icons.md +0 -30
- package/src/utils/.format-relative-time.md +0 -36
- package/src/utils/dynamic-icons.tsx +0 -120
- package/src/utils/format-relative-time.ts +0 -52
- /package/dist/{chunk-N57KWHDB.js.map → chunk-CIPO6DXK.js.map} +0 -0
- /package/dist/components/chat/{block-card.d.ts → entity-cards/block-card.d.ts} +0 -0
- /package/dist/components/chat/{chat-ticket-item.d.ts → entity-cards/chat-ticket-item.d.ts} +0 -0
- /package/src/components/chat/{block-card.tsx → entity-cards/block-card.tsx} +0 -0
|
@@ -0,0 +1,1093 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Lib-side entity-card dispatch — single switch over canonical chat cards.
|
|
5
|
+
*
|
|
6
|
+
* Lib-portable refactor of the hub's `components/shared/entity-card-dispatch.tsx`.
|
|
7
|
+
* Drops the hub-only imports:
|
|
8
|
+
* - `useNavLink` → click routing flows through `<NavLinkAnchorViaRuntime>`
|
|
9
|
+
* (reads `useRequiredChatRuntime` internally) or
|
|
10
|
+
* the chat-runtime's `handleChatNavClick` helper.
|
|
11
|
+
* - `currentPlatform` → runtime.source supplies the identifier.
|
|
12
|
+
* - `buildContentURL` → URLs arrive pre-composed by the server's
|
|
13
|
+
* RAG mapper (`ref.url`); the card just renders.
|
|
14
|
+
* - `tableIdForDocumentType` → only relevant for the hub-side ContentRef
|
|
15
|
+
* reverse-projection — not needed for chat
|
|
16
|
+
* inline cards.
|
|
17
|
+
* - hub `program-configs` → host provides via `ChatCardRenderOptions.extras`.
|
|
18
|
+
* - `buildProductReleaseCardProps` → ditto, host provides via `extras`.
|
|
19
|
+
*
|
|
20
|
+
* Adding a new chat-inline card type:
|
|
21
|
+
* 1. Implement the `size='sm'` branch + skeleton in `./<card>.tsx` (pure
|
|
22
|
+
* presentation, accepts `href` + `targetPlatform`).
|
|
23
|
+
* 2. Add one entry to `CHAT_CARD_REGISTRY` below.
|
|
24
|
+
*
|
|
25
|
+
* Public entry points consumed by the chat shell:
|
|
26
|
+
* - `renderChatInlineEntityCard(ref, opts)` — top-level marker dispatch
|
|
27
|
+
* (block-card hoist for video refs, otherwise compact card).
|
|
28
|
+
* - `<ChatCardLoader />` — fetch + skeleton + render the compact card for
|
|
29
|
+
* fetch-mode entries.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import React, { type ReactNode } from 'react'
|
|
33
|
+
import { useRequiredChatRuntime } from '../../../contexts/chat-runtime-context'
|
|
34
|
+
import type { ChatRef } from '../chat-ref.types'
|
|
35
|
+
import { useChatCardItem } from '../hooks/use-chat-card-item'
|
|
36
|
+
import { handleChatNavClick } from '../utils/nav-click-handler'
|
|
37
|
+
import { resolveSourceRowCTA, resolveSourceIcon } from '../utils/source-row-cta'
|
|
38
|
+
import { resolveHrefForRuntime } from '../utils/chat-nav-resolution'
|
|
39
|
+
import {
|
|
40
|
+
computeIsNewTab,
|
|
41
|
+
newTabAnchorAttrs,
|
|
42
|
+
buildAnchorProps,
|
|
43
|
+
} from '../utils/nav-anchor-props'
|
|
44
|
+
import { safeHref } from '../utils/compact-card-classes'
|
|
45
|
+
import { useChatPanel } from '../chat-panel-context'
|
|
46
|
+
import { getSourceLabel } from '../utils/source-icons'
|
|
47
|
+
import { SourceActionButton } from '../source-action-button'
|
|
48
|
+
import { NavLinkAnchorViaRuntime } from '../nav-link-anchor-via-runtime'
|
|
49
|
+
import { DEFAULT_PROGRAM_CONFIGS } from './program-card-defaults'
|
|
50
|
+
import { defaultBuildProductReleaseCardProps } from './product-release-card-defaults'
|
|
51
|
+
import { ChatVideoEntityCard } from './chat-video-entity-card'
|
|
52
|
+
import { BlockCard } from './block-card'
|
|
53
|
+
import { BlogCard, BlogCardSkeleton } from './blog-card'
|
|
54
|
+
import { CaseStudyCard, CaseStudyCardSkeleton } from './case-study-card'
|
|
55
|
+
import {
|
|
56
|
+
CustomerInterviewCard,
|
|
57
|
+
CustomerInterviewCardSkeleton,
|
|
58
|
+
} from './customer-interview-card'
|
|
59
|
+
import {
|
|
60
|
+
ProductReleaseCard,
|
|
61
|
+
ProductReleaseCardSkeleton,
|
|
62
|
+
type ProductReleaseCardProps,
|
|
63
|
+
} from './product-release-card'
|
|
64
|
+
import {
|
|
65
|
+
ProgramCard,
|
|
66
|
+
ProgramCardSkeleton,
|
|
67
|
+
type ProgramCardProps,
|
|
68
|
+
} from './program-card'
|
|
69
|
+
import {
|
|
70
|
+
InvestorUpdateCard,
|
|
71
|
+
InvestorUpdateCardSkeleton,
|
|
72
|
+
} from './investor-update-card'
|
|
73
|
+
import {
|
|
74
|
+
OnboardingGuideCard,
|
|
75
|
+
OnboardingGuideCardSkeleton,
|
|
76
|
+
} from './onboarding-guide-card'
|
|
77
|
+
import {
|
|
78
|
+
CampaignCardAdmin,
|
|
79
|
+
CampaignCardAdminSkeleton,
|
|
80
|
+
} from './campaign-card-admin'
|
|
81
|
+
import { RoadmapCard, RoadmapCardSkeleton } from './roadmap-card'
|
|
82
|
+
import {
|
|
83
|
+
GitHubActivityCard,
|
|
84
|
+
type GitHubActivityCardAnchorProps,
|
|
85
|
+
} from './github-activity-card'
|
|
86
|
+
import { SlackMessageCard } from './slack-message-card'
|
|
87
|
+
import { HubspotTicketCard } from './hubspot-ticket-card'
|
|
88
|
+
import { DataRoomDocCard } from './data-room-doc-card'
|
|
89
|
+
import {
|
|
90
|
+
GenericEntityCard,
|
|
91
|
+
type GenericEntityCardAnchorProps,
|
|
92
|
+
} from './generic-entity-card'
|
|
93
|
+
import type { GitHubActivityKind } from '../types/entities/github-activity'
|
|
94
|
+
import type { BaseProgramItem, ProgramConfig } from '../types/entities/program-types'
|
|
95
|
+
|
|
96
|
+
// =============================================================================
|
|
97
|
+
// Public option / extras shape
|
|
98
|
+
// =============================================================================
|
|
99
|
+
|
|
100
|
+
/** Optional host-side extras threaded through to render functions whose
|
|
101
|
+
* derived props can't be computed in lib alone (program configs and the
|
|
102
|
+
* product-release prop builder live in hub land). When omitted, the
|
|
103
|
+
* affected card types render `null` from the dispatch — the chat shell's
|
|
104
|
+
* fallback path takes over. */
|
|
105
|
+
export interface ChatCardDispatchExtras {
|
|
106
|
+
/** Per-program-type config map. Keyed by chat documentType
|
|
107
|
+
* (`podcast` / `webinar` / `event`). Each entry is the canonical
|
|
108
|
+
* `<ProgramConfig>` the `<ProgramCard>` expects. */
|
|
109
|
+
programConfigs?: {
|
|
110
|
+
podcast?: ProgramConfig<any>
|
|
111
|
+
webinar?: ProgramConfig<any>
|
|
112
|
+
event?: ProgramConfig<any>
|
|
113
|
+
}
|
|
114
|
+
/** Derive the `<ProductReleaseCard>` prop bundle from a hydrated
|
|
115
|
+
* release row. Hub callers wire `buildProductReleaseCardProps` from
|
|
116
|
+
* `lib/utils/product-release-card-props.ts`. */
|
|
117
|
+
buildProductReleaseCardProps?: (
|
|
118
|
+
release: any,
|
|
119
|
+
) => Omit<ProductReleaseCardProps, 'size' | 'title' | 'summary' | 'version' | 'anchorProps'>
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Per-card render options threaded through from the chat shell. */
|
|
123
|
+
export interface ChatCardRenderOptions {
|
|
124
|
+
baseRoute?: string
|
|
125
|
+
chipBasePlatform?: string
|
|
126
|
+
/** Host-supplied builders for cards whose derived props live in hub
|
|
127
|
+
* land (programs + product_release). When omitted, these card types
|
|
128
|
+
* render `null` and the shell falls back to title text. */
|
|
129
|
+
extras?: ChatCardDispatchExtras
|
|
130
|
+
/** Pre-computed new-tab decision for the inner anchor's `target`
|
|
131
|
+
* attribute. Required — always computed by `ChatCardLoader` via the
|
|
132
|
+
* same rule source chips use, so the rendered `<a target>` matches
|
|
133
|
+
* whatever `ChatCardNavWrap` + `handleChatNavClick` decide at click
|
|
134
|
+
* time. */
|
|
135
|
+
isNewTab: boolean
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// =============================================================================
|
|
139
|
+
// Per-type "no-fetch" wrapper components (ChatRef carries everything).
|
|
140
|
+
// Each wrapper receives `isNewTab` as a prop — `ChatCardLoader` computes
|
|
141
|
+
// it ONCE via `computeIsNewTab` against the resolved `chatRef.url` and
|
|
142
|
+
// threads it through `renderOpts`. Wrappers must NOT call
|
|
143
|
+
// `computeIsNewTab` themselves; the parent's decision is the single
|
|
144
|
+
// source of truth for the rendered `<a target>` AND `ChatCardNavWrap`'s
|
|
145
|
+
// close-on-nav gate.
|
|
146
|
+
// =============================================================================
|
|
147
|
+
|
|
148
|
+
function GitHubChatCard({
|
|
149
|
+
chatRef,
|
|
150
|
+
kind,
|
|
151
|
+
isNewTab,
|
|
152
|
+
}: {
|
|
153
|
+
chatRef: ChatRef
|
|
154
|
+
kind: GitHubActivityKind
|
|
155
|
+
isNewTab: boolean
|
|
156
|
+
}) {
|
|
157
|
+
const anchorProps: GitHubActivityCardAnchorProps | undefined = buildAnchorProps(
|
|
158
|
+
chatRef.url,
|
|
159
|
+
isNewTab,
|
|
160
|
+
)
|
|
161
|
+
return (
|
|
162
|
+
<GitHubActivityCard
|
|
163
|
+
item={{
|
|
164
|
+
id: chatRef.id,
|
|
165
|
+
title: chatRef.title,
|
|
166
|
+
url: chatRef.url ?? null,
|
|
167
|
+
dateUpdated: chatRef.date ?? null,
|
|
168
|
+
kind,
|
|
169
|
+
}}
|
|
170
|
+
variant="compact"
|
|
171
|
+
anchorProps={anchorProps}
|
|
172
|
+
/>
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function HubspotTicketChatCard({
|
|
177
|
+
chatRef,
|
|
178
|
+
isNewTab,
|
|
179
|
+
}: {
|
|
180
|
+
chatRef: ChatRef
|
|
181
|
+
isNewTab: boolean
|
|
182
|
+
}) {
|
|
183
|
+
const status =
|
|
184
|
+
typeof chatRef.metadata?.status === 'string' ? (chatRef.metadata.status as string) : undefined
|
|
185
|
+
const statusLabel =
|
|
186
|
+
typeof chatRef.metadata?.statusLabel === 'string'
|
|
187
|
+
? (chatRef.metadata.statusLabel as string)
|
|
188
|
+
: undefined
|
|
189
|
+
const priority =
|
|
190
|
+
typeof chatRef.metadata?.priority === 'string'
|
|
191
|
+
? (chatRef.metadata.priority as string)
|
|
192
|
+
: undefined
|
|
193
|
+
const customerCompany =
|
|
194
|
+
typeof chatRef.metadata?.customerCompany === 'string'
|
|
195
|
+
? (chatRef.metadata.customerCompany as string)
|
|
196
|
+
: undefined
|
|
197
|
+
const customerEmail =
|
|
198
|
+
typeof chatRef.metadata?.customerEmail === 'string'
|
|
199
|
+
? (chatRef.metadata.customerEmail as string)
|
|
200
|
+
: undefined
|
|
201
|
+
return (
|
|
202
|
+
<HubspotTicketCard
|
|
203
|
+
item={{
|
|
204
|
+
id: chatRef.id,
|
|
205
|
+
title: chatRef.title,
|
|
206
|
+
preview: chatRef.preview,
|
|
207
|
+
status,
|
|
208
|
+
statusLabel,
|
|
209
|
+
priority,
|
|
210
|
+
customerCompany,
|
|
211
|
+
customerEmail,
|
|
212
|
+
url: chatRef.url ?? null,
|
|
213
|
+
dateUpdated: chatRef.date ?? null,
|
|
214
|
+
}}
|
|
215
|
+
variant="compact"
|
|
216
|
+
anchorProps={buildAnchorProps(chatRef.url, isNewTab)}
|
|
217
|
+
/>
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function SlackChatCard({ chatRef, isNewTab }: { chatRef: ChatRef; isNewTab: boolean }) {
|
|
222
|
+
const channelName =
|
|
223
|
+
typeof chatRef.metadata?.channelName === 'string'
|
|
224
|
+
? (chatRef.metadata.channelName as string)
|
|
225
|
+
: undefined
|
|
226
|
+
return (
|
|
227
|
+
<SlackMessageCard
|
|
228
|
+
item={{
|
|
229
|
+
id: chatRef.id,
|
|
230
|
+
title: chatRef.title,
|
|
231
|
+
preview: chatRef.preview,
|
|
232
|
+
url: chatRef.url ?? null,
|
|
233
|
+
dateUpdated: chatRef.date ?? null,
|
|
234
|
+
channel: channelName,
|
|
235
|
+
}}
|
|
236
|
+
variant="compact"
|
|
237
|
+
anchorProps={buildAnchorProps(chatRef.url, isNewTab)}
|
|
238
|
+
/>
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function DataRoomDocChatCard({
|
|
243
|
+
chatRef,
|
|
244
|
+
baseRoute,
|
|
245
|
+
chipBasePlatform,
|
|
246
|
+
isNewTab,
|
|
247
|
+
}: {
|
|
248
|
+
chatRef: ChatRef
|
|
249
|
+
baseRoute?: string
|
|
250
|
+
chipBasePlatform?: string
|
|
251
|
+
isNewTab: boolean
|
|
252
|
+
}) {
|
|
253
|
+
const path =
|
|
254
|
+
typeof chatRef.metadata?.path === 'string' ? (chatRef.metadata.path as string) : undefined
|
|
255
|
+
// Provenance label. NEVER fall back to "Data room" — that would
|
|
256
|
+
// falsely label non-data-room content (openframe-docs, etc.) as
|
|
257
|
+
// private investor material when `sourceRepo` is missing or
|
|
258
|
+
// unrecognized. Generic "Document" is intentionally neutral so users
|
|
259
|
+
// can't be misled about sensitivity / scope.
|
|
260
|
+
const badgeText = chatRef.sourceRepo ? getSourceLabel(chatRef.sourceRepo) : 'Document'
|
|
261
|
+
return (
|
|
262
|
+
<DataRoomDocCard
|
|
263
|
+
item={{
|
|
264
|
+
id: chatRef.id,
|
|
265
|
+
title: chatRef.title,
|
|
266
|
+
preview: chatRef.preview ?? undefined,
|
|
267
|
+
path,
|
|
268
|
+
url: chatRef.url ?? null,
|
|
269
|
+
sourceRepo: chatRef.sourceRepo ?? null,
|
|
270
|
+
baseRoute,
|
|
271
|
+
chipBasePlatform,
|
|
272
|
+
}}
|
|
273
|
+
badgeText={badgeText}
|
|
274
|
+
anchorProps={buildAnchorProps(chatRef.url, isNewTab)}
|
|
275
|
+
/>
|
|
276
|
+
)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function GenericFinancialChatCard({
|
|
280
|
+
chatRef,
|
|
281
|
+
badge,
|
|
282
|
+
scheme,
|
|
283
|
+
isNewTab,
|
|
284
|
+
}: {
|
|
285
|
+
chatRef: ChatRef
|
|
286
|
+
badge: string
|
|
287
|
+
scheme: 'cyan' | 'warning' | 'success' | 'error' | 'default'
|
|
288
|
+
isNewTab: boolean
|
|
289
|
+
}) {
|
|
290
|
+
const facts = Array.isArray(chatRef.metadata?.facts)
|
|
291
|
+
? (chatRef.metadata!.facts as Array<{ label: string; value: string }>)
|
|
292
|
+
: null
|
|
293
|
+
const subtitle =
|
|
294
|
+
typeof chatRef.metadata?.subtitle === 'string'
|
|
295
|
+
? (chatRef.metadata.subtitle as string)
|
|
296
|
+
: null
|
|
297
|
+
const anchorProps: GenericEntityCardAnchorProps | undefined = buildAnchorProps(
|
|
298
|
+
chatRef.url,
|
|
299
|
+
isNewTab,
|
|
300
|
+
)
|
|
301
|
+
return (
|
|
302
|
+
<GenericEntityCard
|
|
303
|
+
item={{
|
|
304
|
+
id: chatRef.id,
|
|
305
|
+
title: chatRef.title,
|
|
306
|
+
subtitle,
|
|
307
|
+
preview: chatRef.preview ?? null,
|
|
308
|
+
url: chatRef.url ?? null,
|
|
309
|
+
badge: { text: badge, scheme },
|
|
310
|
+
facts,
|
|
311
|
+
dateUpdated: chatRef.date ?? null,
|
|
312
|
+
}}
|
|
313
|
+
anchorProps={anchorProps}
|
|
314
|
+
/>
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function ChatInlineVideoPill({ chatRef }: { chatRef: ChatRef }) {
|
|
319
|
+
const title = chatRef.title || 'Video'
|
|
320
|
+
return (
|
|
321
|
+
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs align-middle bg-ods-card border border-ods-border text-ods-text-primary">
|
|
322
|
+
<span aria-hidden="true" className="text-ods-text-secondary">▶</span>
|
|
323
|
+
<span className="truncate max-w-[220px]">{title}</span>
|
|
324
|
+
</span>
|
|
325
|
+
)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/** Wrap a chat-inline card with the "Ask"/"Display" affordance + source
|
|
329
|
+
* tracking strip. Mirrors the hub's `ChatCardWithDiscuss` layout exactly
|
|
330
|
+
* — the visual contract here drove the lib refactor in the first place. */
|
|
331
|
+
function ChatCardWithDiscuss({
|
|
332
|
+
chatRef,
|
|
333
|
+
onDiscuss,
|
|
334
|
+
onDisplay,
|
|
335
|
+
displayAction,
|
|
336
|
+
children,
|
|
337
|
+
}: {
|
|
338
|
+
chatRef: ChatRef
|
|
339
|
+
onDiscuss?: (ref: ChatRef) => void
|
|
340
|
+
onDisplay?: (ref: ChatRef) => void
|
|
341
|
+
displayAction?: boolean
|
|
342
|
+
children: React.ReactNode
|
|
343
|
+
}) {
|
|
344
|
+
const { Icon: SourceIcon, label: sourceLabel } = resolveSourceIcon({
|
|
345
|
+
sourceRepo: chatRef.sourceRepo,
|
|
346
|
+
documentType: chatRef.type,
|
|
347
|
+
})
|
|
348
|
+
const idDisplay =
|
|
349
|
+
chatRef.id && (chatRef.id.length > 24 ? `${chatRef.id.slice(0, 24)}…` : chatRef.id)
|
|
350
|
+
const useDisplay = displayAction && !!onDisplay
|
|
351
|
+
const cardBody = <span className="block [&>*]:!my-0">{children}</span>
|
|
352
|
+
return (
|
|
353
|
+
<span className="mt-1.5 mb-2 block w-full">
|
|
354
|
+
{cardBody}
|
|
355
|
+
<span className="mt-1 flex items-center justify-between gap-2 pl-0.5">
|
|
356
|
+
<SourceActionButton
|
|
357
|
+
chatRef={chatRef}
|
|
358
|
+
onDiscuss={useDisplay ? onDisplay : onDiscuss}
|
|
359
|
+
label={useDisplay ? 'Display' : undefined}
|
|
360
|
+
density="card"
|
|
361
|
+
/>
|
|
362
|
+
{!onDiscuss && !useDisplay ? <span /> : null}
|
|
363
|
+
{idDisplay ? (
|
|
364
|
+
<span
|
|
365
|
+
className="inline-flex items-center gap-1 text-[10px] leading-3 font-mono shrink-0 text-ods-text-secondary opacity-60 hover:opacity-100 hover:text-ods-text-primary transition-opacity"
|
|
366
|
+
title={`${sourceLabel} · ${chatRef.id}`}
|
|
367
|
+
>
|
|
368
|
+
<SourceIcon className="h-3 w-3 shrink-0" />
|
|
369
|
+
<span className="truncate max-w-[180px]">{idDisplay}</span>
|
|
370
|
+
</span>
|
|
371
|
+
) : null}
|
|
372
|
+
</span>
|
|
373
|
+
</span>
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// =============================================================================
|
|
378
|
+
// Per-type fetch-mode card body — composed by ChatCardLoader once item is in.
|
|
379
|
+
// =============================================================================
|
|
380
|
+
|
|
381
|
+
/** Anchor-wrapped product-release card. */
|
|
382
|
+
function ProductReleaseChatCard({
|
|
383
|
+
item,
|
|
384
|
+
chatRef,
|
|
385
|
+
buildProps,
|
|
386
|
+
isNewTab,
|
|
387
|
+
}: {
|
|
388
|
+
item: any
|
|
389
|
+
chatRef: ChatRef
|
|
390
|
+
buildProps: NonNullable<ChatCardDispatchExtras['buildProductReleaseCardProps']>
|
|
391
|
+
isNewTab: boolean
|
|
392
|
+
}) {
|
|
393
|
+
const releaseProps = buildProps(item)
|
|
394
|
+
return (
|
|
395
|
+
<ProductReleaseCard
|
|
396
|
+
size="sm"
|
|
397
|
+
title={item.title}
|
|
398
|
+
summary={item.summary}
|
|
399
|
+
version={item.version}
|
|
400
|
+
{...releaseProps}
|
|
401
|
+
anchorProps={buildAnchorProps(chatRef.url, isNewTab)}
|
|
402
|
+
/>
|
|
403
|
+
)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** Anchor-wrapped marketing-campaign card. Campaigns have no public
|
|
407
|
+
* viewer; the registry entry's `fallbackHref` synthesizes the admin
|
|
408
|
+
* URL upstream in `ChatCardLoader`, so by the time we render here
|
|
409
|
+
* `chatRef.url` is guaranteed non-null AND the parent's `isNewTab`
|
|
410
|
+
* reflects the actual destination. */
|
|
411
|
+
function CampaignChatCard({
|
|
412
|
+
item,
|
|
413
|
+
chatRef,
|
|
414
|
+
isNewTab,
|
|
415
|
+
}: {
|
|
416
|
+
item: any
|
|
417
|
+
chatRef: ChatRef
|
|
418
|
+
isNewTab: boolean
|
|
419
|
+
}) {
|
|
420
|
+
return (
|
|
421
|
+
<CampaignCardAdmin
|
|
422
|
+
campaign={item}
|
|
423
|
+
anchorProps={buildAnchorProps(chatRef.url, isNewTab)!}
|
|
424
|
+
/>
|
|
425
|
+
)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// =============================================================================
|
|
429
|
+
// CHAT_CARD_REGISTRY — single source of truth.
|
|
430
|
+
// =============================================================================
|
|
431
|
+
|
|
432
|
+
type ChatCardRegistryEntry =
|
|
433
|
+
| {
|
|
434
|
+
mode: 'no-fetch'
|
|
435
|
+
label: string
|
|
436
|
+
bareInline?: boolean
|
|
437
|
+
displayAction?: boolean
|
|
438
|
+
render: (chatRef: ChatRef, opts: ChatCardRenderOptions) => React.ReactNode
|
|
439
|
+
}
|
|
440
|
+
| {
|
|
441
|
+
mode: 'fetch'
|
|
442
|
+
label: string
|
|
443
|
+
contentRefType: string
|
|
444
|
+
displayAction?: boolean
|
|
445
|
+
skeleton: () => React.ReactNode
|
|
446
|
+
render: (item: any, chatRef: ChatRef, opts: ChatCardRenderOptions) => React.ReactNode
|
|
447
|
+
/** Optional post-fetch URL synthesizer. When `chatRef.url` is null
|
|
448
|
+
* AFTER `resolveSourceRowCTA`, the loader runs this against the
|
|
449
|
+
* hydrated item to produce a fallback hub-internal URL (e.g.
|
|
450
|
+
* `/admin/campaigns/${item.id}` for marketing campaigns). Result
|
|
451
|
+
* is validated via `safeHref` before being attached to the
|
|
452
|
+
* resolved ref — so the wrapper sees a non-null `href`, the
|
|
453
|
+
* pre-computed `isNewTab` reflects the actual destination, and
|
|
454
|
+
* the click goes through `handleChatNavClick` (no silent
|
|
455
|
+
* bypass of embed-mode / close-on-nav). */
|
|
456
|
+
fallbackHref?: (item: any) => string | null
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
type FinancialBadgeScheme = 'cyan' | 'warning' | 'success' | 'error' | 'default'
|
|
460
|
+
interface FinancialBadgeConfig {
|
|
461
|
+
label: string
|
|
462
|
+
badge: string
|
|
463
|
+
scheme?: FinancialBadgeScheme
|
|
464
|
+
}
|
|
465
|
+
const FINANCIAL_CARD_BADGES: Record<string, FinancialBadgeConfig> = {
|
|
466
|
+
financial_kpi: { label: 'Financial KPI', badge: 'KPI', scheme: 'cyan' },
|
|
467
|
+
cap_table: { label: 'Cap table entry', badge: 'Cap table', scheme: 'warning' },
|
|
468
|
+
profit_loss: { label: 'P&L period', badge: 'P&L' },
|
|
469
|
+
balance_sheet: { label: 'Balance sheet', badge: 'Balance sheet' },
|
|
470
|
+
cash_flow: { label: 'Cash flow', badge: 'Cash flow' },
|
|
471
|
+
}
|
|
472
|
+
function financialRegistryEntries(): Record<string, ChatCardRegistryEntry> {
|
|
473
|
+
const out: Record<string, ChatCardRegistryEntry> = {}
|
|
474
|
+
for (const [docType, cfg] of Object.entries(FINANCIAL_CARD_BADGES)) {
|
|
475
|
+
const scheme = cfg.scheme ?? 'default'
|
|
476
|
+
out[docType] = {
|
|
477
|
+
mode: 'no-fetch',
|
|
478
|
+
label: cfg.label,
|
|
479
|
+
render: (chatRef, opts) => (
|
|
480
|
+
<GenericFinancialChatCard
|
|
481
|
+
chatRef={chatRef}
|
|
482
|
+
badge={cfg.badge}
|
|
483
|
+
scheme={scheme}
|
|
484
|
+
isNewTab={opts.isNewTab}
|
|
485
|
+
/>
|
|
486
|
+
),
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return out
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
interface GitHubCardConfig {
|
|
493
|
+
label: string
|
|
494
|
+
kind: GitHubActivityKind
|
|
495
|
+
}
|
|
496
|
+
const GITHUB_CARD_CONFIGS: Record<string, GitHubCardConfig> = {
|
|
497
|
+
github_commit: { label: 'GitHub commit', kind: 'commit' },
|
|
498
|
+
github_commit_public: { label: 'GitHub commit (public)', kind: 'commit' },
|
|
499
|
+
github_pull_request: { label: 'GitHub PR', kind: 'pull_request' },
|
|
500
|
+
github_pull_request_public: { label: 'GitHub PR (public)', kind: 'pull_request' },
|
|
501
|
+
github_pr_review: { label: 'GitHub review', kind: 'pr_review' },
|
|
502
|
+
github_pr_review_public: { label: 'GitHub review (public)', kind: 'pr_review' },
|
|
503
|
+
}
|
|
504
|
+
function githubRegistryEntries(): Record<string, ChatCardRegistryEntry> {
|
|
505
|
+
const out: Record<string, ChatCardRegistryEntry> = {}
|
|
506
|
+
for (const [docType, cfg] of Object.entries(GITHUB_CARD_CONFIGS)) {
|
|
507
|
+
out[docType] = {
|
|
508
|
+
mode: 'no-fetch',
|
|
509
|
+
label: cfg.label,
|
|
510
|
+
render: (chatRef, opts) => (
|
|
511
|
+
<GitHubChatCard chatRef={chatRef} kind={cfg.kind} isNewTab={opts.isNewTab} />
|
|
512
|
+
),
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return out
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
type ProgramConfigKey = 'podcast' | 'webinar' | 'event'
|
|
519
|
+
interface ProgramCardConfig {
|
|
520
|
+
label: string
|
|
521
|
+
configKey: ProgramConfigKey
|
|
522
|
+
contentRefType: string
|
|
523
|
+
}
|
|
524
|
+
const PROGRAM_CARD_CONFIGS: Record<string, ProgramCardConfig> = {
|
|
525
|
+
podcast: { label: 'Podcast episode', configKey: 'podcast', contentRefType: 'podcast' },
|
|
526
|
+
webinar: { label: 'Webinar', configKey: 'webinar', contentRefType: 'webinar' },
|
|
527
|
+
event: { label: 'Event', configKey: 'event', contentRefType: 'event' },
|
|
528
|
+
}
|
|
529
|
+
function programRegistryEntries(): Record<string, ChatCardRegistryEntry> {
|
|
530
|
+
const out: Record<string, ChatCardRegistryEntry> = {}
|
|
531
|
+
for (const [docType, cfg] of Object.entries(PROGRAM_CARD_CONFIGS)) {
|
|
532
|
+
out[docType] = {
|
|
533
|
+
mode: 'fetch',
|
|
534
|
+
label: cfg.label,
|
|
535
|
+
contentRefType: cfg.contentRefType,
|
|
536
|
+
skeleton: () => <ProgramCardSkeleton size="sm" />,
|
|
537
|
+
render: (item, chatRef, opts) => {
|
|
538
|
+
// Embedder-provided config wins; lib default fills in otherwise
|
|
539
|
+
// so the compact card renders even without `extras`. See
|
|
540
|
+
// `program-card-defaults.ts` for the rationale.
|
|
541
|
+
const config =
|
|
542
|
+
opts?.extras?.programConfigs?.[cfg.configKey] ??
|
|
543
|
+
DEFAULT_PROGRAM_CONFIGS[cfg.configKey]
|
|
544
|
+
return (
|
|
545
|
+
<ProgramCard
|
|
546
|
+
config={config}
|
|
547
|
+
item={item as BaseProgramItem}
|
|
548
|
+
size="sm"
|
|
549
|
+
href={chatRef.url ?? ''}
|
|
550
|
+
targetPlatform={chatRef.targetPlatform ?? null}
|
|
551
|
+
{...newTabAnchorAttrs(opts.isNewTab)}
|
|
552
|
+
/>
|
|
553
|
+
)
|
|
554
|
+
},
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return out
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
type RoadmapCardType = 'roadmap_item' | 'delivery_item' | 'internal_task'
|
|
561
|
+
interface RoadmapEntryConfig {
|
|
562
|
+
label: string
|
|
563
|
+
cardType: RoadmapCardType
|
|
564
|
+
contentRefType: string
|
|
565
|
+
}
|
|
566
|
+
const ROADMAP_CARD_CONFIGS: Record<string, RoadmapEntryConfig> = {
|
|
567
|
+
roadmap_item: { label: 'Roadmap item', cardType: 'roadmap_item', contentRefType: 'roadmap_item' },
|
|
568
|
+
delivery_item: {
|
|
569
|
+
label: 'Delivery item',
|
|
570
|
+
cardType: 'delivery_item',
|
|
571
|
+
contentRefType: 'delivery_item',
|
|
572
|
+
},
|
|
573
|
+
internal_task: {
|
|
574
|
+
label: 'Internal task',
|
|
575
|
+
cardType: 'internal_task',
|
|
576
|
+
contentRefType: 'internal_task',
|
|
577
|
+
},
|
|
578
|
+
}
|
|
579
|
+
function roadmapRegistryEntries(): Record<string, ChatCardRegistryEntry> {
|
|
580
|
+
const out: Record<string, ChatCardRegistryEntry> = {}
|
|
581
|
+
for (const [docType, cfg] of Object.entries(ROADMAP_CARD_CONFIGS)) {
|
|
582
|
+
out[docType] = {
|
|
583
|
+
mode: 'fetch',
|
|
584
|
+
label: cfg.label,
|
|
585
|
+
contentRefType: cfg.contentRefType,
|
|
586
|
+
skeleton: () => <RoadmapCardSkeleton size="sm" />,
|
|
587
|
+
render: (item, chatRef, opts) => (
|
|
588
|
+
<RoadmapCard
|
|
589
|
+
item={item}
|
|
590
|
+
href={chatRef.url ?? ''}
|
|
591
|
+
targetPlatform={chatRef.targetPlatform ?? null}
|
|
592
|
+
{...newTabAnchorAttrs(opts.isNewTab)}
|
|
593
|
+
userVote={null}
|
|
594
|
+
onVote={() => {}}
|
|
595
|
+
size="sm"
|
|
596
|
+
cardType={cfg.cardType}
|
|
597
|
+
/>
|
|
598
|
+
),
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return out
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const CHAT_CARD_REGISTRY: Record<string, ChatCardRegistryEntry> = {
|
|
605
|
+
// ───────── no-fetch: ChatRef carries everything ─────────
|
|
606
|
+
...githubRegistryEntries(),
|
|
607
|
+
slack_message: {
|
|
608
|
+
mode: 'no-fetch',
|
|
609
|
+
label: 'Slack message',
|
|
610
|
+
render: (chatRef, opts) => (
|
|
611
|
+
<SlackChatCard chatRef={chatRef} isNewTab={opts.isNewTab} />
|
|
612
|
+
),
|
|
613
|
+
},
|
|
614
|
+
hubspot_ticket: {
|
|
615
|
+
mode: 'no-fetch',
|
|
616
|
+
label: 'HubSpot ticket',
|
|
617
|
+
render: (chatRef, opts) => (
|
|
618
|
+
<HubspotTicketChatCard chatRef={chatRef} isNewTab={opts.isNewTab} />
|
|
619
|
+
),
|
|
620
|
+
},
|
|
621
|
+
hubspot_ticket_anon: {
|
|
622
|
+
mode: 'no-fetch',
|
|
623
|
+
label: 'HubSpot ticket (anon)',
|
|
624
|
+
render: (chatRef, opts) => (
|
|
625
|
+
<HubspotTicketChatCard chatRef={chatRef} isNewTab={opts.isNewTab} />
|
|
626
|
+
),
|
|
627
|
+
},
|
|
628
|
+
hubspot_ticket_self: {
|
|
629
|
+
mode: 'no-fetch',
|
|
630
|
+
label: 'HubSpot ticket (self)',
|
|
631
|
+
render: (chatRef, opts) => (
|
|
632
|
+
<HubspotTicketChatCard chatRef={chatRef} isNewTab={opts.isNewTab} />
|
|
633
|
+
),
|
|
634
|
+
},
|
|
635
|
+
data_room_doc: {
|
|
636
|
+
mode: 'no-fetch',
|
|
637
|
+
label: 'Data-room doc',
|
|
638
|
+
render: (chatRef, opts) => (
|
|
639
|
+
<DataRoomDocChatCard
|
|
640
|
+
chatRef={chatRef}
|
|
641
|
+
baseRoute={opts?.baseRoute}
|
|
642
|
+
chipBasePlatform={opts?.chipBasePlatform}
|
|
643
|
+
isNewTab={opts.isNewTab}
|
|
644
|
+
/>
|
|
645
|
+
),
|
|
646
|
+
},
|
|
647
|
+
markdown: {
|
|
648
|
+
mode: 'no-fetch',
|
|
649
|
+
label: 'Doc page (markdown)',
|
|
650
|
+
render: (chatRef, opts) => (
|
|
651
|
+
<DataRoomDocChatCard
|
|
652
|
+
chatRef={chatRef}
|
|
653
|
+
baseRoute={opts?.baseRoute}
|
|
654
|
+
chipBasePlatform={opts?.chipBasePlatform}
|
|
655
|
+
isNewTab={opts.isNewTab}
|
|
656
|
+
/>
|
|
657
|
+
),
|
|
658
|
+
},
|
|
659
|
+
video: {
|
|
660
|
+
mode: 'no-fetch',
|
|
661
|
+
label: 'Video',
|
|
662
|
+
bareInline: true,
|
|
663
|
+
render: (chatRef) => <ChatInlineVideoPill chatRef={chatRef} />,
|
|
664
|
+
},
|
|
665
|
+
...financialRegistryEntries(),
|
|
666
|
+
|
|
667
|
+
// ───────── fetch: needs full row from list API ─────────
|
|
668
|
+
blog_post: {
|
|
669
|
+
mode: 'fetch',
|
|
670
|
+
label: 'Blog post',
|
|
671
|
+
contentRefType: 'blog_post_existing',
|
|
672
|
+
skeleton: () => <BlogCardSkeleton size="sm" />,
|
|
673
|
+
render: (item, chatRef, opts) => (
|
|
674
|
+
<BlogCard
|
|
675
|
+
post={item}
|
|
676
|
+
size="sm"
|
|
677
|
+
href={chatRef.url ?? ''}
|
|
678
|
+
targetPlatform={chatRef.targetPlatform ?? null}
|
|
679
|
+
{...newTabAnchorAttrs(opts.isNewTab)}
|
|
680
|
+
hasEmbeddedVideo={chatRef.metadata?.hasEmbeddedVideo === true}
|
|
681
|
+
/>
|
|
682
|
+
),
|
|
683
|
+
},
|
|
684
|
+
case_study: {
|
|
685
|
+
mode: 'fetch',
|
|
686
|
+
label: 'Case study',
|
|
687
|
+
contentRefType: 'case_study',
|
|
688
|
+
skeleton: () => <CaseStudyCardSkeleton size="sm" />,
|
|
689
|
+
render: (item, chatRef, opts) => (
|
|
690
|
+
<CaseStudyCard
|
|
691
|
+
study={item}
|
|
692
|
+
size="sm"
|
|
693
|
+
href={chatRef.url ?? ''}
|
|
694
|
+
targetPlatform={chatRef.targetPlatform ?? null}
|
|
695
|
+
{...newTabAnchorAttrs(opts.isNewTab)}
|
|
696
|
+
/>
|
|
697
|
+
),
|
|
698
|
+
},
|
|
699
|
+
customer_interview: {
|
|
700
|
+
mode: 'fetch',
|
|
701
|
+
label: 'Customer interview',
|
|
702
|
+
contentRefType: 'customer_interview',
|
|
703
|
+
skeleton: () => <CustomerInterviewCardSkeleton size="sm" />,
|
|
704
|
+
render: (item, chatRef, opts) => (
|
|
705
|
+
<CustomerInterviewCard
|
|
706
|
+
interview={item}
|
|
707
|
+
size="sm"
|
|
708
|
+
href={chatRef.url ?? ''}
|
|
709
|
+
targetPlatform={chatRef.targetPlatform ?? null}
|
|
710
|
+
{...newTabAnchorAttrs(opts.isNewTab)}
|
|
711
|
+
/>
|
|
712
|
+
),
|
|
713
|
+
},
|
|
714
|
+
product_release: {
|
|
715
|
+
mode: 'fetch',
|
|
716
|
+
label: 'Product release',
|
|
717
|
+
contentRefType: 'product_release',
|
|
718
|
+
skeleton: () => <ProductReleaseCardSkeleton size="sm" />,
|
|
719
|
+
render: (item, chatRef, opts) => {
|
|
720
|
+
// Embedder-provided builder wins; lib default fills in otherwise
|
|
721
|
+
// (covers `coverImage`, `hasVideoCover`, `formattedDate` — the
|
|
722
|
+
// three fields the compact `size='sm'` card actually reads).
|
|
723
|
+
// Hub-side embedders still pass their richer builder via
|
|
724
|
+
// `extras.buildProductReleaseCardProps` to get lg-only metadata
|
|
725
|
+
// (badge color, changelog counts, etc.).
|
|
726
|
+
const builder =
|
|
727
|
+
opts?.extras?.buildProductReleaseCardProps ?? defaultBuildProductReleaseCardProps
|
|
728
|
+
return (
|
|
729
|
+
<ProductReleaseChatCard
|
|
730
|
+
item={item}
|
|
731
|
+
chatRef={chatRef}
|
|
732
|
+
buildProps={builder}
|
|
733
|
+
isNewTab={opts.isNewTab}
|
|
734
|
+
/>
|
|
735
|
+
)
|
|
736
|
+
},
|
|
737
|
+
},
|
|
738
|
+
...programRegistryEntries(),
|
|
739
|
+
investor_update: {
|
|
740
|
+
mode: 'fetch',
|
|
741
|
+
label: 'Investor update',
|
|
742
|
+
contentRefType: 'investor_update',
|
|
743
|
+
skeleton: () => <InvestorUpdateCardSkeleton size="sm" />,
|
|
744
|
+
render: (item, chatRef, opts) => (
|
|
745
|
+
<InvestorUpdateCard
|
|
746
|
+
update={item}
|
|
747
|
+
size="sm"
|
|
748
|
+
href={chatRef.url ?? ''}
|
|
749
|
+
targetPlatform={chatRef.targetPlatform ?? null}
|
|
750
|
+
{...newTabAnchorAttrs(opts.isNewTab)}
|
|
751
|
+
/>
|
|
752
|
+
),
|
|
753
|
+
},
|
|
754
|
+
onboarding_guide: {
|
|
755
|
+
mode: 'fetch',
|
|
756
|
+
label: 'Onboarding guide',
|
|
757
|
+
contentRefType: 'onboarding_guide',
|
|
758
|
+
displayAction: true,
|
|
759
|
+
skeleton: () => <OnboardingGuideCardSkeleton size="sm" />,
|
|
760
|
+
render: (item, chatRef, opts) => (
|
|
761
|
+
<OnboardingGuideCard
|
|
762
|
+
guide={item}
|
|
763
|
+
size="sm"
|
|
764
|
+
href={chatRef.url ?? ''}
|
|
765
|
+
targetPlatform={chatRef.targetPlatform ?? null}
|
|
766
|
+
{...newTabAnchorAttrs(opts.isNewTab)}
|
|
767
|
+
/>
|
|
768
|
+
),
|
|
769
|
+
},
|
|
770
|
+
marketing_campaign: {
|
|
771
|
+
mode: 'fetch',
|
|
772
|
+
label: 'Marketing campaign',
|
|
773
|
+
contentRefType: 'marketing_campaign',
|
|
774
|
+
skeleton: () => <CampaignCardAdminSkeleton />,
|
|
775
|
+
// No public viewer — synthesize the hub-internal admin URL post-fetch
|
|
776
|
+
// so the wrapper + isNewTab computation see the actual destination.
|
|
777
|
+
fallbackHref: (item: { id?: string }) =>
|
|
778
|
+
item?.id ? `/admin/campaigns/${encodeURIComponent(item.id)}` : null,
|
|
779
|
+
render: (item, chatRef, opts) => (
|
|
780
|
+
<CampaignChatCard
|
|
781
|
+
item={item}
|
|
782
|
+
chatRef={chatRef}
|
|
783
|
+
isNewTab={opts.isNewTab}
|
|
784
|
+
/>
|
|
785
|
+
),
|
|
786
|
+
},
|
|
787
|
+
...roadmapRegistryEntries(),
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// =============================================================================
|
|
791
|
+
// ChatCardNavWrap — click-capture interceptor that routes inner-anchor
|
|
792
|
+
// clicks through the chat runtime's nav handler.
|
|
793
|
+
//
|
|
794
|
+
// Single source of truth for click handling on EVERY inline card. The
|
|
795
|
+
// card body provides its own `<a href={absolute}>` (per the
|
|
796
|
+
// pure-presentation contract) — this wrapper intercepts the primary
|
|
797
|
+
// click via `onClickCapture` BEFORE the browser's default navigation
|
|
798
|
+
// fires, and routes through `handleChatNavClick` to apply runtime nav
|
|
799
|
+
// rules (embed-mode `window.open` / cross-platform new-tab / host
|
|
800
|
+
// `runtime.navigation.navigate`). Modifier / non-primary clicks pass
|
|
801
|
+
// through (`handleChatNavClick` returns early so the browser opens
|
|
802
|
+
// the inner anchor's href naturally).
|
|
803
|
+
//
|
|
804
|
+
// Same click model as source chips — chips use `<a onClick={handleChatNavClick}>`
|
|
805
|
+
// directly; cards use `<span onClickCapture={→handleChatNavClick}>` outside
|
|
806
|
+
// the card's own anchor. Both ultimately call `handleChatNavClick` with
|
|
807
|
+
// the same `{href, targetPlatform}` resolved at `ChatCardLoader` via
|
|
808
|
+
// `resolveSourceRowCTA`. The unification:
|
|
809
|
+
// - Same URL composition (`resolveSourceRowCTA`)
|
|
810
|
+
// - Same embed-mode prefix (`resolveHrefForRuntime`)
|
|
811
|
+
// - Same click router (`handleChatNavClick`)
|
|
812
|
+
// - Same conditional close (`ChatPanelContext.closeChat` on same-tab only)
|
|
813
|
+
// =============================================================================
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* ChatCardNavWrap — click-capture interceptor for inline cards.
|
|
817
|
+
*
|
|
818
|
+
* `<span onClickCapture>` wrapping the card body. The card renders its
|
|
819
|
+
* own `<a href target rel>` with the canonical pre-resolved href +
|
|
820
|
+
* new-tab decision applied (via `opts.isNewTab` from ChatCardLoader).
|
|
821
|
+
*
|
|
822
|
+
* Job:
|
|
823
|
+
* - PRIMARY clicks → preventDefault + route through `handleChatNavClick`
|
|
824
|
+
* - Modifier-clicks → pass through to the browser's native handling
|
|
825
|
+
* - Same-tab nav → close the chat panel (so the panel doesn't linger
|
|
826
|
+
* over the now-current-page content). New-tab nav leaves it open.
|
|
827
|
+
*
|
|
828
|
+
* Single close path for inline cards. The chip block in
|
|
829
|
+
* `embeddable-chat.tsx` mirrors this logic for source chips. Both
|
|
830
|
+
* gate on `!isNewTab` computed from the same `decideNewTab` rule, so
|
|
831
|
+
* the close decision is consistent across surfaces.
|
|
832
|
+
*/
|
|
833
|
+
function ChatCardNavWrap({
|
|
834
|
+
href,
|
|
835
|
+
path,
|
|
836
|
+
targetPlatform,
|
|
837
|
+
isNewTab,
|
|
838
|
+
children,
|
|
839
|
+
}: {
|
|
840
|
+
href: string | null
|
|
841
|
+
/** In-app doc-tree path for `markdown` / `data_room_doc` refs. The
|
|
842
|
+
* runtime's `navigate({path})` opportunistically swaps the active
|
|
843
|
+
* documentation section without a full page nav; null for everything
|
|
844
|
+
* else. Threaded straight through to `handleChatNavClick` so chips
|
|
845
|
+
* and inline cards apply the same routing rule. */
|
|
846
|
+
path: string | null
|
|
847
|
+
targetPlatform: string | null
|
|
848
|
+
/** New-tab decision pre-computed by the parent `ChatCardLoader` —
|
|
849
|
+
* same value the card's `<a target>` already renders with.
|
|
850
|
+
* Consumed here ONLY to decide whether to close the panel. */
|
|
851
|
+
isNewTab: boolean
|
|
852
|
+
children: ReactNode
|
|
853
|
+
}) {
|
|
854
|
+
const runtime = useRequiredChatRuntime()
|
|
855
|
+
const panel = useChatPanel()
|
|
856
|
+
const onClickCapture = (e: React.MouseEvent<HTMLElement>) => {
|
|
857
|
+
if (!href) return
|
|
858
|
+
const targetEl = e.target as HTMLElement
|
|
859
|
+
// Buttons rendered INSIDE the card's outer `<a>` (e.g. RoadmapCard
|
|
860
|
+
// vote buttons, ImageGallery thumbnails) bubble up with
|
|
861
|
+
// `closest('a')` truthy — without this guard, clicking them would
|
|
862
|
+
// route through the chat nav handler and navigate away from the
|
|
863
|
+
// page. The button's own onClick keeps working because we exit
|
|
864
|
+
// before stopPropagation.
|
|
865
|
+
if (targetEl?.closest?.('button')) return
|
|
866
|
+
if (!targetEl?.closest?.('a')) return
|
|
867
|
+
|
|
868
|
+
const handled = handleChatNavClick(e, runtime, { href, path, targetPlatform })
|
|
869
|
+
if (!handled) return
|
|
870
|
+
// Modifier-clicks fall through (handled=false) without stopPropagation
|
|
871
|
+
// so ancestor telemetry handlers still see the bubble.
|
|
872
|
+
e.stopPropagation()
|
|
873
|
+
if (!isNewTab && panel?.closeChat) panel.closeChat()
|
|
874
|
+
}
|
|
875
|
+
return (
|
|
876
|
+
<span className="contents" onClickCapture={onClickCapture}>
|
|
877
|
+
{children}
|
|
878
|
+
</span>
|
|
879
|
+
)
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// =============================================================================
|
|
883
|
+
// ChatCardLoader — fetch + skeleton + render for fetch-mode entries.
|
|
884
|
+
// =============================================================================
|
|
885
|
+
|
|
886
|
+
interface ChatCardLoaderProps {
|
|
887
|
+
chatRef: ChatRef
|
|
888
|
+
onDiscuss?: (ref: ChatRef) => void
|
|
889
|
+
onDisplay?: (ref: ChatRef) => void
|
|
890
|
+
baseRoute?: string
|
|
891
|
+
chipBasePlatform?: string
|
|
892
|
+
extras?: ChatCardDispatchExtras
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/**
|
|
896
|
+
* Generic fetch-mode card loader. Looks up the registry entry by
|
|
897
|
+
* `chatRef.type`, fetches the full item via `useChatCardItem`, and
|
|
898
|
+
* routes through skeleton / null / card-render.
|
|
899
|
+
*
|
|
900
|
+
* SINGLE URL-RESOLUTION POINT — same code path source chips already
|
|
901
|
+
* had. Before render dispatch:
|
|
902
|
+
* - Pass the ref through `resolveSourceRowCTA` to compute the
|
|
903
|
+
* canonical `{href, targetPlatform}` (externalUrl → in-app path
|
|
904
|
+
* fallback → null, with embedder `baseRoute` / `chipBasePlatform`
|
|
905
|
+
* awareness).
|
|
906
|
+
* - Pre-resolve href against `runtime.navigation.defaultContentOrigin`
|
|
907
|
+
* in embed mode (so modifier-click + copy-link land on the hub).
|
|
908
|
+
* - Re-attach the resolved values onto the ref so EVERY downstream
|
|
909
|
+
* card — whether it renders an inner `<a>` from `href` prop
|
|
910
|
+
* (BlogCard, ProgramCard, …) or pulls `anchorProps` from
|
|
911
|
+
* `computeIsNewTab` — sees the SAME canonical URL the
|
|
912
|
+
* chip would render.
|
|
913
|
+
*
|
|
914
|
+
* Eliminates the entire "chip works, inline card doesn't" class of bug.
|
|
915
|
+
*/
|
|
916
|
+
export function ChatCardLoader({
|
|
917
|
+
chatRef,
|
|
918
|
+
onDiscuss,
|
|
919
|
+
onDisplay,
|
|
920
|
+
baseRoute,
|
|
921
|
+
chipBasePlatform,
|
|
922
|
+
extras,
|
|
923
|
+
}: ChatCardLoaderProps) {
|
|
924
|
+
const runtime = useRequiredChatRuntime()
|
|
925
|
+
const resolvedChatRef = React.useMemo<ChatRef>(() => {
|
|
926
|
+
const cta = resolveSourceRowCTA(
|
|
927
|
+
{
|
|
928
|
+
sourceRepo: chatRef.sourceRepo,
|
|
929
|
+
documentType: chatRef.type,
|
|
930
|
+
id: chatRef.id,
|
|
931
|
+
title: chatRef.title,
|
|
932
|
+
externalUrl: chatRef.url,
|
|
933
|
+
targetPlatform: chatRef.targetPlatform,
|
|
934
|
+
path:
|
|
935
|
+
typeof chatRef.metadata?.path === 'string'
|
|
936
|
+
? (chatRef.metadata.path as string)
|
|
937
|
+
: null,
|
|
938
|
+
},
|
|
939
|
+
{
|
|
940
|
+
baseRoute,
|
|
941
|
+
chipBasePlatform,
|
|
942
|
+
currentPlatform: runtime.source,
|
|
943
|
+
},
|
|
944
|
+
)
|
|
945
|
+
const finalHref = cta.href ? resolveHrefForRuntime(cta.href, runtime) : null
|
|
946
|
+
return {
|
|
947
|
+
...chatRef,
|
|
948
|
+
url: finalHref ?? chatRef.url,
|
|
949
|
+
targetPlatform: cta.targetPlatform ?? chatRef.targetPlatform ?? null,
|
|
950
|
+
}
|
|
951
|
+
}, [chatRef, runtime, baseRoute, chipBasePlatform])
|
|
952
|
+
|
|
953
|
+
const entry = CHAT_CARD_REGISTRY[resolvedChatRef.type]
|
|
954
|
+
// Hook order MUST be stable across renders — call the data hook
|
|
955
|
+
// unconditionally regardless of entry mode. For non-fetch types the
|
|
956
|
+
// `contentRefType` is empty so the hook returns `isLoading=false` and
|
|
957
|
+
// `item=undefined`, which we ignore.
|
|
958
|
+
const fetchEntry = entry && entry.mode === 'fetch' ? entry : null
|
|
959
|
+
const { item, isLoading } = useChatCardItem<any>(
|
|
960
|
+
fetchEntry?.contentRefType ?? '',
|
|
961
|
+
fetchEntry ? resolvedChatRef.id : '',
|
|
962
|
+
)
|
|
963
|
+
if (!entry) return null
|
|
964
|
+
|
|
965
|
+
// Apply per-type fallback URL AFTER fetch (e.g. campaign → /admin/...).
|
|
966
|
+
// We mutate `resolvedChatRef.url` BEFORE computing isNewTab so the
|
|
967
|
+
// wrapper's interceptor sees the destination the user will actually
|
|
968
|
+
// visit. `safeHref` blocks `javascript:` / `data:` payloads even
|
|
969
|
+
// though the registry callers compose hub-internal strings today.
|
|
970
|
+
const finalChatRef: ChatRef =
|
|
971
|
+
fetchEntry && !resolvedChatRef.url && item && fetchEntry.fallbackHref
|
|
972
|
+
? {
|
|
973
|
+
...resolvedChatRef,
|
|
974
|
+
url: safeHref(fetchEntry.fallbackHref(item)),
|
|
975
|
+
}
|
|
976
|
+
: resolvedChatRef
|
|
977
|
+
|
|
978
|
+
// Pre-compute new-tab decision ONCE here (the same rule chips use).
|
|
979
|
+
// Render branches that pass `target` / `rel` to their card pull this
|
|
980
|
+
// via `renderOpts.isNewTab` so the inner `<a>` agrees with the
|
|
981
|
+
// runtime nav decision in `ChatCardNavWrap` + `handleChatNavClick`.
|
|
982
|
+
const isNewTab = computeIsNewTab(runtime, finalChatRef.url, finalChatRef.targetPlatform ?? null)
|
|
983
|
+
const renderOpts: ChatCardRenderOptions = { baseRoute, chipBasePlatform, extras, isNewTab }
|
|
984
|
+
|
|
985
|
+
// Wrap EVERY rendered card with ChatCardNavWrap so the inner anchor's
|
|
986
|
+
// primary click routes through the chat runtime (same handler as the
|
|
987
|
+
// source chip). The card's `<a href={absolute}>` provides the visible
|
|
988
|
+
// href for hover-preview / copy-link / modifier-click; the wrapper
|
|
989
|
+
// intercepts the primary click and applies runtime nav rules.
|
|
990
|
+
const path =
|
|
991
|
+
typeof finalChatRef.metadata?.path === 'string'
|
|
992
|
+
? (finalChatRef.metadata.path as string)
|
|
993
|
+
: null
|
|
994
|
+
const navWrap = (children: ReactNode) => (
|
|
995
|
+
<ChatCardNavWrap
|
|
996
|
+
href={finalChatRef.url ?? null}
|
|
997
|
+
path={path}
|
|
998
|
+
targetPlatform={finalChatRef.targetPlatform ?? null}
|
|
999
|
+
isNewTab={isNewTab}
|
|
1000
|
+
>
|
|
1001
|
+
{children}
|
|
1002
|
+
</ChatCardNavWrap>
|
|
1003
|
+
)
|
|
1004
|
+
if (entry.mode === 'no-fetch') {
|
|
1005
|
+
if (entry.bareInline) {
|
|
1006
|
+
return navWrap(entry.render(finalChatRef, renderOpts))
|
|
1007
|
+
}
|
|
1008
|
+
return (
|
|
1009
|
+
<ChatCardWithDiscuss
|
|
1010
|
+
chatRef={finalChatRef}
|
|
1011
|
+
onDiscuss={onDiscuss}
|
|
1012
|
+
onDisplay={onDisplay}
|
|
1013
|
+
displayAction={entry.displayAction}
|
|
1014
|
+
>
|
|
1015
|
+
{navWrap(entry.render(finalChatRef, renderOpts))}
|
|
1016
|
+
</ChatCardWithDiscuss>
|
|
1017
|
+
)
|
|
1018
|
+
}
|
|
1019
|
+
if (isLoading) return <>{entry.skeleton()}</>
|
|
1020
|
+
if (!item) return null
|
|
1021
|
+
return (
|
|
1022
|
+
<ChatCardWithDiscuss
|
|
1023
|
+
chatRef={finalChatRef}
|
|
1024
|
+
onDiscuss={onDiscuss}
|
|
1025
|
+
onDisplay={onDisplay}
|
|
1026
|
+
displayAction={entry.displayAction}
|
|
1027
|
+
>
|
|
1028
|
+
{navWrap(entry.render(item, finalChatRef, renderOpts))}
|
|
1029
|
+
</ChatCardWithDiscuss>
|
|
1030
|
+
)
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// =============================================================================
|
|
1034
|
+
// Public dispatch entry points
|
|
1035
|
+
// =============================================================================
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* Render the chat-inline card for a `[card://<type>:<id>]` marker.
|
|
1039
|
+
*
|
|
1040
|
+
* Single dispatch through `CHAT_CARD_REGISTRY`. The function mirrors the
|
|
1041
|
+
* hub's `renderChatInlineEntityCard` behavior:
|
|
1042
|
+
* - Video-bearing refs return a `<BlockCard>` sentinel so the
|
|
1043
|
+
* `chat-message-enhanced` pre-scan hoists the player out of the
|
|
1044
|
+
* assistant paragraph.
|
|
1045
|
+
* - Other refs render the compact card, optionally wrapped in a
|
|
1046
|
+
* close-on-anchor-click span when `onClose` is supplied.
|
|
1047
|
+
*/
|
|
1048
|
+
export function renderChatInlineEntityCard(
|
|
1049
|
+
chatRef: ChatRef,
|
|
1050
|
+
options: {
|
|
1051
|
+
onDiscuss?: (ref: ChatRef) => void
|
|
1052
|
+
onDisplay?: (ref: ChatRef) => void
|
|
1053
|
+
baseRoute?: string
|
|
1054
|
+
chipBasePlatform?: string
|
|
1055
|
+
extras?: ChatCardDispatchExtras
|
|
1056
|
+
} = {},
|
|
1057
|
+
): React.ReactNode {
|
|
1058
|
+
const { onDiscuss, onDisplay, baseRoute, chipBasePlatform, extras } = options
|
|
1059
|
+
const m = chatRef.metadata ?? {}
|
|
1060
|
+
const hasVideo =
|
|
1061
|
+
(typeof m.videoUrl === 'string' && (m.videoUrl as string).length > 0) ||
|
|
1062
|
+
(typeof m.youtubeUrl === 'string' && (m.youtubeUrl as string).length > 0) ||
|
|
1063
|
+
(typeof m.highlightVideoUrl === 'string' && (m.highlightVideoUrl as string).length > 0)
|
|
1064
|
+
|
|
1065
|
+
const loader = (
|
|
1066
|
+
<ChatCardLoader
|
|
1067
|
+
chatRef={chatRef}
|
|
1068
|
+
onDiscuss={onDiscuss}
|
|
1069
|
+
onDisplay={onDisplay}
|
|
1070
|
+
baseRoute={baseRoute}
|
|
1071
|
+
chipBasePlatform={chipBasePlatform}
|
|
1072
|
+
extras={extras}
|
|
1073
|
+
/>
|
|
1074
|
+
)
|
|
1075
|
+
|
|
1076
|
+
if (hasVideo) {
|
|
1077
|
+
return (
|
|
1078
|
+
<BlockCard inline={loader}>
|
|
1079
|
+
<ChatVideoEntityCard chatRef={chatRef} />
|
|
1080
|
+
</BlockCard>
|
|
1081
|
+
)
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
return loader
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// =============================================================================
|
|
1088
|
+
// NavLink wiring for callers that need to compose anchors (Task 2 + Task 3)
|
|
1089
|
+
// =============================================================================
|
|
1090
|
+
|
|
1091
|
+
/** Re-export so call sites can wrap any subtree with chat-runtime
|
|
1092
|
+
* routing in a single import. */
|
|
1093
|
+
export { NavLinkAnchorViaRuntime }
|