@flamingo-stack/openframe-frontend-core 0.0.296 → 0.0.297

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 +9 -0
  2. package/dist/{chunk-7RIYT7ZH.js → chunk-2QG57XOJ.js} +1067 -205
  3. package/dist/chunk-2QG57XOJ.js.map +1 -0
  4. package/dist/{chunk-WHMATDVP.js → chunk-3JIQVE7T.js} +9 -15
  5. package/dist/{chunk-WHMATDVP.js.map → chunk-3JIQVE7T.js.map} +1 -1
  6. package/dist/{chunk-GLLDTKZK.cjs → chunk-4PSQS3SW.cjs} +7 -9
  7. package/dist/chunk-4PSQS3SW.cjs.map +1 -0
  8. package/dist/{chunk-OY7OF7E7.js → chunk-4TLE6VLU.js} +30 -24
  9. package/dist/chunk-4TLE6VLU.js.map +1 -0
  10. package/dist/{chunk-W6M2FLLT.cjs → chunk-53FUMSZ5.cjs} +40 -46
  11. package/dist/chunk-53FUMSZ5.cjs.map +1 -0
  12. package/dist/{chunk-D3LEFMOA.cjs → chunk-54KNMC2R.cjs} +3 -3
  13. package/dist/{chunk-D3LEFMOA.cjs.map → chunk-54KNMC2R.cjs.map} +1 -1
  14. package/dist/{chunk-EYEW6PTA.cjs → chunk-6C526VNN.cjs} +358 -118
  15. package/dist/chunk-6C526VNN.cjs.map +1 -0
  16. package/dist/{chunk-XREEV72C.cjs → chunk-7OVGB2DQ.cjs} +19 -25
  17. package/dist/chunk-7OVGB2DQ.cjs.map +1 -0
  18. package/dist/{chunk-6GCI7JOE.js → chunk-AD6C23QY.js} +8 -7
  19. package/dist/{chunk-6GCI7JOE.js.map → chunk-AD6C23QY.js.map} +1 -1
  20. package/dist/chunk-F5OB2YAL.cjs +144 -0
  21. package/dist/chunk-F5OB2YAL.cjs.map +1 -0
  22. package/dist/chunk-FBWXMMRB.cjs +2 -0
  23. package/dist/chunk-FBWXMMRB.cjs.map +1 -0
  24. package/dist/{chunk-YIGPRLQY.cjs → chunk-FCDQNTDG.cjs} +21 -20
  25. package/dist/chunk-FCDQNTDG.cjs.map +1 -0
  26. package/dist/{chunk-IE6OU3WQ.cjs → chunk-FQOTC3UU.cjs} +318 -16
  27. package/dist/chunk-FQOTC3UU.cjs.map +1 -0
  28. package/dist/{chunk-QHIXS3W2.cjs → chunk-GUTS7HGA.cjs} +11590 -2105
  29. package/dist/chunk-GUTS7HGA.cjs.map +1 -0
  30. package/dist/chunk-GZ4C3XW6.js +2 -0
  31. package/dist/chunk-GZ4C3XW6.js.map +1 -0
  32. package/dist/{chunk-5P3B2LZW.js → chunk-IL47XWV5.js} +8 -14
  33. package/dist/{chunk-5P3B2LZW.js.map → chunk-IL47XWV5.js.map} +1 -1
  34. package/dist/{chunk-LCNMR277.js → chunk-IZ7JSBFP.js} +1 -1
  35. package/dist/chunk-IZ7JSBFP.js.map +1 -0
  36. package/dist/{chunk-EL6QLAWX.js → chunk-JALO4TAZ.js} +357 -55
  37. package/dist/chunk-JALO4TAZ.js.map +1 -0
  38. package/dist/{chunk-AQOWFSMB.cjs → chunk-L6PSSIUQ.cjs} +1 -1
  39. package/dist/chunk-L6PSSIUQ.cjs.map +1 -0
  40. package/dist/{chunk-MBFWU2EM.js → chunk-L7ULJKG7.js} +6 -10
  41. package/dist/{chunk-MBFWU2EM.js.map → chunk-L7ULJKG7.js.map} +1 -1
  42. package/dist/{chunk-K2PFPBMF.js → chunk-PC746XCO.js} +15050 -5565
  43. package/dist/chunk-PC746XCO.js.map +1 -0
  44. package/dist/{chunk-3ZXUQQL4.js → chunk-PI4WSYQV.js} +2 -2
  45. package/dist/{chunk-E4XABBSU.js → chunk-PWQUAVA3.js} +338 -98
  46. package/dist/chunk-PWQUAVA3.js.map +1 -0
  47. package/dist/chunk-SA2WPJVO.js +144 -0
  48. package/dist/chunk-SA2WPJVO.js.map +1 -0
  49. package/dist/{chunk-X6BV7MB7.cjs → chunk-UNVE2SDJ.cjs} +37 -31
  50. package/dist/chunk-UNVE2SDJ.cjs.map +1 -0
  51. package/dist/{chunk-5E2HOSSH.cjs → chunk-WMSTJAZT.cjs} +913 -51
  52. package/dist/chunk-WMSTJAZT.cjs.map +1 -0
  53. package/dist/{chunk-ZP4AVIZP.js → chunk-X4DOXQRT.js} +4 -6
  54. package/dist/{chunk-ZP4AVIZP.js.map → chunk-X4DOXQRT.js.map} +1 -1
  55. package/dist/{chunk-X647HY3F.cjs → chunk-YBYI62OE.cjs} +33 -37
  56. package/dist/chunk-YBYI62OE.cjs.map +1 -0
  57. package/dist/components/case-studies/index.cjs +126 -0
  58. package/dist/components/case-studies/index.cjs.map +1 -0
  59. package/dist/components/case-studies/index.d.ts +2 -0
  60. package/dist/components/case-studies/index.d.ts.map +1 -0
  61. package/dist/components/case-studies/index.js +126 -0
  62. package/dist/components/case-studies/index.js.map +1 -0
  63. package/dist/components/case-studies/share-experience-section.d.ts +48 -0
  64. package/dist/components/case-studies/share-experience-section.d.ts.map +1 -0
  65. package/dist/components/chat/index.cjs +8 -18
  66. package/dist/components/chat/index.cjs.map +1 -1
  67. package/dist/components/chat/index.js +75 -85
  68. package/dist/components/contact/index.cjs +8 -15
  69. package/dist/components/contact/index.cjs.map +1 -1
  70. package/dist/components/contact/index.js +7 -14
  71. package/dist/components/docs/doc-viewer.d.ts +39 -2
  72. package/dist/components/docs/doc-viewer.d.ts.map +1 -1
  73. package/dist/components/docs/docs-hub-page.d.ts +46 -0
  74. package/dist/components/docs/docs-hub-page.d.ts.map +1 -0
  75. package/dist/components/docs/index.cjs +17 -9
  76. package/dist/components/docs/index.cjs.map +1 -1
  77. package/dist/components/docs/index.d.ts +4 -0
  78. package/dist/components/docs/index.d.ts.map +1 -1
  79. package/dist/components/docs/index.js +16 -8
  80. package/dist/components/docs/skeletons.d.ts +32 -0
  81. package/dist/components/docs/skeletons.d.ts.map +1 -0
  82. package/dist/components/docs/use-docs-resolve-link.d.ts +20 -0
  83. package/dist/components/docs/use-docs-resolve-link.d.ts.map +1 -0
  84. package/dist/components/docs/use-document-tree.d.ts.map +1 -1
  85. package/dist/components/embeds/embed-container.d.ts +37 -0
  86. package/dist/components/embeds/embed-container.d.ts.map +1 -0
  87. package/dist/components/embeds/embed-iframe.d.ts.map +1 -1
  88. package/dist/components/embeds/file-download-card.d.ts +18 -0
  89. package/dist/components/embeds/file-download-card.d.ts.map +1 -0
  90. package/dist/components/embeds/index.cjs +38 -15
  91. package/dist/components/embeds/index.cjs.map +1 -1
  92. package/dist/components/embeds/index.d.ts +8 -0
  93. package/dist/components/embeds/index.d.ts.map +1 -1
  94. package/dist/components/embeds/index.js +40 -17
  95. package/dist/components/embeds/linkedin-embed-client.d.ts +8 -0
  96. package/dist/components/embeds/linkedin-embed-client.d.ts.map +1 -0
  97. package/dist/components/embeds/markdown-image.d.ts +5 -0
  98. package/dist/components/embeds/markdown-image.d.ts.map +1 -0
  99. package/dist/components/embeds/reddit-embed-client.d.ts +7 -0
  100. package/dist/components/embeds/reddit-embed-client.d.ts.map +1 -0
  101. package/dist/components/embeds/rich-markdown-runtime.d.ts +46 -0
  102. package/dist/components/embeds/rich-markdown-runtime.d.ts.map +1 -0
  103. package/dist/components/embeds/twitter-embed-client.d.ts +8 -0
  104. package/dist/components/embeds/twitter-embed-client.d.ts.map +1 -0
  105. package/dist/components/faq/index.cjs +9 -16
  106. package/dist/components/faq/index.cjs.map +1 -1
  107. package/dist/components/faq/index.js +8 -15
  108. package/dist/components/features/index.cjs +8 -16
  109. package/dist/components/features/index.cjs.map +1 -1
  110. package/dist/components/features/index.js +24 -32
  111. package/dist/components/index.cjs +257 -452
  112. package/dist/components/index.cjs.map +1 -1
  113. package/dist/components/index.js +781 -976
  114. package/dist/components/index.js.map +1 -1
  115. package/dist/components/layout/page-header.d.ts +78 -0
  116. package/dist/components/layout/page-header.d.ts.map +1 -0
  117. package/dist/components/layout/page-layout.d.ts +10 -1
  118. package/dist/components/layout/page-layout.d.ts.map +1 -1
  119. package/dist/components/layout/page-with-header.d.ts +67 -0
  120. package/dist/components/layout/page-with-header.d.ts.map +1 -0
  121. package/dist/components/layout/title-block.d.ts +17 -1
  122. package/dist/components/layout/title-block.d.ts.map +1 -1
  123. package/dist/components/navigation/index.cjs +7 -15
  124. package/dist/components/navigation/index.cjs.map +1 -1
  125. package/dist/components/navigation/index.js +9 -17
  126. package/dist/components/onboarding-guides/index.cjs +35 -36
  127. package/dist/components/onboarding-guides/index.cjs.map +1 -1
  128. package/dist/components/onboarding-guides/index.js +13 -14
  129. package/dist/components/onboarding-guides/index.js.map +1 -1
  130. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts +1 -1
  131. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  132. package/dist/components/related-content/index.cjs +9 -16
  133. package/dist/components/related-content/index.cjs.map +1 -1
  134. package/dist/components/related-content/index.js +8 -15
  135. package/dist/components/shared/dev-section/dev-section-page.d.ts +9 -0
  136. package/dist/components/shared/dev-section/dev-section-page.d.ts.map +1 -1
  137. package/dist/components/shared/dev-section/dev-section-view.d.ts.map +1 -1
  138. package/dist/components/shared/dev-section/index.d.ts +1 -1
  139. package/dist/components/shared/dev-section/index.d.ts.map +1 -1
  140. package/dist/components/shared/doc-search/use-doc-search.d.ts.map +1 -1
  141. package/dist/components/shared/legal-document/legal-document-page.d.ts.map +1 -1
  142. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  143. package/dist/components/tickets/index.cjs +100 -112
  144. package/dist/components/tickets/index.cjs.map +1 -1
  145. package/dist/components/tickets/index.js +20 -32
  146. package/dist/components/tickets/index.js.map +1 -1
  147. package/dist/components/ui/file-manager/index.cjs +50 -52
  148. package/dist/components/ui/file-manager/index.cjs.map +1 -1
  149. package/dist/components/ui/file-manager/index.js +4 -6
  150. package/dist/components/ui/file-manager/index.js.map +1 -1
  151. package/dist/components/ui/index.cjs +13 -19
  152. package/dist/components/ui/index.cjs.map +1 -1
  153. package/dist/components/ui/index.d.ts +2 -0
  154. package/dist/components/ui/index.d.ts.map +1 -1
  155. package/dist/components/ui/index.js +133 -139
  156. package/dist/components/ui/release-changelog-section.d.ts +6 -2
  157. package/dist/components/ui/release-changelog-section.d.ts.map +1 -1
  158. package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
  159. package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
  160. package/dist/components/ui/simple-markdown-renderer.d.ts +2 -8
  161. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
  162. package/dist/contexts/chat-runtime-context.d.ts +14 -0
  163. package/dist/contexts/chat-runtime-context.d.ts.map +1 -1
  164. package/dist/contexts/index.cjs +3 -3
  165. package/dist/contexts/index.js +5 -5
  166. package/dist/embed-shims/index.cjs +3 -3
  167. package/dist/embed-shims/index.cjs.map +1 -1
  168. package/dist/embed-shims/index.js +4 -4
  169. package/dist/hooks/index.cjs +4 -9
  170. package/dist/hooks/index.cjs.map +1 -1
  171. package/dist/hooks/index.js +6 -11
  172. package/dist/index.cjs +14 -20
  173. package/dist/index.cjs.map +1 -1
  174. package/dist/index.js +362 -368
  175. package/dist/types/doc-source.d.ts +31 -1
  176. package/dist/types/doc-source.d.ts.map +1 -1
  177. package/dist/utils/index.cjs +4 -0
  178. package/dist/utils/index.cjs.map +1 -1
  179. package/dist/utils/index.d.ts +1 -0
  180. package/dist/utils/index.d.ts.map +1 -1
  181. package/dist/utils/index.js +4 -1
  182. package/dist/utils/index.js.map +1 -1
  183. package/dist/utils/page-header-constants.d.ts +15 -0
  184. package/dist/utils/page-header-constants.d.ts.map +1 -0
  185. package/dist/utils/social-embed-cache.d.ts +29 -0
  186. package/dist/utils/social-embed-cache.d.ts.map +1 -0
  187. package/package.json +7 -1
  188. package/src/components/case-studies/index.ts +4 -0
  189. package/src/components/case-studies/share-experience-section.tsx +185 -0
  190. package/src/components/chat/embeddable-chat.tsx +1 -1
  191. package/src/components/docs/doc-viewer.tsx +111 -19
  192. package/src/components/docs/docs-hub-page.tsx +149 -0
  193. package/src/components/docs/index.ts +17 -0
  194. package/src/components/docs/skeletons.tsx +138 -0
  195. package/src/components/docs/use-docs-resolve-link.ts +52 -0
  196. package/src/components/docs/use-document-tree.ts +21 -0
  197. package/src/components/embeds/embed-container.tsx +80 -0
  198. package/src/components/embeds/embed-iframe.tsx +7 -9
  199. package/src/components/embeds/file-download-card.tsx +54 -0
  200. package/src/components/embeds/index.ts +30 -0
  201. package/src/components/embeds/linkedin-embed-client.tsx +100 -0
  202. package/src/components/embeds/markdown-image.tsx +88 -0
  203. package/src/components/embeds/og-link-preview.tsx +13 -13
  204. package/src/components/embeds/reddit-embed-client.tsx +550 -0
  205. package/src/components/embeds/rich-markdown-runtime.tsx +79 -0
  206. package/src/components/embeds/twitter-embed-client.tsx +308 -0
  207. package/src/components/layout/page-header.tsx +182 -0
  208. package/src/components/layout/page-layout.tsx +14 -1
  209. package/src/components/layout/page-with-header.tsx +110 -0
  210. package/src/components/layout/title-block.tsx +40 -62
  211. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +3 -3
  212. package/src/components/shared/dev-section/dev-section-page.tsx +9 -1
  213. package/src/components/shared/dev-section/dev-section-view.tsx +14 -9
  214. package/src/components/shared/dev-section/index.ts +1 -1
  215. package/src/components/shared/doc-search/use-doc-search.ts +7 -3
  216. package/src/components/shared/legal-document/legal-document-page.tsx +2 -2
  217. package/src/components/shared/product-release/release-detail-page.tsx +6 -4
  218. package/src/components/ui/index.ts +2 -0
  219. package/src/components/ui/release-changelog-section.tsx +7 -2
  220. package/src/components/ui/rich-markdown-renderer.tsx +1203 -0
  221. package/src/components/ui/simple-markdown-renderer.tsx +7 -11
  222. package/src/contexts/chat-runtime-context.tsx +14 -0
  223. package/src/types/doc-source.ts +33 -1
  224. package/src/utils/index.ts +1 -0
  225. package/src/utils/page-header-constants.ts +15 -0
  226. package/src/utils/social-embed-cache.ts +391 -0
  227. package/dist/chunk-26PKDALD.js +0 -2379
  228. package/dist/chunk-26PKDALD.js.map +0 -1
  229. package/dist/chunk-3MCHAFHB.js +0 -89
  230. package/dist/chunk-3MCHAFHB.js.map +0 -1
  231. package/dist/chunk-5E2HOSSH.cjs.map +0 -1
  232. package/dist/chunk-66AANIOC.cjs +0 -619
  233. package/dist/chunk-66AANIOC.cjs.map +0 -1
  234. package/dist/chunk-6JINAOI7.cjs +0 -311
  235. package/dist/chunk-6JINAOI7.cjs.map +0 -1
  236. package/dist/chunk-7RIYT7ZH.js.map +0 -1
  237. package/dist/chunk-AQOWFSMB.cjs.map +0 -1
  238. package/dist/chunk-BOCFIKYS.cjs +0 -3009
  239. package/dist/chunk-BOCFIKYS.cjs.map +0 -1
  240. package/dist/chunk-D652TJBQ.js +0 -3009
  241. package/dist/chunk-D652TJBQ.js.map +0 -1
  242. package/dist/chunk-E4XABBSU.js.map +0 -1
  243. package/dist/chunk-EL6QLAWX.js.map +0 -1
  244. package/dist/chunk-EYEW6PTA.cjs.map +0 -1
  245. package/dist/chunk-FQJK446R.js +0 -1606
  246. package/dist/chunk-FQJK446R.js.map +0 -1
  247. package/dist/chunk-GLLDTKZK.cjs.map +0 -1
  248. package/dist/chunk-IE6OU3WQ.cjs.map +0 -1
  249. package/dist/chunk-J54Z3OCR.cjs +0 -1606
  250. package/dist/chunk-J54Z3OCR.cjs.map +0 -1
  251. package/dist/chunk-K2PFPBMF.js.map +0 -1
  252. package/dist/chunk-KXCRGTRN.cjs +0 -2379
  253. package/dist/chunk-KXCRGTRN.cjs.map +0 -1
  254. package/dist/chunk-LCNMR277.js.map +0 -1
  255. package/dist/chunk-LFGGF7OT.cjs +0 -449
  256. package/dist/chunk-LFGGF7OT.cjs.map +0 -1
  257. package/dist/chunk-M2OCXTNT.js +0 -311
  258. package/dist/chunk-M2OCXTNT.js.map +0 -1
  259. package/dist/chunk-ME4EVDFP.js +0 -619
  260. package/dist/chunk-ME4EVDFP.js.map +0 -1
  261. package/dist/chunk-OQ6X7ZOC.js +0 -449
  262. package/dist/chunk-OQ6X7ZOC.js.map +0 -1
  263. package/dist/chunk-OY7OF7E7.js.map +0 -1
  264. package/dist/chunk-POKKCWKF.js +0 -354
  265. package/dist/chunk-POKKCWKF.js.map +0 -1
  266. package/dist/chunk-QHIXS3W2.cjs.map +0 -1
  267. package/dist/chunk-TFSYSWPS.cjs +0 -89
  268. package/dist/chunk-TFSYSWPS.cjs.map +0 -1
  269. package/dist/chunk-W6M2FLLT.cjs.map +0 -1
  270. package/dist/chunk-X647HY3F.cjs.map +0 -1
  271. package/dist/chunk-X6BV7MB7.cjs.map +0 -1
  272. package/dist/chunk-XREEV72C.cjs.map +0 -1
  273. package/dist/chunk-YETA25JW.cjs +0 -354
  274. package/dist/chunk-YETA25JW.cjs.map +0 -1
  275. package/dist/chunk-YIGPRLQY.cjs.map +0 -1
  276. /package/dist/{chunk-3ZXUQQL4.js.map → chunk-PI4WSYQV.js.map} +0 -0
