@flamingo-stack/openframe-frontend-core 0.0.314 → 0.0.315-snapshot.20260624135932

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 (167) hide show
  1. package/dist/{chunk-NH2RY6VM.js → chunk-2Y4DLBFO.js} +108 -97
  2. package/dist/{chunk-NH2RY6VM.js.map → chunk-2Y4DLBFO.js.map} +1 -1
  3. package/dist/{chunk-VCJOLKED.cjs → chunk-4MCMPYEM.cjs} +12 -12
  4. package/dist/{chunk-VCJOLKED.cjs.map → chunk-4MCMPYEM.cjs.map} +1 -1
  5. package/dist/{chunk-E2LC43T3.js → chunk-4NVA6W3J.js} +27 -22
  6. package/dist/chunk-4NVA6W3J.js.map +1 -0
  7. package/dist/chunk-4V3TCOFC.cjs +394 -0
  8. package/dist/chunk-4V3TCOFC.cjs.map +1 -0
  9. package/dist/{chunk-46UZAYUT.cjs → chunk-63A53WQN.cjs} +33 -33
  10. package/dist/{chunk-46UZAYUT.cjs.map → chunk-63A53WQN.cjs.map} +1 -1
  11. package/dist/{chunk-L7BROXZ7.js → chunk-64DZ2J7Q.js} +5 -5
  12. package/dist/{chunk-OD3BEWDQ.js → chunk-6KERXOFE.js} +3 -3
  13. package/dist/{chunk-JALO4TAZ.js → chunk-AI5X5JTD.js} +4 -4
  14. package/dist/chunk-CSLMCBZV.js +1464 -0
  15. package/dist/chunk-CSLMCBZV.js.map +1 -0
  16. package/dist/{chunk-2LFQJYLQ.cjs → chunk-CUNMBP3A.cjs} +13 -13
  17. package/dist/{chunk-2LFQJYLQ.cjs.map → chunk-CUNMBP3A.cjs.map} +1 -1
  18. package/dist/{chunk-DD35H7HA.cjs → chunk-DHVL36CA.cjs} +40 -40
  19. package/dist/{chunk-DD35H7HA.cjs.map → chunk-DHVL36CA.cjs.map} +1 -1
  20. package/dist/chunk-FCEVVNWY.cjs +1916 -0
  21. package/dist/chunk-FCEVVNWY.cjs.map +1 -0
  22. package/dist/chunk-FOVX3W3C.cjs +1464 -0
  23. package/dist/chunk-FOVX3W3C.cjs.map +1 -0
  24. package/dist/{chunk-BJ6JXN5Z.js → chunk-GHVVOST5.js} +95 -116
  25. package/dist/chunk-GHVVOST5.js.map +1 -0
  26. package/dist/{chunk-TRSDXD23.js → chunk-JAZM3A7E.js} +2 -2
  27. package/dist/{chunk-XKVSR3IV.js → chunk-JEBL5PQK.js} +21 -35
  28. package/dist/{chunk-XKVSR3IV.js.map → chunk-JEBL5PQK.js.map} +1 -1
  29. package/dist/{chunk-5ATH263N.cjs → chunk-L5JSGNT3.cjs} +35 -35
  30. package/dist/{chunk-5ATH263N.cjs.map → chunk-L5JSGNT3.cjs.map} +1 -1
  31. package/dist/{chunk-WJCOWYAP.cjs → chunk-LAMDFGE3.cjs} +41 -36
  32. package/dist/chunk-LAMDFGE3.cjs.map +1 -0
  33. package/dist/{chunk-V4IIBNTA.js → chunk-LQHMXPOJ.js} +5 -5
  34. package/dist/{chunk-LGLPNWS6.cjs → chunk-LWNPMLIH.cjs} +3 -3
  35. package/dist/{chunk-LGLPNWS6.cjs.map → chunk-LWNPMLIH.cjs.map} +1 -1
  36. package/dist/chunk-M3NULYCR.js +1916 -0
  37. package/dist/chunk-M3NULYCR.js.map +1 -0
  38. package/dist/{chunk-UO27TVAO.js → chunk-OKGZK6TT.js} +3 -3
  39. package/dist/{chunk-BHOGI57O.cjs → chunk-OLEW7FYZ.cjs} +123 -144
  40. package/dist/chunk-OLEW7FYZ.cjs.map +1 -0
  41. package/dist/chunk-PIJ4JLJU.js +394 -0
  42. package/dist/chunk-PIJ4JLJU.js.map +1 -0
  43. package/dist/{chunk-E4CQ4RUG.js → chunk-Q4AMYLKX.js} +11 -11
  44. package/dist/{chunk-FQOTC3UU.cjs → chunk-QJGRP2YE.cjs} +4 -4
  45. package/dist/{chunk-FQOTC3UU.cjs.map → chunk-QJGRP2YE.cjs.map} +1 -1
  46. package/dist/{chunk-ZPK5HW7B.cjs → chunk-UGDGUO26.cjs} +3 -3
  47. package/dist/{chunk-ZPK5HW7B.cjs.map → chunk-UGDGUO26.cjs.map} +1 -1
  48. package/dist/{chunk-AD7TII2A.cjs → chunk-VCE3ZEN3.cjs} +5 -5
  49. package/dist/{chunk-AD7TII2A.cjs.map → chunk-VCE3ZEN3.cjs.map} +1 -1
  50. package/dist/{chunk-EC4DGRN6.cjs → chunk-XAQJ4ZLY.cjs} +459 -448
  51. package/dist/chunk-XAQJ4ZLY.cjs.map +1 -0
  52. package/dist/{chunk-ZW3NHMG7.js → chunk-YFGDZFUG.js} +4 -4
  53. package/dist/{chunk-JWX6NIQ4.js → chunk-Z3YORGG4.js} +2 -2
  54. package/dist/{chunk-UNKIRZVY.cjs → chunk-ZYGVJXJ5.cjs} +33 -47
  55. package/dist/chunk-ZYGVJXJ5.cjs.map +1 -0
  56. package/dist/components/case-studies/index.cjs +18 -18
  57. package/dist/components/case-studies/index.cjs.map +1 -1
  58. package/dist/components/case-studies/index.js +8 -8
  59. package/dist/components/chat/index.cjs +8 -8
  60. package/dist/components/chat/index.js +7 -7
  61. package/dist/components/contact/index.cjs +9 -9
  62. package/dist/components/contact/index.js +8 -8
  63. package/dist/components/docs/doc-viewer.d.ts +4 -0
  64. package/dist/components/docs/doc-viewer.d.ts.map +1 -1
  65. package/dist/components/docs/index.cjs +11 -11
  66. package/dist/components/docs/index.js +10 -10
  67. package/dist/components/embeds/index.cjs +9 -9
  68. package/dist/components/embeds/index.js +8 -8
  69. package/dist/components/faq/faq-document-page.d.ts +18 -20
  70. package/dist/components/faq/faq-document-page.d.ts.map +1 -1
  71. package/dist/components/faq/index.cjs +10 -10
  72. package/dist/components/faq/index.js +9 -9
  73. package/dist/components/features/index.cjs +8 -8
  74. package/dist/components/features/index.js +7 -7
  75. package/dist/components/features/push-button-selector.d.ts +1 -0
  76. package/dist/components/features/push-button-selector.d.ts.map +1 -1
  77. package/dist/components/help-center-pages/delivery-page.d.ts +27 -0
  78. package/dist/components/help-center-pages/delivery-page.d.ts.map +1 -0
  79. package/dist/components/help-center-pages/index.cjs +164 -0
  80. package/dist/components/help-center-pages/index.cjs.map +1 -0
  81. package/dist/components/help-center-pages/index.d.ts +25 -0
  82. package/dist/components/help-center-pages/index.d.ts.map +1 -0
  83. package/dist/components/help-center-pages/index.js +164 -0
  84. package/dist/components/help-center-pages/index.js.map +1 -0
  85. package/dist/components/help-center-pages/onboarding-guides-catalog-page.d.ts +41 -0
  86. package/dist/components/help-center-pages/onboarding-guides-catalog-page.d.ts.map +1 -0
  87. package/dist/components/help-center-pages/product-releases-list-page.d.ts +34 -0
  88. package/dist/components/help-center-pages/product-releases-list-page.d.ts.map +1 -0
  89. package/dist/components/help-center-pages/roadmap-page.d.ts +40 -0
  90. package/dist/components/help-center-pages/roadmap-page.d.ts.map +1 -0
  91. package/dist/components/icons/index.cjs +3 -3
  92. package/dist/components/icons/index.js +2 -2
  93. package/dist/components/index.cjs +177 -1555
  94. package/dist/components/index.cjs.map +1 -1
  95. package/dist/components/index.js +348 -1726
  96. package/dist/components/index.js.map +1 -1
  97. package/dist/components/layout/page-layout.d.ts +4 -1
  98. package/dist/components/layout/page-layout.d.ts.map +1 -1
  99. package/dist/components/layout/title-block.d.ts +5 -1
  100. package/dist/components/layout/title-block.d.ts.map +1 -1
  101. package/dist/components/navigation/index.cjs +8 -8
  102. package/dist/components/navigation/index.js +7 -7
  103. package/dist/components/onboarding-guides/index.cjs +15 -364
  104. package/dist/components/onboarding-guides/index.cjs.map +1 -1
  105. package/dist/components/onboarding-guides/index.js +20 -369
  106. package/dist/components/onboarding-guides/index.js.map +1 -1
  107. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts +9 -1
  108. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  109. package/dist/components/related-content/index.cjs +10 -10
  110. package/dist/components/related-content/index.js +9 -9
  111. package/dist/components/shared/dev-section/dev-section-page.d.ts +7 -1
  112. package/dist/components/shared/dev-section/dev-section-page.d.ts.map +1 -1
  113. package/dist/components/shared/dev-section/dev-section-view.d.ts +7 -1
  114. package/dist/components/shared/dev-section/dev-section-view.d.ts.map +1 -1
  115. package/dist/components/shared/legal-document/legal-document-page.d.ts +5 -1
  116. package/dist/components/shared/legal-document/legal-document-page.d.ts.map +1 -1
  117. package/dist/components/shared/product-release/release-detail-page.d.ts +11 -2
  118. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  119. package/dist/components/tickets/help-center-list.d.ts +5 -1
  120. package/dist/components/tickets/help-center-list.d.ts.map +1 -1
  121. package/dist/components/tickets/index.cjs +15 -1882
  122. package/dist/components/tickets/index.cjs.map +1 -1
  123. package/dist/components/tickets/index.js +28 -1895
  124. package/dist/components/tickets/index.js.map +1 -1
  125. package/dist/components/ui/file-manager/index.cjs +53 -53
  126. package/dist/components/ui/file-manager/index.cjs.map +1 -1
  127. package/dist/components/ui/file-manager/index.js +4 -4
  128. package/dist/components/ui/index.cjs +8 -8
  129. package/dist/components/ui/index.cjs.map +1 -1
  130. package/dist/components/ui/index.js +7 -7
  131. package/dist/hooks/index.cjs +5 -5
  132. package/dist/hooks/index.js +4 -4
  133. package/dist/index.cjs +10 -10
  134. package/dist/index.cjs.map +1 -1
  135. package/dist/index.js +9 -9
  136. package/package.json +7 -1
  137. package/src/components/docs/doc-viewer.tsx +21 -34
  138. package/src/components/faq/faq-document-page.tsx +33 -60
  139. package/src/components/features/push-button-selector.tsx +21 -3
  140. package/src/components/help-center-pages/delivery-page.tsx +45 -0
  141. package/src/components/help-center-pages/index.ts +41 -0
  142. package/src/components/help-center-pages/onboarding-guides-catalog-page.tsx +66 -0
  143. package/src/components/help-center-pages/product-releases-list-page.tsx +58 -0
  144. package/src/components/help-center-pages/roadmap-page.tsx +68 -0
  145. package/src/components/layout/page-layout.tsx +11 -0
  146. package/src/components/layout/title-block.tsx +15 -2
  147. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +30 -19
  148. package/src/components/shared/dev-section/dev-section-page.tsx +29 -19
  149. package/src/components/shared/dev-section/dev-section-view.tsx +26 -19
  150. package/src/components/shared/legal-document/legal-document-page.tsx +19 -23
  151. package/src/components/shared/product-release/release-detail-page.tsx +36 -36
  152. package/src/components/tickets/help-center-list.tsx +11 -3
  153. package/dist/chunk-BHOGI57O.cjs.map +0 -1
  154. package/dist/chunk-BJ6JXN5Z.js.map +0 -1
  155. package/dist/chunk-E2LC43T3.js.map +0 -1
  156. package/dist/chunk-EC4DGRN6.cjs.map +0 -1
  157. package/dist/chunk-UNKIRZVY.cjs.map +0 -1
  158. package/dist/chunk-WJCOWYAP.cjs.map +0 -1
  159. /package/dist/{chunk-L7BROXZ7.js.map → chunk-64DZ2J7Q.js.map} +0 -0
  160. /package/dist/{chunk-OD3BEWDQ.js.map → chunk-6KERXOFE.js.map} +0 -0
  161. /package/dist/{chunk-JALO4TAZ.js.map → chunk-AI5X5JTD.js.map} +0 -0
  162. /package/dist/{chunk-TRSDXD23.js.map → chunk-JAZM3A7E.js.map} +0 -0
  163. /package/dist/{chunk-V4IIBNTA.js.map → chunk-LQHMXPOJ.js.map} +0 -0
  164. /package/dist/{chunk-UO27TVAO.js.map → chunk-OKGZK6TT.js.map} +0 -0
  165. /package/dist/{chunk-E4CQ4RUG.js.map → chunk-Q4AMYLKX.js.map} +0 -0
  166. /package/dist/{chunk-ZW3NHMG7.js.map → chunk-YFGDZFUG.js.map} +0 -0
  167. /package/dist/{chunk-JWX6NIQ4.js.map → chunk-Z3YORGG4.js.map} +0 -0
