@flamingo-stack/openframe-frontend-core 0.0.286 → 0.0.287
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-HLQW7MWJ.cjs → chunk-3SDBXXDP.cjs} +21 -21
- package/dist/{chunk-HLQW7MWJ.cjs.map → chunk-3SDBXXDP.cjs.map} +1 -1
- package/dist/{chunk-4WACBTZU.cjs → chunk-6AW25OS6.cjs} +25 -25
- package/dist/{chunk-4WACBTZU.cjs.map → chunk-6AW25OS6.cjs.map} +1 -1
- package/dist/{chunk-QCKN37OP.cjs → chunk-6CSW5TMS.cjs} +35 -35
- package/dist/{chunk-QCKN37OP.cjs.map → chunk-6CSW5TMS.cjs.map} +1 -1
- package/dist/{chunk-YVB3VDIQ.js → chunk-7EYWERFT.js} +2 -2
- package/dist/{chunk-6N26CURS.cjs → chunk-D6RK5YXX.cjs} +25 -3
- package/dist/chunk-D6RK5YXX.cjs.map +1 -0
- package/dist/{chunk-FSBDVT6R.js → chunk-EFYXPR43.js} +2 -2
- package/dist/{chunk-XQL4WDML.js → chunk-GJDXIVEQ.js} +3 -3
- package/dist/{chunk-D5YY5U6J.cjs → chunk-JQ4I743L.cjs} +11 -11
- package/dist/{chunk-D5YY5U6J.cjs.map → chunk-JQ4I743L.cjs.map} +1 -1
- package/dist/{chunk-C6SCWXDP.js → chunk-MV67MBV3.js} +3 -3
- package/dist/{chunk-BBZ7AX5H.cjs → chunk-MWS25U4U.cjs} +10 -10
- package/dist/{chunk-BBZ7AX5H.cjs.map → chunk-MWS25U4U.cjs.map} +1 -1
- package/dist/{chunk-DDAT4RKX.js → chunk-ODR6A6FC.js} +24 -2
- package/dist/chunk-ODR6A6FC.js.map +1 -0
- package/dist/{chunk-GDF2R2ER.cjs → chunk-OXC72UIP.cjs} +120 -120
- package/dist/{chunk-GDF2R2ER.cjs.map → chunk-OXC72UIP.cjs.map} +1 -1
- package/dist/{chunk-RQ6RTBKF.cjs → chunk-RG6FNZUA.cjs} +65 -27
- package/dist/chunk-RG6FNZUA.cjs.map +1 -0
- package/dist/{chunk-5BTZOVDQ.js → chunk-RWCA2ZQK.js} +2 -2
- package/dist/{chunk-QF2X6PTD.js → chunk-TY2EB7VK.js} +58 -20
- package/dist/chunk-TY2EB7VK.js.map +1 -0
- package/dist/{chunk-VCQ3CTYK.js → chunk-ZYLQMCHW.js} +3 -3
- package/dist/components/chat/index.cjs +3 -3
- package/dist/components/chat/index.js +2 -2
- package/dist/components/contact/index.cjs +4 -4
- package/dist/components/contact/index.js +3 -3
- package/dist/components/docs/index.cjs +3 -3
- package/dist/components/docs/index.js +2 -2
- package/dist/components/embeds/index.cjs +4 -4
- package/dist/components/embeds/index.js +3 -3
- package/dist/components/faq/faq-section.d.ts.map +1 -1
- package/dist/components/faq/index.cjs +4 -4
- package/dist/components/faq/index.js +3 -3
- package/dist/components/faq-accordion.d.ts.map +1 -1
- package/dist/components/features/index.cjs +3 -3
- package/dist/components/features/index.js +2 -2
- package/dist/components/index.cjs +142 -142
- package/dist/components/index.js +7 -7
- package/dist/components/navigation/index.cjs +3 -3
- package/dist/components/navigation/index.js +2 -2
- package/dist/components/related-content/index.cjs +4 -4
- package/dist/components/related-content/index.js +3 -3
- package/dist/components/tickets/index.cjs +53 -53
- package/dist/components/tickets/index.js +4 -4
- package/dist/components/ui/index.cjs +3 -3
- package/dist/components/ui/index.js +2 -2
- package/dist/index.cjs +9 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -2
- package/dist/types/marketing.d.ts +1 -1
- package/dist/types/marketing.d.ts.map +1 -1
- package/dist/utils/faq-anchor.d.ts +51 -0
- package/dist/utils/faq-anchor.d.ts.map +1 -0
- package/dist/utils/index.cjs +23 -1
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +21 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/list-url.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/faq/faq-section.tsx +78 -26
- package/src/components/faq-accordion.tsx +8 -1
- package/src/types/marketing.ts +1 -0
- package/src/utils/faq-anchor.ts +70 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/list-url.ts +1 -0
- package/dist/chunk-6N26CURS.cjs.map +0 -1
- package/dist/chunk-DDAT4RKX.js.map +0 -1
- package/dist/chunk-QF2X6PTD.js.map +0 -1
- package/dist/chunk-RQ6RTBKF.cjs.map +0 -1
- /package/dist/{chunk-YVB3VDIQ.js.map → chunk-7EYWERFT.js.map} +0 -0
- /package/dist/{chunk-FSBDVT6R.js.map → chunk-EFYXPR43.js.map} +0 -0
- /package/dist/{chunk-XQL4WDML.js.map → chunk-GJDXIVEQ.js.map} +0 -0
- /package/dist/{chunk-C6SCWXDP.js.map → chunk-MV67MBV3.js.map} +0 -0
- /package/dist/{chunk-5BTZOVDQ.js.map → chunk-RWCA2ZQK.js.map} +0 -0
- /package/dist/{chunk-VCQ3CTYK.js.map → chunk-ZYLQMCHW.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-url.d.ts","sourceRoot":"","sources":["../../src/utils/list-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAWH;;;;iEAIiE;AACjE,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAEtE;
|
|
1
|
+
{"version":3,"file":"list-url.d.ts","sourceRoot":"","sources":["../../src/utils/list-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAWH;;;;iEAIiE;AACjE,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAEtE;AA6BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,SAAK,GAAG,MAAM,GAAG,IAAI,CAa5F"}
|
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import { useSelfFetch } from '../../hooks/use-self-fetch'
|
|
|
7
7
|
import { buildSuggestionUrl } from '../../utils/suggestion-url'
|
|
8
8
|
import { serializeJsonLd } from '../../utils/common'
|
|
9
9
|
import { scrollElementIntoView } from '../../utils/scroll-into-view'
|
|
10
|
+
import { faqSectionSlug, faqItemAnchor, parseFaqHash, type FaqHashTarget } from '../../utils/faq-anchor'
|
|
10
11
|
import { cn } from '../../utils/cn'
|
|
11
12
|
import { buildFaqJsonLdFromFaqs, type FaqSchemaOptions } from './json-ld'
|
|
12
13
|
import { SECTION_HEADING_CLASS } from '../layout/page-heading'
|
|
@@ -59,19 +60,6 @@ function buildFaqsUrl(
|
|
|
59
60
|
return buildSuggestionUrl('/api/faqs', { apiBaseUrl, entityType, entityId, count: minResults })
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
/** Stable, URL-safe anchor id for a category. Prefixed so it can't collide
|
|
63
|
-
* with other in-page ids, and so a bare numeric/blank section still yields a
|
|
64
|
-
* valid id. */
|
|
65
|
-
function sectionSlug(section: string): string {
|
|
66
|
-
return (
|
|
67
|
-
'faq-' +
|
|
68
|
-
section
|
|
69
|
-
.toLowerCase()
|
|
70
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
71
|
-
.replace(/^-+|-+$/g, '')
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
63
|
interface FaqGroup {
|
|
76
64
|
/** null → the uncategorized bucket: no heading, no jump pill, rendered last. */
|
|
77
65
|
section: string | null
|
|
@@ -98,7 +86,7 @@ function groupFaqsBySection(faqs: Faq[]): FaqGroup[] {
|
|
|
98
86
|
}
|
|
99
87
|
let group = byName.get(name)
|
|
100
88
|
if (!group) {
|
|
101
|
-
group = { section: name, slug:
|
|
89
|
+
group = { section: name, slug: faqSectionSlug(name), items: [] }
|
|
102
90
|
byName.set(name, group)
|
|
103
91
|
order.push(name)
|
|
104
92
|
}
|
|
@@ -113,6 +101,12 @@ function groupFaqsBySection(faqs: Faq[]): FaqGroup[] {
|
|
|
113
101
|
* scroll uses, so a category jump lands below the header, not under it. */
|
|
114
102
|
const FAQ_NAV_HEADER_OFFSET = 96
|
|
115
103
|
|
|
104
|
+
/** Map key for the uncategorized bucket — `group.slug` is null for it, so
|
|
105
|
+
* every per-group map (default-open ids, accordion keys) uses this sentinel
|
|
106
|
+
* to keep the lookup typed. */
|
|
107
|
+
const UNCATEGORIZED_KEY = '__uncategorized__'
|
|
108
|
+
const groupKey = (g: FaqGroup): string => g.slug ?? UNCATEGORIZED_KEY
|
|
109
|
+
|
|
116
110
|
/**
|
|
117
111
|
* Grouped FAQ layout: a category jump-nav above stacked `<h2>` category
|
|
118
112
|
* sections (each its own accordion). Isolated into its own component so the
|
|
@@ -177,6 +171,54 @@ function GroupedFaqList({
|
|
|
177
171
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
178
172
|
}, [slugKey])
|
|
179
173
|
|
|
174
|
+
// ─── Hash dispatch — `/faqs#faq-item-<id>` or `/faqs#faq-<section-slug>` ──
|
|
175
|
+
// Tracks the current hash so:
|
|
176
|
+
// 1. an item-kind hash seeds `defaultOpenIds` on the matching accordion
|
|
177
|
+
// (auto-expands the cited question);
|
|
178
|
+
// 2. either kind triggers the cancellation-proof tween scroll with the
|
|
179
|
+
// sticky-header offset (native browser hash scroll runs once, ignores
|
|
180
|
+
// our offset — re-running the tween puts the target in the right spot).
|
|
181
|
+
// Listens to `hashchange` so back/forward replays the same behavior. SSR-
|
|
182
|
+
// safe: initial null state matches the server render; the first effect
|
|
183
|
+
// tick on the client updates it.
|
|
184
|
+
const [hashTarget, setHashTarget] = useState<FaqHashTarget | null>(null)
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
const refresh = () => setHashTarget(parseFaqHash(window.location.hash))
|
|
187
|
+
refresh()
|
|
188
|
+
window.addEventListener('hashchange', refresh)
|
|
189
|
+
return () => window.removeEventListener('hashchange', refresh)
|
|
190
|
+
}, [])
|
|
191
|
+
|
|
192
|
+
// Per-group default-open set when the hash points at an item. The map key
|
|
193
|
+
// matches `groupKey(group)` so the render-time lookup is O(1) per group.
|
|
194
|
+
const defaultOpenByGroupKey = useMemo(() => {
|
|
195
|
+
if (hashTarget?.kind !== 'item') return null
|
|
196
|
+
const targetId = hashTarget.rawId
|
|
197
|
+
const result = new Map<string, (string | number)[]>()
|
|
198
|
+
for (const group of groups) {
|
|
199
|
+
const hit = group.items.find((i) => String(i.id) === targetId)
|
|
200
|
+
if (hit) result.set(groupKey(group), [hit.id])
|
|
201
|
+
}
|
|
202
|
+
return result.size > 0 ? result : null
|
|
203
|
+
}, [groups, hashTarget])
|
|
204
|
+
|
|
205
|
+
// Accordion is uncontrolled — `defaultOpenIds` is only consumed at mount,
|
|
206
|
+
// so a new item hash needs a remount to honor it. Keying off the item-id
|
|
207
|
+
// suffix triggers exactly the remount we need (and stays stable when the
|
|
208
|
+
// hash points at a section, so category navigation never disturbs the
|
|
209
|
+
// accordion's open state).
|
|
210
|
+
const accordionKeySuffix =
|
|
211
|
+
hashTarget?.kind === 'item' ? `item:${hashTarget.rawId}` : 'default'
|
|
212
|
+
|
|
213
|
+
useEffect(() => {
|
|
214
|
+
if (!hashTarget) return
|
|
215
|
+
const elId =
|
|
216
|
+
hashTarget.kind === 'item' ? faqItemAnchor(hashTarget.rawId) : hashTarget.slug
|
|
217
|
+
const el = document.getElementById(elId)
|
|
218
|
+
if (el) scrollElementIntoView(el, { headerOffset: FAQ_NAV_HEADER_OFFSET })
|
|
219
|
+
if (hashTarget.kind === 'section') setActiveSlug(hashTarget.slug)
|
|
220
|
+
}, [hashTarget])
|
|
221
|
+
|
|
180
222
|
const handleJump = useCallback(
|
|
181
223
|
(e: React.MouseEvent<HTMLAnchorElement>, slug: string) => {
|
|
182
224
|
e.preventDefault()
|
|
@@ -215,18 +257,28 @@ function GroupedFaqList({
|
|
|
215
257
|
</nav>
|
|
216
258
|
)}
|
|
217
259
|
<div className="space-y-10">
|
|
218
|
-
{groups.map((group) =>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
260
|
+
{groups.map((group) => {
|
|
261
|
+
const key = groupKey(group)
|
|
262
|
+
return (
|
|
263
|
+
<section
|
|
264
|
+
key={key}
|
|
265
|
+
id={group.slug ?? undefined}
|
|
266
|
+
className="scroll-mt-24 space-y-4"
|
|
267
|
+
>
|
|
268
|
+
{group.section && (
|
|
269
|
+
<CategoryHeading className={SECTION_HEADING_CLASS}>{group.section}</CategoryHeading>
|
|
270
|
+
)}
|
|
271
|
+
<FaqAccordion
|
|
272
|
+
// Re-key on item-hash changes so the remount picks up the new
|
|
273
|
+
// `defaultOpenIds` (the accordion is uncontrolled). Stable for
|
|
274
|
+
// section hashes — category navigation doesn't disturb state.
|
|
275
|
+
key={`${key}:${accordionKeySuffix}`}
|
|
276
|
+
items={group.items}
|
|
277
|
+
defaultOpenIds={defaultOpenByGroupKey?.get(key)}
|
|
278
|
+
/>
|
|
279
|
+
</section>
|
|
280
|
+
)
|
|
281
|
+
})}
|
|
230
282
|
</div>
|
|
231
283
|
</div>
|
|
232
284
|
)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import React, { useRef, useState, useEffect, useCallback } from 'react'
|
|
4
4
|
import { ChevronButton } from './ui/chevron-button'
|
|
5
5
|
import { cn } from "../utils/cn"
|
|
6
|
+
import { faqItemAnchor } from "../utils/faq-anchor"
|
|
6
7
|
|
|
7
8
|
export interface FaqItem {
|
|
8
9
|
id: number | string
|
|
@@ -60,7 +61,13 @@ export function FaqAccordion({ items, defaultOpenIds = [] }: FaqAccordionProps)
|
|
|
60
61
|
return (
|
|
61
62
|
<div
|
|
62
63
|
key={item.id}
|
|
63
|
-
|
|
64
|
+
// Per-row anchor — chat citation chips (`/faqs#faq-item-<id>`) land
|
|
65
|
+
// here via native browser hash scroll AND via `FaqSection`'s tween
|
|
66
|
+
// dispatch. `scroll-mt-24` keeps the row header below the 96px
|
|
67
|
+
// sticky nav offset (matches `<section>`'s scroll-margin for
|
|
68
|
+
// category anchors).
|
|
69
|
+
id={faqItemAnchor(item.id)}
|
|
70
|
+
className={cn('group scroll-mt-24 transition-colors hover:bg-[#1E1E1E]', isOpen ? 'bg-ods-bg' : 'bg-transparent')}
|
|
64
71
|
>
|
|
65
72
|
{/* Header */}
|
|
66
73
|
<div
|
package/src/types/marketing.ts
CHANGED
|
@@ -347,6 +347,7 @@ export type ContentSourceType =
|
|
|
347
347
|
| 'investor_update' // Investor updates
|
|
348
348
|
| 'onboarding_guide' // Onboarding guides (lives on openframe platform)
|
|
349
349
|
| 'what_i_shipped' // What I Shipped employee check-ins (lives on people-hub)
|
|
350
|
+
| 'faq' // FAQ Q&A pair (single-page /faqs index; deep-link by category anchor)
|
|
350
351
|
| 'from_scratch';
|
|
351
352
|
|
|
352
353
|
export type URLInjectionPreference = 'none' | 'in_post' | 'as_comment';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FAQ anchor SSOTs — TWO complementary deep-link kinds on the `/faqs` page,
|
|
3
|
+
* both rendered straight onto the DOM and recognised by ONE parser. Keeping
|
|
4
|
+
* the format helpers + parser in one file means the page, the chat RAG
|
|
5
|
+
* mapper, and any future consumer can't drift on what a hash means.
|
|
6
|
+
*
|
|
7
|
+
* `/faqs#faq-pricing` → category section header (jump-nav pills,
|
|
8
|
+
* scroll-spy)
|
|
9
|
+
* `/faqs#faq-item-42` → individual question (chat citation chips —
|
|
10
|
+
* auto-expands the row + scrolls to it)
|
|
11
|
+
*
|
|
12
|
+
* Reserved namespaces — `faq-item-<digits>` is the item shape; everything
|
|
13
|
+
* else starting with `faq-` is a section slug. `faqSectionSlug` lowercases
|
|
14
|
+
* + dash-collapses + dash-trims, so a section name would only collide with
|
|
15
|
+
* the item shape if it slugified to `faq-item-<digits-only>` (e.g. a
|
|
16
|
+
* category called "Item 42") — none of the 21 production sections do, and
|
|
17
|
+
* `parseFaqHash`'s regex is digits-only so future word-suffixed names like
|
|
18
|
+
* "Item Whatever" (slugifies to `faq-item-whatever`) are also safe.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** Stable, URL-safe anchor id for a category. Prefixed with `faq-` so it
|
|
22
|
+
* can't collide with other in-page ids, and so a bare numeric/blank
|
|
23
|
+
* section still yields a valid id. The helper assumes the caller has
|
|
24
|
+
* already verified the section is a non-blank string (matches
|
|
25
|
+
* `faq-section.tsx`'s `groupFaqsBySection` precondition). */
|
|
26
|
+
export function faqSectionSlug(section: string): string {
|
|
27
|
+
return (
|
|
28
|
+
'faq-' +
|
|
29
|
+
section
|
|
30
|
+
.toLowerCase()
|
|
31
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
32
|
+
.replace(/^-+|-+$/g, '')
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Stable anchor for an individual FAQ row. Rendered as the row container's
|
|
37
|
+
* `id` attribute by `FaqAccordion`; consumed by `FaqSection` (auto-open +
|
|
38
|
+
* auto-scroll on mount) AND by the hub's RAG mapper so chat citations
|
|
39
|
+
* deep-link to the specific question, not just its category. The id is
|
|
40
|
+
* stringified verbatim — the FAQ schema uses integer PKs so `parseFaqHash`'s
|
|
41
|
+
* digits-only regex always matches a real row. */
|
|
42
|
+
export function faqItemAnchor(id: number | string): string {
|
|
43
|
+
return `faq-item-${id}`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Discriminated parse of a `/faqs#…` hash. Returns null for an empty,
|
|
47
|
+
* missing, or unrecognised hash so callers can early-out without
|
|
48
|
+
* scattering string parsing across the file.
|
|
49
|
+
*
|
|
50
|
+
* parseFaqHash('#faq-item-42') → { kind: 'item', rawId: '42' }
|
|
51
|
+
* parseFaqHash('#faq-pricing') → { kind: 'section', slug: 'faq-pricing' }
|
|
52
|
+
* parseFaqHash('#anything-else') → null
|
|
53
|
+
*
|
|
54
|
+
* `rawId` is the matched digit run as a string — the caller compares it
|
|
55
|
+
* to `String(item.id)` so coercion stays at the comparison site. */
|
|
56
|
+
export type FaqHashTarget =
|
|
57
|
+
| { kind: 'item'; rawId: string }
|
|
58
|
+
| { kind: 'section'; slug: string }
|
|
59
|
+
|
|
60
|
+
const FAQ_ITEM_HASH_RE = /^faq-item-(\d+)$/
|
|
61
|
+
|
|
62
|
+
export function parseFaqHash(hash: string | null | undefined): FaqHashTarget | null {
|
|
63
|
+
if (!hash) return null
|
|
64
|
+
const trimmed = hash.replace(/^#/, '')
|
|
65
|
+
if (!trimmed) return null
|
|
66
|
+
const itemMatch = FAQ_ITEM_HASH_RE.exec(trimmed)
|
|
67
|
+
if (itemMatch) return { kind: 'item', rawId: itemMatch[1] }
|
|
68
|
+
if (trimmed.startsWith('faq-')) return { kind: 'section', slug: trimmed }
|
|
69
|
+
return null
|
|
70
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -253,6 +253,13 @@ export {
|
|
|
253
253
|
// Pure + server-safe (the hub imports it server-side from this barrel).
|
|
254
254
|
export { buildListUrl, canonicalContentRefType } from './list-url'
|
|
255
255
|
|
|
256
|
+
// FAQ anchor SSOTs — section (`faq-<slug>`) AND item (`faq-item-<id>`)
|
|
257
|
+
// formats plus the parser, all rendered by `FaqSection`/`FaqAccordion`
|
|
258
|
+
// and recognised by the hub's RAG mapper. One algo per kind, one parser,
|
|
259
|
+
// zero drift across page + chat + future consumers.
|
|
260
|
+
export { faqSectionSlug, faqItemAnchor, parseFaqHash } from './faq-anchor'
|
|
261
|
+
export type { FaqHashTarget } from './faq-anchor'
|
|
262
|
+
|
|
256
263
|
// Content-ref group registry (labels/order/layout per rail type) + list-API
|
|
257
264
|
// response normalizers + the shared suggestion-fetch URL composer — all
|
|
258
265
|
// pure + server-safe; the hub re-exports these from its config/util shims.
|
package/src/utils/list-url.ts
CHANGED
|
@@ -70,6 +70,7 @@ const BUILDERS: Record<string, (ids: string[], base: string) => string> = {
|
|
|
70
70
|
product_release: (ids, b) => `${b}/api/releases?ids=${ids.join(',')}&limit=${ids.length}`,
|
|
71
71
|
customer_interview: (ids, b) => `${b}/api/customer-interviews?ids=${ids.join(',')}&limit=${ids.length}`,
|
|
72
72
|
investor_update: (ids, b) => `${b}/api/investor-updates?ids=${ids.join(',')}&limit=${ids.length}`,
|
|
73
|
+
faq: (ids, b) => `${b}/api/faqs?ids=${ids.join(',')}&limit=${ids.length}`,
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
/**
|