@@ -1,15 +1,29 @@
1
1
  'use client'
2
2
 
3
3
  import React from 'react'
4
- import { cn } from '../../utils/cn'
5
4
  import type { ActionsMenuGroup } from '../ui/actions-menu'
6
- import { EntityImage } from '../ui/entity-image'
7
5
  import { PageActions, type PageActionButton } from '../ui/page-actions'
8
- import { BackButton } from './back-button'
6
+ import { PageHeader } from './page-header'
9
7
 
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
+ */
10
18
  export interface TitleBlockProps {
11
19
  title?: string
12
20
  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
13
27
  image?: { src: string; alt?: string }
14
28
  backButton?: { label?: string; onClick: () => void }
15
29
  actions?: PageActionButton[]
@@ -29,6 +43,8 @@ export interface TitleBlockProps {
29
43
  export function TitleBlock({
30
44
  title,
31
45
  subtitle,
46
+ titleIcon,
47
+ accentDot,
32
48
  image,
33
49
  backButton,
34
50
  actions,
@@ -40,67 +56,29 @@ export function TitleBlock({
40
56
  }: TitleBlockProps) {
41
57
  const hasActions = actions && actions.length > 0
42
58
  const hasMenuActions = !!menuActions && menuActions.some(g => g.items.length > 0)
59
+ const hasActionsSlot = hasActions || hasMenuActions || !!selector
43
60
 
44
- return (
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>
61
+ const actionsNode = hasActionsSlot ? (
62
+ <PageActions
63
+ variant={actionsVariant}
64
+ actions={actions ?? []}
65
+ menuActions={menuActions}
66
+ selector={selector}
67
+ />
68
+ ) : undefined
92
69
 
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>
70
+ 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
+ />
104
82
  )
105
83
  }
106
84
 
@@ -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 { SimpleMarkdownRenderer } from '../ui/simple-markdown-renderer'
32
+ import { RichMarkdownRenderer } from '../ui/rich-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
- * `<SimpleMarkdownRenderer>`. */
65
+ * `<RichMarkdownRenderer>`. */
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 = SimpleMarkdownRenderer,
86
+ MarkdownRenderer = RichMarkdownRenderer,
87
87
  renderRelatedCard,
88
88
  backHref,
89
89
  backLabel = 'Back to Getting Started',
@@ -25,7 +25,15 @@ import {
25
25
  type OpenframeDevSectionKey,
26
26
  } from '../../../utils/dev-sections/openframe-dev-sections';
27
27
 
28
- const SECTION_HERO_ICON_CLASS = 'h-10 w-10 text-ods-accent';
28
+ /** Re-export the constant so existing dev-section call sites keep their
29
+ * old import path. The canonical home is `src/utils/page-header-constants.ts`
30
+ * (NOT a `'use client'` module) so server modules can import it without
31
+ * Next.js turning it into a client reference proxy — that proxy is what
32
+ * blew up lucide's `mergeClasses().trim()` when used as
33
+ * `<Icon className={SECTION_HERO_ICON_CLASS} />` inside a hub
34
+ * server-component preset. */
35
+ import { SECTION_HERO_ICON_CLASS } from '../../../utils/page-header-constants';
36
+ export { SECTION_HERO_ICON_CLASS };
29
37
 
30
38
  export interface DevSectionPageProps {
31
39
  sectionKey: OpenframeDevSectionKey;
@@ -19,6 +19,7 @@ import { useState, useEffect } from 'react';
19
19
  import { useRouter, useSearchParams, usePathname } from '../../../embed-shims';
20
20
  import { SearchInput } from '../../ui';
21
21
  import { StatusFilterComponent } from '../../features';
22
+ import { PageHeader } from '../../layout/page-header';
22
23
  import {
23
24
  OPENFRAME_DEV_SECTIONS,
24
25
  type OpenframeDevSectionKey,
@@ -95,15 +96,19 @@ export function DevSectionView({ sectionKey, hero, preControls, children }: DevS
95
96
  return (
96
97
  <div className="w-full flex flex-col gap-10">
97
98
  {hero ? (
98
- <div className="space-y-4">
99
- <h1 className="text-h1 tracking-[-1.12px] text-ods-text-primary flex items-center gap-3">
100
- {hero.icon}
101
- {hero.title ?? section.hero.title}
102
- </h1>
103
- <p className="font-['DM_Sans'] font-medium text-[18px] leading-[28px] text-ods-text-secondary max-w-3xl">
104
- {hero.description}
105
- </p>
106
- </div>
99
+ // Render through the shared `<PageHeader>` primitive so the dev-
100
+ // section hero (Releases, Roadmap, Onboarding catalog) and the
101
+ // docs-hub hero (Knowledge Hub, Data Room) are LITERALLY the same
102
+ // component rendering the same DOM/CSS. `noBottomMargin` because
103
+ // the parent `gap-10` already supplies the spacing to the next
104
+ // sibling (preControls / search / filter).
105
+ <PageHeader
106
+ title={hero.title ?? section.hero.title}
107
+ titleIcon={hero.icon}
108
+ subtitle={hero.description}
109
+ noBottomMargin
110
+ noTopPadding
111
+ />
107
112
  ) : (
108
113
  <div className="flex items-center justify-between w-full">
109
114
  <h2 className="font-['Azeret_Mono'] font-semibold text-[32px] md:text-[40px] lg:text-[48px] leading-[40px] md:leading-[48px] lg:leading-[56px] text-ods-text-primary tracking-[-0.64px] md:tracking-[-0.8px] lg:tracking-[-0.96px]">
@@ -1,5 +1,5 @@
1
1
  export { DevSectionView, type DevSectionViewProps } from './dev-section-view';
2
- export { DevSectionPage, type DevSectionPageProps } from './dev-section-page';
2
+ export { DevSectionPage, type DevSectionPageProps, SECTION_HERO_ICON_CLASS } from './dev-section-page';
3
3
  export {
4
4
  DevCardRowContent,
5
5
  DevCardRowSkeleton,
@@ -80,7 +80,7 @@ export function useDocSearch(config: UseDocSearchConfig) {
80
80
  onNavigate,
81
81
  tableIds,
82
82
  onInPageSwap,
83
- searchEndpoint = '/api/docs/search',
83
+ searchEndpoint,
84
84
  } = config
85
85
  const tableIdsKey = tableIds && tableIds.length > 0 ? tableIds.join(',') : ''
86
86
 
@@ -88,7 +88,11 @@ export function useDocSearch(config: UseDocSearchConfig) {
88
88
  // Optional chat-runtime read — when present and mode='embed' the
89
89
  // search-result row click short-circuits to a new-tab open against
90
90
  // the absolutized URL. Null/host preserves today's behavior.
91
+ // Also used as the proxy-prefix fallback for `searchEndpoint`, matching
92
+ // how tickets resolves `findTicketUrl`.
91
93
  const runtime = useChatRuntime()
94
+ const resolvedSearchEndpoint =
95
+ searchEndpoint ?? runtime?.endpoints.docsSearchUrl ?? '/api/docs/search'
92
96
 
93
97
  const [query, setQuery] = useState('')
94
98
  const [results, setResults] = useState<SearchResult[]>([])
@@ -114,7 +118,7 @@ export function useDocSearch(config: UseDocSearchConfig) {
114
118
  })
115
119
  if (tableIdsKey) params.set('tableIds', tableIdsKey)
116
120
 
117
- const response = await fetch(`${searchEndpoint}?${params.toString()}`)
121
+ const response = await fetch(`${resolvedSearchEndpoint}?${params.toString()}`)
118
122
  if (!response.ok) {
119
123
  throw new Error(`Search request failed: ${response.status}`)
120
124
  }
@@ -142,7 +146,7 @@ export function useDocSearch(config: UseDocSearchConfig) {
142
146
  return () => {
143
147
  cancelled = true
144
148
  }
145
- }, [debouncedQuery, source, tableIdsKey, searchEndpoint])
149
+ }, [debouncedQuery, source, tableIdsKey, resolvedSearchEndpoint])
146
150
 
147
151
  // Derived loading state — single source of truth for "should the
148
152
  // dropdown show 'Loading...' instead of 'No results found'":
@@ -19,7 +19,7 @@
19
19
 
20
20
  import type { ComponentType } from 'react';
21
21
  import { PageShell, PageLayout, PageHeading } from '../../ui';
22
- import { SimpleMarkdownRenderer } from '../../ui/simple-markdown-renderer';
22
+ import { RichMarkdownRenderer } from '../../ui/rich-markdown-renderer';
23
23
  import { useRouter } from '../../../embed-shims/next-navigation';
24
24
  import { useLegalDocs, type LegalDocument } from './use-legal-docs';
25
25
  import { formatLegalDate } from '../../../utils/format';
@@ -76,7 +76,7 @@ export function LegalDocumentPage({
76
76
  initialData = null,
77
77
  initialLastUpdatedLabel = null,
78
78
  apiEndpoint,
79
- MarkdownRenderer = SimpleMarkdownRenderer,
79
+ MarkdownRenderer = RichMarkdownRenderer,
80
80
  backButton,
81
81
  }: LegalDocumentPageProps) {
82
82
  const router = useRouter();
@@ -10,6 +10,7 @@ import { Card, CardContent } from '../../ui/card';
10
10
  import { PageShell } from '../../layout/article-detail-layout';
11
11
  import { PageLayout } from '../../layout/page-layout';
12
12
  import { ReleaseChangelogSection } from '../../ui/release-changelog-section';
13
+ import { RichMarkdownRenderer } from '../../ui/rich-markdown-renderer';
13
14
  import { EntityTagBadges } from '../../features/entity-tag-badges';
14
15
  import { EntityMetadataAuthorCell } from '../../chat/entity-cards/entity-author-card';
15
16
  import type { EntityAuthor } from '../../../types/entity-author';
@@ -109,10 +110,11 @@ export interface ReleaseDetailPageProps {
109
110
  authorHref?: string;
110
111
  }
111
112
 
112
- // Default simple markdown renderer (just renders as text)
113
- function DefaultMarkdownRenderer({ content }: MarkdownRendererProps) {
114
- return <div className="whitespace-pre-wrap">{content}</div>;
115
- }
113
+ // Default renderer = the lib's `RichMarkdownRenderer` so out-of-the-box
114
+ // release pages get full rich-link previews, embedded media, social cards,
115
+ // etc. Hosts that want a different rendering (or a Supabase-aware preset)
116
+ // override via the `MarkdownRenderer` prop.
117
+ const DefaultMarkdownRenderer = RichMarkdownRenderer;
116
118
 
117
119
  export function ReleaseDetailPage({
118
120
  authorHref,
@@ -61,6 +61,7 @@ export * from './hover-dropdown'
61
61
  export * from '../chat'
62
62
  export * from '../layout/list-page-layout'
63
63
  export * from '../layout/page-container'
64
+ export * from '../layout/page-header'
64
65
  export * from '../layout/page-heading'
65
66
  export * from '../layout/page-layout'
66
67
  export * from '../layout/article-detail-layout'
@@ -160,5 +161,6 @@ export * from './ticket-attachments-list'
160
161
  export * from './ticket-note-card'
161
162
  export * from './ticket-notes-section'
162
163
  export * from './simple-markdown-renderer'
164
+ export { RichMarkdownRenderer, type RichMarkdownRendererProps } from './rich-markdown-renderer'
163
165
  export * from './filter-pill-row'
164
166
 
@@ -3,6 +3,7 @@
3
3
  import React, { useState, useRef, useEffect } from 'react';
4
4
  import { Badge } from './badge';
5
5
  import { ChevronDown } from 'lucide-react';
6
+ import { RichMarkdownRenderer } from './rich-markdown-renderer';
6
7
  import type { ChangelogEntry } from '../../types/product-release';
7
8
 
8
9
  interface ReleaseChangelogSectionProps {
@@ -31,7 +32,11 @@ interface ReleaseChangelogSectionProps {
31
32
  * visual taxonomy across catalog and detail. Inherits the title's color
32
33
  * (secondary for normal sections, red for breaking). */
33
34
  icon?: React.ReactNode;
34
- SimpleMarkdownRenderer: React.ComponentType<{ content: string }>;
35
+ /** Markdown renderer for each entry's description. Optional defaults to
36
+ * the lib's `RichMarkdownRenderer` so changelog rich-link previews
37
+ * (YouTube, OG cards, etc.) work out of the box. Hosts that already
38
+ * wrap with a Supabase-aware preset can keep passing their own. */
39
+ SimpleMarkdownRenderer?: React.ComponentType<{ content: string }>;
35
40
  }
36
41
 
37
42
  // Collapsed height for the preview-first mode. ~120px shows the first
@@ -47,7 +52,7 @@ export function ReleaseChangelogSection({
47
52
  defaultCollapsed = true,
48
53
  previewFirst = false,
49
54
  icon,
50
- SimpleMarkdownRenderer
55
+ SimpleMarkdownRenderer = RichMarkdownRenderer,
51
56
  }: ReleaseChangelogSectionProps) {
52
57
  const [collapsed, setCollapsed] = useState(collapsible ? defaultCollapsed : false);
53
58
  const [previewExpanded, setPreviewExpanded] = useState(false);