@@ -2,19 +2,17 @@
2
2
 
3
3
  /**
4
4
  * FaqDocumentPage — the full `/faqs` page with chrome, so embedders drop in
5
- * ONE component instead of hand-assembling `PageShell` + `PageLayout` + the
6
- * FAQ hero around the bare `<FaqSection>`. Mirrors `LegalDocumentPage` /
7
- * `DevSectionPage`: the page-level layout lives in the lib, the host page is a
8
- * thin wrapper that passes only config + the SSR-resolved data.
5
+ * ONE component instead of hand-assembling `PageShell` + `PageLayout` around
6
+ * the bare `<FaqSection>`. Mirrors `LegalDocumentPage` / `DevSectionPage`: the
7
+ * page-level layout lives in the lib, the host page is a thin wrapper that
8
+ * passes only config + the SSR-resolved data.
9
9
  *
10
- * HERO: renders the canonical FAQ hero (`<h1 class="text-h1">` + accent dot +
11
- * icon + clamped subtitle) — byte-identical to the multi-platform hub's local
12
- * `PageWithHeader` chrome the standalone `/faqs` page historically used. It
13
- * does NOT route through `PageLayout`'s `title`/`subtitle` (the FROZEN
14
- * `text-h2` `TitleBlock` is a different, smaller header used by OpenFrame
15
- * detail surfaces). The page owns the `<h1>`, so `<FaqSection heading={null}>`
16
- * nests its category headings as `<h2>` and the questions as `<h3>` (the
17
- * SEO-recommended FAQ document outline).
10
+ * HERO: the title + subtitle route through the canonical (frozen) `PageLayout`
11
+ * `TitleBlock` with `titleSize="h1"` — the unified Help Center header (the
12
+ * `TitleBlock` element is always an `<h1>`; `titleSize` only sets its typography,
13
+ * here `text-h1`). The page owns that `<h1>`, so `<FaqSection heading={null}>`
14
+ * nests its category headings as `<h2>`/`<h3>` (the SEO-recommended FAQ document
15
+ * outline).
18
16
  *
19
17
  * DATA: pass `initialFaqs` (SSR-resolved, platform-scoped) so `FaqSection`
20
18
  * skips its client self-fetch — the standalone page's static platform-only
@@ -22,27 +20,25 @@
22
20
  * suggestion-fill instead.
23
21
  */
