@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.
Files changed (276) hide show
  1. package/README.md +0 -9
  2. package/dist/chunk-26PKDALD.js +2379 -0
  3. package/dist/chunk-26PKDALD.js.map +1 -0
  4. package/dist/chunk-3MCHAFHB.js +89 -0
  5. package/dist/chunk-3MCHAFHB.js.map +1 -0
  6. package/dist/{chunk-PI4WSYQV.js → chunk-3ZXUQQL4.js} +2 -2
  7. package/dist/{chunk-WMSTJAZT.cjs → chunk-5E2HOSSH.cjs} +51 -913
  8. package/dist/chunk-5E2HOSSH.cjs.map +1 -0
  9. package/dist/{chunk-IL47XWV5.js → chunk-5P3B2LZW.js} +14 -8
  10. package/dist/{chunk-IL47XWV5.js.map → chunk-5P3B2LZW.js.map} +1 -1
  11. package/dist/chunk-66AANIOC.cjs +619 -0
  12. package/dist/chunk-66AANIOC.cjs.map +1 -0
  13. package/dist/{chunk-AD6C23QY.js → chunk-6GCI7JOE.js} +7 -8
  14. package/dist/{chunk-AD6C23QY.js.map → chunk-6GCI7JOE.js.map} +1 -1
  15. package/dist/chunk-6JINAOI7.cjs +311 -0
  16. package/dist/chunk-6JINAOI7.cjs.map +1 -0
  17. package/dist/{chunk-2QG57XOJ.js → chunk-7RIYT7ZH.js} +205 -1067
  18. package/dist/chunk-7RIYT7ZH.js.map +1 -0
  19. package/dist/{chunk-L6PSSIUQ.cjs → chunk-AQOWFSMB.cjs} +1 -1
  20. package/dist/chunk-AQOWFSMB.cjs.map +1 -0
  21. package/dist/chunk-BOCFIKYS.cjs +3009 -0
  22. package/dist/chunk-BOCFIKYS.cjs.map +1 -0
  23. package/dist/{chunk-54KNMC2R.cjs → chunk-D3LEFMOA.cjs} +3 -3
  24. package/dist/{chunk-54KNMC2R.cjs.map → chunk-D3LEFMOA.cjs.map} +1 -1
  25. package/dist/chunk-D652TJBQ.js +3009 -0
  26. package/dist/chunk-D652TJBQ.js.map +1 -0
  27. package/dist/{chunk-PWQUAVA3.js → chunk-E4XABBSU.js} +98 -338
  28. package/dist/chunk-E4XABBSU.js.map +1 -0
  29. package/dist/{chunk-JALO4TAZ.js → chunk-EL6QLAWX.js} +55 -357
  30. package/dist/chunk-EL6QLAWX.js.map +1 -0
  31. package/dist/{chunk-6C526VNN.cjs → chunk-EYEW6PTA.cjs} +118 -358
  32. package/dist/chunk-EYEW6PTA.cjs.map +1 -0
  33. package/dist/chunk-FQJK446R.js +1606 -0
  34. package/dist/chunk-FQJK446R.js.map +1 -0
  35. package/dist/{chunk-4PSQS3SW.cjs → chunk-GLLDTKZK.cjs} +9 -7
  36. package/dist/chunk-GLLDTKZK.cjs.map +1 -0
  37. package/dist/{chunk-FQOTC3UU.cjs → chunk-IE6OU3WQ.cjs} +16 -318
  38. package/dist/chunk-IE6OU3WQ.cjs.map +1 -0
  39. package/dist/chunk-J54Z3OCR.cjs +1606 -0
  40. package/dist/chunk-J54Z3OCR.cjs.map +1 -0
  41. package/dist/{chunk-PC746XCO.js → chunk-K2PFPBMF.js} +5563 -15048
  42. package/dist/chunk-K2PFPBMF.js.map +1 -0
  43. package/dist/chunk-KXCRGTRN.cjs +2379 -0
  44. package/dist/chunk-KXCRGTRN.cjs.map +1 -0
  45. package/dist/{chunk-IZ7JSBFP.js → chunk-LCNMR277.js} +1 -1
  46. package/dist/chunk-LCNMR277.js.map +1 -0
  47. package/dist/chunk-LFGGF7OT.cjs +449 -0
  48. package/dist/chunk-LFGGF7OT.cjs.map +1 -0
  49. package/dist/chunk-M2OCXTNT.js +311 -0
  50. package/dist/chunk-M2OCXTNT.js.map +1 -0
  51. package/dist/{chunk-L7ULJKG7.js → chunk-MBFWU2EM.js} +10 -6
  52. package/dist/{chunk-L7ULJKG7.js.map → chunk-MBFWU2EM.js.map} +1 -1
  53. package/dist/chunk-ME4EVDFP.js +619 -0
  54. package/dist/chunk-ME4EVDFP.js.map +1 -0
  55. package/dist/chunk-OQ6X7ZOC.js +449 -0
  56. package/dist/chunk-OQ6X7ZOC.js.map +1 -0
  57. package/dist/{chunk-4TLE6VLU.js → chunk-OY7OF7E7.js} +24 -30
  58. package/dist/chunk-OY7OF7E7.js.map +1 -0
  59. package/dist/chunk-POKKCWKF.js +354 -0
  60. package/dist/chunk-POKKCWKF.js.map +1 -0
  61. package/dist/{chunk-GUTS7HGA.cjs → chunk-QHIXS3W2.cjs} +2514 -11999
  62. package/dist/chunk-QHIXS3W2.cjs.map +1 -0
  63. package/dist/chunk-TFSYSWPS.cjs +89 -0
  64. package/dist/chunk-TFSYSWPS.cjs.map +1 -0
  65. package/dist/{chunk-53FUMSZ5.cjs → chunk-W6M2FLLT.cjs} +46 -40
  66. package/dist/chunk-W6M2FLLT.cjs.map +1 -0
  67. package/dist/{chunk-3JIQVE7T.js → chunk-WHMATDVP.js} +15 -9
  68. package/dist/{chunk-3JIQVE7T.js.map → chunk-WHMATDVP.js.map} +1 -1
  69. package/dist/{chunk-YBYI62OE.cjs → chunk-X647HY3F.cjs} +37 -33
  70. package/dist/chunk-X647HY3F.cjs.map +1 -0
  71. package/dist/{chunk-UNVE2SDJ.cjs → chunk-X6BV7MB7.cjs} +31 -37
  72. package/dist/chunk-X6BV7MB7.cjs.map +1 -0
  73. package/dist/{chunk-7OVGB2DQ.cjs → chunk-XREEV72C.cjs} +25 -19
  74. package/dist/chunk-XREEV72C.cjs.map +1 -0
  75. package/dist/chunk-YETA25JW.cjs +354 -0
  76. package/dist/chunk-YETA25JW.cjs.map +1 -0
  77. package/dist/{chunk-FCDQNTDG.cjs → chunk-YIGPRLQY.cjs} +20 -21
  78. package/dist/chunk-YIGPRLQY.cjs.map +1 -0
  79. package/dist/{chunk-X4DOXQRT.js → chunk-ZP4AVIZP.js} +6 -4
  80. package/dist/{chunk-X4DOXQRT.js.map → chunk-ZP4AVIZP.js.map} +1 -1
  81. package/dist/components/chat/index.cjs +18 -8
  82. package/dist/components/chat/index.cjs.map +1 -1
  83. package/dist/components/chat/index.js +85 -75
  84. package/dist/components/contact/index.cjs +15 -8
  85. package/dist/components/contact/index.cjs.map +1 -1
  86. package/dist/components/contact/index.js +14 -7
  87. package/dist/components/docs/doc-viewer.d.ts +2 -39
  88. package/dist/components/docs/doc-viewer.d.ts.map +1 -1
  89. package/dist/components/docs/index.cjs +9 -17
  90. package/dist/components/docs/index.cjs.map +1 -1
  91. package/dist/components/docs/index.d.ts +0 -4
  92. package/dist/components/docs/index.d.ts.map +1 -1
  93. package/dist/components/docs/index.js +8 -16
  94. package/dist/components/docs/use-document-tree.d.ts.map +1 -1
  95. package/dist/components/embeds/embed-iframe.d.ts.map +1 -1
  96. package/dist/components/embeds/index.cjs +15 -38
  97. package/dist/components/embeds/index.cjs.map +1 -1
  98. package/dist/components/embeds/index.d.ts +0 -8
  99. package/dist/components/embeds/index.d.ts.map +1 -1
  100. package/dist/components/embeds/index.js +17 -40
  101. package/dist/components/faq/index.cjs +16 -9
  102. package/dist/components/faq/index.cjs.map +1 -1
  103. package/dist/components/faq/index.js +15 -8
  104. package/dist/components/features/index.cjs +16 -8
  105. package/dist/components/features/index.cjs.map +1 -1
  106. package/dist/components/features/index.js +32 -24
  107. package/dist/components/index.cjs +452 -257
  108. package/dist/components/index.cjs.map +1 -1
  109. package/dist/components/index.js +976 -781
  110. package/dist/components/index.js.map +1 -1
  111. package/dist/components/layout/page-layout.d.ts +1 -10
  112. package/dist/components/layout/page-layout.d.ts.map +1 -1
  113. package/dist/components/layout/title-block.d.ts +1 -17
  114. package/dist/components/layout/title-block.d.ts.map +1 -1
  115. package/dist/components/navigation/index.cjs +15 -7
  116. package/dist/components/navigation/index.cjs.map +1 -1
  117. package/dist/components/navigation/index.js +17 -9
  118. package/dist/components/onboarding-guides/index.cjs +36 -35
  119. package/dist/components/onboarding-guides/index.cjs.map +1 -1
  120. package/dist/components/onboarding-guides/index.js +14 -13
  121. package/dist/components/onboarding-guides/index.js.map +1 -1
  122. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts +1 -1
  123. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  124. package/dist/components/related-content/index.cjs +16 -9
  125. package/dist/components/related-content/index.cjs.map +1 -1
  126. package/dist/components/related-content/index.js +15 -8
  127. package/dist/components/shared/dev-section/dev-section-page.d.ts +0 -9
  128. package/dist/components/shared/dev-section/dev-section-page.d.ts.map +1 -1
  129. package/dist/components/shared/dev-section/dev-section-view.d.ts.map +1 -1
  130. package/dist/components/shared/dev-section/index.d.ts +1 -1
  131. package/dist/components/shared/dev-section/index.d.ts.map +1 -1
  132. package/dist/components/shared/doc-search/use-doc-search.d.ts.map +1 -1
  133. package/dist/components/shared/legal-document/legal-document-page.d.ts.map +1 -1
  134. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  135. package/dist/components/tickets/index.cjs +112 -100
  136. package/dist/components/tickets/index.cjs.map +1 -1
  137. package/dist/components/tickets/index.js +32 -20
  138. package/dist/components/tickets/index.js.map +1 -1
  139. package/dist/components/ui/file-manager/index.cjs +52 -50
  140. package/dist/components/ui/file-manager/index.cjs.map +1 -1
  141. package/dist/components/ui/file-manager/index.js +6 -4
  142. package/dist/components/ui/file-manager/index.js.map +1 -1
  143. package/dist/components/ui/index.cjs +19 -13
  144. package/dist/components/ui/index.cjs.map +1 -1
  145. package/dist/components/ui/index.d.ts +0 -2
  146. package/dist/components/ui/index.d.ts.map +1 -1
  147. package/dist/components/ui/index.js +139 -133
  148. package/dist/components/ui/release-changelog-section.d.ts +2 -6
  149. package/dist/components/ui/release-changelog-section.d.ts.map +1 -1
  150. package/dist/components/ui/simple-markdown-renderer.d.ts +8 -2
  151. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
  152. package/dist/contexts/chat-runtime-context.d.ts +0 -14
  153. package/dist/contexts/chat-runtime-context.d.ts.map +1 -1
  154. package/dist/contexts/index.cjs +3 -3
  155. package/dist/contexts/index.js +5 -5
  156. package/dist/embed-shims/index.cjs +3 -3
  157. package/dist/embed-shims/index.cjs.map +1 -1
  158. package/dist/embed-shims/index.js +4 -4
  159. package/dist/hooks/index.cjs +9 -4
  160. package/dist/hooks/index.cjs.map +1 -1
  161. package/dist/hooks/index.js +11 -6
  162. package/dist/index.cjs +20 -14
  163. package/dist/index.cjs.map +1 -1
  164. package/dist/index.js +364 -358
  165. package/dist/types/doc-source.d.ts +1 -31
  166. package/dist/types/doc-source.d.ts.map +1 -1
  167. package/dist/utils/index.cjs +0 -4
  168. package/dist/utils/index.cjs.map +1 -1
  169. package/dist/utils/index.d.ts +0 -1
  170. package/dist/utils/index.d.ts.map +1 -1
  171. package/dist/utils/index.js +1 -4
  172. package/dist/utils/index.js.map +1 -1
  173. package/package.json +1 -7
  174. package/src/components/chat/embeddable-chat.tsx +1 -1
  175. package/src/components/docs/doc-viewer.tsx +19 -111
  176. package/src/components/docs/index.ts +0 -17
  177. package/src/components/docs/use-document-tree.ts +0 -21
  178. package/src/components/embeds/embed-iframe.tsx +9 -7
  179. package/src/components/embeds/index.ts +0 -30
  180. package/src/components/embeds/og-link-preview.tsx +13 -13
  181. package/src/components/layout/page-layout.tsx +1 -14
  182. package/src/components/layout/title-block.tsx +62 -40
  183. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +3 -3
  184. package/src/components/shared/dev-section/dev-section-page.tsx +1 -9
  185. package/src/components/shared/dev-section/dev-section-view.tsx +9 -14
  186. package/src/components/shared/dev-section/index.ts +1 -1
  187. package/src/components/shared/doc-search/use-doc-search.ts +3 -7
  188. package/src/components/shared/legal-document/legal-document-page.tsx +2 -2
  189. package/src/components/shared/product-release/release-detail-page.tsx +4 -6
  190. package/src/components/ui/index.ts +0 -2
  191. package/src/components/ui/release-changelog-section.tsx +2 -7
  192. package/src/components/ui/simple-markdown-renderer.tsx +11 -7
  193. package/src/contexts/chat-runtime-context.tsx +0 -14
  194. package/src/types/doc-source.ts +1 -33
  195. package/src/utils/index.ts +0 -1
  196. package/dist/chunk-2QG57XOJ.js.map +0 -1
  197. package/dist/chunk-4PSQS3SW.cjs.map +0 -1
  198. package/dist/chunk-4TLE6VLU.js.map +0 -1
  199. package/dist/chunk-53FUMSZ5.cjs.map +0 -1
  200. package/dist/chunk-6C526VNN.cjs.map +0 -1
  201. package/dist/chunk-7OVGB2DQ.cjs.map +0 -1
  202. package/dist/chunk-F5OB2YAL.cjs +0 -144
  203. package/dist/chunk-F5OB2YAL.cjs.map +0 -1
  204. package/dist/chunk-FBWXMMRB.cjs +0 -2
  205. package/dist/chunk-FBWXMMRB.cjs.map +0 -1
  206. package/dist/chunk-FCDQNTDG.cjs.map +0 -1
  207. package/dist/chunk-FQOTC3UU.cjs.map +0 -1
  208. package/dist/chunk-GUTS7HGA.cjs.map +0 -1
  209. package/dist/chunk-GZ4C3XW6.js +0 -2
  210. package/dist/chunk-GZ4C3XW6.js.map +0 -1
  211. package/dist/chunk-IZ7JSBFP.js.map +0 -1
  212. package/dist/chunk-JALO4TAZ.js.map +0 -1
  213. package/dist/chunk-L6PSSIUQ.cjs.map +0 -1
  214. package/dist/chunk-PC746XCO.js.map +0 -1
  215. package/dist/chunk-PWQUAVA3.js.map +0 -1
  216. package/dist/chunk-SA2WPJVO.js +0 -144
  217. package/dist/chunk-SA2WPJVO.js.map +0 -1
  218. package/dist/chunk-UNVE2SDJ.cjs.map +0 -1
  219. package/dist/chunk-WMSTJAZT.cjs.map +0 -1
  220. package/dist/chunk-YBYI62OE.cjs.map +0 -1
  221. package/dist/components/case-studies/index.cjs +0 -126
  222. package/dist/components/case-studies/index.cjs.map +0 -1
  223. package/dist/components/case-studies/index.d.ts +0 -2
  224. package/dist/components/case-studies/index.d.ts.map +0 -1
  225. package/dist/components/case-studies/index.js +0 -126
  226. package/dist/components/case-studies/index.js.map +0 -1
  227. package/dist/components/case-studies/share-experience-section.d.ts +0 -48
  228. package/dist/components/case-studies/share-experience-section.d.ts.map +0 -1
  229. package/dist/components/docs/docs-hub-page.d.ts +0 -46
  230. package/dist/components/docs/docs-hub-page.d.ts.map +0 -1
  231. package/dist/components/docs/skeletons.d.ts +0 -32
  232. package/dist/components/docs/skeletons.d.ts.map +0 -1
  233. package/dist/components/docs/use-docs-resolve-link.d.ts +0 -20
  234. package/dist/components/docs/use-docs-resolve-link.d.ts.map +0 -1
  235. package/dist/components/embeds/embed-container.d.ts +0 -37
  236. package/dist/components/embeds/embed-container.d.ts.map +0 -1
  237. package/dist/components/embeds/file-download-card.d.ts +0 -18
  238. package/dist/components/embeds/file-download-card.d.ts.map +0 -1
  239. package/dist/components/embeds/linkedin-embed-client.d.ts +0 -8
  240. package/dist/components/embeds/linkedin-embed-client.d.ts.map +0 -1
  241. package/dist/components/embeds/markdown-image.d.ts +0 -5
  242. package/dist/components/embeds/markdown-image.d.ts.map +0 -1
  243. package/dist/components/embeds/reddit-embed-client.d.ts +0 -7
  244. package/dist/components/embeds/reddit-embed-client.d.ts.map +0 -1
  245. package/dist/components/embeds/rich-markdown-runtime.d.ts +0 -46
  246. package/dist/components/embeds/rich-markdown-runtime.d.ts.map +0 -1
  247. package/dist/components/embeds/twitter-embed-client.d.ts +0 -8
  248. package/dist/components/embeds/twitter-embed-client.d.ts.map +0 -1
  249. package/dist/components/layout/page-header.d.ts +0 -78
  250. package/dist/components/layout/page-header.d.ts.map +0 -1
  251. package/dist/components/layout/page-with-header.d.ts +0 -67
  252. package/dist/components/layout/page-with-header.d.ts.map +0 -1
  253. package/dist/components/ui/rich-markdown-renderer.d.ts +0 -34
  254. package/dist/components/ui/rich-markdown-renderer.d.ts.map +0 -1
  255. package/dist/utils/page-header-constants.d.ts +0 -15
  256. package/dist/utils/page-header-constants.d.ts.map +0 -1
  257. package/dist/utils/social-embed-cache.d.ts +0 -29
  258. package/dist/utils/social-embed-cache.d.ts.map +0 -1
  259. package/src/components/case-studies/index.ts +0 -4
  260. package/src/components/case-studies/share-experience-section.tsx +0 -185
  261. package/src/components/docs/docs-hub-page.tsx +0 -149
  262. package/src/components/docs/skeletons.tsx +0 -138
  263. package/src/components/docs/use-docs-resolve-link.ts +0 -52
  264. package/src/components/embeds/embed-container.tsx +0 -80
  265. package/src/components/embeds/file-download-card.tsx +0 -54
  266. package/src/components/embeds/linkedin-embed-client.tsx +0 -100
  267. package/src/components/embeds/markdown-image.tsx +0 -88
  268. package/src/components/embeds/reddit-embed-client.tsx +0 -550
  269. package/src/components/embeds/rich-markdown-runtime.tsx +0 -79
  270. package/src/components/embeds/twitter-embed-client.tsx +0 -308
  271. package/src/components/layout/page-header.tsx +0 -182
  272. package/src/components/layout/page-with-header.tsx +0 -110
  273. package/src/components/ui/rich-markdown-renderer.tsx +0 -1203
  274. package/src/utils/page-header-constants.ts +0 -15
  275. package/src/utils/social-embed-cache.ts +0 -391
  276. /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-snapshot.20260621021605",
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:'openframe').
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 { 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"
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/docs/resolve-link` POSTs.
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
- /** 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
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, resolveLink])
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
- // 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
- />
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
- // "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)
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
- {isMarkdownContent && (isLoadingContent || isLoadingStructure) && (
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
- </div>
433
- </PageLayout>
341
+ </div>
434
342
  </div>
435
- </PageShell>
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 — clean iframe-sized rectangle.
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-card animate-pulse"
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-border animate-pulse" />
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-border rounded animate-pulse h-4 w-3/4 mb-2" />
268
- <div className="bg-ods-border rounded animate-pulse h-3 w-full mb-1" />
269
- <div className="bg-ods-border rounded animate-pulse h-3 w-2/3 mb-2" />
270
- <div className="bg-ods-border rounded animate-pulse h-3 w-1/3" />
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-border overflow-hidden relative animate-pulse" />
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-border rounded flex-shrink-0 mt-0.5 animate-pulse" />
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-border rounded animate-pulse" style={{ height: '1.25rem', marginBottom: '0.25rem' }} />
284
- <div className="bg-ods-border rounded animate-pulse w-3/4" style={{ height: '1.25rem' }} />
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-border rounded animate-pulse" style={{ height: '1.25rem', marginBottom: '0.25rem' }} />
288
- <div className="bg-ods-border rounded animate-pulse w-5/6" style={{ height: '1.25rem' }} />
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-border rounded animate-pulse" style={{ height: '0.75rem', width: '6rem' }} />
292
- <div className="bg-ods-border rounded animate-pulse" style={{ height: '0.75rem', width: '5rem' }} />
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 || titleIcon || image || backButton || hasActions || selector)
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 { PageHeader } from './page-header'
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
- <PageHeader
72
- title={title}
73
- titleIcon={titleIcon}
74
- subtitle={subtitle}
75
- accentDot={accentDot}
76
- image={image}
77
- backButton={backButton}
78
- actions={actionsNode}
79
- variant={variant}
80
- className={className}
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 { RichMarkdownRenderer } from '../ui/rich-markdown-renderer'
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
- * `<RichMarkdownRenderer>`. */
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 = RichMarkdownRenderer,
86
+ MarkdownRenderer = SimpleMarkdownRenderer,
87
87
  renderRelatedCard,
88
88
  backHref,
89
89
  backLabel = 'Back to Getting Started',