@burdenoff/website-sdk 2026.1101.1 → 2026.1101.2
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 +42 -8
- package/dist/analytics/index.js +19 -69
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +3 -69
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/avatar-live/index.js +1 -0
- package/dist/avatar-live/index.js.map +1 -1
- package/dist/avatar-live/index.mjs +1 -0
- package/dist/avatar-live/index.mjs.map +1 -1
- package/dist/avatar-live-view/index.js +10 -30
- package/dist/avatar-live-view/index.js.map +1 -1
- package/dist/avatar-live-view/index.mjs +4 -24
- package/dist/avatar-live-view/index.mjs.map +1 -1
- package/dist/chunk-23H4JUL4.js +41 -0
- package/dist/chunk-23H4JUL4.js.map +1 -0
- package/dist/chunk-34RX5P75.mjs +25 -0
- package/dist/chunk-34RX5P75.mjs.map +1 -0
- package/dist/chunk-3LFFY7AZ.js +184 -0
- package/dist/chunk-3LFFY7AZ.js.map +1 -0
- package/dist/chunk-3X26GE4S.js +2794 -0
- package/dist/chunk-3X26GE4S.js.map +1 -0
- package/dist/chunk-45GCA4GG.js +85 -0
- package/dist/chunk-45GCA4GG.js.map +1 -0
- package/dist/chunk-4SAGVLHN.js +876 -0
- package/dist/chunk-4SAGVLHN.js.map +1 -0
- package/dist/chunk-4U6YAII5.js +218 -0
- package/dist/chunk-4U6YAII5.js.map +1 -0
- package/dist/chunk-5GMTBOO6.js +21 -0
- package/dist/chunk-5GMTBOO6.js.map +1 -0
- package/dist/chunk-5JRJ57CL.mjs +329 -0
- package/dist/chunk-5JRJ57CL.mjs.map +1 -0
- package/dist/chunk-6C2DKIC7.js +4 -0
- package/dist/chunk-6C2DKIC7.js.map +1 -0
- package/dist/chunk-6IBFBWC5.mjs +17 -0
- package/dist/chunk-6IBFBWC5.mjs.map +1 -0
- package/dist/chunk-6KY2ZRVI.js +116 -0
- package/dist/chunk-6KY2ZRVI.js.map +1 -0
- package/dist/chunk-6VJT3SM4.mjs +182 -0
- package/dist/chunk-6VJT3SM4.mjs.map +1 -0
- package/dist/chunk-6YZUFMK2.mjs +40 -0
- package/dist/chunk-6YZUFMK2.mjs.map +1 -0
- package/dist/chunk-7A6R7CGG.js +47 -0
- package/dist/chunk-7A6R7CGG.js.map +1 -0
- package/dist/chunk-7PWL4V2R.js +4 -0
- package/dist/chunk-7PWL4V2R.js.map +1 -0
- package/dist/chunk-AA33WDYS.js +161 -0
- package/dist/chunk-AA33WDYS.js.map +1 -0
- package/dist/chunk-AHRGFXV2.js +525 -0
- package/dist/chunk-AHRGFXV2.js.map +1 -0
- package/dist/chunk-B63XLDZH.mjs +109 -0
- package/dist/chunk-B63XLDZH.mjs.map +1 -0
- package/dist/chunk-BX2USEWF.mjs +35 -0
- package/dist/chunk-BX2USEWF.mjs.map +1 -0
- package/dist/chunk-BYSZT35R.js +150 -0
- package/dist/chunk-BYSZT35R.js.map +1 -0
- package/dist/chunk-C6OJIHNO.js +12 -0
- package/dist/chunk-C6OJIHNO.js.map +1 -0
- package/dist/chunk-COOELBX7.mjs +63 -0
- package/dist/chunk-COOELBX7.mjs.map +1 -0
- package/dist/chunk-D2TW7MNC.mjs +2771 -0
- package/dist/chunk-D2TW7MNC.mjs.map +1 -0
- package/dist/chunk-D5KEZ6V6.mjs +3 -0
- package/dist/chunk-D5KEZ6V6.mjs.map +1 -0
- package/dist/chunk-E3GUGJMY.js +46 -0
- package/dist/chunk-E3GUGJMY.js.map +1 -0
- package/dist/chunk-EBZ2HGJ2.mjs +52 -0
- package/dist/chunk-EBZ2HGJ2.mjs.map +1 -0
- package/dist/chunk-EDLTUOIA.mjs +210 -0
- package/dist/chunk-EDLTUOIA.mjs.map +1 -0
- package/dist/chunk-EJQSOT4X.js +4 -0
- package/dist/chunk-EJQSOT4X.js.map +1 -0
- package/dist/chunk-EUPFS6MZ.mjs +2019 -0
- package/dist/chunk-EUPFS6MZ.mjs.map +1 -0
- package/dist/chunk-F3XWDC3B.js +77 -0
- package/dist/chunk-F3XWDC3B.js.map +1 -0
- package/dist/chunk-FFADMVIK.mjs +5127 -0
- package/dist/chunk-FFADMVIK.mjs.map +1 -0
- package/dist/chunk-FJWS7BKT.mjs +3 -0
- package/dist/chunk-FJWS7BKT.mjs.map +1 -0
- package/dist/chunk-FJZJDUOR.mjs +3 -0
- package/dist/chunk-FJZJDUOR.mjs.map +1 -0
- package/dist/chunk-GCFLCO2Z.mjs +145 -0
- package/dist/chunk-GCFLCO2Z.mjs.map +1 -0
- package/dist/chunk-GEXC4LRP.js +61 -0
- package/dist/chunk-GEXC4LRP.js.map +1 -0
- package/dist/chunk-GTRAXQGC.mjs +3 -0
- package/dist/chunk-GTRAXQGC.mjs.map +1 -0
- package/dist/chunk-IKOIRUKW.js +270 -0
- package/dist/chunk-IKOIRUKW.js.map +1 -0
- package/dist/chunk-IXTWOPRN.js +45 -0
- package/dist/chunk-IXTWOPRN.js.map +1 -0
- package/dist/chunk-JDXOXGOK.js +547 -0
- package/dist/chunk-JDXOXGOK.js.map +1 -0
- package/dist/chunk-JSLDWYV7.mjs +558 -0
- package/dist/chunk-JSLDWYV7.mjs.map +1 -0
- package/dist/chunk-JXLSTVBK.js +336 -0
- package/dist/chunk-JXLSTVBK.js.map +1 -0
- package/dist/chunk-KHYXK7FG.mjs +49 -0
- package/dist/chunk-KHYXK7FG.mjs.map +1 -0
- package/dist/chunk-KSMBOWQQ.js +2034 -0
- package/dist/chunk-KSMBOWQQ.js.map +1 -0
- package/dist/chunk-KU2PXHGB.mjs +83 -0
- package/dist/chunk-KU2PXHGB.mjs.map +1 -0
- package/dist/chunk-KZANIV3S.mjs +37 -0
- package/dist/chunk-KZANIV3S.mjs.map +1 -0
- package/dist/chunk-L4BP6YOB.js +20 -0
- package/dist/chunk-L4BP6YOB.js.map +1 -0
- package/dist/chunk-MRKA2OAF.mjs +75 -0
- package/dist/chunk-MRKA2OAF.mjs.map +1 -0
- package/dist/chunk-N5EC53MH.mjs +80 -0
- package/dist/chunk-N5EC53MH.mjs.map +1 -0
- package/dist/chunk-NZANQGDM.mjs +34 -0
- package/dist/chunk-NZANQGDM.mjs.map +1 -0
- package/dist/chunk-O4GS3XPZ.js +10 -0
- package/dist/chunk-O4GS3XPZ.js.map +1 -0
- package/dist/chunk-O76QDGRM.js +5154 -0
- package/dist/chunk-O76QDGRM.js.map +1 -0
- package/dist/chunk-OYEUNZJY.js +114 -0
- package/dist/chunk-OYEUNZJY.js.map +1 -0
- package/dist/chunk-PHXAGQNB.js +74 -0
- package/dist/chunk-PHXAGQNB.js.map +1 -0
- package/dist/chunk-PIHHPP7J.mjs +16 -0
- package/dist/chunk-PIHHPP7J.mjs.map +1 -0
- package/dist/chunk-PXRHVVOU.mjs +499 -0
- package/dist/chunk-PXRHVVOU.mjs.map +1 -0
- package/dist/chunk-QMA6U6AU.js +36 -0
- package/dist/chunk-QMA6U6AU.js.map +1 -0
- package/dist/chunk-R6J7IULF.js +44 -0
- package/dist/chunk-R6J7IULF.js.map +1 -0
- package/dist/chunk-R7G6TWIS.mjs +10 -0
- package/dist/chunk-R7G6TWIS.mjs.map +1 -0
- package/dist/chunk-RUMGFI6L.mjs +544 -0
- package/dist/chunk-RUMGFI6L.mjs.map +1 -0
- package/dist/chunk-S54JWSJF.js +565 -0
- package/dist/chunk-S54JWSJF.js.map +1 -0
- package/dist/chunk-SK5UGG6A.js +2041 -0
- package/dist/chunk-SK5UGG6A.js.map +1 -0
- package/dist/chunk-SKIYDKIS.mjs +70 -0
- package/dist/chunk-SKIYDKIS.mjs.map +1 -0
- package/dist/chunk-SZNS5IK6.mjs +322 -0
- package/dist/chunk-SZNS5IK6.mjs.map +1 -0
- package/dist/chunk-T7JIPZAC.js +66 -0
- package/dist/chunk-T7JIPZAC.js.map +1 -0
- package/dist/chunk-TGYQHO2E.mjs +864 -0
- package/dist/chunk-TGYQHO2E.mjs.map +1 -0
- package/dist/chunk-TT3MHN42.mjs +8 -0
- package/dist/chunk-TT3MHN42.mjs.map +1 -0
- package/dist/chunk-UM55U65W.mjs +268 -0
- package/dist/chunk-UM55U65W.mjs.map +1 -0
- package/dist/chunk-UQ2HALUD.js +72 -0
- package/dist/chunk-UQ2HALUD.js.map +1 -0
- package/dist/chunk-UXWT7G77.js +82 -0
- package/dist/chunk-UXWT7G77.js.map +1 -0
- package/dist/chunk-VNS5WDWO.mjs +7 -0
- package/dist/chunk-VNS5WDWO.mjs.map +1 -0
- package/dist/chunk-VRWZLGR7.js +4 -0
- package/dist/chunk-VRWZLGR7.js.map +1 -0
- package/dist/chunk-VZLDSNH4.mjs +22 -0
- package/dist/chunk-VZLDSNH4.mjs.map +1 -0
- package/dist/chunk-W6P3YETJ.js +92 -0
- package/dist/chunk-W6P3YETJ.js.map +1 -0
- package/dist/chunk-WPKFFQCR.mjs +90 -0
- package/dist/chunk-WPKFFQCR.mjs.map +1 -0
- package/dist/chunk-WTVTI5TO.mjs +22 -0
- package/dist/chunk-WTVTI5TO.mjs.map +1 -0
- package/dist/chunk-XJOBZ4RJ.js +44 -0
- package/dist/chunk-XJOBZ4RJ.js.map +1 -0
- package/dist/chunk-XP2JDNDU.js +325 -0
- package/dist/chunk-XP2JDNDU.js.map +1 -0
- package/dist/chunk-Y4V5CEWD.mjs +112 -0
- package/dist/chunk-Y4V5CEWD.mjs.map +1 -0
- package/dist/chunk-YERN2UWM.js +116 -0
- package/dist/chunk-YERN2UWM.js.map +1 -0
- package/dist/chunk-ZKJQWFAA.mjs +114 -0
- package/dist/chunk-ZKJQWFAA.mjs.map +1 -0
- package/dist/chunk-ZOON3S3Y.mjs +138 -0
- package/dist/chunk-ZOON3S3Y.mjs.map +1 -0
- package/dist/chunk-ZP6QRAYC.mjs +2024 -0
- package/dist/chunk-ZP6QRAYC.mjs.map +1 -0
- package/dist/chunk-ZSTFX7FV.js +9 -0
- package/dist/chunk-ZSTFX7FV.js.map +1 -0
- package/dist/client/index.js +23 -331
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +3 -330
- package/dist/client/index.mjs.map +1 -1
- package/dist/comparison/index.js +28 -111
- package/dist/comparison/index.js.map +1 -1
- package/dist/comparison/index.mjs +2 -107
- package/dist/comparison/index.mjs.map +1 -1
- package/dist/components/contact.js +21 -931
- package/dist/components/contact.js.map +1 -1
- package/dist/components/contact.mjs +12 -909
- package/dist/components/contact.mjs.map +1 -1
- package/dist/components/electron-download.js +12 -124
- package/dist/components/electron-download.js.map +1 -1
- package/dist/components/electron-download.mjs +4 -106
- package/dist/components/electron-download.mjs.map +1 -1
- package/dist/components/explore-cta.js +8 -112
- package/dist/components/explore-cta.js.map +1 -1
- package/dist/components/explore-cta.mjs +3 -114
- package/dist/components/explore-cta.mjs.map +1 -1
- package/dist/components/explore.js +62 -7833
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +13 -7800
- package/dist/components/explore.mjs.map +1 -1
- package/dist/components/launch-countdown.js +8 -83
- package/dist/components/launch-countdown.js.map +1 -1
- package/dist/components/launch-countdown.mjs +3 -85
- package/dist/components/launch-countdown.mjs.map +1 -1
- package/dist/components/newsletter.js +20 -993
- package/dist/components/newsletter.js.map +1 -1
- package/dist/components/newsletter.mjs +11 -971
- package/dist/components/newsletter.mjs.map +1 -1
- package/dist/components/partners.js +24 -1302
- package/dist/components/partners.js.map +1 -1
- package/dist/components/partners.mjs +15 -1276
- package/dist/components/partners.mjs.map +1 -1
- package/dist/components/pricing.js +49 -1249
- package/dist/components/pricing.js.map +1 -1
- package/dist/components/pricing.mjs +8 -1226
- package/dist/components/pricing.mjs.map +1 -1
- package/dist/components/problems-solved.js +8 -150
- package/dist/components/problems-solved.js.map +1 -1
- package/dist/components/problems-solved.mjs +4 -133
- package/dist/components/problems-solved.mjs.map +1 -1
- package/dist/components/resource-links.js +8 -304
- package/dist/components/resource-links.js.map +1 -1
- package/dist/components/resource-links.mjs +5 -308
- package/dist/components/resource-links.mjs.map +1 -1
- package/dist/components/social-links.js +8 -343
- package/dist/components/social-links.js.map +1 -1
- package/dist/components/social-links.mjs +5 -347
- package/dist/components/social-links.mjs.map +1 -1
- package/dist/components/unsubscribe.js +10 -627
- package/dist/components/unsubscribe.js.map +1 -1
- package/dist/components/unsubscribe.mjs +6 -611
- package/dist/components/unsubscribe.mjs.map +1 -1
- package/dist/components/waitlist.js +21 -1001
- package/dist/components/waitlist.js.map +1 -1
- package/dist/components/waitlist.mjs +12 -982
- package/dist/components/waitlist.mjs.map +1 -1
- package/dist/components/website-switcher.js +12 -175
- package/dist/components/website-switcher.js.map +1 -1
- package/dist/components/website-switcher.mjs +4 -157
- package/dist/components/website-switcher.mjs.map +1 -1
- package/dist/content/index.js +118 -3616
- package/dist/content/index.js.map +1 -1
- package/dist/content/index.mjs +12 -3567
- package/dist/content/index.mjs.map +1 -1
- package/dist/hooks/index.js +37 -2321
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +6 -2318
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4145 -20599
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3766 -20567
- package/dist/index.mjs.map +1 -1
- package/dist/product/index.js +20 -393
- package/dist/product/index.js.map +1 -1
- package/dist/product/index.mjs +5 -394
- package/dist/product/index.mjs.map +1 -1
- package/dist/seo/index.js +8 -76
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +3 -78
- package/dist/seo/index.mjs.map +1 -1
- package/dist/store/index.js +51 -2650
- package/dist/store/index.js.map +1 -1
- package/dist/store/index.mjs +13 -2619
- package/dist/store/index.mjs.map +1 -1
- package/dist/utils/index.js +69 -134
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +5 -122
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk4U6YAII5_js = require('./chunk-4U6YAII5.js');
|
|
4
|
+
var chunkAHRGFXV2_js = require('./chunk-AHRGFXV2.js');
|
|
5
|
+
var chunkUXWT7G77_js = require('./chunk-UXWT7G77.js');
|
|
6
|
+
var chunkBYSZT35R_js = require('./chunk-BYSZT35R.js');
|
|
7
|
+
var chunkJXLSTVBK_js = require('./chunk-JXLSTVBK.js');
|
|
8
|
+
var react = require('react');
|
|
9
|
+
var lucideReact = require('lucide-react');
|
|
10
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
11
|
+
|
|
12
|
+
var PARTNER_CONTENT_QUERY = `
|
|
13
|
+
query PartnerContent($productId: String!, $limit: Int) {
|
|
14
|
+
publicContentPages(productId: $productId, limit: $limit, offset: 0) {
|
|
15
|
+
items {
|
|
16
|
+
id
|
|
17
|
+
title
|
|
18
|
+
slug
|
|
19
|
+
excerpt
|
|
20
|
+
content
|
|
21
|
+
contentFormat
|
|
22
|
+
thumbnail
|
|
23
|
+
tags
|
|
24
|
+
publishedAt
|
|
25
|
+
lastUpdated
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
var PARTNER_DOCUMENTS_QUERY = `
|
|
31
|
+
query PartnerDocuments($productId: String!, $limit: Int) {
|
|
32
|
+
publicPressKitAssets(productId: $productId, limit: $limit, offset: 0) {
|
|
33
|
+
items {
|
|
34
|
+
id
|
|
35
|
+
category
|
|
36
|
+
title
|
|
37
|
+
description
|
|
38
|
+
fileUrl
|
|
39
|
+
fileName
|
|
40
|
+
fileSize
|
|
41
|
+
mimeType
|
|
42
|
+
version
|
|
43
|
+
tags
|
|
44
|
+
sortOrder
|
|
45
|
+
updatedAt
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
function formatFileSize(bytes) {
|
|
51
|
+
if (!bytes || bytes <= 0) return "";
|
|
52
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
53
|
+
let i = 0;
|
|
54
|
+
let n = bytes;
|
|
55
|
+
while (n >= 1024 && i < units.length - 1) {
|
|
56
|
+
n /= 1024;
|
|
57
|
+
i++;
|
|
58
|
+
}
|
|
59
|
+
return `${n.toFixed(n >= 10 || i === 0 ? 0 : 1)} ${units[i]}`;
|
|
60
|
+
}
|
|
61
|
+
async function downloadDocument(e, doc) {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
const name = doc.fileName || doc.fileUrl.split("/").pop()?.split("?")[0] || doc.title || "partner-document";
|
|
64
|
+
const openInTab = () => window.open(doc.fileUrl, "_blank", "noopener,noreferrer");
|
|
65
|
+
try {
|
|
66
|
+
const res = await fetch(doc.fileUrl, { mode: "cors" });
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
openInTab();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const blob = await res.blob();
|
|
72
|
+
const objUrl = URL.createObjectURL(blob);
|
|
73
|
+
const a = document.createElement("a");
|
|
74
|
+
a.href = objUrl;
|
|
75
|
+
a.download = name;
|
|
76
|
+
document.body.appendChild(a);
|
|
77
|
+
a.click();
|
|
78
|
+
a.remove();
|
|
79
|
+
URL.revokeObjectURL(objUrl);
|
|
80
|
+
} catch {
|
|
81
|
+
openInTab();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function PartnerHero({
|
|
85
|
+
title,
|
|
86
|
+
subtitle
|
|
87
|
+
}) {
|
|
88
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "bg-gradient-to-b from-background to-muted/20 py-16 md:py-24", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "container mx-auto px-4 max-w-4xl text-center", children: [
|
|
89
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-4xl md:text-5xl font-bold tracking-tight text-foreground mb-4", children: title }),
|
|
90
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg md:text-xl text-muted-foreground max-w-2xl mx-auto", children: subtitle })
|
|
91
|
+
] }) });
|
|
92
|
+
}
|
|
93
|
+
function stripLeadingHeading(content, format) {
|
|
94
|
+
if (format === "html") {
|
|
95
|
+
return content.replace(/^\s*<h1\b[^>]*>[\s\S]*?<\/h1>\s*/i, "");
|
|
96
|
+
}
|
|
97
|
+
return content.replace(/^\s*#\s+.*(?:\r?\n)*/, "");
|
|
98
|
+
}
|
|
99
|
+
function PartnerContentSection({
|
|
100
|
+
page
|
|
101
|
+
}) {
|
|
102
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12 md:py-16", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
103
|
+
"div",
|
|
104
|
+
{
|
|
105
|
+
className: [
|
|
106
|
+
"mx-auto max-w-3xl px-4",
|
|
107
|
+
// Headings
|
|
108
|
+
"[&_h1]:text-3xl [&_h1]:font-bold [&_h1]:tracking-tight [&_h1]:mt-0 [&_h1]:mb-6",
|
|
109
|
+
"[&_h2]:text-2xl [&_h2]:font-bold [&_h2]:tracking-tight [&_h2]:mt-10 [&_h2]:mb-4",
|
|
110
|
+
"[&_h3]:text-xl [&_h3]:font-semibold [&_h3]:mt-7 [&_h3]:mb-3",
|
|
111
|
+
"[&_h4]:text-lg [&_h4]:font-semibold [&_h4]:mt-6 [&_h4]:mb-2",
|
|
112
|
+
// Block elements
|
|
113
|
+
"[&_p]:my-4 [&_p]:leading-relaxed [&_p]:text-base",
|
|
114
|
+
"[&_ul]:my-4 [&_ul]:pl-6 [&_ul]:list-disc [&_ul]:space-y-1",
|
|
115
|
+
"[&_ol]:my-4 [&_ol]:pl-6 [&_ol]:list-decimal [&_ol]:space-y-1",
|
|
116
|
+
"[&_li]:leading-relaxed",
|
|
117
|
+
"[&_li>p]:my-1",
|
|
118
|
+
"[&_blockquote]:border-l-4 [&_blockquote]:border-border [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:my-4 [&_blockquote]:text-muted-foreground",
|
|
119
|
+
"[&_hr]:my-8 [&_hr]:border-border",
|
|
120
|
+
// Inline elements
|
|
121
|
+
"[&_strong]:font-semibold [&_strong]:text-foreground",
|
|
122
|
+
"[&_em]:italic",
|
|
123
|
+
"[&_a]:underline [&_a]:underline-offset-2 [&_a]:text-accent hover:[&_a]:text-accent/80 [&_a]:transition-colors",
|
|
124
|
+
"[&_code]:rounded [&_code]:bg-muted [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:text-sm [&_code]:font-mono",
|
|
125
|
+
"[&_pre]:my-4 [&_pre]:overflow-x-auto [&_pre]:rounded-lg [&_pre]:bg-muted [&_pre]:p-4 [&_pre]:text-sm",
|
|
126
|
+
"[&_pre>code]:bg-transparent [&_pre>code]:p-0"
|
|
127
|
+
].join(" "),
|
|
128
|
+
children: page.content && /* @__PURE__ */ jsxRuntime.jsx(
|
|
129
|
+
chunk4U6YAII5_js.ContentRenderer,
|
|
130
|
+
{
|
|
131
|
+
content: stripLeadingHeading(page.content, page.contentFormat),
|
|
132
|
+
format: (
|
|
133
|
+
// Validate before passing; unknown formats fall through to
|
|
134
|
+
// ContentRenderer's default behavior (markdown rendering)
|
|
135
|
+
// rather than getting silently force-cast to an
|
|
136
|
+
// unsupported variant.
|
|
137
|
+
page.contentFormat === "markdown" || page.contentFormat === "html" ? page.contentFormat : void 0
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
) });
|
|
143
|
+
}
|
|
144
|
+
function PartnerDocumentCard({ doc }) {
|
|
145
|
+
const sizeLabel = formatFileSize(doc.fileSize);
|
|
146
|
+
const ext = doc.fileName?.split(".").pop()?.toUpperCase();
|
|
147
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("article", { className: "flex flex-col gap-3 rounded-xl border border-border bg-card p-5 shadow-sm hover:shadow-md transition-shadow", children: [
|
|
148
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
|
|
149
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg bg-muted p-2.5 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { size: 20, className: "text-muted-foreground" }) }),
|
|
150
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
151
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-foreground truncate", children: doc.title }),
|
|
152
|
+
doc.version && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground mt-0.5", children: [
|
|
153
|
+
"Version ",
|
|
154
|
+
doc.version
|
|
155
|
+
] })
|
|
156
|
+
] })
|
|
157
|
+
] }),
|
|
158
|
+
doc.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground line-clamp-3", children: doc.description }),
|
|
159
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 mt-auto pt-2 border-t border-border/60", children: [
|
|
160
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground flex items-center gap-2", children: [
|
|
161
|
+
ext && /* @__PURE__ */ jsxRuntime.jsx("span", { children: ext }),
|
|
162
|
+
sizeLabel && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
163
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\xB7" }),
|
|
164
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: sizeLabel })
|
|
165
|
+
] })
|
|
166
|
+
] }),
|
|
167
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
168
|
+
"a",
|
|
169
|
+
{
|
|
170
|
+
href: doc.fileUrl,
|
|
171
|
+
download: doc.fileName ?? void 0,
|
|
172
|
+
onClick: (e) => void downloadDocument(e, doc),
|
|
173
|
+
className: "inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-3 py-1.5 text-sm font-medium text-foreground hover:bg-muted transition-colors",
|
|
174
|
+
children: [
|
|
175
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { size: 14 }),
|
|
176
|
+
"Download"
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
)
|
|
180
|
+
] })
|
|
181
|
+
] });
|
|
182
|
+
}
|
|
183
|
+
function PartnerDocumentsSection({
|
|
184
|
+
title,
|
|
185
|
+
subtitle,
|
|
186
|
+
docs
|
|
187
|
+
}) {
|
|
188
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12 md:py-16 bg-muted/20", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "container mx-auto px-4 max-w-5xl", children: [
|
|
189
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "mb-8 md:mb-10 text-center", children: [
|
|
190
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl md:text-3xl font-bold text-foreground mb-2", children: title }),
|
|
191
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground max-w-2xl mx-auto", children: subtitle })
|
|
192
|
+
] }),
|
|
193
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: docs.map((doc) => /* @__PURE__ */ jsxRuntime.jsx(PartnerDocumentCard, { doc }, doc.id)) })
|
|
194
|
+
] }) });
|
|
195
|
+
}
|
|
196
|
+
var DEFAULT_PARTNER_CATEGORY = {
|
|
197
|
+
value: "partnership",
|
|
198
|
+
label: "Partner program"
|
|
199
|
+
};
|
|
200
|
+
function PartnersPage(props) {
|
|
201
|
+
const {
|
|
202
|
+
productName: productNameProp,
|
|
203
|
+
heroTitle = "Partner with us",
|
|
204
|
+
heroSubtitle,
|
|
205
|
+
contentTag = "partner",
|
|
206
|
+
contentSlug,
|
|
207
|
+
documentsTag = "partner",
|
|
208
|
+
documentsTitle = "Partner Documents",
|
|
209
|
+
documentsSubtitle,
|
|
210
|
+
showContactForm = true,
|
|
211
|
+
contactCategory,
|
|
212
|
+
formTitle = "Become a partner",
|
|
213
|
+
formSubtitle,
|
|
214
|
+
contactEmail,
|
|
215
|
+
contactPhone,
|
|
216
|
+
officeAddress,
|
|
217
|
+
responseTime,
|
|
218
|
+
recaptchaSiteKey,
|
|
219
|
+
additionalOptions,
|
|
220
|
+
seoTitle,
|
|
221
|
+
seoDescription,
|
|
222
|
+
seoKeywords,
|
|
223
|
+
className
|
|
224
|
+
} = props;
|
|
225
|
+
const client = chunkJXLSTVBK_js.useWebSDK();
|
|
226
|
+
const config = chunkJXLSTVBK_js.useWebSDKConfig();
|
|
227
|
+
const { product } = chunkBYSZT35R_js.useProduct();
|
|
228
|
+
const resolvedProductId = product?.id ?? config?.productId ?? productNameProp ?? "";
|
|
229
|
+
const resolvedProductName = productNameProp ?? product?.name ?? config?.productId ?? "our team";
|
|
230
|
+
const [contentPage, setContentPage] = react.useState(null);
|
|
231
|
+
const [docs, setDocs] = react.useState([]);
|
|
232
|
+
const [loading, setLoading] = react.useState(true);
|
|
233
|
+
react.useEffect(() => {
|
|
234
|
+
if (!client || !resolvedProductId) {
|
|
235
|
+
setContentPage(null);
|
|
236
|
+
setDocs([]);
|
|
237
|
+
setLoading(false);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
let cancelled = false;
|
|
241
|
+
setLoading(true);
|
|
242
|
+
void Promise.allSettled([
|
|
243
|
+
client.query(PARTNER_CONTENT_QUERY, { productId: resolvedProductId, limit: 50 }),
|
|
244
|
+
client.query(
|
|
245
|
+
PARTNER_DOCUMENTS_QUERY,
|
|
246
|
+
{ productId: resolvedProductId, limit: 50 }
|
|
247
|
+
)
|
|
248
|
+
]).then(([contentResult, docsResult]) => {
|
|
249
|
+
if (cancelled) return;
|
|
250
|
+
if (contentResult.status === "rejected") {
|
|
251
|
+
setContentPage(null);
|
|
252
|
+
} else if (contentResult.status === "fulfilled") {
|
|
253
|
+
const items = contentResult.value.data?.publicContentPages?.items ?? [];
|
|
254
|
+
const match = contentSlug ? items.find((p) => p.slug === contentSlug) : items.find((p) => p.tags?.includes(contentTag));
|
|
255
|
+
setContentPage(match ?? null);
|
|
256
|
+
}
|
|
257
|
+
if (docsResult.status === "rejected") {
|
|
258
|
+
setDocs([]);
|
|
259
|
+
} else if (docsResult.status === "fulfilled") {
|
|
260
|
+
const items = docsResult.value.data?.publicPressKitAssets?.items ?? [];
|
|
261
|
+
const filtered = items.filter(
|
|
262
|
+
(d) => d.category === "DOCUMENT" && d.tags?.includes(documentsTag) && !!d.fileUrl
|
|
263
|
+
).sort(
|
|
264
|
+
(a, b) => a.sortOrder - b.sortOrder
|
|
265
|
+
);
|
|
266
|
+
setDocs(filtered);
|
|
267
|
+
}
|
|
268
|
+
setLoading(false);
|
|
269
|
+
});
|
|
270
|
+
return () => {
|
|
271
|
+
cancelled = true;
|
|
272
|
+
};
|
|
273
|
+
}, [client, resolvedProductId, contentSlug, contentTag, documentsTag]);
|
|
274
|
+
let partnerCategories;
|
|
275
|
+
if (contactCategory === false) {
|
|
276
|
+
partnerCategories = [];
|
|
277
|
+
} else if (Array.isArray(contactCategory)) {
|
|
278
|
+
partnerCategories = contactCategory.length > 0 ? contactCategory : [DEFAULT_PARTNER_CATEGORY];
|
|
279
|
+
} else {
|
|
280
|
+
partnerCategories = [contactCategory ?? DEFAULT_PARTNER_CATEGORY];
|
|
281
|
+
}
|
|
282
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
|
|
283
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
284
|
+
chunkUXWT7G77_js.PageHead,
|
|
285
|
+
{
|
|
286
|
+
title: seoTitle ?? `${heroTitle} \u2014 ${resolvedProductName}`,
|
|
287
|
+
description: seoDescription ?? heroSubtitle ?? `Join the ${resolvedProductName} partner programme.`,
|
|
288
|
+
keywords: seoKeywords
|
|
289
|
+
}
|
|
290
|
+
),
|
|
291
|
+
/* @__PURE__ */ jsxRuntime.jsx(PartnerHero, { title: heroTitle, subtitle: heroSubtitle }),
|
|
292
|
+
!loading && contentPage && /* @__PURE__ */ jsxRuntime.jsx(PartnerContentSection, { page: contentPage }),
|
|
293
|
+
!loading && docs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
294
|
+
PartnerDocumentsSection,
|
|
295
|
+
{
|
|
296
|
+
title: documentsTitle,
|
|
297
|
+
subtitle: documentsSubtitle,
|
|
298
|
+
docs
|
|
299
|
+
}
|
|
300
|
+
),
|
|
301
|
+
showContactForm && /* @__PURE__ */ jsxRuntime.jsx(
|
|
302
|
+
chunkAHRGFXV2_js.ContactPage,
|
|
303
|
+
{
|
|
304
|
+
productName: resolvedProductName,
|
|
305
|
+
heroTitle: formTitle,
|
|
306
|
+
headingLevel: 2,
|
|
307
|
+
heroDescription: formSubtitle ?? `Tell us about your organisation and a partner manager from ${resolvedProductName} will be in touch.`,
|
|
308
|
+
contactEmail,
|
|
309
|
+
contactPhone,
|
|
310
|
+
officeAddress,
|
|
311
|
+
responseTime,
|
|
312
|
+
recaptchaSiteKey,
|
|
313
|
+
additionalOptions,
|
|
314
|
+
categories: partnerCategories,
|
|
315
|
+
categoryLabel: "Partnership type",
|
|
316
|
+
categoryRequired: partnerCategories.length > 0
|
|
317
|
+
}
|
|
318
|
+
)
|
|
319
|
+
] });
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
exports.PartnersPage = PartnersPage;
|
|
323
|
+
exports.stripLeadingHeading = stripLeadingHeading;
|
|
324
|
+
//# sourceMappingURL=chunk-XP2JDNDU.js.map
|
|
325
|
+
//# sourceMappingURL=chunk-XP2JDNDU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/partners.tsx"],"names":["jsxs","jsx","ContentRenderer","FileText","Fragment","Download","useWebSDK","useWebSDKConfig","useProduct","useState","useEffect","PageHead","ContactPage"],"mappings":"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","file":"chunk-XP2JDNDU.js","sourcesContent":["\"use client\";\n\n/**\n * Partners Page Component\n *\n * CMS-powered public partner programme page. Composes three sources of truth\n * we already manage in the admin:\n *\n * 1. **Marketing copy** — a single `ProductContentPage` matched by `tag`\n * (default `\"partner\"`) or by `slug`. Rendered through `ContentRenderer`\n * so admins can use the full CMS editor — no hardcoded copy in this file.\n * 2. **Downloadable documents** — `ProductPressKitAsset`s with category\n * `\"DOCUMENT\"` and a matching `tag` (default `\"partner\"`). Typically the\n * Partner / Reseller Agreement PDF, deck, FAQ, etc. Self-hides when empty.\n * 3. **\"Become a partner\" contact form** — embedded `<ContactPage>` with the\n * inquiry category **locked** to `\"partnership\"` so submissions land in the\n * admin support inbox tagged for the partner-program lane (shared inbox\n * routing for v1; per-category email routing is a separate backend change).\n *\n * The page is intentionally section-based and gracefully degrades: if the\n * admin hasn't created a content page yet, only the hero + form render; if\n * no documents are uploaded, the document section disappears; if neither\n * exists, the page is just a form. This keeps the partner page useful from\n * day one without blocking on CMS data.\n *\n * Mirrors the `PressKitPage` + `BlogListPage` architecture; data fetching\n * goes through the same `WebSDKClient` GraphQL helpers everything else uses.\n *\n * @example\n * ```tsx\n * import { PartnersPage } from '@burdenoff/website-sdk'\n *\n * <Route\n * path=\"/partners\"\n * element={\n * <PartnersPage\n * productName=\"VibeControls\"\n * contactEmail=\"partnerships@vibecontrols.com\"\n * contactPhone=\"+91-XXX-XXX-XXXX\"\n * officeAddress={{ line1: \"…\", line2: \"\", line3: \"\", country: \"India\" }}\n * />\n * }\n * />\n * ```\n */\n\nimport { useEffect, useState } from \"react\";\n\nimport { Download, FileText } from \"lucide-react\";\n\nimport { ContactPage } from \"./contact\";\nimport { useWebSDK, useWebSDKConfig } from \"../client/provider\";\nimport { ContentRenderer } from \"../content/content-provider\";\nimport { useProduct } from \"../product/product-provider\";\nimport { PageHead } from \"../seo/page-head\";\n\nimport type { ContactCategory, ContactPageProps } from \"./contact\";\nimport type { ContentPageListItem } from \"../content/content-provider\";\n\n/**\n * Office address shape consumed by `<ContactPage>`. Mirrored here as a\n * local type so we don't widen `contact.tsx`'s public surface just for\n * this consumer — keeps the contact module's exports unchanged.\n */\ninterface OfficeAddress {\n line1: string;\n line2: string;\n line3: string;\n country: string;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A downloadable document surfaced on the partners page. Same shape as\n * `PressKitAsset` but only the fields the card uses — keeps the type\n * surface tight and avoids a cross-file import of the press-kit type.\n */\ninterface PartnerDocument {\n id: string;\n category: string;\n title: string;\n description?: string | null;\n fileUrl: string;\n fileName?: string | null;\n fileSize?: number | null;\n mimeType?: string | null;\n version?: string | null;\n tags: string[];\n sortOrder: number;\n updatedAt: string;\n}\n\nexport interface PartnersPageProps {\n /** Product name (e.g. `\"VibeControls\"`). Falls back to SDK config. */\n productName?: string;\n\n // ── Hero ─────────────────────────────────────────────────────────────\n /** Hero headline. Default: `\"Partner with us\"`. */\n heroTitle?: string;\n /** Hero subtitle / pitch line. */\n heroSubtitle?: string;\n\n // ── CMS marketing copy section ───────────────────────────────────────\n /**\n * Tag filter for the marketing-copy body. Default: `\"partner\"`. The\n * component fetches the FIRST published `ProductContentPage` whose\n * tags array contains this tag and renders its body via\n * `ContentRenderer`. Self-hides if none exist.\n */\n contentTag?: string;\n /**\n * Pin a specific content page by slug. If set, overrides `contentTag`.\n * Useful when multiple partner pages exist and you want to render one\n * canonical version per route.\n */\n contentSlug?: string;\n\n // ── Documents section ────────────────────────────────────────────────\n /**\n * Tag filter for the downloadable documents. Default: `\"partner\"`.\n * Combined with the implicit `category === \"DOCUMENT\"` filter — only\n * Press Kit assets that match BOTH are rendered as cards. Self-hides\n * when empty.\n */\n documentsTag?: string;\n /** Documents-section heading. Default: `\"Partner Documents\"`. */\n documentsTitle?: string;\n /** Documents-section subtitle / lead. */\n documentsSubtitle?: string;\n\n // ── Contact form section ─────────────────────────────────────────────\n /**\n * Whether to render the \"Become a partner\" contact form. Default: `true`.\n * Set to `false` for a documents-only / read-only partner landing page.\n */\n showContactForm?: boolean;\n /**\n * Inquiry-category options for the embedded `<ContactPage>` dropdown.\n * Default: `{ value: \"partnership\", label: \"Partner program\" }` (a single,\n * required option so every submission is tagged for partner triage). Pass an\n * **array** to offer multiple selectable partner tracks (Referral, Reseller,\n * MSP, …). Pass `false` to disable the dropdown entirely.\n */\n contactCategory?: ContactCategory | ContactCategory[] | false;\n /** Heading shown above the form. Default: `\"Become a partner\"`. */\n formTitle?: string;\n /** Subtitle / lead above the form. */\n formSubtitle?: string;\n\n // ── Contact-form passthroughs (required for <ContactPage>) ───────────\n contactEmail: string;\n contactPhone: string;\n officeAddress: OfficeAddress;\n responseTime?: string;\n recaptchaSiteKey?: string;\n /** Forwarded to `<ContactPage additionalOptions>`. */\n additionalOptions?: ContactPageProps[\"additionalOptions\"];\n\n // ── SEO ──────────────────────────────────────────────────────────────\n seoTitle?: string;\n seoDescription?: string;\n seoKeywords?: string;\n\n className?: string;\n}\n\n// ============================================================================\n// Queries\n// ============================================================================\n\nconst PARTNER_CONTENT_QUERY = `\n query PartnerContent($productId: String!, $limit: Int) {\n publicContentPages(productId: $productId, limit: $limit, offset: 0) {\n items {\n id\n title\n slug\n excerpt\n content\n contentFormat\n thumbnail\n tags\n publishedAt\n lastUpdated\n }\n }\n }\n`;\n\nconst PARTNER_DOCUMENTS_QUERY = `\n query PartnerDocuments($productId: String!, $limit: Int) {\n publicPressKitAssets(productId: $productId, limit: $limit, offset: 0) {\n items {\n id\n category\n title\n description\n fileUrl\n fileName\n fileSize\n mimeType\n version\n tags\n sortOrder\n updatedAt\n }\n }\n }\n`;\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction formatFileSize(bytes: number | null | undefined): string {\n if (!bytes || bytes <= 0) return \"\";\n const units = [\"B\", \"KB\", \"MB\", \"GB\"];\n let i = 0;\n let n = bytes;\n while (n >= 1024 && i < units.length - 1) {\n n /= 1024;\n i++;\n }\n return `${n.toFixed(n >= 10 || i === 0 ? 0 : 1)} ${units[i]}`;\n}\n\n/**\n * Download an asset as a file (vs opening in a tab). Same blob-fetch\n * pattern as press-kit `downloadAsset` — works wherever the bucket\n * allows cross-origin GET (verified for dev/alpha/prod presskit\n * buckets, 2026-05-20).\n */\nasync function downloadDocument(\n e: { preventDefault: () => void },\n doc: PartnerDocument,\n): Promise<void> {\n e.preventDefault();\n const name =\n doc.fileName ||\n doc.fileUrl.split(\"/\").pop()?.split(\"?\")[0] ||\n doc.title ||\n \"partner-document\";\n const openInTab = () =>\n window.open(doc.fileUrl, \"_blank\", \"noopener,noreferrer\");\n try {\n const res = await fetch(doc.fileUrl, { mode: \"cors\" });\n if (!res.ok) {\n openInTab();\n return;\n }\n const blob = await res.blob();\n const objUrl = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = objUrl;\n a.download = name;\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(objUrl);\n } catch {\n openInTab();\n }\n}\n\n// ============================================================================\n// Sub-components\n// ============================================================================\n\nfunction PartnerHero({\n title,\n subtitle,\n}: {\n title: string;\n subtitle?: string;\n}) {\n return (\n <section className=\"bg-gradient-to-b from-background to-muted/20 py-16 md:py-24\">\n <div className=\"container mx-auto px-4 max-w-4xl text-center\">\n <h1 className=\"text-4xl md:text-5xl font-bold tracking-tight text-foreground mb-4\">\n {title}\n </h1>\n {subtitle && (\n <p className=\"text-lg md:text-xl text-muted-foreground max-w-2xl mx-auto\">\n {subtitle}\n </p>\n )}\n </div>\n </section>\n );\n}\n\n/**\n * Strip a single leading top-level heading from CMS body content. The\n * `PartnerHero` already renders the page title, so a content body that also\n * opens with `# Title` (the natural way an author writes a page) would print\n * the title twice. Removing the body's leading heading keeps one visible\n * title and one `<h1>` per page. Only the *first* heading is touched — all\n * section headings below it are preserved.\n *\n * Exported for unit testing only; not re-exported from the package barrel.\n */\nexport function stripLeadingHeading(content: string, format?: string): string {\n if (format === \"html\") {\n return content.replace(/^\\s*<h1\\b[^>]*>[\\s\\S]*?<\\/h1>\\s*/i, \"\");\n }\n // markdown (default): drop a leading \"# Heading\" line + any trailing blanks.\n // Trailing newlines are optional (`*`, not `+`) so a body that is only\n // \"# Title\" with no trailing newline — common after editor/API trimming —\n // still gets stripped. `#\\s+` matches H1 only; `## Section` is left intact.\n return content.replace(/^\\s*#\\s+.*(?:\\r?\\n)*/, \"\");\n}\n\nfunction PartnerContentSection({\n page,\n}: {\n page: ContentPageListItem & { content?: string; contentFormat?: string };\n}) {\n // Restore typography for the markdown-rendered HTML — Tailwind preflight\n // strips browser defaults, and we don't want to assume consumer sites have\n // `@tailwindcss/typography` installed. Arbitrary-children selectors keep\n // this portable to every product website that consumes the SDK.\n return (\n <section className=\"py-12 md:py-16\">\n <div\n className={[\n \"mx-auto max-w-3xl px-4\",\n // Headings\n \"[&_h1]:text-3xl [&_h1]:font-bold [&_h1]:tracking-tight [&_h1]:mt-0 [&_h1]:mb-6\",\n \"[&_h2]:text-2xl [&_h2]:font-bold [&_h2]:tracking-tight [&_h2]:mt-10 [&_h2]:mb-4\",\n \"[&_h3]:text-xl [&_h3]:font-semibold [&_h3]:mt-7 [&_h3]:mb-3\",\n \"[&_h4]:text-lg [&_h4]:font-semibold [&_h4]:mt-6 [&_h4]:mb-2\",\n // Block elements\n \"[&_p]:my-4 [&_p]:leading-relaxed [&_p]:text-base\",\n \"[&_ul]:my-4 [&_ul]:pl-6 [&_ul]:list-disc [&_ul]:space-y-1\",\n \"[&_ol]:my-4 [&_ol]:pl-6 [&_ol]:list-decimal [&_ol]:space-y-1\",\n \"[&_li]:leading-relaxed\",\n \"[&_li>p]:my-1\",\n \"[&_blockquote]:border-l-4 [&_blockquote]:border-border [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:my-4 [&_blockquote]:text-muted-foreground\",\n \"[&_hr]:my-8 [&_hr]:border-border\",\n // Inline elements\n \"[&_strong]:font-semibold [&_strong]:text-foreground\",\n \"[&_em]:italic\",\n \"[&_a]:underline [&_a]:underline-offset-2 [&_a]:text-accent hover:[&_a]:text-accent/80 [&_a]:transition-colors\",\n \"[&_code]:rounded [&_code]:bg-muted [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:text-sm [&_code]:font-mono\",\n \"[&_pre]:my-4 [&_pre]:overflow-x-auto [&_pre]:rounded-lg [&_pre]:bg-muted [&_pre]:p-4 [&_pre]:text-sm\",\n \"[&_pre>code]:bg-transparent [&_pre>code]:p-0\",\n ].join(\" \")}\n >\n {page.content && (\n <ContentRenderer\n content={stripLeadingHeading(page.content, page.contentFormat)}\n format={\n // Validate before passing; unknown formats fall through to\n // ContentRenderer's default behavior (markdown rendering)\n // rather than getting silently force-cast to an\n // unsupported variant.\n page.contentFormat === \"markdown\" || page.contentFormat === \"html\"\n ? page.contentFormat\n : undefined\n }\n />\n )}\n </div>\n </section>\n );\n}\n\nfunction PartnerDocumentCard({ doc }: { doc: PartnerDocument }) {\n const sizeLabel = formatFileSize(doc.fileSize);\n const ext = doc.fileName?.split(\".\").pop()?.toUpperCase();\n return (\n <article className=\"flex flex-col gap-3 rounded-xl border border-border bg-card p-5 shadow-sm hover:shadow-md transition-shadow\">\n <div className=\"flex items-start gap-3\">\n <div className=\"rounded-lg bg-muted p-2.5 shrink-0\">\n <FileText size={20} className=\"text-muted-foreground\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"font-semibold text-foreground truncate\">\n {doc.title}\n </h3>\n {doc.version && (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Version {doc.version}\n </p>\n )}\n </div>\n </div>\n {doc.description && (\n <p className=\"text-sm text-muted-foreground line-clamp-3\">\n {doc.description}\n </p>\n )}\n <div className=\"flex items-center justify-between gap-3 mt-auto pt-2 border-t border-border/60\">\n <div className=\"text-xs text-muted-foreground flex items-center gap-2\">\n {ext && <span>{ext}</span>}\n {sizeLabel && (\n <>\n <span aria-hidden>·</span>\n <span>{sizeLabel}</span>\n </>\n )}\n </div>\n <a\n href={doc.fileUrl}\n download={doc.fileName ?? undefined}\n onClick={(e) => void downloadDocument(e, doc)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-3 py-1.5 text-sm font-medium text-foreground hover:bg-muted transition-colors\"\n >\n <Download size={14} />\n Download\n </a>\n </div>\n </article>\n );\n}\n\nfunction PartnerDocumentsSection({\n title,\n subtitle,\n docs,\n}: {\n title: string;\n subtitle?: string;\n docs: PartnerDocument[];\n}) {\n return (\n <section className=\"py-12 md:py-16 bg-muted/20\">\n <div className=\"container mx-auto px-4 max-w-5xl\">\n <header className=\"mb-8 md:mb-10 text-center\">\n <h2 className=\"text-2xl md:text-3xl font-bold text-foreground mb-2\">\n {title}\n </h2>\n {subtitle && (\n <p className=\"text-muted-foreground max-w-2xl mx-auto\">\n {subtitle}\n </p>\n )}\n </header>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {docs.map((doc) => (\n <PartnerDocumentCard key={doc.id} doc={doc} />\n ))}\n </div>\n </div>\n </section>\n );\n}\n\n// ============================================================================\n// Main component\n// ============================================================================\n\nconst DEFAULT_PARTNER_CATEGORY: ContactCategory = {\n value: \"partnership\",\n label: \"Partner program\",\n};\n\nexport function PartnersPage(props: PartnersPageProps) {\n const {\n productName: productNameProp,\n heroTitle = \"Partner with us\",\n heroSubtitle,\n\n contentTag = \"partner\",\n contentSlug,\n\n documentsTag = \"partner\",\n documentsTitle = \"Partner Documents\",\n documentsSubtitle,\n\n showContactForm = true,\n contactCategory,\n formTitle = \"Become a partner\",\n formSubtitle,\n\n contactEmail,\n contactPhone,\n officeAddress,\n responseTime,\n recaptchaSiteKey,\n additionalOptions,\n\n seoTitle,\n seoDescription,\n seoKeywords,\n className,\n } = props;\n\n const client = useWebSDK();\n const config = useWebSDKConfig();\n const { product } = useProduct();\n\n const resolvedProductId =\n product?.id ?? config?.productId ?? productNameProp ?? \"\";\n const resolvedProductName =\n productNameProp ?? product?.name ?? config?.productId ?? \"our team\";\n\n const [contentPage, setContentPage] = useState<\n (ContentPageListItem & { content?: string; contentFormat?: string }) | null\n >(null);\n const [docs, setDocs] = useState<PartnerDocument[]>([]);\n const [loading, setLoading] = useState<boolean>(true);\n\n // Single fetch on mount/productId-change — small payloads, no pagination needed\n // on a partners page (one content body + a handful of docs at most).\n useEffect(() => {\n if (!client || !resolvedProductId) {\n // Reset section state when the product scope unsets (e.g. provider re-\n // resolution between routes). Without this, the page would keep\n // rendering the previous product's content + docs because the render\n // guards only check `!loading` plus existing state.\n setContentPage(null);\n setDocs([]);\n setLoading(false);\n return;\n }\n let cancelled = false;\n setLoading(true);\n\n void Promise.allSettled([\n client.query<{\n publicContentPages: {\n items: (ContentPageListItem & {\n content?: string;\n contentFormat?: string;\n })[];\n };\n }>(PARTNER_CONTENT_QUERY, { productId: resolvedProductId, limit: 50 }),\n client.query<{ publicPressKitAssets: { items: PartnerDocument[] } }>(\n PARTNER_DOCUMENTS_QUERY,\n { productId: resolvedProductId, limit: 50 },\n ),\n ]).then(([contentResult, docsResult]) => {\n if (cancelled) return;\n\n // Content page — match by slug if given, else first item carrying the tag.\n // Clear the previous match on a rejected request so stale data from an\n // earlier product / tag doesn't linger on screen across navigations.\n if (contentResult.status === \"rejected\") {\n setContentPage(null);\n } else if (contentResult.status === \"fulfilled\") {\n type ContentItem = ContentPageListItem & {\n content?: string;\n contentFormat?: string;\n };\n const items: ContentItem[] =\n contentResult.value.data?.publicContentPages?.items ?? [];\n const match: ContentItem | undefined = contentSlug\n ? items.find((p: ContentItem) => p.slug === contentSlug)\n : items.find((p: ContentItem) => p.tags?.includes(contentTag));\n setContentPage(match ?? null);\n }\n\n // Documents — only category === \"DOCUMENT\" AND tag matches AND has a fileUrl.\n // Same stale-clear behavior as the content section above.\n if (docsResult.status === \"rejected\") {\n setDocs([]);\n } else if (docsResult.status === \"fulfilled\") {\n const items: PartnerDocument[] =\n docsResult.value.data?.publicPressKitAssets?.items ?? [];\n const filtered = items\n .filter(\n (d: PartnerDocument) =>\n d.category === \"DOCUMENT\" &&\n d.tags?.includes(documentsTag) &&\n !!d.fileUrl,\n )\n .sort(\n (a: PartnerDocument, b: PartnerDocument) =>\n a.sortOrder - b.sortOrder,\n );\n setDocs(filtered);\n }\n\n setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [client, resolvedProductId, contentSlug, contentTag, documentsTag]);\n\n // Normalise the contact-category options for the dropdown:\n // - `false` → no dropdown (explicitly disabled)\n // - a non-empty array → those partner tracks\n // - a single value → that one option\n // - unset OR `[]` → the default partner category\n // An empty array is treated as \"use the default\", not \"disable\" — so an\n // accidental `contactCategory={[]}` doesn't silently drop the dropdown; pass\n // `false` to disable it intentionally.\n let partnerCategories: ContactCategory[];\n if (contactCategory === false) {\n partnerCategories = [];\n } else if (Array.isArray(contactCategory)) {\n partnerCategories =\n contactCategory.length > 0 ? contactCategory : [DEFAULT_PARTNER_CATEGORY];\n } else {\n partnerCategories = [contactCategory ?? DEFAULT_PARTNER_CATEGORY];\n }\n\n return (\n <div className={className}>\n <PageHead\n title={seoTitle ?? `${heroTitle} — ${resolvedProductName}`}\n description={\n seoDescription ??\n heroSubtitle ??\n `Join the ${resolvedProductName} partner programme.`\n }\n keywords={seoKeywords}\n />\n\n <PartnerHero title={heroTitle} subtitle={heroSubtitle} />\n\n {!loading && contentPage && <PartnerContentSection page={contentPage} />}\n\n {!loading && docs.length > 0 && (\n <PartnerDocumentsSection\n title={documentsTitle}\n subtitle={documentsSubtitle}\n docs={docs}\n />\n )}\n\n {showContactForm && (\n <ContactPage\n productName={resolvedProductName}\n heroTitle={formTitle}\n // Embedded inside PartnersPage, which already owns the page <h1>.\n // Render the form's \"Become a partner\" as an <h2> section header so\n // there's a single <h1> per page and no competing full-size hero.\n headingLevel={2}\n heroDescription={\n formSubtitle ??\n `Tell us about your organisation and a partner manager from ${resolvedProductName} will be in touch.`\n }\n contactEmail={contactEmail}\n contactPhone={contactPhone}\n officeAddress={officeAddress}\n responseTime={responseTime}\n recaptchaSiteKey={recaptchaSiteKey}\n additionalOptions={additionalOptions}\n // Partnership-type dropdown: one or more partner tracks so every\n // submission is tagged for the partner-program lane. Skipped when the\n // consumer passes `false`.\n categories={partnerCategories}\n categoryLabel=\"Partnership type\"\n categoryRequired={partnerCategories.length > 0}\n />\n )}\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { cn } from './chunk-R7G6TWIS.mjs';
|
|
2
|
+
import { forwardRef, useState, useEffect } from 'react';
|
|
3
|
+
import { Sparkles } from 'lucide-react';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
function useCurrentPath(explicit) {
|
|
7
|
+
const [path, setPath] = useState(explicit ?? null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (explicit !== void 0) {
|
|
10
|
+
setPath(explicit);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (typeof window === "undefined") return;
|
|
14
|
+
const read = () => setPath(window.location.pathname);
|
|
15
|
+
read();
|
|
16
|
+
window.addEventListener("popstate", read);
|
|
17
|
+
return () => window.removeEventListener("popstate", read);
|
|
18
|
+
}, [explicit]);
|
|
19
|
+
return path;
|
|
20
|
+
}
|
|
21
|
+
function samePath(a, b) {
|
|
22
|
+
if (!a) return false;
|
|
23
|
+
const norm = (v) => v.length > 1 ? v.replace(/\/+$/, "") : v;
|
|
24
|
+
return norm(a) === norm(b);
|
|
25
|
+
}
|
|
26
|
+
var ExploreCta = forwardRef(
|
|
27
|
+
function ExploreCta2({
|
|
28
|
+
variant,
|
|
29
|
+
href = "/explore",
|
|
30
|
+
label = "Ask AI",
|
|
31
|
+
className,
|
|
32
|
+
onNavigate,
|
|
33
|
+
onClick,
|
|
34
|
+
currentPath,
|
|
35
|
+
expanded,
|
|
36
|
+
controls
|
|
37
|
+
}, ref) {
|
|
38
|
+
const path = useCurrentPath(currentPath);
|
|
39
|
+
const isActive = samePath(path, href);
|
|
40
|
+
if (variant === "floating" && isActive) return null;
|
|
41
|
+
const handleClick = (event) => {
|
|
42
|
+
onClick?.();
|
|
43
|
+
if (!onNavigate) return;
|
|
44
|
+
if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
onNavigate(href);
|
|
49
|
+
};
|
|
50
|
+
const classes = {
|
|
51
|
+
// A quiet icon control, deliberately NOT a second gradient pill: a header should carry one
|
|
52
|
+
// primary CTA ("Get started"), and a competing coloured button next to it reads as clutter.
|
|
53
|
+
// This matches the theme toggle's visual weight, so the row scans as [utilities] [CTA].
|
|
54
|
+
// The prominent, labelled entry point to /explore is the floating bubble, which is visible
|
|
55
|
+
// on every page without scrolling. `shrink-0` keeps it from squeezing the nav.
|
|
56
|
+
header: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
57
|
+
mobile: "inline-flex w-full items-center gap-2 rounded-lg border border-border bg-card px-3 py-2 text-sm font-medium text-card-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
58
|
+
floating: "fixed bottom-5 right-5 z-40 inline-flex items-center gap-2 rounded-full bg-gradient-to-r from-primary to-primary/70 px-4 py-3 text-sm font-medium text-primary-foreground shadow-lg transition-opacity hover:opacity-90"
|
|
59
|
+
};
|
|
60
|
+
const hooks = {
|
|
61
|
+
header: "cta-header",
|
|
62
|
+
mobile: "cta-mobile",
|
|
63
|
+
floating: "cta-floating"
|
|
64
|
+
};
|
|
65
|
+
return /* @__PURE__ */ jsxs(
|
|
66
|
+
"a",
|
|
67
|
+
{
|
|
68
|
+
ref,
|
|
69
|
+
"data-boff-explore": hooks[variant],
|
|
70
|
+
href,
|
|
71
|
+
onClick: handleClick,
|
|
72
|
+
"aria-label": label,
|
|
73
|
+
"aria-current": isActive ? "page" : void 0,
|
|
74
|
+
"aria-expanded": expanded,
|
|
75
|
+
"aria-haspopup": expanded === void 0 ? void 0 : "dialog",
|
|
76
|
+
"aria-controls": expanded === void 0 ? void 0 : controls,
|
|
77
|
+
className: cn(
|
|
78
|
+
classes[variant],
|
|
79
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
80
|
+
className
|
|
81
|
+
),
|
|
82
|
+
children: [
|
|
83
|
+
/* @__PURE__ */ jsx(
|
|
84
|
+
Sparkles,
|
|
85
|
+
{
|
|
86
|
+
className: cn(
|
|
87
|
+
"shrink-0",
|
|
88
|
+
variant === "floating" ? "h-4 w-4" : variant === "header" ? "h-5 w-5" : "h-3.5 w-3.5"
|
|
89
|
+
),
|
|
90
|
+
"aria-hidden": "true"
|
|
91
|
+
}
|
|
92
|
+
),
|
|
93
|
+
/* @__PURE__ */ jsx(
|
|
94
|
+
"span",
|
|
95
|
+
{
|
|
96
|
+
className: cn(
|
|
97
|
+
variant === "floating" && "hidden sm:inline",
|
|
98
|
+
// Never labelled in the header — see the class comment above.
|
|
99
|
+
variant === "header" && "hidden"
|
|
100
|
+
),
|
|
101
|
+
children: label
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
export { ExploreCta };
|
|
111
|
+
//# sourceMappingURL=chunk-Y4V5CEWD.mjs.map
|
|
112
|
+
//# sourceMappingURL=chunk-Y4V5CEWD.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/explore-cta.tsx"],"names":["ExploreCta"],"mappings":"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","file":"chunk-Y4V5CEWD.mjs","sourcesContent":["/**\n * ExploreCta — the entry point to `/explore` from a site's navigation.\n *\n * Three shapes of the same link, so a product site can place it once in the\n * desktop header, once in the mobile menu, and optionally as a floating bubble\n * on content pages, without any of them re-implementing the styling:\n *\n * - `header` — a gradient sparkle pill for the desktop nav.\n * - `mobile` — a compact full-width row for a mobile menu list.\n * - `floating` — a fixed bottom-right bubble; hides itself on `/explore`\n * so it never covers the page it links to.\n *\n * Import from the package ROOT (`@burdenoff/website-sdk`) for consistency with\n * `ExplorePage`, which must be root-imported because of tsup's\n * `splitting: false`. This component holds no context of its own, so a\n * sub-path import also works — but keeping both on the root import is one less\n * footgun for the 38 sites that ship them together.\n *\n * @example\n * ```tsx\n * import { ExploreCta } from '@burdenoff/website-sdk'\n *\n * <ExploreCta variant=\"header\" onNavigate={(href) => navigate(href)} />\n * <ExploreCta variant=\"floating\" currentPath={location.pathname} />\n * ```\n */\n\"use client\";\n\nimport { forwardRef, useEffect, useState } from \"react\";\n\nimport { Sparkles } from \"lucide-react\";\n\nimport { cn } from \"../utils/cn\";\n\nexport interface ExploreCtaProps {\n /** Which of the three presentations to render. */\n variant: \"header\" | \"mobile\" | \"floating\";\n /** Target route. Default `/explore`. */\n href?: string;\n /** Visible label / accessible name. Default `Ask AI`. */\n label?: string;\n /** Extra classes for the rendered element. */\n className?: string;\n /** SPA navigation. When omitted the component renders a plain `<a href>`. */\n onNavigate?: (href: string) => void;\n /** Extra click handler (analytics, closing a mobile menu, …). */\n onClick?: () => void;\n /**\n * Current route, when the host knows it (`useLocation().pathname`).\n * Used to mark the link as `aria-current=\"page\"` and to hide the floating\n * bubble on the Explore page itself. Falls back to `window.location.pathname`,\n * which cannot observe SPA `pushState` navigations on its own.\n */\n currentPath?: string;\n /**\n * BOFF-9697. For a host whose floating button opens the site-wide assistant panel (`ExplorePanel`) instead of\n * navigating: whether that panel is open. When set, the link also says it opens a dialog (`aria-haspopup`) and\n * which one (`controls`). Unset (every other site): the link renders exactly as before.\n */\n expanded?: boolean;\n /** BOFF-9697. The id of the panel the button opens; used only together with `expanded`. */\n controls?: string;\n}\n\n/**\n * Resolve the active path without breaking SSR/prerender: the first render\n * always returns `null` (matching the server output), and the real value lands\n * in an effect. `popstate` covers back/forward; hosts that navigate with\n * `pushState` should pass `currentPath` from their router.\n */\nfunction useCurrentPath(explicit?: string): string | null {\n const [path, setPath] = useState<string | null>(explicit ?? null);\n\n useEffect(() => {\n if (explicit !== undefined) {\n setPath(explicit);\n return;\n }\n if (typeof window === \"undefined\") return;\n const read = () => setPath(window.location.pathname);\n read();\n window.addEventListener(\"popstate\", read);\n return () => window.removeEventListener(\"popstate\", read);\n }, [explicit]);\n\n return path;\n}\n\n/** `/explore` and `/explore/` are the same page. */\nfunction samePath(a: string | null, b: string): boolean {\n if (!a) return false;\n const norm = (v: string) => (v.length > 1 ? v.replace(/\\/+$/, \"\") : v);\n return norm(a) === norm(b);\n}\n\n/** The rendered `<a>` is forwarded, so a panel can return focus to the button that opened it (BOFF-9697). */\nexport const ExploreCta = forwardRef<HTMLAnchorElement, ExploreCtaProps>(\n function ExploreCta(\n {\n variant,\n href = \"/explore\",\n label = \"Ask AI\",\n className,\n onNavigate,\n onClick,\n currentPath,\n expanded,\n controls,\n },\n ref,\n ) {\n const path = useCurrentPath(currentPath);\n const isActive = samePath(path, href);\n\n // The floating bubble exists to get visitors TO /explore. On /explore it is\n // pure obstruction, so it removes itself.\n if (variant === \"floating\" && isActive) return null;\n\n const handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {\n onClick?.();\n if (!onNavigate) return;\n // Let the browser handle modified clicks (new tab, download, …).\n if (\n event.defaultPrevented ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.altKey ||\n event.button !== 0\n ) {\n return;\n }\n event.preventDefault();\n onNavigate(href);\n };\n\n const classes: Record<ExploreCtaProps[\"variant\"], string> = {\n // A quiet icon control, deliberately NOT a second gradient pill: a header should carry one\n // primary CTA (\"Get started\"), and a competing coloured button next to it reads as clutter.\n // This matches the theme toggle's visual weight, so the row scans as [utilities] [CTA].\n // The prominent, labelled entry point to /explore is the floating bubble, which is visible\n // on every page without scrolling. `shrink-0` keeps it from squeezing the nav.\n header:\n \"inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground\",\n mobile:\n \"inline-flex w-full items-center gap-2 rounded-lg border border-border bg-card px-3 py-2 text-sm font-medium text-card-foreground transition-colors hover:bg-accent hover:text-accent-foreground\",\n floating:\n \"fixed bottom-5 right-5 z-40 inline-flex items-center gap-2 rounded-full bg-gradient-to-r from-primary to-primary/70 px-4 py-3 text-sm font-medium text-primary-foreground shadow-lg transition-opacity hover:opacity-90\",\n };\n\n const hooks: Record<ExploreCtaProps[\"variant\"], string> = {\n header: \"cta-header\",\n mobile: \"cta-mobile\",\n floating: \"cta-floating\",\n };\n\n return (\n <a\n ref={ref}\n data-boff-explore={hooks[variant]}\n href={href}\n onClick={handleClick}\n aria-label={label}\n aria-current={isActive ? \"page\" : undefined}\n aria-expanded={expanded}\n aria-haspopup={expanded === undefined ? undefined : \"dialog\"}\n aria-controls={expanded === undefined ? undefined : controls}\n className={cn(\n classes[variant],\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n className,\n )}\n >\n <Sparkles\n className={cn(\n \"shrink-0\",\n variant === \"floating\"\n ? \"h-4 w-4\"\n : variant === \"header\"\n ? \"h-5 w-5\"\n : \"h-3.5 w-3.5\",\n )}\n aria-hidden=\"true\"\n />\n {/* The icon alone carries the affordance where space is tight; `aria-label` carries\n the accessible name at every width, so hiding the text costs nothing to a\n screen reader. Floating shows its label from `sm` up, header from `2xl`. */}\n <span\n className={cn(\n variant === \"floating\" && \"hidden sm:inline\",\n // Never labelled in the header — see the class comment above.\n variant === \"header\" && \"hidden\",\n )}\n >\n {label}\n </span>\n </a>\n );\n },\n);\n"]}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkBYSZT35R_js = require('./chunk-BYSZT35R.js');
|
|
4
|
+
var lucideReact = require('lucide-react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
function DiscordIcon({ className }) {
|
|
8
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9
|
+
"svg",
|
|
10
|
+
{
|
|
11
|
+
role: "img",
|
|
12
|
+
viewBox: "0 0 24 24",
|
|
13
|
+
fill: "currentColor",
|
|
14
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
15
|
+
className,
|
|
16
|
+
"aria-hidden": "true",
|
|
17
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20.317 4.369A19.79 19.79 0 0 0 16.558 3a.075.075 0 0 0-.079.037c-.34.6-.717 1.382-.98 1.99a18.27 18.27 0 0 0-5.998 0 12.51 12.51 0 0 0-.99-1.99.077.077 0 0 0-.079-.037 19.74 19.74 0 0 0-3.76 1.369.07.07 0 0 0-.032.028C.533 8.045-.32 11.6.099 15.114a.082.082 0 0 0 .031.056 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.027 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.105 13.1 13.1 0 0 1-1.872-.892.077.077 0 0 1-.008-.128c.126-.094.252-.192.372-.291a.074.074 0 0 1 .078-.01c3.927 1.793 8.18 1.793 12.061 0a.074.074 0 0 1 .079.009c.12.099.246.198.372.292a.077.077 0 0 1-.006.127 12.3 12.3 0 0 1-1.873.892.077.077 0 0 0-.041.106c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.84 19.84 0 0 0 6.002-3.03.077.077 0 0 0 .032-.055c.5-4.063-.838-7.587-3.549-10.717a.061.061 0 0 0-.031-.028zM8.02 13.001c-1.182 0-2.157-1.085-2.157-2.419 0-1.333.956-2.418 2.157-2.418 1.21 0 2.176 1.094 2.157 2.418 0 1.334-.956 2.419-2.157 2.419zm7.974 0c-1.182 0-2.157-1.085-2.157-2.419 0-1.333.956-2.418 2.157-2.418 1.21 0 2.176 1.094 2.157 2.418 0 1.334-.946 2.419-2.157 2.419z" })
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function PinterestIcon({ className }) {
|
|
22
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
23
|
+
"svg",
|
|
24
|
+
{
|
|
25
|
+
role: "img",
|
|
26
|
+
viewBox: "0 0 24 24",
|
|
27
|
+
fill: "currentColor",
|
|
28
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
29
|
+
className,
|
|
30
|
+
"aria-hidden": "true",
|
|
31
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.162-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.663.967-2.911 2.168-2.911 1.024 0 1.518.769 1.518 1.688 0 1.029-.653 2.567-.992 3.992-.285 1.193.6 2.165 1.775 2.165 2.128 0 3.768-2.245 3.768-5.487 0-2.861-2.063-4.869-5.008-4.869-3.41 0-5.409 2.562-5.409 5.199 0 1.033.394 2.143.889 2.741.099.12.112.225.085.345-.09.375-.293 1.199-.334 1.363-.053.225-.172.271-.401.165-1.495-.69-2.433-2.878-2.433-4.646 0-3.776 2.748-7.252 7.92-7.252 4.158 0 7.392 2.967 7.392 6.923 0 4.135-2.607 7.462-6.233 7.462-1.214 0-2.357-.629-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12.017 24c6.624 0 11.99-5.367 11.99-11.987C24.007 5.367 18.641 0 12.017 0z" })
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
var PLATFORMS = {
|
|
36
|
+
twitter: { Icon: lucideReact.Twitter, label: "Twitter / X", aliases: ["x"] },
|
|
37
|
+
linkedin: { Icon: lucideReact.Linkedin, label: "LinkedIn" },
|
|
38
|
+
github: { Icon: lucideReact.Github, label: "GitHub" },
|
|
39
|
+
facebook: { Icon: lucideReact.Facebook, label: "Facebook" },
|
|
40
|
+
youtube: { Icon: lucideReact.Youtube, label: "YouTube" },
|
|
41
|
+
instagram: { Icon: lucideReact.Instagram, label: "Instagram" },
|
|
42
|
+
discord: { Icon: DiscordIcon, label: "Discord" },
|
|
43
|
+
pinterest: { Icon: PinterestIcon, label: "Pinterest" }
|
|
44
|
+
};
|
|
45
|
+
var KEY_TO_PLATFORM = (() => {
|
|
46
|
+
const map = {};
|
|
47
|
+
for (const [key, def] of Object.entries(PLATFORMS)) {
|
|
48
|
+
map[key] = key;
|
|
49
|
+
for (const alias of def.aliases ?? []) {
|
|
50
|
+
map[alias] = key;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return map;
|
|
54
|
+
})();
|
|
55
|
+
var DEFAULT_ITEM_CLASS = "text-muted-foreground hover:text-foreground transition-colors";
|
|
56
|
+
function isSafeUrl(value) {
|
|
57
|
+
const trimmed = value.trim();
|
|
58
|
+
if (/^[/?#]/.test(trimmed)) return true;
|
|
59
|
+
return /^(https?:|mailto:|tel:)/i.test(trimmed);
|
|
60
|
+
}
|
|
61
|
+
function SocialLinks({
|
|
62
|
+
links: linksProp,
|
|
63
|
+
email: emailProp,
|
|
64
|
+
platforms: platformAllow,
|
|
65
|
+
showEmail,
|
|
66
|
+
iconClassName = "h-5 w-5",
|
|
67
|
+
itemClassName = DEFAULT_ITEM_CLASS,
|
|
68
|
+
className = "flex space-x-4"
|
|
69
|
+
}) {
|
|
70
|
+
const { product } = chunkBYSZT35R_js.useProduct();
|
|
71
|
+
const links = linksProp ?? product?.socialLinks ?? {};
|
|
72
|
+
const email = emailProp !== void 0 ? emailProp : product?.contactEmail ?? null;
|
|
73
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
74
|
+
for (const [rawKey, url] of Object.entries(links)) {
|
|
75
|
+
if (!url || typeof url !== "string") continue;
|
|
76
|
+
if (!isSafeUrl(url)) continue;
|
|
77
|
+
const platform = KEY_TO_PLATFORM[rawKey.toLowerCase()];
|
|
78
|
+
if (!platform) continue;
|
|
79
|
+
resolved.set(platform, url);
|
|
80
|
+
}
|
|
81
|
+
const orderedPlatforms = platformAllow ? platformAllow.filter((p) => resolved.has(p)) : Array.from(resolved.keys());
|
|
82
|
+
const wantEmail = (showEmail ?? !!email) && !!email;
|
|
83
|
+
if (orderedPlatforms.length === 0 && !wantEmail) return null;
|
|
84
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
|
|
85
|
+
orderedPlatforms.map((platform) => {
|
|
86
|
+
const { Icon, label } = PLATFORMS[platform];
|
|
87
|
+
const url = resolved.get(platform);
|
|
88
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
89
|
+
"a",
|
|
90
|
+
{
|
|
91
|
+
href: url,
|
|
92
|
+
target: "_blank",
|
|
93
|
+
rel: "noopener noreferrer",
|
|
94
|
+
"aria-label": label,
|
|
95
|
+
className: itemClassName,
|
|
96
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: iconClassName })
|
|
97
|
+
},
|
|
98
|
+
platform
|
|
99
|
+
);
|
|
100
|
+
}),
|
|
101
|
+
wantEmail && /* @__PURE__ */ jsxRuntime.jsx(
|
|
102
|
+
"a",
|
|
103
|
+
{
|
|
104
|
+
href: `mailto:${email}`,
|
|
105
|
+
"aria-label": "Email",
|
|
106
|
+
className: itemClassName,
|
|
107
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { className: iconClassName })
|
|
108
|
+
},
|
|
109
|
+
"email"
|
|
110
|
+
)
|
|
111
|
+
] });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
exports.SocialLinks = SocialLinks;
|
|
115
|
+
//# sourceMappingURL=chunk-YERN2UWM.js.map
|
|
116
|
+
//# sourceMappingURL=chunk-YERN2UWM.js.map
|