@flamingo-stack/openframe-frontend-core 0.0.703 → 0.0.704-snapshot.20261006133653
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-3L7KCOGO.cjs → chunk-2QEUFXNS.cjs} +30 -30
- package/dist/{chunk-BMJUKS6S.cjs → chunk-3256UJXS.cjs} +47 -47
- package/dist/{chunk-GZYLZ4MB.js → chunk-4S7TJYRQ.js} +3 -3
- package/dist/{chunk-ENGBNKUJ.js → chunk-5EFZO5EB.js} +675 -569
- package/dist/{chunk-TCZCMD5Q.js → chunk-5HBHO5TB.js} +1 -1
- package/dist/{chunk-BOUPNYUV.js → chunk-64HOMVYC.js} +5 -5
- package/dist/{chunk-YR6JPJF4.js → chunk-6XIF2Z7I.js} +4 -4
- package/dist/{chunk-NU724ZVN.cjs → chunk-7GHB2IK6.cjs} +121 -121
- package/dist/{chunk-GX3OUTFO.cjs → chunk-7ZYIC7NA.cjs} +69 -55
- package/dist/{chunk-53AC23ZN.js → chunk-A6WVQKOZ.js} +24 -24
- package/dist/{chunk-4OGAXAEG.cjs → chunk-ABU3TGXA.cjs} +3 -3
- package/dist/{chunk-RTXTGLGB.cjs → chunk-ACV4DFQ3.cjs} +4 -4
- package/dist/{chunk-RLDAYA2A.cjs → chunk-BH6PJP66.cjs} +29 -29
- package/dist/{chunk-BRXOGCH3.cjs → chunk-BIZNSF3U.cjs} +3 -3
- package/dist/{chunk-2A4XES7R.cjs → chunk-BM5MVGH3.cjs} +3 -3
- package/dist/{chunk-6YCXA7CN.js → chunk-CH5232HV.js} +20 -19
- package/dist/{chunk-UIBSSVON.cjs → chunk-D7BTSVMS.cjs} +2 -2
- package/dist/{chunk-YBGEPKC2.cjs → chunk-F7Y2ZS5U.cjs} +6 -6
- package/dist/{chunk-5V6O73EH.js → chunk-FLKJYMVB.js} +3 -3
- package/dist/{chunk-NMGX2ZTU.js → chunk-IFUQVZF4.js} +17 -17
- package/dist/{chunk-2NE3DNXY.js → chunk-IKCQK67U.js} +2 -2
- package/dist/{chunk-KFDP3DUL.cjs → chunk-IXPUM3AW.cjs} +98 -98
- package/dist/{chunk-QGTDWFT6.js → chunk-IZHZMBIX.js} +2469 -1928
- package/dist/{chunk-67CXGPTW.cjs → chunk-JKEEFQOX.cjs} +505 -72
- package/dist/{chunk-NYSYSKSH.cjs → chunk-M6HTJTFH.cjs} +15 -15
- package/dist/{chunk-OGLCD3UL.js → chunk-MFFCUVWG.js} +6 -6
- package/dist/{chunk-KJ5LWATV.js → chunk-MKXO4Q5P.js} +7 -7
- package/dist/{chunk-EMCQGFXD.cjs → chunk-MMOODW57.cjs} +28 -27
- package/dist/{chunk-Q76ZTHNV.js → chunk-MP2C3LJ4.js} +1 -1
- package/dist/{chunk-J4K5JOLI.js → chunk-MV4HYG3B.js} +25 -11
- package/dist/{chunk-2T6QWNXU.js → chunk-NDESEPW5.js} +99 -11
- package/dist/{chunk-HHFPQNP3.js → chunk-NJDHFC55.js} +15 -15
- package/dist/{chunk-HUOLB7ZN.cjs → chunk-OHFS7VOU.cjs} +9 -9
- package/dist/{chunk-7632TNE7.js → chunk-OSNIZNVH.js} +7 -7
- package/dist/{chunk-UTW4SQDI.js → chunk-OUHMD6EU.js} +10 -10
- package/dist/{chunk-MXHJROXJ.cjs → chunk-P23CRLU4.cjs} +1245 -1139
- package/dist/{chunk-64O4L7WN.js → chunk-PDWVPI3S.js} +11 -55
- package/dist/{chunk-DAW6TDZB.js → chunk-PFC2HWQA.js} +30 -16
- package/dist/{chunk-G55W76S6.js → chunk-POZ7F77D.js} +12 -13
- package/dist/{chunk-PJP5SMOU.js → chunk-PPEZGUL7.js} +500 -67
- package/dist/{chunk-SFGXIFYO.cjs → chunk-QC7Q3XCE.cjs} +24 -24
- package/dist/{chunk-MDBHZBW7.cjs → chunk-RKV5B7EU.cjs} +92 -4
- package/dist/{chunk-5VPIC5MD.cjs → chunk-SAAZEWUR.cjs} +12 -12
- package/dist/{chunk-IIMICN7L.cjs → chunk-TYWLNCNH.cjs} +4 -48
- package/dist/{chunk-HYLIQMZH.cjs → chunk-UBP5RNGK.cjs} +33 -33
- package/dist/{chunk-HUMWQMCU.js → chunk-UT4YHQZW.js} +3 -3
- package/dist/{chunk-BSEIEWM5.cjs → chunk-V3H26CNS.cjs} +28 -14
- package/dist/{chunk-NGJCWEYX.cjs → chunk-VHCACDKP.cjs} +46 -46
- package/dist/{chunk-SL2FOFT2.js → chunk-VMAZCLX4.js} +7 -7
- package/dist/{chunk-5FFNNJM7.js → chunk-VR2ZLFCP.js} +1 -1
- package/dist/{chunk-NCTYD7HL.js → chunk-VYWMEL5F.js} +14 -14
- package/dist/{chunk-HY5YL3U5.cjs → chunk-XBWE423R.cjs} +1994 -1453
- package/dist/{chunk-XCIFHW4E.cjs → chunk-XOYH2YQE.cjs} +2 -2
- package/dist/{chunk-S6V7A5FS.cjs → chunk-ZQZFIE2K.cjs} +32 -33
- package/dist/components/case-studies/index.cjs +24 -24
- package/dist/components/case-studies/index.js +10 -10
- package/dist/components/chat/chat-archive-page.d.ts +3 -3
- package/dist/components/chat/chat-archive-page.d.ts.map +1 -1
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/chat-nav-sidebar.d.ts +4 -0
- package/dist/components/chat/chat-nav-sidebar.d.ts.map +1 -1
- package/dist/components/chat/chat-panel-header.d.ts +3 -2
- package/dist/components/chat/chat-panel-header.d.ts.map +1 -1
- package/dist/components/chat/embeddable-chat.d.ts +36 -2
- package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +14 -6
- package/dist/components/chat/index.d.ts +4 -1
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +13 -5
- package/dist/components/chat/mingo-archive-list.d.ts +17 -0
- package/dist/components/chat/mingo-archive-list.d.ts.map +1 -0
- package/dist/components/chat/mingo-chat-header.d.ts +31 -0
- package/dist/components/chat/mingo-chat-header.d.ts.map +1 -0
- package/dist/components/chat/mingo-chat-rail.d.ts +54 -0
- package/dist/components/chat/mingo-chat-rail.d.ts.map +1 -0
- package/dist/components/chat/model-display.d.ts.map +1 -1
- package/dist/components/contact/contact-form.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +11 -11
- package/dist/components/contact/index.js +10 -10
- package/dist/components/content-loading-container.d.ts +1 -1
- package/dist/components/content-loading-container.d.ts.map +1 -1
- package/dist/components/docs/index.cjs +14 -14
- package/dist/components/docs/index.js +13 -13
- package/dist/components/docs/skeletons.d.ts.map +1 -1
- package/dist/components/embeds/index.cjs +11 -11
- package/dist/components/embeds/index.js +10 -10
- package/dist/components/faq/index.cjs +12 -12
- package/dist/components/faq/index.js +11 -11
- package/dist/components/features/figma-prototype-viewer.d.ts.map +1 -1
- package/dist/components/features/index.cjs +10 -10
- package/dist/components/features/index.js +9 -9
- package/dist/components/features/media-gallery-manager.d.ts.map +1 -1
- package/dist/components/features/parallax-image-showcase.d.ts.map +1 -1
- package/dist/components/features/policy-configuration-panel.d.ts.map +1 -1
- package/dist/components/features/section-selector.d.ts.map +1 -1
- package/dist/components/help-center-pages/index.cjs +119 -119
- package/dist/components/help-center-pages/index.js +39 -39
- package/dist/components/help-center-pages/trust-center-sections.d.ts +2 -2
- package/dist/components/help-center-pages/trust-center-sections.d.ts.map +1 -1
- package/dist/components/index.cjs +94 -86
- package/dist/components/index.js +32 -24
- package/dist/components/layout/article-detail-layout.d.ts +1 -1
- package/dist/components/layout/article-detail-layout.d.ts.map +1 -1
- package/dist/components/layout/page-container.d.ts.map +1 -1
- package/dist/components/layout/title-block.d.ts +2 -2
- package/dist/components/layout/title-block.d.ts.map +1 -1
- package/dist/components/loading/page-layout-skeleton.d.ts.map +1 -1
- package/dist/components/loading/unified-skeleton.d.ts.map +1 -1
- package/dist/components/meeting-scheduler/booking-form.d.ts +4 -4
- package/dist/components/meeting-scheduler/booking-form.d.ts.map +1 -1
- package/dist/components/meeting-scheduler/context-panel.d.ts.map +1 -1
- package/dist/components/meeting-scheduler/index.cjs +127 -127
- package/dist/components/meeting-scheduler/index.d.ts +2 -2
- package/dist/components/meeting-scheduler/index.d.ts.map +1 -1
- package/dist/components/meeting-scheduler/index.js +50 -50
- package/dist/components/navigation/app-header.d.ts +4 -0
- package/dist/components/navigation/app-header.d.ts.map +1 -1
- package/dist/components/navigation/app-layout-side-panel.d.ts +142 -0
- package/dist/components/navigation/app-layout-side-panel.d.ts.map +1 -0
- package/dist/components/navigation/app-layout.d.ts +11 -1
- package/dist/components/navigation/app-layout.d.ts.map +1 -1
- package/dist/components/navigation/header-mingo-button.d.ts +4 -1
- package/dist/components/navigation/header-mingo-button.d.ts.map +1 -1
- package/dist/components/navigation/index.cjs +13 -13
- package/dist/components/navigation/index.d.ts +1 -0
- package/dist/components/navigation/index.d.ts.map +1 -1
- package/dist/components/navigation/index.js +12 -12
- package/dist/components/navigation/navigation-sidebar.d.ts +8 -1
- package/dist/components/navigation/navigation-sidebar.d.ts.map +1 -1
- package/dist/components/navigation/sliding-sidebar.d.ts.map +1 -1
- package/dist/components/onboarding-guides/index.cjs +14 -14
- package/dist/components/onboarding-guides/index.js +13 -13
- package/dist/components/persistent-filter-controls.d.ts.map +1 -1
- package/dist/components/related-content/index.cjs +7 -7
- package/dist/components/related-content/index.js +6 -6
- package/dist/components/shared/detail-page-skeleton.d.ts.map +1 -1
- package/dist/components/tickets/help-center-create-form.d.ts +4 -4
- package/dist/components/tickets/index.cjs +15 -15
- package/dist/components/tickets/index.js +14 -14
- package/dist/components/ui/announcement-bar-view.d.ts.map +1 -1
- package/dist/components/ui/breadcrumb.d.ts.map +1 -1
- package/dist/components/ui/checkbox-block.d.ts.map +1 -1
- package/dist/components/ui/dashboard-info-card.d.ts +1 -1
- package/dist/components/ui/dashboard-info-card.d.ts.map +1 -1
- package/dist/components/ui/data-table/data-table-body.d.ts +2 -2
- package/dist/components/ui/data-table/data-table-skeleton.d.ts +2 -2
- package/dist/components/ui/data-table/data-table-skeleton.d.ts.map +1 -1
- package/dist/components/ui/data-table/utils.d.ts +2 -2
- package/dist/components/ui/dialog.d.ts.map +1 -1
- package/dist/components/ui/drawer.d.ts.map +1 -1
- package/dist/components/ui/entity-image.d.ts +2 -2
- package/dist/components/ui/file-manager/index.cjs +36 -36
- package/dist/components/ui/file-manager/index.js +3 -3
- package/dist/components/ui/filter-modal.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +18 -10
- package/dist/components/ui/index.js +17 -9
- package/dist/components/ui/info-card-row.d.ts.map +1 -1
- package/dist/components/ui/menubar.d.ts +1 -1
- package/dist/components/ui/menubar.d.ts.map +1 -1
- package/dist/components/ui/modal-v2.d.ts.map +1 -1
- package/dist/components/ui/modal.d.ts.map +1 -1
- package/dist/components/ui/no-data/no-data-actions.d.ts.map +1 -1
- package/dist/components/ui/no-data/no-data-styles.d.ts +1 -1
- package/dist/components/ui/no-data/no-data-styles.d.ts.map +1 -1
- package/dist/components/ui/page-actions.d.ts.map +1 -1
- package/dist/components/ui/sheet.d.ts.map +1 -1
- package/dist/components/ui/table/table-skeleton.d.ts +1 -1
- package/dist/components/ui/table/table-skeleton.d.ts.map +1 -1
- package/dist/hooks/index.cjs +23 -9
- package/dist/hooks/index.js +24 -10
- package/dist/hooks/ui/index.d.ts +1 -0
- package/dist/hooks/ui/index.d.ts.map +1 -1
- package/dist/hooks/ui/use-content-breakpoint.d.ts +32 -0
- package/dist/hooks/ui/use-content-breakpoint.d.ts.map +1 -0
- package/dist/hooks/ui/use-isomorphic-layout-effect.d.ts +2 -2
- package/dist/hooks/ui/use-isomorphic-layout-effect.d.ts.map +1 -1
- package/dist/hooks/ui/use-media-query.d.ts.map +1 -1
- package/dist/index.cjs +39 -17
- package/dist/index.js +41 -19
- package/dist/styles/layout-steps.d.ts +30 -0
- package/dist/styles/layout-steps.d.ts.map +1 -0
- package/dist/tailwind.config.cjs +36 -11
- package/dist/tailwind.config.js +36 -11
- package/eslint-config/README.md +9 -0
- package/eslint-config/base.js +17 -1
- package/eslint-config/layout-variants.js +57 -0
- package/package.json +3 -1
- package/src/ODS_TOKEN_RULES.md +40 -0
- package/src/components/chat/chat-archive-page.tsx +9 -7
- package/src/components/chat/chat-input.tsx +5 -1
- package/src/components/chat/chat-nav-sidebar.tsx +10 -4
- package/src/components/chat/chat-panel-header.tsx +8 -5
- package/src/components/chat/embeddable-chat.tsx +675 -485
- package/src/components/chat/index.ts +4 -0
- package/src/components/chat/mingo-archive-list.tsx +108 -0
- package/src/components/chat/mingo-chat-header.tsx +104 -0
- package/src/components/chat/mingo-chat-rail.tsx +361 -0
- package/src/components/chat/model-display.tsx +8 -1
- package/src/components/contact/contact-form.tsx +11 -9
- package/src/components/content-loading-container.tsx +4 -2
- package/src/components/docs/doc-viewer.tsx +7 -7
- package/src/components/docs/skeletons.tsx +7 -4
- package/src/components/dynamic-skeleton.tsx +1 -1
- package/src/components/embeds/claude-embed.tsx +1 -1
- package/src/components/embeds/embed-viewer-frame.tsx +4 -4
- package/src/components/embeds/figma-embed.tsx +2 -2
- package/src/components/embeds/google-sheets-viewer.tsx +1 -1
- package/src/components/embeds/pdf-viewer.tsx +3 -3
- package/src/components/empty-state.tsx +6 -6
- package/src/components/faq/faq-section.tsx +2 -2
- package/src/components/faq-accordion.tsx +1 -1
- package/src/components/features/board/board-column-header.tsx +1 -1
- package/src/components/features/command-box.tsx +3 -3
- package/src/components/features/entity-video-section.tsx +2 -2
- package/src/components/features/figma-prototype-viewer.tsx +4 -1
- package/src/components/features/media-gallery-manager.tsx +3 -1
- package/src/components/features/parallax-image-showcase.tsx +9 -6
- package/src/components/features/policy-configuration-panel.tsx +9 -7
- package/src/components/features/provider-button.tsx +1 -1
- package/src/components/features/section-selector.tsx +11 -6
- package/src/components/features/select-button.tsx +4 -4
- package/src/components/features/seo-editor-preview.tsx +2 -2
- package/src/components/features/video-ratio-tabs.tsx +3 -3
- package/src/components/features/waitlist-form.tsx +1 -1
- package/src/components/help-center-pages/trust-center-page.tsx +1 -1
- package/src/components/help-center-pages/trust-center-sections.tsx +14 -14
- package/src/components/icon-display.tsx +1 -1
- package/src/components/layout/article-detail-layout.tsx +4 -2
- package/src/components/layout/list-page-layout.tsx +2 -2
- package/src/components/layout/page-container.tsx +26 -14
- package/src/components/layout/page-heading.tsx +1 -1
- package/src/components/layout/page-layout.tsx +1 -1
- package/src/components/layout/title-block.tsx +13 -13
- package/src/components/loading/card-skeleton.tsx +11 -11
- package/src/components/loading/category-vendor-selector-skeleton.tsx +1 -1
- package/src/components/loading/content-skeleton.tsx +6 -6
- package/src/components/loading/device-card-skeleton.tsx +1 -1
- package/src/components/loading/margin-report-skeleton.tsx +7 -7
- package/src/components/loading/msp-profile-form-skeleton.tsx +3 -3
- package/src/components/loading/organization-card-skeleton.tsx +2 -2
- package/src/components/loading/page-layout-skeleton.tsx +80 -68
- package/src/components/loading/unified-skeleton.tsx +16 -6
- package/src/components/media-carousel.tsx +3 -3
- package/src/components/meeting-scheduler/booking-form.tsx +9 -8
- package/src/components/meeting-scheduler/context-panel.tsx +8 -6
- package/src/components/meeting-scheduler/directory.tsx +4 -4
- package/src/components/meeting-scheduler/index.tsx +15 -15
- package/src/components/meeting-scheduler/slot-picker.tsx +12 -12
- package/src/components/navigation/app-header.tsx +6 -0
- package/src/components/navigation/app-layout-side-panel.tsx +594 -0
- package/src/components/navigation/app-layout.tsx +69 -4
- package/src/components/navigation/header-mingo-button.tsx +13 -3
- package/src/components/navigation/index.ts +5 -0
- package/src/components/navigation/navigation-sidebar.tsx +17 -3
- package/src/components/navigation/sliding-sidebar.tsx +2 -1
- package/src/components/pagination.tsx +3 -3
- package/src/components/persistent-filter-controls.tsx +6 -2
- package/src/components/platform/ScriptArguments.tsx +1 -1
- package/src/components/platform/ScriptInfoSection.tsx +4 -4
- package/src/components/platform/SoftwareSourceBadge.tsx +1 -1
- package/src/components/shared/article-author-byline.tsx +1 -1
- package/src/components/shared/delivery/delivery-lists.tsx +2 -2
- package/src/components/shared/delivery/delivery-row.tsx +7 -7
- package/src/components/shared/delivery/delivery-table.tsx +3 -3
- package/src/components/shared/detail-page-skeleton.tsx +11 -5
- package/src/components/shared/dev-section/dev-card-row.tsx +6 -6
- package/src/components/shared/dev-section/dev-section-view.tsx +1 -1
- package/src/components/shared/product-release/product-release-card-skeleton.tsx +8 -8
- package/src/components/shared/product-release/product-release-card.tsx +9 -9
- package/src/components/shared/product-release/product-releases-view.tsx +1 -1
- package/src/components/shared/product-release/release-detail-page.tsx +5 -5
- package/src/components/shared/roadmap/roadmap-grid-skeleton.tsx +1 -1
- package/src/components/shared/roadmap/roadmap-grid.tsx +3 -3
- package/src/components/tickets/help-center-card.tsx +1 -1
- package/src/components/tickets/help-center-create-form.tsx +12 -12
- package/src/components/ui/announcement-bar-view.tsx +2 -10
- package/src/components/ui/benefit-card.tsx +18 -18
- package/src/components/ui/brand-association-grid.tsx +4 -4
- package/src/components/ui/breadcrumb.tsx +4 -1
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/checkbox-block.tsx +9 -7
- package/src/components/ui/content-loader.tsx +3 -3
- package/src/components/ui/cursor-pagination.tsx +3 -3
- package/src/components/ui/dashboard-info-card.tsx +13 -9
- package/src/components/ui/data-attribution.tsx +2 -2
- package/src/components/ui/data-table/data-table-body.tsx +2 -2
- package/src/components/ui/data-table/data-table-header.tsx +15 -15
- package/src/components/ui/data-table/data-table-skeleton.tsx +6 -6
- package/src/components/ui/data-table/utils.ts +5 -5
- package/src/components/ui/dialog.tsx +4 -1
- package/src/components/ui/drawer.tsx +2 -1
- package/src/components/ui/duration-input.tsx +1 -1
- package/src/components/ui/entity-image.tsx +3 -3
- package/src/components/ui/feature-card.tsx +10 -10
- package/src/components/ui/file-manager/file-manager-action-bar.tsx +1 -1
- package/src/components/ui/file-manager/file-manager.tsx +1 -1
- package/src/components/ui/filter-modal.tsx +8 -1
- package/src/components/ui/highlight-card.tsx +7 -7
- package/src/components/ui/info-card-row.tsx +10 -6
- package/src/components/ui/modal-v2.tsx +7 -2
- package/src/components/ui/modal.tsx +3 -2
- package/src/components/ui/no-data/no-data-actions.tsx +10 -4
- package/src/components/ui/no-data/no-data-styles.ts +1 -1
- package/src/components/ui/no-data/no-data.tsx +1 -1
- package/src/components/ui/organization-card.tsx +1 -1
- package/src/components/ui/page-actions.tsx +34 -5
- package/src/components/ui/progress-bar.tsx +2 -2
- package/src/components/ui/query-report-table/query-report-table.tsx +1 -1
- package/src/components/ui/search-input.tsx +2 -2
- package/src/components/ui/service-card.tsx +2 -2
- package/src/components/ui/sheet.tsx +2 -1
- package/src/components/ui/skeleton.tsx +3 -3
- package/src/components/ui/stacked-rows-panel.tsx +4 -4
- package/src/components/ui/tab-navigation.tsx +2 -2
- package/src/components/ui/tab-selector.tsx +2 -2
- package/src/components/ui/table/table-header.tsx +3 -3
- package/src/components/ui/table/table-skeleton.tsx +3 -3
- package/src/components/ui/table/utils.ts +5 -5
- package/src/components/ui/tag-search-input.tsx +3 -3
- package/src/components/ui/tags-manager.tsx +5 -5
- package/src/components/ui/test-run.tsx +2 -2
- package/src/components/ui/ticket-info-section.tsx +1 -1
- package/src/components/ui/ticket-notes-section.tsx +1 -1
- package/src/components/ui/ticket-status-config-row.tsx +15 -15
- package/src/hooks/ui/index.ts +1 -0
- package/src/hooks/ui/use-content-breakpoint.ts +58 -0
- package/src/hooks/ui/use-media-query.ts +3 -2
- package/src/styles/app-globals.css +13 -0
- package/src/styles/index.css +2 -0
- package/src/styles/layout-steps.ts +14 -0
- package/src/styles/ods-colors.css +15 -0
- package/src/styles/ods-content-area-tokens.css +27 -0
- package/src/styles/ods-content-area.css +31 -0
- package/src/styles/ods-effects.css +4 -2
- package/src/styles/ods-responsive-tokens.css +14 -4
- package/tailwind.config.ts +42 -7
|
@@ -61,6 +61,7 @@ import { Drawer, DrawerContent } from '../ui/drawer';
|
|
|
61
61
|
import { HoverDropdown, type HoverDropdownItem } from '../ui/hover-dropdown';
|
|
62
62
|
import { CollisionBoundaryContext, PortalContainerContext } from '../ui/portal-container';
|
|
63
63
|
import { SquareAvatar } from '../ui/square-avatar';
|
|
64
|
+
import { ChatAppearanceContext } from './chat-appearance-context';
|
|
64
65
|
import { ChatArchivePage } from './chat-archive-page';
|
|
65
66
|
import { ChatAttachmentChipStrip } from './chat-attachment-bar';
|
|
66
67
|
import { ChatComposer, type ChatComposerLock } from './chat-composer';
|
|
@@ -85,7 +86,10 @@ import { useEmptyStateConfig } from './hooks/use-empty-state-config';
|
|
|
85
86
|
import { fetchSlashCommands, useSlashCommandRegistry, type SlashCommandSummary } from './hooks/use-slash-commands';
|
|
86
87
|
import type { ChatSource, UseSseChatAdapterOptions } from './hooks/use-sse-chat-adapter';
|
|
87
88
|
import { useUnifiedChat, type ChatMode, type UseUnifiedChatModes } from './hooks/use-unified-chat';
|
|
89
|
+
import { MingoArchiveList } from './mingo-archive-list';
|
|
90
|
+
import { MingoChatHeader } from './mingo-chat-header';
|
|
88
91
|
import { ChatDialogModals } from './mingo-chat-modals';
|
|
92
|
+
import { MingoChatRail, type MingoDialogStatus } from './mingo-chat-rail';
|
|
89
93
|
import { MingoHistoryRail } from './mingo-history-rail';
|
|
90
94
|
import { MingoOnboardingCard } from './mingo-onboarding-card';
|
|
91
95
|
import { MingoOnboardingCardSkeleton } from './mingo-onboarding-card-skeleton';
|
|
@@ -93,7 +97,8 @@ import { MingoWelcome, type MingoWelcomeProps } from './mingo-welcome';
|
|
|
93
97
|
import { NavLinkAnchorViaRuntime } from './nav-link-anchor-via-runtime';
|
|
94
98
|
import { accentFromIdentityIcon, getAgentAccent } from './quick-action-chip';
|
|
95
99
|
import { SourceActionButton } from './source-action-button';
|
|
96
|
-
import
|
|
100
|
+
import { CHAT_APPEARANCE, type ChatAppearance } from './types/chat.types';
|
|
101
|
+
import type { ChatInputRef, DialogItem, SlashCommandActionId } from './types/component.types';
|
|
97
102
|
import type { ChatContextItem, ChatContextPickerConfig } from './types/context-item.types';
|
|
98
103
|
import type { MessageSegment, Message } from './types/message.types';
|
|
99
104
|
import type {
|
|
@@ -123,6 +128,8 @@ import { resolveSourceRowCTA, sourceRowCtxFromRuntime } from './utils/source-row
|
|
|
123
128
|
* self-contained — the host wires nothing.
|
|
124
129
|
*/
|
|
125
130
|
const HISTORY_RAIL_WIDTH = 320;
|
|
131
|
+
/** The v2 chat list (`MingoChatRail`, Figma `chat-sidebar`): the narrowest the v2 chat draws. */
|
|
132
|
+
export const MINGO_V2_RAIL_WIDTH = 296;
|
|
126
133
|
const CHAT_BLOCK_MIN_WIDTH = 400;
|
|
127
134
|
const SPLIT_MIN_WIDTH = HISTORY_RAIL_WIDTH + CHAT_BLOCK_MIN_WIDTH;
|
|
128
135
|
|
|
@@ -324,9 +331,42 @@ export interface EmbeddableChatProps {
|
|
|
324
331
|
* suppressed — those are Drawer-shell concerns. The consumer is
|
|
325
332
|
* responsible for mount/unmount and for opening/closing via the
|
|
326
333
|
* `open` / `onOpenChange` props (which the in-body close button still
|
|
327
|
-
* drives).
|
|
334
|
+
* drives). The host must provide the Radix Dialog it sits in.
|
|
335
|
+
* - `'inline'`: like `'none'`, for a host that is NOT a dialog (a panel
|
|
336
|
+
* docked into the page layout): no Radix Dialog is expected, so the
|
|
337
|
+
* panel names itself through the host's region rather than a
|
|
338
|
+
* `Dialog.Title`.
|
|
328
339
|
*/
|
|
329
|
-
shell?: 'drawer' | 'none';
|
|
340
|
+
shell?: 'drawer' | 'none' | 'inline';
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Whether the panel offers a close button. `false` for a chat that is part
|
|
344
|
+
* of the layout rather than an overlay (docked beside the page): every
|
|
345
|
+
* header leaves its close control out. Default `true`.
|
|
346
|
+
*/
|
|
347
|
+
closable?: boolean;
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* `'v2'`: the Mingo v2 layout (Figma openframe - mingo) — the chat list as a
|
|
351
|
+
* full-height `MingoChatRail` beside the chat, the `MingoChatHeader` over the
|
|
352
|
+
* chat only, Mingo's cyan-tinted surface. Default `'classic'`.
|
|
353
|
+
*/
|
|
354
|
+
appearance?: ChatAppearance;
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* v2: the →| control, shown while the list and the chat both fit. The host
|
|
358
|
+
* steps its panel back one size (see `collapseTo`).
|
|
359
|
+
*/
|
|
360
|
+
onCollapse?: () => void;
|
|
361
|
+
/**
|
|
362
|
+
* v2: what `onCollapse` leaves room for. `list` (default): the list alone, so
|
|
363
|
+
* an open chat is closed first. `column`: a narrower panel that still shows
|
|
364
|
+
* the open chat, which stays open.
|
|
365
|
+
*/
|
|
366
|
+
collapseTo?: 'list' | 'column';
|
|
367
|
+
|
|
368
|
+
/** v2: the status glyph at the end of a chat's row (working / unread / approval). */
|
|
369
|
+
dialogStatusOf?: (dialog: DialogItem) => MingoDialogStatus | undefined;
|
|
330
370
|
|
|
331
371
|
/**
|
|
332
372
|
* Display name of the signed-in user, shown as the sub-line under the chat
|
|
@@ -529,22 +569,29 @@ function useRailPresence(open: boolean): { mounted: boolean; active: boolean } {
|
|
|
529
569
|
function RailSlot({
|
|
530
570
|
active,
|
|
531
571
|
innerClassName,
|
|
572
|
+
className,
|
|
573
|
+
narrow = false,
|
|
532
574
|
children,
|
|
533
575
|
}: {
|
|
534
576
|
active: boolean;
|
|
535
577
|
innerClassName?: string;
|
|
578
|
+
className?: string;
|
|
579
|
+
/** The v2 rail's 296px instead of 320px. */
|
|
580
|
+
narrow?: boolean;
|
|
536
581
|
children: React.ReactNode;
|
|
537
582
|
}) {
|
|
583
|
+
const width = narrow ? 'w-[296px]' : 'w-80';
|
|
538
584
|
return (
|
|
539
585
|
<div
|
|
540
586
|
className={cn(
|
|
541
587
|
// Border on the OUTER so the rail/chat divider tracks the animating
|
|
542
588
|
// boundary (and fades out with the panel) instead of vanishing early.
|
|
543
589
|
'shrink-0 overflow-hidden border-r border-ods-border transition-[width,opacity] ease-out',
|
|
544
|
-
active ? 'duration-[240ms]
|
|
590
|
+
active ? cn('duration-[240ms] opacity-100', width) : 'duration-[300ms] w-0 opacity-0',
|
|
591
|
+
className,
|
|
545
592
|
)}
|
|
546
593
|
>
|
|
547
|
-
<div className={cn('h-full
|
|
594
|
+
<div className={cn('h-full', width, innerClassName)}>{children}</div>
|
|
548
595
|
</div>
|
|
549
596
|
);
|
|
550
597
|
}
|
|
@@ -973,6 +1020,11 @@ function EmbeddableChatInner({
|
|
|
973
1020
|
aiAgentConfigUrl: aiAgentConfigUrlProp,
|
|
974
1021
|
defaultActiveMode,
|
|
975
1022
|
shell = 'drawer',
|
|
1023
|
+
closable = true,
|
|
1024
|
+
appearance = CHAT_APPEARANCE.CLASSIC,
|
|
1025
|
+
onCollapse,
|
|
1026
|
+
collapseTo = 'list',
|
|
1027
|
+
dialogStatusOf,
|
|
976
1028
|
userDisplayName,
|
|
977
1029
|
userAvatarUrl,
|
|
978
1030
|
mingoWelcome,
|
|
@@ -985,11 +1037,12 @@ function EmbeddableChatInner({
|
|
|
985
1037
|
contextMemory,
|
|
986
1038
|
handleRef,
|
|
987
1039
|
}: EmbeddableChatProps & { handleRef?: React.Ref<EmbeddableChatHandle> }) {
|
|
988
|
-
// `shell
|
|
1040
|
+
// `shell` 'none' / 'inline' means the consumer hosts us inside their own panel
|
|
989
1041
|
// (e.g. AppLayoutDrawer in openframe-frontend). Several drawer-shell
|
|
990
1042
|
// concerns are unconditional in this codebase — gate them off here so
|
|
991
1043
|
// we don't double-up with the host's behaviour.
|
|
992
|
-
const shellLess = shell
|
|
1044
|
+
const shellLess = shell !== 'drawer';
|
|
1045
|
+
const isV2 = appearance === CHAT_APPEARANCE.V2;
|
|
993
1046
|
const runtime = useRequiredChatRuntime();
|
|
994
1047
|
// Optional on embedders (platform-agnostic); '' is a harmless sentinel for the
|
|
995
1048
|
// `ask-ai:open-with-ref` event filter below. Deliberately NOT the hub's
|
|
@@ -1526,6 +1579,8 @@ function EmbeddableChatInner({
|
|
|
1526
1579
|
const resolvedBaseRoute = baseRoute || (source === 'flamingo' ? '/knowledge-base' : '/data-room');
|
|
1527
1580
|
|
|
1528
1581
|
const handleClose = useCallback(() => setIsOpen(false), [setIsOpen]);
|
|
1582
|
+
// What the header close controls call; absent on a panel that cannot close.
|
|
1583
|
+
const closeControl = closable ? handleClose : undefined;
|
|
1529
1584
|
|
|
1530
1585
|
const handleNavigationClose = useCallback(() => {
|
|
1531
1586
|
navigatingAwayRef.current = true;
|
|
@@ -1942,16 +1997,17 @@ function EmbeddableChatInner({
|
|
|
1942
1997
|
// Only the split threshold is state, not the width: the observer fires on
|
|
1943
1998
|
// every pixel of a drawer drag, and a width in state re-rendered this whole
|
|
1944
1999
|
// component each frame for a value that changes at one width.
|
|
2000
|
+
const splitMinWidth = (isV2 ? MINGO_V2_RAIL_WIDTH : HISTORY_RAIL_WIDTH) + CHAT_BLOCK_MIN_WIDTH;
|
|
1945
2001
|
const [canSplit, setCanSplit] = useState(false);
|
|
1946
2002
|
useEffect(() => {
|
|
1947
2003
|
if (!panelBoundary || typeof ResizeObserver === 'undefined') return undefined;
|
|
1948
2004
|
const ro = new ResizeObserver(entries => {
|
|
1949
2005
|
const w = entries[0]?.contentRect?.width;
|
|
1950
|
-
if (typeof w === 'number') setCanSplit(w >=
|
|
2006
|
+
if (typeof w === 'number') setCanSplit(w >= splitMinWidth);
|
|
1951
2007
|
});
|
|
1952
2008
|
ro.observe(panelBoundary);
|
|
1953
2009
|
return () => ro.disconnect();
|
|
1954
|
-
}, [panelBoundary]);
|
|
2010
|
+
}, [panelBoundary, splitMinWidth]);
|
|
1955
2011
|
|
|
1956
2012
|
// ONE node for two consumers: the width measurement above and the
|
|
1957
2013
|
// collision-boundary context. State, not a ref, so both re-run when the node
|
|
@@ -1963,10 +2019,13 @@ function EmbeddableChatInner({
|
|
|
1963
2019
|
// width 0 before flipping. Seeding in the effect instead is what the
|
|
1964
2020
|
// pre-refactor code did, but `react-hooks/set-state-in-effect` rejects it in
|
|
1965
2021
|
// a reactive (non-mount-only) effect.
|
|
1966
|
-
const setPanelNode = useCallback(
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2022
|
+
const setPanelNode = useCallback(
|
|
2023
|
+
(node: HTMLDivElement | null) => {
|
|
2024
|
+
setPanelBoundary(node);
|
|
2025
|
+
if (node) setCanSplit(node.clientWidth >= splitMinWidth);
|
|
2026
|
+
},
|
|
2027
|
+
[splitMinWidth],
|
|
2028
|
+
);
|
|
1970
2029
|
|
|
1971
2030
|
// Rail collapse toggle (Figma ⟶| control), persisted so it survives the
|
|
1972
2031
|
// drawer remounting on close.
|
|
@@ -2205,12 +2264,12 @@ function EmbeddableChatInner({
|
|
|
2205
2264
|
avatar: headerAvatar,
|
|
2206
2265
|
backAriaLabel: 'Back to chats',
|
|
2207
2266
|
onBack: () => setComposeOpen(false),
|
|
2208
|
-
onClose:
|
|
2267
|
+
onClose: closeControl,
|
|
2209
2268
|
}
|
|
2210
2269
|
: {
|
|
2211
2270
|
showBack: false,
|
|
2212
2271
|
title: 'Current Chats',
|
|
2213
|
-
onClose:
|
|
2272
|
+
onClose: closeControl,
|
|
2214
2273
|
onOpenArchive: headerOnOpenArchive,
|
|
2215
2274
|
onToggleSearch: mingoCaps.onSearchChange ? () => setRailSearchOpen(o => !o) : undefined,
|
|
2216
2275
|
searchActive: railSearchOpen,
|
|
@@ -2225,7 +2284,7 @@ function EmbeddableChatInner({
|
|
|
2225
2284
|
backAriaLabel: headerBackAriaLabel,
|
|
2226
2285
|
isArchivedView: isViewingArchived,
|
|
2227
2286
|
onBack: headerOnBack,
|
|
2228
|
-
onClose:
|
|
2287
|
+
onClose: closeControl,
|
|
2229
2288
|
onRestore: headerOnRestore,
|
|
2230
2289
|
onRename: headerOnRename,
|
|
2231
2290
|
onArchive: headerOnArchive,
|
|
@@ -2234,15 +2293,87 @@ function EmbeddableChatInner({
|
|
|
2234
2293
|
onOpenArchive: headerOnOpenArchive,
|
|
2235
2294
|
};
|
|
2236
2295
|
|
|
2296
|
+
// v2 list + header (see `appearance`). The list stays on screen while the
|
|
2297
|
+
// archive opens beside it, so picking a chat from it leaves the archive.
|
|
2298
|
+
const leaveArchiveThen =
|
|
2299
|
+
(action: () => void): (() => void) =>
|
|
2300
|
+
() => {
|
|
2301
|
+
if (archiveOpen) closeArchive();
|
|
2302
|
+
action();
|
|
2303
|
+
};
|
|
2304
|
+
const mingoRailProps = {
|
|
2305
|
+
dialogs,
|
|
2306
|
+
activeDialogId: activeDialogId ?? undefined,
|
|
2307
|
+
// Beside a new chat (wide only: narrow, the list is its own screen).
|
|
2308
|
+
draftTitle: wideMingo && !hasConversation && !archiveOpen ? freshConversationTitle : undefined,
|
|
2309
|
+
onSelectDialog: (id: string) => leaveArchiveThen(() => handleSelectDialog(id))(),
|
|
2310
|
+
onNewChat: leaveArchiveThen(handleNewChat),
|
|
2311
|
+
onOpenArchive: headerOnOpenArchive && (archiveOpen ? closeArchive : headerOnOpenArchive),
|
|
2312
|
+
archiveActive: archiveOpen,
|
|
2313
|
+
// The suggestions a new chat opens on.
|
|
2314
|
+
onWhatToAsk: leaveArchiveThen(handleNewChat),
|
|
2315
|
+
statusOf: dialogStatusOf,
|
|
2316
|
+
onRequestRename: mingoCaps.canRename ? setRenameTarget : undefined,
|
|
2317
|
+
onRequestArchive: mingoCaps.canArchive ? setArchiveTarget : undefined,
|
|
2318
|
+
onRequestCopyLink: mingoCaps.onCopyLink,
|
|
2319
|
+
onRequestCompact: mingoCaps.compactDialog,
|
|
2320
|
+
scope: dialogScope,
|
|
2321
|
+
onScopeChange: setDialogScope,
|
|
2322
|
+
searchQuery: mingoCaps.searchQuery,
|
|
2323
|
+
onSearchChange: mingoCaps.onSearchChange,
|
|
2324
|
+
hasMore: hasMoreDialogs,
|
|
2325
|
+
isLoadingMore: isDialogsLoading && dialogs.length > 0,
|
|
2326
|
+
onLoadMore: () => {
|
|
2327
|
+
void loadMoreDialogs();
|
|
2328
|
+
},
|
|
2329
|
+
isLoadingHistory: dialogsInitialLoading,
|
|
2330
|
+
loadError: dialogsLoadError,
|
|
2331
|
+
onRetry: reloadDialogs,
|
|
2332
|
+
};
|
|
2333
|
+
// Over the chat column only; none on the narrow list (it is its own screen)
|
|
2334
|
+
// or over the archive (it brings its own back bar).
|
|
2335
|
+
const v2Header =
|
|
2336
|
+
isV2 && !stackedListView ? (
|
|
2337
|
+
<div className="col-start-2 row-start-1 min-w-0">
|
|
2338
|
+
<MingoChatHeader
|
|
2339
|
+
title={headerShowBack || isGuideEmpty ? headerTitle : freshConversationTitle}
|
|
2340
|
+
subtitle={headerPersonName}
|
|
2341
|
+
avatar={headerAvatar}
|
|
2342
|
+
// Wide: shows / hides the list beside the chat. Narrow: back to the
|
|
2343
|
+
// list, the only one of the two that fits.
|
|
2344
|
+
onToggleList={wideMingo ? toggleRailCollapsed : headerShowBack ? headerOnBack : () => setComposeOpen(false)}
|
|
2345
|
+
listOpen={splitActive}
|
|
2346
|
+
menuItems={headerShowBack && !isViewingArchived ? splitHeaderMenuItems : []}
|
|
2347
|
+
onRestore={isViewingArchived ? headerOnRestore : undefined}
|
|
2348
|
+
// Only while the list and the chat both fit: narrow, the toggle is
|
|
2349
|
+
// already the way back to the list.
|
|
2350
|
+
onCollapse={
|
|
2351
|
+
wideMingo && onCollapse
|
|
2352
|
+
? () => {
|
|
2353
|
+
// The minimum is the list alone: a conversation left open
|
|
2354
|
+
// would take the narrow panel instead.
|
|
2355
|
+
if (collapseTo === 'list' && hasConversation) headerOnBack();
|
|
2356
|
+
onCollapse();
|
|
2357
|
+
}
|
|
2358
|
+
: undefined
|
|
2359
|
+
}
|
|
2360
|
+
onClose={closeControl}
|
|
2361
|
+
/>
|
|
2362
|
+
</div>
|
|
2363
|
+
) : null;
|
|
2364
|
+
|
|
2237
2365
|
// Chat body — defined once, then rendered inside whichever shell applies.
|
|
2238
2366
|
// Radix overlays (⋯ menus, tooltips) portal into `portalHost` — a node inside
|
|
2239
2367
|
// this panel — so they inherit the drawer's stacking context and need only a
|
|
2240
2368
|
// small, local z-index instead of escalating to beat the drawer at the
|
|
2241
2369
|
// document root. See `PortalContainerContext`.
|
|
2242
2370
|
const body = (
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2371
|
+
// The whole panel reads the appearance (the composer's footer too), not
|
|
2372
|
+
// only the thread `ChatMessageList` provides it to.
|
|
2373
|
+
<ChatAppearanceContext.Provider value={appearance}>
|
|
2374
|
+
<PortalContainerContext.Provider value={portalHost}>
|
|
2375
|
+
<CollisionBoundaryContext.Provider value={panelBoundary}>
|
|
2376
|
+
{/* Panel surface depends on state (Figma):
|
|
2246
2377
|
• Narrow "Current Chats" LIST + FULL-PANEL archive page → grey
|
|
2247
2378
|
`ods-card` (#212121) — matching the grey rail those lists live
|
|
2248
2379
|
in when the panel is wide,
|
|
@@ -2255,209 +2386,286 @@ function EmbeddableChatInner({
|
|
|
2255
2386
|
— in the split layout it lives in the rail (which owns its own
|
|
2256
2387
|
grey), so the chat block on the right must keep the conversation's
|
|
2257
2388
|
dark surface instead of following the archive. */}
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2389
|
+
<div
|
|
2390
|
+
ref={setPanelNode}
|
|
2391
|
+
// v2: one surface for the list and the chat, Mingo's cyan-tinted bg.
|
|
2392
|
+
data-surface={isV2 ? 'mingo' : undefined}
|
|
2393
|
+
className={`flex h-full flex-col overflow-hidden transition-colors duration-200 ${
|
|
2394
|
+
!isV2 && ((archiveOpen && !splitActive) || stackedListView) ? 'bg-ods-card' : 'bg-ods-bg'
|
|
2395
|
+
} ${previewMode ? 'pointer-events-none select-none' : ''}`}
|
|
2396
|
+
>
|
|
2397
|
+
{/* Archive-page ↔ chat-panel swap fades in (200ms) to match the
|
|
2265
2398
|
surface flip. The full-panel archive is used only when NOT in
|
|
2266
2399
|
the wide split layout — there the archive opens inside the left
|
|
2267
2400
|
rail instead (see the rail column below). */}
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
<
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
<
|
|
2330
|
-
<span className="min-w-0 flex-1 truncate text-ods-text-primary text-h3">
|
|
2331
|
-
Current Chats
|
|
2332
|
-
</span>
|
|
2333
|
-
</div>
|
|
2334
|
-
{mingoCaps.onSearchChange && (
|
|
2335
|
-
<ChatHeaderIconButton
|
|
2336
|
-
onClick={() => setRailSearchOpen(o => !o)}
|
|
2337
|
-
aria-label="Search chats"
|
|
2338
|
-
aria-pressed={railSearchOpen}
|
|
2339
|
-
>
|
|
2340
|
-
<SearchIcon size={24} />
|
|
2341
|
-
</ChatHeaderIconButton>
|
|
2342
|
-
)}
|
|
2343
|
-
</>
|
|
2344
|
-
)}
|
|
2345
|
-
{headerOnOpenArchive && (
|
|
2346
|
-
<ChatHeaderIconButton onClick={headerOnOpenArchive} aria-label="Chat archive">
|
|
2347
|
-
<ClockHistoryIcon size={24} />
|
|
2401
|
+
{archiveOpen && !splitActive ? (
|
|
2402
|
+
<div key="archive-view" className="flex min-h-0 flex-1 flex-col duration-200 animate-in fade-in-0">
|
|
2403
|
+
<ChatArchivePage
|
|
2404
|
+
dialogs={archivedDialogs}
|
|
2405
|
+
onSelectDialog={handleArchivedSelect}
|
|
2406
|
+
onBack={closeArchive}
|
|
2407
|
+
onClose={closeControl}
|
|
2408
|
+
isLoading={archivedLoading}
|
|
2409
|
+
isFetching={archivedPending}
|
|
2410
|
+
hasMore={archivedCursor != null}
|
|
2411
|
+
onLoadMore={() => {
|
|
2412
|
+
void loadArchivedPage(archivedCursor ?? undefined);
|
|
2413
|
+
}}
|
|
2414
|
+
/>
|
|
2415
|
+
</div>
|
|
2416
|
+
) : (
|
|
2417
|
+
<div
|
|
2418
|
+
key="chat-view"
|
|
2419
|
+
className={cn(
|
|
2420
|
+
'min-h-0 flex-1 duration-200 animate-in fade-in-0',
|
|
2421
|
+
// v2: the list runs the full height beside a column of header,
|
|
2422
|
+
// banner and chat; each child below takes its cell explicitly.
|
|
2423
|
+
isV2 ? 'grid grid-cols-[auto_minmax(0,1fr)] grid-rows-[auto_auto_minmax(0,1fr)]' : 'flex flex-col',
|
|
2424
|
+
)}
|
|
2425
|
+
>
|
|
2426
|
+
{isV2 && railPresence.mounted && (
|
|
2427
|
+
<RailSlot
|
|
2428
|
+
active={railPresence.active}
|
|
2429
|
+
narrow
|
|
2430
|
+
className="col-start-1 row-span-3 row-start-1"
|
|
2431
|
+
innerClassName="flex min-h-0 flex-col"
|
|
2432
|
+
>
|
|
2433
|
+
<MingoChatRail {...mingoRailProps} className="w-full border-r-0" />
|
|
2434
|
+
</RailSlot>
|
|
2435
|
+
)}
|
|
2436
|
+
{isV2 ? (
|
|
2437
|
+
v2Header
|
|
2438
|
+
) : showWideHeader ? (
|
|
2439
|
+
// Wide Mingo header (Figma 113:60931 / 113:63630). Split: a
|
|
2440
|
+
// two-cell bar — the "Current Chats" rail header (search /
|
|
2441
|
+
// archive / collapse) over the 320px rail + the chat-block header
|
|
2442
|
+
// (title / ⋯ / close) over the fill column. Collapsed
|
|
2443
|
+
// (`wideCollapsed`): the rail cell is gone, leaving the corner
|
|
2444
|
+
// expand toggle + the chat-block header (the fill column shows
|
|
2445
|
+
// the chat / new-chat welcome). No back chevron — chat-list
|
|
2446
|
+
// navigation is the rail toggle. Shown whenever the panel is wide
|
|
2447
|
+
// enough to split (width ≥ `SPLIT_MIN_WIDTH`), NOT gated on
|
|
2448
|
+
// the viewport `md` breakpoint — otherwise a 720–799px panel on a
|
|
2449
|
+
// sub-`md` viewport would split the body yet drop to the mobile
|
|
2450
|
+
// single-bar header (no rail search / collapse controls).
|
|
2451
|
+
<div className="flex h-14 w-full flex-shrink-0 overflow-hidden border-b border-ods-border bg-ods-card">
|
|
2452
|
+
{railPresence.mounted && (
|
|
2453
|
+
<RailSlot active={railPresence.active} innerClassName="flex overflow-hidden">
|
|
2454
|
+
{archiveOpen ? (
|
|
2455
|
+
// Archive open in the wide layout — the rail header
|
|
2456
|
+
// turns into a "Chat Archive" back bar (the list itself
|
|
2457
|
+
// renders in the rail below); the chat block is untouched.
|
|
2458
|
+
// Back is a full-height leading cell, matching the other
|
|
2459
|
+
// header cells (not a small inline chevron).
|
|
2460
|
+
<>
|
|
2461
|
+
<ChatHeaderIconButton divider="right" onClick={closeArchive} aria-label="Back to chats">
|
|
2462
|
+
<Chevron02LeftIcon size={24} />
|
|
2348
2463
|
</ChatHeaderIconButton>
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2464
|
+
<div className="flex min-w-0 flex-1 items-center px-[var(--spacing-system-mf)]">
|
|
2465
|
+
<span className="min-w-0 flex-1 truncate text-ods-text-primary text-h3">
|
|
2466
|
+
Chat Archive
|
|
2467
|
+
</span>
|
|
2468
|
+
</div>
|
|
2469
|
+
</>
|
|
2470
|
+
) : (
|
|
2471
|
+
// "Current Chats" rail header — title fills, then the
|
|
2472
|
+
// search + archive controls. When search is open the
|
|
2473
|
+
// inline field takes over the title area in place
|
|
2474
|
+
// (Figma 116:51217) and the magnifier toggle is hidden.
|
|
2475
|
+
<>
|
|
2476
|
+
{railSearchOpen && mingoCaps.onSearchChange ? (
|
|
2477
|
+
<ChatHeaderSearchField
|
|
2478
|
+
initialValue={mingoCaps.searchQuery}
|
|
2479
|
+
onSearchChange={mingoCaps.onSearchChange}
|
|
2480
|
+
onCollapse={() => setRailSearchOpen(false)}
|
|
2481
|
+
/>
|
|
2482
|
+
) : (
|
|
2483
|
+
<>
|
|
2484
|
+
<div className="flex min-w-0 flex-1 items-center px-[var(--spacing-system-mf)]">
|
|
2485
|
+
<span className="min-w-0 flex-1 truncate text-ods-text-primary text-h3">
|
|
2486
|
+
Current Chats
|
|
2487
|
+
</span>
|
|
2488
|
+
</div>
|
|
2489
|
+
{mingoCaps.onSearchChange && (
|
|
2490
|
+
<ChatHeaderIconButton
|
|
2491
|
+
onClick={() => setRailSearchOpen(o => !o)}
|
|
2492
|
+
aria-label="Search chats"
|
|
2493
|
+
aria-pressed={railSearchOpen}
|
|
2494
|
+
>
|
|
2495
|
+
<SearchIcon size={24} />
|
|
2496
|
+
</ChatHeaderIconButton>
|
|
2497
|
+
)}
|
|
2498
|
+
</>
|
|
2499
|
+
)}
|
|
2500
|
+
{headerOnOpenArchive && (
|
|
2501
|
+
<ChatHeaderIconButton onClick={headerOnOpenArchive} aria-label="Chat archive">
|
|
2502
|
+
<ClockHistoryIcon size={24} />
|
|
2503
|
+
</ChatHeaderIconButton>
|
|
2504
|
+
)}
|
|
2505
|
+
</>
|
|
2506
|
+
)}
|
|
2507
|
+
</RailSlot>
|
|
2508
|
+
)}
|
|
2354
2509
|
|
|
2355
|
-
|
|
2356
|
-
|
|
2510
|
+
<div className="flex min-w-0 flex-1">
|
|
2511
|
+
{/* Rail collapse / expand toggle — lives on the chat side,
|
|
2357
2512
|
at its left edge (Figma 259:90465). Right arrow collapses
|
|
2358
2513
|
the list; left arrow brings it back. */}
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2514
|
+
<button
|
|
2515
|
+
type="button"
|
|
2516
|
+
onClick={toggleRailCollapsed}
|
|
2517
|
+
aria-label={splitActive ? 'Collapse chat list' : 'Show chat list'}
|
|
2518
|
+
aria-pressed={!splitActive}
|
|
2519
|
+
className="flex size-14 shrink-0 items-center justify-center border-r border-ods-border text-ods-text-secondary transition-colors hover:bg-ods-bg-hover hover:text-ods-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ods-accent"
|
|
2520
|
+
>
|
|
2521
|
+
{splitActive ? <Arrow02RightIcon size={24} /> : <Arrow02LeftIcon size={24} />}
|
|
2522
|
+
</button>
|
|
2523
|
+
{/* No back cell in the wide layout — the left rail (and
|
|
2369
2524
|
its collapse/expand toggle) already provides chat-list
|
|
2370
2525
|
navigation, so a back chevron would be redundant. */}
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2526
|
+
<div className="flex min-w-0 flex-1 items-center gap-[var(--spacing-system-m)] px-[var(--spacing-system-mf)] py-[var(--spacing-system-sf)]">
|
|
2527
|
+
<div className="flex min-w-0 flex-col">
|
|
2528
|
+
<p className="truncate leading-tight text-ods-text-primary text-h3">
|
|
2529
|
+
{headerShowBack || isGuideEmpty ? headerTitle : freshConversationTitle}
|
|
2530
|
+
</p>
|
|
2531
|
+
{headerPersonName && (
|
|
2532
|
+
<p className="truncate leading-tight text-ods-text-secondary text-h6">{headerPersonName}</p>
|
|
2533
|
+
)}
|
|
2534
|
+
</div>
|
|
2535
|
+
{headerAvatar ? (
|
|
2536
|
+
// Owner avatar at the title cell's right edge (Figma 113:63273).
|
|
2537
|
+
<SquareAvatar
|
|
2538
|
+
variant="round"
|
|
2539
|
+
sizePx={32}
|
|
2540
|
+
className="ml-auto"
|
|
2541
|
+
src={headerAvatar.avatarUrl || undefined}
|
|
2542
|
+
alt={headerAvatar.name || undefined}
|
|
2543
|
+
fallback={headerAvatar.name || undefined}
|
|
2544
|
+
initialsClassName="text-[11px] text-ods-text-secondary"
|
|
2545
|
+
title={headerAvatar.name || undefined}
|
|
2546
|
+
/>
|
|
2547
|
+
) : null}
|
|
2379
2548
|
</div>
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
<
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2549
|
+
|
|
2550
|
+
{isViewingArchived && headerOnRestore && (
|
|
2551
|
+
<ChatHeaderIconButton onClick={headerOnRestore} aria-label="Unarchive chat">
|
|
2552
|
+
<Refresh01LeftIcon size={24} />
|
|
2553
|
+
</ChatHeaderIconButton>
|
|
2554
|
+
)}
|
|
2555
|
+
{headerShowBack && !isViewingArchived && splitHeaderMenuItems.length > 0 && (
|
|
2556
|
+
<ActionsMenuDropdown
|
|
2557
|
+
triggerAriaLabel="Chat actions"
|
|
2558
|
+
onCloseAutoFocus={e => e.preventDefault()}
|
|
2559
|
+
groups={[{ items: splitHeaderMenuItems }]}
|
|
2560
|
+
customTrigger={
|
|
2561
|
+
<ChatHeaderIconButton aria-label="Chat actions">
|
|
2562
|
+
<Ellipsis01Icon size={24} />
|
|
2563
|
+
</ChatHeaderIconButton>
|
|
2564
|
+
}
|
|
2391
2565
|
/>
|
|
2392
|
-
)
|
|
2566
|
+
)}
|
|
2567
|
+
{closeControl && (
|
|
2568
|
+
<ChatHeaderIconButton onClick={closeControl} aria-label="Close">
|
|
2569
|
+
<XmarkIcon size={24} />
|
|
2570
|
+
</ChatHeaderIconButton>
|
|
2571
|
+
)}
|
|
2393
2572
|
</div>
|
|
2394
|
-
|
|
2395
|
-
{isViewingArchived && headerOnRestore && (
|
|
2396
|
-
<ChatHeaderIconButton onClick={headerOnRestore} aria-label="Unarchive chat">
|
|
2397
|
-
<Refresh01LeftIcon size={24} />
|
|
2398
|
-
</ChatHeaderIconButton>
|
|
2399
|
-
)}
|
|
2400
|
-
{headerShowBack && !isViewingArchived && splitHeaderMenuItems.length > 0 && (
|
|
2401
|
-
<ActionsMenuDropdown
|
|
2402
|
-
triggerAriaLabel="Chat actions"
|
|
2403
|
-
onCloseAutoFocus={e => e.preventDefault()}
|
|
2404
|
-
groups={[{ items: splitHeaderMenuItems }]}
|
|
2405
|
-
customTrigger={
|
|
2406
|
-
<ChatHeaderIconButton aria-label="Chat actions">
|
|
2407
|
-
<Ellipsis01Icon size={24} />
|
|
2408
|
-
</ChatHeaderIconButton>
|
|
2409
|
-
}
|
|
2410
|
-
/>
|
|
2411
|
-
)}
|
|
2412
|
-
<ChatHeaderIconButton onClick={handleClose} aria-label="Close">
|
|
2413
|
-
<XmarkIcon size={24} />
|
|
2414
|
-
</ChatHeaderIconButton>
|
|
2415
2573
|
</div>
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
{/* Guide-mode indicator banner (Figma node 7532:328222) —
|
|
2574
|
+
) : (
|
|
2575
|
+
// Narrow single-column header — list / compose / conversation /
|
|
2576
|
+
// guide, resolved into `narrowHeaderProps` above. (Wide layouts,
|
|
2577
|
+
// including rail-collapsed, use the wide header above.) Embedded
|
|
2578
|
+
// previews (hero demo tabs) force the compact bar via `compact`.
|
|
2579
|
+
<ChatPanelHeader {...narrowHeaderProps} compact={previewMode} />
|
|
2580
|
+
)}
|
|
2581
|
+
|
|
2582
|
+
{/* Guide-mode indicator banner (Figma node 7532:328222) —
|
|
2426
2583
|
full-bleed accent strip below the header. Shown only when
|
|
2427
2584
|
Guide mode is active AND the default (Mingo) mode also exists:
|
|
2428
2585
|
the banner contrasts the temporary Guide session against the
|
|
2429
2586
|
default chat, so it's meaningless in a guide-only setup. */}
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2587
|
+
{activeMode === 'guide' && hasMingoMode && (
|
|
2588
|
+
<GuideModeBanner
|
|
2589
|
+
className={cn('duration-200 animate-in fade-in-0', isV2 && 'col-start-2 row-start-2')}
|
|
2590
|
+
/>
|
|
2591
|
+
)}
|
|
2433
2592
|
|
|
2434
|
-
|
|
2593
|
+
{/* Chat-panel row. In the wide Mingo layout (`splitActive`) the
|
|
2435
2594
|
dialog history is hoisted into a fixed 320px "Current Chats"
|
|
2436
2595
|
rail on the left; the stacked layout keeps it inline in the
|
|
2437
2596
|
Mingo empty state (`<MingoChatHistory>` via `<MingoWelcome>`). */}
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2597
|
+
<div className={cn('flex min-h-0 flex-1 overflow-hidden', isV2 && 'col-start-2 row-start-3 min-w-0')}>
|
|
2598
|
+
{!isV2 && railPresence.mounted && (
|
|
2599
|
+
<RailSlot active={railPresence.active} innerClassName="flex flex-col min-h-0 bg-ods-card">
|
|
2600
|
+
{archiveOpen ? (
|
|
2601
|
+
// Archive list inside the rail (header lives in the split
|
|
2602
|
+
// header's left cell above). Right chat block stays put.
|
|
2603
|
+
<ChatArchivePage
|
|
2604
|
+
embedded
|
|
2605
|
+
dialogs={archivedDialogs}
|
|
2606
|
+
onSelectDialog={handleArchivedSelect}
|
|
2607
|
+
isLoading={archivedLoading}
|
|
2608
|
+
isFetching={archivedPending}
|
|
2609
|
+
hasMore={archivedCursor != null}
|
|
2610
|
+
onLoadMore={() => {
|
|
2611
|
+
void loadArchivedPage(archivedCursor ?? undefined);
|
|
2612
|
+
}}
|
|
2613
|
+
/>
|
|
2614
|
+
) : (
|
|
2615
|
+
<MingoHistoryRail
|
|
2616
|
+
dialogs={dialogs}
|
|
2617
|
+
activeDialogId={activeDialogId ?? undefined}
|
|
2618
|
+
onSelectDialog={handleSelectDialog}
|
|
2619
|
+
onNewChat={handleNewChat}
|
|
2620
|
+
onRequestRename={mingoCaps.canRename ? setRenameTarget : undefined}
|
|
2621
|
+
onRequestArchive={mingoCaps.canArchive ? setArchiveTarget : undefined}
|
|
2622
|
+
onRequestCopyLink={mingoCaps.onCopyLink}
|
|
2623
|
+
onRequestCompact={mingoCaps.compactDialog}
|
|
2624
|
+
scope={dialogScope}
|
|
2625
|
+
onScopeChange={setDialogScope}
|
|
2626
|
+
searchQuery={mingoCaps.searchQuery}
|
|
2627
|
+
hasMore={hasMoreDialogs}
|
|
2628
|
+
isLoadingMore={isDialogsLoading && dialogs.length > 0}
|
|
2629
|
+
onLoadMore={() => {
|
|
2630
|
+
void loadMoreDialogs();
|
|
2631
|
+
}}
|
|
2632
|
+
isLoadingHistory={dialogsInitialLoading}
|
|
2633
|
+
loadError={dialogsLoadError}
|
|
2634
|
+
onRetry={reloadDialogs}
|
|
2635
|
+
/>
|
|
2636
|
+
)}
|
|
2637
|
+
</RailSlot>
|
|
2638
|
+
)}
|
|
2639
|
+
<div className={cn('flex min-h-0 min-w-0 flex-1 flex-col', isV2 && 'ods-glow-accent-corner')}>
|
|
2640
|
+
{isV2 && archiveOpen ? (
|
|
2641
|
+
// v2: the archive opens in the chat column under the chat's
|
|
2642
|
+
// header; the list stays, and "Chat Archive" there toggles back.
|
|
2643
|
+
<MingoArchiveList
|
|
2446
2644
|
dialogs={archivedDialogs}
|
|
2447
2645
|
onSelectDialog={handleArchivedSelect}
|
|
2448
2646
|
isLoading={archivedLoading}
|
|
2449
|
-
isFetching={archivedPending}
|
|
2450
2647
|
hasMore={archivedCursor != null}
|
|
2648
|
+
isLoadingMore={archivedPending}
|
|
2451
2649
|
onLoadMore={() => {
|
|
2452
2650
|
void loadArchivedPage(archivedCursor ?? undefined);
|
|
2453
2651
|
}}
|
|
2454
2652
|
/>
|
|
2455
|
-
) : (
|
|
2653
|
+
) : stackedListView && isV2 ? (
|
|
2654
|
+
<MingoChatRail
|
|
2655
|
+
{...mingoRailProps}
|
|
2656
|
+
onNewChat={() => setComposeOpen(true)}
|
|
2657
|
+
className="w-full border-r-0 duration-200 animate-in fade-in-0"
|
|
2658
|
+
/>
|
|
2659
|
+
) : stackedListView ? (
|
|
2660
|
+
// Narrow "Current Chats" list (Figma 341:36190) — the default
|
|
2661
|
+
// single-column view. No composer here; "Start New Chat" opens
|
|
2662
|
+
// the compose view.
|
|
2456
2663
|
<MingoHistoryRail
|
|
2664
|
+
className="duration-200 animate-in fade-in-0"
|
|
2457
2665
|
dialogs={dialogs}
|
|
2458
2666
|
activeDialogId={activeDialogId ?? undefined}
|
|
2459
2667
|
onSelectDialog={handleSelectDialog}
|
|
2460
|
-
onNewChat={
|
|
2668
|
+
onNewChat={() => setComposeOpen(true)}
|
|
2461
2669
|
onRequestRename={mingoCaps.canRename ? setRenameTarget : undefined}
|
|
2462
2670
|
onRequestArchive={mingoCaps.canArchive ? setArchiveTarget : undefined}
|
|
2463
2671
|
onRequestCopyLink={mingoCaps.onCopyLink}
|
|
@@ -2474,317 +2682,297 @@ function EmbeddableChatInner({
|
|
|
2474
2682
|
loadError={dialogsLoadError}
|
|
2475
2683
|
onRetry={reloadDialogs}
|
|
2476
2684
|
/>
|
|
2477
|
-
)
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
onRequestRename={mingoCaps.canRename ? setRenameTarget : undefined}
|
|
2492
|
-
onRequestArchive={mingoCaps.canArchive ? setArchiveTarget : undefined}
|
|
2493
|
-
onRequestCopyLink={mingoCaps.onCopyLink}
|
|
2494
|
-
onRequestCompact={mingoCaps.compactDialog}
|
|
2495
|
-
scope={dialogScope}
|
|
2496
|
-
onScopeChange={setDialogScope}
|
|
2497
|
-
searchQuery={mingoCaps.searchQuery}
|
|
2498
|
-
hasMore={hasMoreDialogs}
|
|
2499
|
-
isLoadingMore={isDialogsLoading && dialogs.length > 0}
|
|
2500
|
-
onLoadMore={() => {
|
|
2501
|
-
void loadMoreDialogs();
|
|
2502
|
-
}}
|
|
2503
|
-
isLoadingHistory={dialogsInitialLoading}
|
|
2504
|
-
loadError={dialogsLoadError}
|
|
2505
|
-
onRetry={reloadDialogs}
|
|
2506
|
-
/>
|
|
2507
|
-
) : (
|
|
2508
|
-
<>
|
|
2509
|
-
<div ref={galleryPanelRef} className="flex min-h-0 flex-1 flex-col p-[var(--spacing-system-m)]">
|
|
2510
|
-
<div
|
|
2511
|
-
key={contentViewKey}
|
|
2512
|
-
className="flex min-h-0 flex-1 flex-col duration-200 animate-in fade-in-0"
|
|
2513
|
-
>
|
|
2514
|
-
{hasConversation ? (
|
|
2515
|
-
<div className="flex min-h-0 flex-1 flex-col">
|
|
2516
|
-
{messagesInitialLoading ? (
|
|
2517
|
-
// Match the real list's `fullWidth` layout so swapping
|
|
2518
|
-
// skeleton → bubbles doesn't shift the column. The panel
|
|
2519
|
-
// wrapper above already pads (`p-[var(--spacing-system-m)]`),
|
|
2520
|
-
// so the skeleton sits flush (no inner px/pb).
|
|
2521
|
-
//
|
|
2522
|
-
// In `previewMode` the chat lives in a fixed-height host box
|
|
2523
|
-
// (e.g. the Mingo hero demo). The default bottom-anchored
|
|
2524
|
-
// skeleton overflows a short panel and grows its OWN
|
|
2525
|
-
// scrollbar — ugly. `fill` top-anchors + clips overflow so
|
|
2526
|
-
// it reads as "the whole panel is loading" and never scrolls.
|
|
2527
|
-
<ChatMessageListSkeleton fullWidth fill={previewMode} className="flex-1" />
|
|
2528
|
-
) : (
|
|
2529
|
-
<ChatMessageList
|
|
2530
|
-
messages={messages}
|
|
2531
|
-
isTyping={chatLoading}
|
|
2532
|
-
// The stage the turn reports while the user waits
|
|
2533
|
-
// ("Searching 28 sources"); the generic phrase otherwise.
|
|
2534
|
-
typingMessage={streamingProgress ? chatProgressLabel(streamingProgress) : undefined}
|
|
2535
|
-
// Sticky footer for approvals the host lifted out of the
|
|
2536
|
-
// thread — see the prop's docblock.
|
|
2537
|
-
pendingApprovals={pendingApprovals}
|
|
2538
|
-
// Real drawer: the library's smart follow. Passive in-page
|
|
2539
|
-
// demo (previewMode): deterministic hard pin instead — a
|
|
2540
|
-
// scripted assistant-only stream from a cold mount never
|
|
2541
|
-
// satisfies the library's "at bottom" gate, so the reply
|
|
2542
|
-
// landed below the fold. `pinBottom` snaps to bottom on
|
|
2543
|
-
// every frame; identical mechanism to the Fae demo box, so
|
|
2544
|
-
// both surfaces behave 1:1.
|
|
2545
|
-
autoScroll={!previewMode}
|
|
2546
|
-
pinBottom={previewMode}
|
|
2547
|
-
// Passive in-page demos (previewMode) let the surrounding
|
|
2548
|
-
// page scroll over the thread; the real drawer keeps
|
|
2549
|
-
// containment (deck slide-scroll fix).
|
|
2550
|
-
overscrollContain={!previewMode}
|
|
2551
|
-
assistantType="mingo"
|
|
2552
|
-
assistantIcon={mingoAssistantIcon}
|
|
2553
|
-
renderEntityCard={renderEntityCard}
|
|
2554
|
-
resolveContextIcon={resolveContextIcon}
|
|
2555
|
-
renderContextItem={renderContextItem}
|
|
2556
|
-
renderMention={renderMention}
|
|
2557
|
-
renderAfterMessage={renderMessageSources}
|
|
2558
|
-
// Gated on `chatLoading` for the same reason the composer
|
|
2559
|
-
// is: no second send while a turn is in flight. Passive
|
|
2560
|
-
// demo hosts (previewMode) stay read-only.
|
|
2561
|
-
onAskSelect={chatLoading || previewMode ? undefined : handleAskSelect}
|
|
2562
|
-
NavLinkAnchor={NavLinkAnchorViaRuntime}
|
|
2563
|
-
// Real Mingo drawer: hide the message-list scrollbar
|
|
2564
|
-
// (scroll stays functional). Scoped here via `className`
|
|
2565
|
-
// instead of `ChatMessageList` itself, so other list
|
|
2566
|
-
// consumers (host chat, tickets) keep their thin bar.
|
|
2685
|
+
) : (
|
|
2686
|
+
<>
|
|
2687
|
+
<div ref={galleryPanelRef} className="flex min-h-0 flex-1 flex-col p-[var(--spacing-system-m)]">
|
|
2688
|
+
<div
|
|
2689
|
+
key={contentViewKey}
|
|
2690
|
+
className="flex min-h-0 flex-1 flex-col duration-200 animate-in fade-in-0"
|
|
2691
|
+
>
|
|
2692
|
+
{hasConversation ? (
|
|
2693
|
+
<div className="flex min-h-0 flex-1 flex-col">
|
|
2694
|
+
{messagesInitialLoading ? (
|
|
2695
|
+
// Match the real list's `fullWidth` layout so swapping
|
|
2696
|
+
// skeleton → bubbles doesn't shift the column. The panel
|
|
2697
|
+
// wrapper above already pads (`p-[var(--spacing-system-m)]`),
|
|
2698
|
+
// so the skeleton sits flush (no inner px/pb).
|
|
2567
2699
|
//
|
|
2568
|
-
// `previewMode`
|
|
2569
|
-
//
|
|
2570
|
-
//
|
|
2571
|
-
//
|
|
2572
|
-
//
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2700
|
+
// In `previewMode` the chat lives in a fixed-height host box
|
|
2701
|
+
// (e.g. the Mingo hero demo). The default bottom-anchored
|
|
2702
|
+
// skeleton overflows a short panel and grows its OWN
|
|
2703
|
+
// scrollbar — ugly. `fill` top-anchors + clips overflow so
|
|
2704
|
+
// it reads as "the whole panel is loading" and never scrolls.
|
|
2705
|
+
<ChatMessageListSkeleton fullWidth fill={previewMode} className="flex-1" />
|
|
2706
|
+
) : (
|
|
2707
|
+
<ChatMessageList
|
|
2708
|
+
messages={messages}
|
|
2709
|
+
// v2 thread: names without the colon, 24px
|
|
2710
|
+
// faces, 16px between messages (shared with fae v2).
|
|
2711
|
+
appearance={appearance}
|
|
2712
|
+
isTyping={chatLoading}
|
|
2713
|
+
// The stage the turn reports while the user waits
|
|
2714
|
+
// ("Searching 28 sources"); the generic phrase otherwise.
|
|
2715
|
+
typingMessage={streamingProgress ? chatProgressLabel(streamingProgress) : undefined}
|
|
2716
|
+
// Sticky footer for approvals the host lifted out of the
|
|
2717
|
+
// thread — see the prop's docblock.
|
|
2718
|
+
pendingApprovals={pendingApprovals}
|
|
2719
|
+
// Real drawer: the library's smart follow. Passive in-page
|
|
2720
|
+
// demo (previewMode): deterministic hard pin instead — a
|
|
2721
|
+
// scripted assistant-only stream from a cold mount never
|
|
2722
|
+
// satisfies the library's "at bottom" gate, so the reply
|
|
2723
|
+
// landed below the fold. `pinBottom` snaps to bottom on
|
|
2724
|
+
// every frame; identical mechanism to the Fae demo box, so
|
|
2725
|
+
// both surfaces behave 1:1.
|
|
2726
|
+
autoScroll={!previewMode}
|
|
2727
|
+
pinBottom={previewMode}
|
|
2728
|
+
// Passive in-page demos (previewMode) let the surrounding
|
|
2729
|
+
// page scroll over the thread; the real drawer keeps
|
|
2730
|
+
// containment (deck slide-scroll fix).
|
|
2731
|
+
overscrollContain={!previewMode}
|
|
2732
|
+
assistantType="mingo"
|
|
2733
|
+
assistantIcon={mingoAssistantIcon}
|
|
2734
|
+
renderEntityCard={renderEntityCard}
|
|
2735
|
+
resolveContextIcon={resolveContextIcon}
|
|
2736
|
+
renderContextItem={renderContextItem}
|
|
2737
|
+
renderMention={renderMention}
|
|
2738
|
+
renderAfterMessage={renderMessageSources}
|
|
2739
|
+
// Gated on `chatLoading` for the same reason the composer
|
|
2740
|
+
// is: no second send while a turn is in flight. Passive
|
|
2741
|
+
// demo hosts (previewMode) stay read-only.
|
|
2742
|
+
onAskSelect={chatLoading || previewMode ? undefined : handleAskSelect}
|
|
2743
|
+
NavLinkAnchor={NavLinkAnchorViaRuntime}
|
|
2744
|
+
// Real Mingo drawer: hide the message-list scrollbar
|
|
2745
|
+
// (scroll stays functional). Scoped here via `className`
|
|
2746
|
+
// instead of `ChatMessageList` itself, so other list
|
|
2747
|
+
// consumers (host chat, tickets) keep their thin bar.
|
|
2748
|
+
//
|
|
2749
|
+
// `previewMode` (the passive in-page demo) instead:
|
|
2750
|
+
// • KEEP the default thin scrollbar — the "elevator" —
|
|
2751
|
+
// so the Mingo demo's scroll controls match the Fae
|
|
2752
|
+
// demo box (which renders the default ChatMessageList
|
|
2753
|
+
// scrollbar) 1:1.
|
|
2754
|
+
// • Re-enable pointer events on the scroller: previewMode
|
|
2755
|
+
// puts `pointer-events-none` on the whole panel (line
|
|
2756
|
+
// ~1981) so the demo doesn't trap clicks, but that also
|
|
2757
|
+
// killed wheel/touch scroll on the thread (the Mingo
|
|
2758
|
+
// embed couldn't scroll while the Fae box could). Only
|
|
2759
|
+
// the scroller re-enables; composer + chrome stay inert.
|
|
2760
|
+
className={
|
|
2761
|
+
previewMode
|
|
2762
|
+
? 'pointer-events-auto flex-1'
|
|
2763
|
+
: 'flex-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden'
|
|
2764
|
+
}
|
|
2765
|
+
// No inner `px`/`pb`: the panel wrapper already pads with
|
|
2766
|
+
// `p-[var(--spacing-system-m)]`. The default content class
|
|
2767
|
+
// adds `px-[var(--spacing-system-m)]` + `pb-…xs`, which
|
|
2768
|
+
// double-inset the thread; `pb-0` overrides via twMerge.
|
|
2769
|
+
contentClassName="max-w-none pb-0"
|
|
2770
|
+
fullWidth
|
|
2771
|
+
hasNextPage={hasMoreMessages}
|
|
2772
|
+
isFetchingNextPage={isMessagesLoading}
|
|
2773
|
+
onLoadMore={loadMoreMessages}
|
|
2774
|
+
/>
|
|
2775
|
+
)}
|
|
2776
|
+
</div>
|
|
2777
|
+
) : activeMode === 'mingo' ? (
|
|
2778
|
+
/* Figma node 7532:222444 — default (Mingo-mode) empty state:
|
|
2598
2779
|
centred greeting + capability grid + Guide-chat promo +
|
|
2599
2780
|
quick-action chips. Guide mode keeps the slash-command
|
|
2600
2781
|
onboarding list below. */
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2782
|
+
<MingoWelcome
|
|
2783
|
+
onStartGuideChat={
|
|
2784
|
+
effectiveModes.guide ? () => handleActiveModeChange('guide') : undefined
|
|
2785
|
+
}
|
|
2786
|
+
{...mingoWelcome}
|
|
2787
|
+
// History now lives in its own list view (the wide rail or
|
|
2788
|
+
// the narrow "Current Chats" list), so the welcome is always
|
|
2789
|
+
// the new-user compose surface: greeting + grid + promo +
|
|
2790
|
+
// primary Guide chip.
|
|
2791
|
+
hasExistingChats={false}
|
|
2792
|
+
// Hover/focus PREVIEWS the action's full prompt as ghost text
|
|
2793
|
+
// in the empty composer (see `quickActionPreview` /
|
|
2794
|
+
// `ChatInput.previewText`). Wired after the `{...mingoWelcome}`
|
|
2795
|
+
// spread so the host can't override it.
|
|
2796
|
+
onQuickActionHover={action => setQuickActionPreview(action.prompt ?? action.label)}
|
|
2797
|
+
onQuickActionHoverEnd={() => setQuickActionPreview(null)}
|
|
2798
|
+
// A built-in agent caps the quick-action wall at 2 rows;
|
|
2799
|
+
// this is the Mingo surface, so fall back to 'mingo'.
|
|
2800
|
+
agentSlug={activeAgentSlug ?? 'mingo'}
|
|
2801
|
+
/>
|
|
2802
|
+
) : (
|
|
2803
|
+
/* Figma node 7532:328214 — Guide-mode empty state: greeting
|
|
2623
2804
|
+ slash-command onboarding list share one scroll region,
|
|
2624
2805
|
with a pinned quick-action chip row above the composer. */
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2806
|
+
<GuideWelcome
|
|
2807
|
+
// Admin/host greeting customises the guide subtitle; an
|
|
2808
|
+
// explicit `guideWelcome.subtitle` still wins (spread below).
|
|
2809
|
+
subtitle={effectiveGreeting ?? undefined}
|
|
2810
|
+
// While the admin greeting is still being fetched, render a
|
|
2811
|
+
// subtitle skeleton instead of flashing empty → text.
|
|
2812
|
+
subtitleLoading={emptyStateLoading}
|
|
2813
|
+
{...guideWelcome}
|
|
2814
|
+
// Agent identity (name → title, icon → empty-state glyph)
|
|
2815
|
+
// wins over the host `guideWelcome` spread + built-in
|
|
2816
|
+
// defaults; falls back to the host value when no agent is
|
|
2817
|
+
// active. Placed after the spread so resolution is
|
|
2818
|
+
// deterministic.
|
|
2819
|
+
title={effectiveAssistantName ?? guideWelcome?.title}
|
|
2820
|
+
icon={effectiveAssistantIcon ?? guideWelcome?.icon}
|
|
2821
|
+
// Admin "try-asking chips" → Guide quick-action chips.
|
|
2822
|
+
// Precedence: when an AGENT is active and its fetched chips
|
|
2823
|
+
// arrived, the agent's chips win — the host array is the
|
|
2824
|
+
// platform default, not the agent's. (`agentConfigUrl` is
|
|
2825
|
+
// the same derived value that drives the config fetch, so
|
|
2826
|
+
// this can never disagree with what was fetched; while the
|
|
2827
|
+
// fetch is in-flight the fetched list is [] and host chips
|
|
2828
|
+
// show.) Outside agent mode the host-provided
|
|
2829
|
+
// `guideWelcome.quickActions` wins as before.
|
|
2830
|
+
quickActions={
|
|
2831
|
+
agentConfigUrl && guideSuggestedActions.length > 0
|
|
2832
|
+
? guideSuggestedActions
|
|
2833
|
+
: (guideWelcome?.quickActions ?? guideSuggestedActions)
|
|
2834
|
+
}
|
|
2835
|
+
// Quick-action chips SEND the prompt immediately on click.
|
|
2836
|
+
onQuickAction={action => {
|
|
2837
|
+
setQuickActionPreview(null);
|
|
2838
|
+
handleSend(action.prompt ?? action.label);
|
|
2839
|
+
}}
|
|
2840
|
+
// Hover/focus PREVIEWS the action's full prompt as ghost text
|
|
2841
|
+
// in the empty composer (the chip label is short; this reveals
|
|
2842
|
+
// what will be sent). Declarative + non-destructive — see
|
|
2843
|
+
// `quickActionPreview` / `ChatInput.previewText`.
|
|
2844
|
+
onQuickActionHover={action => setQuickActionPreview(action.prompt ?? action.label)}
|
|
2845
|
+
onQuickActionHoverEnd={() => setQuickActionPreview(null)}
|
|
2846
|
+
// In agent mode a built-in agent (fae/mingo) caps the wall at
|
|
2847
|
+
// 2 rows; host/guide mode (no active agent) keeps the default.
|
|
2848
|
+
agentSlug={activeAgentSlug}
|
|
2849
|
+
>
|
|
2850
|
+
{/* Figma node 7363:205938 — single-column slash-command
|
|
2670
2851
|
list. No own scroll (GuideWelcome's region scrolls); the
|
|
2671
2852
|
rounded-md frame holds the cards on the dark surface. */}
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2853
|
+
{(chipCommands.length > 0 || !commandsLoaded) && (
|
|
2854
|
+
<div className="shrink-0 overflow-hidden rounded-md border border-ods-border">
|
|
2855
|
+
{!commandsLoaded &&
|
|
2856
|
+
chipCommands.length === 0 &&
|
|
2857
|
+
SKELETON_ROW_VARIANTS.map((variant, i) => (
|
|
2858
|
+
<MingoOnboardingCardSkeleton
|
|
2859
|
+
key={`chip-skeleton-${i}`}
|
|
2860
|
+
titleWidth={variant.titleWidth}
|
|
2861
|
+
slashWidth={variant.slashWidth}
|
|
2862
|
+
descriptionLines={variant.descriptionLines}
|
|
2863
|
+
/>
|
|
2864
|
+
))}
|
|
2865
|
+
{chipCommands.map(cmd => {
|
|
2866
|
+
const Icon = resolveIcon(cmd.iconName);
|
|
2867
|
+
const cmdId = cmd.id;
|
|
2868
|
+
const label = cmd.label ?? `/${cmdId}`;
|
|
2869
|
+
const cardActions = cmd.actions.map(action => ({
|
|
2870
|
+
id: action.id,
|
|
2871
|
+
label: action.label,
|
|
2872
|
+
onClick: () => dispatchSlashCommandAction(action.id, cmdId, chatInputRef),
|
|
2873
|
+
}));
|
|
2874
|
+
return (
|
|
2875
|
+
<MingoOnboardingCard
|
|
2876
|
+
key={cmdId}
|
|
2877
|
+
icon={<Icon size={16} />}
|
|
2878
|
+
title={label}
|
|
2879
|
+
slashCommand={`/${cmdId}`}
|
|
2880
|
+
description={cmd.description}
|
|
2881
|
+
actions={cardActions}
|
|
2882
|
+
/>
|
|
2883
|
+
);
|
|
2884
|
+
})}
|
|
2885
|
+
</div>
|
|
2886
|
+
)}
|
|
2887
|
+
</GuideWelcome>
|
|
2888
|
+
)}
|
|
2889
|
+
</div>
|
|
2708
2890
|
</div>
|
|
2709
|
-
</div>
|
|
2710
2891
|
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2892
|
+
<ChatAttachmentChipStrip
|
|
2893
|
+
attachments={stagedAttachments}
|
|
2894
|
+
onRemove={removeAttachment}
|
|
2895
|
+
disabled={chatLoading}
|
|
2896
|
+
/>
|
|
2716
2897
|
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2898
|
+
<ChatComposer
|
|
2899
|
+
key={composerKey}
|
|
2900
|
+
archived={isViewingArchived}
|
|
2901
|
+
lock={composerLock}
|
|
2902
|
+
inputRef={chatInputRef}
|
|
2903
|
+
onSend={handleSend}
|
|
2904
|
+
onStop={stopMessage}
|
|
2905
|
+
sending={chatLoading || hasInflightUploads}
|
|
2906
|
+
placeholder={
|
|
2907
|
+
hasInflightUploads
|
|
2908
|
+
? 'Waiting for uploads to finish…'
|
|
2909
|
+
: isV2
|
|
2910
|
+
? 'Enter your Request...'
|
|
2911
|
+
: 'Ask a question...'
|
|
2912
|
+
}
|
|
2913
|
+
autoFocus={previewMode ? false : autoFocusInput}
|
|
2914
|
+
slashCommands={slashCommandsProp}
|
|
2915
|
+
previewText={quickActionPreview ?? undefined}
|
|
2916
|
+
showAttachmentButton={attachmentsEnabled && activeMode === 'guide'}
|
|
2917
|
+
attachmentsCount={stagedAttachments.length}
|
|
2918
|
+
onAddFiles={addAttachmentFiles}
|
|
2919
|
+
attachmentsDisabled={chatLoading}
|
|
2920
|
+
contextPicker={contextPickerForMode}
|
|
2921
|
+
selectedContextItems={contextItems}
|
|
2922
|
+
onToggleContextItem={toggleContextItem}
|
|
2923
|
+
onRemoveContextItem={removeContextItem}
|
|
2924
|
+
contextMemoryItems={contextMemory?.items}
|
|
2925
|
+
onRemoveContextMemoryItem={contextMemory?.onRemove}
|
|
2926
|
+
contextPickerOpen={contextPickerOpen}
|
|
2927
|
+
onOpenContextPicker={openContextPicker}
|
|
2928
|
+
onCloseContextPicker={closeContextPicker}
|
|
2929
|
+
mentionQuery={mentionQuery}
|
|
2930
|
+
onMentionQueryChange={handleMentionQueryChange}
|
|
2931
|
+
onValueChange={handleContextValueChange}
|
|
2932
|
+
model={{
|
|
2933
|
+
provider: currentProvider ?? 'anthropic',
|
|
2934
|
+
modelName: currentModelLabel ?? 'Claude',
|
|
2935
|
+
usedTokens:
|
|
2936
|
+
currentInputTokens != null
|
|
2937
|
+
? (currentInputTokens ?? 0) + (currentOutputTokens ?? 0)
|
|
2938
|
+
: undefined,
|
|
2939
|
+
contextWindow: currentContextWindowMaxTokens ?? undefined,
|
|
2940
|
+
inputTokens: currentInputTokens ?? undefined,
|
|
2941
|
+
outputTokens: currentOutputTokens ?? undefined,
|
|
2942
|
+
hitRatePct: currentCacheHitRatePct ?? undefined,
|
|
2943
|
+
breakdown: currentUsageBreakdown ?? undefined,
|
|
2944
|
+
}}
|
|
2945
|
+
/>
|
|
2946
|
+
</>
|
|
2947
|
+
)}
|
|
2948
|
+
</div>
|
|
2761
2949
|
</div>
|
|
2762
2950
|
</div>
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
{galleryModal}
|
|
2951
|
+
)}
|
|
2952
|
+
</div>
|
|
2953
|
+
{galleryModal}
|
|
2767
2954
|
|
|
2768
|
-
|
|
2955
|
+
{/* Rename / Archive / Unarchive chat modals (Figma 7592:225962,
|
|
2769
2956
|
7592:226181). Triggered from the header ⋯ and the dialog-history
|
|
2770
2957
|
rows; rendered inside the panel so they overlay the chat. */}
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2958
|
+
<ChatDialogModals
|
|
2959
|
+
renameTarget={renameTarget}
|
|
2960
|
+
setRenameTarget={setRenameTarget}
|
|
2961
|
+
onConfirmRename={handleConfirmRename}
|
|
2962
|
+
archiveTarget={archiveTarget}
|
|
2963
|
+
setArchiveTarget={setArchiveTarget}
|
|
2964
|
+
onConfirmArchive={handleConfirmArchive}
|
|
2965
|
+
restoreTarget={restoreTarget}
|
|
2966
|
+
setRestoreTarget={setRestoreTarget}
|
|
2967
|
+
onConfirmRestore={handleConfirmRestore}
|
|
2968
|
+
/>
|
|
2782
2969
|
|
|
2783
|
-
|
|
2970
|
+
{/* Portal target for in-panel Radix overlays — `display: contents`
|
|
2784
2971
|
so it adds no box; content is positioned `fixed` by Radix. */}
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2972
|
+
<div ref={setPortalHost} style={{ display: 'contents' }} />
|
|
2973
|
+
</CollisionBoundaryContext.Provider>
|
|
2974
|
+
</PortalContainerContext.Provider>
|
|
2975
|
+
</ChatAppearanceContext.Provider>
|
|
2788
2976
|
);
|
|
2789
2977
|
|
|
2790
2978
|
// Conditional shell: inline (shell-less host, e.g. AppLayoutDrawer, which
|
|
@@ -2796,9 +2984,11 @@ function EmbeddableChatInner({
|
|
|
2796
2984
|
accessible name — Radix warns when a Dialog.Content has no Title. The
|
|
2797
2985
|
panel supplies its own visually-hidden title here, mirroring the
|
|
2798
2986
|
drawer-shell branch below, so it's accessible regardless of host. */}
|
|
2799
|
-
|
|
2800
|
-
<
|
|
2801
|
-
|
|
2987
|
+
{shell === 'none' && (
|
|
2988
|
+
<VisuallyHidden>
|
|
2989
|
+
<DialogPrimitive.Title>{sourceLabel} AI Assistant</DialogPrimitive.Title>
|
|
2990
|
+
</VisuallyHidden>
|
|
2991
|
+
)}
|
|
2802
2992
|
{body}
|
|
2803
2993
|
</ChatPanelContext.Provider>
|
|
2804
2994
|
) : (
|