@flamingo-stack/openframe-frontend-core 0.0.702 → 0.0.703-snapshot.20261006080901
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-CYYTD5ZK.cjs → chunk-262YQFOS.cjs} +47 -47
- package/dist/{chunk-SAA7B3DA.js → chunk-2G546OND.js} +500 -67
- package/dist/{chunk-6JPQDYYY.js → chunk-2JDVL7UV.js} +2614 -2001
- package/dist/{chunk-ASN65P3F.cjs → chunk-4DQMTBMK.cjs} +15 -15
- package/dist/{chunk-CZ34HXDW.js → chunk-4KGXLVCF.js} +686 -725
- package/dist/{chunk-TCZCMD5Q.js → chunk-5HBHO5TB.js} +1 -1
- package/dist/{chunk-446KS5BG.js → chunk-5QJDM6UV.js} +5 -5
- package/dist/{chunk-UJJWTJ6S.js → chunk-6WQIUQUC.js} +30 -16
- package/dist/{chunk-YR6JPJF4.js → chunk-6XIF2Z7I.js} +4 -4
- package/dist/{chunk-YGRHITPY.cjs → chunk-7JIL3WOH.cjs} +24 -24
- package/dist/{chunk-RS7HWAYX.js → chunk-7LFIKJX2.js} +3 -3
- package/dist/{chunk-4OGAXAEG.cjs → chunk-ABU3TGXA.cjs} +3 -3
- package/dist/{chunk-3WSFIV5G.cjs → chunk-AMYY3PNL.cjs} +69 -55
- package/dist/{chunk-BRXOGCH3.cjs → chunk-BIZNSF3U.cjs} +3 -3
- package/dist/{chunk-2A4XES7R.cjs → chunk-BM5MVGH3.cjs} +3 -3
- package/dist/{chunk-IIMICN7L.cjs → chunk-C3BWIU7R.cjs} +4 -44
- package/dist/{chunk-LZNJH23A.cjs → chunk-C7XGRLT5.cjs} +12 -12
- package/dist/{chunk-6YCXA7CN.js → chunk-CH5232HV.js} +20 -19
- package/dist/{chunk-UIBSSVON.cjs → chunk-D7BTSVMS.cjs} +2 -2
- package/dist/{chunk-BO5ZHDA4.js → chunk-ERCV6HHJ.js} +7 -7
- package/dist/{chunk-5V6O73EH.js → chunk-FLKJYMVB.js} +3 -3
- package/dist/{chunk-Z5HDCZAS.js → chunk-FXENTYE5.js} +15 -15
- package/dist/{chunk-HIXGAY2L.cjs → chunk-HFJW24JJ.cjs} +121 -121
- package/dist/{chunk-HPJ4XS2L.js → chunk-HJAYVKWQ.js} +24 -24
- package/dist/{chunk-PLK6GHN7.js → chunk-I7DFUQMN.js} +10 -10
- package/dist/{chunk-KJ5LWATV.js → chunk-IHU5ANUY.js} +7 -7
- package/dist/{chunk-AEQANLBW.cjs → chunk-IZGDG5X6.cjs} +505 -72
- package/dist/{chunk-2V4Z44G6.js → chunk-JEYRXT5L.js} +17 -17
- package/dist/{chunk-B3LZJ6J3.cjs → chunk-L3IC42IF.cjs} +32 -32
- package/dist/{chunk-RTGPIHVO.cjs → chunk-LDPEQGKT.cjs} +2243 -1630
- package/dist/{chunk-FD4DBTFO.cjs → chunk-LTSTC3N5.cjs} +1253 -1292
- package/dist/{chunk-OGLCD3UL.js → chunk-MFFCUVWG.js} +6 -6
- package/dist/{chunk-3L7KCOGO.cjs → chunk-MGGGBHYD.cjs} +30 -30
- package/dist/{chunk-QFW3RUZS.cjs → chunk-MI3JUJ75.cjs} +33 -33
- package/dist/{chunk-EMCQGFXD.cjs → chunk-MMOODW57.cjs} +28 -27
- package/dist/{chunk-Q76ZTHNV.js → chunk-MP2C3LJ4.js} +1 -1
- package/dist/{chunk-E3DH543A.cjs → chunk-N3TO7JV3.cjs} +98 -98
- package/dist/{chunk-2T6QWNXU.js → chunk-NDESEPW5.js} +99 -11
- package/dist/{chunk-ETFFEA3J.js → chunk-NRLJUBCS.js} +7 -7
- package/dist/{chunk-HUOLB7ZN.cjs → chunk-OHFS7VOU.cjs} +9 -9
- package/dist/{chunk-MWUBBBWZ.js → chunk-QVSFBSWV.js} +10 -10
- package/dist/{chunk-MDBHZBW7.cjs → chunk-RKV5B7EU.cjs} +92 -4
- package/dist/{chunk-3G76LRGL.cjs → chunk-SYXQLETR.cjs} +29 -29
- package/dist/{chunk-FHM7GD5B.cjs → chunk-UK62YTH6.cjs} +28 -14
- package/dist/{chunk-HUMWQMCU.js → chunk-UT4YHQZW.js} +3 -3
- package/dist/{chunk-NGJCWEYX.cjs → chunk-VHCACDKP.cjs} +46 -46
- package/dist/{chunk-5FFNNJM7.js → chunk-VR2ZLFCP.js} +1 -1
- package/dist/{chunk-IZKOQVXO.js → chunk-VTASHWER.js} +14 -14
- package/dist/{chunk-64O4L7WN.js → chunk-WUJNYGO2.js} +11 -51
- package/dist/{chunk-JOY6HVPV.js → chunk-XATTBO5X.js} +25 -11
- package/dist/{chunk-L7KZA7ZD.cjs → chunk-XIFOBQRQ.cjs} +6 -6
- package/dist/{chunk-CXDJUKC6.cjs → chunk-XJKZ4IKT.cjs} +4 -4
- package/dist/{chunk-XCIFHW4E.cjs → chunk-XOYH2YQE.cjs} +2 -2
- package/dist/{chunk-HYFLTFFB.js → chunk-ZQFZSFQI.js} +2 -2
- 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-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-drawer.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 +7 -3
- 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/panel-resize-handle.d.ts +25 -0
- package/dist/components/ui/panel-resize-handle.d.ts.map +1 -0
- 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/hooks/ui/use-resizable-panel-size.d.ts +46 -0
- package/dist/hooks/ui/use-resizable-panel-size.d.ts.map +1 -0
- 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-nav-sidebar.tsx +10 -4
- package/src/components/chat/chat-panel-header.tsx +8 -5
- package/src/components/chat/embeddable-chat.tsx +686 -494
- 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-drawer.tsx +14 -237
- 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/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 +43 -189
- 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/panel-resize-handle.tsx +184 -0
- 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/hooks/ui/use-resizable-panel-size.ts +114 -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
|
@@ -8,19 +8,19 @@ import {
|
|
|
8
8
|
type ComponentPropsWithoutRef,
|
|
9
9
|
type ComponentRef,
|
|
10
10
|
type HTMLAttributes,
|
|
11
|
-
type KeyboardEvent,
|
|
12
|
-
type PointerEvent,
|
|
13
11
|
type ReactNode,
|
|
14
12
|
forwardRef,
|
|
15
|
-
useCallback,
|
|
16
13
|
useEffect,
|
|
17
14
|
useRef,
|
|
18
15
|
useState,
|
|
16
|
+
useSyncExternalStore,
|
|
19
17
|
} from 'react';
|
|
20
18
|
|
|
19
|
+
import { ViewportBreakpoints } from '../../hooks/ui/use-content-breakpoint';
|
|
21
20
|
import { useHeaderHeight } from '../../hooks/ui/use-header-height';
|
|
21
|
+
import { type PanelDefaultSize, useResizablePanelSize } from '../../hooks/ui/use-resizable-panel-size';
|
|
22
22
|
import { cn } from '../../utils/cn';
|
|
23
|
-
import {
|
|
23
|
+
import { PanelResizeHandle } from './panel-resize-handle';
|
|
24
24
|
|
|
25
25
|
/** Unified overlay backdrop — dimmed, no blur. Single source of truth for
|
|
26
26
|
* every full-screen backdrop (Drawer, AppLayoutDrawer, MobileBurgerMenu,
|
|
@@ -138,181 +138,21 @@ type DrawerSide = 'right' | 'left' | 'top' | 'bottom';
|
|
|
138
138
|
|
|
139
139
|
const HORIZONTAL_SIDES: ReadonlySet<DrawerSide> = new Set(['left', 'right']);
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const clampToViewport = useCallback(
|
|
157
|
-
(value: number) => {
|
|
158
|
-
const vp = viewportSize(isHorizontal);
|
|
159
|
-
const effectiveMax = vp > 0 ? Math.min(maxSize, vp - 80) : maxSize;
|
|
160
|
-
return clamp(value, minSize, Math.max(minSize, effectiveMax));
|
|
161
|
-
},
|
|
162
|
-
[isHorizontal, minSize, maxSize],
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
const readInitial = useCallback(() => {
|
|
166
|
-
if (!enabled) return defaultSize;
|
|
167
|
-
if (typeof window === 'undefined') return defaultSize;
|
|
168
|
-
if (!storageKey) return clampToViewport(defaultSize);
|
|
169
|
-
try {
|
|
170
|
-
const raw = window.localStorage.getItem(storageKey);
|
|
171
|
-
if (!raw) return clampToViewport(defaultSize);
|
|
172
|
-
const parsed = parseFloat(raw);
|
|
173
|
-
if (!Number.isFinite(parsed)) return clampToViewport(defaultSize);
|
|
174
|
-
return clampToViewport(parsed);
|
|
175
|
-
} catch {
|
|
176
|
-
return clampToViewport(defaultSize);
|
|
177
|
-
}
|
|
178
|
-
}, [enabled, storageKey, defaultSize, clampToViewport]);
|
|
179
|
-
|
|
180
|
-
const [size, setSizeRaw] = useState<number>(readInitial);
|
|
181
|
-
|
|
182
|
-
const setSize = useCallback((next: number) => setSizeRaw(clampToViewport(next)), [clampToViewport]);
|
|
183
|
-
|
|
184
|
-
useEffect(() => {
|
|
185
|
-
if (!enabled || !storageKey || typeof window === 'undefined') return;
|
|
186
|
-
try {
|
|
187
|
-
window.localStorage.setItem(storageKey, String(Math.round(size)));
|
|
188
|
-
} catch {
|
|
189
|
-
// ignore quota / disabled-storage
|
|
190
|
-
}
|
|
191
|
-
}, [enabled, size, storageKey]);
|
|
192
|
-
|
|
193
|
-
useEffect(() => {
|
|
194
|
-
if (!enabled || typeof window === 'undefined') return undefined;
|
|
195
|
-
const onResize = () => setSizeRaw(prev => clampToViewport(prev));
|
|
196
|
-
window.addEventListener('resize', onResize);
|
|
197
|
-
return () => window.removeEventListener('resize', onResize);
|
|
198
|
-
}, [enabled, clampToViewport]);
|
|
199
|
-
|
|
200
|
-
return { size, setSize };
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
interface DrawerResizeHandleProps {
|
|
204
|
-
side: DrawerSide;
|
|
205
|
-
size: number;
|
|
206
|
-
minSize: number;
|
|
207
|
-
maxSize: number;
|
|
208
|
-
onSize: (next: number) => void;
|
|
209
|
-
ariaLabel?: string;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function DrawerResizeHandle({ side, size, minSize, maxSize, onSize, ariaLabel }: DrawerResizeHandleProps) {
|
|
213
|
-
const isHorizontal = HORIZONTAL_SIDES.has(side);
|
|
214
|
-
const startRef = useRef<{ x: number; y: number; size: number } | null>(null);
|
|
215
|
-
|
|
216
|
-
const direction = side === 'right' || side === 'bottom' ? -1 : 1;
|
|
217
|
-
|
|
218
|
-
const handlePointerDown = (e: PointerEvent<HTMLDivElement>) => {
|
|
219
|
-
if (e.button !== 0 && e.pointerType === 'mouse') return;
|
|
220
|
-
e.preventDefault();
|
|
221
|
-
startRef.current = { x: e.clientX, y: e.clientY, size };
|
|
222
|
-
e.currentTarget.setPointerCapture(e.pointerId);
|
|
223
|
-
document.body.style.cursor = isHorizontal ? 'col-resize' : 'row-resize';
|
|
224
|
-
document.body.style.userSelect = 'none';
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
const handlePointerMove = (e: PointerEvent<HTMLDivElement>) => {
|
|
228
|
-
const start = startRef.current;
|
|
229
|
-
if (!start) return;
|
|
230
|
-
const delta = isHorizontal ? e.clientX - start.x : e.clientY - start.y;
|
|
231
|
-
onSize(start.size + delta * direction);
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
const endDrag = (e: PointerEvent<HTMLDivElement>) => {
|
|
235
|
-
if (!startRef.current) return;
|
|
236
|
-
startRef.current = null;
|
|
237
|
-
try {
|
|
238
|
-
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
239
|
-
} catch {
|
|
240
|
-
// ignore — pointer may already be released
|
|
241
|
-
}
|
|
242
|
-
document.body.style.cursor = '';
|
|
243
|
-
document.body.style.userSelect = '';
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
|
|
247
|
-
const step = e.shiftKey ? 40 : 16;
|
|
248
|
-
if (isHorizontal) {
|
|
249
|
-
if (e.key === 'ArrowLeft') {
|
|
250
|
-
e.preventDefault();
|
|
251
|
-
onSize(size + step * (side === 'right' ? 1 : -1));
|
|
252
|
-
} else if (e.key === 'ArrowRight') {
|
|
253
|
-
e.preventDefault();
|
|
254
|
-
onSize(size + step * (side === 'right' ? -1 : 1));
|
|
255
|
-
}
|
|
256
|
-
} else {
|
|
257
|
-
if (e.key === 'ArrowUp') {
|
|
258
|
-
e.preventDefault();
|
|
259
|
-
onSize(size + step * (side === 'bottom' ? 1 : -1));
|
|
260
|
-
} else if (e.key === 'ArrowDown') {
|
|
261
|
-
e.preventDefault();
|
|
262
|
-
onSize(size + step * (side === 'bottom' ? -1 : 1));
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
if (e.key === 'Home') {
|
|
266
|
-
e.preventDefault();
|
|
267
|
-
onSize(minSize);
|
|
268
|
-
} else if (e.key === 'End') {
|
|
269
|
-
e.preventDefault();
|
|
270
|
-
onSize(maxSize);
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
// Handle is rendered as a SIBLING of the panel (child of DialogPrimitive.Content)
|
|
275
|
-
// so the panel can use `overflow-hidden` without clipping the handle.
|
|
276
|
-
// Wrapper has `py-4 px-4` (or `md:py-4 md:px-4` for flush on desktop)
|
|
277
|
-
// when the handle is visible — handle is desktop-only, where both flush
|
|
278
|
-
// and non-flush wrappers carry that padding — so `top-4 bottom-4` (or
|
|
279
|
-
// `left-4 right-4`) aligns the handle with the panel's bounds.
|
|
280
|
-
const trackPosition =
|
|
281
|
-
side === 'right'
|
|
282
|
-
? 'right-full top-4 bottom-4 w-3 items-center justify-end pr-1'
|
|
283
|
-
: side === 'left'
|
|
284
|
-
? 'left-full top-4 bottom-4 w-3 items-center justify-start pl-1'
|
|
285
|
-
: side === 'bottom'
|
|
286
|
-
? 'bottom-full left-4 right-4 h-3 justify-center items-end pb-1'
|
|
287
|
-
: 'top-full left-4 right-4 h-3 justify-center items-start pt-1';
|
|
288
|
-
|
|
289
|
-
const cursorClass = isHorizontal ? 'cursor-col-resize' : 'cursor-row-resize';
|
|
290
|
-
|
|
291
|
-
const gripClass = isHorizontal ? 'h-10 w-1' : 'w-10 h-1';
|
|
292
|
-
|
|
293
|
-
return (
|
|
294
|
-
<div
|
|
295
|
-
role="separator"
|
|
296
|
-
tabIndex={0}
|
|
297
|
-
aria-orientation={isHorizontal ? 'vertical' : 'horizontal'}
|
|
298
|
-
aria-valuenow={Math.round(size)}
|
|
299
|
-
aria-valuemin={minSize}
|
|
300
|
-
aria-valuemax={maxSize}
|
|
301
|
-
aria-label={ariaLabel ?? (isHorizontal ? 'Resize panel width' : 'Resize panel height')}
|
|
302
|
-
onPointerDown={handlePointerDown}
|
|
303
|
-
onPointerMove={handlePointerMove}
|
|
304
|
-
onPointerUp={endDrag}
|
|
305
|
-
onPointerCancel={endDrag}
|
|
306
|
-
onKeyDown={handleKeyDown}
|
|
307
|
-
className={cn(
|
|
308
|
-
'group absolute z-20 flex touch-none select-none',
|
|
309
|
-
'outline-none ring-0 focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0',
|
|
310
|
-
trackPosition,
|
|
311
|
-
cursorClass,
|
|
312
|
-
)}
|
|
313
|
-
>
|
|
314
|
-
<div aria-hidden className={cn('rounded-full bg-ods-bg-surface', gripClass)} />
|
|
315
|
-
</div>
|
|
141
|
+
const subscribeToResize = (onChange: () => void) => {
|
|
142
|
+
window.addEventListener('resize', onChange);
|
|
143
|
+
return () => window.removeEventListener('resize', onChange);
|
|
144
|
+
};
|
|
145
|
+
const subscribeToNothing = () => () => {};
|
|
146
|
+
const noExtent = () => 0;
|
|
147
|
+
|
|
148
|
+
/** The viewport's extent along the resize axis, in px. 0 on the server and
|
|
149
|
+
* while `enabled` is false, when nothing listens for resizes at all. A change
|
|
150
|
+
* on the other axis (a phone's URL bar collapsing) re-renders nothing. */
|
|
151
|
+
function useViewportExtent(enabled: boolean, isHorizontal: boolean): number {
|
|
152
|
+
return useSyncExternalStore(
|
|
153
|
+
enabled ? subscribeToResize : subscribeToNothing,
|
|
154
|
+
enabled ? (isHorizontal ? () => window.innerWidth : () => window.innerHeight) : noExtent,
|
|
155
|
+
noExtent,
|
|
316
156
|
);
|
|
317
157
|
}
|
|
318
158
|
|
|
@@ -326,9 +166,12 @@ interface DrawerContentBaseProps
|
|
|
326
166
|
minSize?: number;
|
|
327
167
|
/** Maximum allowed size (px) when resizable. Also clamped by viewport. */
|
|
328
168
|
maxSize?: number;
|
|
329
|
-
/**
|
|
330
|
-
|
|
331
|
-
|
|
169
|
+
/** Size (px) while the user has not resized the panel. Never stored. Pass a
|
|
170
|
+
* function of the viewport's extent (0 on the server) for a default that
|
|
171
|
+
* tracks the window. */
|
|
172
|
+
defaultSize?: PanelDefaultSize;
|
|
173
|
+
/** localStorage key for the size the user chose with the handle. Only that
|
|
174
|
+
* choice is stored; see `useResizablePanelSize`. */
|
|
332
175
|
storageKey?: string;
|
|
333
176
|
/** Pixel breakpoint below which `resizable` is disabled and inline
|
|
334
177
|
* size is not applied (so consumer CSS can render full-viewport).
|
|
@@ -400,8 +243,6 @@ const DrawerContent = forwardRef<ComponentRef<typeof DialogPrimitive.Content>, D
|
|
|
400
243
|
) => {
|
|
401
244
|
const resolvedSide: DrawerSide = side ?? 'right';
|
|
402
245
|
const isHorizontal = HORIZONTAL_SIDES.has(resolvedSide);
|
|
403
|
-
const initialSize = defaultSize ?? (isHorizontal ? 560 : 480);
|
|
404
|
-
|
|
405
246
|
const headerHeight = useHeaderHeight();
|
|
406
247
|
|
|
407
248
|
const [isMobile, setIsMobile] = useState(false);
|
|
@@ -414,12 +255,21 @@ const DrawerContent = forwardRef<ComponentRef<typeof DialogPrimitive.Content>, D
|
|
|
414
255
|
return () => mq.removeEventListener('change', update);
|
|
415
256
|
}, [mobileBreakpoint]);
|
|
416
257
|
|
|
417
|
-
|
|
258
|
+
// The panel keeps 80px of the viewport free so the page behind it, and the
|
|
259
|
+
// resize handle, stay reachable.
|
|
260
|
+
const available = useViewportExtent(resizable, isHorizontal);
|
|
261
|
+
const panelRef = useRef<HTMLDivElement>(null);
|
|
262
|
+
const {
|
|
263
|
+
size: resizedSize,
|
|
264
|
+
setSize,
|
|
265
|
+
clampSize,
|
|
266
|
+
} = useResizablePanelSize({
|
|
418
267
|
enabled: resizable,
|
|
419
|
-
isHorizontal,
|
|
420
268
|
minSize,
|
|
421
269
|
maxSize,
|
|
422
|
-
defaultSize:
|
|
270
|
+
defaultSize: defaultSize ?? (isHorizontal ? 560 : 480),
|
|
271
|
+
available,
|
|
272
|
+
reserve: 80,
|
|
423
273
|
storageKey,
|
|
424
274
|
});
|
|
425
275
|
|
|
@@ -443,20 +293,24 @@ const DrawerContent = forwardRef<ComponentRef<typeof DialogPrimitive.Content>, D
|
|
|
443
293
|
`overflow-hidden` so the drag track stays visible while the
|
|
444
294
|
panel cleanly clips children to its rounded corners. */}
|
|
445
295
|
{applyInlineSize ? (
|
|
446
|
-
<
|
|
296
|
+
<PanelResizeHandle
|
|
297
|
+
variant="overlay"
|
|
447
298
|
side={resolvedSide}
|
|
448
299
|
size={resizedSize}
|
|
449
300
|
minSize={minSize}
|
|
450
301
|
maxSize={maxSize}
|
|
451
302
|
onSize={setSize}
|
|
303
|
+
clampSize={clampSize}
|
|
304
|
+
panelRef={panelRef}
|
|
452
305
|
ariaLabel={resizeAriaLabel}
|
|
453
306
|
/>
|
|
454
307
|
) : null}
|
|
455
308
|
<div
|
|
309
|
+
ref={panelRef}
|
|
456
310
|
className={cn(drawerPanelVariants({ side, flush, size }), className, panelClassName)}
|
|
457
311
|
style={{ ...sizeStyle, ...panelStyle }}
|
|
458
312
|
>
|
|
459
|
-
{children}
|
|
313
|
+
<ViewportBreakpoints>{children}</ViewportBreakpoints>
|
|
460
314
|
</div>
|
|
461
315
|
</DialogPrimitive.Content>
|
|
462
316
|
</DrawerPortal>
|
|
@@ -115,7 +115,7 @@ export function DurationInput({ value, onChange, invalid, className }: DurationI
|
|
|
115
115
|
}
|
|
116
116
|
}}
|
|
117
117
|
className={cn(
|
|
118
|
-
'flex h-11 w-full items-center gap-[var(--spacing-system-xxs)] rounded-md border border-ods-border bg-ods-card px-[var(--spacing-system-sf)] transition-colors duration-200 md:h-12',
|
|
118
|
+
'flex h-11 w-full items-center gap-[var(--spacing-system-xxs)] rounded-md border border-ods-border bg-ods-card px-[var(--spacing-system-sf)] transition-colors duration-200 content-md:h-12',
|
|
119
119
|
'cursor-text focus-within:border-ods-accent',
|
|
120
120
|
invalid && 'border-ods-error focus-within:border-ods-error',
|
|
121
121
|
className,
|
|
@@ -7,7 +7,7 @@ import { cn } from '../../utils/cn';
|
|
|
7
7
|
import { personInitials } from '../../utils/format';
|
|
8
8
|
|
|
9
9
|
/** The design size, when a caller does not state one. */
|
|
10
|
-
const ENTITY_IMAGE_SIZE = 'size-[52px] md:size-[60px]';
|
|
10
|
+
const ENTITY_IMAGE_SIZE = 'size-[52px] content-md:size-[60px]';
|
|
11
11
|
|
|
12
12
|
export interface EntityImageProps {
|
|
13
13
|
src?: string | null;
|
|
@@ -18,10 +18,10 @@ export interface EntityImageProps {
|
|
|
18
18
|
* REPLACES the default size, for both the image and its initials fallback.
|
|
19
19
|
*
|
|
20
20
|
* Sizing through `className` does NOT work here and cannot be made to:
|
|
21
|
-
* the default is responsive (`size-[52px] md:size-[60px]`), and
|
|
21
|
+
* the default is responsive (`size-[52px] content-md:size-[60px]`), and
|
|
22
22
|
* tailwind-merge lets `size-*` override `w`/`h` but never the reverse — so a
|
|
23
23
|
* caller passing `h-4 w-6` dropped the base `size-[52px]` and kept
|
|
24
|
-
* `md:size-[60px]`, rendering 16px on a phone and 60px on a desktop. State
|
|
24
|
+
* `content-md:size-[60px]`, rendering 16px on a phone and 60px on a desktop. State
|
|
25
25
|
* the size here instead; it is substituted, not merged.
|
|
26
26
|
*/
|
|
27
27
|
sizeClassName?: string;
|
|
@@ -59,9 +59,9 @@ export interface FeatureCardGridProps {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
const GRID_COLUMNS = {
|
|
62
|
-
2: 'grid-cols-1 md:grid-cols-2',
|
|
63
|
-
3: 'grid-cols-1 md:grid-cols-3',
|
|
64
|
-
4: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4',
|
|
62
|
+
2: 'grid-cols-1 content-md:grid-cols-2',
|
|
63
|
+
3: 'grid-cols-1 content-md:grid-cols-3',
|
|
64
|
+
4: 'grid-cols-1 content-md:grid-cols-2 content-lg:grid-cols-4',
|
|
65
65
|
} as const;
|
|
66
66
|
|
|
67
67
|
/**
|
|
@@ -75,10 +75,10 @@ function fourColumnBorders(index: number, count: number): string {
|
|
|
75
75
|
if (index < count - 1) classes.push('border-b');
|
|
76
76
|
const mdRows = Math.ceil(count / 2);
|
|
77
77
|
const lgRows = Math.ceil(count / 4);
|
|
78
|
-
classes.push(index % 2 === 0 && index < count - 1 ? 'md:border-r' : 'md:border-r-0');
|
|
79
|
-
classes.push(Math.floor(index / 2) < mdRows - 1 ? 'md:border-b' : 'md:border-b-0');
|
|
80
|
-
classes.push(index % 4 !== 3 && index < count - 1 ? 'lg:border-r' : 'lg:border-r-0');
|
|
81
|
-
classes.push(Math.floor(index / 4) < lgRows - 1 ? 'lg:border-b' : 'lg:border-b-0');
|
|
78
|
+
classes.push(index % 2 === 0 && index < count - 1 ? 'content-md:border-r' : 'content-md:border-r-0');
|
|
79
|
+
classes.push(Math.floor(index / 2) < mdRows - 1 ? 'content-md:border-b' : 'content-md:border-b-0');
|
|
80
|
+
classes.push(index % 4 !== 3 && index < count - 1 ? 'content-lg:border-r' : 'content-lg:border-r-0');
|
|
81
|
+
classes.push(Math.floor(index / 4) < lgRows - 1 ? 'content-lg:border-b' : 'content-lg:border-b-0');
|
|
82
82
|
return ` ${classes.join(' ')}`;
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -117,7 +117,7 @@ export function FeatureCardGrid({
|
|
|
117
117
|
if (!isLastInRow) {
|
|
118
118
|
// On mobile (1 column), never show right border
|
|
119
119
|
// On desktop (2/3 columns), show right border except for last in row
|
|
120
|
-
classes += ' md:border-r border-ods-border';
|
|
120
|
+
classes += ' content-md:border-r border-ods-border';
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
// Bottom border logic
|
|
@@ -130,10 +130,10 @@ export function FeatureCardGrid({
|
|
|
130
130
|
|
|
131
131
|
// Desktop: override mobile border, show bottom border for all rows except last
|
|
132
132
|
if (!isLastRow) {
|
|
133
|
-
classes += ' md:border-b border-ods-border';
|
|
133
|
+
classes += ' content-md:border-b border-ods-border';
|
|
134
134
|
} else {
|
|
135
135
|
// Last row on desktop - remove bottom border
|
|
136
|
-
classes += ' md:border-b-0';
|
|
136
|
+
classes += ' content-md:border-b-0';
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
return classes;
|
|
@@ -17,7 +17,7 @@ export function FileManagerActionBar({
|
|
|
17
17
|
className,
|
|
18
18
|
}: FileManagerActionBarProps) {
|
|
19
19
|
return (
|
|
20
|
-
<div className={cn('flex flex-wrap items-center gap-4 md:justify-end', className)}>
|
|
20
|
+
<div className={cn('flex flex-wrap items-center gap-4 content-md:justify-end', className)}>
|
|
21
21
|
<Button variant="outline" size="small-legacy" onClick={onNewFolder} leftIcon={<FolderPlus className="h-4 w-4" />}>
|
|
22
22
|
New Folder
|
|
23
23
|
</Button>
|
|
@@ -129,7 +129,7 @@ export function FileManager({
|
|
|
129
129
|
return (
|
|
130
130
|
<div className={cn('flex h-full flex-col bg-ods-bg', className)}>
|
|
131
131
|
<div className="flex min-h-0 flex-1 flex-col space-y-6 py-2">
|
|
132
|
-
<div className="mb-4 flex flex-col justify-between gap-4 md:flex-row">
|
|
132
|
+
<div className="mb-4 flex flex-col justify-between gap-4 content-md:flex-row">
|
|
133
133
|
<FileManagerBreadcrumb items={breadcrumbItems} onItemClick={handleBreadcrumbClick} />
|
|
134
134
|
|
|
135
135
|
{showActions && (
|
|
@@ -175,7 +175,14 @@ export function FilterModal({
|
|
|
175
175
|
const isEmpty = !isLoading && !hasSort && !hasFilterGroups && !hasTagFilter && !dateFilter;
|
|
176
176
|
|
|
177
177
|
return (
|
|
178
|
-
<ModalV2
|
|
178
|
+
<ModalV2
|
|
179
|
+
isOpen={isOpen}
|
|
180
|
+
onClose={onClose}
|
|
181
|
+
// Full width as the phone's bottom sheet. A wide window gets the medium dialog
|
|
182
|
+
// width instead: page content narrowed by a docked side panel shows the
|
|
183
|
+
// mobile filter button there too, and a window-wide sheet read as broken.
|
|
184
|
+
className={cn('max-h-[90vh] max-w-none md:max-w-[min(42rem,calc(100vw-2rem))]', className)}
|
|
185
|
+
>
|
|
179
186
|
<ModalV2Header>
|
|
180
187
|
<ModalV2Title>{title}</ModalV2Title>
|
|
181
188
|
</ModalV2Header>
|
|
@@ -18,11 +18,11 @@ export function HighlightCard({ item, className = '' }: HighlightCardProps) {
|
|
|
18
18
|
const desktopWidth = item.category.length * 14;
|
|
19
19
|
|
|
20
20
|
return (
|
|
21
|
-
<div className={`relative bg-ods-bg p-6 md:p-10 ${className}`}>
|
|
21
|
+
<div className={`relative bg-ods-bg p-6 content-md:p-10 ${className}`}>
|
|
22
22
|
<div className="relative">
|
|
23
23
|
{/* Mobile highlight */}
|
|
24
24
|
<div
|
|
25
|
-
className="absolute left-[80px] top-0 h-8 rounded-md md:hidden"
|
|
25
|
+
className="absolute left-[80px] top-0 h-8 rounded-md content-md:hidden"
|
|
26
26
|
style={{
|
|
27
27
|
backgroundColor: item.highlightBg,
|
|
28
28
|
width: `${mobileWidth}px`,
|
|
@@ -30,7 +30,7 @@ export function HighlightCard({ item, className = '' }: HighlightCardProps) {
|
|
|
30
30
|
/>
|
|
31
31
|
{/* Desktop highlight */}
|
|
32
32
|
<div
|
|
33
|
-
className="absolute left-[95px] top-0 hidden h-10 rounded-md md:block"
|
|
33
|
+
className="absolute left-[95px] top-0 hidden h-10 rounded-md content-md:block"
|
|
34
34
|
style={{
|
|
35
35
|
backgroundColor: item.highlightBg,
|
|
36
36
|
width: `${desktopWidth}px`,
|
|
@@ -57,7 +57,7 @@ export function HighlightCardGrid({
|
|
|
57
57
|
className = '',
|
|
58
58
|
cardClassName = 'bg-ods-card border border-ods-border rounded-lg p-0 overflow-hidden',
|
|
59
59
|
}: HighlightCardGridProps) {
|
|
60
|
-
const gridCols = columns === 2 ? 'grid-cols-1 md:grid-cols-2' : 'grid-cols-1 md:grid-cols-3';
|
|
60
|
+
const gridCols = columns === 2 ? 'grid-cols-1 content-md:grid-cols-2' : 'grid-cols-1 content-md:grid-cols-3';
|
|
61
61
|
const itemsPerRow = columns;
|
|
62
62
|
const rows = Math.ceil(items.length / itemsPerRow);
|
|
63
63
|
|
|
@@ -68,7 +68,7 @@ export function HighlightCardGrid({
|
|
|
68
68
|
if (!isLastInRow) {
|
|
69
69
|
// On mobile (1 column), never show right border
|
|
70
70
|
// On desktop (2/3 columns), show right border except for last in row
|
|
71
|
-
classes += ' md:border-r border-ods-border';
|
|
71
|
+
classes += ' content-md:border-r border-ods-border';
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// Bottom border logic
|
|
@@ -81,10 +81,10 @@ export function HighlightCardGrid({
|
|
|
81
81
|
|
|
82
82
|
// Desktop: override mobile border, show bottom border for all rows except last
|
|
83
83
|
if (!isLastRow) {
|
|
84
|
-
classes += ' md:border-b border-ods-border';
|
|
84
|
+
classes += ' content-md:border-b border-ods-border';
|
|
85
85
|
} else {
|
|
86
86
|
// Last row on desktop - remove bottom border
|
|
87
|
-
classes += ' md:border-b-0';
|
|
87
|
+
classes += ' content-md:border-b-0';
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
return classes;
|
|
@@ -14,7 +14,7 @@ export interface InfoCardRowProps {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const CELL =
|
|
17
|
-
'flex items-center gap-[var(--spacing-system-s)] min-w-0 p-[var(--spacing-system-xsf)] md:p-[var(--spacing-system-m)] min-h-[60px] md:min-h-[76px]';
|
|
17
|
+
'flex items-center gap-[var(--spacing-system-s)] min-w-0 p-[var(--spacing-system-xsf)] content-md:p-[var(--spacing-system-m)] min-h-[60px] content-md:min-h-[76px]';
|
|
18
18
|
|
|
19
19
|
function StatCell({ section, className }: { section: InfoCardRowSection; className?: string }) {
|
|
20
20
|
return (
|
|
@@ -24,11 +24,13 @@ function StatCell({ section, className }: { section: InfoCardRowSection; classNa
|
|
|
24
24
|
<div className="flex min-w-0 items-center gap-[var(--spacing-system-s)]">
|
|
25
25
|
<p className="min-w-0 flex-1 truncate text-ods-text-primary text-h3">{section.caption}</p>
|
|
26
26
|
{section.icon && (
|
|
27
|
-
<div className="flex size-6 shrink-0 items-center justify-center md:hidden">{section.icon}</div>
|
|
27
|
+
<div className="flex size-6 shrink-0 items-center justify-center content-md:hidden">{section.icon}</div>
|
|
28
28
|
)}
|
|
29
29
|
</div>
|
|
30
30
|
</div>
|
|
31
|
-
{section.icon &&
|
|
31
|
+
{section.icon && (
|
|
32
|
+
<div className="hidden size-6 shrink-0 items-center justify-center content-md:flex">{section.icon}</div>
|
|
33
|
+
)}
|
|
32
34
|
</div>
|
|
33
35
|
);
|
|
34
36
|
}
|
|
@@ -37,11 +39,13 @@ export function InfoCardRow({ lead, stats, className }: InfoCardRowProps) {
|
|
|
37
39
|
return (
|
|
38
40
|
<div
|
|
39
41
|
className={cn(
|
|
40
|
-
'flex shrink-0 flex-col overflow-hidden rounded-md border border-ods-border bg-ods-card md:flex-row',
|
|
42
|
+
'flex shrink-0 flex-col overflow-hidden rounded-md border border-ods-border bg-ods-card content-md:flex-row',
|
|
41
43
|
className,
|
|
42
44
|
)}
|
|
43
45
|
>
|
|
44
|
-
<div
|
|
46
|
+
<div
|
|
47
|
+
className={cn(CELL, 'border-b border-ods-border content-md:flex-1 content-md:border-b-0 content-md:border-r')}
|
|
48
|
+
>
|
|
45
49
|
{lead.icon && (
|
|
46
50
|
<div className="flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-sm border border-ods-border [&>*]:size-full [&_img]:object-cover">
|
|
47
51
|
{lead.icon}
|
|
@@ -53,7 +57,7 @@ export function InfoCardRow({ lead, stats, className }: InfoCardRowProps) {
|
|
|
53
57
|
</div>
|
|
54
58
|
</div>
|
|
55
59
|
|
|
56
|
-
<div className="flex md:flex-1">
|
|
60
|
+
<div className="flex content-md:flex-1">
|
|
57
61
|
<StatCell section={stats[0]} className="border-r border-ods-border" />
|
|
58
62
|
<StatCell section={stats[1]} />
|
|
59
63
|
</div>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { type ReactNode, createContext, forwardRef, useContext, useRef, useEffect, useState } from 'react';
|
|
4
4
|
import { RemoveScroll } from 'react-remove-scroll';
|
|
5
|
+
import { ViewportBreakpoints } from '../../hooks/ui/use-content-breakpoint';
|
|
5
6
|
import { cn } from '../../utils/cn';
|
|
6
7
|
import { XmarkIcon } from '../icons-v2-generated';
|
|
7
8
|
|
|
@@ -235,7 +236,9 @@ const Modal = forwardRef<HTMLDivElement, ModalProps>(
|
|
|
235
236
|
mirrored there as INSET_TRANSITION_MS — it delays the app's
|
|
236
237
|
scroll-the-focused-field re-assert until this transition settles. */}
|
|
237
238
|
<div
|
|
238
|
-
|
|
239
|
+
// `ods-viewport-layer`: a modal follows the window, so a modal opened from a
|
|
240
|
+
// narrow content area takes the window's tokens, not the area's mobile ones.
|
|
241
|
+
className="ods-viewport-layer fixed inset-0 z-[1300] flex items-end justify-center transition-[padding] duration-200 md:items-center"
|
|
239
242
|
style={{ paddingBottom: 'var(--of-keyboard-inset, 0px)' }}
|
|
240
243
|
>
|
|
241
244
|
<div
|
|
@@ -303,7 +306,9 @@ const Modal = forwardRef<HTMLDivElement, ModalProps>(
|
|
|
303
306
|
role="dialog"
|
|
304
307
|
aria-modal="true"
|
|
305
308
|
>
|
|
306
|
-
<ModalContext.Provider value={{ onClose }}>
|
|
309
|
+
<ModalContext.Provider value={{ onClose }}>
|
|
310
|
+
<ViewportBreakpoints>{children}</ViewportBreakpoints>
|
|
311
|
+
</ModalContext.Provider>
|
|
307
312
|
</div>
|
|
308
313
|
</div>
|
|
309
314
|
</RemoveScroll>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { usePreventScroll } from '@react-aria/overlays';
|
|
4
4
|
import { type ReactNode, forwardRef, useEffect } from 'react';
|
|
5
|
+
import { ViewportBreakpoints } from '../../hooks/ui/use-content-breakpoint';
|
|
5
6
|
import { cn } from '../../utils/cn';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -61,7 +62,7 @@ const Modal = forwardRef<HTMLDivElement, ModalProps>(({ isOpen, onClose, childre
|
|
|
61
62
|
if (!isOpen) return null;
|
|
62
63
|
|
|
63
64
|
return (
|
|
64
|
-
<div className="fixed inset-0 z-[1300] flex items-center justify-center">
|
|
65
|
+
<div className="ods-viewport-layer fixed inset-0 z-[1300] flex items-center justify-center">
|
|
65
66
|
<div className="absolute inset-0 bg-ods-overlay" onClick={onClose} aria-hidden="true" />
|
|
66
67
|
<div
|
|
67
68
|
ref={ref}
|
|
@@ -72,7 +73,7 @@ const Modal = forwardRef<HTMLDivElement, ModalProps>(({ isOpen, onClose, childre
|
|
|
72
73
|
role="dialog"
|
|
73
74
|
aria-modal="true"
|
|
74
75
|
>
|
|
75
|
-
{children}
|
|
76
|
+
<ViewportBreakpoints>{children}</ViewportBreakpoints>
|
|
76
77
|
</div>
|
|
77
78
|
</div>
|
|
78
79
|
);
|
|
@@ -25,13 +25,15 @@ const NoDataAction = React.forwardRef<HTMLDivElement, NoDataActionProps>(functio
|
|
|
25
25
|
ref={ref}
|
|
26
26
|
className={cn(
|
|
27
27
|
'flex flex-1 items-center gap-[var(--spacing-system-s)] p-[var(--spacing-system-m)] text-ods-text-secondary',
|
|
28
|
-
'md:w-[224px] md:flex-none md:flex-col md:items-start md:gap-[var(--spacing-system-xs)]',
|
|
28
|
+
'content-md:w-[224px] content-md:flex-none content-md:flex-col content-md:items-start content-md:gap-[var(--spacing-system-xs)]',
|
|
29
29
|
className,
|
|
30
30
|
)}
|
|
31
31
|
{...props}
|
|
32
32
|
>
|
|
33
33
|
{icon && <span className={cn(noDataIconClasses, 'text-ods-text-primary')}>{icon}</span>}
|
|
34
|
-
<span className="min-w-0 flex-1 break-words text-h6 md:w-full md:flex-none">
|
|
34
|
+
<span className="min-w-0 flex-1 break-words text-h6 content-md:w-full content-md:flex-none">
|
|
35
|
+
{label ?? children}
|
|
36
|
+
</span>
|
|
35
37
|
</div>
|
|
36
38
|
);
|
|
37
39
|
});
|
|
@@ -61,7 +63,11 @@ const NoDataActions = React.forwardRef<HTMLDivElement, NoDataActionsProps>(funct
|
|
|
61
63
|
return (
|
|
62
64
|
<div
|
|
63
65
|
ref={ref}
|
|
64
|
-
className={cn(
|
|
66
|
+
className={cn(
|
|
67
|
+
noDataActionsVariants({ variant }),
|
|
68
|
+
'flex w-full flex-col content-md:w-auto content-md:flex-row',
|
|
69
|
+
className,
|
|
70
|
+
)}
|
|
65
71
|
{...props}
|
|
66
72
|
>
|
|
67
73
|
{blocks.map((block, index) => (
|
|
@@ -69,7 +75,7 @@ const NoDataActions = React.forwardRef<HTMLDivElement, NoDataActionsProps>(funct
|
|
|
69
75
|
{index > 0 && (
|
|
70
76
|
<div
|
|
71
77
|
aria-hidden="true"
|
|
72
|
-
className="shrink-0 self-stretch border-t border-ods-border md:border-l md:border-t-0"
|
|
78
|
+
className="shrink-0 self-stretch border-t border-ods-border content-md:border-l content-md:border-t-0"
|
|
73
79
|
/>
|
|
74
80
|
)}
|
|
75
81
|
{block}
|
|
@@ -7,7 +7,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
|
|
|
7
7
|
// Leading-icon glyph scale: 16px on mobile, 24px on md+. Color is intentionally
|
|
8
8
|
// omitted so the glyph inherits the current text color.
|
|
9
9
|
export const noDataIconClasses =
|
|
10
|
-
'inline-flex shrink-0 items-center justify-center [&_svg]:h-4 [&_svg]:w-4 md:[&_svg]:h-6 md:[&_svg]:w-6';
|
|
10
|
+
'inline-flex shrink-0 items-center justify-center [&_svg]:h-4 [&_svg]:w-4 content-md:[&_svg]:h-6 content-md:[&_svg]:w-6';
|
|
11
11
|
|
|
12
12
|
// Surface for the info-block group container: a transparent, bordered panel with
|
|
13
13
|
// rounded corners. `overflow-hidden` keeps only the outer blocks round — inner
|
|
@@ -65,7 +65,7 @@ const NoData = React.forwardRef<HTMLDivElement, NoDataProps>(function NoDataImpl
|
|
|
65
65
|
leftIcon={buttonIcon}
|
|
66
66
|
onClick={onButtonClick}
|
|
67
67
|
{...buttonProps}
|
|
68
|
-
className={cn('w-full md:w-auto', buttonProps?.className)}
|
|
68
|
+
className={cn('w-full content-md:w-auto', buttonProps?.className)}
|
|
69
69
|
>
|
|
70
70
|
{buttonLabel}
|
|
71
71
|
</Button>
|
|
@@ -127,7 +127,7 @@ export function OrganizationCard({
|
|
|
127
127
|
customFooter
|
|
128
128
|
) : footerStats && footerStats.length > 0 ? (
|
|
129
129
|
<div className="flex w-full min-w-0 items-center justify-between gap-2">
|
|
130
|
-
<div className="flex min-w-0 flex-shrink items-center gap-3 md:gap-4">
|
|
130
|
+
<div className="flex min-w-0 flex-shrink items-center gap-3 content-md:gap-4">
|
|
131
131
|
{footerStats.map((stat, index) => (
|
|
132
132
|
<div key={index} className="flex flex-shrink-0 items-center gap-1">
|
|
133
133
|
{stat.icon}
|