@flamingo-stack/openframe-frontend-core 0.0.295 → 0.0.296-snapshot.20260621021605
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 +9 -0
- package/dist/{chunk-7RIYT7ZH.js → chunk-2QG57XOJ.js} +1067 -205
- package/dist/chunk-2QG57XOJ.js.map +1 -0
- package/dist/{chunk-7KXD7CWD.js → chunk-3JIQVE7T.js} +9 -15
- package/dist/{chunk-7KXD7CWD.js.map → chunk-3JIQVE7T.js.map} +1 -1
- package/dist/{chunk-FT4FCV7L.cjs → chunk-4PSQS3SW.cjs} +7 -9
- package/dist/chunk-4PSQS3SW.cjs.map +1 -0
- package/dist/{chunk-OOKKGOPQ.js → chunk-4TLE6VLU.js} +30 -24
- package/dist/chunk-4TLE6VLU.js.map +1 -0
- package/dist/{chunk-6IBA2MQV.cjs → chunk-53FUMSZ5.cjs} +40 -46
- package/dist/chunk-53FUMSZ5.cjs.map +1 -0
- package/dist/{chunk-D3LEFMOA.cjs → chunk-54KNMC2R.cjs} +3 -3
- package/dist/{chunk-D3LEFMOA.cjs.map → chunk-54KNMC2R.cjs.map} +1 -1
- package/dist/{chunk-EYEW6PTA.cjs → chunk-6C526VNN.cjs} +358 -118
- package/dist/chunk-6C526VNN.cjs.map +1 -0
- package/dist/{chunk-5O6N3BKR.cjs → chunk-7OVGB2DQ.cjs} +19 -25
- package/dist/chunk-7OVGB2DQ.cjs.map +1 -0
- package/dist/{chunk-6GCI7JOE.js → chunk-AD6C23QY.js} +8 -7
- package/dist/{chunk-6GCI7JOE.js.map → chunk-AD6C23QY.js.map} +1 -1
- package/dist/chunk-F5OB2YAL.cjs +144 -0
- package/dist/chunk-F5OB2YAL.cjs.map +1 -0
- package/dist/chunk-FBWXMMRB.cjs +2 -0
- package/dist/chunk-FBWXMMRB.cjs.map +1 -0
- package/dist/{chunk-YIGPRLQY.cjs → chunk-FCDQNTDG.cjs} +21 -20
- package/dist/chunk-FCDQNTDG.cjs.map +1 -0
- package/dist/{chunk-XXI7BNB6.cjs → chunk-FQOTC3UU.cjs} +321 -18
- package/dist/chunk-FQOTC3UU.cjs.map +1 -0
- package/dist/{chunk-INDQMNP6.cjs → chunk-GUTS7HGA.cjs} +11658 -2146
- package/dist/chunk-GUTS7HGA.cjs.map +1 -0
- package/dist/chunk-GZ4C3XW6.js +2 -0
- package/dist/chunk-GZ4C3XW6.js.map +1 -0
- package/dist/{chunk-HOVJGXF7.js → chunk-IL47XWV5.js} +8 -14
- package/dist/{chunk-HOVJGXF7.js.map → chunk-IL47XWV5.js.map} +1 -1
- package/dist/{chunk-LCNMR277.js → chunk-IZ7JSBFP.js} +1 -1
- package/dist/chunk-IZ7JSBFP.js.map +1 -0
- package/dist/{chunk-5IJ46KAV.js → chunk-JALO4TAZ.js} +360 -57
- package/dist/chunk-JALO4TAZ.js.map +1 -0
- package/dist/{chunk-AQOWFSMB.cjs → chunk-L6PSSIUQ.cjs} +1 -1
- package/dist/chunk-L6PSSIUQ.cjs.map +1 -0
- package/dist/{chunk-J3RDKZ32.js → chunk-L7ULJKG7.js} +6 -10
- package/dist/{chunk-J3RDKZ32.js.map → chunk-L7ULJKG7.js.map} +1 -1
- package/dist/{chunk-6BZEAPNT.js → chunk-PC746XCO.js} +15120 -5608
- package/dist/chunk-PC746XCO.js.map +1 -0
- package/dist/{chunk-3ZXUQQL4.js → chunk-PI4WSYQV.js} +2 -2
- package/dist/{chunk-E4XABBSU.js → chunk-PWQUAVA3.js} +338 -98
- package/dist/chunk-PWQUAVA3.js.map +1 -0
- package/dist/chunk-SA2WPJVO.js +144 -0
- package/dist/chunk-SA2WPJVO.js.map +1 -0
- package/dist/{chunk-ETACGX2A.cjs → chunk-UNVE2SDJ.cjs} +37 -31
- package/dist/chunk-UNVE2SDJ.cjs.map +1 -0
- package/dist/{chunk-5E2HOSSH.cjs → chunk-WMSTJAZT.cjs} +913 -51
- package/dist/chunk-WMSTJAZT.cjs.map +1 -0
- package/dist/{chunk-EJXHZX2E.js → chunk-X4DOXQRT.js} +4 -6
- package/dist/{chunk-EJXHZX2E.js.map → chunk-X4DOXQRT.js.map} +1 -1
- package/dist/{chunk-A2YL7QRX.cjs → chunk-YBYI62OE.cjs} +33 -37
- package/dist/chunk-YBYI62OE.cjs.map +1 -0
- package/dist/components/case-studies/index.cjs +126 -0
- package/dist/components/case-studies/index.cjs.map +1 -0
- package/dist/components/case-studies/index.d.ts +2 -0
- package/dist/components/case-studies/index.d.ts.map +1 -0
- package/dist/components/case-studies/index.js +126 -0
- package/dist/components/case-studies/index.js.map +1 -0
- package/dist/components/case-studies/share-experience-section.d.ts +48 -0
- package/dist/components/case-studies/share-experience-section.d.ts.map +1 -0
- package/dist/components/chat/chat-container.d.ts.map +1 -1
- package/dist/components/chat/error-message-display.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +8 -18
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +75 -85
- package/dist/components/chat/types/component.types.d.ts +2 -0
- package/dist/components/chat/types/component.types.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +8 -15
- package/dist/components/contact/index.cjs.map +1 -1
- package/dist/components/contact/index.js +7 -14
- package/dist/components/docs/doc-viewer.d.ts +39 -2
- package/dist/components/docs/doc-viewer.d.ts.map +1 -1
- package/dist/components/docs/docs-hub-page.d.ts +46 -0
- package/dist/components/docs/docs-hub-page.d.ts.map +1 -0
- package/dist/components/docs/index.cjs +17 -9
- package/dist/components/docs/index.cjs.map +1 -1
- package/dist/components/docs/index.d.ts +4 -0
- package/dist/components/docs/index.d.ts.map +1 -1
- package/dist/components/docs/index.js +16 -8
- package/dist/components/docs/skeletons.d.ts +32 -0
- package/dist/components/docs/skeletons.d.ts.map +1 -0
- package/dist/components/docs/use-docs-resolve-link.d.ts +20 -0
- package/dist/components/docs/use-docs-resolve-link.d.ts.map +1 -0
- package/dist/components/docs/use-document-tree.d.ts.map +1 -1
- package/dist/components/embeds/embed-container.d.ts +37 -0
- package/dist/components/embeds/embed-container.d.ts.map +1 -0
- package/dist/components/embeds/embed-iframe.d.ts.map +1 -1
- package/dist/components/embeds/file-download-card.d.ts +18 -0
- package/dist/components/embeds/file-download-card.d.ts.map +1 -0
- package/dist/components/embeds/index.cjs +38 -15
- package/dist/components/embeds/index.cjs.map +1 -1
- package/dist/components/embeds/index.d.ts +8 -0
- package/dist/components/embeds/index.d.ts.map +1 -1
- package/dist/components/embeds/index.js +40 -17
- package/dist/components/embeds/linkedin-embed-client.d.ts +8 -0
- package/dist/components/embeds/linkedin-embed-client.d.ts.map +1 -0
- package/dist/components/embeds/markdown-image.d.ts +5 -0
- package/dist/components/embeds/markdown-image.d.ts.map +1 -0
- package/dist/components/embeds/reddit-embed-client.d.ts +7 -0
- package/dist/components/embeds/reddit-embed-client.d.ts.map +1 -0
- package/dist/components/embeds/rich-markdown-runtime.d.ts +46 -0
- package/dist/components/embeds/rich-markdown-runtime.d.ts.map +1 -0
- package/dist/components/embeds/twitter-embed-client.d.ts +8 -0
- package/dist/components/embeds/twitter-embed-client.d.ts.map +1 -0
- package/dist/components/faq/index.cjs +9 -16
- package/dist/components/faq/index.cjs.map +1 -1
- package/dist/components/faq/index.js +8 -15
- package/dist/components/features/index.cjs +8 -16
- package/dist/components/features/index.cjs.map +1 -1
- package/dist/components/features/index.js +24 -32
- package/dist/components/features/notifications/notification-drawer.d.ts.map +1 -1
- package/dist/components/features/notifications/notifications-context.d.ts +5 -1
- package/dist/components/features/notifications/notifications-context.d.ts.map +1 -1
- package/dist/components/index.cjs +257 -452
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +781 -976
- package/dist/components/index.js.map +1 -1
- package/dist/components/layout/page-header.d.ts +78 -0
- package/dist/components/layout/page-header.d.ts.map +1 -0
- package/dist/components/layout/page-layout.d.ts +10 -1
- package/dist/components/layout/page-layout.d.ts.map +1 -1
- package/dist/components/layout/page-with-header.d.ts +67 -0
- package/dist/components/layout/page-with-header.d.ts.map +1 -0
- package/dist/components/layout/title-block.d.ts +17 -1
- package/dist/components/layout/title-block.d.ts.map +1 -1
- package/dist/components/navigation/index.cjs +7 -15
- package/dist/components/navigation/index.cjs.map +1 -1
- package/dist/components/navigation/index.js +9 -17
- package/dist/components/onboarding-guides/index.cjs +35 -36
- package/dist/components/onboarding-guides/index.cjs.map +1 -1
- package/dist/components/onboarding-guides/index.js +13 -14
- 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 +9 -16
- package/dist/components/related-content/index.cjs.map +1 -1
- package/dist/components/related-content/index.js +8 -15
- package/dist/components/shared/dev-section/dev-section-page.d.ts +9 -0
- 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 +100 -112
- package/dist/components/tickets/index.cjs.map +1 -1
- package/dist/components/tickets/index.js +20 -32
- package/dist/components/tickets/index.js.map +1 -1
- package/dist/components/ui/button/split-button.d.ts.map +1 -1
- package/dist/components/ui/file-manager/index.cjs +50 -52
- package/dist/components/ui/file-manager/index.cjs.map +1 -1
- package/dist/components/ui/file-manager/index.js +4 -6
- package/dist/components/ui/file-manager/index.js.map +1 -1
- package/dist/components/ui/index.cjs +13 -19
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +2 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +133 -139
- package/dist/components/ui/release-changelog-section.d.ts +6 -2
- package/dist/components/ui/release-changelog-section.d.ts.map +1 -1
- package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
- package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
- package/dist/components/ui/simple-markdown-renderer.d.ts +2 -8
- package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
- package/dist/contexts/chat-runtime-context.d.ts +14 -0
- 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 +4 -9
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +6 -11
- package/dist/index.cjs +14 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +362 -368
- package/dist/types/doc-source.d.ts +31 -1
- package/dist/types/doc-source.d.ts.map +1 -1
- package/dist/utils/index.cjs +4 -0
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/page-header-constants.d.ts +15 -0
- package/dist/utils/page-header-constants.d.ts.map +1 -0
- package/dist/utils/social-embed-cache.d.ts +29 -0
- package/dist/utils/social-embed-cache.d.ts.map +1 -0
- package/package.json +7 -1
- package/src/components/case-studies/index.ts +4 -0
- package/src/components/case-studies/share-experience-section.tsx +185 -0
- package/src/components/chat/chat-container.tsx +5 -7
- package/src/components/chat/embeddable-chat.tsx +1 -1
- package/src/components/chat/error-message-display.tsx +49 -31
- package/src/components/chat/types/component.types.ts +2 -0
- package/src/components/docs/doc-viewer.tsx +111 -19
- package/src/components/docs/docs-hub-page.tsx +149 -0
- package/src/components/docs/index.ts +17 -0
- package/src/components/docs/skeletons.tsx +138 -0
- package/src/components/docs/use-docs-resolve-link.ts +52 -0
- package/src/components/docs/use-document-tree.ts +21 -0
- package/src/components/embeds/embed-container.tsx +80 -0
- package/src/components/embeds/embed-iframe.tsx +7 -9
- package/src/components/embeds/file-download-card.tsx +54 -0
- package/src/components/embeds/index.ts +30 -0
- package/src/components/embeds/linkedin-embed-client.tsx +100 -0
- package/src/components/embeds/markdown-image.tsx +88 -0
- package/src/components/embeds/og-link-preview.tsx +13 -13
- package/src/components/embeds/reddit-embed-client.tsx +550 -0
- package/src/components/embeds/rich-markdown-runtime.tsx +79 -0
- package/src/components/embeds/twitter-embed-client.tsx +308 -0
- package/src/components/features/notifications/notification-drawer.tsx +18 -7
- package/src/components/features/notifications/notifications-context.tsx +7 -0
- package/src/components/layout/page-header.tsx +182 -0
- package/src/components/layout/page-layout.tsx +14 -1
- package/src/components/layout/page-with-header.tsx +110 -0
- package/src/components/layout/title-block.tsx +40 -62
- package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +3 -3
- package/src/components/shared/dev-section/dev-section-page.tsx +9 -1
- package/src/components/shared/dev-section/dev-section-view.tsx +14 -9
- package/src/components/shared/dev-section/index.ts +1 -1
- package/src/components/shared/doc-search/use-doc-search.ts +7 -3
- package/src/components/shared/legal-document/legal-document-page.tsx +2 -2
- package/src/components/shared/product-release/release-detail-page.tsx +6 -4
- package/src/components/ui/button/split-button.tsx +5 -2
- package/src/components/ui/index.ts +2 -0
- package/src/components/ui/release-changelog-section.tsx +7 -2
- package/src/components/ui/rich-markdown-renderer.tsx +1203 -0
- package/src/components/ui/simple-markdown-renderer.tsx +7 -11
- package/src/contexts/chat-runtime-context.tsx +14 -0
- package/src/stories/NotificationDrawer.stories.tsx +2 -0
- package/src/types/doc-source.ts +33 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/page-header-constants.ts +15 -0
- package/src/utils/social-embed-cache.ts +391 -0
- package/dist/chunk-26PKDALD.js +0 -2379
- package/dist/chunk-26PKDALD.js.map +0 -1
- package/dist/chunk-3MCHAFHB.js +0 -89
- package/dist/chunk-3MCHAFHB.js.map +0 -1
- package/dist/chunk-3XIB4VKS.cjs +0 -619
- package/dist/chunk-3XIB4VKS.cjs.map +0 -1
- package/dist/chunk-4W7NYJ3B.cjs +0 -3009
- package/dist/chunk-4W7NYJ3B.cjs.map +0 -1
- package/dist/chunk-5E2HOSSH.cjs.map +0 -1
- package/dist/chunk-5IJ46KAV.js.map +0 -1
- package/dist/chunk-5O6N3BKR.cjs.map +0 -1
- package/dist/chunk-6BZEAPNT.js.map +0 -1
- package/dist/chunk-6IBA2MQV.cjs.map +0 -1
- package/dist/chunk-6JINAOI7.cjs +0 -311
- package/dist/chunk-6JINAOI7.cjs.map +0 -1
- package/dist/chunk-7RIYT7ZH.js.map +0 -1
- package/dist/chunk-A2YL7QRX.cjs.map +0 -1
- package/dist/chunk-AQOWFSMB.cjs.map +0 -1
- package/dist/chunk-E4XABBSU.js.map +0 -1
- package/dist/chunk-ETACGX2A.cjs.map +0 -1
- package/dist/chunk-EYEW6PTA.cjs.map +0 -1
- package/dist/chunk-FQJK446R.js +0 -1606
- package/dist/chunk-FQJK446R.js.map +0 -1
- package/dist/chunk-FT4FCV7L.cjs.map +0 -1
- package/dist/chunk-INDQMNP6.cjs.map +0 -1
- package/dist/chunk-J54Z3OCR.cjs +0 -1606
- package/dist/chunk-J54Z3OCR.cjs.map +0 -1
- package/dist/chunk-KXCRGTRN.cjs +0 -2379
- package/dist/chunk-KXCRGTRN.cjs.map +0 -1
- package/dist/chunk-LCNMR277.js.map +0 -1
- package/dist/chunk-LFGGF7OT.cjs +0 -449
- package/dist/chunk-LFGGF7OT.cjs.map +0 -1
- package/dist/chunk-M2OCXTNT.js +0 -311
- package/dist/chunk-M2OCXTNT.js.map +0 -1
- package/dist/chunk-NSPOYUBH.js +0 -3009
- package/dist/chunk-NSPOYUBH.js.map +0 -1
- package/dist/chunk-OOKKGOPQ.js.map +0 -1
- package/dist/chunk-OQ6X7ZOC.js +0 -449
- package/dist/chunk-OQ6X7ZOC.js.map +0 -1
- package/dist/chunk-POKKCWKF.js +0 -354
- package/dist/chunk-POKKCWKF.js.map +0 -1
- package/dist/chunk-TFSYSWPS.cjs +0 -89
- package/dist/chunk-TFSYSWPS.cjs.map +0 -1
- package/dist/chunk-XXI7BNB6.cjs.map +0 -1
- package/dist/chunk-YD43AKI5.js +0 -619
- package/dist/chunk-YD43AKI5.js.map +0 -1
- package/dist/chunk-YETA25JW.cjs +0 -354
- package/dist/chunk-YETA25JW.cjs.map +0 -1
- package/dist/chunk-YIGPRLQY.cjs.map +0 -1
- /package/dist/{chunk-3ZXUQQL4.js.map → chunk-PI4WSYQV.js.map} +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String constants shared by page-header consumers (`<PageHeader>`,
|
|
3
|
+
* `<DevSectionPage>`, `<DocsHubPage>` callers). Lives in `utils/` —
|
|
4
|
+
* NOT `'use client'` — so server modules (e.g. the hub's
|
|
5
|
+
* `lib/docs/hub-docs-presets.tsx` that builds preset JSX with
|
|
6
|
+
* `<Icon className={SECTION_HERO_ICON_CLASS} />`) can import the raw
|
|
7
|
+
* string. Importing the constant from a `'use client'` module turns it
|
|
8
|
+
* into a Next.js client-reference proxy in server contexts, which
|
|
9
|
+
* lucide's internal `mergeClasses` then calls `.trim()` on and crashes.
|
|
10
|
+
*/
|
|
11
|
+
/** Tailwind class applied uniformly to every section-hero / page-header
|
|
12
|
+
* icon across the lib (Roadmap Map, Releases Rocket, Knowledge Hub
|
|
13
|
+
* BookOpen, Data Room Building2, …). Yellow accent color, 40x40. */
|
|
14
|
+
export declare const SECTION_HERO_ICON_CLASS = "h-10 w-10 text-ods-accent";
|
|
15
|
+
//# sourceMappingURL=page-header-constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-header-constants.d.ts","sourceRoot":"","sources":["../../src/utils/page-header-constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;qEAEqE;AACrE,eAAO,MAAM,uBAAuB,8BAA8B,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
interface CacheOptions {
|
|
2
|
+
platform: 'reddit' | 'twitter';
|
|
3
|
+
url: string;
|
|
4
|
+
apiEndpoint: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class SocialEmbedCache {
|
|
7
|
+
private static instance;
|
|
8
|
+
static getInstance(): SocialEmbedCache;
|
|
9
|
+
getFromMemory(url: string): any | null;
|
|
10
|
+
setInMemory(url: string, data: any): void;
|
|
11
|
+
getFromServer(options: CacheOptions): Promise<any | null>;
|
|
12
|
+
private updateServerCache;
|
|
13
|
+
setInServer(options: CacheOptions, data: any): Promise<void>;
|
|
14
|
+
fetchDirect(options: CacheOptions & {
|
|
15
|
+
directFetcher: () => Promise<any>;
|
|
16
|
+
}): Promise<any | null>;
|
|
17
|
+
fetchWithHierarchy(options: CacheOptions & {
|
|
18
|
+
dataValidator: (data: any) => boolean;
|
|
19
|
+
onDataUpdate: (data: any) => void;
|
|
20
|
+
onError: (error: string) => void;
|
|
21
|
+
onLoading: (loading: boolean) => void;
|
|
22
|
+
}): Promise<void>;
|
|
23
|
+
private scheduleAsyncRefresh;
|
|
24
|
+
private backgroundRefresh;
|
|
25
|
+
private silentBackgroundRefresh;
|
|
26
|
+
}
|
|
27
|
+
export declare const socialCache: SocialEmbedCache;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=social-embed-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"social-embed-cache.d.ts","sourceRoot":"","sources":["../../src/utils/social-embed-cache.ts"],"names":[],"mappings":"AAmBA,UAAU,YAAY;IACpB,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmB;IAE1C,MAAM,CAAC,WAAW,IAAI,gBAAgB;IAQtC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAKtC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAKnC,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;YAoBjD,iBAAiB;IAezB,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B5D,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG;QACxC,aAAa,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;KAClC,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAajB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG;QAC/C,aAAa,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC;QACtC,YAAY,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;QAClC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QACjC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;KACvC,GAAG,OAAO,CAAC,IAAI,CAAC;IAmIjB,OAAO,CAAC,oBAAoB;YAgCd,iBAAiB;IAiD/B,OAAO,CAAC,uBAAuB;CAgDhC;AAED,eAAO,MAAM,WAAW,kBAAiC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flamingo-stack/openframe-frontend-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.296-snapshot.20260621021605",
|
|
4
4
|
"description": "Shared design system and components for all Flamingo platforms",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -78,6 +78,12 @@
|
|
|
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
|
+
},
|
|
81
87
|
"./schemas/contact-schema": {
|
|
82
88
|
"types": "./dist/schemas/contact-schema.d.ts",
|
|
83
89
|
"import": "./dist/schemas/contact-schema.js",
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { BenefitCard, BenefitCardGrid } from '../ui'
|
|
5
|
+
import {
|
|
6
|
+
G2Icon,
|
|
7
|
+
CapterraIcon,
|
|
8
|
+
TrustpilotIcon,
|
|
9
|
+
GetAppIcon,
|
|
10
|
+
} from '../icons'
|
|
11
|
+
import {
|
|
12
|
+
ContactForm,
|
|
13
|
+
type ContactFormProps,
|
|
14
|
+
} from '../contact'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* `<ShareExperienceSection>` — the case-studies "Share Your Experience"
|
|
18
|
+
* CTA block.
|
|
19
|
+
*
|
|
20
|
+
* Hub usage: rendered inside the unified case-studies chrome (between
|
|
21
|
+
* the search bar and the case-study card grid) so it stays at the same
|
|
22
|
+
* y-offset + gutters as the rest of the page content.
|
|
23
|
+
*
|
|
24
|
+
* Embedders mount this anywhere they like. The inner `<ContactForm>`
|
|
25
|
+
* submits through the AMBIENT `EndpointsRuntime.contactUrl` (same proxy
|
|
26
|
+
* seam every other embed-aware form uses), so embedders behind a
|
|
27
|
+
* `/content` reverse proxy get a working submission with no per-call-
|
|
28
|
+
* site wiring.
|
|
29
|
+
*
|
|
30
|
+
* **Copy is overridable.** Every string is a prop with a sensible
|
|
31
|
+
* "Flamingo case-studies" default so the hub keeps its existing copy
|
|
32
|
+
* verbatim; embedders override what they need.
|
|
33
|
+
*
|
|
34
|
+
* **Contact-form integration is configurable.** Hub auto-resolves
|
|
35
|
+
* `userId` / `helpCategoryOptions` / `rdtCid` / `onSubmitSuccess` from
|
|
36
|
+
* its app context and passes them down via `contactFormProps`;
|
|
37
|
+
* embedders without that context just omit them. All other
|
|
38
|
+
* `ContactFormProps` are forwarded too, so the host can adjust prefill,
|
|
39
|
+
* success redirect, hidden fields, etc. without forking this component.
|
|
40
|
+
*/
|
|
41
|
+
export interface ShareExperienceSectionProps {
|
|
42
|
+
/** Override the section heading. JSX so the host can break lines /
|
|
43
|
+
* colorize the accent the same way the hub does. Default: the
|
|
44
|
+
* hub's two-line "Share Your Experience / with Fellow MSPs:" copy. */
|
|
45
|
+
title?: React.ReactNode
|
|
46
|
+
/** Override the lead paragraph. Default: the hub's review-incentive
|
|
47
|
+
* copy referencing Flamingo. Pass a brand-neutral string in embeds. */
|
|
48
|
+
subtitle?: React.ReactNode
|
|
49
|
+
/** Override the "How it works?" sub-heading. */
|
|
50
|
+
howItWorksTitle?: React.ReactNode
|
|
51
|
+
/** Override the "How it works?" body copy. */
|
|
52
|
+
howItWorksBody?: React.ReactNode
|
|
53
|
+
/** Forwarded to the inner `<ContactForm>`. The hub passes its
|
|
54
|
+
* auto-resolved `userId` / `helpCategoryOptions` / `rdtCid` /
|
|
55
|
+
* `onSubmitSuccess` here. Embedders pass overrides like
|
|
56
|
+
* `successRedirectUrl` or extra prefill copy. */
|
|
57
|
+
contactFormProps?: Partial<ContactFormProps>
|
|
58
|
+
className?: string
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const DEFAULT_TITLE: React.ReactNode = (
|
|
62
|
+
<>
|
|
63
|
+
Share Your Experience
|
|
64
|
+
<br />
|
|
65
|
+
with Fellow MSPs<span className="text-ods-accent">:</span>
|
|
66
|
+
</>
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
const DEFAULT_SUBTITLE: React.ReactNode = (
|
|
70
|
+
<>
|
|
71
|
+
We know your time is valuable. When you leave an honest review about
|
|
72
|
+
your Flamingo experience, we'd like to thank you with a gift
|
|
73
|
+
certificate – not as payment for a review, but as appreciation for
|
|
74
|
+
the time you invest in helping other MSPs make informed decisions.
|
|
75
|
+
</>
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
const DEFAULT_HOW_IT_WORKS_TITLE: React.ReactNode = (
|
|
79
|
+
<>
|
|
80
|
+
How it works<span className="text-ods-accent">?</span>
|
|
81
|
+
</>
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
const DEFAULT_HOW_IT_WORKS_BODY: React.ReactNode = (
|
|
85
|
+
<>
|
|
86
|
+
Share your name and email with us, and we'll reach out to guide
|
|
87
|
+
you through the review process and arrange your thank-you gift
|
|
88
|
+
certificate.
|
|
89
|
+
</>
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
/** Defaults that match the hub's existing /case-studies behavior. Host
|
|
93
|
+
* overrides via `contactFormProps` win over these. */
|
|
94
|
+
const DEFAULT_CONTACT_FORM_PROPS = {
|
|
95
|
+
prefilledReason: 'I want to do a case study',
|
|
96
|
+
prefilledMessage: 'I want to do a case study',
|
|
97
|
+
hideFields: ['companySize', 'referralSource', 'helpCategory', 'message'] as ContactFormProps['hideFields'],
|
|
98
|
+
title: '',
|
|
99
|
+
subtitle: '',
|
|
100
|
+
footerText: '',
|
|
101
|
+
noBorder: true,
|
|
102
|
+
noPadding: true,
|
|
103
|
+
buttonVariant: 'outline' as ContactFormProps['buttonVariant'],
|
|
104
|
+
buttonClassName: 'w-full',
|
|
105
|
+
successToastMessage: "Thank you! We'll reach out to schedule your case study.",
|
|
106
|
+
} satisfies Partial<ContactFormProps>
|
|
107
|
+
|
|
108
|
+
export function ShareExperienceSection({
|
|
109
|
+
title = DEFAULT_TITLE,
|
|
110
|
+
subtitle = DEFAULT_SUBTITLE,
|
|
111
|
+
howItWorksTitle = DEFAULT_HOW_IT_WORKS_TITLE,
|
|
112
|
+
howItWorksBody = DEFAULT_HOW_IT_WORKS_BODY,
|
|
113
|
+
contactFormProps,
|
|
114
|
+
className,
|
|
115
|
+
}: ShareExperienceSectionProps = {}) {
|
|
116
|
+
return (
|
|
117
|
+
<section className={`flex flex-col gap-10${className ? ` ${className}` : ''}`}>
|
|
118
|
+
<div className="text-ods-text-primary">
|
|
119
|
+
<h2 className="text-h1 text-ods-text-primary">{title}</h2>
|
|
120
|
+
<p className="text-h4 mt-6 max-w-[765px]">{subtitle}</p>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div className="bg-ods-background border border-ods-border rounded-md p-10">
|
|
124
|
+
<div className="flex flex-col gap-10">
|
|
125
|
+
<div className="flex flex-col gap-6 text-ods-text-primary">
|
|
126
|
+
<h3 className="text-h2">{howItWorksTitle}</h3>
|
|
127
|
+
<p className="text-h4">{howItWorksBody}</p>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<BenefitCardGrid columns={4}>
|
|
131
|
+
<BenefitCard
|
|
132
|
+
icon={
|
|
133
|
+
<div className="bg-ods-background border border-ods-border rounded-md p-2 w-12 h-12 flex items-center justify-center">
|
|
134
|
+
<G2Icon width={24} height={24} />
|
|
135
|
+
</div>
|
|
136
|
+
}
|
|
137
|
+
title="G2"
|
|
138
|
+
description="g2.com"
|
|
139
|
+
variant="auth-figma"
|
|
140
|
+
/>
|
|
141
|
+
<BenefitCard
|
|
142
|
+
icon={
|
|
143
|
+
<div className="bg-ods-background border border-ods-border rounded-md p-2 w-12 h-12 flex items-center justify-center">
|
|
144
|
+
<CapterraIcon width={24} height={24} />
|
|
145
|
+
</div>
|
|
146
|
+
}
|
|
147
|
+
title="Capterra"
|
|
148
|
+
description="capterra.com"
|
|
149
|
+
variant="auth-figma"
|
|
150
|
+
/>
|
|
151
|
+
<BenefitCard
|
|
152
|
+
icon={
|
|
153
|
+
<div className="bg-ods-background border border-ods-border rounded-md p-2 w-12 h-12 flex items-center justify-center">
|
|
154
|
+
<TrustpilotIcon width={24} height={24} />
|
|
155
|
+
</div>
|
|
156
|
+
}
|
|
157
|
+
title="TrustPilot"
|
|
158
|
+
description="trustpilot.com"
|
|
159
|
+
variant="auth-figma"
|
|
160
|
+
/>
|
|
161
|
+
<BenefitCard
|
|
162
|
+
icon={
|
|
163
|
+
<div className="bg-ods-background border border-ods-border rounded-md p-2 w-12 h-12 flex items-center justify-center">
|
|
164
|
+
<GetAppIcon width={24} height={24} />
|
|
165
|
+
</div>
|
|
166
|
+
}
|
|
167
|
+
title="GetApp"
|
|
168
|
+
description="getapp.com"
|
|
169
|
+
variant="auth-figma"
|
|
170
|
+
/>
|
|
171
|
+
</BenefitCardGrid>
|
|
172
|
+
|
|
173
|
+
{/* Submission proxies through ambient EndpointsRuntime.contactUrl —
|
|
174
|
+
* no per-call-site wiring needed for embeds behind a reverse
|
|
175
|
+
* proxy. Hub's auto-resolving wrapper passes userId / rdtCid /
|
|
176
|
+
* onSubmitSuccess via `contactFormProps`. */}
|
|
177
|
+
<ContactForm
|
|
178
|
+
{...DEFAULT_CONTACT_FORM_PROPS}
|
|
179
|
+
{...contactFormProps}
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
</section>
|
|
184
|
+
)
|
|
185
|
+
}
|
|
@@ -12,16 +12,14 @@ import type { ConnectionIndicatorProps, ChatContainerProps, ChatHeaderProps } fr
|
|
|
12
12
|
const ConnectionIndicator: React.FC<ConnectionIndicatorProps> = ({ status }) => {
|
|
13
13
|
const getStatusStyles = () => {
|
|
14
14
|
switch (status) {
|
|
15
|
-
// ODS
|
|
16
|
-
//
|
|
17
|
-
// (`bg-green-500` / `bg-red-500`) would diverge from the theme and
|
|
18
|
-
// is forbidden by the host's design-token policy.
|
|
15
|
+
// ODS semantic status tokens — preset-defined utilities aliasing the same
|
|
16
|
+
// green/yellow/red as the raw ods-attention palette (which is CSS-vars only).
|
|
19
17
|
case 'connected':
|
|
20
|
-
return 'bg-ods-
|
|
18
|
+
return 'bg-ods-success'
|
|
21
19
|
case 'connecting':
|
|
22
|
-
return 'bg-ods-
|
|
20
|
+
return 'bg-ods-warning animate-pulse'
|
|
23
21
|
case 'disconnected':
|
|
24
|
-
return 'bg-ods-
|
|
22
|
+
return 'bg-ods-error'
|
|
25
23
|
default:
|
|
26
24
|
return 'bg-ods-text-tertiary'
|
|
27
25
|
}
|
|
@@ -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:'openframe').
|
|
1131
1131
|
const resolvedBaseRoute =
|
|
1132
1132
|
baseRoute || (source === 'flamingo' ? '/knowledge-base' : '/data-room')
|
|
1133
1133
|
|
|
@@ -2,51 +2,69 @@
|
|
|
2
2
|
|
|
3
3
|
import { forwardRef, useState } from "react"
|
|
4
4
|
import { cn } from "../../utils/cn"
|
|
5
|
-
import {
|
|
5
|
+
import { AlertCircleIcon } from "../icons-v2-generated"
|
|
6
|
+
import { ExpandChevron } from "./expand-chevron"
|
|
7
|
+
import { useCollapsible } from "./hooks/use-collapsible"
|
|
6
8
|
import type { ErrorMessageDisplayProps } from "./types"
|
|
7
9
|
|
|
10
|
+
const iconTint = {
|
|
11
|
+
error: "text-ods-error",
|
|
12
|
+
warning: "text-ods-warning",
|
|
13
|
+
info: "text-ods-text-secondary",
|
|
14
|
+
} as const
|
|
15
|
+
|
|
8
16
|
const ErrorMessageDisplay = forwardRef<HTMLDivElement, ErrorMessageDisplayProps>(
|
|
9
|
-
({ className, title, details, ...props }, ref) => {
|
|
10
|
-
const [
|
|
17
|
+
({ className, title, details, type = "error", ...props }, ref) => {
|
|
18
|
+
const [expanded, setExpanded] = useState(false)
|
|
19
|
+
const { innerRef, containerStyle } = useCollapsible({ expanded })
|
|
20
|
+
const hasDetails = Boolean(details)
|
|
11
21
|
|
|
12
22
|
return (
|
|
13
23
|
<div
|
|
14
24
|
ref={ref}
|
|
15
25
|
className={cn(
|
|
16
|
-
"bg-[var(--
|
|
26
|
+
"bg-ods-card rounded-md p-[var(--spacing-system-xsf)] mb-[var(--spacing-system-xsf)]",
|
|
17
27
|
className
|
|
18
28
|
)}
|
|
19
29
|
{...props}
|
|
20
30
|
>
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
)}
|
|
40
|
-
/>
|
|
41
|
-
</button>
|
|
31
|
+
<button
|
|
32
|
+
type="button"
|
|
33
|
+
onClick={hasDetails ? () => setExpanded(prev => !prev) : undefined}
|
|
34
|
+
aria-expanded={hasDetails ? expanded : undefined}
|
|
35
|
+
aria-label={
|
|
36
|
+
hasDetails ? (expanded ? "Collapse details" : "Expand details") : undefined
|
|
37
|
+
}
|
|
38
|
+
disabled={!hasDetails}
|
|
39
|
+
className={cn(
|
|
40
|
+
"flex w-full items-center gap-[var(--spacing-system-xsf)] text-left",
|
|
41
|
+
hasDetails ? "cursor-pointer" : "cursor-default"
|
|
42
|
+
)}
|
|
43
|
+
>
|
|
44
|
+
<AlertCircleIcon size={16} className={cn("shrink-0", iconTint[type])} />
|
|
45
|
+
<span
|
|
46
|
+
className={cn(
|
|
47
|
+
"min-w-0 flex-1 font-mono text-sm font-medium uppercase leading-5 tracking-[-0.28px]",
|
|
48
|
+
expanded ? "text-ods-text-primary" : "truncate text-ods-text-secondary"
|
|
42
49
|
)}
|
|
50
|
+
>
|
|
51
|
+
{title}
|
|
52
|
+
</span>
|
|
53
|
+
{hasDetails && <ExpandChevron expanded={expanded} />}
|
|
54
|
+
</button>
|
|
55
|
+
|
|
56
|
+
{hasDetails && (
|
|
57
|
+
<div style={containerStyle}>
|
|
58
|
+
<div
|
|
59
|
+
ref={innerRef}
|
|
60
|
+
className="px-[var(--spacing-system-lf)] pt-[var(--spacing-system-xsf)]"
|
|
61
|
+
>
|
|
62
|
+
<p className="text-sm font-medium leading-5 text-ods-text-primary">
|
|
63
|
+
{details}
|
|
64
|
+
</p>
|
|
65
|
+
</div>
|
|
43
66
|
</div>
|
|
44
|
-
|
|
45
|
-
<span className="text-sm leading-5 text-white font-['DM_Sans'] font-medium mt-1">
|
|
46
|
-
{details}
|
|
47
|
-
</span>
|
|
48
|
-
)}
|
|
49
|
-
</div>
|
|
67
|
+
)}
|
|
50
68
|
</div>
|
|
51
69
|
)
|
|
52
70
|
}
|
|
@@ -448,6 +448,8 @@ export interface ApprovalRequestMessageProps extends HTMLAttributes<HTMLDivEleme
|
|
|
448
448
|
export interface ErrorMessageDisplayProps extends HTMLAttributes<HTMLDivElement> {
|
|
449
449
|
title: string
|
|
450
450
|
details?: string
|
|
451
|
+
/** Severity — drives the icon tint. Defaults to `error`. */
|
|
452
|
+
type?: 'error' | 'warning' | 'info'
|
|
451
453
|
}
|
|
452
454
|
|
|
453
455
|
// ========== Context Compaction Display Props ==========
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useMemo } from "react"
|
|
4
4
|
import { MultiLevelNavigation, MobileNavigationDropdown } from "../navigation/multi-level-navigation"
|
|
5
|
-
import {
|
|
5
|
+
import { PageHeader } from "../layout/page-header"
|
|
6
|
+
import { PageLayout } from "../layout/page-layout"
|
|
7
|
+
import { PageShell } from "../layout/article-detail-layout"
|
|
8
|
+
import { useRouter } from "../../embed-shims/next-navigation"
|
|
6
9
|
import { PersistentSidebar, PersistentMobileDropdown } from "../persistent-filter-controls"
|
|
7
10
|
import { CategorySidebarSkeleton } from "../loading/page-layout-skeleton"
|
|
8
11
|
import { DocSearchBar, useDocSearch } from "../shared/doc-search"
|
|
@@ -12,6 +15,7 @@ import { useScrollSpy } from "./use-scroll-spy"
|
|
|
12
15
|
import { useDocNavigation } from "./doc-navigation-context"
|
|
13
16
|
import { findDocNodeByPath } from "../../utils/doc-tree-nav"
|
|
14
17
|
import type { DocContent, DocNode, DocRenderHandlers, DocSourceId } from "../../types/doc-source"
|
|
18
|
+
import { useDocsResolveLink } from "./use-docs-resolve-link"
|
|
15
19
|
|
|
16
20
|
/** Color tokens for the doc-viewer chrome. Hub-side `DocViewer` callers share
|
|
17
21
|
* this constant; no need to override per source — the palette is intentionally
|
|
@@ -30,7 +34,7 @@ export const DEFAULT_DOC_VIEWER_PALETTE = {
|
|
|
30
34
|
export interface DocViewerProps {
|
|
31
35
|
/**
|
|
32
36
|
* Registry source id (`'openframe-docs'`, `'data-room-docs'`, …). Flowed through
|
|
33
|
-
* `renderContent`'s handlers for `/api/resolve-link` POSTs.
|
|
37
|
+
* `renderContent`'s handlers for `/api/docs/resolve-link` POSTs.
|
|
34
38
|
*/
|
|
35
39
|
sourceId: DocSourceId
|
|
36
40
|
|
|
@@ -55,7 +59,24 @@ export interface DocViewerProps {
|
|
|
55
59
|
*/
|
|
56
60
|
chatSource: string
|
|
57
61
|
|
|
58
|
-
title
|
|
62
|
+
/** Page title — rendered via the shared `<PageHeader>` primitive
|
|
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
|
|
59
80
|
/** Override the default ODS palette. Optional — most callers should omit. */
|
|
60
81
|
colorPalette?: typeof DEFAULT_DOC_VIEWER_PALETTE
|
|
61
82
|
className?: string
|
|
@@ -74,6 +95,17 @@ export interface DocViewerProps {
|
|
|
74
95
|
structureEndpoint?: string
|
|
75
96
|
/** Same shape as `structureEndpoint`. Defaults to `/api/docs/sources/${sourceId}/content`. */
|
|
76
97
|
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
|
|
77
109
|
/** Base route path for URL navigation. */
|
|
78
110
|
baseRoute: string
|
|
79
111
|
|
|
@@ -85,6 +117,13 @@ export interface DocViewerProps {
|
|
|
85
117
|
|
|
86
118
|
/** Folder-index filename (default `'README.md'`). */
|
|
87
119
|
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
|
|
88
127
|
}
|
|
89
128
|
|
|
90
129
|
export function DocViewer(props: DocViewerProps) {
|
|
@@ -97,16 +136,22 @@ function DocViewerContent({
|
|
|
97
136
|
renderSkeleton,
|
|
98
137
|
chatSource,
|
|
99
138
|
title,
|
|
139
|
+
titleIcon,
|
|
140
|
+
subtitle,
|
|
141
|
+
accentDot,
|
|
100
142
|
colorPalette = DEFAULT_DOC_VIEWER_PALETTE,
|
|
101
143
|
className = "",
|
|
102
144
|
docPath,
|
|
103
145
|
sidebarLabel = "DOCUMENTATION",
|
|
104
146
|
structureEndpoint,
|
|
105
147
|
contentEndpoint,
|
|
148
|
+
searchEndpoint,
|
|
149
|
+
resolveLinkEndpoint,
|
|
106
150
|
baseRoute,
|
|
107
151
|
emptyStateText,
|
|
108
152
|
showAIChat = false,
|
|
109
153
|
folderIndexFile,
|
|
154
|
+
backButton,
|
|
110
155
|
}: DocViewerProps) {
|
|
111
156
|
// Default endpoints derived from sourceId. Hub callers omit the props in 99%
|
|
112
157
|
// of cases; the override is for embed contexts where the doc-viewer sits
|
|
@@ -115,6 +160,13 @@ function DocViewerContent({
|
|
|
115
160
|
structureEndpoint ?? `/api/docs/sources/${sourceId}/structure`
|
|
116
161
|
const resolvedContentEndpoint =
|
|
117
162
|
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)
|
|
118
170
|
const {
|
|
119
171
|
structure,
|
|
120
172
|
selectedPath,
|
|
@@ -139,9 +191,23 @@ function DocViewerContent({
|
|
|
139
191
|
const { activeSection, handleSectionClick } = useScrollSpy(content?.sections)
|
|
140
192
|
|
|
141
193
|
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
|
+
}
|
|
142
207
|
const docSearch = useDocSearch({
|
|
143
208
|
source: chatSource,
|
|
144
209
|
baseRoute,
|
|
210
|
+
searchEndpoint,
|
|
145
211
|
onNavigate: (path) => navigateToDoc(path, { fromInternalLink: true }),
|
|
146
212
|
onInPageSwap: (path) => docNav.navigate(path),
|
|
147
213
|
})
|
|
@@ -152,8 +218,9 @@ function DocViewerContent({
|
|
|
152
218
|
onInternalLinkClick: navigateToDoc,
|
|
153
219
|
currentPath: selectedPath,
|
|
154
220
|
sourceId,
|
|
221
|
+
onResolveLink: resolveLink,
|
|
155
222
|
})
|
|
156
|
-
}, [content, selectedPath, renderContent, navigateToDoc, sourceId])
|
|
223
|
+
}, [content, selectedPath, renderContent, navigateToDoc, sourceId, resolveLink])
|
|
157
224
|
|
|
158
225
|
// Selected node's documentType drives:
|
|
159
226
|
// - which skeleton the caller renders during fetch (markdown vs embed)
|
|
@@ -192,15 +259,32 @@ function DocViewerContent({
|
|
|
192
259
|
const resolvedEmptyText = emptyStateText || defaultEmptyText
|
|
193
260
|
|
|
194
261
|
return (
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
262
|
+
// STRUCTURAL UNIFICATION: render through the IDENTICAL wrapper chain
|
|
263
|
+
// `<DevSectionPage>` uses (PageShell → PageLayout → `gap-10 flex-col`),
|
|
264
|
+
// not a hand-rolled custom container with similar-looking spacing.
|
|
265
|
+
// PageLayout owns the back-button row; the inner `gap-10` div +
|
|
266
|
+
// `<PageHeader noTopPadding noBottomMargin>` renders the title section
|
|
267
|
+
// the same way `<DevSectionView>`'s hero does. This is the only way to
|
|
268
|
+
// guarantee /knowledge-base sits at pixel-identical vertical rhythm to
|
|
269
|
+
// /roadmap / /releases / /onboarding-guides — same components, same DOM,
|
|
270
|
+
// not "same CSS classes that look similar on paper."
|
|
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
|
+
/>
|
|
204
288
|
|
|
205
289
|
{showAIChat && (
|
|
206
290
|
<DocSearchBar
|
|
@@ -271,9 +355,16 @@ function DocViewerContent({
|
|
|
271
355
|
<div className="flex-1 min-w-0 w-full">
|
|
272
356
|
<div
|
|
273
357
|
className={`grid grid-cols-1 ${
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
358
|
+
// "On this page" right column only makes sense for
|
|
359
|
+
// MARKDOWN content (PDFs / Sheets / Figma / file have no
|
|
360
|
+
// sections to navigate to). Gating the grid template on
|
|
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)
|
|
277
368
|
? 'lg:grid-cols-[1fr_280px]'
|
|
278
369
|
: ''
|
|
279
370
|
} gap-8`}
|
|
@@ -292,7 +383,7 @@ function DocViewerContent({
|
|
|
292
383
|
</article>
|
|
293
384
|
</div>
|
|
294
385
|
|
|
295
|
-
{(isLoadingContent || isLoadingStructure) && (
|
|
386
|
+
{isMarkdownContent && (isLoadingContent || isLoadingStructure) && (
|
|
296
387
|
<div className="hidden lg:block">
|
|
297
388
|
<div className="sticky top-24">
|
|
298
389
|
<div className="h-[14px] w-28 bg-ods-border rounded animate-pulse mb-5" />
|
|
@@ -338,8 +429,9 @@ function DocViewerContent({
|
|
|
338
429
|
</div>
|
|
339
430
|
</div>
|
|
340
431
|
)}
|
|
341
|
-
|
|
432
|
+
</div>
|
|
433
|
+
</PageLayout>
|
|
342
434
|
</div>
|
|
343
|
-
</
|
|
435
|
+
</PageShell>
|
|
344
436
|
)
|
|
345
437
|
}
|