@flamingo-stack/openframe-frontend-core 0.0.705 → 0.0.706-snapshot.20261006181108
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/chat-protocol/index.cjs +23 -14
- package/dist/chat-protocol/index.js +23 -14
- package/dist/chat-protocol/nats-decoder.d.ts.map +1 -1
- package/dist/chat-protocol/source-metadata.d.ts +11 -2
- package/dist/chat-protocol/source-metadata.d.ts.map +1 -1
- package/dist/{chunk-QFXRPRFT.js → chunk-2YHNQAMU.js} +3 -3
- package/dist/{chunk-YHM5AWTT.js → chunk-3FZP73R4.js} +6 -6
- package/dist/{chunk-VR2ZLFCP.js → chunk-4IBPRIQH.js} +1 -1
- package/dist/{chunk-AQWZNP6A.js → chunk-4RVC6TCE.js} +4 -4
- package/dist/{chunk-OUY3HHW6.cjs → chunk-4UMOD5NU.cjs} +928 -539
- package/dist/{chunk-IKTQ3ZAG.cjs → chunk-54L6NMKQ.cjs} +6 -6
- package/dist/{chunk-A75QY6CD.cjs → chunk-56LOCS37.cjs} +21 -21
- package/dist/{chunk-WA6GUYQ4.cjs → chunk-5CMYEGHE.cjs} +104 -104
- package/dist/{chunk-VA5T32XA.js → chunk-632NGOIH.js} +2 -2
- package/dist/{chunk-MMOODW57.cjs → chunk-6NTPY5QA.cjs} +1887 -94
- package/dist/{chunk-VESKITRQ.cjs → chunk-7XVBJDH7.cjs} +728 -732
- package/dist/{chunk-3MX5S4CF.cjs → chunk-AGNG62O2.cjs} +905 -2564
- package/dist/{chunk-ZSAO2HBW.js → chunk-BETJB7UV.js} +15 -15
- package/dist/{chunk-MP2C3LJ4.js → chunk-CUME3VTQ.js} +1 -1
- package/dist/{chunk-PDWVPI3S.js → chunk-CZ7Y7UG4.js} +4 -72
- package/dist/{chunk-F6I6XZMN.js → chunk-E2TQZIOJ.js} +5 -5
- package/dist/{chunk-X5MQ7JRP.js → chunk-ECXW3RIH.js} +9 -9
- package/dist/{chunk-JEZKGCZI.cjs → chunk-EUSDLX5W.cjs} +26 -26
- package/dist/{chunk-6NJKKO73.cjs → chunk-F4E3L3KV.cjs} +15 -15
- package/dist/{chunk-MFFCUVWG.js → chunk-F57ECE2I.js} +1 -1
- package/dist/{chunk-F6AFPNDF.js → chunk-FBY4V3YS.js} +15 -15
- package/dist/{chunk-CH5232HV.js → chunk-FI6GMDO7.js} +2455 -662
- package/dist/{chunk-NDESEPW5.js → chunk-FXJ3WWUB.js} +68 -0
- package/dist/{chunk-FCGC42TS.js → chunk-HTBN3XYF.js} +57 -61
- package/dist/{chunk-ZSAGLQOD.cjs → chunk-I43ZVJRL.cjs} +17 -17
- package/dist/{chunk-7VVFKJY5.js → chunk-IBQZMRWO.js} +1796 -3455
- package/dist/{chunk-4KX6OED2.cjs → chunk-JFSLQ2XS.cjs} +46 -46
- package/dist/{chunk-5HBHO5TB.js → chunk-JPG7OHEG.js} +1 -1
- package/dist/{chunk-MKXO4Q5P.js → chunk-KUC673HM.js} +383 -142
- package/dist/{chunk-4I45Y3DN.cjs → chunk-L3Q7R7CQ.cjs} +6 -6
- package/dist/{chunk-X72J4ACL.cjs → chunk-LLSUVPQC.cjs} +252 -8
- package/dist/{chunk-RKV5B7EU.cjs → chunk-LM7TXMLU.cjs} +72 -4
- package/dist/{chunk-PN2RKPDF.js → chunk-LSQPH73L.js} +10 -10
- package/dist/{chunk-HPWWNJE7.cjs → chunk-MY3JYZQY.cjs} +89 -89
- package/dist/{chunk-2YXVWZVF.js → chunk-N45D4ZXQ.js} +959 -715
- package/dist/{chunk-Z2VNQQ74.js → chunk-NCPTID44.js} +978 -942
- package/dist/{chunk-KOWVJD4V.cjs → chunk-O6WNIA6W.cjs} +56 -56
- package/dist/{chunk-ABU3TGXA.cjs → chunk-OF6GEI5A.cjs} +3 -3
- package/dist/{chunk-OHFS7VOU.cjs → chunk-PLYEKV3N.cjs} +2 -2
- package/dist/{chunk-VHCACDKP.cjs → chunk-RQRX4YC3.cjs} +39 -39
- package/dist/{chunk-DW7G4KG3.js → chunk-RZNRVXHH.js} +3 -3
- package/dist/{chunk-G5A3PSPV.js → chunk-SGJP2WKD.js} +1080 -691
- package/dist/{chunk-7LS22BZU.cjs → chunk-STXYW25T.cjs} +14 -14
- package/dist/{chunk-YFBM2K6X.cjs → chunk-TB5EDWRC.cjs} +4 -4
- package/dist/{chunk-RBDP4WDE.js → chunk-U6BWEKJC.js} +6 -6
- package/dist/{chunk-XOYH2YQE.cjs → chunk-UDFRUKLC.cjs} +2 -2
- package/dist/{chunk-TYWLNCNH.cjs → chunk-UVTD52MD.cjs} +14 -82
- package/dist/{chunk-N3COXDBH.cjs → chunk-VX4E6YSB.cjs} +41 -5
- package/dist/{chunk-2QEUFXNS.cjs → chunk-WCVZCGK5.cjs} +312 -71
- package/dist/{chunk-6XIF2Z7I.js → chunk-WMX26HB5.js} +3 -3
- package/dist/{chunk-IHERL5V4.cjs → chunk-WXAT5C4C.cjs} +34 -34
- package/dist/{chunk-D7BTSVMS.cjs → chunk-Y2GSOUCS.cjs} +2 -2
- package/dist/{chunk-6SEANMOU.js → chunk-Y5VSOYPS.js} +11 -11
- package/dist/{chunk-DENB2XJC.js → chunk-YQWTGQG5.js} +2 -2
- package/dist/components/case-studies/index.cjs +30 -32
- package/dist/components/case-studies/index.js +14 -16
- package/dist/components/chat/entity-cards/case-study-card.d.ts +11 -4
- package/dist/components/chat/entity-cards/case-study-card.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +9 -11
- package/dist/components/chat/index.js +14 -16
- package/dist/components/chat/types/message.types.d.ts +20 -16
- package/dist/components/chat/types/message.types.d.ts.map +1 -1
- package/dist/components/chat/types/unified-chat-state.types.d.ts +1 -1
- package/dist/components/chat/utils/icon-library.d.ts.map +1 -1
- package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +12 -14
- package/dist/components/contact/index.js +11 -13
- package/dist/components/docs/index.cjs +15 -17
- package/dist/components/docs/index.js +14 -16
- package/dist/components/embeds/index.cjs +12 -14
- package/dist/components/embeds/index.js +11 -13
- package/dist/components/faq/index.cjs +13 -15
- package/dist/components/faq/index.js +12 -14
- package/dist/components/features/index.cjs +12 -14
- package/dist/components/features/index.js +21 -23
- package/dist/components/help-center-pages/index.cjs +118 -120
- package/dist/components/help-center-pages/index.js +33 -35
- package/dist/components/icons/index.cjs +3 -5
- package/dist/components/icons/index.js +9 -11
- package/dist/components/icons-v2-generated/index.cjs +3 -5
- package/dist/components/icons-v2-generated/index.js +2 -4
- package/dist/components/index.cjs +86 -159
- package/dist/components/index.d.ts +0 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +329 -402
- package/dist/components/loading/page-layout-skeleton.d.ts +1 -1
- package/dist/components/meeting-scheduler/index.cjs +62 -64
- package/dist/components/meeting-scheduler/index.js +12 -14
- package/dist/components/navigation/index.cjs +28 -16
- package/dist/components/navigation/index.d.ts +14 -10
- package/dist/components/navigation/index.d.ts.map +1 -1
- package/dist/components/navigation/index.js +38 -26
- package/dist/components/navigation/mingo-ai-button.d.ts +38 -3
- package/dist/components/navigation/mingo-ai-button.d.ts.map +1 -1
- package/dist/components/navigation/mobile-nav-sheet-id.d.ts +3 -0
- package/dist/components/navigation/mobile-nav-sheet-id.d.ts.map +1 -0
- package/dist/components/navigation/mobile-nav-sheet.d.ts +48 -0
- package/dist/components/navigation/mobile-nav-sheet.d.ts.map +1 -0
- package/dist/components/navigation/nav-item-row.d.ts +27 -0
- package/dist/components/navigation/nav-item-row.d.ts.map +1 -0
- package/dist/components/navigation/nav-panel.d.ts +43 -0
- package/dist/components/navigation/nav-panel.d.ts.map +1 -0
- package/dist/components/navigation/navigation-sidebar-item.d.ts +1 -2
- package/dist/components/navigation/navigation-sidebar-item.d.ts.map +1 -1
- package/dist/components/navigation/site-footer.d.ts +28 -0
- package/dist/components/navigation/site-footer.d.ts.map +1 -0
- package/dist/components/navigation/site-header.d.ts +61 -0
- package/dist/components/navigation/site-header.d.ts.map +1 -0
- package/dist/components/navigation/site-nav-link.d.ts +26 -0
- package/dist/components/navigation/site-nav-link.d.ts.map +1 -0
- package/dist/components/navigation/top-navigation.d.ts +2 -2
- package/dist/components/navigation/top-navigation.d.ts.map +1 -1
- package/dist/components/onboarding-guides/index.cjs +15 -17
- package/dist/components/onboarding-guides/index.js +14 -16
- package/dist/components/related-content/index.cjs +10 -8
- package/dist/components/related-content/index.js +9 -7
- package/dist/components/tickets/index.cjs +16 -18
- package/dist/components/tickets/index.js +15 -17
- package/dist/components/ui/index.cjs +12 -14
- package/dist/components/ui/index.js +17 -19
- package/dist/hooks/index.cjs +19 -11
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +19 -11
- package/dist/hooks/ui/index.d.ts +3 -0
- package/dist/hooks/ui/index.d.ts.map +1 -1
- package/dist/hooks/ui/use-active-section.d.ts +10 -0
- package/dist/hooks/ui/use-active-section.d.ts.map +1 -0
- package/dist/hooks/ui/use-nav-menus.d.ts +48 -0
- package/dist/hooks/ui/use-nav-menus.d.ts.map +1 -0
- package/dist/hooks/ui/use-visitor-os.d.ts +15 -0
- package/dist/hooks/ui/use-visitor-os.d.ts.map +1 -0
- package/dist/hooks/use-location-hash.d.ts +9 -0
- package/dist/hooks/use-location-hash.d.ts.map +1 -0
- package/dist/index.cjs +55 -22
- package/dist/index.js +229 -196
- package/dist/types/case-study.d.ts +9 -0
- package/dist/types/case-study.d.ts.map +1 -1
- package/dist/types/navigation.d.ts +95 -65
- package/dist/types/navigation.d.ts.map +1 -1
- package/dist/utils/index.cjs +55 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +50 -1
- package/dist/utils/source-icons.d.ts.map +1 -1
- package/dist/utils/visitor-os.d.ts +45 -0
- package/dist/utils/visitor-os.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/chat-protocol/nats-decoder.ts +10 -8
- package/src/chat-protocol/source-metadata.ts +25 -2
- package/src/components/chat/entity-cards/case-study-card.tsx +115 -5
- package/src/components/chat/types/message.types.ts +21 -15
- package/src/components/chat/types/unified-chat-state.types.ts +1 -1
- package/src/components/chat/utils/icon-library.tsx +35 -1
- package/src/components/chat/utils/process-historical-messages.ts +12 -4
- package/src/components/index.ts +0 -2
- package/src/components/loading/page-layout-skeleton.tsx +1 -1
- package/src/components/navigation/index.ts +21 -14
- package/src/components/navigation/mingo-ai-button.tsx +139 -63
- package/src/components/navigation/mobile-nav-sheet-id.ts +2 -0
- package/src/components/navigation/mobile-nav-sheet.tsx +241 -0
- package/src/components/navigation/nav-item-row.tsx +129 -0
- package/src/components/navigation/nav-panel.tsx +196 -0
- package/src/components/navigation/navigation-sidebar-item.tsx +1 -2
- package/src/components/navigation/site-footer.tsx +256 -0
- package/src/components/navigation/site-header.tsx +339 -0
- package/src/components/navigation/site-nav-link.tsx +41 -0
- package/src/components/navigation/ticket-alerts-button.tsx +2 -2
- package/src/components/navigation/top-navigation.tsx +2 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/ui/index.ts +3 -0
- package/src/hooks/ui/use-active-section.ts +44 -0
- package/src/hooks/ui/use-nav-menus.ts +200 -0
- package/src/hooks/ui/use-visitor-os.ts +33 -0
- package/src/hooks/use-location-hash.ts +34 -0
- package/src/styles/chat-animations.css +57 -2
- package/src/types/case-study.ts +16 -0
- package/src/types/navigation.ts +80 -66
- package/src/utils/index.ts +1 -0
- package/src/utils/source-icons.ts +13 -0
- package/src/utils/visitor-os.ts +84 -0
- package/dist/chunk-LMBC5FFP.js +0 -43
- package/dist/chunk-O43V3EOS.js +0 -252
- package/dist/chunk-QZVSJF2K.cjs +0 -252
- package/dist/chunk-RALRPFDW.cjs +0 -43
- package/dist/components/footer-waitlist-button.d.ts +0 -29
- package/dist/components/footer-waitlist-button.d.ts.map +0 -1
- package/dist/components/footer.d.ts +0 -47
- package/dist/components/footer.d.ts.map +0 -1
- package/dist/components/navigation/client-only-header.d.ts +0 -8
- package/dist/components/navigation/client-only-header.d.ts.map +0 -1
- package/dist/components/navigation/header-skeleton.d.ts +0 -12
- package/dist/components/navigation/header-skeleton.d.ts.map +0 -1
- package/dist/components/navigation/header.d.ts +0 -9
- package/dist/components/navigation/header.d.ts.map +0 -1
- package/dist/components/navigation/mobile-nav-panel.d.ts +0 -10
- package/dist/components/navigation/mobile-nav-panel.d.ts.map +0 -1
- package/src/components/footer-waitlist-button.tsx +0 -53
- package/src/components/footer.tsx +0 -195
- package/src/components/navigation/client-only-header.tsx +0 -22
- package/src/components/navigation/header-skeleton.tsx +0 -74
- package/src/components/navigation/header.tsx +0 -429
- package/src/components/navigation/mobile-nav-panel.tsx +0 -155
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useSyncExternalStore } from 'react';
|
|
4
|
+
import { detectVisitorOs, type VisitorOs } from '../../utils/visitor-os';
|
|
5
|
+
|
|
6
|
+
export type VisitorOsState = { known: false; os: null } | { known: true; os: VisitorOs | null };
|
|
7
|
+
|
|
8
|
+
const UNKNOWN: VisitorOsState = { known: false, os: null };
|
|
9
|
+
// One state object per answer, so the snapshot is stable between reads.
|
|
10
|
+
const KNOWN = new Map<VisitorOs | null, VisitorOsState>();
|
|
11
|
+
|
|
12
|
+
const subscribe = () => () => {};
|
|
13
|
+
const getServerSnapshot = () => UNKNOWN;
|
|
14
|
+
function getSnapshot(): VisitorOsState {
|
|
15
|
+
// `userAgentData` is the Client Hints API (Chromium only, so not in every DOM typing).
|
|
16
|
+
const stated = (navigator as Navigator & { userAgentData?: { platform?: string } }).userAgentData?.platform;
|
|
17
|
+
const os = detectVisitorOs(navigator.userAgent, { platform: stated, maxTouchPoints: navigator.maxTouchPoints });
|
|
18
|
+
let state = KNOWN.get(os);
|
|
19
|
+
if (!state) {
|
|
20
|
+
state = { known: true, os };
|
|
21
|
+
KNOWN.set(os, state);
|
|
22
|
+
}
|
|
23
|
+
return state;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The visitor's system in the browser, through the one detection rule
|
|
28
|
+
* (`utils/visitor-os`). `known` is false on the server and while React
|
|
29
|
+
* hydrates: the server cannot see the browser, and a guess would mismatch.
|
|
30
|
+
*/
|
|
31
|
+
export function useVisitorOs(): VisitorOsState {
|
|
32
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
33
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useSyncExternalStore } from 'react';
|
|
4
|
+
import { normalizeHashFragment } from '../utils/same-page-hash-nav';
|
|
5
|
+
|
|
6
|
+
/** `navigateSamePageHash` dispatches `hashchange` itself; `popstate` covers back and forward. */
|
|
7
|
+
const HASH_EVENTS = ['hashchange', 'popstate'] as const;
|
|
8
|
+
|
|
9
|
+
function subscribe(onChange: () => void): () => void {
|
|
10
|
+
for (const event of HASH_EVENTS) window.addEventListener(event, onChange);
|
|
11
|
+
return () => {
|
|
12
|
+
for (const event of HASH_EVENTS) window.removeEventListener(event, onChange);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function readHash(): string {
|
|
17
|
+
const raw = normalizeHashFragment(window.location.hash).replace(/^#/, '');
|
|
18
|
+
try {
|
|
19
|
+
return decodeURIComponent(raw);
|
|
20
|
+
} catch {
|
|
21
|
+
return raw;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The URL's hash without its `#`, or `''`: the READ side of same-page anchor
|
|
27
|
+
* navigation (`navigateSamePageHash` writes it, `useScrollToHash` scrolls to
|
|
28
|
+
* it). For a component whose state follows the anchor: a tab group that opens
|
|
29
|
+
* the tab a link names. Empty on the server and during hydration (the server
|
|
30
|
+
* never sees a hash), then the real one.
|
|
31
|
+
*/
|
|
32
|
+
export function useLocationHash(): string {
|
|
33
|
+
return useSyncExternalStore(subscribe, readHash, () => '');
|
|
34
|
+
}
|
|
@@ -134,12 +134,12 @@
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
/* Ring mask: clips the rotating conic layer to a
|
|
137
|
+
/* Ring mask: clips the rotating conic layer to a 1px band along the frame's
|
|
138
138
|
rounded outline (padding-box XOR), so the interior stays fully transparent
|
|
139
139
|
and the host background shows through — no opaque cover element. */
|
|
140
140
|
.mingo-edge-frame {
|
|
141
141
|
overflow: hidden;
|
|
142
|
-
padding:
|
|
142
|
+
padding: 1px;
|
|
143
143
|
-webkit-mask:
|
|
144
144
|
linear-gradient(#fff 0 0) content-box,
|
|
145
145
|
linear-gradient(#fff 0 0);
|
|
@@ -198,3 +198,58 @@
|
|
|
198
198
|
opacity: 0;
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
|
+
|
|
202
|
+
/* -----------------------------------------------------------------------------
|
|
203
|
+
* Site header mega menus: how a panel's CONTENT arrives.
|
|
204
|
+
* open from a closed bar: a short fade and settle.
|
|
205
|
+
* from-start from the menu before it in the row: slides in from the left.
|
|
206
|
+
* from-end from the menu after it: slides in from the right.
|
|
207
|
+
* Between two mega menus the surface itself does not animate (NavPanel hands it
|
|
208
|
+
* over in one frame), so only the content moves, in the direction the pointer
|
|
209
|
+
* travelled. Short and ease-out: it must never make the menu feel slower.
|
|
210
|
+
* Reduced motion: no movement, a plain fade.
|
|
211
|
+
* ---------------------------------------------------------------------------*/
|
|
212
|
+
@keyframes nav-panel-open {
|
|
213
|
+
from {
|
|
214
|
+
opacity: 0;
|
|
215
|
+
transform: translateY(-4px);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@keyframes nav-panel-from-start {
|
|
220
|
+
from {
|
|
221
|
+
opacity: 0;
|
|
222
|
+
transform: translateX(-24px);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@keyframes nav-panel-from-end {
|
|
227
|
+
from {
|
|
228
|
+
opacity: 0;
|
|
229
|
+
transform: translateX(24px);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@keyframes nav-panel-fade {
|
|
234
|
+
from {
|
|
235
|
+
opacity: 0;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.nav-panel-content[data-motion='open'] {
|
|
240
|
+
animation: nav-panel-open 180ms cubic-bezier(0.2, 0, 0, 1);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.nav-panel-content[data-motion='from-start'] {
|
|
244
|
+
animation: nav-panel-from-start 220ms cubic-bezier(0.2, 0, 0, 1);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.nav-panel-content[data-motion='from-end'] {
|
|
248
|
+
animation: nav-panel-from-end 220ms cubic-bezier(0.2, 0, 0, 1);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
@media (prefers-reduced-motion: reduce) {
|
|
252
|
+
.nav-panel-content[data-motion] {
|
|
253
|
+
animation: nav-panel-fade 120ms linear;
|
|
254
|
+
}
|
|
255
|
+
}
|
package/src/types/case-study.ts
CHANGED
|
@@ -82,6 +82,22 @@ export interface CaseStudy {
|
|
|
82
82
|
case_study_tags?: TagAssoc[];
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* What a case study card reads: the story, its cover and video, whose story it
|
|
87
|
+
* is and who tells it. A full `CaseStudy` row satisfies it; a surface that ships
|
|
88
|
+
* the card's data to the browser (the site menu) sends only this.
|
|
89
|
+
*/
|
|
90
|
+
export type CaseStudyCardData = Pick<CaseStudy, 'id' | 'title' | 'summary' | 'featured_image'> &
|
|
91
|
+
Partial<
|
|
92
|
+
Pick<
|
|
93
|
+
CaseStudy,
|
|
94
|
+
'main_video_url' | 'main_video_thumbnail' | 'highlight_video_url' | 'highlight_video_thumbnail' | 'video_bites'
|
|
95
|
+
>
|
|
96
|
+
> & {
|
|
97
|
+
user?: Pick<UserProfile, 'full_name' | 'job_title'> & Partial<Pick<UserProfile, 'avatar_url'>>;
|
|
98
|
+
msp?: Pick<MSP, 'name' | 'icon_url'>;
|
|
99
|
+
};
|
|
100
|
+
|
|
85
101
|
export interface CreateCaseStudyData {
|
|
86
102
|
title: string;
|
|
87
103
|
slug: string;
|
package/src/types/navigation.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
+
import type { CaseStudyCardData } from './case-study';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Base navigation item interface used across all navigation components
|
|
@@ -13,80 +14,93 @@ export interface NavigationItem {
|
|
|
13
14
|
children?: NavigationItem[];
|
|
14
15
|
onClick?: () => void;
|
|
15
16
|
element?: React.ReactNode; // For completely custom navigation items
|
|
16
|
-
isExternal?: boolean; // For external links that open in new tab
|
|
17
|
-
type?: 'single' | 'dropdown'; // Type of navigation item
|
|
18
|
-
dropdownContent?: React.ReactNode; // Additional content for dropdown (e.g., social icons)
|
|
19
|
-
showDropdownDivider?: boolean; // Whether to show divider above dropdown content
|
|
20
|
-
className?: string; // Custom CSS classes to override default styling
|
|
21
|
-
dropdownClassName?: string; // Custom CSS classes for dropdown menu background
|
|
22
17
|
}
|
|
23
18
|
|
|
24
19
|
/**
|
|
25
|
-
*
|
|
20
|
+
* The site navigation model: ONE serializable description of a platform's
|
|
21
|
+
* header, mega menus, mobile menu and footer. Plain data only (no functions, no
|
|
22
|
+
* React elements), so a server resolver can build it and hand it to the client
|
|
23
|
+
* components (`SiteHeader`, `MobileNavSheet`, `SiteFooter`), which only render.
|
|
24
|
+
*
|
|
25
|
+
* A link is declared once and referenced from every surface, so one change to
|
|
26
|
+
* the model changes the header, the mobile menu and the footer together.
|
|
26
27
|
*/
|
|
27
|
-
export interface
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* for the default "Mingo AI". */
|
|
58
|
-
label?: string;
|
|
59
|
-
};
|
|
60
|
-
/** Support-ticket alerts cell (`TicketAlertsButton`), rendered before
|
|
61
|
-
* the Mingo launcher in the flush cell row. Attention-only: renders
|
|
62
|
-
* nothing unless a `<TicketLiveProvider>` is mounted AND there are
|
|
63
|
-
* unread support replies — declaring it is side-effect-free. */
|
|
64
|
-
tickets?: {
|
|
65
|
-
/** BASE path of the tickets surface (any nesting prefix allowed —
|
|
66
|
-
* '/tickets', '/support/portal/tickets'). The cell builds the SSOT
|
|
67
|
-
* deep link `<href>?ticket=<id>` for the newest-unread ticket. */
|
|
68
|
-
href: string;
|
|
69
|
-
/** Optional host navigation (router push) — receives the FULL
|
|
70
|
-
* computed href. Defaults to `window.location.assign`. */
|
|
71
|
-
onClick?: (href: string) => void;
|
|
72
|
-
};
|
|
73
|
-
className?: string;
|
|
74
|
-
style?: React.CSSProperties;
|
|
75
|
-
autoHide?: boolean;
|
|
76
|
-
backgroundColor?: string; // ODS background color (e.g., 'bg-ods-card', 'bg-ods-accent')
|
|
28
|
+
export interface NavLink {
|
|
29
|
+
id: string;
|
|
30
|
+
/** The label shown in menus and the footer. */
|
|
31
|
+
label: string;
|
|
32
|
+
/** Internal path, internal path with `#anchor`, or absolute URL. */
|
|
33
|
+
href: string;
|
|
34
|
+
/** One line shown under the label in mega menus and the mobile sheet. */
|
|
35
|
+
description?: string;
|
|
36
|
+
/** An `EntityIcon` glyph name. */
|
|
37
|
+
iconName?: string;
|
|
38
|
+
/**
|
|
39
|
+
* A server-configured icon (an agent's avatar: a packaged mark by name, or an
|
|
40
|
+
* uploaded image), in `EntityIcon`'s own shape. Drawn round, and it wins over
|
|
41
|
+
* `iconName`.
|
|
42
|
+
*/
|
|
43
|
+
icon?: { name?: string | null; url?: string | null; props?: Record<string, unknown> | null };
|
|
44
|
+
/** "Chocolatey · Homebrew · WinGet"; rendered as "Built on ...". */
|
|
45
|
+
builtOn?: string;
|
|
46
|
+
/** Filled by the resolver, for labels such as "All {count} customer stories". */
|
|
47
|
+
count?: number;
|
|
48
|
+
/** Names a live counter the host supplies at render (`badges` prop). */
|
|
49
|
+
badgeKey?: string;
|
|
50
|
+
/** Set by the resolver, never by a config: the link leaves this site. */
|
|
51
|
+
external?: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface NavGroup {
|
|
55
|
+
id: string;
|
|
56
|
+
title?: string;
|
|
57
|
+
links: NavLink[];
|
|
77
58
|
}
|
|
78
59
|
|
|
79
60
|
/**
|
|
80
|
-
*
|
|
61
|
+
* A featured customer story shown as a card beside a menu's columns: the
|
|
62
|
+
* record itself, drawn by the shared case study card.
|
|
81
63
|
*/
|
|
82
|
-
export interface
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
64
|
+
export interface NavFeature {
|
|
65
|
+
id: string;
|
|
66
|
+
href: string;
|
|
67
|
+
study: CaseStudyCardData;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface NavMenu {
|
|
71
|
+
id: string;
|
|
72
|
+
label: string;
|
|
73
|
+
/** A menu with only `href` is a plain link. */
|
|
74
|
+
href?: string;
|
|
75
|
+
iconName?: string;
|
|
76
|
+
/** Path prefixes that mark this menu as the current section. */
|
|
77
|
+
match?: string[];
|
|
78
|
+
/** One column is a list; more than one makes a mega menu. */
|
|
79
|
+
columns?: NavGroup[];
|
|
80
|
+
/** Featured cards shown beside the columns. */
|
|
81
|
+
features?: NavFeature[];
|
|
82
|
+
/** The side list of a mega menu. */
|
|
83
|
+
sideLinks?: NavLink[];
|
|
84
|
+
sideTitle?: string;
|
|
85
|
+
/** Show the brand's social links under the menu's links. */
|
|
86
|
+
showSocial?: boolean;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type SiteNavPrimaryCta = 'trial' | 'waitlist' | 'none' | { label: string; href: string };
|
|
90
|
+
|
|
91
|
+
export interface SiteNav {
|
|
92
|
+
menus: NavMenu[];
|
|
93
|
+
/**
|
|
94
|
+
* The mobile sheet's groups, when they differ from `menus` (a column promoted
|
|
95
|
+
* to its own group). Omitted: the sheet uses `menus`.
|
|
96
|
+
*/
|
|
97
|
+
mobileMenus?: NavMenu[];
|
|
98
|
+
footerColumns: NavGroup[];
|
|
99
|
+
signIn?: NavLink;
|
|
100
|
+
primaryCta: SiteNavPrimaryCta;
|
|
101
|
+
closingBand?: { heading: string; subheading: string; secondary?: NavLink };
|
|
102
|
+
legal: { company: string; notes: string[]; links: NavLink[] };
|
|
103
|
+
brand: { name: string; tagline: string; social: NavLink[]; statusUrl?: string };
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
/**
|
package/src/utils/index.ts
CHANGED
|
@@ -116,6 +116,7 @@ export * from './shell-utils';
|
|
|
116
116
|
export * from './video-bite-id';
|
|
117
117
|
// OS type utilities
|
|
118
118
|
export * from './os-utils';
|
|
119
|
+
export * from './visitor-os';
|
|
119
120
|
// Phone utilities
|
|
120
121
|
export * from './country-phone-utils';
|
|
121
122
|
export * from './compliance-standards';
|
|
@@ -40,6 +40,19 @@ export const SOURCE_ICON_NAMES: Record<string, string> = {
|
|
|
40
40
|
podcasts: 'headphones',
|
|
41
41
|
'customer-interviews': 'users',
|
|
42
42
|
faqs: 'info',
|
|
43
|
+
// Not a chat source: listed so the site menus and the admin sidebar draw the
|
|
44
|
+
// media library with one glyph, from this registry like every other kind.
|
|
45
|
+
media: 'image',
|
|
46
|
+
|
|
47
|
+
// Admin sections that are not chat sources, and the case-study audiences:
|
|
48
|
+
// listed so every glyph a menu, a sidebar or a dashboard tile shows is named
|
|
49
|
+
// here and nowhere else.
|
|
50
|
+
campaigns: 'megaphone-01',
|
|
51
|
+
'contact-submissions': 'email',
|
|
52
|
+
'code-documentation': 'book-open',
|
|
53
|
+
'audience-msp': 'hierarchy-02',
|
|
54
|
+
'audience-mssp': 'shield-lock',
|
|
55
|
+
'audience-it-team': 'buildings',
|
|
43
56
|
|
|
44
57
|
// Trust (single-record live source over the public Vanta projection)
|
|
45
58
|
'trust-center': 'shield',
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE detection of the system a visitor is on. One rule, read by everything
|
|
3
|
+
* that depends on it: which installer the desktop app's download offers, and
|
|
4
|
+
* which shortcut key a hint shows. Never test `navigator.platform` or a
|
|
5
|
+
* User-Agent anywhere else.
|
|
6
|
+
*
|
|
7
|
+
* Pure and server-safe: the server passes the request's User-Agent, the browser
|
|
8
|
+
* goes through `useVisitorOs` (hooks), which also passes the touch-point count.
|
|
9
|
+
*/
|
|
10
|
+
export type VisitorOs = 'mac' | 'windows' | 'linux' | 'ios' | 'android';
|
|
11
|
+
|
|
12
|
+
/** The systems the desktop app installs on. */
|
|
13
|
+
export const DESKTOP_OSES = ['mac', 'windows', 'linux'] as const;
|
|
14
|
+
export type DesktopOs = (typeof DESKTOP_OSES)[number];
|
|
15
|
+
|
|
16
|
+
export interface VisitorOsHints {
|
|
17
|
+
/**
|
|
18
|
+
* The platform the browser STATES through User-Agent Client Hints:
|
|
19
|
+
* `navigator.userAgentData.platform` in the browser, the `Sec-CH-UA-Platform`
|
|
20
|
+
* request header on the server (Chromium browsers send it on every request).
|
|
21
|
+
* It is the current standard and is read first: browsers are freezing the
|
|
22
|
+
* User-Agent string, so the hint is the value they keep accurate. Safari and
|
|
23
|
+
* Firefox send none, which is why the User-Agent stays the fallback.
|
|
24
|
+
*/
|
|
25
|
+
platform?: string | null;
|
|
26
|
+
/**
|
|
27
|
+
* `navigator.maxTouchPoints`, when the caller is a browser. An iPad asks for
|
|
28
|
+
* the desktop site by default and then calls itself a Macintosh; a Macintosh
|
|
29
|
+
* with a touch screen does not exist, so touch points tell the two apart. The
|
|
30
|
+
* server has no such signal and reads that iPad as a Mac.
|
|
31
|
+
*/
|
|
32
|
+
maxTouchPoints?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Client Hints platform names (the header quotes them) to ours. Chrome OS runs Linux apps. */
|
|
36
|
+
const HINT_PLATFORMS: Record<string, VisitorOs> = {
|
|
37
|
+
macos: 'mac',
|
|
38
|
+
windows: 'windows',
|
|
39
|
+
linux: 'linux',
|
|
40
|
+
'chrome os': 'linux',
|
|
41
|
+
'chromium os': 'linux',
|
|
42
|
+
android: 'android',
|
|
43
|
+
ios: 'ios',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The visitor's system, or null when nothing names one. Order: the Client Hints
|
|
48
|
+
* platform, then the User-Agent, with touch points separating an iPad from a Mac.
|
|
49
|
+
*/
|
|
50
|
+
export function detectVisitorOs(userAgent: string | null | undefined, hints: VisitorOsHints = {}): VisitorOs | null {
|
|
51
|
+
const touchMac = (os: VisitorOs) => (os === 'mac' && (hints.maxTouchPoints ?? 0) > 1 ? 'ios' : os);
|
|
52
|
+
const hinted = HINT_PLATFORMS[(hints.platform ?? '').replace(/"/g, '').trim().toLowerCase()];
|
|
53
|
+
if (hinted) return touchMac(hinted);
|
|
54
|
+
|
|
55
|
+
const ua = userAgent ?? '';
|
|
56
|
+
if (!ua) return null;
|
|
57
|
+
// Phones and tablets first: Android's User-Agent also says "Linux".
|
|
58
|
+
if (/iPhone|iPad|iPod/i.test(ua)) return 'ios';
|
|
59
|
+
if (/Android/i.test(ua)) return 'android';
|
|
60
|
+
if (/Windows NT|Win64|Win32/i.test(ua)) return 'windows';
|
|
61
|
+
if (/Macintosh|Mac OS X/i.test(ua)) return touchMac('mac');
|
|
62
|
+
if (/Linux|X11|CrOS/i.test(ua)) return 'linux';
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The system as a desktop one, or null for a phone, a tablet or an unknown system. */
|
|
67
|
+
export function desktopOsOf(os: VisitorOs | null): DesktopOs | null {
|
|
68
|
+
return os !== null && (DESKTOP_OSES as readonly string[]).includes(os) ? (os as DesktopOs) : null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** The desktop system a User-Agent comes from: `desktopOsOf(detectVisitorOs(...))`. */
|
|
72
|
+
export function detectDesktopOs(userAgent: string | null | undefined, hints?: VisitorOsHints): DesktopOs | null {
|
|
73
|
+
return desktopOsOf(detectVisitorOs(userAgent, hints));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Apple systems use the Command key for shortcuts; every other system uses Control. */
|
|
77
|
+
export function usesCommandKey(os: VisitorOs | null): boolean {
|
|
78
|
+
return os === 'mac' || os === 'ios';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** A shortcut as its hint reads on the visitor's system: `⌘K` or `Ctrl K`. */
|
|
82
|
+
export function shortcutLabel(os: VisitorOs | null, key: string): string {
|
|
83
|
+
return usesCommandKey(os) ? `⌘${key}` : `Ctrl ${key}`;
|
|
84
|
+
}
|
package/dist/chunk-LMBC5FFP.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
// src/components/icons-v2-generated/signs-and-symbols/xmark-circle-icon.tsx
|
|
4
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
-
function XmarkCircleIcon({
|
|
6
|
-
className = "",
|
|
7
|
-
size = 24,
|
|
8
|
-
color = "currentColor",
|
|
9
|
-
...props
|
|
10
|
-
}) {
|
|
11
|
-
return /* @__PURE__ */ jsxs(
|
|
12
|
-
"svg",
|
|
13
|
-
{
|
|
14
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
15
|
-
width: size,
|
|
16
|
-
height: size,
|
|
17
|
-
fill: "none",
|
|
18
|
-
viewBox: "0 0 24 24",
|
|
19
|
-
className,
|
|
20
|
-
...props,
|
|
21
|
-
children: [
|
|
22
|
-
/* @__PURE__ */ jsx(
|
|
23
|
-
"path",
|
|
24
|
-
{
|
|
25
|
-
fill: color,
|
|
26
|
-
d: "M20.875 12a8.875 8.875 0 1 0-17.75 0 8.875 8.875 0 0 0 17.75 0m2.25 0c0 6.144-4.98 11.124-11.124 11.125S.875 18.145.875 12 5.856.875 12.001.875c6.143 0 11.124 4.981 11.124 11.126Z"
|
|
27
|
-
}
|
|
28
|
-
),
|
|
29
|
-
/* @__PURE__ */ jsx(
|
|
30
|
-
"path",
|
|
31
|
-
{
|
|
32
|
-
fill: color,
|
|
33
|
-
d: "M14.705 7.705a1.125 1.125 0 0 1 1.59 1.59L13.59 12l2.706 2.706.076.085a1.125 1.125 0 0 1-1.582 1.582l-.085-.076L12 13.59l-2.704 2.706a1.125 1.125 0 0 1-1.59-1.59l2.704-2.707-2.704-2.704-.078-.085A1.125 1.125 0 0 1 9.21 7.627l.085.078L12 10.409z"
|
|
34
|
-
}
|
|
35
|
-
)
|
|
36
|
-
]
|
|
37
|
-
}
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export {
|
|
42
|
-
XmarkCircleIcon
|
|
43
|
-
};
|