24
22
 
25
- import React from 'react';
26
- import { HelpCircle } from 'lucide-react';
27
23
  import type { Faq } from '../../types/faq';
28
24
  import { PageShell, PageLayout } from '../ui';
29
25
  import { useRouter } from '../../embed-shims/next-navigation';
30
- import { SECTION_HERO_ICON_CLASS } from '../../utils/page-header-constants';
31
26
  import { FaqSection } from './faq-section';
32
27
  import type { FaqSchemaOptions } from './json-ld';
33
28
 
34
29
  export interface FaqDocumentPageProps {
35
- /** Hero `<h1>`. Default "Frequently Asked Questions". */
30
+ /** Page title (frozen `PageLayout` `TitleBlock`). Default "Frequently Asked Questions". */
36
31
  title?: string;
37
- /** Subtitle under the title (auto-clamped to 2 lines). */
32
+ /** Subtitle under the title. */
38
33
  subtitle?: string;
39
- /** Icon rendered before the title. Default `<HelpCircle>` (the FAQ glyph). */
40
- titleIcon?: React.ReactNode;
41
- /** Render the yellow accent dot after the title (default true). */
42
- accentDot?: boolean;
43
34
  /** Back-button config — same pattern as `DevSectionPage` / `LegalDocumentPage`.
44
35
  * Pass `false` to hide. Default `{ label: 'Back to home', href: '/' }`. */
45
36
  backButton?: { label?: string; href?: string } | false;
37
+ /** Render the standalone `<PageShell>` (own `<main>` + bg + max-width). Default
38
+ * true. Pass false when the host layout already provides the page container
39
+ * (e.g. openframe-frontend's `AppLayout` `<main>`) — only the padding box
40
+ * renders, avoiding a nested `<main>`. */
41
+ shell?: boolean;
46
42
  /** SSR-hydrate `FaqSection` (skips the client fetch — the platform-only
47
43
  * contract for the standalone page). Omit for self-fetching embeds. */
48
44
  initialFaqs?: Faq[];
@@ -63,8 +59,6 @@ export interface FaqDocumentPageProps {
63
59
  export function FaqDocumentPage({
64
60
  title = 'Frequently Asked Questions',
65
61
  subtitle,
66
- titleIcon = <HelpCircle className={SECTION_HERO_ICON_CLASS} />,
67
- accentDot = true,
68
62
  backButton,
69
63
  initialFaqs,
70
64
  emitJsonLd,
@@ -73,6 +67,7 @@ export function FaqDocumentPage({
73
67
  entityType,
74
68
  entityId,
75
69
  minResults,
70
+ shell = true,
76
71
  }: FaqDocumentPageProps) {
77
72
  const router = useRouter();
78
73
 
@@ -87,42 +82,20 @@ export function FaqDocumentPage({
87
82
  onClick: () => router.push(backButton?.href ?? '/'),
88
83
  };
89
84
 
90
- return (
91
- <PageShell>
92
- <PageLayout backButton={backCfg}>
93
- <div className="w-full flex flex-col gap-10">
94
- {/* Canonical FAQ hero — the exact DOM/CSS the hub's local
95
- `PageWithHeader` rendered (text-h1 + accent dot + icon + clamped
96
- subtitle), inlined here so the standalone `/faqs` look is owned by
97
- the lib. Intentionally NOT the frozen `text-h2` `TitleBlock`. */}
98
- <div className="flex items-end justify-between gap-[var(--spacing-system-m)] md:flex-col md:items-start md:justify-start lg:flex-row lg:items-end lg:justify-between">
99
- <div className="flex flex-col gap-[var(--spacing-system-xs)] flex-1 min-w-0">
100
- <div className="space-y-4">
101
- <h1 className="text-h1 tracking-[-1.12px] text-ods-text-primary flex items-center gap-3">
102
- {titleIcon}
103
- <span>
104
- {title}
105
- {accentDot && <span className="text-ods-accent">.</span>}
106
- </span>
107
- </h1>
108
- <p className="font-['DM_Sans'] font-medium text-[18px] leading-[28px] text-ods-text-secondary max-w-3xl line-clamp-2 min-h-[56px]">
109
- {subtitle || ' '}
110
- </p>
111
- </div>
112
- </div>
113
- </div>
114
- <FaqSection
115
- initialFaqs={initialFaqs}
116
- heading={null}
117
- emitJsonLd={emitJsonLd}
118
- jsonLd={jsonLd}
119
- apiBaseUrl={apiBaseUrl}
120
- entityType={entityType}
121
- entityId={entityId}
122
- minResults={minResults}
123
- />
124
- </div>
125
- </PageLayout>
126
- </PageShell>
85
+ const inner = (
86
+ <PageLayout title={title} subtitle={subtitle} backButton={backCfg} titleSize="h1">
87
+ <FaqSection
88
+ initialFaqs={initialFaqs}
89
+ heading={null}
90
+ emitJsonLd={emitJsonLd}
91
+ jsonLd={jsonLd}
92
+ apiBaseUrl={apiBaseUrl}
93
+ entityType={entityType}
94
+ entityId={entityId}
95
+ minResults={minResults}
96
+ />
97
+ </PageLayout>
127
98
  );
99
+
100
+ return shell ? <PageShell>{inner}</PageShell> : <div className="page-shell-content">{inner}</div>;
128
101
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { Button, Badge } from "../ui";
4
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip";
4
5
  import { Check } from 'lucide-react';
5
6
  import React from 'react';
6
7
 
@@ -15,6 +16,7 @@ export interface SelectableOption {
15
16
  icon?: React.ReactNode;
16
17
  color?: string;
17
18
  disabled?: boolean; // If true, option is shown grayed out and not selectable
19
+ disabledReason?: string; // Tooltip shown on hover when disabled — explains WHY it's unavailable
18
20
  section?: string; // Optional section ID to group options
19
21
  }
20
22
 
@@ -151,19 +153,21 @@ export function PushButtonSelector({
151
153
  const renderOption = (option: SelectableOption) => {
152
154
  const isSelected = validSelectedIds.includes(option.id);
153
155
 
154
- return (
156
+ const optionEl = (
155
157
  <div
156
158
  key={option.id}
157
159
  className={`
158
160
  p-4 rounded-lg border transition-all duration-200 group
159
161
  ${option.disabled
160
- ? 'cursor-not-allowed opacity-40 bg-ods-card border-ods-border'
162
+ ? `${isSelected ? 'cursor-pointer' : 'cursor-not-allowed'} opacity-40 bg-ods-card border-ods-border`
161
163
  : isSelected
162
164
  ? 'cursor-pointer bg-ods-bg-secondary border-ods-accent shadow-sm'
163
165
  : 'cursor-pointer bg-ods-bg-primary border-ods-border hover:border-ods-border-hover hover:bg-ods-bg-hover'
164
166
  }
165
167
  `}
166
- onClick={() => !option.disabled && toggleSelection(option.id)}
168
+ // Disabled options can't be newly SELECTED, but an already-selected one
169
+ // (e.g. it later became unavailable) must still be removable.
170
+ onClick={() => (!option.disabled || isSelected) && toggleSelection(option.id)}
167
171
  >
168
172
  <div className="flex items-center justify-between gap-4">
169
173
  <div className="flex items-center gap-3 flex-1 min-w-0">
@@ -199,6 +203,18 @@ export function PushButtonSelector({
199
203
  </div>
200
204
  </div>
201
205
  );
206
+
207
+ // Disabled options explain WHY on hover via the unified Tooltip.
208
+ if (option.disabled && option.disabledReason) {
209
+ return (
210
+ <Tooltip key={option.id}>
211
+ <TooltipTrigger asChild>{optionEl}</TooltipTrigger>
212
+ <TooltipContent className="max-w-xs">{option.disabledReason}</TooltipContent>
213
+ </Tooltip>
214
+ );
215
+ }
216
+
217
+ return optionEl;
202
218
  };
203
219
 
204
220
  // Group options by section if sections are provided
@@ -271,6 +287,7 @@ export function PushButtonSelector({
271
287
  };
272
288
 
273
289
  return (
290
+ <TooltipProvider delayDuration={150}>
274
291
  <div className={`space-y-4 ${className}`}>
275
292
  {title && (
276
293
  <h3 className="text-h5 text-ods-text-primary">
@@ -319,5 +336,6 @@ export function PushButtonSelector({
319
336
  </div>
320
337
  )}
321
338
  </div>
339
+ </TooltipProvider>
322
340
  );
323
341
  }
@@ -0,0 +1,45 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * `<DeliveryPage>` — the full bug-fixes & enhancements (`delivery`) page:
5
+ * `DevSectionPage sectionKey="delivery"` chrome wrapping the self-contained
6
+ * `<DeliveryLists>` (Recently Completed + Active Tasks tables). Hosts configure
7
+ * only the two bucket api routes.
8
+ */
9
+
10
+ import type { ReactNode } from 'react'
11
+ import { DevSectionPage } from '../shared/dev-section'
12
+ import { DeliveryLists } from '../shared/delivery'
13
+
14
+ export interface DeliveryPageProps {
15
+ /** GET endpoint for the "Recently Completed" bucket. Default `/api/delivery/completed`. */
16
+ completedEndpoint?: string
17
+ /** GET endpoint for the "Active Tasks" bucket. Default `/api/delivery/in-progress`. */
18
+ inProgressEndpoint?: string
19
+ /** Back-button config. Pass `false` to hide. Default `{ href: '/' }`. */
20
+ backButton?: { label?: string; href?: string } | false
21
+ title?: string
22
+ subtitle?: string
23
+ /** Optional slot rendered below the lists, inside the page chrome. */
24
+ belowContent?: ReactNode
25
+ /** Render the standalone `<PageShell>`. Default true. Pass false when the host
26
+ * layout already provides the page container (forwarded to `DevSectionPage`). */
27
+ shell?: boolean
28
+ }
29
+
30
+ export function DeliveryPage({
31
+ completedEndpoint,
32
+ inProgressEndpoint,
33
+ backButton,
34
+ title,
35
+ subtitle,
36
+ belowContent,
37
+ shell,
38
+ }: DeliveryPageProps) {
39
+ return (
40
+ <DevSectionPage sectionKey="delivery" backButton={backButton} title={title} subtitle={subtitle} shell={shell}>
41
+ <DeliveryLists completedApiEndpoint={completedEndpoint} inProgressApiEndpoint={inProgressEndpoint} />
42
+ {belowContent}
43
+ </DevSectionPage>
44
+ )
45
+ }
@@ -0,0 +1,41 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * Help Center pages — ready-made, full-page components (each owns the canonical
5
+ * `PageShell` + `PageLayout` chrome) so a host route is a one-line mount with NO
6
+ * local wrapper. Shared by openframe-frontend (self-fetch via the `/content`
7
+ * proxy, mounted under `/help-center/*`) and multi-platform-hub (SSR with
8
+ * server-fetched `initialData` + `generateMetadata`/JSON-LD kept in the server
9
+ * route). Endpoint config + SSR data + optional slots are passed as props.
10
+ *
11
+ * This barrel ALSO re-exports the already-existing full-pages (FAQ / Legal /
12
+ * Release detail / Onboarding detail / Docs / Tickets) so consumers have ONE
13
+ * import site for "help center pages". Re-exports are NAMED (not `export *`) to
14
+ * avoid TS2308 ambiguous-re-export collisions, and this barrel is intentionally
15
+ * NOT merged into the top-level `components/index.ts`.
16
+ */
17
+
18
+ // New combined pages. (The Help Center *index* landing is intentionally NOT
19
+ // here — it stays a host-local page; its links + icons are app-specific.)
20
+ export { RoadmapPage, type RoadmapPageProps } from './roadmap-page'
21
+ export { ProductReleasesListPage, type ProductReleasesListPageProps } from './product-releases-list-page'
22
+ export { DeliveryPage, type DeliveryPageProps } from './delivery-page'
23
+ export {
24
+ OnboardingGuidesCatalogPage,
25
+ type OnboardingGuidesCatalogPageProps,
26
+ } from './onboarding-guides-catalog-page'
27
+
28
+ // Existing full-pages re-exported for a single Help Center import site.
29
+ export { FaqDocumentPage, type FaqDocumentPageProps } from '../faq'
30
+ export { LegalDocumentPage, type LegalDocumentPageProps } from '../shared/legal-document'
31
+ export {
32
+ ReleaseDetailPage,
33
+ type ReleaseDetailPageProps,
34
+ type VideoDisplaySectionProps,
35
+ } from '../shared/product-release'
36
+ export {
37
+ OnboardingGuideDetailView,
38
+ type OnboardingGuideDetailViewProps,
39
+ } from '../onboarding-guides'
40
+ export { DocsHubPage } from '../docs'
41
+ export { HelpCenterList } from '../tickets'
@@ -0,0 +1,66 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * `<OnboardingGuidesCatalogPage>` — the full `/onboarding-guides` catalog page:
5
+ * `DevSectionPage sectionKey="onboarding"` chrome wrapping the self-contained
6
+ * `<OnboardingGuidesCatalogView>` (RAG search + section pills + guide grid).
7
+ * Supports both SSR (`initialGuides`/`initialSections`) and self-fetch
8
+ * (`guidesEndpoint`/`sectionsEndpoint`) modes — forwarded to the view verbatim.
9
+ */
10
+
11
+ import type { ReactNode } from 'react'
12
+ import type { OnboardingGuide } from '../chat/types/entities/onboarding-guide'
13
+ import { DevSectionPage } from '../shared/dev-section'
14
+ import { OnboardingGuidesCatalogView } from '../onboarding-guides'
15
+
16
+ type SectionSummary = { section: string; section_order: number; count: number }
17
+
18
+ export interface OnboardingGuidesCatalogPageProps {
19
+ /** Self-fetch: GET list endpoint (the api route). Appends `?section=`. */
20
+ guidesEndpoint?: string
21
+ /** Self-fetch: GET section-summary endpoint (the api route). */
22
+ sectionsEndpoint?: string
23
+ /** Controlled / SSR: server-fetched guides + sections + active section. */
24
+ initialGuides?: OnboardingGuide[]
25
+ initialSections?: SectionSummary[]
26
+ initialSection?: string
27
+ /** Base path the catalog is mounted under (card href prefix + `?section=` push). */
28
+ basePath?: string
29
+ /** Back-button config. Pass `false` to hide. Default `{ href: '/' }`. */
30
+ backButton?: { label?: string; href?: string } | false
31
+ title?: string
32
+ subtitle?: string
33
+ /** Optional slot rendered below the catalog, inside the page chrome. */
34
+ belowContent?: ReactNode
35
+ /** Render the standalone `<PageShell>`. Default true. Pass false when the host
36
+ * layout already provides the page container (forwarded to `DevSectionPage`). */
37
+ shell?: boolean
38
+ }
39
+
40
+ export function OnboardingGuidesCatalogPage({
41
+ guidesEndpoint,
42
+ sectionsEndpoint,
43
+ initialGuides,
44
+ initialSections,
45
+ initialSection,
46
+ basePath,
47
+ backButton,
48
+ title,
49
+ subtitle,
50
+ belowContent,
51
+ shell,
52
+ }: OnboardingGuidesCatalogPageProps) {
53
+ return (
54
+ <DevSectionPage sectionKey="onboarding" backButton={backButton} title={title} subtitle={subtitle} shell={shell}>
55
+ <OnboardingGuidesCatalogView
56
+ guidesEndpoint={guidesEndpoint}
57
+ sectionsEndpoint={sectionsEndpoint}
58
+ initialGuides={initialGuides}
59
+ initialSections={initialSections}
60
+ initialSection={initialSection}
61
+ basePath={basePath}
62
+ />
63
+ {belowContent}
64
+ </DevSectionPage>
65
+ )
66
+ }
@@ -0,0 +1,58 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * `<ProductReleasesListPage>` — the full `/releases` list page: `DevSectionPage
5
+ * sectionKey="releases"` chrome wrapping the self-contained `<ProductReleasesView>`.
6
+ * Hosts configure the api route + detail `basePath` (+ optional SSR `initialData`
7
+ * and a custom card-prop builder). Card → detail nav flows through
8
+ * `runtime.composeContentUrl`.
9
+ */
10
+
11
+ import type { ReactNode } from 'react'
12
+ import type { ProductRelease, ProductReleaseListResponse } from '../../types/product-release'
13
+ import { DevSectionPage } from '../shared/dev-section'
14
+ import { ProductReleasesView, type ProductReleaseCardExtras } from '../shared/product-release'
15
+
16
+ export interface ProductReleasesListPageProps {
17
+ /** GET list endpoint (the api route). Default `/api/releases`. */
18
+ releasesEndpoint?: string
19
+ /** Fallback detail-href prefix when `composeContentUrl` is not wired. Default `/releases`. */
20
+ basePath?: string
21
+ /** Derive the per-card prop bundle (defaults to the lib's rich builder). */
22
+ buildCardProps?: (release: ProductRelease) => ProductReleaseCardExtras
23
+ /** Optional SSR hydrate for the first page (hub server-fetch). */
24
+ initialData?: ProductReleaseListResponse
25
+ /** Back-button config. Pass `false` to hide. Default `{ href: '/' }`. */
26
+ backButton?: { label?: string; href?: string } | false
27
+ title?: string
28
+ subtitle?: string
29
+ /** Optional slot rendered below the list, inside the page chrome. */
30
+ belowContent?: ReactNode
31
+ /** Render the standalone `<PageShell>`. Default true. Pass false when the host
32
+ * layout already provides the page container (forwarded to `DevSectionPage`). */
33
+ shell?: boolean
34
+ }
35
+
36
+ export function ProductReleasesListPage({
37
+ releasesEndpoint,
38
+ basePath,
39
+ buildCardProps,
40
+ initialData,
41
+ backButton,
42
+ title,
43
+ subtitle,
44
+ belowContent,
45
+ shell,
46
+ }: ProductReleasesListPageProps) {
47
+ return (
48
+ <DevSectionPage sectionKey="releases" backButton={backButton} title={title} subtitle={subtitle} shell={shell}>
49
+ <ProductReleasesView
50
+ endpoint={releasesEndpoint}
51
+ basePath={basePath}
52
+ buildCardProps={buildCardProps}
53
+ initialData={initialData}
54
+ />
55
+ {belowContent}
56
+ </DevSectionPage>
57
+ )
58
+ }
@@ -0,0 +1,68 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * `<RoadmapPage>` — the full `/roadmap` page: `DevSectionPage sectionKey="roadmap"`
5
+ * (PageShell + PageLayout + hero + search/status chrome) wrapping the
6
+ * self-contained `<RoadmapView>` list. Hosts configure only the api routes
7
+ * (+ optional SSR `initialItems`); both openframe-frontend and the hub mount
8
+ * this instead of hand-composing `DevSectionPage` + `RoadmapView`.
9
+ */
10
+
11
+ import type { ReactNode } from 'react'
12
+ import type { RoadmapItem } from '../chat/types/entities/roadmap-item'
13
+ import { DevSectionPage } from '../shared/dev-section'
14
+ import { RoadmapView } from '../shared/roadmap'
15
+ import type { UseRoadmapVotingOptions } from '../shared/roadmap'
16
+
17
+ export interface RoadmapPageProps {
18
+ /** GET list endpoint (the api route). Default `/api/roadmap`. */
19
+ roadmapEndpoint?: string
20
+ /** Per-task refresh URL builder (after a vote). Default `/api/roadmap/<id>`. */
21
+ buildRefreshUrl?: (taskId: string) => string
22
+ /** Vote POST endpoint, forwarded to `RoadmapView` via `votingOptions`. */
23
+ voteApiEndpoint?: string
24
+ /** Full voting options override — takes precedence over `voteApiEndpoint`. */
25
+ votingOptions?: UseRoadmapVotingOptions
26
+ /** Optional SSR hydrate (hub server-fetch) — skips the initial client fetch. */
27
+ initialItems?: RoadmapItem[]
28
+ /** Indent the grid (the hub's full-page roadmap look). Default off. */
29
+ showLeftMargin?: boolean
30
+ /** Back-button config. Pass `false` to hide. Default `{ href: '/' }`. */
31
+ backButton?: { label?: string; href?: string } | false
32
+ /** Override the hero title/subtitle (defaults from `OPENFRAME_DEV_SECTIONS`). */
33
+ title?: string
34
+ subtitle?: string
35
+ /** Optional slot rendered below the list, inside the page chrome — e.g. the
36
+ * hub's related-content rail. */
37
+ belowContent?: ReactNode
38
+ /** Render the standalone `<PageShell>`. Default true. Pass false when the host
39
+ * layout already provides the page container (forwarded to `DevSectionPage`). */
40
+ shell?: boolean
41
+ }
42
+
43
+ export function RoadmapPage({
44
+ roadmapEndpoint,
45
+ buildRefreshUrl,
46
+ voteApiEndpoint,
47
+ votingOptions,
48
+ initialItems,
49
+ showLeftMargin,
50
+ backButton,
51
+ title,
52
+ subtitle,
53
+ belowContent,
54
+ shell,
55
+ }: RoadmapPageProps) {
56
+ return (
57
+ <DevSectionPage sectionKey="roadmap" backButton={backButton} title={title} subtitle={subtitle} shell={shell}>
58
+ <RoadmapView
59
+ endpoint={roadmapEndpoint}
60
+ initialItems={initialItems}
61
+ showLeftMargin={showLeftMargin}
62
+ buildRefreshUrl={buildRefreshUrl}
63
+ votingOptions={votingOptions ?? (voteApiEndpoint ? { voteApiEndpoint } : undefined)}
64
+ />
65
+ {belowContent}
66
+ </DevSectionPage>
67
+ )
68
+ }
@@ -25,6 +25,12 @@
25
25
  * If a new design genuinely needs different chrome: build a SEPARATE new
26
26
  * component for it. Never mutate this one. If you believe an edit here is
27
27
  * unavoidable, STOP and get explicit human sign-off first.
28
+ *
29
+ * SANCTIONED EXCEPTION (2026-06, explicit human sign-off): the OPTIONAL
30
+ * `titleSize` prop, forwarded to `TitleBlock`. Defaults to `'h2'` — the frozen
31
+ * baseline is unchanged for every existing caller. `titleSize="h1"` opts the
32
+ * title up to `text-h1` (the unified Help Center pages). Additive + default-
33
+ * preserving; do NOT change the default or anything else here.
28
34
  * ========================================================================== */
29
35
 
30
36
  import React from 'react'
@@ -49,6 +55,9 @@ export interface PageLayoutProps {
49
55
  className?: string
50
56
  contentClassName?: string
51
57
  showHeader?: boolean
58
+ /** Title typography size, forwarded to `TitleBlock`. Default `'h2'` (frozen
59
+ * baseline). Pass `'h1'` for the unified Help Center pages. */
60
+ titleSize?: 'h1' | 'h2'
52
61
  }
53
62
 
54
63
  /**
@@ -70,6 +79,7 @@ export function PageLayout({
70
79
  className,
71
80
  contentClassName,
72
81
  showHeader = true,
82
+ titleSize,
73
83
  }: PageLayoutProps) {
74
84
  const hasActions = actions && actions.length > 0
75
85
  const needsBottomPadding = hasActions && actionsVariant === 'primary-buttons'
@@ -88,6 +98,7 @@ export function PageLayout({
88
98
  menuActions={menuActions}
89
99
  selector={selector}
90
100
  variant={headerVariant}
101
+ titleSize={titleSize}
91
102
  />
92
103
  )}
93
104
 
@@ -22,6 +22,13 @@
22
22
  * current output. If a new design needs different chrome, build a SEPARATE new
23
23
  * component — never mutate this one. If an edit here seems unavoidable, STOP
24
24
  * and get explicit human sign-off first.
25
+ *
26
+ * SANCTIONED EXCEPTION (2026-06, explicit human sign-off): the OPTIONAL
27
+ * `titleSize` prop. It defaults to `'h2'` — i.e. the frozen baseline above is
28
+ * unchanged for EVERY existing caller. A caller may pass `titleSize="h1"` to
29
+ * opt the title typography up to `text-h1` (used by the unified Help Center
30
+ * pages). This is additive and default-preserving; do NOT change the default or
31
+ * touch anything else here.
25
32
  * ========================================================================== */
26
33
 
27
34
  import React from 'react'
@@ -59,6 +66,10 @@ export interface TitleBlockProps {
59
66
  */
60
67
  variant?: 'plain' | 'card'
61
68
  className?: string
69
+ /** Title typography size. Default `'h2'` (the frozen baseline). Pass `'h1'` to
70
+ * opt the title up to `text-h1` (the unified Help Center pages). Subtitle stays
71
+ * `text-h6` either way. */
72
+ titleSize?: 'h1' | 'h2'
62
73
  }
63
74
 
64
75
  export function TitleBlock({
@@ -72,9 +83,11 @@ export function TitleBlock({
72
83
  selector,
73
84
  variant = 'plain',
74
85
  className,
86
+ titleSize = 'h2',
75
87
  }: TitleBlockProps) {
76
88
  const hasActions = actions && actions.length > 0
77
89
  const hasMenuActions = !!menuActions && menuActions.some(g => g.items.length > 0)
90
+ const titleClass = titleSize === 'h1' ? 'text-h1' : 'text-h2'
78
91
 
79
92
  return (
80
93
  <div
@@ -113,7 +126,7 @@ export function TitleBlock({
113
126
  )}
114
127
  <div className="flex flex-col justify-center min-w-0 flex-1">
115
128
  {title && (
116
- <h1 className="text-h2 text-ods-text-primary truncate" title={title}>{title}</h1>
129
+ <h1 className={cn(titleClass, 'text-ods-text-primary truncate')} title={title}>{title}</h1>
117
130
  )}
118
131
  {subtitle && (
119
132
  <p className="text-h6 text-ods-text-secondary truncate" title={subtitle}>{subtitle}</p>
@@ -121,7 +134,7 @@ export function TitleBlock({
121
134
  </div>
122
135
  </div>
123
136
  ) : (
124
- title && <h1 className="text-h2 text-ods-text-primary">{title}</h1>
137
+ title && <h1 className={cn(titleClass, 'text-ods-text-primary')}>{title}</h1>
125
138
  )}
126
139
  </div>
127
140