@flamingo-stack/openframe-frontend-core 0.0.296-snapshot.20260621021605 → 0.0.296
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -9
- package/dist/chunk-26PKDALD.js +2379 -0
- package/dist/chunk-26PKDALD.js.map +1 -0
- package/dist/chunk-3MCHAFHB.js +89 -0
- package/dist/chunk-3MCHAFHB.js.map +1 -0
- package/dist/{chunk-PI4WSYQV.js → chunk-3ZXUQQL4.js} +2 -2
- package/dist/{chunk-WMSTJAZT.cjs → chunk-5E2HOSSH.cjs} +51 -913
- package/dist/chunk-5E2HOSSH.cjs.map +1 -0
- package/dist/{chunk-IL47XWV5.js → chunk-5P3B2LZW.js} +14 -8
- package/dist/{chunk-IL47XWV5.js.map → chunk-5P3B2LZW.js.map} +1 -1
- package/dist/chunk-66AANIOC.cjs +619 -0
- package/dist/chunk-66AANIOC.cjs.map +1 -0
- package/dist/{chunk-AD6C23QY.js → chunk-6GCI7JOE.js} +7 -8
- package/dist/{chunk-AD6C23QY.js.map → chunk-6GCI7JOE.js.map} +1 -1
- package/dist/chunk-6JINAOI7.cjs +311 -0
- package/dist/chunk-6JINAOI7.cjs.map +1 -0
- package/dist/{chunk-2QG57XOJ.js → chunk-7RIYT7ZH.js} +205 -1067
- package/dist/chunk-7RIYT7ZH.js.map +1 -0
- package/dist/{chunk-L6PSSIUQ.cjs → chunk-AQOWFSMB.cjs} +1 -1
- package/dist/chunk-AQOWFSMB.cjs.map +1 -0
- package/dist/chunk-BOCFIKYS.cjs +3009 -0
- package/dist/chunk-BOCFIKYS.cjs.map +1 -0
- package/dist/{chunk-54KNMC2R.cjs → chunk-D3LEFMOA.cjs} +3 -3
- package/dist/{chunk-54KNMC2R.cjs.map → chunk-D3LEFMOA.cjs.map} +1 -1
- package/dist/chunk-D652TJBQ.js +3009 -0
- package/dist/chunk-D652TJBQ.js.map +1 -0
- package/dist/{chunk-PWQUAVA3.js → chunk-E4XABBSU.js} +98 -338
- package/dist/chunk-E4XABBSU.js.map +1 -0
- package/dist/{chunk-JALO4TAZ.js → chunk-EL6QLAWX.js} +55 -357
- package/dist/chunk-EL6QLAWX.js.map +1 -0
- package/dist/{chunk-6C526VNN.cjs → chunk-EYEW6PTA.cjs} +118 -358
- package/dist/chunk-EYEW6PTA.cjs.map +1 -0
- package/dist/chunk-FQJK446R.js +1606 -0
- package/dist/chunk-FQJK446R.js.map +1 -0
- package/dist/{chunk-4PSQS3SW.cjs → chunk-GLLDTKZK.cjs} +9 -7
- package/dist/chunk-GLLDTKZK.cjs.map +1 -0
- package/dist/{chunk-FQOTC3UU.cjs → chunk-IE6OU3WQ.cjs} +16 -318
- package/dist/chunk-IE6OU3WQ.cjs.map +1 -0
- package/dist/chunk-J54Z3OCR.cjs +1606 -0
- package/dist/chunk-J54Z3OCR.cjs.map +1 -0
- package/dist/{chunk-PC746XCO.js → chunk-K2PFPBMF.js} +5563 -15048
- package/dist/chunk-K2PFPBMF.js.map +1 -0
- package/dist/chunk-KXCRGTRN.cjs +2379 -0
- package/dist/chunk-KXCRGTRN.cjs.map +1 -0
- package/dist/{chunk-IZ7JSBFP.js → chunk-LCNMR277.js} +1 -1
- package/dist/chunk-LCNMR277.js.map +1 -0
- package/dist/chunk-LFGGF7OT.cjs +449 -0
- package/dist/chunk-LFGGF7OT.cjs.map +1 -0
- package/dist/chunk-M2OCXTNT.js +311 -0
- package/dist/chunk-M2OCXTNT.js.map +1 -0
- package/dist/{chunk-L7ULJKG7.js → chunk-MBFWU2EM.js} +10 -6
- package/dist/{chunk-L7ULJKG7.js.map → chunk-MBFWU2EM.js.map} +1 -1
- package/dist/chunk-ME4EVDFP.js +619 -0
- package/dist/chunk-ME4EVDFP.js.map +1 -0
- package/dist/chunk-OQ6X7ZOC.js +449 -0
- package/dist/chunk-OQ6X7ZOC.js.map +1 -0
- package/dist/{chunk-4TLE6VLU.js → chunk-OY7OF7E7.js} +24 -30
- package/dist/chunk-OY7OF7E7.js.map +1 -0
- package/dist/chunk-POKKCWKF.js +354 -0
- package/dist/chunk-POKKCWKF.js.map +1 -0
- package/dist/{chunk-GUTS7HGA.cjs → chunk-QHIXS3W2.cjs} +2514 -11999
- package/dist/chunk-QHIXS3W2.cjs.map +1 -0
- package/dist/chunk-TFSYSWPS.cjs +89 -0
- package/dist/chunk-TFSYSWPS.cjs.map +1 -0
- package/dist/{chunk-53FUMSZ5.cjs → chunk-W6M2FLLT.cjs} +46 -40
- package/dist/chunk-W6M2FLLT.cjs.map +1 -0
- package/dist/{chunk-3JIQVE7T.js → chunk-WHMATDVP.js} +15 -9
- package/dist/{chunk-3JIQVE7T.js.map → chunk-WHMATDVP.js.map} +1 -1
- package/dist/{chunk-YBYI62OE.cjs → chunk-X647HY3F.cjs} +37 -33
- package/dist/chunk-X647HY3F.cjs.map +1 -0
- package/dist/{chunk-UNVE2SDJ.cjs → chunk-X6BV7MB7.cjs} +31 -37
- package/dist/chunk-X6BV7MB7.cjs.map +1 -0
- package/dist/{chunk-7OVGB2DQ.cjs → chunk-XREEV72C.cjs} +25 -19
- package/dist/chunk-XREEV72C.cjs.map +1 -0
- package/dist/chunk-YETA25JW.cjs +354 -0
- package/dist/chunk-YETA25JW.cjs.map +1 -0
- package/dist/{chunk-FCDQNTDG.cjs → chunk-YIGPRLQY.cjs} +20 -21
- package/dist/chunk-YIGPRLQY.cjs.map +1 -0
- package/dist/{chunk-X4DOXQRT.js → chunk-ZP4AVIZP.js} +6 -4
- package/dist/{chunk-X4DOXQRT.js.map → chunk-ZP4AVIZP.js.map} +1 -1
- package/dist/components/chat/index.cjs +18 -8
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +85 -75
- package/dist/components/contact/index.cjs +15 -8
- package/dist/components/contact/index.cjs.map +1 -1
- package/dist/components/contact/index.js +14 -7
- package/dist/components/docs/doc-viewer.d.ts +2 -39
- package/dist/components/docs/doc-viewer.d.ts.map +1 -1
- package/dist/components/docs/index.cjs +9 -17
- package/dist/components/docs/index.cjs.map +1 -1
- package/dist/components/docs/index.d.ts +0 -4
- package/dist/components/docs/index.d.ts.map +1 -1
- package/dist/components/docs/index.js +8 -16
- package/dist/components/docs/use-document-tree.d.ts.map +1 -1
- package/dist/components/embeds/embed-iframe.d.ts.map +1 -1
- package/dist/components/embeds/index.cjs +15 -38
- package/dist/components/embeds/index.cjs.map +1 -1
- package/dist/components/embeds/index.d.ts +0 -8
- package/dist/components/embeds/index.d.ts.map +1 -1
- package/dist/components/embeds/index.js +17 -40
- package/dist/components/faq/index.cjs +16 -9
- package/dist/components/faq/index.cjs.map +1 -1
- package/dist/components/faq/index.js +15 -8
- package/dist/components/features/index.cjs +16 -8
- package/dist/components/features/index.cjs.map +1 -1
- package/dist/components/features/index.js +32 -24
- package/dist/components/index.cjs +452 -257
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +976 -781
- package/dist/components/index.js.map +1 -1
- package/dist/components/layout/page-layout.d.ts +1 -10
- package/dist/components/layout/page-layout.d.ts.map +1 -1
- package/dist/components/layout/title-block.d.ts +1 -17
- package/dist/components/layout/title-block.d.ts.map +1 -1
- package/dist/components/navigation/index.cjs +15 -7
- package/dist/components/navigation/index.cjs.map +1 -1
- package/dist/components/navigation/index.js +17 -9
- package/dist/components/onboarding-guides/index.cjs +36 -35
- package/dist/components/onboarding-guides/index.cjs.map +1 -1
- package/dist/components/onboarding-guides/index.js +14 -13
- package/dist/components/onboarding-guides/index.js.map +1 -1
- package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts +1 -1
- package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
- package/dist/components/related-content/index.cjs +16 -9
- package/dist/components/related-content/index.cjs.map +1 -1
- package/dist/components/related-content/index.js +15 -8
- package/dist/components/shared/dev-section/dev-section-page.d.ts +0 -9
- package/dist/components/shared/dev-section/dev-section-page.d.ts.map +1 -1
- package/dist/components/shared/dev-section/dev-section-view.d.ts.map +1 -1
- package/dist/components/shared/dev-section/index.d.ts +1 -1
- package/dist/components/shared/dev-section/index.d.ts.map +1 -1
- package/dist/components/shared/doc-search/use-doc-search.d.ts.map +1 -1
- package/dist/components/shared/legal-document/legal-document-page.d.ts.map +1 -1
- package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
- package/dist/components/tickets/index.cjs +112 -100
- package/dist/components/tickets/index.cjs.map +1 -1
- package/dist/components/tickets/index.js +32 -20
- package/dist/components/tickets/index.js.map +1 -1
- package/dist/components/ui/file-manager/index.cjs +52 -50
- package/dist/components/ui/file-manager/index.cjs.map +1 -1
- package/dist/components/ui/file-manager/index.js +6 -4
- package/dist/components/ui/file-manager/index.js.map +1 -1
- package/dist/components/ui/index.cjs +19 -13
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +0 -2
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +139 -133
- package/dist/components/ui/release-changelog-section.d.ts +2 -6
- package/dist/components/ui/release-changelog-section.d.ts.map +1 -1
- package/dist/components/ui/simple-markdown-renderer.d.ts +8 -2
- package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
- package/dist/contexts/chat-runtime-context.d.ts +0 -14
- package/dist/contexts/chat-runtime-context.d.ts.map +1 -1
- package/dist/contexts/index.cjs +3 -3
- package/dist/contexts/index.js +5 -5
- package/dist/embed-shims/index.cjs +3 -3
- package/dist/embed-shims/index.cjs.map +1 -1
- package/dist/embed-shims/index.js +4 -4
- package/dist/hooks/index.cjs +9 -4
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +11 -6
- package/dist/index.cjs +20 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +364 -358
- package/dist/types/doc-source.d.ts +1 -31
- package/dist/types/doc-source.d.ts.map +1 -1
- package/dist/utils/index.cjs +0 -4
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -4
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -7
- package/src/components/chat/embeddable-chat.tsx +1 -1
- package/src/components/docs/doc-viewer.tsx +19 -111
- package/src/components/docs/index.ts +0 -17
- package/src/components/docs/use-document-tree.ts +0 -21
- package/src/components/embeds/embed-iframe.tsx +9 -7
- package/src/components/embeds/index.ts +0 -30
- package/src/components/embeds/og-link-preview.tsx +13 -13
- package/src/components/layout/page-layout.tsx +1 -14
- package/src/components/layout/title-block.tsx +62 -40
- package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +3 -3
- package/src/components/shared/dev-section/dev-section-page.tsx +1 -9
- package/src/components/shared/dev-section/dev-section-view.tsx +9 -14
- package/src/components/shared/dev-section/index.ts +1 -1
- package/src/components/shared/doc-search/use-doc-search.ts +3 -7
- package/src/components/shared/legal-document/legal-document-page.tsx +2 -2
- package/src/components/shared/product-release/release-detail-page.tsx +4 -6
- package/src/components/ui/index.ts +0 -2
- package/src/components/ui/release-changelog-section.tsx +2 -7
- package/src/components/ui/simple-markdown-renderer.tsx +11 -7
- package/src/contexts/chat-runtime-context.tsx +0 -14
- package/src/types/doc-source.ts +1 -33
- package/src/utils/index.ts +0 -1
- package/dist/chunk-2QG57XOJ.js.map +0 -1
- package/dist/chunk-4PSQS3SW.cjs.map +0 -1
- package/dist/chunk-4TLE6VLU.js.map +0 -1
- package/dist/chunk-53FUMSZ5.cjs.map +0 -1
- package/dist/chunk-6C526VNN.cjs.map +0 -1
- package/dist/chunk-7OVGB2DQ.cjs.map +0 -1
- package/dist/chunk-F5OB2YAL.cjs +0 -144
- package/dist/chunk-F5OB2YAL.cjs.map +0 -1
- package/dist/chunk-FBWXMMRB.cjs +0 -2
- package/dist/chunk-FBWXMMRB.cjs.map +0 -1
- package/dist/chunk-FCDQNTDG.cjs.map +0 -1
- package/dist/chunk-FQOTC3UU.cjs.map +0 -1
- package/dist/chunk-GUTS7HGA.cjs.map +0 -1
- package/dist/chunk-GZ4C3XW6.js +0 -2
- package/dist/chunk-GZ4C3XW6.js.map +0 -1
- package/dist/chunk-IZ7JSBFP.js.map +0 -1
- package/dist/chunk-JALO4TAZ.js.map +0 -1
- package/dist/chunk-L6PSSIUQ.cjs.map +0 -1
- package/dist/chunk-PC746XCO.js.map +0 -1
- package/dist/chunk-PWQUAVA3.js.map +0 -1
- package/dist/chunk-SA2WPJVO.js +0 -144
- package/dist/chunk-SA2WPJVO.js.map +0 -1
- package/dist/chunk-UNVE2SDJ.cjs.map +0 -1
- package/dist/chunk-WMSTJAZT.cjs.map +0 -1
- package/dist/chunk-YBYI62OE.cjs.map +0 -1
- package/dist/components/case-studies/index.cjs +0 -126
- package/dist/components/case-studies/index.cjs.map +0 -1
- package/dist/components/case-studies/index.d.ts +0 -2
- package/dist/components/case-studies/index.d.ts.map +0 -1
- package/dist/components/case-studies/index.js +0 -126
- package/dist/components/case-studies/index.js.map +0 -1
- package/dist/components/case-studies/share-experience-section.d.ts +0 -48
- package/dist/components/case-studies/share-experience-section.d.ts.map +0 -1
- package/dist/components/docs/docs-hub-page.d.ts +0 -46
- package/dist/components/docs/docs-hub-page.d.ts.map +0 -1
- package/dist/components/docs/skeletons.d.ts +0 -32
- package/dist/components/docs/skeletons.d.ts.map +0 -1
- package/dist/components/docs/use-docs-resolve-link.d.ts +0 -20
- package/dist/components/docs/use-docs-resolve-link.d.ts.map +0 -1
- package/dist/components/embeds/embed-container.d.ts +0 -37
- package/dist/components/embeds/embed-container.d.ts.map +0 -1
- package/dist/components/embeds/file-download-card.d.ts +0 -18
- package/dist/components/embeds/file-download-card.d.ts.map +0 -1
- package/dist/components/embeds/linkedin-embed-client.d.ts +0 -8
- package/dist/components/embeds/linkedin-embed-client.d.ts.map +0 -1
- package/dist/components/embeds/markdown-image.d.ts +0 -5
- package/dist/components/embeds/markdown-image.d.ts.map +0 -1
- package/dist/components/embeds/reddit-embed-client.d.ts +0 -7
- package/dist/components/embeds/reddit-embed-client.d.ts.map +0 -1
- package/dist/components/embeds/rich-markdown-runtime.d.ts +0 -46
- package/dist/components/embeds/rich-markdown-runtime.d.ts.map +0 -1
- package/dist/components/embeds/twitter-embed-client.d.ts +0 -8
- package/dist/components/embeds/twitter-embed-client.d.ts.map +0 -1
- package/dist/components/layout/page-header.d.ts +0 -78
- package/dist/components/layout/page-header.d.ts.map +0 -1
- package/dist/components/layout/page-with-header.d.ts +0 -67
- package/dist/components/layout/page-with-header.d.ts.map +0 -1
- package/dist/components/ui/rich-markdown-renderer.d.ts +0 -34
- package/dist/components/ui/rich-markdown-renderer.d.ts.map +0 -1
- package/dist/utils/page-header-constants.d.ts +0 -15
- package/dist/utils/page-header-constants.d.ts.map +0 -1
- package/dist/utils/social-embed-cache.d.ts +0 -29
- package/dist/utils/social-embed-cache.d.ts.map +0 -1
- package/src/components/case-studies/index.ts +0 -4
- package/src/components/case-studies/share-experience-section.tsx +0 -185
- package/src/components/docs/docs-hub-page.tsx +0 -149
- package/src/components/docs/skeletons.tsx +0 -138
- package/src/components/docs/use-docs-resolve-link.ts +0 -52
- package/src/components/embeds/embed-container.tsx +0 -80
- package/src/components/embeds/file-download-card.tsx +0 -54
- package/src/components/embeds/linkedin-embed-client.tsx +0 -100
- package/src/components/embeds/markdown-image.tsx +0 -88
- package/src/components/embeds/reddit-embed-client.tsx +0 -550
- package/src/components/embeds/rich-markdown-runtime.tsx +0 -79
- package/src/components/embeds/twitter-embed-client.tsx +0 -308
- package/src/components/layout/page-header.tsx +0 -182
- package/src/components/layout/page-with-header.tsx +0 -110
- package/src/components/ui/rich-markdown-renderer.tsx +0 -1203
- package/src/utils/page-header-constants.ts +0 -15
- package/src/utils/social-embed-cache.ts +0 -391
- /package/dist/{chunk-PI4WSYQV.js.map → chunk-3ZXUQQL4.js.map} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flamingo-stack/openframe-frontend-core",
|
|
3
|
-
"version": "0.0.296
|
|
3
|
+
"version": "0.0.296",
|
|
4
4
|
"description": "Shared design system and components for all Flamingo platforms",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -78,12 +78,6 @@
|
|
|
78
78
|
"require": "./dist/components/contact/index.cjs",
|
|
79
79
|
"default": "./dist/components/contact/index.js"
|
|
80
80
|
},
|
|
81
|
-
"./components/case-studies": {
|
|
82
|
-
"types": "./dist/components/case-studies/index.d.ts",
|
|
83
|
-
"import": "./dist/components/case-studies/index.js",
|
|
84
|
-
"require": "./dist/components/case-studies/index.cjs",
|
|
85
|
-
"default": "./dist/components/case-studies/index.js"
|
|
86
|
-
},
|
|
87
81
|
"./schemas/contact-schema": {
|
|
88
82
|
"types": "./dist/schemas/contact-schema.d.ts",
|
|
89
83
|
"import": "./dist/schemas/contact-schema.js",
|
|
@@ -1127,7 +1127,7 @@ function EmbeddableChatInner({
|
|
|
1127
1127
|
// falls back to the platform default here) — instead it sets a truthy baseRoute +
|
|
1128
1128
|
// `chipBasePlatform` so doc chips with no externalUrl resolve cross-platform to that
|
|
1129
1129
|
// platform's public knowledge hub (`getBaseUrl(chipBasePlatform)/knowledge-base/…`),
|
|
1130
|
-
// exactly like the hub's openframe config (baseRoute:'/', chipBasePlatform:'
|
|
1130
|
+
// exactly like the hub's openframe config (baseRoute:'/', chipBasePlatform:'flamingo').
|
|
1131
1131
|
const resolvedBaseRoute =
|
|
1132
1132
|
baseRoute || (source === 'flamingo' ? '/knowledge-base' : '/data-room')
|
|
1133
1133
|
|
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useMemo } from "react"
|
|
4
4
|
import { MultiLevelNavigation, MobileNavigationDropdown } from "../navigation/multi-level-navigation"
|
|
5
|
-
import {
|
|
6
|
-
import { PageLayout } from "../layout/page-layout"
|
|
7
|
-
import { PageShell } from "../layout/article-detail-layout"
|
|
8
|
-
import { useRouter } from "../../embed-shims/next-navigation"
|
|
5
|
+
import { PageHeading } from "../layout/page-heading"
|
|
9
6
|
import { PersistentSidebar, PersistentMobileDropdown } from "../persistent-filter-controls"
|
|
10
7
|
import { CategorySidebarSkeleton } from "../loading/page-layout-skeleton"
|
|
11
8
|
import { DocSearchBar, useDocSearch } from "../shared/doc-search"
|
|
@@ -15,7 +12,6 @@ import { useScrollSpy } from "./use-scroll-spy"
|
|
|
15
12
|
import { useDocNavigation } from "./doc-navigation-context"
|
|
16
13
|
import { findDocNodeByPath } from "../../utils/doc-tree-nav"
|
|
17
14
|
import type { DocContent, DocNode, DocRenderHandlers, DocSourceId } from "../../types/doc-source"
|
|
18
|
-
import { useDocsResolveLink } from "./use-docs-resolve-link"
|
|
19
15
|
|
|
20
16
|
/** Color tokens for the doc-viewer chrome. Hub-side `DocViewer` callers share
|
|
21
17
|
* this constant; no need to override per source — the palette is intentionally
|
|
@@ -34,7 +30,7 @@ export const DEFAULT_DOC_VIEWER_PALETTE = {
|
|
|
34
30
|
export interface DocViewerProps {
|
|
35
31
|
/**
|
|
36
32
|
* Registry source id (`'openframe-docs'`, `'data-room-docs'`, …). Flowed through
|
|
37
|
-
* `renderContent`'s handlers for `/api/
|
|
33
|
+
* `renderContent`'s handlers for `/api/resolve-link` POSTs.
|
|
38
34
|
*/
|
|
39
35
|
sourceId: DocSourceId
|
|
40
36
|
|
|
@@ -59,24 +55,7 @@ export interface DocViewerProps {
|
|
|
59
55
|
*/
|
|
60
56
|
chatSource: string
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
* so the doc-viewer chrome matches every other lib page
|
|
64
|
-
* (DevSectionPage / LegalDocumentPage / OnboardingGuideDetailView)
|
|
65
|
-
* pixel-for-pixel. ReactNode is intentionally not supported here —
|
|
66
|
-
* every consumer renders the same typography. */
|
|
67
|
-
title?: string
|
|
68
|
-
/** Optional icon rendered inline before the title text — same slot
|
|
69
|
-
* `<DevSectionView>`'s hero uses (Map for Roadmap, Rocket for Releases,
|
|
70
|
-
* etc.). Pass a pre-rendered React element styled with
|
|
71
|
-
* `SECTION_HERO_ICON_CLASS` (`h-10 w-10 text-ods-accent`) for visual
|
|
72
|
-
* parity with other lib pages. */
|
|
73
|
-
titleIcon?: React.ReactNode
|
|
74
|
-
/** Subtitle (h6, secondary text) rendered beneath the title. */
|
|
75
|
-
subtitle?: string
|
|
76
|
-
/** Render a yellow accent dot (`.`) after the title — same flag as
|
|
77
|
-
* the hub's legacy `<AdminPageHeader accentDot>` so the docs-hub
|
|
78
|
-
* surface keeps its existing accent styling after the migration. */
|
|
79
|
-
accentDot?: boolean
|
|
58
|
+
title: string | React.ReactNode
|
|
80
59
|
/** Override the default ODS palette. Optional — most callers should omit. */
|
|
81
60
|
colorPalette?: typeof DEFAULT_DOC_VIEWER_PALETTE
|
|
82
61
|
className?: string
|
|
@@ -95,17 +74,6 @@ export interface DocViewerProps {
|
|
|
95
74
|
structureEndpoint?: string
|
|
96
75
|
/** Same shape as `structureEndpoint`. Defaults to `/api/docs/sources/${sourceId}/content`. */
|
|
97
76
|
contentEndpoint?: string
|
|
98
|
-
/** RAG-search endpoint that backs the in-source search bar (when `showAIChat`
|
|
99
|
-
* is on). Defaults to `/api/docs/search`. Override for proxy-prefix embeds —
|
|
100
|
-
* same injectability pattern as `structureEndpoint` / `contentEndpoint`. */
|
|
101
|
-
searchEndpoint?: string
|
|
102
|
-
/** POST internal-link resolver. The viewer threads an async `onResolveLink`
|
|
103
|
-
* into `renderContent`'s `handlers` that posts `{ link, currentPath, source }`
|
|
104
|
-
* here. Defaults to `/api/docs/resolve-link`. Override for proxy-prefix embeds —
|
|
105
|
-
* same injectability pattern as `structureEndpoint` / `contentEndpoint` /
|
|
106
|
-
* `searchEndpoint`, with `ChatRuntime.endpoints.docsResolveLinkUrl` as a
|
|
107
|
-
* runtime fallback (prop → runtime → default). */
|
|
108
|
-
resolveLinkEndpoint?: string
|
|
109
77
|
/** Base route path for URL navigation. */
|
|
110
78
|
baseRoute: string
|
|
111
79
|
|
|
@@ -117,13 +85,6 @@ export interface DocViewerProps {
|
|
|
117
85
|
|
|
118
86
|
/** Folder-index filename (default `'README.md'`). */
|
|
119
87
|
folderIndexFile?: string
|
|
120
|
-
|
|
121
|
-
/** Back-button shown above the title. Mirrors `<DevSectionPage>` /
|
|
122
|
-
* `<HelpCenterList>` / `<LegalDocumentPage>` so every embeddable surface
|
|
123
|
-
* shares the same chrome. Defaults to `{ label: 'Back to home', href: '/' }`.
|
|
124
|
-
* Pass `false` to hide; pass `{ href: '/docs' }` etc. when the embed's
|
|
125
|
-
* home isn't `/`. */
|
|
126
|
-
backButton?: { label?: string; href?: string } | false
|
|
127
88
|
}
|
|
128
89
|
|
|
129
90
|
export function DocViewer(props: DocViewerProps) {
|
|
@@ -136,22 +97,16 @@ function DocViewerContent({
|
|
|
136
97
|
renderSkeleton,
|
|
137
98
|
chatSource,
|
|
138
99
|
title,
|
|
139
|
-
titleIcon,
|
|
140
|
-
subtitle,
|
|
141
|
-
accentDot,
|
|
142
100
|
colorPalette = DEFAULT_DOC_VIEWER_PALETTE,
|
|
143
101
|
className = "",
|
|
144
102
|
docPath,
|
|
145
103
|
sidebarLabel = "DOCUMENTATION",
|
|
146
104
|
structureEndpoint,
|
|
147
105
|
contentEndpoint,
|
|
148
|
-
searchEndpoint,
|
|
149
|
-
resolveLinkEndpoint,
|
|
150
106
|
baseRoute,
|
|
151
107
|
emptyStateText,
|
|
152
108
|
showAIChat = false,
|
|
153
109
|
folderIndexFile,
|
|
154
|
-
backButton,
|
|
155
110
|
}: DocViewerProps) {
|
|
156
111
|
// Default endpoints derived from sourceId. Hub callers omit the props in 99%
|
|
157
112
|
// of cases; the override is for embed contexts where the doc-viewer sits
|
|
@@ -160,13 +115,6 @@ function DocViewerContent({
|
|
|
160
115
|
structureEndpoint ?? `/api/docs/sources/${sourceId}/structure`
|
|
161
116
|
const resolvedContentEndpoint =
|
|
162
117
|
contentEndpoint ?? `/api/docs/sources/${sourceId}/content`
|
|
163
|
-
// Resolve-link endpoint chain (prop → ChatRuntime.endpoints → hub default)
|
|
164
|
-
// + the full fetch + JSON-parse pipeline live in `useDocsResolveLink`.
|
|
165
|
-
// Keeping it factored out as a proper hook makes the contract reusable
|
|
166
|
-
// by any embedder rendering doc content outside `<DocViewer>` (custom
|
|
167
|
-
// markdown renderers, link-resolver previews, etc.) and keeps this
|
|
168
|
-
// component focused on layout + state.
|
|
169
|
-
const resolveLink = useDocsResolveLink(sourceId, resolveLinkEndpoint)
|
|
170
118
|
const {
|
|
171
119
|
structure,
|
|
172
120
|
selectedPath,
|
|
@@ -191,23 +139,9 @@ function DocViewerContent({
|
|
|
191
139
|
const { activeSection, handleSectionClick } = useScrollSpy(content?.sections)
|
|
192
140
|
|
|
193
141
|
const docNav = useDocNavigation()
|
|
194
|
-
|
|
195
|
-
// Back-button config — mirrors `<DevSectionPage>` so the docs surface
|
|
196
|
-
// matches every other embeddable page's chrome. Default target is `/`
|
|
197
|
-
// (the embed's home); pass `backButton: false` to hide entirely, or
|
|
198
|
-
// override the href when the embed's home isn't `/`.
|
|
199
|
-
const router = useRouter()
|
|
200
|
-
const backCfg =
|
|
201
|
-
backButton === false
|
|
202
|
-
? null
|
|
203
|
-
: {
|
|
204
|
-
label: backButton?.label ?? 'Back to home',
|
|
205
|
-
onClick: () => router.push(backButton?.href ?? '/'),
|
|
206
|
-
}
|
|
207
142
|
const docSearch = useDocSearch({
|
|
208
143
|
source: chatSource,
|
|
209
144
|
baseRoute,
|
|
210
|
-
searchEndpoint,
|
|
211
145
|
onNavigate: (path) => navigateToDoc(path, { fromInternalLink: true }),
|
|
212
146
|
onInPageSwap: (path) => docNav.navigate(path),
|
|
213
147
|
})
|
|
@@ -218,9 +152,8 @@ function DocViewerContent({
|
|
|
218
152
|
onInternalLinkClick: navigateToDoc,
|
|
219
153
|
currentPath: selectedPath,
|
|
220
154
|
sourceId,
|
|
221
|
-
onResolveLink: resolveLink,
|
|
222
155
|
})
|
|
223
|
-
}, [content, selectedPath, renderContent, navigateToDoc, sourceId
|
|
156
|
+
}, [content, selectedPath, renderContent, navigateToDoc, sourceId])
|
|
224
157
|
|
|
225
158
|
// Selected node's documentType drives:
|
|
226
159
|
// - which skeleton the caller renders during fetch (markdown vs embed)
|
|
@@ -259,32 +192,15 @@ function DocViewerContent({
|
|
|
259
192
|
const resolvedEmptyText = emptyStateText || defaultEmptyText
|
|
260
193
|
|
|
261
194
|
return (
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
//
|
|
272
|
-
// `colorPalette` / `className` / `bgStyle` flow through PageShell's
|
|
273
|
-
// contentClassName + an inner style-passthrough wrapper so legacy
|
|
274
|
-
// palette overrides still apply (none in the codebase today; the API
|
|
275
|
-
// surface is preserved).
|
|
276
|
-
<PageShell contentClassName={`${bgClass} ${className}`}>
|
|
277
|
-
<div style={{ ...bgStyle, ...containerBgStyle }}>
|
|
278
|
-
<PageLayout backButton={backCfg ?? undefined}>
|
|
279
|
-
<div className="w-full flex flex-col gap-10">
|
|
280
|
-
<PageHeader
|
|
281
|
-
title={title}
|
|
282
|
-
titleIcon={titleIcon}
|
|
283
|
-
subtitle={subtitle}
|
|
284
|
-
accentDot={accentDot}
|
|
285
|
-
noTopPadding
|
|
286
|
-
noBottomMargin
|
|
287
|
-
/>
|
|
195
|
+
<section className={`${bgClass} ${className}`} style={bgStyle}>
|
|
196
|
+
<div
|
|
197
|
+
className="max-w-[1920px] px-6 md:px-20 py-6 md:py-10 mx-auto"
|
|
198
|
+
style={containerBgStyle}
|
|
199
|
+
>
|
|
200
|
+
<div className="flex flex-col gap-6">
|
|
201
|
+
<div className="flex flex-col gap-4">
|
|
202
|
+
{typeof title === 'string' ? <PageHeading>{title}</PageHeading> : title}
|
|
203
|
+
</div>
|
|
288
204
|
|
|
289
205
|
{showAIChat && (
|
|
290
206
|
<DocSearchBar
|
|
@@ -355,16 +271,9 @@ function DocViewerContent({
|
|
|
355
271
|
<div className="flex-1 min-w-0 w-full">
|
|
356
272
|
<div
|
|
357
273
|
className={`grid grid-cols-1 ${
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
// `isMarkdownContent` also suppresses the section-skeleton
|
|
362
|
-
// bars during embed loads — the user-reported "skeleton
|
|
363
|
-
// shouldn't be on file pages" bug.
|
|
364
|
-
isMarkdownContent &&
|
|
365
|
-
((showStickyNav && stickyNavSections.length > 0) ||
|
|
366
|
-
isLoadingContent ||
|
|
367
|
-
isLoadingStructure)
|
|
274
|
+
(showStickyNav && stickyNavSections.length > 0) ||
|
|
275
|
+
isLoadingContent ||
|
|
276
|
+
isLoadingStructure
|
|
368
277
|
? 'lg:grid-cols-[1fr_280px]'
|
|
369
278
|
: ''
|
|
370
279
|
} gap-8`}
|
|
@@ -383,7 +292,7 @@ function DocViewerContent({
|
|
|
383
292
|
</article>
|
|
384
293
|
</div>
|
|
385
294
|
|
|
386
|
-
{
|
|
295
|
+
{(isLoadingContent || isLoadingStructure) && (
|
|
387
296
|
<div className="hidden lg:block">
|
|
388
297
|
<div className="sticky top-24">
|
|
389
298
|
<div className="h-[14px] w-28 bg-ods-border rounded animate-pulse mb-5" />
|
|
@@ -429,9 +338,8 @@ function DocViewerContent({
|
|
|
429
338
|
</div>
|
|
430
339
|
</div>
|
|
431
340
|
)}
|
|
432
|
-
|
|
433
|
-
</PageLayout>
|
|
341
|
+
</div>
|
|
434
342
|
</div>
|
|
435
|
-
</
|
|
343
|
+
</section>
|
|
436
344
|
)
|
|
437
345
|
}
|
|
@@ -3,11 +3,6 @@
|
|
|
3
3
|
export { DocViewer } from './doc-viewer'
|
|
4
4
|
export type { DocViewerProps } from './doc-viewer'
|
|
5
5
|
|
|
6
|
-
export { DocsHubPage } from './docs-hub-page'
|
|
7
|
-
export type { DocsHubPageProps, DocumentTypeRenderers } from './docs-hub-page'
|
|
8
|
-
|
|
9
|
-
export { MarkdownSkeleton, EmbedSkeleton } from './skeletons'
|
|
10
|
-
|
|
11
6
|
export { useDocumentTree } from './use-document-tree'
|
|
12
7
|
export type { UseDocumentTreeConfig } from './use-document-tree'
|
|
13
8
|
|
|
@@ -15,15 +10,3 @@ export { useScrollSpy } from './use-scroll-spy'
|
|
|
15
10
|
|
|
16
11
|
export { DocNavigationProvider, useDocNavigation } from './doc-navigation-context'
|
|
17
12
|
export type { DocNavigator } from './doc-navigation-context'
|
|
18
|
-
|
|
19
|
-
// Re-export the doc-source types embedders need to implement the
|
|
20
|
-
// `/api/docs/sources/[sourceId]/{structure,content}` + `/api/docs/resolve-link`
|
|
21
|
-
// API contract.
|
|
22
|
-
export type {
|
|
23
|
-
DocNode,
|
|
24
|
-
DocContent,
|
|
25
|
-
DocRenderHandlers,
|
|
26
|
-
DocSourceId,
|
|
27
|
-
DocumentType,
|
|
28
|
-
ResolveLinkResult,
|
|
29
|
-
} from '../../types/doc-source'
|
|
@@ -102,27 +102,6 @@ export function useDocumentTree(
|
|
|
102
102
|
return () => window.removeEventListener('popstate', handlePopState)
|
|
103
103
|
}, [normalizedBaseRoute, folderIndexFile])
|
|
104
104
|
|
|
105
|
-
// External-URL → state sync. The popstate listener above catches browser
|
|
106
|
-
// back/forward, but client-side routers (react-router, Next App Router…)
|
|
107
|
-
// change the URL via `history.pushState` which does NOT fire popstate.
|
|
108
|
-
// The host re-renders the viewer with a new `initialPath` prop instead, so
|
|
109
|
-
// we mirror the popstate logic here against the (memoized) `cleanInitialPath`.
|
|
110
|
-
// Without this, a chat-card click that soft-navigates via react-router
|
|
111
|
-
// updates the URL but the viewer stays on the previously-selected doc.
|
|
112
|
-
useEffect(() => {
|
|
113
|
-
if (cleanInitialPath === selectedPathRef.current) return
|
|
114
|
-
setSelectedPath(cleanInitialPath)
|
|
115
|
-
if (cleanInitialPath) {
|
|
116
|
-
const parentPath = cleanInitialPath.includes('/')
|
|
117
|
-
? cleanInitialPath.substring(0, cleanInitialPath.lastIndexOf('/'))
|
|
118
|
-
: cleanInitialPath
|
|
119
|
-
setExpandedNodes(new Set(getDocAncestorNodeIds(parentPath)))
|
|
120
|
-
}
|
|
121
|
-
// Match popstate's scroll-to-content delay; the targeted content fetch
|
|
122
|
-
// dispatched by the selectedPath effect lands before this fires.
|
|
123
|
-
setTimeout(scrollToContent, 150)
|
|
124
|
-
}, [cleanInitialPath])
|
|
125
|
-
|
|
126
105
|
useEffect(() => {
|
|
127
106
|
if (!isInitialized) {
|
|
128
107
|
// Kick off the speculative content fetch IN PARALLEL with the structure
|
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useState, useCallback, useRef, useEffect } from 'react'
|
|
4
4
|
|
|
5
|
-
/** Loading skeleton for iframe embeds —
|
|
6
|
-
* Uses `bg-ods-card` (visible token) rather than `bg-ods-skeleton`
|
|
7
|
-
* which resolves to transparent in this build (the same gotcha
|
|
8
|
-
* documented in `chat-message-row.tsx`'s skeleton). No fake inner
|
|
9
|
-
* placeholder cruft — a real loading iframe shows a blank rectangle. */
|
|
5
|
+
/** Loading skeleton for iframe embeds — matches project skeleton pattern */
|
|
10
6
|
function EmbedLoadingSkeleton({ height }: { height?: string }) {
|
|
11
7
|
return (
|
|
12
8
|
<div
|
|
13
|
-
className="w-full rounded-lg border border-ods-border overflow-hidden bg-ods-
|
|
9
|
+
className="w-full rounded-lg border border-ods-border overflow-hidden bg-ods-skeleton animate-pulse"
|
|
14
10
|
style={{ height: height || 'calc(100vh - 250px)' }}
|
|
15
|
-
|
|
11
|
+
>
|
|
12
|
+
<div className="flex flex-col items-center justify-center h-full gap-4">
|
|
13
|
+
<div className="w-12 h-12 rounded-lg bg-ods-card" />
|
|
14
|
+
<div className="h-4 w-48 rounded bg-ods-card" />
|
|
15
|
+
<div className="h-3 w-32 rounded bg-ods-card" />
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
16
18
|
)
|
|
17
19
|
}
|
|
18
20
|
|
|
@@ -16,33 +16,3 @@ export type {
|
|
|
16
16
|
OGData,
|
|
17
17
|
BuildPlaceholderUrl,
|
|
18
18
|
} from './og-link-preview'
|
|
19
|
-
|
|
20
|
-
export { FileDownloadCard } from './file-download-card'
|
|
21
|
-
export type { FileDownloadCardProps } from './file-download-card'
|
|
22
|
-
|
|
23
|
-
// Satellite embeds wired into `<RichMarkdownRenderer>` (`components/ui`).
|
|
24
|
-
// Exported individually so embedders can compose them outside the renderer
|
|
25
|
-
// (e.g. a release page that wants a single reddit card without parsing
|
|
26
|
-
// markdown). The runtime knobs (proxy endpoints, image transformer) are
|
|
27
|
-
// shared via `RichMarkdownRuntimeProvider` — call sites that mount a
|
|
28
|
-
// satellite directly should wrap with the provider when they need
|
|
29
|
-
// overrides; otherwise the defaults match the hub's existing endpoints.
|
|
30
|
-
export { RedditEmbedClient } from './reddit-embed-client'
|
|
31
|
-
export { TwitterEmbedClient } from './twitter-embed-client'
|
|
32
|
-
export { LinkedInEmbedClient } from './linkedin-embed-client'
|
|
33
|
-
export { MarkdownImage } from './markdown-image'
|
|
34
|
-
export {
|
|
35
|
-
EmbedContainer,
|
|
36
|
-
YouTubeContainer,
|
|
37
|
-
TwitterContainer,
|
|
38
|
-
RedditContainer,
|
|
39
|
-
LinkPreviewContainer,
|
|
40
|
-
LinkedInContainer,
|
|
41
|
-
EMBED_SIZES,
|
|
42
|
-
type EmbedSize,
|
|
43
|
-
} from './embed-container'
|
|
44
|
-
export {
|
|
45
|
-
RichMarkdownRuntimeProvider,
|
|
46
|
-
useRichMarkdownRuntime,
|
|
47
|
-
type RichMarkdownRuntime,
|
|
48
|
-
} from './rich-markdown-runtime'
|
|
@@ -262,34 +262,34 @@ export const OGLinkPreview: React.FC<OGLinkPreviewProps> = ({
|
|
|
262
262
|
const renderSkeleton = () => isCompact ? (
|
|
263
263
|
<div className="my-4">
|
|
264
264
|
<div className="flex flex-row border border-ods-border rounded-lg overflow-hidden bg-ods-card h-[120px]">
|
|
265
|
-
<div className="w-[200px] h-full flex-shrink-0 bg-ods-
|
|
265
|
+
<div className="w-[200px] h-full flex-shrink-0 bg-ods-skeleton animate-pulse" />
|
|
266
266
|
<div className="flex-1 p-3 flex flex-col justify-center">
|
|
267
|
-
<div className="bg-ods-
|
|
268
|
-
<div className="bg-ods-
|
|
269
|
-
<div className="bg-ods-
|
|
270
|
-
<div className="bg-ods-
|
|
267
|
+
<div className="bg-ods-skeleton rounded animate-pulse h-4 w-3/4 mb-2" />
|
|
268
|
+
<div className="bg-ods-skeleton rounded animate-pulse h-3 w-full mb-1" />
|
|
269
|
+
<div className="bg-ods-skeleton rounded animate-pulse h-3 w-2/3 mb-2" />
|
|
270
|
+
<div className="bg-ods-skeleton rounded animate-pulse h-3 w-1/3" />
|
|
271
271
|
</div>
|
|
272
272
|
</div>
|
|
273
273
|
</div>
|
|
274
274
|
) : (
|
|
275
275
|
<div className="my-6">
|
|
276
276
|
<div className="block border border-ods-border rounded-lg overflow-hidden bg-ods-card">
|
|
277
|
-
<div className="aspect-video w-full bg-ods-
|
|
277
|
+
<div className="aspect-video w-full bg-ods-skeleton overflow-hidden relative animate-pulse" />
|
|
278
278
|
<div className="p-4">
|
|
279
279
|
<div className="flex items-start gap-3">
|
|
280
|
-
<div className="w-6 h-6 bg-ods-
|
|
280
|
+
<div className="w-6 h-6 bg-ods-skeleton rounded flex-shrink-0 mt-0.5 animate-pulse" />
|
|
281
281
|
<div className="flex-1 min-w-0">
|
|
282
282
|
<div className="h-[2.5rem] leading-[1.25rem] mb-2 overflow-hidden">
|
|
283
|
-
<div className="bg-ods-
|
|
284
|
-
<div className="bg-ods-
|
|
283
|
+
<div className="bg-ods-skeleton rounded animate-pulse" style={{ height: '1.25rem', marginBottom: '0.25rem' }} />
|
|
284
|
+
<div className="bg-ods-skeleton rounded animate-pulse w-3/4" style={{ height: '1.25rem' }} />
|
|
285
285
|
</div>
|
|
286
286
|
<div className="h-[2.5rem] leading-[1.25rem] mb-2 overflow-hidden">
|
|
287
|
-
<div className="bg-ods-
|
|
288
|
-
<div className="bg-ods-
|
|
287
|
+
<div className="bg-ods-skeleton rounded animate-pulse" style={{ height: '1.25rem', marginBottom: '0.25rem' }} />
|
|
288
|
+
<div className="bg-ods-skeleton rounded animate-pulse w-5/6" style={{ height: '1.25rem' }} />
|
|
289
289
|
</div>
|
|
290
290
|
<div className="flex items-center gap-2">
|
|
291
|
-
<div className="bg-ods-
|
|
292
|
-
<div className="bg-ods-
|
|
291
|
+
<div className="bg-ods-skeleton rounded animate-pulse" style={{ height: '0.75rem', width: '6rem' }} />
|
|
292
|
+
<div className="bg-ods-skeleton rounded animate-pulse" style={{ height: '0.75rem', width: '5rem' }} />
|
|
293
293
|
</div>
|
|
294
294
|
</div>
|
|
295
295
|
</div>
|
|
@@ -10,11 +10,6 @@ export interface PageLayoutProps {
|
|
|
10
10
|
children: React.ReactNode
|
|
11
11
|
title?: string
|
|
12
12
|
subtitle?: string
|
|
13
|
-
/** Inline icon rendered before the title text — forwarded to
|
|
14
|
-
* TitleBlock/PageHeader. Same shape as DevSectionPage's hero icon. */
|
|
15
|
-
titleIcon?: React.ReactNode
|
|
16
|
-
/** Yellow accent dot after the title — forwarded to TitleBlock/PageHeader. */
|
|
17
|
-
accentDot?: boolean
|
|
18
13
|
image?: { src: string; alt?: string }
|
|
19
14
|
backButton?: { label?: string; onClick: () => void }
|
|
20
15
|
actions?: PageActionButton[]
|
|
@@ -38,8 +33,6 @@ export function PageLayout({
|
|
|
38
33
|
children,
|
|
39
34
|
title,
|
|
40
35
|
subtitle,
|
|
41
|
-
titleIcon,
|
|
42
|
-
accentDot,
|
|
43
36
|
image,
|
|
44
37
|
backButton,
|
|
45
38
|
actions,
|
|
@@ -53,16 +46,14 @@ export function PageLayout({
|
|
|
53
46
|
}: PageLayoutProps) {
|
|
54
47
|
const hasActions = actions && actions.length > 0
|
|
55
48
|
const needsBottomPadding = hasActions && actionsVariant === 'primary-buttons'
|
|
56
|
-
const hasHeader = showHeader && (title || subtitle ||
|
|
49
|
+
const hasHeader = showHeader && (title || subtitle || image || backButton || hasActions || selector)
|
|
57
50
|
|
|
58
51
|
return (
|
|
59
52
|
<div className={cn('flex flex-col w-full', className)}>
|
|
60
53
|
{hasHeader && (
|
|
61
54
|
<TitleBlock
|
|
62
55
|
title={title}
|
|
63
|
-
titleIcon={titleIcon}
|
|
64
56
|
subtitle={subtitle}
|
|
65
|
-
accentDot={accentDot}
|
|
66
57
|
image={image}
|
|
67
58
|
backButton={backButton}
|
|
68
59
|
actions={actions}
|
|
@@ -83,8 +74,4 @@ export function PageLayout({
|
|
|
83
74
|
export type { PageActionButton } from '../ui/page-actions'
|
|
84
75
|
export { TitleBlock } from './title-block'
|
|
85
76
|
export type { TitleBlockProps } from './title-block'
|
|
86
|
-
export { PageHeader } from './page-header'
|
|
87
|
-
export type { PageHeaderProps } from './page-header'
|
|
88
|
-
export { PageWithHeader } from './page-with-header'
|
|
89
|
-
export type { PageWithHeaderProps } from './page-with-header'
|
|
90
77
|
export default PageLayout
|
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import React from 'react'
|
|
4
|
+
import { cn } from '../../utils/cn'
|
|
4
5
|
import type { ActionsMenuGroup } from '../ui/actions-menu'
|
|
6
|
+
import { EntityImage } from '../ui/entity-image'
|
|
5
7
|
import { PageActions, type PageActionButton } from '../ui/page-actions'
|
|
6
|
-
import {
|
|
8
|
+
import { BackButton } from './back-button'
|
|
7
9
|
|
|
8
|
-
/**
|
|
9
|
-
* `<TitleBlock>` — thin adapter over `<PageHeader>` that turns the
|
|
10
|
-
* `actions: PageActionButton[]` / `menuActions` / `selector` API into
|
|
11
|
-
* a `ReactNode` slot that PageHeader can render. Kept as a separate
|
|
12
|
-
* component for backwards compatibility (`PageLayout` consumes it,
|
|
13
|
-
* external callers may too) — all the DOM/CSS lives in PageHeader.
|
|
14
|
-
*
|
|
15
|
-
* If a new consumer doesn't need the `PageActions` wiring, prefer
|
|
16
|
-
* `<PageHeader>` directly.
|
|
17
|
-
*/
|
|
18
10
|
export interface TitleBlockProps {
|
|
19
11
|
title?: string
|
|
20
12
|
subtitle?: string
|
|
21
|
-
/** Inline icon rendered before the title text (e.g. HelpCircle on /faqs,
|
|
22
|
-
* BookOpen on /knowledge-base, Map on /roadmap). Forwarded verbatim to
|
|
23
|
-
* `<PageHeader>`. */
|
|
24
|
-
titleIcon?: React.ReactNode
|
|
25
|
-
/** Yellow accent dot after the title — same flag as PageHeader. */
|
|
26
|
-
accentDot?: boolean
|
|
27
13
|
image?: { src: string; alt?: string }
|
|
28
14
|
backButton?: { label?: string; onClick: () => void }
|
|
29
15
|
actions?: PageActionButton[]
|
|
@@ -43,8 +29,6 @@ export interface TitleBlockProps {
|
|
|
43
29
|
export function TitleBlock({
|
|
44
30
|
title,
|
|
45
31
|
subtitle,
|
|
46
|
-
titleIcon,
|
|
47
|
-
accentDot,
|
|
48
32
|
image,
|
|
49
33
|
backButton,
|
|
50
34
|
actions,
|
|
@@ -56,29 +40,67 @@ export function TitleBlock({
|
|
|
56
40
|
}: TitleBlockProps) {
|
|
57
41
|
const hasActions = actions && actions.length > 0
|
|
58
42
|
const hasMenuActions = !!menuActions && menuActions.some(g => g.items.length > 0)
|
|
59
|
-
const hasActionsSlot = hasActions || hasMenuActions || !!selector
|
|
60
|
-
|
|
61
|
-
const actionsNode = hasActionsSlot ? (
|
|
62
|
-
<PageActions
|
|
63
|
-
variant={actionsVariant}
|
|
64
|
-
actions={actions ?? []}
|
|
65
|
-
menuActions={menuActions}
|
|
66
|
-
selector={selector}
|
|
67
|
-
/>
|
|
68
|
-
) : undefined
|
|
69
43
|
|
|
70
44
|
return (
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
45
|
+
<div
|
|
46
|
+
className={cn(
|
|
47
|
+
'flex items-end justify-between gap-[var(--spacing-system-m)]',
|
|
48
|
+
'md:flex-col md:items-start md:justify-start lg:flex-row lg:items-end lg:justify-between',
|
|
49
|
+
'pt-[var(--spacing-system-l)]',
|
|
50
|
+
variant === 'card'
|
|
51
|
+
? cn(
|
|
52
|
+
'bg-ods-card border-b border-ods-border',
|
|
53
|
+
'px-[var(--spacing-system-l)] pb-[var(--spacing-system-l)]',
|
|
54
|
+
'md:bg-transparent md:border-b-0',
|
|
55
|
+
'md:px-0 md:pb-0',
|
|
56
|
+
'md:mb-[var(--spacing-system-l)]',
|
|
57
|
+
)
|
|
58
|
+
: 'mb-[var(--spacing-system-l)]',
|
|
59
|
+
className,
|
|
60
|
+
)}
|
|
61
|
+
>
|
|
62
|
+
<div className="flex flex-col gap-[var(--spacing-system-xs)] flex-1 min-w-0">
|
|
63
|
+
{backButton && (
|
|
64
|
+
<BackButton
|
|
65
|
+
onClick={backButton.onClick}
|
|
66
|
+
label={backButton.label}
|
|
67
|
+
className="hidden md:inline-flex"
|
|
68
|
+
/>
|
|
69
|
+
)}
|
|
70
|
+
{(image || subtitle) ? (
|
|
71
|
+
<div className="flex items-center gap-[var(--spacing-system-m)] min-w-0 w-full">
|
|
72
|
+
{image && (
|
|
73
|
+
<EntityImage
|
|
74
|
+
src={image.src}
|
|
75
|
+
alt={image.alt}
|
|
76
|
+
fallbackText={image.alt || title}
|
|
77
|
+
/>
|
|
78
|
+
)}
|
|
79
|
+
<div className="flex flex-col justify-center min-w-0 flex-1">
|
|
80
|
+
{title && (
|
|
81
|
+
<h1 className="text-h2 text-ods-text-primary truncate" title={title}>{title}</h1>
|
|
82
|
+
)}
|
|
83
|
+
{subtitle && (
|
|
84
|
+
<p className="text-h6 text-ods-text-secondary truncate" title={subtitle}>{subtitle}</p>
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
) : (
|
|
89
|
+
title && <h1 className="text-h2 text-ods-text-primary">{title}</h1>
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
{(hasActions || hasMenuActions || selector) && (
|
|
94
|
+
<div className="flex gap-2 items-center shrink-0">
|
|
95
|
+
<PageActions
|
|
96
|
+
variant={actionsVariant}
|
|
97
|
+
actions={actions ?? []}
|
|
98
|
+
menuActions={menuActions}
|
|
99
|
+
selector={selector}
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
82
104
|
)
|
|
83
105
|
}
|
|
84
106
|
|
|
@@ -29,7 +29,7 @@ import { EntityVideoSection } from '../features/entity-video-section'
|
|
|
29
29
|
import { VideoBitesDisplay } from '../features/video-bites-display'
|
|
30
30
|
import { useVideoWarmup } from '../features/use-video-warmup'
|
|
31
31
|
import { getCaptionsUrl } from '../features/captions-url'
|
|
32
|
-
import {
|
|
32
|
+
import { SimpleMarkdownRenderer } from '../ui/simple-markdown-renderer'
|
|
33
33
|
import { EntityTagBadges } from '../features/entity-tag-badges'
|
|
34
34
|
import { LoadError } from '../ui/error-state'
|
|
35
35
|
import { ArticleAuthorByline } from '../shared/article-author-byline'
|
|
@@ -62,7 +62,7 @@ export interface OnboardingGuideDetailViewProps {
|
|
|
62
62
|
* byline renders nothing below the name when the bio is empty. */
|
|
63
63
|
fallbackBio?: string | null
|
|
64
64
|
/** Optional markdown renderer override. Defaults to lib
|
|
65
|
-
* `<
|
|
65
|
+
* `<SimpleMarkdownRenderer>`. */
|
|
66
66
|
MarkdownRenderer?: ComponentType<{ content: string }>
|
|
67
67
|
/** Optional per-row related-card renderer override. */
|
|
68
68
|
renderRelatedCard?: (guide: OnboardingGuide) => ReactNode
|
|
@@ -83,7 +83,7 @@ export function OnboardingGuideDetailView({
|
|
|
83
83
|
slug,
|
|
84
84
|
guideEndpoint,
|
|
85
85
|
related = [],
|
|
86
|
-
MarkdownRenderer =
|
|
86
|
+
MarkdownRenderer = SimpleMarkdownRenderer,
|
|
87
87
|
renderRelatedCard,
|
|
88
88
|
backHref,
|
|
89
89
|
backLabel = 'Back to Getting Started',
|