@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,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helper for the host-side markdown formatter ↔ server-side
|
|
3
|
+
* parser pair. Single source of truth so the host-side build (chat
|
|
4
|
+
* bubble render) and the server-side strip (LLM input cleanup) can
|
|
5
|
+
* never drift.
|
|
6
|
+
*
|
|
7
|
+
* Lib-side replacement for the hub's `lib/utils/chat-attachment-markdown.ts`.
|
|
8
|
+
* The hub file pulled its constants from `lib/config/chat-attachment-config`
|
|
9
|
+
* + its `ChatAttachment` type from `lib/types/chat-attachment`. Both are
|
|
10
|
+
* inlined here as lib-local constants/types — they're stable wire-format
|
|
11
|
+
* contracts (the hub's view-route owns the prefix + token-param name; any
|
|
12
|
+
* change is a coordinated migration).
|
|
13
|
+
*
|
|
14
|
+
* URL flavors at a glance:
|
|
15
|
+
* - HOST-SIDE (user-bubble render): uses the runtime's
|
|
16
|
+
* `attachmentViewUrlPrefix` (hub default = `/api/storage/view/chat-attachments/`).
|
|
17
|
+
* Embedded apps override per their reverse-proxy topology.
|
|
18
|
+
* - SERVER-SIDE (strip regex): uses the constant
|
|
19
|
+
* `CHAT_ATTACHMENT_VIEW_URL_PREFIX` directly. The chat ROUTE always
|
|
20
|
+
* runs on the hub, so it always strips on the hub default.
|
|
21
|
+
* - ANTHROPIC image-blocks: uses the RAW Supabase signed URL — NOT the
|
|
22
|
+
* proxy URL — because Anthropic's image fetcher doesn't reliably
|
|
23
|
+
* follow 302 redirects.
|
|
24
|
+
*
|
|
25
|
+
* Security gates inside the formatter:
|
|
26
|
+
* - Filename markdown chars escaped via `escapeMarkdownInline` so a
|
|
27
|
+
* name like `screenshot](https://evil.com).png` cannot terminate
|
|
28
|
+
* the markdown image early and embed an attacker-controlled URL.
|
|
29
|
+
* - `<` and `>` escaped too — prevents CommonMark autolink expansion
|
|
30
|
+
* for filenames containing URL-shaped text.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Lib-local constants + types (mirror the hub's chat-attachment-config /
|
|
35
|
+
// chat-attachment.ts). These are wire-format contracts owned by the hub's
|
|
36
|
+
// view route; embedders that want to override the prefix do so via
|
|
37
|
+
// `ChatRuntime.endpoints.attachmentViewUrlPrefix`, not by changing these.
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
/** Hub-default prefix for the view-proxy URL. Embedders override via the
|
|
41
|
+
* runtime. The server-side strip regex always uses THIS value (server
|
|
42
|
+
* runs on the hub). */
|
|
43
|
+
export const CHAT_ATTACHMENT_VIEW_URL_PREFIX = '/api/storage/view/chat-attachments/'
|
|
44
|
+
|
|
45
|
+
/** Query parameter name for the HMAC view token. */
|
|
46
|
+
export const CHAT_ATTACHMENT_VIEW_TOKEN_QUERY_PARAM = 't'
|
|
47
|
+
|
|
48
|
+
/** Subset Anthropic's image content-block API supports. HEIC / video
|
|
49
|
+
* attachments fall through to the text-marker form so the LLM still sees
|
|
50
|
+
* a reference even when it can't visually parse the file. */
|
|
51
|
+
export const ANTHROPIC_SUPPORTED_IMAGE_MIME = [
|
|
52
|
+
'image/jpeg',
|
|
53
|
+
'image/png',
|
|
54
|
+
'image/webp',
|
|
55
|
+
'image/gif',
|
|
56
|
+
] as const
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Wire shape for a single chat attachment.
|
|
60
|
+
*
|
|
61
|
+
* `viewToken` is server-issued (HMAC-signed) and embedded in the markdown
|
|
62
|
+
* URL's `?t=` query parameter. The client never generates it — the upload
|
|
63
|
+
* route returns it alongside the storage path.
|
|
64
|
+
*/
|
|
65
|
+
export interface ChatAttachment {
|
|
66
|
+
storagePath: string
|
|
67
|
+
viewToken: string
|
|
68
|
+
contentType: string
|
|
69
|
+
fileName: string
|
|
70
|
+
size: number
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// URL building
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Build the markdown view-URL for a chat attachment.
|
|
79
|
+
*
|
|
80
|
+
* `viewUrlPrefix` is parameterized (NOT pulled from the constant) so
|
|
81
|
+
* host-side callers can pass the runtime's prefix
|
|
82
|
+
* (`ChatRuntime.endpoints.attachmentViewUrlPrefix`) — embedded apps
|
|
83
|
+
* supply an absolute URL against the hub's origin so chat-history
|
|
84
|
+
* markdown works cross-origin.
|
|
85
|
+
*
|
|
86
|
+
* Server-side callers (the strip regex source) should pass
|
|
87
|
+
* `CHAT_ATTACHMENT_VIEW_URL_PREFIX` directly.
|
|
88
|
+
*/
|
|
89
|
+
export function buildChatAttachmentViewUrl(
|
|
90
|
+
viewUrlPrefix: string,
|
|
91
|
+
storagePath: string,
|
|
92
|
+
viewToken: string,
|
|
93
|
+
): string {
|
|
94
|
+
return `${viewUrlPrefix}${storagePath}?${CHAT_ATTACHMENT_VIEW_TOKEN_QUERY_PARAM}=${encodeURIComponent(viewToken)}`
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// Markdown formatter
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Escape inline-markdown special characters from a filename before
|
|
103
|
+
* interpolation. Closes the markdown-injection / phishing primitive:
|
|
104
|
+
* a filename like `screenshot](https://evil.com).png` would otherwise
|
|
105
|
+
* terminate `` early and emit an attacker-controlled
|
|
106
|
+
* URL in the user's bubble.
|
|
107
|
+
*
|
|
108
|
+
* Escapes: `[`, `]`, `(`, `)`, `\`, `\n`, `\r`, `<`, `>`, `"`.
|
|
109
|
+
*/
|
|
110
|
+
export function escapeMarkdownInline(text: string): string {
|
|
111
|
+
return text.replace(/[[\]()\\\n\r<>"]/g, (ch) => {
|
|
112
|
+
switch (ch) {
|
|
113
|
+
case '\n':
|
|
114
|
+
return ' '
|
|
115
|
+
case '\r':
|
|
116
|
+
return ''
|
|
117
|
+
default:
|
|
118
|
+
return `\\${ch}`
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Format a single chat-attachment as a markdown line to append to the
|
|
125
|
+
* user's bubble text BEFORE sending.
|
|
126
|
+
*
|
|
127
|
+
* Images (MIME in `ANTHROPIC_SUPPORTED_IMAGE_MIME`) emit the `![]()`
|
|
128
|
+
* image form so the browser renders the attachment inline. Everything
|
|
129
|
+
* else (HEIC, video, audio) emits the `[Attached: ...]` link form so the
|
|
130
|
+
* bubble shows a clickable file pill instead of a broken-image icon.
|
|
131
|
+
*/
|
|
132
|
+
export function formatChatAttachmentMarkdownForBubble(
|
|
133
|
+
att: ChatAttachment,
|
|
134
|
+
viewUrlPrefix: string,
|
|
135
|
+
): string {
|
|
136
|
+
const safeName = escapeMarkdownInline(att.fileName)
|
|
137
|
+
const url = buildChatAttachmentViewUrl(viewUrlPrefix, att.storagePath, att.viewToken)
|
|
138
|
+
const isImage = (ANTHROPIC_SUPPORTED_IMAGE_MIME as readonly string[]).includes(att.contentType)
|
|
139
|
+
return isImage ? `\n\n` : `\n\n[Attached: ${safeName}](${url})`
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
// Server-side strip regex + parser
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Module-private: the `CHAT_ATTACHMENT_VIEW_URL_PREFIX` with regex
|
|
148
|
+
* meta-characters escaped, so it can be safely interpolated into
|
|
149
|
+
* regex sources. Computed ONCE at module load. Exported so other
|
|
150
|
+
* regex-building call sites can share the same source of truth.
|
|
151
|
+
*/
|
|
152
|
+
export const CHAT_ATTACHMENT_VIEW_URL_PREFIX_REGEX_ESCAPED =
|
|
153
|
+
CHAT_ATTACHMENT_VIEW_URL_PREFIX.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Single anchored regex matching both the image (`![]()`) and link
|
|
157
|
+
* (`[Attached: ...]`) forms keyed on the server-side prefix.
|
|
158
|
+
*
|
|
159
|
+
* `gm` flags — multi-line anchored so the regex matches per-line.
|
|
160
|
+
* Non-chat markdown links/images stay untouched because the regex
|
|
161
|
+
* requires the literal `/api/storage/view/chat-attachments/` prefix.
|
|
162
|
+
*/
|
|
163
|
+
export const CHAT_ATTACHMENT_MARKDOWN_PATTERN = new RegExp(
|
|
164
|
+
`^\\s*!?\\[[^\\]]*\\]\\(${CHAT_ATTACHMENT_VIEW_URL_PREFIX_REGEX_ESCAPED}[^)]+\\)\\s*$`,
|
|
165
|
+
'gm',
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Strip pre-embedded chat-attachment markdown lines from `text`.
|
|
170
|
+
* Returns the cleaned text + the storage paths extracted from the
|
|
171
|
+
* matched URLs.
|
|
172
|
+
*/
|
|
173
|
+
export function stripChatAttachmentMarkdown(text: string): {
|
|
174
|
+
stripped: string
|
|
175
|
+
storagePaths: string[]
|
|
176
|
+
} {
|
|
177
|
+
const storagePaths: string[] = []
|
|
178
|
+
const pathExtract = new RegExp(
|
|
179
|
+
`\\(${CHAT_ATTACHMENT_VIEW_URL_PREFIX_REGEX_ESCAPED}([^?)]+)`,
|
|
180
|
+
)
|
|
181
|
+
const stripped = text.replace(CHAT_ATTACHMENT_MARKDOWN_PATTERN, (match) => {
|
|
182
|
+
const m = match.match(pathExtract)
|
|
183
|
+
if (m && m[1]) storagePaths.push(m[1])
|
|
184
|
+
return ''
|
|
185
|
+
})
|
|
186
|
+
return {
|
|
187
|
+
stripped: stripped.replace(/\n{3,}/g, '\n\n').trim(),
|
|
188
|
+
storagePaths,
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared `fetch` wrapper for chat-side endpoints that need to carry
|
|
5
|
+
* the bearer-act-as identity (proxy `Authorization` + `X-Chat-Act-As`
|
|
6
|
+
* headers from `chat-proxy-auth-storage.ts`).
|
|
7
|
+
*
|
|
8
|
+
* Three call sites today:
|
|
9
|
+
* - `useEmbeddedChat` — chat-stream + confirm-tool POST.
|
|
10
|
+
* - `useChatAttachments` — chat-attachment upload-URL mint.
|
|
11
|
+
* - `useChatIdentity` — capability route GET.
|
|
12
|
+
*
|
|
13
|
+
* Without a unified helper, a future chat endpoint that forgets to call
|
|
14
|
+
* `applyProxyAuth` silently degrades bearer-act-as users to anon.
|
|
15
|
+
*
|
|
16
|
+
* Drop-in replacement for `fetch()` — `Authorization` / `X-Chat-Act-As`
|
|
17
|
+
* are merged into `init.headers` if proxy creds are stashed in
|
|
18
|
+
* localStorage, otherwise the call falls through unchanged.
|
|
19
|
+
*
|
|
20
|
+
* Use this for any client-side fetch hitting `/api/docs/chat/*`,
|
|
21
|
+
* `/api/chat/*`, or `/api/storage/generate-upload-url` (chat-attachment
|
|
22
|
+
* surface). Routes that do NOT need bearer-act-as (e.g.
|
|
23
|
+
* `/api/profile/me`) keep using vanilla `fetch`.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { applyProxyAuth } from './chat-proxy-auth-storage'
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* `fetch` wrapper that attaches chat-proxy bearer headers (when
|
|
30
|
+
* present in localStorage) and forces `credentials: 'same-origin'`
|
|
31
|
+
* so Supabase auth cookies travel too.
|
|
32
|
+
*
|
|
33
|
+
* Headers are MERGED: caller-supplied `init.headers` keys override the
|
|
34
|
+
* proxy headers (so a caller explicitly passing `Authorization` wins).
|
|
35
|
+
* In practice `applyProxyAuth` only sets the keys our chat auth chain
|
|
36
|
+
* cares about and no caller should override those — but the merge
|
|
37
|
+
* direction is documented so a future caller doesn't get a surprise.
|
|
38
|
+
*/
|
|
39
|
+
export function chatAuthedFetch(url: string, init: RequestInit = {}): Promise<Response> {
|
|
40
|
+
// `applyProxyAuth` accepts `Record<string, string>`; normalize the
|
|
41
|
+
// caller's headers to that shape. RequestInit accepts `HeadersInit`
|
|
42
|
+
// which is broader (Headers instance OR array of tuples).
|
|
43
|
+
//
|
|
44
|
+
// When the caller passes no headers, fall back to the same default
|
|
45
|
+
// `applyProxyAuth` uses internally — `Content-Type: application/json`
|
|
46
|
+
// — so JSON POSTs keep their content-type when only `applyProxyAuth(url)`
|
|
47
|
+
// is used at the call site. GET callers that explicitly want no body
|
|
48
|
+
// headers can pass `init.headers = {}` to opt out.
|
|
49
|
+
let baseHeaders: Record<string, string>
|
|
50
|
+
if (init.headers === undefined) {
|
|
51
|
+
baseHeaders = { 'Content-Type': 'application/json' }
|
|
52
|
+
} else {
|
|
53
|
+
baseHeaders = {}
|
|
54
|
+
if (init.headers instanceof Headers) {
|
|
55
|
+
init.headers.forEach((v, k) => {
|
|
56
|
+
baseHeaders[k] = v
|
|
57
|
+
})
|
|
58
|
+
} else if (Array.isArray(init.headers)) {
|
|
59
|
+
for (const [k, v] of init.headers) baseHeaders[k] = v
|
|
60
|
+
} else {
|
|
61
|
+
Object.assign(baseHeaders, init.headers as Record<string, string>)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const { url: authedUrl, headers } = applyProxyAuth(url, baseHeaders)
|
|
66
|
+
return fetch(authedUrl, {
|
|
67
|
+
...init,
|
|
68
|
+
headers,
|
|
69
|
+
// Always include Supabase auth cookies. `applyProxyAuth` handles
|
|
70
|
+
// the bearer header layer; cookies are the session-tier carrier.
|
|
71
|
+
credentials: init.credentials ?? 'same-origin',
|
|
72
|
+
})
|
|
73
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Embed-mode navigation resolver + shared click-handling primitives.
|
|
5
|
+
*
|
|
6
|
+
* Used by the lib chat panel's chip + card click handlers to force
|
|
7
|
+
* new-tab + absolutize against the embedder-supplied content origin.
|
|
8
|
+
*
|
|
9
|
+
* Refactor from hub origin (D5): inferTargetPlatformFromHref +
|
|
10
|
+
* getPlatformDomain dropped. Caller threads `targetPlatform` directly.
|
|
11
|
+
* Relative URLs without a defaultContentOrigin emit a dev warning
|
|
12
|
+
* and resolve against window.location.origin (likely wrong in embed
|
|
13
|
+
* mode; embedder should set defaultContentOrigin).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { ChatRuntime } from '../../../contexts/chat-runtime-context'
|
|
17
|
+
|
|
18
|
+
/** Arguments accepted by `window.open` for a new tab — keep `noopener`
|
|
19
|
+
* + `noreferrer` to prevent the opened page from accessing
|
|
20
|
+
* window.opener (reverse-tabnabbing class). */
|
|
21
|
+
export const NEW_TAB_FEATURES = 'noopener,noreferrer'
|
|
22
|
+
|
|
23
|
+
/** Modifier-click predicate — matches the existing useNavLink branch
|
|
24
|
+
* (cmd/ctrl/shift/alt OR non-primary mouse button). */
|
|
25
|
+
export function isModifierClick(e: {
|
|
26
|
+
button?: number
|
|
27
|
+
metaKey?: boolean
|
|
28
|
+
ctrlKey?: boolean
|
|
29
|
+
shiftKey?: boolean
|
|
30
|
+
altKey?: boolean
|
|
31
|
+
}): boolean {
|
|
32
|
+
return (
|
|
33
|
+
e.button !== 0 ||
|
|
34
|
+
!!e.metaKey ||
|
|
35
|
+
!!e.ctrlKey ||
|
|
36
|
+
!!e.shiftKey ||
|
|
37
|
+
!!e.altKey
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Strip the origin from a same-origin absolute URL, returning a relative
|
|
42
|
+
* path the host's router will treat as in-app navigation. Pass-through
|
|
43
|
+
* for already-relative URLs and for cross-origin URLs. */
|
|
44
|
+
export function stripSameOriginToPath(href: string): string {
|
|
45
|
+
if (!href.startsWith('http')) return href
|
|
46
|
+
try {
|
|
47
|
+
const u = new URL(href)
|
|
48
|
+
return u.pathname + u.search + u.hash
|
|
49
|
+
} catch {
|
|
50
|
+
return href
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ExternalNavResolution {
|
|
55
|
+
/** Absolutized href — relative paths are joined with
|
|
56
|
+
* `runtime.navigation.defaultContentOrigin` (embed contract). */
|
|
57
|
+
href: string
|
|
58
|
+
/** Synchronous opener. MUST be invoked inline from a user gesture for
|
|
59
|
+
* popup-blocker compatibility (Safari/Firefox). Honors
|
|
60
|
+
* runtime.navigation.openExternal override, else falls back to
|
|
61
|
+
* window.open(href, '_blank', 'noopener,noreferrer'). */
|
|
62
|
+
open: () => void
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Pre-resolve an href against the embed-mode `defaultContentOrigin`.
|
|
67
|
+
*
|
|
68
|
+
* In `embed` mode every chat-rendered anchor MUST point at an absolute
|
|
69
|
+
* URL on the hub origin (not the embedder origin). Without
|
|
70
|
+
* pre-resolution, relative paths like `/knowledge-base/foo.md` render
|
|
71
|
+
* as `<a href="/knowledge-base/...">` — the click handler intercepts
|
|
72
|
+
* primary-button clicks correctly, but modifier-click (cmd/ctrl/middle/
|
|
73
|
+
* right) bypasses the handler and opens `<embedder-origin>/...` → 404.
|
|
74
|
+
* Pre-resolution at render time makes every browser-native navigation
|
|
75
|
+
* path (hover preview, status bar, copy-link, new-tab via modifier)
|
|
76
|
+
* land on the hub correctly.
|
|
77
|
+
*
|
|
78
|
+
* In `host` mode (the hub itself) the href is returned unchanged —
|
|
79
|
+
* relative paths resolve naturally against the hub's own origin.
|
|
80
|
+
*
|
|
81
|
+
* Absolute URLs and protocol-relative URLs are returned unchanged in
|
|
82
|
+
* both modes.
|
|
83
|
+
*/
|
|
84
|
+
export function resolveHrefForRuntime(
|
|
85
|
+
href: string,
|
|
86
|
+
runtime: ChatRuntime,
|
|
87
|
+
): string {
|
|
88
|
+
if (runtime.navigation.mode !== 'embed') return href
|
|
89
|
+
if (href.startsWith('http')) return href
|
|
90
|
+
if (href.startsWith('//')) return href
|
|
91
|
+
const origin = runtime.navigation.defaultContentOrigin
|
|
92
|
+
if (!origin) return href
|
|
93
|
+
return origin.replace(/\/+$/, '') + (href.startsWith('/') ? href : '/' + href)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resolve external navigation in embed mode.
|
|
98
|
+
*
|
|
99
|
+
* Browser-only: called from React event handlers (onClick, imperative
|
|
100
|
+
* click handlers) after mount. No SSR-reachable paths.
|
|
101
|
+
*/
|
|
102
|
+
export function resolveExternalNavigation(args: {
|
|
103
|
+
href: string
|
|
104
|
+
targetPlatform: string | null | undefined
|
|
105
|
+
runtime: ChatRuntime
|
|
106
|
+
}): ExternalNavResolution {
|
|
107
|
+
let abs = args.href
|
|
108
|
+
|
|
109
|
+
// Defense: protocol-relative URLs (`//evil.com/x`) are NOT same-origin —
|
|
110
|
+
// browsers treat them as cross-origin absolute. Without this guard,
|
|
111
|
+
// a malicious href like `//evil.com/x` would skip the `startsWith('http')`
|
|
112
|
+
// check and reach the origin-concat branch below, producing a malformed
|
|
113
|
+
// URL that some browsers normalize back to `https://evil.com/x`
|
|
114
|
+
// (open-redirect class).
|
|
115
|
+
if (abs.startsWith('//')) abs = window.location.protocol + abs
|
|
116
|
+
|
|
117
|
+
if (!abs.startsWith('http')) {
|
|
118
|
+
if (args.runtime.navigation.defaultContentOrigin) {
|
|
119
|
+
// Strip trailing slashes via a loop, not `/\/+$/` — CodeQL flags
|
|
120
|
+
// the greedy `+` as polynomial-redos even with the `$` anchor.
|
|
121
|
+
// The loop is unambiguously O(n) in slash count.
|
|
122
|
+
let origin = args.runtime.navigation.defaultContentOrigin
|
|
123
|
+
while (origin.endsWith('/')) origin = origin.slice(0, -1)
|
|
124
|
+
abs = origin + (abs.startsWith('/') ? abs : '/' + abs)
|
|
125
|
+
} else if (
|
|
126
|
+
args.runtime.navigation.mode === 'embed' &&
|
|
127
|
+
process.env.NODE_ENV !== 'production'
|
|
128
|
+
) {
|
|
129
|
+
console.warn(
|
|
130
|
+
'[chat-nav-resolution] relative href in embed mode with no ' +
|
|
131
|
+
'defaultContentOrigin set on runtime.navigation — link will resolve ' +
|
|
132
|
+
'against the embedder origin.',
|
|
133
|
+
{ href: abs, targetPlatform: args.targetPlatform },
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const open = () => {
|
|
139
|
+
// Explicit if/else (NOT `??`) — `??` only short-circuits on
|
|
140
|
+
// null/undefined LHS, but `openExternal?.(href)` returns void on a
|
|
141
|
+
// successful call, which `??` treats as undefined and re-fires
|
|
142
|
+
// window.open — double-open bug.
|
|
143
|
+
if (args.runtime.navigation.openExternal) {
|
|
144
|
+
args.runtime.navigation.openExternal(abs)
|
|
145
|
+
} else {
|
|
146
|
+
window.open(abs, '_blank', NEW_TAB_FEATURES)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { href: abs, open }
|
|
151
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Client-side persistence for the chat-proxy credentials
|
|
5
|
+
* (`CHAT_PROXY_SECRET` + impersonation email). When set, the chat widget
|
|
6
|
+
* attaches them as `Authorization: Bearer <secret>` + `X-Chat-Act-As: <email>`
|
|
7
|
+
* on every call to `/api/docs/chat` and `/api/chat/agent/*` — proving to
|
|
8
|
+
* the server that this session is acting on behalf of <email>.
|
|
9
|
+
*
|
|
10
|
+
* Persists to **`sessionStorage`** (not `localStorage`) so the bearer
|
|
11
|
+
* token and act-as identity evaporate when the tab closes. An XSS sink
|
|
12
|
+
* on this origin can still exfiltrate the value while the tab is open
|
|
13
|
+
* (impossible to avoid without server-side opaque tokens), but the
|
|
14
|
+
* exposure window shrinks from "indefinite" to "current tab session"
|
|
15
|
+
* which is an order of magnitude better. Admin-only by convention —
|
|
16
|
+
* the `/debug` admin route hosts the paste-creds UI and is gated
|
|
17
|
+
* behind the platform's `askAI.enabled` flag.
|
|
18
|
+
*
|
|
19
|
+
* Namespaced under `<platform>.chat.proxy-auth.v1` so switching
|
|
20
|
+
* `NEXT_PUBLIC_APP_TYPE` mid-session doesn't drag stale creds across
|
|
21
|
+
* surfaces.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { createLocalStorageAdapter } from '../../../utils/local-storage-adapter'
|
|
25
|
+
import { getAppType } from '../../../utils/app-config'
|
|
26
|
+
|
|
27
|
+
export interface ChatProxyAuth {
|
|
28
|
+
secret: string
|
|
29
|
+
email: string
|
|
30
|
+
/** Optional identity passthrough — empty/omitted = not sent. Server
|
|
31
|
+
* parses these as `X-Chat-{First,Last}-Name` / `X-Chat-Avatar-Url` and
|
|
32
|
+
* threads them through `resolveChatProxyIdentity`'s returned user. */
|
|
33
|
+
firstName?: string
|
|
34
|
+
lastName?: string
|
|
35
|
+
avatarUrl?: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isValidPersistedAuth(value: unknown): value is ChatProxyAuth {
|
|
39
|
+
if (!value || typeof value !== 'object') return false
|
|
40
|
+
const v = value as Record<string, unknown>
|
|
41
|
+
if (
|
|
42
|
+
typeof v.secret !== 'string' || v.secret.trim().length === 0 ||
|
|
43
|
+
typeof v.email !== 'string' || v.email.trim().length === 0
|
|
44
|
+
) return false
|
|
45
|
+
// Optional fields: when present must be strings. Empty string is treated
|
|
46
|
+
// as absent later (in `getChatProxyAuth`).
|
|
47
|
+
if (v.firstName != null && typeof v.firstName !== 'string') return false
|
|
48
|
+
if (v.lastName != null && typeof v.lastName !== 'string') return false
|
|
49
|
+
if (v.avatarUrl != null && typeof v.avatarUrl !== 'string') return false
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const adapter = createLocalStorageAdapter<ChatProxyAuth>({
|
|
54
|
+
key: 'chat.proxy-auth.v1',
|
|
55
|
+
// Namespace by platform so a developer switching `NEXT_PUBLIC_APP_TYPE`
|
|
56
|
+
// mid-session doesn't drag stale creds across surfaces.
|
|
57
|
+
namespace: () => getAppType(),
|
|
58
|
+
validate: isValidPersistedAuth,
|
|
59
|
+
logTag: '[chat-proxy-auth-storage]',
|
|
60
|
+
// sessionStorage — cleared when the tab closes. Bearer token + act-as
|
|
61
|
+
// identity should NOT outlive the current session, so localStorage's
|
|
62
|
+
// indefinite persistence is the wrong choice here. See file-level
|
|
63
|
+
// doc comment for the threat-model rationale.
|
|
64
|
+
backend: 'session',
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
/** Trim + null-coerce an optional identity field so consumers can do
|
|
68
|
+
* `auth.firstName ?? ''` without worrying about whitespace-only strings. */
|
|
69
|
+
function normalizeOptional(value: string | undefined): string | undefined {
|
|
70
|
+
if (!value) return undefined
|
|
71
|
+
const trimmed = value.trim()
|
|
72
|
+
return trimmed.length > 0 ? trimmed : undefined
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Returns full credentials (secret + email + optional identity passthrough)
|
|
77
|
+
* when secret + email are available in localStorage. Survives page reloads.
|
|
78
|
+
* Returns `null` when nothing is saved — callers treat that as "fall back
|
|
79
|
+
* to cookie auth".
|
|
80
|
+
*/
|
|
81
|
+
export function getChatProxyAuth(): ChatProxyAuth | null {
|
|
82
|
+
const persisted = adapter.load()
|
|
83
|
+
if (!persisted) return null
|
|
84
|
+
return {
|
|
85
|
+
secret: persisted.secret,
|
|
86
|
+
email: persisted.email.trim().toLowerCase(),
|
|
87
|
+
firstName: normalizeOptional(persisted.firstName),
|
|
88
|
+
lastName: normalizeOptional(persisted.lastName),
|
|
89
|
+
avatarUrl: normalizeOptional(persisted.avatarUrl),
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Returns the LAST email the admin saved. The bar reads this to pre-fill
|
|
95
|
+
* the email field on mount.
|
|
96
|
+
*/
|
|
97
|
+
export function getPersistedProxyEmail(): string | null {
|
|
98
|
+
const persisted = adapter.load()
|
|
99
|
+
return persisted?.email.trim().toLowerCase() ?? null
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Save the proxy creds to localStorage. Secret + email are required;
|
|
103
|
+
* identity-passthrough fields are persisted only when non-empty. */
|
|
104
|
+
export function setChatProxyAuth(value: ChatProxyAuth): void {
|
|
105
|
+
adapter.save({
|
|
106
|
+
secret: value.secret,
|
|
107
|
+
email: value.email.trim().toLowerCase(),
|
|
108
|
+
firstName: normalizeOptional(value.firstName),
|
|
109
|
+
lastName: normalizeOptional(value.lastName),
|
|
110
|
+
avatarUrl: normalizeOptional(value.avatarUrl),
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Drop the persisted creds. */
|
|
115
|
+
export function clearChatProxyAuth(): void {
|
|
116
|
+
adapter.clear()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Apply the chat-proxy auth (Bearer + X-Chat-Act-As) to a fetch call's
|
|
121
|
+
* URL + headers. Used by every chat-side route that needs to identify
|
|
122
|
+
* itself as the proxied customer (the docs chat stream AND every
|
|
123
|
+
* confirm-tool / agent-* route the chat shell calls afterwards). When
|
|
124
|
+
* proxy auth is absent (regular cookie-session users), returns the
|
|
125
|
+
* inputs unchanged so the cookie-auth path still works.
|
|
126
|
+
*
|
|
127
|
+
* `X-Chat-Act-As` header (vs a URL query param) keeps PII out of
|
|
128
|
+
* access logs, Sentry breadcrumbs, browser history, and CDN analytics.
|
|
129
|
+
*/
|
|
130
|
+
export function applyProxyAuth(
|
|
131
|
+
url: string,
|
|
132
|
+
baseHeaders: Record<string, string> = { 'Content-Type': 'application/json' },
|
|
133
|
+
): { url: string; headers: Record<string, string> } {
|
|
134
|
+
const auth = getChatProxyAuth()
|
|
135
|
+
const headers = { ...baseHeaders }
|
|
136
|
+
if (auth?.secret) {
|
|
137
|
+
headers.Authorization = `Bearer ${auth.secret}`
|
|
138
|
+
}
|
|
139
|
+
if (auth?.email) {
|
|
140
|
+
headers['X-Chat-Act-As'] = auth.email
|
|
141
|
+
}
|
|
142
|
+
// Optional identity passthrough — only attached when present so the
|
|
143
|
+
// server's "required vs optional" header shape stays exact.
|
|
144
|
+
if (auth?.firstName) headers['X-Chat-First-Name'] = auth.firstName
|
|
145
|
+
if (auth?.lastName) headers['X-Chat-Last-Name'] = auth.lastName
|
|
146
|
+
if (auth?.avatarUrl) headers['X-Chat-Avatar-Url'] = auth.avatarUrl
|
|
147
|
+
return { url, headers }
|
|
148
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single CSS string for chip-density action buttons (Recent / Search /
|
|
3
|
+
* Find / Display, plus the inline Display popover's submit / cancel
|
|
4
|
+
* buttons).
|
|
5
|
+
*
|
|
6
|
+
* Shared between the empty-state chip's action row and the
|
|
7
|
+
* `<DisplayChipAction>` popover so both render with byte-equivalent
|
|
8
|
+
* styling — no per-call ad-hoc Tailwind chain that drifts over time.
|
|
9
|
+
*
|
|
10
|
+
* Sizing intent: 11px font + tight `px-2 py-1` padding lands below UI-Kit
|
|
11
|
+
* `Button size="small"` (24-32px min-height). These are chip-density
|
|
12
|
+
* action buttons, not standard buttons — they sit inside the empty-state
|
|
13
|
+
* chip card's tertiary action row.
|
|
14
|
+
*/
|
|
15
|
+
export const CHIP_ACTION_BUTTON_CLASS =
|
|
16
|
+
'text-[11px] font-medium text-ods-text-secondary hover:text-ods-text-primary ' +
|
|
17
|
+
'bg-transparent hover:bg-ods-card-hover border border-ods-border rounded-md ' +
|
|
18
|
+
'px-2 py-1 transition-colors focus-visible:outline-none focus-visible:ring-2 ' +
|
|
19
|
+
'focus-visible:ring-ods-focus'
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared className generator for the chat-adjacent UI family:
|
|
3
|
+
* - **Source chips** (citation list below an assistant turn)
|
|
4
|
+
* - **Inline entity-card pills** (within prose, marker-rendered)
|
|
5
|
+
* - **Search-result rows** (dropdown beneath the search input)
|
|
6
|
+
*
|
|
7
|
+
* Centralising the token here means a single ODS change propagates to
|
|
8
|
+
* every surface — chip / card / dropdown row read as the same family.
|
|
9
|
+
*
|
|
10
|
+
* The `tone` arg controls the resting text color:
|
|
11
|
+
* - `secondary` — citation chips and tertiary metadata. Muted resting.
|
|
12
|
+
* - `primary` — chips that ARE the subject of the sentence. Matches
|
|
13
|
+
* body text color so the chip reads as content, not metadata.
|
|
14
|
+
*
|
|
15
|
+
* The `density` arg controls size / padding:
|
|
16
|
+
* - `'chip'` — inline pill (`px-2 py-0.5 text-[11px]`). Default;
|
|
17
|
+
* used by the citation row and inline entity-card markers.
|
|
18
|
+
* - `'list-row'` — wider, taller row (`px-3 py-2 text-sm`). Used by
|
|
19
|
+
* the search-bar dropdown. Same ODS family — same border, hover
|
|
20
|
+
* transition, accent treatment — just larger touch target.
|
|
21
|
+
* - `'card-row'` — for the tracking strip beneath a card frame
|
|
22
|
+
* (`px-2 py-1 text-[11px]` no border). Same family, no frame.
|
|
23
|
+
*/
|
|
24
|
+
export interface ChipClassOptions {
|
|
25
|
+
tone: 'primary' | 'secondary'
|
|
26
|
+
/** Visual density. Defaults to `'chip'`. */
|
|
27
|
+
density?: 'chip' | 'list-row' | 'card-row'
|
|
28
|
+
/** Extra classes appended verbatim (e.g. `cursor-pointer`). */
|
|
29
|
+
extra?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function chatChipClass({ tone, density = 'chip', extra }: ChipClassOptions): string {
|
|
33
|
+
const toneClass = tone === 'primary' ? 'text-ods-text-primary' : 'text-ods-text-secondary'
|
|
34
|
+
// Size / padding by density. All three share the same border + hover
|
|
35
|
+
// semantics so a chip and a search-row read as the same UI family.
|
|
36
|
+
const sizeClass = density === 'list-row'
|
|
37
|
+
? 'px-3 py-2 text-sm gap-2'
|
|
38
|
+
: density === 'card-row'
|
|
39
|
+
? 'px-2 py-1 text-[11px] gap-1.5'
|
|
40
|
+
: 'px-2 py-0.5 text-[11px] gap-1.5'
|
|
41
|
+
// `card-row` is the "no-frame" variant — no border, no card bg, so it
|
|
42
|
+
// sits cleanly under a card without visually wrapping it.
|
|
43
|
+
const frameClass = density === 'card-row'
|
|
44
|
+
? ''
|
|
45
|
+
: 'bg-ods-card border border-ods-border rounded'
|
|
46
|
+
const base =
|
|
47
|
+
`inline-flex items-center ${sizeClass} ${frameClass} ` +
|
|
48
|
+
`${toneClass} ` +
|
|
49
|
+
'hover:text-ods-accent hover:border-ods-accent transition-colors align-baseline'
|
|
50
|
+
return extra ? `${base} ${extra}` : base
|
|
51
|
+
}
|