@flamingo-stack/openframe-frontend-core 0.0.296 → 0.0.297-snapshot.20260621145353
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/README.md +9 -0
- package/dist/{chunk-7RIYT7ZH.js → chunk-2QG57XOJ.js} +1067 -205
- package/dist/chunk-2QG57XOJ.js.map +1 -0
- package/dist/{chunk-5P3B2LZW.js → chunk-3LQWMUHJ.js} +8 -14
- package/dist/{chunk-5P3B2LZW.js.map → chunk-3LQWMUHJ.js.map} +1 -1
- package/dist/{chunk-D3LEFMOA.cjs → chunk-54KNMC2R.cjs} +3 -3
- package/dist/{chunk-D3LEFMOA.cjs.map → chunk-54KNMC2R.cjs.map} +1 -1
- package/dist/{chunk-X647HY3F.cjs → chunk-57HYFVTZ.cjs} +33 -37
- package/dist/chunk-57HYFVTZ.cjs.map +1 -0
- package/dist/{chunk-K2PFPBMF.js → chunk-5MLYCLOI.js} +15050 -5565
- package/dist/chunk-5MLYCLOI.js.map +1 -0
- package/dist/{chunk-YIGPRLQY.cjs → chunk-67WXHSCX.cjs} +21 -20
- package/dist/chunk-67WXHSCX.cjs.map +1 -0
- package/dist/{chunk-QHIXS3W2.cjs → chunk-BL6XZ2XD.cjs} +11591 -2106
- package/dist/chunk-BL6XZ2XD.cjs.map +1 -0
- package/dist/{chunk-6GCI7JOE.js → chunk-DVHQGII5.js} +8 -7
- package/dist/{chunk-6GCI7JOE.js.map → chunk-DVHQGII5.js.map} +1 -1
- package/dist/chunk-FBWXMMRB.cjs +2 -0
- package/dist/chunk-FBWXMMRB.cjs.map +1 -0
- package/dist/{chunk-IE6OU3WQ.cjs → chunk-FQOTC3UU.cjs} +318 -16
- package/dist/chunk-FQOTC3UU.cjs.map +1 -0
- package/dist/chunk-GZ4C3XW6.js +2 -0
- package/dist/chunk-GZ4C3XW6.js.map +1 -0
- package/dist/{chunk-LCNMR277.js → chunk-IZ7JSBFP.js} +1 -1
- package/dist/chunk-IZ7JSBFP.js.map +1 -0
- package/dist/{chunk-EL6QLAWX.js → chunk-JALO4TAZ.js} +357 -55
- package/dist/chunk-JALO4TAZ.js.map +1 -0
- package/dist/{chunk-AQOWFSMB.cjs → chunk-L6PSSIUQ.cjs} +1 -1
- package/dist/chunk-L6PSSIUQ.cjs.map +1 -0
- package/dist/chunk-N4DEX22O.js +144 -0
- package/dist/chunk-N4DEX22O.js.map +1 -0
- package/dist/{chunk-ZP4AVIZP.js → chunk-NEVMYN4G.js} +4 -6
- package/dist/{chunk-ZP4AVIZP.js.map → chunk-NEVMYN4G.js.map} +1 -1
- package/dist/{chunk-3ZXUQQL4.js → chunk-PI4WSYQV.js} +2 -2
- package/dist/chunk-PLNR6BHN.cjs +144 -0
- package/dist/chunk-PLNR6BHN.cjs.map +1 -0
- package/dist/{chunk-X6BV7MB7.cjs → chunk-PQEQUMSS.cjs} +37 -31
- package/dist/chunk-PQEQUMSS.cjs.map +1 -0
- package/dist/{chunk-EYEW6PTA.cjs → chunk-Q77BDAR7.cjs} +358 -118
- package/dist/chunk-Q77BDAR7.cjs.map +1 -0
- package/dist/{chunk-WHMATDVP.js → chunk-QE5CNWPF.js} +9 -15
- package/dist/{chunk-WHMATDVP.js.map → chunk-QE5CNWPF.js.map} +1 -1
- package/dist/{chunk-OY7OF7E7.js → chunk-RY62M66O.js} +30 -24
- package/dist/chunk-RY62M66O.js.map +1 -0
- package/dist/{chunk-E4XABBSU.js → chunk-WDWGFUT2.js} +338 -98
- package/dist/chunk-WDWGFUT2.js.map +1 -0
- package/dist/{chunk-5E2HOSSH.cjs → chunk-WMSTJAZT.cjs} +913 -51
- package/dist/chunk-WMSTJAZT.cjs.map +1 -0
- package/dist/{chunk-GLLDTKZK.cjs → chunk-X26HXH3L.cjs} +7 -9
- package/dist/chunk-X26HXH3L.cjs.map +1 -0
- package/dist/{chunk-W6M2FLLT.cjs → chunk-XG2KGQ76.cjs} +40 -46
- package/dist/chunk-XG2KGQ76.cjs.map +1 -0
- package/dist/{chunk-MBFWU2EM.js → chunk-XKIO5K5N.js} +6 -10
- package/dist/{chunk-MBFWU2EM.js.map → chunk-XKIO5K5N.js.map} +1 -1
- package/dist/{chunk-XREEV72C.cjs → chunk-ZUXADRGJ.cjs} +19 -25
- package/dist/chunk-ZUXADRGJ.cjs.map +1 -0
- package/dist/components/case-studies/index.cjs +126 -0
- package/dist/components/case-studies/index.cjs.map +1 -0
- package/dist/components/case-studies/index.d.ts +2 -0
- package/dist/components/case-studies/index.d.ts.map +1 -0
- package/dist/components/case-studies/index.js +126 -0
- package/dist/components/case-studies/index.js.map +1 -0
- package/dist/components/case-studies/share-experience-section.d.ts +48 -0
- package/dist/components/case-studies/share-experience-section.d.ts.map +1 -0
- package/dist/components/chat/guide-welcome.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +8 -18
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +75 -85
- package/dist/components/contact/index.cjs +8 -15
- package/dist/components/contact/index.cjs.map +1 -1
- package/dist/components/contact/index.js +7 -14
- package/dist/components/docs/doc-viewer.d.ts +39 -2
- package/dist/components/docs/doc-viewer.d.ts.map +1 -1
- package/dist/components/docs/docs-hub-page.d.ts +46 -0
- package/dist/components/docs/docs-hub-page.d.ts.map +1 -0
- package/dist/components/docs/index.cjs +17 -9
- package/dist/components/docs/index.cjs.map +1 -1
- package/dist/components/docs/index.d.ts +4 -0
- package/dist/components/docs/index.d.ts.map +1 -1
- package/dist/components/docs/index.js +16 -8
- package/dist/components/docs/skeletons.d.ts +32 -0
- package/dist/components/docs/skeletons.d.ts.map +1 -0
- package/dist/components/docs/use-docs-resolve-link.d.ts +20 -0
- package/dist/components/docs/use-docs-resolve-link.d.ts.map +1 -0
- package/dist/components/docs/use-document-tree.d.ts.map +1 -1
- package/dist/components/embeds/embed-container.d.ts +37 -0
- package/dist/components/embeds/embed-container.d.ts.map +1 -0
- package/dist/components/embeds/embed-iframe.d.ts.map +1 -1
- package/dist/components/embeds/file-download-card.d.ts +18 -0
- package/dist/components/embeds/file-download-card.d.ts.map +1 -0
- package/dist/components/embeds/index.cjs +38 -15
- package/dist/components/embeds/index.cjs.map +1 -1
- package/dist/components/embeds/index.d.ts +8 -0
- package/dist/components/embeds/index.d.ts.map +1 -1
- package/dist/components/embeds/index.js +40 -17
- package/dist/components/embeds/linkedin-embed-client.d.ts +8 -0
- package/dist/components/embeds/linkedin-embed-client.d.ts.map +1 -0
- package/dist/components/embeds/markdown-image.d.ts +5 -0
- package/dist/components/embeds/markdown-image.d.ts.map +1 -0
- package/dist/components/embeds/reddit-embed-client.d.ts +7 -0
- package/dist/components/embeds/reddit-embed-client.d.ts.map +1 -0
- package/dist/components/embeds/rich-markdown-runtime.d.ts +46 -0
- package/dist/components/embeds/rich-markdown-runtime.d.ts.map +1 -0
- package/dist/components/embeds/twitter-embed-client.d.ts +8 -0
- package/dist/components/embeds/twitter-embed-client.d.ts.map +1 -0
- package/dist/components/faq/index.cjs +9 -16
- package/dist/components/faq/index.cjs.map +1 -1
- package/dist/components/faq/index.js +8 -15
- package/dist/components/features/index.cjs +8 -16
- package/dist/components/features/index.cjs.map +1 -1
- package/dist/components/features/index.js +24 -32
- package/dist/components/index.cjs +257 -452
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +781 -976
- package/dist/components/index.js.map +1 -1
- package/dist/components/layout/page-header.d.ts +78 -0
- package/dist/components/layout/page-header.d.ts.map +1 -0
- package/dist/components/layout/page-layout.d.ts +10 -1
- package/dist/components/layout/page-layout.d.ts.map +1 -1
- package/dist/components/layout/page-with-header.d.ts +67 -0
- package/dist/components/layout/page-with-header.d.ts.map +1 -0
- package/dist/components/layout/title-block.d.ts +17 -1
- package/dist/components/layout/title-block.d.ts.map +1 -1
- package/dist/components/navigation/index.cjs +7 -15
- package/dist/components/navigation/index.cjs.map +1 -1
- package/dist/components/navigation/index.js +9 -17
- package/dist/components/onboarding-guides/index.cjs +35 -36
- package/dist/components/onboarding-guides/index.cjs.map +1 -1
- package/dist/components/onboarding-guides/index.js +13 -14
- package/dist/components/onboarding-guides/index.js.map +1 -1
- package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts +1 -1
- package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
- package/dist/components/related-content/index.cjs +9 -16
- package/dist/components/related-content/index.cjs.map +1 -1
- package/dist/components/related-content/index.js +8 -15
- package/dist/components/shared/dev-section/dev-section-page.d.ts +9 -0
- package/dist/components/shared/dev-section/dev-section-page.d.ts.map +1 -1
- package/dist/components/shared/dev-section/dev-section-view.d.ts.map +1 -1
- package/dist/components/shared/dev-section/index.d.ts +1 -1
- package/dist/components/shared/dev-section/index.d.ts.map +1 -1
- package/dist/components/shared/doc-search/use-doc-search.d.ts.map +1 -1
- package/dist/components/shared/legal-document/legal-document-page.d.ts.map +1 -1
- package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
- package/dist/components/tickets/index.cjs +100 -112
- package/dist/components/tickets/index.cjs.map +1 -1
- package/dist/components/tickets/index.js +20 -32
- package/dist/components/tickets/index.js.map +1 -1
- package/dist/components/ui/file-manager/index.cjs +50 -52
- package/dist/components/ui/file-manager/index.cjs.map +1 -1
- package/dist/components/ui/file-manager/index.js +4 -6
- package/dist/components/ui/file-manager/index.js.map +1 -1
- package/dist/components/ui/index.cjs +13 -19
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +2 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +133 -139
- package/dist/components/ui/release-changelog-section.d.ts +6 -2
- package/dist/components/ui/release-changelog-section.d.ts.map +1 -1
- package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
- package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
- package/dist/components/ui/simple-markdown-renderer.d.ts +2 -8
- package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
- package/dist/contexts/chat-runtime-context.d.ts +14 -0
- package/dist/contexts/chat-runtime-context.d.ts.map +1 -1
- package/dist/contexts/index.cjs +3 -3
- package/dist/contexts/index.js +5 -5
- package/dist/embed-shims/index.cjs +3 -3
- package/dist/embed-shims/index.cjs.map +1 -1
- package/dist/embed-shims/index.js +4 -4
- package/dist/hooks/index.cjs +4 -9
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +6 -11
- package/dist/index.cjs +14 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +362 -368
- package/dist/types/doc-source.d.ts +31 -1
- package/dist/types/doc-source.d.ts.map +1 -1
- package/dist/utils/index.cjs +4 -0
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/page-header-constants.d.ts +15 -0
- package/dist/utils/page-header-constants.d.ts.map +1 -0
- package/dist/utils/social-embed-cache.d.ts +29 -0
- package/dist/utils/social-embed-cache.d.ts.map +1 -0
- package/package.json +7 -1
- package/src/components/case-studies/index.ts +4 -0
- package/src/components/case-studies/share-experience-section.tsx +185 -0
- package/src/components/chat/embeddable-chat.tsx +1 -1
- package/src/components/chat/guide-welcome.tsx +12 -3
- package/src/components/docs/doc-viewer.tsx +116 -20
- package/src/components/docs/docs-hub-page.tsx +149 -0
- package/src/components/docs/index.ts +17 -0
- package/src/components/docs/skeletons.tsx +138 -0
- package/src/components/docs/use-docs-resolve-link.ts +52 -0
- package/src/components/docs/use-document-tree.ts +21 -0
- package/src/components/embeds/embed-container.tsx +80 -0
- package/src/components/embeds/embed-iframe.tsx +7 -9
- package/src/components/embeds/file-download-card.tsx +54 -0
- package/src/components/embeds/index.ts +30 -0
- package/src/components/embeds/linkedin-embed-client.tsx +100 -0
- package/src/components/embeds/markdown-image.tsx +88 -0
- package/src/components/embeds/og-link-preview.tsx +13 -13
- package/src/components/embeds/reddit-embed-client.tsx +550 -0
- package/src/components/embeds/rich-markdown-runtime.tsx +79 -0
- package/src/components/embeds/twitter-embed-client.tsx +308 -0
- package/src/components/layout/page-header.tsx +182 -0
- package/src/components/layout/page-layout.tsx +14 -1
- package/src/components/layout/page-with-header.tsx +110 -0
- package/src/components/layout/title-block.tsx +40 -62
- package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +3 -3
- package/src/components/shared/dev-section/dev-section-page.tsx +9 -1
- package/src/components/shared/dev-section/dev-section-view.tsx +14 -9
- package/src/components/shared/dev-section/index.ts +1 -1
- package/src/components/shared/doc-search/use-doc-search.ts +7 -3
- package/src/components/shared/legal-document/legal-document-page.tsx +2 -2
- package/src/components/shared/product-release/release-detail-page.tsx +6 -4
- package/src/components/ui/index.ts +2 -0
- package/src/components/ui/release-changelog-section.tsx +7 -2
- package/src/components/ui/rich-markdown-renderer.tsx +1203 -0
- package/src/components/ui/simple-markdown-renderer.tsx +11 -12
- package/src/contexts/chat-runtime-context.tsx +14 -0
- package/src/styles/app-globals.css +24 -0
- package/src/types/doc-source.ts +33 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/page-header-constants.ts +15 -0
- package/src/utils/social-embed-cache.ts +391 -0
- package/dist/chunk-26PKDALD.js +0 -2379
- package/dist/chunk-26PKDALD.js.map +0 -1
- package/dist/chunk-3MCHAFHB.js +0 -89
- package/dist/chunk-3MCHAFHB.js.map +0 -1
- package/dist/chunk-5E2HOSSH.cjs.map +0 -1
- package/dist/chunk-66AANIOC.cjs +0 -619
- package/dist/chunk-66AANIOC.cjs.map +0 -1
- package/dist/chunk-6JINAOI7.cjs +0 -311
- package/dist/chunk-6JINAOI7.cjs.map +0 -1
- package/dist/chunk-7RIYT7ZH.js.map +0 -1
- package/dist/chunk-AQOWFSMB.cjs.map +0 -1
- package/dist/chunk-BOCFIKYS.cjs +0 -3009
- package/dist/chunk-BOCFIKYS.cjs.map +0 -1
- package/dist/chunk-D652TJBQ.js +0 -3009
- package/dist/chunk-D652TJBQ.js.map +0 -1
- package/dist/chunk-E4XABBSU.js.map +0 -1
- package/dist/chunk-EL6QLAWX.js.map +0 -1
- package/dist/chunk-EYEW6PTA.cjs.map +0 -1
- package/dist/chunk-FQJK446R.js +0 -1606
- package/dist/chunk-FQJK446R.js.map +0 -1
- package/dist/chunk-GLLDTKZK.cjs.map +0 -1
- package/dist/chunk-IE6OU3WQ.cjs.map +0 -1
- package/dist/chunk-J54Z3OCR.cjs +0 -1606
- package/dist/chunk-J54Z3OCR.cjs.map +0 -1
- package/dist/chunk-K2PFPBMF.js.map +0 -1
- package/dist/chunk-KXCRGTRN.cjs +0 -2379
- package/dist/chunk-KXCRGTRN.cjs.map +0 -1
- package/dist/chunk-LCNMR277.js.map +0 -1
- package/dist/chunk-LFGGF7OT.cjs +0 -449
- package/dist/chunk-LFGGF7OT.cjs.map +0 -1
- package/dist/chunk-M2OCXTNT.js +0 -311
- package/dist/chunk-M2OCXTNT.js.map +0 -1
- package/dist/chunk-ME4EVDFP.js +0 -619
- package/dist/chunk-ME4EVDFP.js.map +0 -1
- package/dist/chunk-OQ6X7ZOC.js +0 -449
- package/dist/chunk-OQ6X7ZOC.js.map +0 -1
- package/dist/chunk-OY7OF7E7.js.map +0 -1
- package/dist/chunk-POKKCWKF.js +0 -354
- package/dist/chunk-POKKCWKF.js.map +0 -1
- package/dist/chunk-QHIXS3W2.cjs.map +0 -1
- package/dist/chunk-TFSYSWPS.cjs +0 -89
- package/dist/chunk-TFSYSWPS.cjs.map +0 -1
- package/dist/chunk-W6M2FLLT.cjs.map +0 -1
- package/dist/chunk-X647HY3F.cjs.map +0 -1
- package/dist/chunk-X6BV7MB7.cjs.map +0 -1
- package/dist/chunk-XREEV72C.cjs.map +0 -1
- package/dist/chunk-YETA25JW.cjs +0 -354
- package/dist/chunk-YETA25JW.cjs.map +0 -1
- package/dist/chunk-YIGPRLQY.cjs.map +0 -1
- /package/dist/{chunk-3ZXUQQL4.js.map → chunk-PI4WSYQV.js.map} +0 -0
|
@@ -1,34 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
ELAPSED_MS_FIELD,
|
|
4
|
-
HONEYPOT_FIELD,
|
|
5
|
-
ToolTypeValues,
|
|
6
|
-
consumeAccessCode,
|
|
7
|
-
normalizeHashFragment,
|
|
8
|
-
scrollElementIntoView,
|
|
9
|
-
transformPlatformConfigsToOptions,
|
|
10
|
-
validateAccessCode,
|
|
11
|
-
validateAndConsumeAccessCode
|
|
12
|
-
} from "./chunk-OQ6X7ZOC.js";
|
|
13
2
|
import {
|
|
14
3
|
useRequiredEndpointsRuntime
|
|
15
4
|
} from "./chunk-MJNXIEV2.js";
|
|
16
|
-
import {
|
|
17
|
-
createNatsClient
|
|
18
|
-
} from "./chunk-PHWQLKVE.js";
|
|
19
|
-
import {
|
|
20
|
-
contentFetch
|
|
21
|
-
} from "./chunk-3MCHAFHB.js";
|
|
22
|
-
import {
|
|
23
|
-
useDebounce
|
|
24
|
-
} from "./chunk-POKKCWKF.js";
|
|
25
5
|
import {
|
|
26
6
|
init_next_navigation,
|
|
27
7
|
useRouter,
|
|
28
8
|
useSearchParams
|
|
29
9
|
} from "./chunk-PLJLE4A4.js";
|
|
30
10
|
import {
|
|
31
|
-
|
|
11
|
+
FlamingoLogo,
|
|
12
|
+
MiamiCyberGangLogoFaceOnly,
|
|
13
|
+
OpenFrameLogo,
|
|
14
|
+
OpenmspLogo
|
|
32
15
|
} from "./chunk-V4IIBNTA.js";
|
|
33
16
|
import {
|
|
34
17
|
cn,
|
|
@@ -43,12 +26,108 @@ import {
|
|
|
43
26
|
TacticalRmmLogoIcon,
|
|
44
27
|
XmarkIcon
|
|
45
28
|
} from "./chunk-J7AV6H63.js";
|
|
29
|
+
import {
|
|
30
|
+
createNatsClient
|
|
31
|
+
} from "./chunk-PHWQLKVE.js";
|
|
32
|
+
|
|
33
|
+
// src/hooks/ui/use-auto-limit-tags.ts
|
|
34
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
35
|
+
function useAutoLimitTags({
|
|
36
|
+
count,
|
|
37
|
+
limitTags = "auto",
|
|
38
|
+
placeholder = "",
|
|
39
|
+
reserveInputWidth = true
|
|
40
|
+
}) {
|
|
41
|
+
const middleRef = useRef(null);
|
|
42
|
+
const measureRef = useRef(null);
|
|
43
|
+
const textMeasureRef = useRef(null);
|
|
44
|
+
const badgeRef = useRef(null);
|
|
45
|
+
const inputRef = useRef(null);
|
|
46
|
+
const [visibleCount, setVisibleCount] = useState(count);
|
|
47
|
+
const recalculate = useCallback(() => {
|
|
48
|
+
if (limitTags !== "auto") {
|
|
49
|
+
setVisibleCount(Math.min(limitTags, count));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const middle = middleRef.current;
|
|
53
|
+
const measure = measureRef.current;
|
|
54
|
+
if (!middle || !measure) {
|
|
55
|
+
setVisibleCount(count);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (count === 0) {
|
|
59
|
+
setVisibleCount(0);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const cs = getComputedStyle(middle);
|
|
63
|
+
const padL = parseFloat(cs.paddingLeft) || 0;
|
|
64
|
+
const padR = parseFloat(cs.paddingRight) || 0;
|
|
65
|
+
const gap = parseFloat(cs.gap) || 0;
|
|
66
|
+
const middleW = middle.clientWidth;
|
|
67
|
+
let inputReservedW = 0;
|
|
68
|
+
let trailingGap = 0;
|
|
69
|
+
if (reserveInputWidth) {
|
|
70
|
+
const textW = textMeasureRef.current?.offsetWidth ?? 60;
|
|
71
|
+
const inputMinW = inputRef.current ? parseFloat(getComputedStyle(inputRef.current).minWidth) || 60 : 60;
|
|
72
|
+
inputReservedW = Math.max(textW + 8, inputMinW);
|
|
73
|
+
trailingGap = gap;
|
|
74
|
+
}
|
|
75
|
+
const available = middleW - padL - padR - inputReservedW - trailingGap;
|
|
76
|
+
const tagEls = Array.from(measure.children);
|
|
77
|
+
const widths = tagEls.map((el) => el.offsetWidth);
|
|
78
|
+
let total = 0;
|
|
79
|
+
for (let i = 0; i < widths.length; i++) {
|
|
80
|
+
total += widths[i] + (i > 0 ? gap : 0);
|
|
81
|
+
}
|
|
82
|
+
if (total <= available) {
|
|
83
|
+
setVisibleCount(count);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const badgeW = badgeRef.current?.offsetWidth ?? 40;
|
|
87
|
+
const spaceWithBadge = available - badgeW - gap;
|
|
88
|
+
let used = 0;
|
|
89
|
+
let fitCount = 0;
|
|
90
|
+
for (let i = 0; i < widths.length; i++) {
|
|
91
|
+
const need = widths[i] + (i > 0 ? gap : 0);
|
|
92
|
+
if (used + need > spaceWithBadge) break;
|
|
93
|
+
used += need;
|
|
94
|
+
fitCount++;
|
|
95
|
+
}
|
|
96
|
+
setVisibleCount(Math.max(0, fitCount));
|
|
97
|
+
}, [count, limitTags, placeholder, reserveInputWidth]);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
recalculate();
|
|
100
|
+
}, [recalculate]);
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
const el = middleRef.current;
|
|
103
|
+
if (!el) return;
|
|
104
|
+
const ro = new ResizeObserver(recalculate);
|
|
105
|
+
ro.observe(el);
|
|
106
|
+
return () => ro.disconnect();
|
|
107
|
+
}, [recalculate]);
|
|
108
|
+
return { visibleCount, middleRef, measureRef, textMeasureRef, badgeRef, inputRef };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/hooks/ui/use-debounce.ts
|
|
112
|
+
import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
113
|
+
function useDebounce(value, delay = 500) {
|
|
114
|
+
const [debouncedValue, setDebouncedValue] = useState2(value);
|
|
115
|
+
useEffect2(() => {
|
|
116
|
+
const timer = setTimeout(() => {
|
|
117
|
+
setDebouncedValue(value);
|
|
118
|
+
}, delay);
|
|
119
|
+
return () => {
|
|
120
|
+
clearTimeout(timer);
|
|
121
|
+
};
|
|
122
|
+
}, [value, delay]);
|
|
123
|
+
return debouncedValue;
|
|
124
|
+
}
|
|
46
125
|
|
|
47
126
|
// src/hooks/ui/use-header-height.ts
|
|
48
|
-
import { useEffect, useState } from "react";
|
|
127
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
49
128
|
function useHeaderHeight(defaultHeight = 64) {
|
|
50
|
-
const [height, setHeight] =
|
|
51
|
-
|
|
129
|
+
const [height, setHeight] = useState3(defaultHeight);
|
|
130
|
+
useEffect3(() => {
|
|
52
131
|
const measure = () => {
|
|
53
132
|
let total = 0;
|
|
54
133
|
const header2 = document.querySelector("header");
|
|
@@ -87,22 +166,22 @@ function useHeaderHeight(defaultHeight = 64) {
|
|
|
87
166
|
}
|
|
88
167
|
|
|
89
168
|
// src/hooks/ui/use-horizontal-scrollbar.ts
|
|
90
|
-
import { useRef, useState as
|
|
169
|
+
import { useRef as useRef2, useState as useState4, useCallback as useCallback2 } from "react";
|
|
91
170
|
function useHorizontalScrollbar() {
|
|
92
|
-
const scrollElRef =
|
|
93
|
-
const trackRef =
|
|
94
|
-
const thumbRef =
|
|
95
|
-
const roRef =
|
|
96
|
-
const moRef =
|
|
97
|
-
const [thumbRatio, setThumbRatio] =
|
|
98
|
-
const [canScrollLeft, setCanScrollLeft] =
|
|
99
|
-
const [canScrollRight, setCanScrollRight] =
|
|
100
|
-
const prevCanScrollLeftRef =
|
|
101
|
-
const prevCanScrollRightRef =
|
|
102
|
-
const isDraggingRef =
|
|
103
|
-
const dragStartRef =
|
|
104
|
-
const rafIdRef =
|
|
105
|
-
const syncThumbToDOM =
|
|
171
|
+
const scrollElRef = useRef2(null);
|
|
172
|
+
const trackRef = useRef2(null);
|
|
173
|
+
const thumbRef = useRef2(null);
|
|
174
|
+
const roRef = useRef2(null);
|
|
175
|
+
const moRef = useRef2(null);
|
|
176
|
+
const [thumbRatio, setThumbRatio] = useState4(0);
|
|
177
|
+
const [canScrollLeft, setCanScrollLeft] = useState4(false);
|
|
178
|
+
const [canScrollRight, setCanScrollRight] = useState4(false);
|
|
179
|
+
const prevCanScrollLeftRef = useRef2(false);
|
|
180
|
+
const prevCanScrollRightRef = useRef2(false);
|
|
181
|
+
const isDraggingRef = useRef2(false);
|
|
182
|
+
const dragStartRef = useRef2({ mouseX: 0, scrollLeft: 0 });
|
|
183
|
+
const rafIdRef = useRef2(0);
|
|
184
|
+
const syncThumbToDOM = useCallback2(() => {
|
|
106
185
|
const el = scrollElRef.current;
|
|
107
186
|
const thumb = thumbRef.current;
|
|
108
187
|
if (!el || !thumb) return;
|
|
@@ -115,7 +194,7 @@ function useHorizontalScrollbar() {
|
|
|
115
194
|
const fraction = Math.min(Math.max(el.scrollLeft, 0), maxScroll) / maxScroll;
|
|
116
195
|
thumb.style.left = `${fraction * (1 - ratio) * 100}%`;
|
|
117
196
|
}, []);
|
|
118
|
-
const syncEdgeFades =
|
|
197
|
+
const syncEdgeFades = useCallback2(() => {
|
|
119
198
|
const el = scrollElRef.current;
|
|
120
199
|
if (!el) return;
|
|
121
200
|
const maxScroll = el.scrollWidth - el.clientWidth;
|
|
@@ -143,7 +222,7 @@ function useHorizontalScrollbar() {
|
|
|
143
222
|
setCanScrollRight(right);
|
|
144
223
|
}
|
|
145
224
|
}, []);
|
|
146
|
-
const measure =
|
|
225
|
+
const measure = useCallback2(() => {
|
|
147
226
|
const el = scrollElRef.current;
|
|
148
227
|
if (!el) return;
|
|
149
228
|
const ratio = el.clientWidth / el.scrollWidth;
|
|
@@ -151,7 +230,7 @@ function useHorizontalScrollbar() {
|
|
|
151
230
|
syncThumbToDOM();
|
|
152
231
|
syncEdgeFades();
|
|
153
232
|
}, [syncThumbToDOM, syncEdgeFades]);
|
|
154
|
-
const scrollRef =
|
|
233
|
+
const scrollRef = useCallback2((node) => {
|
|
155
234
|
if (roRef.current) {
|
|
156
235
|
roRef.current.disconnect();
|
|
157
236
|
roRef.current = null;
|
|
@@ -193,7 +272,7 @@ function useHorizontalScrollbar() {
|
|
|
193
272
|
setCanScrollRight(false);
|
|
194
273
|
}
|
|
195
274
|
}, [measure, syncThumbToDOM, syncEdgeFades]);
|
|
196
|
-
const onScroll =
|
|
275
|
+
const onScroll = useCallback2(() => {
|
|
197
276
|
if (isDraggingRef.current) return;
|
|
198
277
|
if (rafIdRef.current) cancelAnimationFrame(rafIdRef.current);
|
|
199
278
|
rafIdRef.current = requestAnimationFrame(() => {
|
|
@@ -201,7 +280,7 @@ function useHorizontalScrollbar() {
|
|
|
201
280
|
syncEdgeFades();
|
|
202
281
|
});
|
|
203
282
|
}, [syncThumbToDOM, syncEdgeFades]);
|
|
204
|
-
const onTrackClick =
|
|
283
|
+
const onTrackClick = useCallback2((e) => {
|
|
205
284
|
if (e.target.closest("[data-scrollbar-thumb]")) return;
|
|
206
285
|
const track = trackRef.current;
|
|
207
286
|
const el = scrollElRef.current;
|
|
@@ -219,13 +298,13 @@ function useHorizontalScrollbar() {
|
|
|
219
298
|
const targetScrollLeft = targetFraction * (el.scrollWidth - el.clientWidth);
|
|
220
299
|
el.scrollTo({ left: targetScrollLeft, behavior: "smooth" });
|
|
221
300
|
}, []);
|
|
222
|
-
const onTrackWheel =
|
|
301
|
+
const onTrackWheel = useCallback2((e) => {
|
|
223
302
|
const el = scrollElRef.current;
|
|
224
303
|
if (!el) return;
|
|
225
304
|
e.preventDefault();
|
|
226
305
|
el.scrollLeft += e.deltaX || e.deltaY;
|
|
227
306
|
}, []);
|
|
228
|
-
const onThumbPointerDown =
|
|
307
|
+
const onThumbPointerDown = useCallback2((e) => {
|
|
229
308
|
e.preventDefault();
|
|
230
309
|
e.stopPropagation();
|
|
231
310
|
const el = scrollElRef.current;
|
|
@@ -236,7 +315,7 @@ function useHorizontalScrollbar() {
|
|
|
236
315
|
target.setPointerCapture(e.pointerId);
|
|
237
316
|
target.style.cursor = "grabbing";
|
|
238
317
|
}, []);
|
|
239
|
-
const onThumbPointerMove =
|
|
318
|
+
const onThumbPointerMove = useCallback2((e) => {
|
|
240
319
|
if (!isDraggingRef.current) return;
|
|
241
320
|
const el = scrollElRef.current;
|
|
242
321
|
const track = trackRef.current;
|
|
@@ -256,7 +335,7 @@ function useHorizontalScrollbar() {
|
|
|
256
335
|
syncThumbToDOM();
|
|
257
336
|
syncEdgeFades();
|
|
258
337
|
}, [syncThumbToDOM, syncEdgeFades]);
|
|
259
|
-
const onThumbPointerUp =
|
|
338
|
+
const onThumbPointerUp = useCallback2((e) => {
|
|
260
339
|
isDraggingRef.current = false;
|
|
261
340
|
const target = e.currentTarget;
|
|
262
341
|
target.releasePointerCapture(e.pointerId);
|
|
@@ -279,7 +358,7 @@ function useHorizontalScrollbar() {
|
|
|
279
358
|
}
|
|
280
359
|
|
|
281
360
|
// src/hooks/ui/use-image-edge-color.ts
|
|
282
|
-
import { useState as
|
|
361
|
+
import { useState as useState5, useEffect as useEffect4 } from "react";
|
|
283
362
|
function extractEdgeColor(img) {
|
|
284
363
|
const canvas = document.createElement("canvas");
|
|
285
364
|
const ctx = canvas.getContext("2d");
|
|
@@ -335,8 +414,8 @@ function extractEdgeColor(img) {
|
|
|
335
414
|
return `rgb(${r}, ${g}, ${b})`;
|
|
336
415
|
}
|
|
337
416
|
function useImageEdgeColor(imageUrl, fallback = "#000000") {
|
|
338
|
-
const [color, setColor] =
|
|
339
|
-
|
|
417
|
+
const [color, setColor] = useState5(fallback);
|
|
418
|
+
useEffect4(() => {
|
|
340
419
|
if (!imageUrl) {
|
|
341
420
|
setColor(fallback);
|
|
342
421
|
return;
|
|
@@ -365,9 +444,9 @@ function useImageEdgeColor(imageUrl, fallback = "#000000") {
|
|
|
365
444
|
}
|
|
366
445
|
|
|
367
446
|
// src/hooks/ui/use-local-storage.ts
|
|
368
|
-
import { useEffect as
|
|
447
|
+
import { useEffect as useEffect5, useRef as useRef3, useState as useState6 } from "react";
|
|
369
448
|
function useLocalStorage(key, initialValue) {
|
|
370
|
-
const [storedValue, setStoredValue] =
|
|
449
|
+
const [storedValue, setStoredValue] = useState6(() => {
|
|
371
450
|
try {
|
|
372
451
|
if (typeof window !== "undefined") {
|
|
373
452
|
const item = window.localStorage.getItem(key);
|
|
@@ -378,9 +457,9 @@ function useLocalStorage(key, initialValue) {
|
|
|
378
457
|
}
|
|
379
458
|
return initialValue;
|
|
380
459
|
});
|
|
381
|
-
const isInitialized =
|
|
382
|
-
const isFromStorageEvent =
|
|
383
|
-
|
|
460
|
+
const isInitialized = useRef3(true);
|
|
461
|
+
const isFromStorageEvent = useRef3(false);
|
|
462
|
+
useEffect5(() => {
|
|
384
463
|
if (!isInitialized.current) return;
|
|
385
464
|
const handleStorageChange = (e) => {
|
|
386
465
|
if (e.key === key && e.newValue !== null) {
|
|
@@ -419,7 +498,7 @@ function useLocalStorage(key, initialValue) {
|
|
|
419
498
|
window.removeEventListener("localStorageUpdate", handleCustomStorageUpdate);
|
|
420
499
|
};
|
|
421
500
|
}, [key]);
|
|
422
|
-
|
|
501
|
+
useEffect5(() => {
|
|
423
502
|
if (!isInitialized.current) return;
|
|
424
503
|
if (isFromStorageEvent.current) {
|
|
425
504
|
isFromStorageEvent.current = false;
|
|
@@ -445,9 +524,9 @@ function useLocalStorage(key, initialValue) {
|
|
|
445
524
|
}
|
|
446
525
|
|
|
447
526
|
// src/hooks/ui/use-media-query.ts
|
|
448
|
-
import { useLayoutEffect, useState as
|
|
527
|
+
import { useLayoutEffect, useState as useState7 } from "react";
|
|
449
528
|
function useMediaQuery(query) {
|
|
450
|
-
const [matches, setMatches] =
|
|
529
|
+
const [matches, setMatches] = useState7(void 0);
|
|
451
530
|
useLayoutEffect(() => {
|
|
452
531
|
const matchMedia = window.matchMedia(query);
|
|
453
532
|
const handleChange = () => {
|
|
@@ -480,24 +559,24 @@ function useLgUp() {
|
|
|
480
559
|
}
|
|
481
560
|
|
|
482
561
|
// src/hooks/ui/use-memoized-callback.ts
|
|
483
|
-
import { useCallback as
|
|
562
|
+
import { useCallback as useCallback3, useRef as useRef4 } from "react";
|
|
484
563
|
function useMemoizedCallback(callback, dependencies) {
|
|
485
|
-
const callbackRef =
|
|
486
|
-
const dependenciesRef =
|
|
564
|
+
const callbackRef = useRef4(callback);
|
|
565
|
+
const dependenciesRef = useRef4(dependencies);
|
|
487
566
|
callbackRef.current = callback;
|
|
488
567
|
const depsChanged = dependencies.some((dep, i) => !Object.is(dep, dependenciesRef.current[i]));
|
|
489
568
|
if (depsChanged) {
|
|
490
569
|
dependenciesRef.current = dependencies;
|
|
491
570
|
}
|
|
492
|
-
return
|
|
571
|
+
return useCallback3(((...args) => callbackRef.current(...args)), [depsChanged]);
|
|
493
572
|
}
|
|
494
573
|
|
|
495
574
|
// src/hooks/ui/use-notification-permission.ts
|
|
496
|
-
import { useCallback as
|
|
575
|
+
import { useCallback as useCallback4, useEffect as useEffect6, useState as useState8 } from "react";
|
|
497
576
|
function useNotificationPermission() {
|
|
498
|
-
const [supported, setSupported] =
|
|
499
|
-
const [permission, setPermission] =
|
|
500
|
-
|
|
577
|
+
const [supported, setSupported] = useState8(false);
|
|
578
|
+
const [permission, setPermission] = useState8("default");
|
|
579
|
+
useEffect6(() => {
|
|
501
580
|
if (typeof window === "undefined" || !("Notification" in window)) return;
|
|
502
581
|
setSupported(true);
|
|
503
582
|
const sync = () => setPermission(Notification.permission);
|
|
@@ -518,7 +597,7 @@ function useNotificationPermission() {
|
|
|
518
597
|
window.removeEventListener("focus", sync);
|
|
519
598
|
};
|
|
520
599
|
}, []);
|
|
521
|
-
const request =
|
|
600
|
+
const request = useCallback4(async () => {
|
|
522
601
|
if (typeof window === "undefined" || !("Notification" in window)) {
|
|
523
602
|
return "denied";
|
|
524
603
|
}
|
|
@@ -533,7 +612,7 @@ function useNotificationPermission() {
|
|
|
533
612
|
}
|
|
534
613
|
|
|
535
614
|
// src/hooks/ui/use-onboarding-state.ts
|
|
536
|
-
import { useState as
|
|
615
|
+
import { useState as useState9, useEffect as useEffect7, useCallback as useCallback5 } from "react";
|
|
537
616
|
|
|
538
617
|
// src/utils/onboarding-storage.ts
|
|
539
618
|
var DEFAULT_STATE = {
|
|
@@ -608,9 +687,9 @@ function dismissOnboarding(key) {
|
|
|
608
687
|
|
|
609
688
|
// src/hooks/ui/use-onboarding-state.ts
|
|
610
689
|
function useOnboardingState(storageKey = "openframe-onboarding-state") {
|
|
611
|
-
const [state, setState] =
|
|
612
|
-
const [, forceUpdate] =
|
|
613
|
-
|
|
690
|
+
const [state, setState] = useState9(() => loadOnboardingState(storageKey));
|
|
691
|
+
const [, forceUpdate] = useState9(0);
|
|
692
|
+
useEffect7(() => {
|
|
614
693
|
const handleStorageUpdate = (e) => {
|
|
615
694
|
if (e.detail.key === storageKey) {
|
|
616
695
|
const newState = loadOnboardingState(storageKey);
|
|
@@ -624,38 +703,38 @@ function useOnboardingState(storageKey = "openframe-onboarding-state") {
|
|
|
624
703
|
window.removeEventListener("localStorageUpdate", handleStorageUpdate);
|
|
625
704
|
};
|
|
626
705
|
}, [storageKey]);
|
|
627
|
-
const markComplete =
|
|
706
|
+
const markComplete = useCallback5((stepId) => {
|
|
628
707
|
console.log(`\u{1F3AF} markComplete called for: "${stepId}"`);
|
|
629
708
|
const newState = markStepComplete(storageKey, stepId);
|
|
630
709
|
setState(newState);
|
|
631
710
|
forceUpdate((prev) => prev + 1);
|
|
632
711
|
}, [storageKey]);
|
|
633
|
-
const markSkipped =
|
|
712
|
+
const markSkipped = useCallback5((stepId) => {
|
|
634
713
|
console.log(`\u23ED\uFE0F markSkipped called for: "${stepId}"`);
|
|
635
714
|
const newState = markStepSkipped(storageKey, stepId);
|
|
636
715
|
setState(newState);
|
|
637
716
|
forceUpdate((prev) => prev + 1);
|
|
638
717
|
}, [storageKey]);
|
|
639
|
-
const dismissOnboarding2 =
|
|
718
|
+
const dismissOnboarding2 = useCallback5(() => {
|
|
640
719
|
console.log(`\u{1F6AB} dismissOnboarding called`);
|
|
641
720
|
const newState = dismissOnboarding(storageKey);
|
|
642
721
|
setState(newState);
|
|
643
722
|
forceUpdate((prev) => prev + 1);
|
|
644
723
|
}, [storageKey]);
|
|
645
|
-
const markMultipleComplete2 =
|
|
724
|
+
const markMultipleComplete2 = useCallback5((stepIds) => {
|
|
646
725
|
console.log(`\u{1F3AF} markMultipleComplete called for:`, stepIds);
|
|
647
726
|
const newState = markMultipleComplete(storageKey, stepIds);
|
|
648
727
|
setState(newState);
|
|
649
728
|
forceUpdate((prev) => prev + 1);
|
|
650
729
|
console.log(`\u{1F4DD} State after batch:`, newState);
|
|
651
730
|
}, [storageKey]);
|
|
652
|
-
const isStepComplete =
|
|
731
|
+
const isStepComplete = useCallback5((stepId) => {
|
|
653
732
|
return state.completedSteps.includes(stepId);
|
|
654
733
|
}, [state.completedSteps]);
|
|
655
|
-
const isStepSkipped =
|
|
734
|
+
const isStepSkipped = useCallback5((stepId) => {
|
|
656
735
|
return state.skippedSteps.includes(stepId);
|
|
657
736
|
}, [state.skippedSteps]);
|
|
658
|
-
const allStepsComplete =
|
|
737
|
+
const allStepsComplete = useCallback5((steps) => {
|
|
659
738
|
return steps.every((step) => isStepComplete(step.id) || isStepSkipped(step.id));
|
|
660
739
|
}, [isStepComplete, isStepSkipped]);
|
|
661
740
|
return {
|
|
@@ -671,19 +750,19 @@ function useOnboardingState(storageKey = "openframe-onboarding-state") {
|
|
|
671
750
|
}
|
|
672
751
|
|
|
673
752
|
// src/hooks/ui/use-search.ts
|
|
674
|
-
import { useState as
|
|
753
|
+
import { useState as useState10, useEffect as useEffect8, useCallback as useCallback6 } from "react";
|
|
675
754
|
function useSearch(config) {
|
|
676
755
|
const { searchFn, mapResult, debounceMs = 300, minQueryLength = 2 } = config;
|
|
677
|
-
const [query, setQuery] =
|
|
678
|
-
const [results, setResults] =
|
|
679
|
-
const [isLoading, setIsLoading] =
|
|
680
|
-
const [error, setError] =
|
|
756
|
+
const [query, setQuery] = useState10("");
|
|
757
|
+
const [results, setResults] = useState10([]);
|
|
758
|
+
const [isLoading, setIsLoading] = useState10(false);
|
|
759
|
+
const [error, setError] = useState10(null);
|
|
681
760
|
const debouncedQuery = useDebounce(query, debounceMs);
|
|
682
|
-
const clearResults =
|
|
761
|
+
const clearResults = useCallback6(() => {
|
|
683
762
|
setResults([]);
|
|
684
763
|
setError(null);
|
|
685
764
|
}, []);
|
|
686
|
-
|
|
765
|
+
useEffect8(() => {
|
|
687
766
|
if (!debouncedQuery || debouncedQuery.length < minQueryLength) {
|
|
688
767
|
setResults([]);
|
|
689
768
|
setIsLoading(false);
|
|
@@ -756,11 +835,11 @@ function useTablePagination(config) {
|
|
|
756
835
|
}
|
|
757
836
|
|
|
758
837
|
// src/hooks/ui/use-throttle.ts
|
|
759
|
-
import { useState as
|
|
838
|
+
import { useState as useState11, useEffect as useEffect9, useRef as useRef5 } from "react";
|
|
760
839
|
function useThrottle(value, limit = 200) {
|
|
761
|
-
const [throttledValue, setThrottledValue] =
|
|
762
|
-
const lastUpdated =
|
|
763
|
-
|
|
840
|
+
const [throttledValue, setThrottledValue] = useState11(value);
|
|
841
|
+
const lastUpdated = useRef5(Date.now());
|
|
842
|
+
useEffect9(() => {
|
|
764
843
|
const now = Date.now();
|
|
765
844
|
const elapsed = now - lastUpdated.current;
|
|
766
845
|
if (elapsed >= limit) {
|
|
@@ -780,13 +859,13 @@ function useThrottle(value, limit = 200) {
|
|
|
780
859
|
}
|
|
781
860
|
|
|
782
861
|
// src/hooks/ui/use-window-size.ts
|
|
783
|
-
import { useLayoutEffect as useLayoutEffect2, useState as
|
|
862
|
+
import { useLayoutEffect as useLayoutEffect2, useState as useState12 } from "react";
|
|
784
863
|
function useWindowSize() {
|
|
785
|
-
const [windowSize, setWindowSize] =
|
|
864
|
+
const [windowSize, setWindowSize] = useState12({
|
|
786
865
|
width: 0,
|
|
787
866
|
height: 0
|
|
788
867
|
});
|
|
789
|
-
const [isClient, setIsClient] =
|
|
868
|
+
const [isClient, setIsClient] = useState12(false);
|
|
790
869
|
useLayoutEffect2(() => {
|
|
791
870
|
setIsClient(true);
|
|
792
871
|
if (!isClient) return;
|
|
@@ -804,14 +883,188 @@ function useWindowSize() {
|
|
|
804
883
|
}
|
|
805
884
|
|
|
806
885
|
// src/hooks/platform/use-platform-config.ts
|
|
807
|
-
import { useState as
|
|
886
|
+
import { useState as useState13, useEffect as useEffect10 } from "react";
|
|
887
|
+
|
|
888
|
+
// src/utils/platform-config.tsx
|
|
889
|
+
import { Globe } from "lucide-react";
|
|
890
|
+
import { jsx } from "react/jsx-runtime";
|
|
891
|
+
var platformIcons = {
|
|
892
|
+
openframe: /* @__PURE__ */ jsx(OpenFrameLogo, { className: "h-5 w-5", lowerPathColor: "#FFC008", upperPathColor: "#ffffff" }),
|
|
893
|
+
openmsp: /* @__PURE__ */ jsx(OpenmspLogo, { className: "h-5 w-5" }),
|
|
894
|
+
flamingo: /* @__PURE__ */ jsx(FlamingoLogo, { className: "h-5 w-5", fill: "#EC4899" }),
|
|
895
|
+
"flamingo-teaser": /* @__PURE__ */ jsx(FlamingoLogo, { className: "h-5 w-5", fill: "#EC4899" }),
|
|
896
|
+
"marketing-hub": /* @__PURE__ */ jsx(FlamingoLogo, { className: "h-5 w-5", fill: "#F357BB" }),
|
|
897
|
+
"product-hub": /* @__PURE__ */ jsx(FlamingoLogo, { className: "h-5 w-5", fill: "#5EA62E" }),
|
|
898
|
+
"revenue-hub": /* @__PURE__ */ jsx(FlamingoLogo, { className: "h-5 w-5", fill: "#FFC008" }),
|
|
899
|
+
"people-hub": /* @__PURE__ */ jsx(FlamingoLogo, { className: "h-5 w-5", fill: "#5EFAF0" }),
|
|
900
|
+
"company-hub": /* @__PURE__ */ jsx(FlamingoLogo, { className: "h-5 w-5", fill: "#f36666" }),
|
|
901
|
+
tmcg: /* @__PURE__ */ jsx(MiamiCyberGangLogoFaceOnly, { className: "h-5 w-5" }),
|
|
902
|
+
universal: /* @__PURE__ */ jsx(Globe, { className: "h-5 w-5 text-[#10B981]" })
|
|
903
|
+
};
|
|
904
|
+
var platformColors = {
|
|
905
|
+
openmsp: "bg-[#3B82F6]",
|
|
906
|
+
openframe: "bg-[#8B5CF6]",
|
|
907
|
+
flamingo: "bg-[#EC4899]",
|
|
908
|
+
"flamingo-teaser": "bg-[#F59E0B]",
|
|
909
|
+
"marketing-hub": "bg-[#F357BB]",
|
|
910
|
+
"product-hub": "bg-[#5EA62E]",
|
|
911
|
+
"revenue-hub": "bg-[#FFC008]",
|
|
912
|
+
"people-hub": "bg-[#5EFAF0]",
|
|
913
|
+
"company-hub": "bg-[#f36666]",
|
|
914
|
+
tmcg: "bg-[#FF6B6B]",
|
|
915
|
+
universal: "bg-[#10B981]"
|
|
916
|
+
};
|
|
917
|
+
var platformDisplayNames = {
|
|
918
|
+
openmsp: "OpenMSP",
|
|
919
|
+
openframe: "OpenFrame",
|
|
920
|
+
flamingo: "Flamingo",
|
|
921
|
+
"flamingo-teaser": "Flamingo Teaser",
|
|
922
|
+
"marketing-hub": "Flamingo Marketing Hub",
|
|
923
|
+
"product-hub": "Flamingo Product Hub",
|
|
924
|
+
"revenue-hub": "Flamingo Revenue Hub",
|
|
925
|
+
"people-hub": "Flamingo People Hub",
|
|
926
|
+
"company-hub": "Flamingo Company Hub",
|
|
927
|
+
tmcg: "TMCG",
|
|
928
|
+
universal: "Universal"
|
|
929
|
+
};
|
|
930
|
+
var platformDescriptions = {
|
|
931
|
+
openmsp: "Comprehensive directory and comparison platform for managed service providers (MSPs) and technology vendors. Reduce vendor costs and discover open-source alternatives.",
|
|
932
|
+
openframe: "AI-driven open-source security operations center (SOC) and endpoint detection platform for MSPs.",
|
|
933
|
+
flamingo: "AI-driven open-source OS for MSPs. Swap bloated vendor tools for open ones. Automate the boring crap. Take your margin back.",
|
|
934
|
+
"flamingo-teaser": "Preview of Flamingo - the AI-driven open-source OS for MSPs.",
|
|
935
|
+
tmcg: "The Miami Cyber Gang - A cybersecurity community focused on education and collaboration.",
|
|
936
|
+
universal: "Cross-platform universal content."
|
|
937
|
+
};
|
|
938
|
+
var platformSlogans = {
|
|
939
|
+
openmsp: "Find Your Perfect MSP Partner",
|
|
940
|
+
openframe: "Open-Source Security Operations",
|
|
941
|
+
flamingo: "Open-Source OS for MSPs",
|
|
942
|
+
"flamingo-teaser": "Coming Soon: Open-Source OS for MSPs",
|
|
943
|
+
tmcg: "Miami Cyber Community",
|
|
944
|
+
universal: "Universal Platform"
|
|
945
|
+
};
|
|
946
|
+
var platformHexColors = {
|
|
947
|
+
openmsp: "#FFC008",
|
|
948
|
+
openframe: "#FFC008",
|
|
949
|
+
flamingo: "#FF6B9D",
|
|
950
|
+
universal: "#FFC008",
|
|
951
|
+
"flamingo-teaser": "#F59E0B",
|
|
952
|
+
"marketing-hub": "#F357BB",
|
|
953
|
+
"product-hub": "#5EA62E",
|
|
954
|
+
"revenue-hub": "#FFC008",
|
|
955
|
+
"people-hub": "#5EFAF0",
|
|
956
|
+
"company-hub": "#f36666",
|
|
957
|
+
tmcg: "#FF6B6B"
|
|
958
|
+
};
|
|
959
|
+
var platformIconNames = {
|
|
960
|
+
openmsp: "openmsp-logo",
|
|
961
|
+
openframe: "openframe-logo",
|
|
962
|
+
flamingo: "flamingo-logo",
|
|
963
|
+
universal: "globe",
|
|
964
|
+
"flamingo-teaser": "flamingo-logo",
|
|
965
|
+
"marketing-hub": "flamingo-logo",
|
|
966
|
+
"product-hub": "flamingo-logo",
|
|
967
|
+
"revenue-hub": "flamingo-logo",
|
|
968
|
+
"people-hub": "flamingo-logo",
|
|
969
|
+
"company-hub": "flamingo-logo",
|
|
970
|
+
tmcg: "tmcg-logo"
|
|
971
|
+
};
|
|
972
|
+
function getDefaultColorForPlatform(platformName) {
|
|
973
|
+
return platformHexColors[platformName] || platformHexColors.universal;
|
|
974
|
+
}
|
|
975
|
+
function getDefaultIconForPlatform(platformName) {
|
|
976
|
+
return platformIconNames[platformName] || platformIconNames.universal;
|
|
977
|
+
}
|
|
978
|
+
function transformPlatformConfigsToOptions(platformConfigs) {
|
|
979
|
+
return platformConfigs.map((platform) => ({
|
|
980
|
+
id: platform.id,
|
|
981
|
+
// Database UUID for matching
|
|
982
|
+
name: platform.name,
|
|
983
|
+
// Platform name enum
|
|
984
|
+
displayName: platform.display_name,
|
|
985
|
+
// Human-readable name
|
|
986
|
+
description: platform.description,
|
|
987
|
+
icon: platformIcons[platform.name] || platformIcons.universal,
|
|
988
|
+
color: platformColors[platform.name] || platformColors.universal
|
|
989
|
+
}));
|
|
990
|
+
}
|
|
991
|
+
function getPlatformIcon(platformName) {
|
|
992
|
+
return platformIcons[platformName] || platformIcons.universal;
|
|
993
|
+
}
|
|
994
|
+
function getPlatformColor(platformName) {
|
|
995
|
+
return platformColors[platformName] || platformColors.universal;
|
|
996
|
+
}
|
|
997
|
+
function getPlatformDisplayName(platformName) {
|
|
998
|
+
return platformDisplayNames[platformName] || platformName;
|
|
999
|
+
}
|
|
1000
|
+
function getPlatformDescription(platformName) {
|
|
1001
|
+
return platformDescriptions[platformName] || platformName;
|
|
1002
|
+
}
|
|
1003
|
+
function getPlatformSlogan(platformName) {
|
|
1004
|
+
return platformSlogans[platformName] || platformName;
|
|
1005
|
+
}
|
|
1006
|
+
function getSmallPlatformIcon(platformName) {
|
|
1007
|
+
const className = "h-4 w-4 flex-shrink-0";
|
|
1008
|
+
switch (platformName) {
|
|
1009
|
+
case "openframe":
|
|
1010
|
+
return /* @__PURE__ */ jsx(OpenFrameLogo, { className, lowerPathColor: "#FFC008", upperPathColor: "#ffffff" });
|
|
1011
|
+
case "openmsp":
|
|
1012
|
+
return /* @__PURE__ */ jsx(OpenmspLogo, { className, frontBubbleColor: "#f1f1f1", innerFrontBubbleColor: "#000000", backBubbleColor: "#FFC008" });
|
|
1013
|
+
case "flamingo":
|
|
1014
|
+
case "flamingo-teaser":
|
|
1015
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className: `${className}`, fill: "#EC4899" });
|
|
1016
|
+
case "marketing-hub":
|
|
1017
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className, fill: "var(--ods-flamingo-pink-base)" });
|
|
1018
|
+
case "product-hub":
|
|
1019
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className, fill: "var(--ods-attention-green-success)" });
|
|
1020
|
+
case "revenue-hub":
|
|
1021
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className, fill: "var(--ods-attention-yellow-warning)" });
|
|
1022
|
+
case "people-hub":
|
|
1023
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className, fill: "var(--ods-flamingo-cyan-base)" });
|
|
1024
|
+
case "company-hub":
|
|
1025
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className, fill: "var(--ods-attention-red-error)" });
|
|
1026
|
+
case "tmcg":
|
|
1027
|
+
return /* @__PURE__ */ jsx(MiamiCyberGangLogoFaceOnly, { className });
|
|
1028
|
+
case "universal":
|
|
1029
|
+
default:
|
|
1030
|
+
return /* @__PURE__ */ jsx(Globe, { className });
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
function getPlatformIconComponent(platformName, className = "h-6 w-6") {
|
|
1034
|
+
switch (platformName) {
|
|
1035
|
+
case "openframe":
|
|
1036
|
+
return /* @__PURE__ */ jsx(OpenFrameLogo, { className });
|
|
1037
|
+
case "openmsp":
|
|
1038
|
+
return /* @__PURE__ */ jsx(OpenmspLogo, { className, color: "#f1f1f1" });
|
|
1039
|
+
case "flamingo":
|
|
1040
|
+
case "flamingo-teaser":
|
|
1041
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className: `${className} text-white` });
|
|
1042
|
+
case "marketing-hub":
|
|
1043
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className, fill: "var(--ods-flamingo-pink-base)" });
|
|
1044
|
+
case "product-hub":
|
|
1045
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className, fill: "var(--ods-attention-green-success)" });
|
|
1046
|
+
case "revenue-hub":
|
|
1047
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className, fill: "var(--ods-attention-yellow-warning)" });
|
|
1048
|
+
case "people-hub":
|
|
1049
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className, fill: "var(--ods-flamingo-cyan-base)" });
|
|
1050
|
+
case "company-hub":
|
|
1051
|
+
return /* @__PURE__ */ jsx(FlamingoLogo, { className, fill: "var(--ods-attention-red-error)" });
|
|
1052
|
+
case "tmcg":
|
|
1053
|
+
return /* @__PURE__ */ jsx(MiamiCyberGangLogoFaceOnly, { size: 24, className });
|
|
1054
|
+
case "universal":
|
|
1055
|
+
default:
|
|
1056
|
+
return /* @__PURE__ */ jsx(Globe, { className });
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// src/hooks/platform/use-platform-config.ts
|
|
808
1061
|
var platformCache = null;
|
|
809
1062
|
var fetchPromise = null;
|
|
810
1063
|
function usePlatformConfig() {
|
|
811
|
-
const [platforms, setPlatforms] =
|
|
812
|
-
const [isLoading, setIsLoading] =
|
|
813
|
-
const [error, setError] =
|
|
814
|
-
|
|
1064
|
+
const [platforms, setPlatforms] = useState13(platformCache || []);
|
|
1065
|
+
const [isLoading, setIsLoading] = useState13(!platformCache);
|
|
1066
|
+
const [error, setError] = useState13(null);
|
|
1067
|
+
useEffect10(() => {
|
|
815
1068
|
if (platformCache) {
|
|
816
1069
|
setPlatforms(platformCache);
|
|
817
1070
|
setIsLoading(false);
|
|
@@ -882,11 +1135,35 @@ import { toast as sonnerToast2 } from "sonner";
|
|
|
882
1135
|
import * as React from "react";
|
|
883
1136
|
import { Toaster as SonnerToaster, toast as sonnerToast } from "sonner";
|
|
884
1137
|
|
|
1138
|
+
// src/types/tool.types.ts
|
|
1139
|
+
var ToolTypeValues = {
|
|
1140
|
+
TACTICAL_RMM: "TACTICAL_RMM",
|
|
1141
|
+
FLEET_MDM: "FLEET_MDM",
|
|
1142
|
+
MESHCENTRAL: "MESHCENTRAL",
|
|
1143
|
+
AUTHENTIK: "AUTHENTIK",
|
|
1144
|
+
OPENFRAME: "OPENFRAME",
|
|
1145
|
+
OPENFRAME_CHAT: "OPENFRAME_CHAT",
|
|
1146
|
+
OPENFRAME_CLIENT: "OPENFRAME_CLIENT",
|
|
1147
|
+
OSQUERY: "OSQUERY",
|
|
1148
|
+
SYSTEM: "SYSTEM"
|
|
1149
|
+
};
|
|
1150
|
+
var toolLabels = {
|
|
1151
|
+
TACTICAL_RMM: "Tactical",
|
|
1152
|
+
FLEET_MDM: "Fleet",
|
|
1153
|
+
MESHCENTRAL: "MeshCentral",
|
|
1154
|
+
AUTHENTIK: "Authentik",
|
|
1155
|
+
OPENFRAME: "OpenFrame",
|
|
1156
|
+
OPENFRAME_CHAT: "OpenFrame Chat",
|
|
1157
|
+
OPENFRAME_CLIENT: "OpenFrame Client",
|
|
1158
|
+
OSQUERY: "Osquery",
|
|
1159
|
+
SYSTEM: "System"
|
|
1160
|
+
};
|
|
1161
|
+
|
|
885
1162
|
// src/components/tool-icon.tsx
|
|
886
|
-
import { Fragment, jsx } from "react/jsx-runtime";
|
|
1163
|
+
import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
|
|
887
1164
|
var renderOpenFrameLogo = (_size, className) => (
|
|
888
1165
|
// eslint-disable-next-line deprecation/deprecation
|
|
889
|
-
/* @__PURE__ */
|
|
1166
|
+
/* @__PURE__ */ jsx2(
|
|
890
1167
|
OpenFrameLogo,
|
|
891
1168
|
{
|
|
892
1169
|
className: className ?? "h-4 w-auto",
|
|
@@ -896,22 +1173,22 @@ var renderOpenFrameLogo = (_size, className) => (
|
|
|
896
1173
|
)
|
|
897
1174
|
);
|
|
898
1175
|
var toolIconMap = {
|
|
899
|
-
[ToolTypeValues.FLEET_MDM]: (size, className) => /* @__PURE__ */
|
|
900
|
-
[ToolTypeValues.MESHCENTRAL]: (size, className) => /* @__PURE__ */
|
|
901
|
-
[ToolTypeValues.TACTICAL_RMM]: (size, className) => /* @__PURE__ */
|
|
1176
|
+
[ToolTypeValues.FLEET_MDM]: (size, className) => /* @__PURE__ */ jsx2(FleetMdmLogoGreyIcon, { size, className }),
|
|
1177
|
+
[ToolTypeValues.MESHCENTRAL]: (size, className) => /* @__PURE__ */ jsx2(MeshcentralLogoGreyIcon, { size, className }),
|
|
1178
|
+
[ToolTypeValues.TACTICAL_RMM]: (size, className) => /* @__PURE__ */ jsx2(TacticalRmmLogoIcon, { size, className }),
|
|
902
1179
|
[ToolTypeValues.OPENFRAME]: renderOpenFrameLogo,
|
|
903
1180
|
[ToolTypeValues.OPENFRAME_CHAT]: renderOpenFrameLogo,
|
|
904
1181
|
[ToolTypeValues.OPENFRAME_CLIENT]: renderOpenFrameLogo,
|
|
905
|
-
[ToolTypeValues.AUTHENTIK]: (size, className) => /* @__PURE__ */
|
|
906
|
-
[ToolTypeValues.OSQUERY]: (size, className) => /* @__PURE__ */
|
|
1182
|
+
[ToolTypeValues.AUTHENTIK]: (size, className) => /* @__PURE__ */ jsx2(AuthentikLogoGreyIcon, { size, className }),
|
|
1183
|
+
[ToolTypeValues.OSQUERY]: (size, className) => /* @__PURE__ */ jsx2(OsqueryLogoGreyIcon, { size, className }),
|
|
907
1184
|
[ToolTypeValues.SYSTEM]: () => null
|
|
908
1185
|
};
|
|
909
|
-
var ToolIcon = ({ toolType, size = 16, className }) => /* @__PURE__ */
|
|
1186
|
+
var ToolIcon = ({ toolType, size = 16, className }) => /* @__PURE__ */ jsx2(Fragment, { children: toolIconMap[toolType]?.(size, className) ?? null });
|
|
910
1187
|
ToolIcon.displayName = "ToolIcon";
|
|
911
1188
|
|
|
912
1189
|
// src/components/ui/toaster.tsx
|
|
913
1190
|
init_cn();
|
|
914
|
-
import { Fragment as Fragment2, jsx as
|
|
1191
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
915
1192
|
var dotColorByVariant = {
|
|
916
1193
|
default: "bg-ods-text-secondary",
|
|
917
1194
|
success: "bg-ods-success",
|
|
@@ -944,22 +1221,22 @@ function ToastHeader({
|
|
|
944
1221
|
className
|
|
945
1222
|
),
|
|
946
1223
|
children: [
|
|
947
|
-
/* @__PURE__ */
|
|
1224
|
+
/* @__PURE__ */ jsx3("div", { className: "flex size-6 shrink-0 items-center justify-center", children: /* @__PURE__ */ jsx3("span", { className: cn("size-[9px] rounded-full", dotColorByVariant[variant]) }) }),
|
|
948
1225
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col justify-center font-['DM_Sans'] font-medium", children: [
|
|
949
|
-
title ? /* @__PURE__ */
|
|
950
|
-
description ? /* @__PURE__ */
|
|
1226
|
+
title ? /* @__PURE__ */ jsx3("p", { className: "truncate pr-5 text-[18px] leading-6 text-ods-text-primary", title: typeof title === "string" ? title : void 0, children: title }) : null,
|
|
1227
|
+
description ? /* @__PURE__ */ jsx3("p", { className: "text-[14px] leading-5 text-ods-text-secondary line-clamp-3", title: typeof description === "string" ? description : void 0, children: description }) : null
|
|
951
1228
|
] }),
|
|
952
|
-
dismissible ? /* @__PURE__ */
|
|
1229
|
+
dismissible ? /* @__PURE__ */ jsx3(
|
|
953
1230
|
"button",
|
|
954
1231
|
{
|
|
955
1232
|
type: "button",
|
|
956
1233
|
"aria-label": "Close",
|
|
957
1234
|
onClick: () => sonnerToast.dismiss(id),
|
|
958
1235
|
className: "absolute right-[7px] top-[7px] flex size-4 items-center justify-center text-ods-text-secondary transition-colors hover:text-ods-text-primary",
|
|
959
|
-
children: /* @__PURE__ */
|
|
1236
|
+
children: /* @__PURE__ */ jsx3(XmarkIcon, { size: 16 })
|
|
960
1237
|
}
|
|
961
1238
|
) : null,
|
|
962
|
-
showProgress && duration !== Infinity && duration > 0 ? /* @__PURE__ */
|
|
1239
|
+
showProgress && duration !== Infinity && duration > 0 ? /* @__PURE__ */ jsx3(
|
|
963
1240
|
"div",
|
|
964
1241
|
{
|
|
965
1242
|
className: cn(
|
|
@@ -984,7 +1261,7 @@ function ToastCard({
|
|
|
984
1261
|
dismissible = true,
|
|
985
1262
|
className
|
|
986
1263
|
}) {
|
|
987
|
-
return /* @__PURE__ */
|
|
1264
|
+
return /* @__PURE__ */ jsx3(
|
|
988
1265
|
"div",
|
|
989
1266
|
{
|
|
990
1267
|
role: "status",
|
|
@@ -992,7 +1269,7 @@ function ToastCard({
|
|
|
992
1269
|
"w-[368px] max-w-[calc(100vw-32px)] overflow-hidden rounded-md border border-ods-border bg-ods-card shadow-lg",
|
|
993
1270
|
className
|
|
994
1271
|
),
|
|
995
|
-
children: /* @__PURE__ */
|
|
1272
|
+
children: /* @__PURE__ */ jsx3(
|
|
996
1273
|
ToastHeader,
|
|
997
1274
|
{
|
|
998
1275
|
id,
|
|
@@ -1041,7 +1318,7 @@ function CommandApprovalToast({
|
|
|
1041
1318
|
className
|
|
1042
1319
|
),
|
|
1043
1320
|
children: [
|
|
1044
|
-
/* @__PURE__ */
|
|
1321
|
+
/* @__PURE__ */ jsx3(
|
|
1045
1322
|
ToastHeader,
|
|
1046
1323
|
{
|
|
1047
1324
|
id,
|
|
@@ -1054,7 +1331,7 @@ function CommandApprovalToast({
|
|
|
1054
1331
|
className: "border-b border-ods-border"
|
|
1055
1332
|
}
|
|
1056
1333
|
),
|
|
1057
|
-
/* @__PURE__ */
|
|
1334
|
+
/* @__PURE__ */ jsx3(
|
|
1058
1335
|
"div",
|
|
1059
1336
|
{
|
|
1060
1337
|
className: "grid transition-[grid-template-rows] duration-300 ease-out",
|
|
@@ -1062,13 +1339,13 @@ function CommandApprovalToast({
|
|
|
1062
1339
|
"aria-hidden": !expanded,
|
|
1063
1340
|
children: /* @__PURE__ */ jsxs("div", { className: "overflow-hidden", children: [
|
|
1064
1341
|
/* @__PURE__ */ jsxs("div", { className: "flex h-11 w-full items-center gap-2 border-b border-ods-border bg-ods-card px-3 py-2", children: [
|
|
1065
|
-
/* @__PURE__ */
|
|
1066
|
-
toolType ? /* @__PURE__ */
|
|
1342
|
+
/* @__PURE__ */ jsx3("p", { className: "min-w-0 flex-1 truncate font-['DM_Sans'] text-[14px] font-medium leading-5 text-ods-text-primary", title: command, children: command }),
|
|
1343
|
+
toolType ? /* @__PURE__ */ jsx3(ToolIcon, { toolType, size: 16 }) : null
|
|
1067
1344
|
] }),
|
|
1068
1345
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 bg-ods-bg p-3", children: [
|
|
1069
|
-
approvalDescription ? /* @__PURE__ */
|
|
1346
|
+
approvalDescription ? /* @__PURE__ */ jsx3("p", { className: "font-['DM_Sans'] text-[14px] font-medium leading-5 text-ods-text-secondary", children: approvalDescription }) : null,
|
|
1070
1347
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
1071
|
-
/* @__PURE__ */
|
|
1348
|
+
/* @__PURE__ */ jsx3(
|
|
1072
1349
|
"button",
|
|
1073
1350
|
{
|
|
1074
1351
|
type: "button",
|
|
@@ -1078,7 +1355,7 @@ function CommandApprovalToast({
|
|
|
1078
1355
|
children: approveLabel
|
|
1079
1356
|
}
|
|
1080
1357
|
),
|
|
1081
|
-
/* @__PURE__ */
|
|
1358
|
+
/* @__PURE__ */ jsx3(
|
|
1082
1359
|
"button",
|
|
1083
1360
|
{
|
|
1084
1361
|
type: "button",
|
|
@@ -1101,8 +1378,8 @@ function CommandApprovalToast({
|
|
|
1101
1378
|
className: "flex w-full items-center gap-2 bg-ods-card px-3 py-2 text-left font-['DM_Sans'] text-[14px] font-medium leading-5 text-ods-text-primary transition-colors hover:bg-ods-bg-hover",
|
|
1102
1379
|
"aria-expanded": false,
|
|
1103
1380
|
children: [
|
|
1104
|
-
/* @__PURE__ */
|
|
1105
|
-
/* @__PURE__ */
|
|
1381
|
+
/* @__PURE__ */ jsx3("span", { className: "flex-1", children: "Show Command" }),
|
|
1382
|
+
/* @__PURE__ */ jsx3(Chevron02DownIcon, { size: 16 })
|
|
1106
1383
|
]
|
|
1107
1384
|
}
|
|
1108
1385
|
)
|
|
@@ -1119,13 +1396,13 @@ function Toaster({
|
|
|
1119
1396
|
} = {}) {
|
|
1120
1397
|
const { classNames: userClassNames, ...restToastOptions } = toastOptions ?? {};
|
|
1121
1398
|
return /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1122
|
-
/* @__PURE__ */
|
|
1399
|
+
/* @__PURE__ */ jsx3("style", { children: `
|
|
1123
1400
|
@keyframes toast-progress {
|
|
1124
1401
|
from { transform: scaleX(1); }
|
|
1125
1402
|
to { transform: scaleX(0); }
|
|
1126
1403
|
}
|
|
1127
1404
|
` }),
|
|
1128
|
-
/* @__PURE__ */
|
|
1405
|
+
/* @__PURE__ */ jsx3(
|
|
1129
1406
|
SonnerToaster,
|
|
1130
1407
|
{
|
|
1131
1408
|
position,
|
|
@@ -1155,7 +1432,7 @@ function showToast(options) {
|
|
|
1155
1432
|
...rest
|
|
1156
1433
|
} = opts;
|
|
1157
1434
|
return sonnerToast.custom(
|
|
1158
|
-
(id) => /* @__PURE__ */
|
|
1435
|
+
(id) => /* @__PURE__ */ jsx3(
|
|
1159
1436
|
ToastCard,
|
|
1160
1437
|
{
|
|
1161
1438
|
id,
|
|
@@ -1187,7 +1464,7 @@ function showCommandApprovalToast(options) {
|
|
|
1187
1464
|
...rest
|
|
1188
1465
|
} = options;
|
|
1189
1466
|
return sonnerToast.custom(
|
|
1190
|
-
(id) => /* @__PURE__ */
|
|
1467
|
+
(id) => /* @__PURE__ */ jsx3(
|
|
1191
1468
|
CommandApprovalToast,
|
|
1192
1469
|
{
|
|
1193
1470
|
id,
|
|
@@ -1236,16 +1513,270 @@ var useToast = () => ({
|
|
|
1236
1513
|
});
|
|
1237
1514
|
|
|
1238
1515
|
// src/hooks/use-contact-submission.ts
|
|
1239
|
-
import { useState as
|
|
1516
|
+
import { useState as useState15, useCallback as useCallback7, useEffect as useEffect11 } from "react";
|
|
1240
1517
|
init_next_navigation();
|
|
1518
|
+
|
|
1519
|
+
// src/utils/local-storage-adapter.ts
|
|
1520
|
+
function getStorage(backend) {
|
|
1521
|
+
if (typeof window === "undefined") return null;
|
|
1522
|
+
try {
|
|
1523
|
+
return backend === "session" ? window.sessionStorage : window.localStorage;
|
|
1524
|
+
} catch {
|
|
1525
|
+
return null;
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
function createLocalStorageAdapter(options) {
|
|
1529
|
+
const tag = options.logTag ?? "[local-storage]";
|
|
1530
|
+
const backend = options.backend ?? "local";
|
|
1531
|
+
const resolveKey = () => {
|
|
1532
|
+
const ns = options.namespace?.();
|
|
1533
|
+
return ns ? `${ns}.${options.key}` : options.key;
|
|
1534
|
+
};
|
|
1535
|
+
return {
|
|
1536
|
+
resolveKey,
|
|
1537
|
+
load() {
|
|
1538
|
+
const storage = getStorage(backend);
|
|
1539
|
+
if (!storage) return null;
|
|
1540
|
+
try {
|
|
1541
|
+
const raw = storage.getItem(resolveKey());
|
|
1542
|
+
if (!raw) return null;
|
|
1543
|
+
const parsed = JSON.parse(raw);
|
|
1544
|
+
if (options.validate && !options.validate(parsed)) return null;
|
|
1545
|
+
return parsed;
|
|
1546
|
+
} catch (err) {
|
|
1547
|
+
console.warn(`${tag} parse failed for key ${resolveKey()}:`, err);
|
|
1548
|
+
return null;
|
|
1549
|
+
}
|
|
1550
|
+
},
|
|
1551
|
+
save(value) {
|
|
1552
|
+
const storage = getStorage(backend);
|
|
1553
|
+
if (!storage) return;
|
|
1554
|
+
try {
|
|
1555
|
+
storage.setItem(resolveKey(), JSON.stringify(value));
|
|
1556
|
+
} catch (err) {
|
|
1557
|
+
console.warn(`${tag} write failed for key ${resolveKey()}:`, err);
|
|
1558
|
+
}
|
|
1559
|
+
},
|
|
1560
|
+
clear() {
|
|
1561
|
+
const storage = getStorage(backend);
|
|
1562
|
+
if (!storage) return;
|
|
1563
|
+
try {
|
|
1564
|
+
storage.removeItem(resolveKey());
|
|
1565
|
+
} catch (err) {
|
|
1566
|
+
console.warn(`${tag} clear failed for key ${resolveKey()}:`, err);
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
// src/utils/app-config.ts
|
|
1573
|
+
function getAppType() {
|
|
1574
|
+
return process.env.NEXT_PUBLIC_APP_TYPE || "openmsp";
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
// src/utils/embed-proxy-auth-storage.ts
|
|
1578
|
+
function isValidPersistedAuth(value) {
|
|
1579
|
+
if (!value || typeof value !== "object") return false;
|
|
1580
|
+
const v = value;
|
|
1581
|
+
if (typeof v.secret !== "string" || v.secret.trim().length === 0 || typeof v.email !== "string" || v.email.trim().length === 0) return false;
|
|
1582
|
+
if (v.firstName != null && typeof v.firstName !== "string") return false;
|
|
1583
|
+
if (v.lastName != null && typeof v.lastName !== "string") return false;
|
|
1584
|
+
if (v.avatarUrl != null && typeof v.avatarUrl !== "string") return false;
|
|
1585
|
+
return true;
|
|
1586
|
+
}
|
|
1587
|
+
var adapter = createLocalStorageAdapter({
|
|
1588
|
+
// Storage key unchanged from the legacy chat-prefixed helper. Renaming
|
|
1589
|
+
// it would silently log every existing admin out — the key is a
|
|
1590
|
+
// storage contract, not a code identifier.
|
|
1591
|
+
key: "chat.proxy-auth.v1",
|
|
1592
|
+
namespace: () => getAppType(),
|
|
1593
|
+
validate: isValidPersistedAuth,
|
|
1594
|
+
logTag: "[embed-proxy-auth-storage]",
|
|
1595
|
+
// localStorage — survives tab close, new tabs, and browser restarts.
|
|
1596
|
+
// Admin re-pasting creds every tab cycle was the dev-experience
|
|
1597
|
+
// tradeoff prior `sessionStorage` setup demanded — rejected. See
|
|
1598
|
+
// file-level doc comment for the security tradeoff rationale.
|
|
1599
|
+
backend: "local"
|
|
1600
|
+
});
|
|
1601
|
+
function normalizeOptional(value) {
|
|
1602
|
+
if (!value) return void 0;
|
|
1603
|
+
const trimmed = value.trim();
|
|
1604
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
1605
|
+
}
|
|
1606
|
+
function getEmbedProxyAuth() {
|
|
1607
|
+
const persisted = adapter.load();
|
|
1608
|
+
if (!persisted) return null;
|
|
1609
|
+
return {
|
|
1610
|
+
secret: persisted.secret,
|
|
1611
|
+
email: persisted.email.trim().toLowerCase(),
|
|
1612
|
+
firstName: normalizeOptional(persisted.firstName),
|
|
1613
|
+
lastName: normalizeOptional(persisted.lastName),
|
|
1614
|
+
avatarUrl: normalizeOptional(persisted.avatarUrl)
|
|
1615
|
+
};
|
|
1616
|
+
}
|
|
1617
|
+
function getPersistedProxyEmail() {
|
|
1618
|
+
const persisted = adapter.load();
|
|
1619
|
+
return persisted?.email.trim().toLowerCase() ?? null;
|
|
1620
|
+
}
|
|
1621
|
+
function setEmbedProxyAuth(value) {
|
|
1622
|
+
adapter.save({
|
|
1623
|
+
secret: value.secret,
|
|
1624
|
+
email: value.email.trim().toLowerCase(),
|
|
1625
|
+
firstName: normalizeOptional(value.firstName),
|
|
1626
|
+
lastName: normalizeOptional(value.lastName),
|
|
1627
|
+
avatarUrl: normalizeOptional(value.avatarUrl)
|
|
1628
|
+
});
|
|
1629
|
+
}
|
|
1630
|
+
function clearEmbedProxyAuth() {
|
|
1631
|
+
adapter.clear();
|
|
1632
|
+
}
|
|
1633
|
+
function applyProxyAuth(url, baseHeaders = { "Content-Type": "application/json" }) {
|
|
1634
|
+
const auth = getEmbedProxyAuth();
|
|
1635
|
+
const headers = { ...baseHeaders };
|
|
1636
|
+
if (auth?.secret) {
|
|
1637
|
+
headers.Authorization = `Bearer ${auth.secret}`;
|
|
1638
|
+
}
|
|
1639
|
+
if (auth?.email) {
|
|
1640
|
+
headers["X-Chat-Act-As"] = auth.email;
|
|
1641
|
+
}
|
|
1642
|
+
if (auth?.firstName) headers["X-Chat-First-Name"] = auth.firstName;
|
|
1643
|
+
if (auth?.lastName) headers["X-Chat-Last-Name"] = auth.lastName;
|
|
1644
|
+
if (auth?.avatarUrl) headers["X-Chat-Avatar-Url"] = auth.avatarUrl;
|
|
1645
|
+
return { url, headers };
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
// src/utils/embed-authed-fetch.ts
|
|
1649
|
+
var ADAPTER_GLOBAL_KEY = "__embedAuthedFetchAdapter__";
|
|
1650
|
+
function getRegisteredAuthAdapter() {
|
|
1651
|
+
if (typeof globalThis === "undefined") return null;
|
|
1652
|
+
return globalThis[ADAPTER_GLOBAL_KEY] ?? null;
|
|
1653
|
+
}
|
|
1654
|
+
function storeRegisteredAuthAdapter(adapter2) {
|
|
1655
|
+
if (typeof globalThis === "undefined") return;
|
|
1656
|
+
globalThis[ADAPTER_GLOBAL_KEY] = adapter2;
|
|
1657
|
+
}
|
|
1658
|
+
function setEmbedAuthAdapter(adapter2) {
|
|
1659
|
+
if (adapter2 && getRegisteredAuthAdapter() && process.env.NODE_ENV !== "production") {
|
|
1660
|
+
console.warn(
|
|
1661
|
+
"[setEmbedAuthAdapter] overwriting a previously-registered auth adapter. Two chat-runtime providers should not coexist \u2014 verify mount order and pass `null` from the unmounting provider."
|
|
1662
|
+
);
|
|
1663
|
+
}
|
|
1664
|
+
storeRegisteredAuthAdapter(adapter2);
|
|
1665
|
+
}
|
|
1666
|
+
function hasEmbedAuthAdapter() {
|
|
1667
|
+
return getRegisteredAuthAdapter() !== null;
|
|
1668
|
+
}
|
|
1669
|
+
function embedAuthedFetch(url, init = {}) {
|
|
1670
|
+
assertSameOrigin(url);
|
|
1671
|
+
let baseHeaders;
|
|
1672
|
+
if (init.headers === void 0) {
|
|
1673
|
+
baseHeaders = { "Content-Type": "application/json" };
|
|
1674
|
+
} else {
|
|
1675
|
+
baseHeaders = {};
|
|
1676
|
+
if (init.headers instanceof Headers) {
|
|
1677
|
+
init.headers.forEach((v, k) => {
|
|
1678
|
+
baseHeaders[k] = v;
|
|
1679
|
+
});
|
|
1680
|
+
} else if (Array.isArray(init.headers)) {
|
|
1681
|
+
for (const [k, v] of init.headers) baseHeaders[k] = v;
|
|
1682
|
+
} else {
|
|
1683
|
+
Object.assign(baseHeaders, init.headers);
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
return fetchWithRefresh(url, init, baseHeaders, false);
|
|
1687
|
+
}
|
|
1688
|
+
var IN_FLIGHT_REFRESH_GLOBAL_KEY = "__embedAuthedFetchInFlightRefresh__";
|
|
1689
|
+
function getInFlightRefresh() {
|
|
1690
|
+
if (typeof globalThis === "undefined") return null;
|
|
1691
|
+
return globalThis[IN_FLIGHT_REFRESH_GLOBAL_KEY] ?? null;
|
|
1692
|
+
}
|
|
1693
|
+
function setInFlightRefresh(refresh) {
|
|
1694
|
+
if (typeof globalThis === "undefined") return;
|
|
1695
|
+
globalThis[IN_FLIGHT_REFRESH_GLOBAL_KEY] = refresh;
|
|
1696
|
+
}
|
|
1697
|
+
function dedupedRefresh() {
|
|
1698
|
+
const adapter2 = getRegisteredAuthAdapter();
|
|
1699
|
+
if (!adapter2?.refresh) return Promise.resolve(false);
|
|
1700
|
+
let inFlightRefresh = getInFlightRefresh();
|
|
1701
|
+
if (!inFlightRefresh) {
|
|
1702
|
+
inFlightRefresh = Promise.resolve().then(() => adapter2.refresh()).catch(() => false).finally(() => {
|
|
1703
|
+
setInFlightRefresh(null);
|
|
1704
|
+
});
|
|
1705
|
+
setInFlightRefresh(inFlightRefresh);
|
|
1706
|
+
}
|
|
1707
|
+
return inFlightRefresh;
|
|
1708
|
+
}
|
|
1709
|
+
async function fetchWithRefresh(url, init, baseHeaders, isRetry) {
|
|
1710
|
+
const { url: authedUrl, headers } = applyProxyAuth(url, { ...baseHeaders });
|
|
1711
|
+
const adapter2 = getRegisteredAuthAdapter();
|
|
1712
|
+
if (adapter2?.getHeaders) {
|
|
1713
|
+
for (const [k, v] of Object.entries(adapter2.getHeaders())) {
|
|
1714
|
+
if (v !== void 0) headers[k] = v;
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
const credentials = adapter2?.credentials ?? init.credentials ?? "same-origin";
|
|
1718
|
+
const response = await fetch(authedUrl, {
|
|
1719
|
+
...init,
|
|
1720
|
+
headers,
|
|
1721
|
+
// Default `same-origin` carries Supabase cookies for the MPH proxy-
|
|
1722
|
+
// auth model. Hosts on different origins (openframe-frontend ↔
|
|
1723
|
+
// openframe gateway) register `credentials: 'include'` via the
|
|
1724
|
+
// adapter to make their own cookies travel cross-origin (CORS +
|
|
1725
|
+
// `SameSite=None` must be configured server-side for that to work).
|
|
1726
|
+
credentials
|
|
1727
|
+
});
|
|
1728
|
+
if (response.status === 401 && !isRetry && adapter2?.refresh) {
|
|
1729
|
+
const refreshed = await dedupedRefresh();
|
|
1730
|
+
if (refreshed) {
|
|
1731
|
+
return fetchWithRefresh(url, init, baseHeaders, true);
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
return response;
|
|
1735
|
+
}
|
|
1736
|
+
function assertSameOrigin(url) {
|
|
1737
|
+
if (typeof window === "undefined") return;
|
|
1738
|
+
let target;
|
|
1739
|
+
let pageOrigin;
|
|
1740
|
+
try {
|
|
1741
|
+
target = new URL(url, window.location.href);
|
|
1742
|
+
pageOrigin = new URL(window.location.href).origin;
|
|
1743
|
+
} catch {
|
|
1744
|
+
throw new Error(`embedAuthedFetch: refusing to fetch malformed URL (${JSON.stringify(url)})`);
|
|
1745
|
+
}
|
|
1746
|
+
if (target.protocol !== "http:" && target.protocol !== "https:") {
|
|
1747
|
+
throw new Error(
|
|
1748
|
+
`embedAuthedFetch: refusing non-http(s) URL (${target.protocol}) \u2014 pass a relative /api/* path instead`
|
|
1749
|
+
);
|
|
1750
|
+
}
|
|
1751
|
+
if (target.origin !== pageOrigin) {
|
|
1752
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1753
|
+
console.warn(
|
|
1754
|
+
`[embedAuthedFetch] cross-origin fetch to ${target.origin} allowed in dev (NODE_ENV !== 'production'). Production builds will reject this \u2014 wire a same-origin proxy before shipping.`
|
|
1755
|
+
);
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
throw new Error(
|
|
1759
|
+
`embedAuthedFetch: refusing cross-origin fetch to ${target.origin} \u2014 pass a relative /api/* path instead`
|
|
1760
|
+
);
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
// src/utils/embed-content-fetch.ts
|
|
1765
|
+
var contentFetch = (input, init) => {
|
|
1766
|
+
if (!hasEmbedAuthAdapter()) return fetch(input, init);
|
|
1767
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
1768
|
+
return embedAuthedFetch(url, init);
|
|
1769
|
+
};
|
|
1770
|
+
|
|
1771
|
+
// src/hooks/use-contact-submission.ts
|
|
1241
1772
|
function useContactSubmission(options = {}) {
|
|
1242
1773
|
const { userId, successRedirectUrl, successToastMessage, onSuccess } = options;
|
|
1243
1774
|
const { toast: toast2 } = useToast();
|
|
1244
1775
|
const router = useRouter();
|
|
1245
1776
|
const { contactUrl } = useRequiredEndpointsRuntime();
|
|
1246
|
-
const [isSubmitting, setIsSubmitting] =
|
|
1247
|
-
const [isSuccess, setIsSuccess] =
|
|
1248
|
-
const submit =
|
|
1777
|
+
const [isSubmitting, setIsSubmitting] = useState15(false);
|
|
1778
|
+
const [isSuccess, setIsSuccess] = useState15(false);
|
|
1779
|
+
const submit = useCallback7(async (formData) => {
|
|
1249
1780
|
if (isSubmitting) return;
|
|
1250
1781
|
setIsSubmitting(true);
|
|
1251
1782
|
try {
|
|
@@ -1280,7 +1811,7 @@ function useContactSubmission(options = {}) {
|
|
|
1280
1811
|
setIsSubmitting(false);
|
|
1281
1812
|
}
|
|
1282
1813
|
}, [isSubmitting, toast2, userId, successToastMessage, contactUrl]);
|
|
1283
|
-
|
|
1814
|
+
useEffect11(() => {
|
|
1284
1815
|
if (isSuccess && successRedirectUrl) {
|
|
1285
1816
|
console.log("\u{1F680} Contact submission successful, redirecting to:", successRedirectUrl);
|
|
1286
1817
|
const timer = setTimeout(() => {
|
|
@@ -1294,7 +1825,7 @@ function useContactSubmission(options = {}) {
|
|
|
1294
1825
|
return () => clearTimeout(timer);
|
|
1295
1826
|
}
|
|
1296
1827
|
}, [isSuccess, successRedirectUrl, router]);
|
|
1297
|
-
|
|
1828
|
+
useEffect11(() => {
|
|
1298
1829
|
if (isSuccess && onSuccess) {
|
|
1299
1830
|
onSuccess();
|
|
1300
1831
|
}
|
|
@@ -1303,19 +1834,19 @@ function useContactSubmission(options = {}) {
|
|
|
1303
1834
|
}
|
|
1304
1835
|
|
|
1305
1836
|
// src/hooks/use-quick-action-hint.ts
|
|
1306
|
-
import { useEffect as
|
|
1837
|
+
import { useEffect as useEffect12, useState as useState16, useRef as useRef6, useCallback as useCallback8 } from "react";
|
|
1307
1838
|
function useQuickActionHint({
|
|
1308
1839
|
actionCount,
|
|
1309
1840
|
cycleDuration = 5e3,
|
|
1310
1841
|
enabled = true
|
|
1311
1842
|
}) {
|
|
1312
|
-
const [activeHintIndex, setActiveHintIndex] =
|
|
1313
|
-
const containerRef =
|
|
1314
|
-
const timeoutRef =
|
|
1315
|
-
const cycleCountRef =
|
|
1316
|
-
const currentIndexRef =
|
|
1317
|
-
const sequenceRef =
|
|
1318
|
-
const shuffleIndices =
|
|
1843
|
+
const [activeHintIndex, setActiveHintIndex] = useState16(-1);
|
|
1844
|
+
const containerRef = useRef6(null);
|
|
1845
|
+
const timeoutRef = useRef6(null);
|
|
1846
|
+
const cycleCountRef = useRef6(0);
|
|
1847
|
+
const currentIndexRef = useRef6(0);
|
|
1848
|
+
const sequenceRef = useRef6([]);
|
|
1849
|
+
const shuffleIndices = useCallback8((length) => {
|
|
1319
1850
|
const indices = Array.from({ length }, (_, i) => i);
|
|
1320
1851
|
for (let i = indices.length - 1; i > 0; i--) {
|
|
1321
1852
|
const j = Math.floor(Math.random() * (i + 1));
|
|
@@ -1323,7 +1854,7 @@ function useQuickActionHint({
|
|
|
1323
1854
|
}
|
|
1324
1855
|
return indices;
|
|
1325
1856
|
}, []);
|
|
1326
|
-
const stopHint =
|
|
1857
|
+
const stopHint = useCallback8(() => {
|
|
1327
1858
|
if (timeoutRef.current) {
|
|
1328
1859
|
clearTimeout(timeoutRef.current);
|
|
1329
1860
|
timeoutRef.current = null;
|
|
@@ -1333,7 +1864,7 @@ function useQuickActionHint({
|
|
|
1333
1864
|
currentIndexRef.current = 0;
|
|
1334
1865
|
sequenceRef.current = [];
|
|
1335
1866
|
}, []);
|
|
1336
|
-
const advanceHint =
|
|
1867
|
+
const advanceHint = useCallback8(() => {
|
|
1337
1868
|
if (currentIndexRef.current === 0) {
|
|
1338
1869
|
sequenceRef.current = shuffleIndices(actionCount);
|
|
1339
1870
|
}
|
|
@@ -1346,7 +1877,7 @@ function useQuickActionHint({
|
|
|
1346
1877
|
}
|
|
1347
1878
|
timeoutRef.current = setTimeout(advanceHint, cycleDuration);
|
|
1348
1879
|
}, [actionCount, cycleDuration, shuffleIndices]);
|
|
1349
|
-
|
|
1880
|
+
useEffect12(() => {
|
|
1350
1881
|
if (!enabled || actionCount === 0) {
|
|
1351
1882
|
return;
|
|
1352
1883
|
}
|
|
@@ -1372,7 +1903,7 @@ function useQuickActionHint({
|
|
|
1372
1903
|
}
|
|
1373
1904
|
|
|
1374
1905
|
// src/hooks/use-copy-to-clipboard.ts
|
|
1375
|
-
import { useCallback as
|
|
1906
|
+
import { useCallback as useCallback9, useState as useState17 } from "react";
|
|
1376
1907
|
function useCopyToClipboard({
|
|
1377
1908
|
successTitle = "Copied",
|
|
1378
1909
|
successDescription = "Copied to clipboard",
|
|
@@ -1381,8 +1912,8 @@ function useCopyToClipboard({
|
|
|
1381
1912
|
resetDelay = 2e3
|
|
1382
1913
|
} = {}) {
|
|
1383
1914
|
const { toast: toast2 } = useToast();
|
|
1384
|
-
const [copied, setCopied] =
|
|
1385
|
-
const copy =
|
|
1915
|
+
const [copied, setCopied] = useState17(false);
|
|
1916
|
+
const copy = useCallback9(
|
|
1386
1917
|
async (text) => {
|
|
1387
1918
|
try {
|
|
1388
1919
|
await navigator.clipboard.writeText(text);
|
|
@@ -1399,7 +1930,7 @@ function useCopyToClipboard({
|
|
|
1399
1930
|
}
|
|
1400
1931
|
|
|
1401
1932
|
// src/hooks/use-batch-images.ts
|
|
1402
|
-
import { useEffect as
|
|
1933
|
+
import { useEffect as useEffect13, useMemo as useMemo2, useState as useState18, useRef as useRef7 } from "react";
|
|
1403
1934
|
var globalBatchImageConfig = {};
|
|
1404
1935
|
function configureBatchImageFetch(config) {
|
|
1405
1936
|
globalBatchImageConfig = { ...globalBatchImageConfig, ...config };
|
|
@@ -1472,14 +2003,14 @@ async function batchFetchAuthenticatedImages(imageUrls, config) {
|
|
|
1472
2003
|
return results;
|
|
1473
2004
|
}
|
|
1474
2005
|
function useBatchImages(imageUrls, config) {
|
|
1475
|
-
const [fetchedImages, setFetchedImages] =
|
|
1476
|
-
const [loading, setLoading] =
|
|
2006
|
+
const [fetchedImages, setFetchedImages] = useState18({});
|
|
2007
|
+
const [loading, setLoading] = useState18(false);
|
|
1477
2008
|
const uniqueUrls = useMemo2(
|
|
1478
2009
|
() => Array.from(new Set(imageUrls.filter((url) => Boolean(url)))),
|
|
1479
2010
|
[imageUrls]
|
|
1480
2011
|
);
|
|
1481
|
-
const requestedUrls =
|
|
1482
|
-
|
|
2012
|
+
const requestedUrls = useRef7(/* @__PURE__ */ new Set());
|
|
2013
|
+
useEffect13(() => {
|
|
1483
2014
|
if (uniqueUrls.length === 0) {
|
|
1484
2015
|
setFetchedImages({});
|
|
1485
2016
|
return;
|
|
@@ -1509,7 +2040,7 @@ function useBatchImages(imageUrls, config) {
|
|
|
1509
2040
|
}
|
|
1510
2041
|
|
|
1511
2042
|
// src/hooks/use-authenticated-image.ts
|
|
1512
|
-
import { useEffect as
|
|
2043
|
+
import { useEffect as useEffect14, useState as useState19, useRef as useRef8 } from "react";
|
|
1513
2044
|
var globalImageConfig = {};
|
|
1514
2045
|
var imageCache = /* @__PURE__ */ new Map();
|
|
1515
2046
|
var pendingRequests = /* @__PURE__ */ new Map();
|
|
@@ -1538,11 +2069,11 @@ function getImageConfig() {
|
|
|
1538
2069
|
};
|
|
1539
2070
|
}
|
|
1540
2071
|
function useAuthenticatedImage(imageUrl, refreshKey, config) {
|
|
1541
|
-
const [fetchedImageUrl, setFetchedImageUrl] =
|
|
1542
|
-
const [isLoading, setIsLoading] =
|
|
1543
|
-
const [error, setError] =
|
|
1544
|
-
const currentCacheKeyRef =
|
|
1545
|
-
|
|
2072
|
+
const [fetchedImageUrl, setFetchedImageUrl] = useState19();
|
|
2073
|
+
const [isLoading, setIsLoading] = useState19(false);
|
|
2074
|
+
const [error, setError] = useState19(null);
|
|
2075
|
+
const currentCacheKeyRef = useRef8(null);
|
|
2076
|
+
useEffect14(() => {
|
|
1546
2077
|
if (!imageUrl) {
|
|
1547
2078
|
setFetchedImageUrl(void 0);
|
|
1548
2079
|
setIsLoading(false);
|
|
@@ -1653,7 +2184,7 @@ function useAuthenticatedImage(imageUrl, refreshKey, config) {
|
|
|
1653
2184
|
});
|
|
1654
2185
|
pendingRequests.set(cacheKey, fetchPromise2);
|
|
1655
2186
|
}, [imageUrl, refreshKey, config]);
|
|
1656
|
-
|
|
2187
|
+
useEffect14(() => {
|
|
1657
2188
|
return () => {
|
|
1658
2189
|
if (currentCacheKeyRef.current) {
|
|
1659
2190
|
const entry = imageCache.get(currentCacheKeyRef.current);
|
|
@@ -1668,7 +2199,7 @@ function useAuthenticatedImage(imageUrl, refreshKey, config) {
|
|
|
1668
2199
|
|
|
1669
2200
|
// src/hooks/state/use-query-params.ts
|
|
1670
2201
|
init_next_navigation();
|
|
1671
|
-
import { useEffect as
|
|
2202
|
+
import { useEffect as useEffect15, useState as useState20, useMemo as useMemo3, useCallback as useCallback10 } from "react";
|
|
1672
2203
|
|
|
1673
2204
|
// src/hooks/state/graphql-parser.ts
|
|
1674
2205
|
import {
|
|
@@ -2130,14 +2661,14 @@ var introspector = new GraphQLIntrospector();
|
|
|
2130
2661
|
function useQueryParams(query, options = {}) {
|
|
2131
2662
|
const router = useRouter();
|
|
2132
2663
|
const searchParams = useSearchParams();
|
|
2133
|
-
const [isLoading, setIsLoading] =
|
|
2134
|
-
const [isReady, setIsReady] =
|
|
2135
|
-
const [error, setError] =
|
|
2136
|
-
const [schema, setSchema] =
|
|
2664
|
+
const [isLoading, setIsLoading] = useState20(true);
|
|
2665
|
+
const [isReady, setIsReady] = useState20(false);
|
|
2666
|
+
const [error, setError] = useState20(null);
|
|
2667
|
+
const [schema, setSchema] = useState20({});
|
|
2137
2668
|
const defaultValues = options.defaultValues || {};
|
|
2138
2669
|
const skipIntrospection = options.skipIntrospection || false;
|
|
2139
2670
|
const debug = options.debug || false;
|
|
2140
|
-
|
|
2671
|
+
useEffect15(() => {
|
|
2141
2672
|
async function initialize() {
|
|
2142
2673
|
try {
|
|
2143
2674
|
if (debug) console.log("[useQueryParams] Initializing...");
|
|
@@ -2207,14 +2738,14 @@ function useQueryParams(query, options = {}) {
|
|
|
2207
2738
|
});
|
|
2208
2739
|
return result;
|
|
2209
2740
|
}, [searchParams]);
|
|
2210
|
-
const updateUrl =
|
|
2741
|
+
const updateUrl = useCallback10((newParams) => {
|
|
2211
2742
|
const url = newParams.toString() ? `?${newParams.toString()}` : window.location.pathname;
|
|
2212
2743
|
if (debug) {
|
|
2213
2744
|
console.log("[useQueryParams] Updating URL:", url);
|
|
2214
2745
|
}
|
|
2215
2746
|
router.replace(url, { scroll: false });
|
|
2216
2747
|
}, [router, debug]);
|
|
2217
|
-
const setParam =
|
|
2748
|
+
const setParam = useCallback10((key, value) => {
|
|
2218
2749
|
if (!isReady) {
|
|
2219
2750
|
console.warn("[useQueryParams] Schema not ready, cannot set param");
|
|
2220
2751
|
return;
|
|
@@ -2228,7 +2759,7 @@ function useQueryParams(query, options = {}) {
|
|
|
2228
2759
|
console.error("[useQueryParams] Failed to set param:", err);
|
|
2229
2760
|
}
|
|
2230
2761
|
}, [variables, schema, isReady, updateUrl]);
|
|
2231
|
-
const setParams =
|
|
2762
|
+
const setParams = useCallback10((updates) => {
|
|
2232
2763
|
if (!isReady) {
|
|
2233
2764
|
console.warn("[useQueryParams] Schema not ready, cannot set params");
|
|
2234
2765
|
return;
|
|
@@ -2242,7 +2773,7 @@ function useQueryParams(query, options = {}) {
|
|
|
2242
2773
|
console.error("[useQueryParams] Failed to set params:", err);
|
|
2243
2774
|
}
|
|
2244
2775
|
}, [variables, schema, isReady, updateUrl]);
|
|
2245
|
-
const clearParamsHandler =
|
|
2776
|
+
const clearParamsHandler = useCallback10((keys) => {
|
|
2246
2777
|
if (!isReady) {
|
|
2247
2778
|
console.warn("[useQueryParams] Schema not ready, cannot clear params");
|
|
2248
2779
|
return;
|
|
@@ -2256,7 +2787,7 @@ function useQueryParams(query, options = {}) {
|
|
|
2256
2787
|
console.error("[useQueryParams] Failed to clear params:", err);
|
|
2257
2788
|
}
|
|
2258
2789
|
}, [variables, schema, isReady, updateUrl]);
|
|
2259
|
-
const resetParams =
|
|
2790
|
+
const resetParams = useCallback10(() => {
|
|
2260
2791
|
if (debug) {
|
|
2261
2792
|
console.log("[useQueryParams] Resetting params");
|
|
2262
2793
|
}
|
|
@@ -2289,9 +2820,9 @@ function applyParamMapping(schema, mapping) {
|
|
|
2289
2820
|
|
|
2290
2821
|
// src/hooks/state/use-api-params.ts
|
|
2291
2822
|
init_next_navigation();
|
|
2292
|
-
import { useCallback as
|
|
2823
|
+
import { useCallback as useCallback11, useMemo as useMemo4, useRef as useRef9 } from "react";
|
|
2293
2824
|
function useContentStable(value, key) {
|
|
2294
|
-
const ref =
|
|
2825
|
+
const ref = useRef9(void 0);
|
|
2295
2826
|
if (ref.current && ref.current.key === key) return ref.current.value;
|
|
2296
2827
|
ref.current = { value, key };
|
|
2297
2828
|
return value;
|
|
@@ -2324,7 +2855,7 @@ function useApiParams(schema, options = {}) {
|
|
|
2324
2855
|
}
|
|
2325
2856
|
return flattened;
|
|
2326
2857
|
}, [schemaKey]);
|
|
2327
|
-
const prevParamsRef =
|
|
2858
|
+
const prevParamsRef = useRef9(void 0);
|
|
2328
2859
|
const params = useMemo4(() => {
|
|
2329
2860
|
const sp = new URLSearchParams(searchString);
|
|
2330
2861
|
const result = {};
|
|
@@ -2348,7 +2879,7 @@ function useApiParams(schema, options = {}) {
|
|
|
2348
2879
|
prevParamsRef.current = result;
|
|
2349
2880
|
return result;
|
|
2350
2881
|
}, [searchString, schemaKey, debug]);
|
|
2351
|
-
const addParamToSearchParams =
|
|
2882
|
+
const addParamToSearchParams = useCallback11((searchParams, key, value) => {
|
|
2352
2883
|
if (value === void 0 || value === "" || value === null) {
|
|
2353
2884
|
return;
|
|
2354
2885
|
}
|
|
@@ -2376,7 +2907,7 @@ function useApiParams(schema, options = {}) {
|
|
|
2376
2907
|
}
|
|
2377
2908
|
return newParams;
|
|
2378
2909
|
}, [params, schemaKey, flattenedSchema, addParamToSearchParams]);
|
|
2379
|
-
const updateUrl =
|
|
2910
|
+
const updateUrl = useCallback11((newParams, keysToRemove = []) => {
|
|
2380
2911
|
const finalParams = new URLSearchParams(searchString);
|
|
2381
2912
|
keysToRemove.forEach((key) => {
|
|
2382
2913
|
if (key in stableSchema) {
|
|
@@ -2412,7 +2943,7 @@ function useApiParams(schema, options = {}) {
|
|
|
2412
2943
|
}
|
|
2413
2944
|
return false;
|
|
2414
2945
|
};
|
|
2415
|
-
const setParam =
|
|
2946
|
+
const setParam = useCallback11((key, value) => {
|
|
2416
2947
|
const config = stableSchema[key];
|
|
2417
2948
|
if (!config) {
|
|
2418
2949
|
console.warn(`[useApiParams] Unknown parameter: ${key}`);
|
|
@@ -2426,7 +2957,7 @@ function useApiParams(schema, options = {}) {
|
|
|
2426
2957
|
updateUrl(newParams);
|
|
2427
2958
|
}
|
|
2428
2959
|
}, [schemaKey, updateUrl, addParamToSearchParams]);
|
|
2429
|
-
const setParams =
|
|
2960
|
+
const setParams = useCallback11((updates) => {
|
|
2430
2961
|
const newParams = new URLSearchParams();
|
|
2431
2962
|
const keysToRemove = [];
|
|
2432
2963
|
for (const [key, value] of Object.entries(updates)) {
|
|
@@ -2443,11 +2974,11 @@ function useApiParams(schema, options = {}) {
|
|
|
2443
2974
|
}
|
|
2444
2975
|
updateUrl(newParams, keysToRemove);
|
|
2445
2976
|
}, [schemaKey, updateUrl, addParamToSearchParams]);
|
|
2446
|
-
const clearParams2 =
|
|
2977
|
+
const clearParams2 = useCallback11((keys) => {
|
|
2447
2978
|
const newParams = new URLSearchParams();
|
|
2448
2979
|
updateUrl(newParams, keys);
|
|
2449
2980
|
}, [updateUrl]);
|
|
2450
|
-
const resetParams =
|
|
2981
|
+
const resetParams = useCallback11(() => {
|
|
2451
2982
|
if (debug) {
|
|
2452
2983
|
console.log("[useApiParams] Resetting params");
|
|
2453
2984
|
}
|
|
@@ -2484,7 +3015,7 @@ function createSearchParams(params) {
|
|
|
2484
3015
|
}
|
|
2485
3016
|
|
|
2486
3017
|
// src/hooks/state/use-cursor-pagination-state.ts
|
|
2487
|
-
import { useCallback as
|
|
3018
|
+
import { useCallback as useCallback12, useEffect as useEffect16, useRef as useRef10, useState as useState21 } from "react";
|
|
2488
3019
|
var urlSchema = {
|
|
2489
3020
|
search: { type: "string", default: "" },
|
|
2490
3021
|
cursor: { type: "string", default: "" }
|
|
@@ -2495,13 +3026,13 @@ function useCursorPaginationState(options) {
|
|
|
2495
3026
|
onSearchChange
|
|
2496
3027
|
} = options;
|
|
2497
3028
|
const { params, setParam, setParams } = useApiParams(urlSchema);
|
|
2498
|
-
const [searchInput, setSearchInput] =
|
|
2499
|
-
const [hasLoadedBeyondFirst, setHasLoadedBeyondFirst] =
|
|
2500
|
-
const [initialLoadCount, setInitialLoadCount] =
|
|
2501
|
-
const lastSearchRef =
|
|
2502
|
-
const isSyncingFromUrl =
|
|
2503
|
-
const isInitialLoadInProgress =
|
|
2504
|
-
|
|
3029
|
+
const [searchInput, setSearchInput] = useState21(params.search || "");
|
|
3030
|
+
const [hasLoadedBeyondFirst, setHasLoadedBeyondFirst] = useState21(false);
|
|
3031
|
+
const [initialLoadCount, setInitialLoadCount] = useState21(0);
|
|
3032
|
+
const lastSearchRef = useRef10(null);
|
|
3033
|
+
const isSyncingFromUrl = useRef10(false);
|
|
3034
|
+
const isInitialLoadInProgress = useRef10(true);
|
|
3035
|
+
useEffect16(() => {
|
|
2505
3036
|
if (isInitialLoadInProgress.current) return;
|
|
2506
3037
|
const urlSearch = params.search || "";
|
|
2507
3038
|
if (urlSearch !== searchInput) {
|
|
@@ -2512,7 +3043,7 @@ function useCursorPaginationState(options) {
|
|
|
2512
3043
|
}, 0);
|
|
2513
3044
|
}
|
|
2514
3045
|
}, [params.search, initialLoadCount]);
|
|
2515
|
-
|
|
3046
|
+
useEffect16(() => {
|
|
2516
3047
|
if (isInitialLoadInProgress.current) return;
|
|
2517
3048
|
if (isSyncingFromUrl.current) return;
|
|
2518
3049
|
if (searchInput !== params.search) {
|
|
@@ -2523,7 +3054,7 @@ function useCursorPaginationState(options) {
|
|
|
2523
3054
|
});
|
|
2524
3055
|
}
|
|
2525
3056
|
}, [searchInput, params.search, setParams, initialLoadCount]);
|
|
2526
|
-
|
|
3057
|
+
useEffect16(() => {
|
|
2527
3058
|
if (initialLoadCount === 0) {
|
|
2528
3059
|
const cursor = params.cursor || null;
|
|
2529
3060
|
const search = params.search || "";
|
|
@@ -2537,7 +3068,7 @@ function useCursorPaginationState(options) {
|
|
|
2537
3068
|
});
|
|
2538
3069
|
}
|
|
2539
3070
|
}, []);
|
|
2540
|
-
|
|
3071
|
+
useEffect16(() => {
|
|
2541
3072
|
if (isInitialLoadInProgress.current) return;
|
|
2542
3073
|
if (initialLoadCount === 0) return;
|
|
2543
3074
|
const currentSearch = params.search || "";
|
|
@@ -2547,7 +3078,7 @@ function useCursorPaginationState(options) {
|
|
|
2547
3078
|
onSearchChange(currentSearch);
|
|
2548
3079
|
}
|
|
2549
3080
|
}, [params.search, onSearchChange, initialLoadCount]);
|
|
2550
|
-
const handleNextPage =
|
|
3081
|
+
const handleNextPage = useCallback12(
|
|
2551
3082
|
async (endCursor, fetchFn) => {
|
|
2552
3083
|
setParam("cursor", endCursor);
|
|
2553
3084
|
await fetchFn();
|
|
@@ -2555,7 +3086,7 @@ function useCursorPaginationState(options) {
|
|
|
2555
3086
|
},
|
|
2556
3087
|
[setParam]
|
|
2557
3088
|
);
|
|
2558
|
-
const handleResetToFirstPage =
|
|
3089
|
+
const handleResetToFirstPage = useCallback12(
|
|
2559
3090
|
async (fetchFn) => {
|
|
2560
3091
|
setParam("cursor", "");
|
|
2561
3092
|
await fetchFn();
|
|
@@ -2577,16 +3108,16 @@ function useCursorPaginationState(options) {
|
|
|
2577
3108
|
}
|
|
2578
3109
|
|
|
2579
3110
|
// src/hooks/nats/use-nats-client.ts
|
|
2580
|
-
import { useEffect as
|
|
3111
|
+
import { useEffect as useEffect17, useMemo as useMemo5, useState as useState22 } from "react";
|
|
2581
3112
|
function useNatsClient(clientOptions, options = {}) {
|
|
2582
3113
|
const { autoConnect = true } = options;
|
|
2583
3114
|
const client = useMemo5(() => {
|
|
2584
3115
|
if (!clientOptions) return null;
|
|
2585
3116
|
return createNatsClient(clientOptions);
|
|
2586
3117
|
}, [clientOptions]);
|
|
2587
|
-
const [status, setStatus] =
|
|
2588
|
-
const [lastError, setLastError] =
|
|
2589
|
-
|
|
3118
|
+
const [status, setStatus] = useState22("disconnected");
|
|
3119
|
+
const [lastError, setLastError] = useState22(null);
|
|
3120
|
+
useEffect17(() => {
|
|
2590
3121
|
if (!client) {
|
|
2591
3122
|
setStatus("disconnected");
|
|
2592
3123
|
setLastError(null);
|
|
@@ -2616,8 +3147,125 @@ function useNatsClient(clientOptions, options = {}) {
|
|
|
2616
3147
|
};
|
|
2617
3148
|
}
|
|
2618
3149
|
|
|
3150
|
+
// src/hooks/use-near-viewport.ts
|
|
3151
|
+
import { useEffect as useEffect18, useRef as useRef11, useState as useState23, useCallback as useCallback13 } from "react";
|
|
3152
|
+
var observers = /* @__PURE__ */ new Map();
|
|
3153
|
+
var subscribers = /* @__PURE__ */ new WeakMap();
|
|
3154
|
+
function getObserverFor(rootMargin) {
|
|
3155
|
+
const existing = observers.get(rootMargin);
|
|
3156
|
+
if (existing) return existing;
|
|
3157
|
+
const io = new IntersectionObserver(
|
|
3158
|
+
(entries) => {
|
|
3159
|
+
entries.forEach((entry) => {
|
|
3160
|
+
if (!entry.isIntersecting) return;
|
|
3161
|
+
const cb = subscribers.get(entry.target);
|
|
3162
|
+
if (cb) {
|
|
3163
|
+
cb();
|
|
3164
|
+
io.unobserve(entry.target);
|
|
3165
|
+
subscribers.delete(entry.target);
|
|
3166
|
+
}
|
|
3167
|
+
});
|
|
3168
|
+
},
|
|
3169
|
+
{ rootMargin }
|
|
3170
|
+
);
|
|
3171
|
+
observers.set(rootMargin, io);
|
|
3172
|
+
return io;
|
|
3173
|
+
}
|
|
3174
|
+
function useNearViewport(rootMargin = "500px") {
|
|
3175
|
+
const [isNear, setIsNear] = useState23(false);
|
|
3176
|
+
const elRef = useRef11(null);
|
|
3177
|
+
const ref = useCallback13(
|
|
3178
|
+
(node) => {
|
|
3179
|
+
const prev = elRef.current;
|
|
3180
|
+
if (prev) {
|
|
3181
|
+
const stillOurs = subscribers.get(prev);
|
|
3182
|
+
if (stillOurs) {
|
|
3183
|
+
subscribers.delete(prev);
|
|
3184
|
+
observers.get(rootMargin)?.unobserve(prev);
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
elRef.current = node;
|
|
3188
|
+
if (!node) return;
|
|
3189
|
+
const cb = () => setIsNear(true);
|
|
3190
|
+
subscribers.set(node, cb);
|
|
3191
|
+
getObserverFor(rootMargin).observe(node);
|
|
3192
|
+
},
|
|
3193
|
+
[rootMargin]
|
|
3194
|
+
);
|
|
3195
|
+
useEffect18(() => {
|
|
3196
|
+
return () => {
|
|
3197
|
+
const el = elRef.current;
|
|
3198
|
+
if (!el) return;
|
|
3199
|
+
if (subscribers.get(el)) {
|
|
3200
|
+
subscribers.delete(el);
|
|
3201
|
+
observers.get(rootMargin)?.unobserve(el);
|
|
3202
|
+
}
|
|
3203
|
+
};
|
|
3204
|
+
}, [rootMargin]);
|
|
3205
|
+
return { ref, isNear };
|
|
3206
|
+
}
|
|
3207
|
+
|
|
2619
3208
|
// src/hooks/use-access-code-integration.ts
|
|
2620
3209
|
import React2 from "react";
|
|
3210
|
+
|
|
3211
|
+
// src/utils/access-code-client.ts
|
|
3212
|
+
async function validateAccessCode(email, code, endpoints) {
|
|
3213
|
+
try {
|
|
3214
|
+
const response = await fetch(endpoints.validateUrl, {
|
|
3215
|
+
method: "POST",
|
|
3216
|
+
headers: {
|
|
3217
|
+
"Content-Type": "application/json"
|
|
3218
|
+
},
|
|
3219
|
+
body: JSON.stringify({ email, code })
|
|
3220
|
+
});
|
|
3221
|
+
if (!response.ok) {
|
|
3222
|
+
const error = await response.json().catch(() => ({}));
|
|
3223
|
+
throw new Error(error.error || "Validation request failed");
|
|
3224
|
+
}
|
|
3225
|
+
return await response.json();
|
|
3226
|
+
} catch (error) {
|
|
3227
|
+
return {
|
|
3228
|
+
valid: false,
|
|
3229
|
+
message: error instanceof Error ? error.message : "Validation failed"
|
|
3230
|
+
};
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
async function consumeAccessCode(email, code, endpoints) {
|
|
3234
|
+
try {
|
|
3235
|
+
const response = await fetch(endpoints.consumeUrl, {
|
|
3236
|
+
method: "POST",
|
|
3237
|
+
headers: {
|
|
3238
|
+
"Content-Type": "application/json"
|
|
3239
|
+
},
|
|
3240
|
+
body: JSON.stringify({ email, code })
|
|
3241
|
+
});
|
|
3242
|
+
if (!response.ok) {
|
|
3243
|
+
const error = await response.json().catch(() => ({}));
|
|
3244
|
+
throw new Error(error.error || "Consumption request failed");
|
|
3245
|
+
}
|
|
3246
|
+
return await response.json();
|
|
3247
|
+
} catch (error) {
|
|
3248
|
+
return {
|
|
3249
|
+
success: false,
|
|
3250
|
+
consumed: false,
|
|
3251
|
+
message: error instanceof Error ? error.message : "Consumption failed"
|
|
3252
|
+
};
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
async function validateAndConsumeAccessCode(email, code, endpoints) {
|
|
3256
|
+
const validation = await validateAccessCode(email, code, endpoints);
|
|
3257
|
+
if (!validation.valid) {
|
|
3258
|
+
return validation;
|
|
3259
|
+
}
|
|
3260
|
+
const consumption = await consumeAccessCode(email, code, endpoints);
|
|
3261
|
+
return {
|
|
3262
|
+
...validation,
|
|
3263
|
+
consumed: consumption.consumed,
|
|
3264
|
+
message: consumption.consumed ? `Access granted for ${validation.cohort_name}` : consumption.message || validation.message
|
|
3265
|
+
};
|
|
3266
|
+
}
|
|
3267
|
+
|
|
3268
|
+
// src/hooks/use-access-code-integration.ts
|
|
2621
3269
|
function useAccessCodeIntegration() {
|
|
2622
3270
|
const runtime = useRequiredEndpointsRuntime();
|
|
2623
3271
|
const endpoints = runtime.accessCode;
|
|
@@ -2659,12 +3307,158 @@ function useAccessCodeIntegration() {
|
|
|
2659
3307
|
};
|
|
2660
3308
|
}
|
|
2661
3309
|
|
|
3310
|
+
// src/hooks/use-og-placeholder.ts
|
|
3311
|
+
import { useMemo as useMemo6 } from "react";
|
|
3312
|
+
function useOgPlaceholder(buildUrl, title, siteName = "", enabled = true, aspect = "wide") {
|
|
3313
|
+
return useMemo6(() => {
|
|
3314
|
+
if (!enabled || !title) return null;
|
|
3315
|
+
const options = {};
|
|
3316
|
+
if (siteName) options.site = siteName;
|
|
3317
|
+
if (aspect === "square") options.aspect = "square";
|
|
3318
|
+
return buildUrl(title, options);
|
|
3319
|
+
}, [buildUrl, title, siteName, enabled, aspect]);
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3322
|
+
// src/hooks/use-scroll-to-hash.ts
|
|
3323
|
+
import { useEffect as useEffect19 } from "react";
|
|
3324
|
+
|
|
3325
|
+
// src/utils/scroll-into-view.ts
|
|
3326
|
+
var activeRaf = 0;
|
|
3327
|
+
var teardownActive = null;
|
|
3328
|
+
function cancelActiveScroll() {
|
|
3329
|
+
if (activeRaf) {
|
|
3330
|
+
cancelAnimationFrame(activeRaf);
|
|
3331
|
+
activeRaf = 0;
|
|
3332
|
+
}
|
|
3333
|
+
if (teardownActive) {
|
|
3334
|
+
teardownActive();
|
|
3335
|
+
teardownActive = null;
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
var easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
|
|
3339
|
+
function getScrollableAncestor(el) {
|
|
3340
|
+
for (let node = el.parentElement; node; node = node.parentElement) {
|
|
3341
|
+
const overflowY = getComputedStyle(node).overflowY;
|
|
3342
|
+
if ((overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay") && node.scrollHeight > node.clientHeight) {
|
|
3343
|
+
return node;
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
return null;
|
|
3347
|
+
}
|
|
3348
|
+
function scrollElementIntoView(target, options = {}) {
|
|
3349
|
+
if (typeof window === "undefined" || !target) return;
|
|
3350
|
+
const { headerOffset = 0, behavior = "smooth", adjustTargetY, durationMs = 320 } = options;
|
|
3351
|
+
const container = getScrollableAncestor(target);
|
|
3352
|
+
const readCurrent = () => container ? container.scrollTop : window.scrollY;
|
|
3353
|
+
const writeTo = (y) => {
|
|
3354
|
+
if (container) container.scrollTop = y;
|
|
3355
|
+
else window.scrollTo(0, y);
|
|
3356
|
+
};
|
|
3357
|
+
const computeTarget = () => {
|
|
3358
|
+
const raw = container ? container.scrollTop + (target.getBoundingClientRect().top - container.getBoundingClientRect().top) - headerOffset : target.getBoundingClientRect().top + window.scrollY - headerOffset;
|
|
3359
|
+
const adjusted = adjustTargetY ? adjustTargetY(raw) : raw;
|
|
3360
|
+
const maxScroll = container ? Math.max(0, container.scrollHeight - container.clientHeight) : Math.max(0, document.documentElement.scrollHeight - window.innerHeight);
|
|
3361
|
+
return Math.min(Math.max(0, adjusted), maxScroll);
|
|
3362
|
+
};
|
|
3363
|
+
cancelActiveScroll();
|
|
3364
|
+
const prefersReduced = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
3365
|
+
if (behavior === "instant" || behavior === "auto" || prefersReduced) {
|
|
3366
|
+
writeTo(computeTarget());
|
|
3367
|
+
return;
|
|
3368
|
+
}
|
|
3369
|
+
let startY = null;
|
|
3370
|
+
let startTime = 0;
|
|
3371
|
+
const onUserGesture = () => cancelActiveScroll();
|
|
3372
|
+
window.addEventListener("wheel", onUserGesture, { passive: true });
|
|
3373
|
+
window.addEventListener("touchmove", onUserGesture, { passive: true });
|
|
3374
|
+
teardownActive = () => {
|
|
3375
|
+
window.removeEventListener("wheel", onUserGesture);
|
|
3376
|
+
window.removeEventListener("touchmove", onUserGesture);
|
|
3377
|
+
};
|
|
3378
|
+
const step = (now) => {
|
|
3379
|
+
if (startY === null) {
|
|
3380
|
+
startY = readCurrent();
|
|
3381
|
+
startTime = now;
|
|
3382
|
+
}
|
|
3383
|
+
const targetY = computeTarget();
|
|
3384
|
+
const t = Math.min(1, (now - startTime) / durationMs);
|
|
3385
|
+
const y = startY + (targetY - startY) * easeOutCubic(t);
|
|
3386
|
+
writeTo(y);
|
|
3387
|
+
if (t < 1) {
|
|
3388
|
+
activeRaf = requestAnimationFrame(step);
|
|
3389
|
+
} else {
|
|
3390
|
+
writeTo(computeTarget());
|
|
3391
|
+
activeRaf = 0;
|
|
3392
|
+
if (teardownActive) {
|
|
3393
|
+
teardownActive();
|
|
3394
|
+
teardownActive = null;
|
|
3395
|
+
}
|
|
3396
|
+
}
|
|
3397
|
+
};
|
|
3398
|
+
activeRaf = requestAnimationFrame(step);
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3401
|
+
// src/utils/same-page-hash-nav.ts
|
|
3402
|
+
var STICKY_HEADER_OFFSET_PX = 96;
|
|
3403
|
+
var HUB_HEADER_OFFSET_PX = 80;
|
|
3404
|
+
function normalizeHashFragment(hash) {
|
|
3405
|
+
if (!hash) return "";
|
|
3406
|
+
const second = hash.indexOf("#", 1);
|
|
3407
|
+
return second < 0 ? hash : hash.slice(0, second);
|
|
3408
|
+
}
|
|
3409
|
+
function navigateSamePageHash(target, options = {}) {
|
|
3410
|
+
if (typeof window === "undefined") return false;
|
|
3411
|
+
const { headerOffset = 0, history: historyMode = "push" } = options;
|
|
3412
|
+
const normalizedTarget = target.startsWith("#") ? window.location.pathname + window.location.search + target : target;
|
|
3413
|
+
let url;
|
|
3414
|
+
try {
|
|
3415
|
+
url = new URL(normalizedTarget, window.location.href);
|
|
3416
|
+
} catch {
|
|
3417
|
+
return false;
|
|
3418
|
+
}
|
|
3419
|
+
if (url.origin !== window.location.origin || url.pathname !== window.location.pathname || url.search !== window.location.search) {
|
|
3420
|
+
return false;
|
|
3421
|
+
}
|
|
3422
|
+
const current = window.location.pathname + window.location.search + window.location.hash;
|
|
3423
|
+
const normalizedHash = normalizeHashFragment(url.hash);
|
|
3424
|
+
if (process.env.NODE_ENV === "development" && normalizedHash !== url.hash) {
|
|
3425
|
+
console.warn(
|
|
3426
|
+
`[navigateSamePageHash] malformed fragment "${url.hash}" \u2192 normalizing to "${normalizedHash}". Fix the upstream composer.`
|
|
3427
|
+
);
|
|
3428
|
+
}
|
|
3429
|
+
const next = url.pathname + url.search + normalizedHash;
|
|
3430
|
+
const id = normalizedHash && normalizedHash !== "#" ? normalizedHash.slice(1) : "";
|
|
3431
|
+
if (!id && next !== current) return false;
|
|
3432
|
+
if (next !== current) {
|
|
3433
|
+
const oldURL = window.location.href;
|
|
3434
|
+
if (historyMode === "replace") {
|
|
3435
|
+
window.history.replaceState(null, "", next);
|
|
3436
|
+
} else {
|
|
3437
|
+
window.history.pushState(null, "", next);
|
|
3438
|
+
}
|
|
3439
|
+
window.dispatchEvent(new HashChangeEvent("hashchange", {
|
|
3440
|
+
oldURL,
|
|
3441
|
+
newURL: window.location.href
|
|
3442
|
+
}));
|
|
3443
|
+
}
|
|
3444
|
+
const el = id ? document.getElementById(id) : null;
|
|
3445
|
+
if (id && !el && process.env.NODE_ENV === "development") {
|
|
3446
|
+
console.warn(
|
|
3447
|
+
`[navigateSamePageHash] anchor "#${id}" not found \u2014 scrolling to top.`
|
|
3448
|
+
);
|
|
3449
|
+
}
|
|
3450
|
+
scrollElementIntoView(el ?? document.documentElement, {
|
|
3451
|
+
behavior: "smooth",
|
|
3452
|
+
headerOffset
|
|
3453
|
+
});
|
|
3454
|
+
return true;
|
|
3455
|
+
}
|
|
3456
|
+
|
|
2662
3457
|
// src/hooks/use-scroll-to-hash.ts
|
|
2663
|
-
import { useEffect as useEffect16 } from "react";
|
|
2664
3458
|
var MAX_POLL_FRAMES = 60;
|
|
2665
3459
|
function useScrollToHash(readyDep = true, options) {
|
|
2666
3460
|
const headerOffset = options?.headerOffset ?? 0;
|
|
2667
|
-
|
|
3461
|
+
useEffect19(() => {
|
|
2668
3462
|
if (typeof window === "undefined") return;
|
|
2669
3463
|
if (readyDep === null || readyDep === false) return;
|
|
2670
3464
|
let rafId = null;
|
|
@@ -2704,18 +3498,40 @@ function useScrollToHash(readyDep = true, options) {
|
|
|
2704
3498
|
}
|
|
2705
3499
|
|
|
2706
3500
|
// src/hooks/use-humanity-signals.ts
|
|
2707
|
-
import { useCallback as
|
|
3501
|
+
import { useCallback as useCallback14, useRef as useRef12 } from "react";
|
|
3502
|
+
|
|
3503
|
+
// src/utils/humanity-signals.ts
|
|
3504
|
+
var HONEYPOT_FIELD = "contact_url_confirm";
|
|
3505
|
+
var ELAPSED_MS_FIELD = "form_elapsed_ms";
|
|
3506
|
+
var DEFAULT_MIN_FILL_MS = 700;
|
|
3507
|
+
function extractHumanitySignals(body) {
|
|
3508
|
+
const b = body ?? {};
|
|
3509
|
+
const rawHp = b[HONEYPOT_FIELD];
|
|
3510
|
+
const honeypot = rawHp == null ? "" : String(rawHp);
|
|
3511
|
+
const rawMs = b[ELAPSED_MS_FIELD];
|
|
3512
|
+
const elapsedMs = typeof rawMs === "number" && Number.isFinite(rawMs) ? rawMs : null;
|
|
3513
|
+
return { honeypot, elapsedMs };
|
|
3514
|
+
}
|
|
3515
|
+
function evaluateHumanitySignals(body, opts) {
|
|
3516
|
+
const { honeypot, elapsedMs } = extractHumanitySignals(body);
|
|
3517
|
+
if (honeypot.trim() !== "") return { ok: false, reason: "honeypot" };
|
|
3518
|
+
if (elapsedMs !== null && elapsedMs < opts.minFillMs) return { ok: false, reason: "too_fast" };
|
|
3519
|
+
return { ok: true };
|
|
3520
|
+
}
|
|
3521
|
+
var splitCsvEnv = (s) => s?.split(",").map((t) => t.trim()).filter(Boolean) ?? [];
|
|
3522
|
+
|
|
3523
|
+
// src/hooks/use-humanity-signals.ts
|
|
2708
3524
|
function useHumanitySignals() {
|
|
2709
|
-
const ref =
|
|
2710
|
-
const mountedAt =
|
|
2711
|
-
const getSignals =
|
|
3525
|
+
const ref = useRef12(null);
|
|
3526
|
+
const mountedAt = useRef12(typeof performance !== "undefined" ? performance.now() : 0);
|
|
3527
|
+
const getSignals = useCallback14(
|
|
2712
3528
|
() => ({
|
|
2713
3529
|
[HONEYPOT_FIELD]: ref.current?.value ?? "",
|
|
2714
3530
|
[ELAPSED_MS_FIELD]: typeof performance !== "undefined" ? Math.round(performance.now() - mountedAt.current) : 0
|
|
2715
3531
|
}),
|
|
2716
3532
|
[]
|
|
2717
3533
|
);
|
|
2718
|
-
const resetSignals =
|
|
3534
|
+
const resetSignals = useCallback14(() => {
|
|
2719
3535
|
if (ref.current) ref.current.value = "";
|
|
2720
3536
|
if (typeof performance !== "undefined") mountedAt.current = performance.now();
|
|
2721
3537
|
}, []);
|
|
@@ -2723,6 +3539,8 @@ function useHumanitySignals() {
|
|
|
2723
3539
|
}
|
|
2724
3540
|
|
|
2725
3541
|
export {
|
|
3542
|
+
useAutoLimitTags,
|
|
3543
|
+
useDebounce,
|
|
2726
3544
|
useHeaderHeight,
|
|
2727
3545
|
useHorizontalScrollbar,
|
|
2728
3546
|
useImageEdgeColor,
|
|
@@ -2739,9 +3557,28 @@ export {
|
|
|
2739
3557
|
useTablePagination,
|
|
2740
3558
|
useThrottle,
|
|
2741
3559
|
useWindowSize,
|
|
3560
|
+
platformIcons,
|
|
3561
|
+
platformColors,
|
|
3562
|
+
platformDisplayNames,
|
|
3563
|
+
platformDescriptions,
|
|
3564
|
+
platformSlogans,
|
|
3565
|
+
platformHexColors,
|
|
3566
|
+
platformIconNames,
|
|
3567
|
+
getDefaultColorForPlatform,
|
|
3568
|
+
getDefaultIconForPlatform,
|
|
3569
|
+
transformPlatformConfigsToOptions,
|
|
3570
|
+
getPlatformIcon,
|
|
3571
|
+
getPlatformColor,
|
|
3572
|
+
getPlatformDisplayName,
|
|
3573
|
+
getPlatformDescription,
|
|
3574
|
+
getPlatformSlogan,
|
|
3575
|
+
getSmallPlatformIcon,
|
|
3576
|
+
getPlatformIconComponent,
|
|
2742
3577
|
usePlatformConfig,
|
|
2743
3578
|
usePlatformByValue,
|
|
2744
3579
|
useValidatePlatform,
|
|
3580
|
+
ToolTypeValues,
|
|
3581
|
+
toolLabels,
|
|
2745
3582
|
ToolIcon,
|
|
2746
3583
|
dotColorByVariant,
|
|
2747
3584
|
progressColorByVariant,
|
|
@@ -2752,6 +3589,15 @@ export {
|
|
|
2752
3589
|
showCommandApprovalToast,
|
|
2753
3590
|
toast,
|
|
2754
3591
|
useToast,
|
|
3592
|
+
getAppType,
|
|
3593
|
+
getEmbedProxyAuth,
|
|
3594
|
+
getPersistedProxyEmail,
|
|
3595
|
+
setEmbedProxyAuth,
|
|
3596
|
+
clearEmbedProxyAuth,
|
|
3597
|
+
applyProxyAuth,
|
|
3598
|
+
setEmbedAuthAdapter,
|
|
3599
|
+
embedAuthedFetch,
|
|
3600
|
+
contentFetch,
|
|
2755
3601
|
useContactSubmission,
|
|
2756
3602
|
useQuickActionHint,
|
|
2757
3603
|
useCopyToClipboard,
|
|
@@ -2784,8 +3630,24 @@ export {
|
|
|
2784
3630
|
createSearchParams,
|
|
2785
3631
|
useCursorPaginationState,
|
|
2786
3632
|
useNatsClient,
|
|
3633
|
+
useNearViewport,
|
|
3634
|
+
validateAccessCode,
|
|
3635
|
+
consumeAccessCode,
|
|
3636
|
+
validateAndConsumeAccessCode,
|
|
2787
3637
|
useAccessCodeIntegration,
|
|
3638
|
+
useOgPlaceholder,
|
|
3639
|
+
scrollElementIntoView,
|
|
3640
|
+
STICKY_HEADER_OFFSET_PX,
|
|
3641
|
+
HUB_HEADER_OFFSET_PX,
|
|
3642
|
+
normalizeHashFragment,
|
|
3643
|
+
navigateSamePageHash,
|
|
2788
3644
|
useScrollToHash,
|
|
3645
|
+
HONEYPOT_FIELD,
|
|
3646
|
+
ELAPSED_MS_FIELD,
|
|
3647
|
+
DEFAULT_MIN_FILL_MS,
|
|
3648
|
+
extractHumanitySignals,
|
|
3649
|
+
evaluateHumanitySignals,
|
|
3650
|
+
splitCsvEnv,
|
|
2789
3651
|
useHumanitySignals
|
|
2790
3652
|
};
|
|
2791
|
-
//# sourceMappingURL=chunk-
|
|
3653
|
+
//# sourceMappingURL=chunk-2QG57XOJ.js.map
|