@burdenoff/website-sdk 0.0.0-dev → 2026.511.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/index.js +0 -1
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +0 -1
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/client/index.d.mts +2 -5
- package/dist/client/index.d.ts +2 -5
- package/dist/client/index.js +2 -11
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +2 -11
- package/dist/client/index.mjs.map +1 -1
- package/dist/components/contact.d.mts +2 -77
- package/dist/components/contact.d.ts +2 -77
- package/dist/components/contact.js +9 -112
- package/dist/components/contact.js.map +1 -1
- package/dist/components/contact.mjs +10 -112
- package/dist/components/contact.mjs.map +1 -1
- package/dist/components/newsletter.js +6 -17
- package/dist/components/newsletter.js.map +1 -1
- package/dist/components/newsletter.mjs +6 -17
- package/dist/components/newsletter.mjs.map +1 -1
- package/dist/components/pricing.d.mts +0 -38
- package/dist/components/pricing.d.ts +0 -38
- package/dist/components/pricing.js +84 -267
- package/dist/components/pricing.js.map +1 -1
- package/dist/components/pricing.mjs +84 -267
- package/dist/components/pricing.mjs.map +1 -1
- package/dist/components/waitlist.js +2 -6
- package/dist/components/waitlist.js.map +1 -1
- package/dist/components/waitlist.mjs +2 -6
- package/dist/components/waitlist.mjs.map +1 -1
- package/dist/content/index.d.mts +9 -181
- package/dist/content/index.d.ts +9 -181
- package/dist/content/index.js +16 -2177
- package/dist/content/index.js.map +1 -1
- package/dist/content/index.mjs +6 -2141
- package/dist/content/index.mjs.map +1 -1
- package/dist/index.d.mts +5 -43
- package/dist/index.d.ts +5 -43
- package/dist/index.js +373 -3919
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +378 -3905
- package/dist/index.mjs.map +1 -1
- package/dist/product/index.d.mts +0 -8
- package/dist/product/index.d.ts +0 -8
- package/dist/product/index.js +4 -24
- package/dist/product/index.js.map +1 -1
- package/dist/product/index.mjs +4 -24
- package/dist/product/index.mjs.map +1 -1
- package/package.json +3 -5
- package/dist/components/electron-download.d.mts +0 -32
- package/dist/components/electron-download.d.ts +0 -32
- package/dist/components/electron-download.js +0 -131
- package/dist/components/electron-download.js.map +0 -1
- package/dist/components/electron-download.mjs +0 -108
- package/dist/components/electron-download.mjs.map +0 -1
- package/dist/components/launch-countdown.d.mts +0 -15
- package/dist/components/launch-countdown.d.ts +0 -15
- package/dist/components/launch-countdown.js +0 -89
- package/dist/components/launch-countdown.js.map +0 -1
- package/dist/components/launch-countdown.mjs +0 -87
- package/dist/components/launch-countdown.mjs.map +0 -1
- package/dist/components/partners.d.mts +0 -88
- package/dist/components/partners.d.ts +0 -88
- package/dist/components/partners.js +0 -1169
- package/dist/components/partners.js.map +0 -1
- package/dist/components/partners.mjs +0 -1143
- package/dist/components/partners.mjs.map +0 -1
- package/dist/components/problems-solved.d.mts +0 -37
- package/dist/components/problems-solved.d.ts +0 -37
- package/dist/components/problems-solved.js +0 -157
- package/dist/components/problems-solved.js.map +0 -1
- package/dist/components/problems-solved.mjs +0 -135
- package/dist/components/problems-solved.mjs.map +0 -1
- package/dist/components/resource-links.d.mts +0 -28
- package/dist/components/resource-links.d.ts +0 -28
- package/dist/components/resource-links.js +0 -229
- package/dist/components/resource-links.js.map +0 -1
- package/dist/components/resource-links.mjs +0 -227
- package/dist/components/resource-links.mjs.map +0 -1
- package/dist/components/social-links.d.mts +0 -37
- package/dist/components/social-links.d.ts +0 -37
- package/dist/components/social-links.js +0 -268
- package/dist/components/social-links.js.map +0 -1
- package/dist/components/social-links.mjs +0 -266
- package/dist/components/social-links.mjs.map +0 -1
- package/dist/components/website-switcher.d.mts +0 -27
- package/dist/components/website-switcher.d.ts +0 -27
- package/dist/components/website-switcher.js +0 -168
- package/dist/components/website-switcher.js.map +0 -1
- package/dist/components/website-switcher.mjs +0 -146
- package/dist/components/website-switcher.mjs.map +0 -1
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { Download } from 'lucide-react';
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { Slot } from '@radix-ui/react-slot';
|
|
4
|
-
import { cva } from 'class-variance-authority';
|
|
5
|
-
import { clsx } from 'clsx';
|
|
6
|
-
import { twMerge } from 'tailwind-merge';
|
|
7
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
8
|
-
|
|
9
|
-
function cn(...inputs) {
|
|
10
|
-
return twMerge(clsx(inputs));
|
|
11
|
-
}
|
|
12
|
-
var buttonVariants = cva(
|
|
13
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
14
|
-
{
|
|
15
|
-
variants: {
|
|
16
|
-
variant: {
|
|
17
|
-
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
18
|
-
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
19
|
-
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
20
|
-
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
21
|
-
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
22
|
-
link: "text-primary underline-offset-4 hover:underline"
|
|
23
|
-
},
|
|
24
|
-
size: {
|
|
25
|
-
default: "h-9 px-4 py-2",
|
|
26
|
-
sm: "h-8 rounded-md px-3 text-xs",
|
|
27
|
-
lg: "h-10 rounded-md px-8",
|
|
28
|
-
icon: "h-9 w-9"
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
defaultVariants: {
|
|
32
|
-
variant: "default",
|
|
33
|
-
size: "default"
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
);
|
|
37
|
-
var Button = React.forwardRef(
|
|
38
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
39
|
-
const Comp = asChild ? Slot : "button";
|
|
40
|
-
return /* @__PURE__ */ jsx(
|
|
41
|
-
Comp,
|
|
42
|
-
{
|
|
43
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
44
|
-
ref,
|
|
45
|
-
...props
|
|
46
|
-
}
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
Button.displayName = "Button";
|
|
51
|
-
function detectElectronPlatform(userAgent = typeof navigator !== "undefined" ? navigator.userAgent : "") {
|
|
52
|
-
const ua = userAgent.toLowerCase();
|
|
53
|
-
if (ua.includes("win")) return "win";
|
|
54
|
-
if (ua.includes("mac")) return "mac";
|
|
55
|
-
if (ua.includes("linux")) return "linux";
|
|
56
|
-
return "unknown";
|
|
57
|
-
}
|
|
58
|
-
function buildDownloadUrl(base, artifactName, platform, platformMap) {
|
|
59
|
-
const normalizedBase = base.replace(/\/$/, "");
|
|
60
|
-
const platformKey = platformMap[platform] ?? platform;
|
|
61
|
-
const fileName = artifactName.includes("{platform}") ? artifactName.replace(/\{platform\}/g, platformKey) : artifactName;
|
|
62
|
-
return `${normalizedBase}/${fileName}`;
|
|
63
|
-
}
|
|
64
|
-
function ElectronDownloadLink({
|
|
65
|
-
downloadBaseUrl,
|
|
66
|
-
artifactName,
|
|
67
|
-
hidden = true,
|
|
68
|
-
label = "Download desktop app",
|
|
69
|
-
downloadLabel = label,
|
|
70
|
-
platformMap = {},
|
|
71
|
-
className,
|
|
72
|
-
variant = "default",
|
|
73
|
-
size = "default"
|
|
74
|
-
}) {
|
|
75
|
-
if (hidden) return null;
|
|
76
|
-
const platform = detectElectronPlatform();
|
|
77
|
-
const href = buildDownloadUrl(
|
|
78
|
-
downloadBaseUrl,
|
|
79
|
-
artifactName,
|
|
80
|
-
platform,
|
|
81
|
-
platformMap
|
|
82
|
-
);
|
|
83
|
-
return /* @__PURE__ */ jsx(
|
|
84
|
-
Button,
|
|
85
|
-
{
|
|
86
|
-
variant,
|
|
87
|
-
size,
|
|
88
|
-
className: cn("inline-flex items-center gap-2", className),
|
|
89
|
-
asChild: true,
|
|
90
|
-
children: /* @__PURE__ */ jsxs(
|
|
91
|
-
"a",
|
|
92
|
-
{
|
|
93
|
-
href,
|
|
94
|
-
download: true,
|
|
95
|
-
"aria-label": `${downloadLabel}${platform !== "unknown" ? ` for ${platform}` : ""}`,
|
|
96
|
-
children: [
|
|
97
|
-
/* @__PURE__ */ jsx(Download, { className: "h-4 w-4", "aria-hidden": "true" }),
|
|
98
|
-
label
|
|
99
|
-
]
|
|
100
|
-
}
|
|
101
|
-
)
|
|
102
|
-
}
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export { ElectronDownloadLink, detectElectronPlatform };
|
|
107
|
-
//# sourceMappingURL=electron-download.mjs.map
|
|
108
|
-
//# sourceMappingURL=electron-download.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/cn.ts","../../src/ui/button.tsx","../../src/components/electron-download.tsx"],"names":["jsx"],"mappings":"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","file":"electron-download.mjs","sourcesContent":["/**\n * Utility function to merge Tailwind CSS classes\n * Combines clsx and tailwind-merge for optimal class handling\n */\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge multiple class names intelligently\n * - Handles conditional classes via clsx\n * - Deduplicates and resolves Tailwind conflicts via tailwind-merge\n *\n * @example\n * ```ts\n * cn('px-4 py-2', 'bg-blue-500', { 'text-white': isActive })\n * // => 'px-4 py-2 bg-blue-500 text-white' (if isActive is true)\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import * as React from \"react\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../utils/cn\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-9 w-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n );\n },\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","\"use client\";\n\n/**\n * ElectronDownloadLink Component\n *\n * A download link that auto-detects the visitor's operating system and points\n * to the matching Electron artifact. Hidden by default via the `hidden` prop so\n * it can be staged in pages and revealed once a desktop build is ready.\n *\n * The `artifactName` prop may contain a `{platform}` token which is replaced\n * with the detected platform key (`win`, `mac`, or `linux`).\n *\n * @example\n * ```tsx\n * import { ElectronDownloadLink } from '@burdenoff/website-sdk'\n *\n * <ElectronDownloadLink\n * downloadBaseUrl=\"https://releases.example.com/desktop\"\n * artifactName=\"MyApp-{platform}.zip\"\n * />\n * ```\n */\n\nimport { Download } from \"lucide-react\";\n\nimport { Button } from \"../ui/button\";\nimport { cn } from \"../utils/cn\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type DetectedPlatform = \"win\" | \"mac\" | \"linux\" | \"unknown\";\n\nexport interface ElectronDownloadLinkProps {\n /** Base URL where artifacts are hosted (with or without trailing slash). */\n downloadBaseUrl: string;\n /** Artifact file name; may include a `{platform}` token. */\n artifactName: string;\n /** When true, the element is not rendered. Defaults to true (hidden). */\n hidden?: boolean;\n /** Link/button text. */\n label?: string;\n /** Accessible label for the download action. */\n downloadLabel?: string;\n /** Optional mapping from detected platform to artifact platform key. */\n platformMap?: Partial<Record<DetectedPlatform, string>>;\n /** Additional CSS class for the link. */\n className?: string;\n /** Variant for the rendered button. */\n variant?: \"default\" | \"outline\" | \"ghost\" | \"link\";\n /** Size for the rendered button. */\n size?: \"default\" | \"sm\" | \"lg\" | \"icon\";\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Detect the visitor's desktop operating system from the user agent string.\n * Returns `win`, `mac`, `linux`, or `unknown`. This is intended for choosing\n * a download artifact; it intentionally does not distinguish mobile OSes.\n */\nexport function detectElectronPlatform(\n userAgent: string = typeof navigator !== \"undefined\"\n ? navigator.userAgent\n : \"\",\n): DetectedPlatform {\n const ua = userAgent.toLowerCase();\n\n if (ua.includes(\"win\")) return \"win\";\n if (ua.includes(\"mac\")) return \"mac\";\n if (ua.includes(\"linux\")) return \"linux\";\n\n return \"unknown\";\n}\n\nfunction buildDownloadUrl(\n base: string,\n artifactName: string,\n platform: DetectedPlatform,\n platformMap: Partial<Record<DetectedPlatform, string>>,\n): string {\n const normalizedBase = base.replace(/\\/$/, \"\");\n const platformKey = platformMap[platform] ?? platform;\n const fileName = artifactName.includes(\"{platform}\")\n ? artifactName.replace(/\\{platform\\}/g, platformKey)\n : artifactName;\n return `${normalizedBase}/${fileName}`;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function ElectronDownloadLink({\n downloadBaseUrl,\n artifactName,\n hidden = true,\n label = \"Download desktop app\",\n downloadLabel = label,\n platformMap = {},\n className,\n variant = \"default\",\n size = \"default\",\n}: ElectronDownloadLinkProps) {\n if (hidden) return null;\n\n const platform = detectElectronPlatform();\n const href = buildDownloadUrl(\n downloadBaseUrl,\n artifactName,\n platform,\n platformMap,\n );\n\n return (\n <Button\n variant={variant}\n size={size}\n className={cn(\"inline-flex items-center gap-2\", className)}\n asChild\n >\n <a\n href={href}\n download\n aria-label={`${downloadLabel}${platform !== \"unknown\" ? ` for ${platform}` : \"\"}`}\n >\n <Download className=\"h-4 w-4\" aria-hidden=\"true\" />\n {label}\n </a>\n </Button>\n );\n}\n"]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
|
|
3
|
-
interface LaunchCountdownProps {
|
|
4
|
-
/** Launch moment as epoch milliseconds. */
|
|
5
|
-
launchDate: number;
|
|
6
|
-
/** Optional accessible label describing the launch moment. */
|
|
7
|
-
launchLabel?: string;
|
|
8
|
-
/** Message shown once the countdown reaches zero. */
|
|
9
|
-
launchedMessage?: string;
|
|
10
|
-
/** Optional additional CSS class for the outer container. */
|
|
11
|
-
className?: string;
|
|
12
|
-
}
|
|
13
|
-
declare function LaunchCountdown({ launchDate, launchLabel, launchedMessage, className, }: LaunchCountdownProps): react_jsx_runtime.JSX.Element;
|
|
14
|
-
|
|
15
|
-
export { LaunchCountdown, type LaunchCountdownProps };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
|
|
3
|
-
interface LaunchCountdownProps {
|
|
4
|
-
/** Launch moment as epoch milliseconds. */
|
|
5
|
-
launchDate: number;
|
|
6
|
-
/** Optional accessible label describing the launch moment. */
|
|
7
|
-
launchLabel?: string;
|
|
8
|
-
/** Message shown once the countdown reaches zero. */
|
|
9
|
-
launchedMessage?: string;
|
|
10
|
-
/** Optional additional CSS class for the outer container. */
|
|
11
|
-
className?: string;
|
|
12
|
-
}
|
|
13
|
-
declare function LaunchCountdown({ launchDate, launchLabel, launchedMessage, className, }: LaunchCountdownProps): react_jsx_runtime.JSX.Element;
|
|
14
|
-
|
|
15
|
-
export { LaunchCountdown, type LaunchCountdownProps };
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var react = require('react');
|
|
4
|
-
var lucideReact = require('lucide-react');
|
|
5
|
-
var clsx = require('clsx');
|
|
6
|
-
var tailwindMerge = require('tailwind-merge');
|
|
7
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
-
|
|
9
|
-
function cn(...inputs) {
|
|
10
|
-
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
11
|
-
}
|
|
12
|
-
function splitRemaining(ms) {
|
|
13
|
-
const clamped = Math.max(0, ms);
|
|
14
|
-
const totalSeconds = Math.floor(clamped / 1e3);
|
|
15
|
-
return {
|
|
16
|
-
days: Math.floor(totalSeconds / 86400),
|
|
17
|
-
hours: Math.floor(totalSeconds % 86400 / 3600),
|
|
18
|
-
minutes: Math.floor(totalSeconds % 3600 / 60),
|
|
19
|
-
seconds: totalSeconds % 60
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function padTwo(n) {
|
|
23
|
-
return String(n).padStart(2, "0");
|
|
24
|
-
}
|
|
25
|
-
function LaunchCountdown({
|
|
26
|
-
launchDate,
|
|
27
|
-
launchLabel,
|
|
28
|
-
launchedMessage = "We have launched!",
|
|
29
|
-
className
|
|
30
|
-
}) {
|
|
31
|
-
const [now, setNow] = react.useState(() => Date.now());
|
|
32
|
-
const remainingMs = launchDate - now;
|
|
33
|
-
const hasLaunched = remainingMs <= 0;
|
|
34
|
-
react.useEffect(() => {
|
|
35
|
-
if (hasLaunched) return;
|
|
36
|
-
const interval = setInterval(() => {
|
|
37
|
-
setNow(Date.now());
|
|
38
|
-
}, 1e3);
|
|
39
|
-
return () => clearInterval(interval);
|
|
40
|
-
}, [hasLaunched]);
|
|
41
|
-
const { days, hours, minutes, seconds } = splitRemaining(remainingMs);
|
|
42
|
-
const cells = [
|
|
43
|
-
{ label: "Days", value: padTwo(Math.min(days, 99)) },
|
|
44
|
-
{ label: "Hours", value: padTwo(hours) },
|
|
45
|
-
{ label: "Minutes", value: padTwo(minutes) },
|
|
46
|
-
{ label: "Seconds", value: padTwo(seconds) }
|
|
47
|
-
];
|
|
48
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
49
|
-
"div",
|
|
50
|
-
{
|
|
51
|
-
className: cn("inline-flex flex-col gap-3", className),
|
|
52
|
-
role: "timer",
|
|
53
|
-
"aria-label": launchLabel ?? (hasLaunched ? launchedMessage : `Countdown to launch`),
|
|
54
|
-
children: [
|
|
55
|
-
!hasLaunched && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-mono uppercase tracking-wider text-muted-foreground", children: "Launching in" }),
|
|
56
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2 sm:gap-3", children: hasLaunched ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
57
|
-
"div",
|
|
58
|
-
{
|
|
59
|
-
className: cn(
|
|
60
|
-
"flex min-w-[15rem] items-center justify-center gap-3 rounded-lg border border-primary/30 bg-primary/10 px-6 py-4",
|
|
61
|
-
"text-center"
|
|
62
|
-
),
|
|
63
|
-
children: [
|
|
64
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Rocket, { className: "h-5 w-5 text-primary", "aria-hidden": "true" }),
|
|
65
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-lg font-semibold text-foreground", children: launchedMessage })
|
|
66
|
-
]
|
|
67
|
-
}
|
|
68
|
-
) : cells.map((cell) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69
|
-
"div",
|
|
70
|
-
{
|
|
71
|
-
className: cn(
|
|
72
|
-
"flex min-w-[3.75rem] flex-col items-center rounded-lg border border-border/60 bg-card px-3 py-2 sm:min-w-[4.5rem] sm:px-4 sm:py-3"
|
|
73
|
-
),
|
|
74
|
-
children: [
|
|
75
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-2xl font-bold tabular-nums text-foreground sm:text-3xl", children: cell.value }),
|
|
76
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1 text-[10px] font-medium uppercase tracking-wide text-muted-foreground sm:text-xs", children: cell.label })
|
|
77
|
-
]
|
|
78
|
-
},
|
|
79
|
-
cell.label
|
|
80
|
-
)) }),
|
|
81
|
-
!hasLaunched && launchLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: launchLabel })
|
|
82
|
-
]
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
exports.LaunchCountdown = LaunchCountdown;
|
|
88
|
-
//# sourceMappingURL=launch-countdown.js.map
|
|
89
|
-
//# sourceMappingURL=launch-countdown.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/cn.ts","../../src/components/launch-countdown.tsx"],"names":["twMerge","clsx","useState","useEffect","jsxs","jsx","Rocket"],"mappings":"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","file":"launch-countdown.js","sourcesContent":["/**\n * Utility function to merge Tailwind CSS classes\n * Combines clsx and tailwind-merge for optimal class handling\n */\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge multiple class names intelligently\n * - Handles conditional classes via clsx\n * - Deduplicates and resolves Tailwind conflicts via tailwind-merge\n *\n * @example\n * ```ts\n * cn('px-4 py-2', 'bg-blue-500', { 'text-white': isActive })\n * // => 'px-4 py-2 bg-blue-500 text-white' (if isActive is true)\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\n/**\n * LaunchCountdown Component\n *\n * Reusable countdown timer counting down to a `launchDate` (epoch ms). Renders\n * a fixed-size grid of days / hours / minutes / seconds and flips to a\n * \"Launched\" message once the moment passes. Uses semantic theme tokens so it\n * works in light, dark, and high-contrast themes.\n *\n * @example\n * ```tsx\n * import { LaunchCountdown } from '@burdenoff/website-sdk'\n *\n * <LaunchCountdown launchDate={Date.UTC(2026, 7, 15, 0, 0, 0)} />\n * ```\n */\n\nimport { useEffect, useState } from \"react\";\n\nimport { Rocket } from \"lucide-react\";\n\nimport { cn } from \"../utils/cn\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface LaunchCountdownProps {\n /** Launch moment as epoch milliseconds. */\n launchDate: number;\n /** Optional accessible label describing the launch moment. */\n launchLabel?: string;\n /** Message shown once the countdown reaches zero. */\n launchedMessage?: string;\n /** Optional additional CSS class for the outer container. */\n className?: string;\n}\n\ninterface Remaining {\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction splitRemaining(ms: number): Remaining {\n const clamped = Math.max(0, ms);\n const totalSeconds = Math.floor(clamped / 1000);\n return {\n days: Math.floor(totalSeconds / 86400),\n hours: Math.floor((totalSeconds % 86400) / 3600),\n minutes: Math.floor((totalSeconds % 3600) / 60),\n seconds: totalSeconds % 60,\n };\n}\n\nfunction padTwo(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function LaunchCountdown({\n launchDate,\n launchLabel,\n launchedMessage = \"We have launched!\",\n className,\n}: LaunchCountdownProps) {\n const [now, setNow] = useState(() => Date.now());\n const remainingMs = launchDate - now;\n const hasLaunched = remainingMs <= 0;\n\n useEffect(() => {\n if (hasLaunched) return;\n\n const interval = setInterval(() => {\n setNow(Date.now());\n }, 1000);\n\n return () => clearInterval(interval);\n }, [hasLaunched]);\n\n const { days, hours, minutes, seconds } = splitRemaining(remainingMs);\n\n const cells: Array<{ label: string; value: string }> = [\n { label: \"Days\", value: padTwo(Math.min(days, 99)) },\n { label: \"Hours\", value: padTwo(hours) },\n { label: \"Minutes\", value: padTwo(minutes) },\n { label: \"Seconds\", value: padTwo(seconds) },\n ];\n\n return (\n <div\n className={cn(\"inline-flex flex-col gap-3\", className)}\n role=\"timer\"\n aria-label={\n launchLabel ?? (hasLaunched ? launchedMessage : `Countdown to launch`)\n }\n >\n {!hasLaunched && (\n <span className=\"text-xs font-mono uppercase tracking-wider text-muted-foreground\">\n Launching in\n </span>\n )}\n\n <div className=\"flex gap-2 sm:gap-3\">\n {hasLaunched ? (\n <div\n className={cn(\n \"flex min-w-[15rem] items-center justify-center gap-3 rounded-lg border border-primary/30 bg-primary/10 px-6 py-4\",\n \"text-center\",\n )}\n >\n <Rocket className=\"h-5 w-5 text-primary\" aria-hidden=\"true\" />\n <span className=\"text-lg font-semibold text-foreground\">\n {launchedMessage}\n </span>\n </div>\n ) : (\n cells.map((cell) => (\n <div\n key={cell.label}\n className={cn(\n \"flex min-w-[3.75rem] flex-col items-center rounded-lg border border-border/60 bg-card px-3 py-2 sm:min-w-[4.5rem] sm:px-4 sm:py-3\",\n )}\n >\n <span className=\"font-mono text-2xl font-bold tabular-nums text-foreground sm:text-3xl\">\n {cell.value}\n </span>\n <span className=\"mt-1 text-[10px] font-medium uppercase tracking-wide text-muted-foreground sm:text-xs\">\n {cell.label}\n </span>\n </div>\n ))\n )}\n </div>\n\n {!hasLaunched && launchLabel && (\n <span className=\"text-sm text-muted-foreground\">{launchLabel}</span>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
2
|
-
import { Rocket } from 'lucide-react';
|
|
3
|
-
import { clsx } from 'clsx';
|
|
4
|
-
import { twMerge } from 'tailwind-merge';
|
|
5
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
-
|
|
7
|
-
function cn(...inputs) {
|
|
8
|
-
return twMerge(clsx(inputs));
|
|
9
|
-
}
|
|
10
|
-
function splitRemaining(ms) {
|
|
11
|
-
const clamped = Math.max(0, ms);
|
|
12
|
-
const totalSeconds = Math.floor(clamped / 1e3);
|
|
13
|
-
return {
|
|
14
|
-
days: Math.floor(totalSeconds / 86400),
|
|
15
|
-
hours: Math.floor(totalSeconds % 86400 / 3600),
|
|
16
|
-
minutes: Math.floor(totalSeconds % 3600 / 60),
|
|
17
|
-
seconds: totalSeconds % 60
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
function padTwo(n) {
|
|
21
|
-
return String(n).padStart(2, "0");
|
|
22
|
-
}
|
|
23
|
-
function LaunchCountdown({
|
|
24
|
-
launchDate,
|
|
25
|
-
launchLabel,
|
|
26
|
-
launchedMessage = "We have launched!",
|
|
27
|
-
className
|
|
28
|
-
}) {
|
|
29
|
-
const [now, setNow] = useState(() => Date.now());
|
|
30
|
-
const remainingMs = launchDate - now;
|
|
31
|
-
const hasLaunched = remainingMs <= 0;
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (hasLaunched) return;
|
|
34
|
-
const interval = setInterval(() => {
|
|
35
|
-
setNow(Date.now());
|
|
36
|
-
}, 1e3);
|
|
37
|
-
return () => clearInterval(interval);
|
|
38
|
-
}, [hasLaunched]);
|
|
39
|
-
const { days, hours, minutes, seconds } = splitRemaining(remainingMs);
|
|
40
|
-
const cells = [
|
|
41
|
-
{ label: "Days", value: padTwo(Math.min(days, 99)) },
|
|
42
|
-
{ label: "Hours", value: padTwo(hours) },
|
|
43
|
-
{ label: "Minutes", value: padTwo(minutes) },
|
|
44
|
-
{ label: "Seconds", value: padTwo(seconds) }
|
|
45
|
-
];
|
|
46
|
-
return /* @__PURE__ */ jsxs(
|
|
47
|
-
"div",
|
|
48
|
-
{
|
|
49
|
-
className: cn("inline-flex flex-col gap-3", className),
|
|
50
|
-
role: "timer",
|
|
51
|
-
"aria-label": launchLabel ?? (hasLaunched ? launchedMessage : `Countdown to launch`),
|
|
52
|
-
children: [
|
|
53
|
-
!hasLaunched && /* @__PURE__ */ jsx("span", { className: "text-xs font-mono uppercase tracking-wider text-muted-foreground", children: "Launching in" }),
|
|
54
|
-
/* @__PURE__ */ jsx("div", { className: "flex gap-2 sm:gap-3", children: hasLaunched ? /* @__PURE__ */ jsxs(
|
|
55
|
-
"div",
|
|
56
|
-
{
|
|
57
|
-
className: cn(
|
|
58
|
-
"flex min-w-[15rem] items-center justify-center gap-3 rounded-lg border border-primary/30 bg-primary/10 px-6 py-4",
|
|
59
|
-
"text-center"
|
|
60
|
-
),
|
|
61
|
-
children: [
|
|
62
|
-
/* @__PURE__ */ jsx(Rocket, { className: "h-5 w-5 text-primary", "aria-hidden": "true" }),
|
|
63
|
-
/* @__PURE__ */ jsx("span", { className: "text-lg font-semibold text-foreground", children: launchedMessage })
|
|
64
|
-
]
|
|
65
|
-
}
|
|
66
|
-
) : cells.map((cell) => /* @__PURE__ */ jsxs(
|
|
67
|
-
"div",
|
|
68
|
-
{
|
|
69
|
-
className: cn(
|
|
70
|
-
"flex min-w-[3.75rem] flex-col items-center rounded-lg border border-border/60 bg-card px-3 py-2 sm:min-w-[4.5rem] sm:px-4 sm:py-3"
|
|
71
|
-
),
|
|
72
|
-
children: [
|
|
73
|
-
/* @__PURE__ */ jsx("span", { className: "font-mono text-2xl font-bold tabular-nums text-foreground sm:text-3xl", children: cell.value }),
|
|
74
|
-
/* @__PURE__ */ jsx("span", { className: "mt-1 text-[10px] font-medium uppercase tracking-wide text-muted-foreground sm:text-xs", children: cell.label })
|
|
75
|
-
]
|
|
76
|
-
},
|
|
77
|
-
cell.label
|
|
78
|
-
)) }),
|
|
79
|
-
!hasLaunched && launchLabel && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: launchLabel })
|
|
80
|
-
]
|
|
81
|
-
}
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export { LaunchCountdown };
|
|
86
|
-
//# sourceMappingURL=launch-countdown.mjs.map
|
|
87
|
-
//# sourceMappingURL=launch-countdown.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/cn.ts","../../src/components/launch-countdown.tsx"],"names":[],"mappings":"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","file":"launch-countdown.mjs","sourcesContent":["/**\n * Utility function to merge Tailwind CSS classes\n * Combines clsx and tailwind-merge for optimal class handling\n */\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge multiple class names intelligently\n * - Handles conditional classes via clsx\n * - Deduplicates and resolves Tailwind conflicts via tailwind-merge\n *\n * @example\n * ```ts\n * cn('px-4 py-2', 'bg-blue-500', { 'text-white': isActive })\n * // => 'px-4 py-2 bg-blue-500 text-white' (if isActive is true)\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\n/**\n * LaunchCountdown Component\n *\n * Reusable countdown timer counting down to a `launchDate` (epoch ms). Renders\n * a fixed-size grid of days / hours / minutes / seconds and flips to a\n * \"Launched\" message once the moment passes. Uses semantic theme tokens so it\n * works in light, dark, and high-contrast themes.\n *\n * @example\n * ```tsx\n * import { LaunchCountdown } from '@burdenoff/website-sdk'\n *\n * <LaunchCountdown launchDate={Date.UTC(2026, 7, 15, 0, 0, 0)} />\n * ```\n */\n\nimport { useEffect, useState } from \"react\";\n\nimport { Rocket } from \"lucide-react\";\n\nimport { cn } from \"../utils/cn\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface LaunchCountdownProps {\n /** Launch moment as epoch milliseconds. */\n launchDate: number;\n /** Optional accessible label describing the launch moment. */\n launchLabel?: string;\n /** Message shown once the countdown reaches zero. */\n launchedMessage?: string;\n /** Optional additional CSS class for the outer container. */\n className?: string;\n}\n\ninterface Remaining {\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction splitRemaining(ms: number): Remaining {\n const clamped = Math.max(0, ms);\n const totalSeconds = Math.floor(clamped / 1000);\n return {\n days: Math.floor(totalSeconds / 86400),\n hours: Math.floor((totalSeconds % 86400) / 3600),\n minutes: Math.floor((totalSeconds % 3600) / 60),\n seconds: totalSeconds % 60,\n };\n}\n\nfunction padTwo(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function LaunchCountdown({\n launchDate,\n launchLabel,\n launchedMessage = \"We have launched!\",\n className,\n}: LaunchCountdownProps) {\n const [now, setNow] = useState(() => Date.now());\n const remainingMs = launchDate - now;\n const hasLaunched = remainingMs <= 0;\n\n useEffect(() => {\n if (hasLaunched) return;\n\n const interval = setInterval(() => {\n setNow(Date.now());\n }, 1000);\n\n return () => clearInterval(interval);\n }, [hasLaunched]);\n\n const { days, hours, minutes, seconds } = splitRemaining(remainingMs);\n\n const cells: Array<{ label: string; value: string }> = [\n { label: \"Days\", value: padTwo(Math.min(days, 99)) },\n { label: \"Hours\", value: padTwo(hours) },\n { label: \"Minutes\", value: padTwo(minutes) },\n { label: \"Seconds\", value: padTwo(seconds) },\n ];\n\n return (\n <div\n className={cn(\"inline-flex flex-col gap-3\", className)}\n role=\"timer\"\n aria-label={\n launchLabel ?? (hasLaunched ? launchedMessage : `Countdown to launch`)\n }\n >\n {!hasLaunched && (\n <span className=\"text-xs font-mono uppercase tracking-wider text-muted-foreground\">\n Launching in\n </span>\n )}\n\n <div className=\"flex gap-2 sm:gap-3\">\n {hasLaunched ? (\n <div\n className={cn(\n \"flex min-w-[15rem] items-center justify-center gap-3 rounded-lg border border-primary/30 bg-primary/10 px-6 py-4\",\n \"text-center\",\n )}\n >\n <Rocket className=\"h-5 w-5 text-primary\" aria-hidden=\"true\" />\n <span className=\"text-lg font-semibold text-foreground\">\n {launchedMessage}\n </span>\n </div>\n ) : (\n cells.map((cell) => (\n <div\n key={cell.label}\n className={cn(\n \"flex min-w-[3.75rem] flex-col items-center rounded-lg border border-border/60 bg-card px-3 py-2 sm:min-w-[4.5rem] sm:px-4 sm:py-3\",\n )}\n >\n <span className=\"font-mono text-2xl font-bold tabular-nums text-foreground sm:text-3xl\">\n {cell.value}\n </span>\n <span className=\"mt-1 text-[10px] font-medium uppercase tracking-wide text-muted-foreground sm:text-xs\">\n {cell.label}\n </span>\n </div>\n ))\n )}\n </div>\n\n {!hasLaunched && launchLabel && (\n <span className=\"text-sm text-muted-foreground\">{launchLabel}</span>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { ContactCategory, ContactPageProps } from './contact.mjs';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Office address shape consumed by `<ContactPage>`. Mirrored here as a
|
|
6
|
-
* local type so we don't widen `contact.tsx`'s public surface just for
|
|
7
|
-
* this consumer — keeps the contact module's exports unchanged.
|
|
8
|
-
*/
|
|
9
|
-
interface OfficeAddress {
|
|
10
|
-
line1: string;
|
|
11
|
-
line2: string;
|
|
12
|
-
line3: string;
|
|
13
|
-
country: string;
|
|
14
|
-
}
|
|
15
|
-
interface PartnersPageProps {
|
|
16
|
-
/** Product name (e.g. `"VibeControls"`). Falls back to SDK config. */
|
|
17
|
-
productName?: string;
|
|
18
|
-
/** Hero headline. Default: `"Partner with us"`. */
|
|
19
|
-
heroTitle?: string;
|
|
20
|
-
/** Hero subtitle / pitch line. */
|
|
21
|
-
heroSubtitle?: string;
|
|
22
|
-
/**
|
|
23
|
-
* Tag filter for the marketing-copy body. Default: `"partner"`. The
|
|
24
|
-
* component fetches the FIRST published `ProductContentPage` whose
|
|
25
|
-
* tags array contains this tag and renders its body via
|
|
26
|
-
* `ContentRenderer`. Self-hides if none exist.
|
|
27
|
-
*/
|
|
28
|
-
contentTag?: string;
|
|
29
|
-
/**
|
|
30
|
-
* Pin a specific content page by slug. If set, overrides `contentTag`.
|
|
31
|
-
* Useful when multiple partner pages exist and you want to render one
|
|
32
|
-
* canonical version per route.
|
|
33
|
-
*/
|
|
34
|
-
contentSlug?: string;
|
|
35
|
-
/**
|
|
36
|
-
* Tag filter for the downloadable documents. Default: `"partner"`.
|
|
37
|
-
* Combined with the implicit `category === "DOCUMENT"` filter — only
|
|
38
|
-
* Press Kit assets that match BOTH are rendered as cards. Self-hides
|
|
39
|
-
* when empty.
|
|
40
|
-
*/
|
|
41
|
-
documentsTag?: string;
|
|
42
|
-
/** Documents-section heading. Default: `"Partner Documents"`. */
|
|
43
|
-
documentsTitle?: string;
|
|
44
|
-
/** Documents-section subtitle / lead. */
|
|
45
|
-
documentsSubtitle?: string;
|
|
46
|
-
/**
|
|
47
|
-
* Whether to render the "Become a partner" contact form. Default: `true`.
|
|
48
|
-
* Set to `false` for a documents-only / read-only partner landing page.
|
|
49
|
-
*/
|
|
50
|
-
showContactForm?: boolean;
|
|
51
|
-
/**
|
|
52
|
-
* Inquiry-category options for the embedded `<ContactPage>` dropdown.
|
|
53
|
-
* Default: `{ value: "partnership", label: "Partner program" }` (a single,
|
|
54
|
-
* required option so every submission is tagged for partner triage). Pass an
|
|
55
|
-
* **array** to offer multiple selectable partner tracks (Referral, Reseller,
|
|
56
|
-
* MSP, …). Pass `false` to disable the dropdown entirely.
|
|
57
|
-
*/
|
|
58
|
-
contactCategory?: ContactCategory | ContactCategory[] | false;
|
|
59
|
-
/** Heading shown above the form. Default: `"Become a partner"`. */
|
|
60
|
-
formTitle?: string;
|
|
61
|
-
/** Subtitle / lead above the form. */
|
|
62
|
-
formSubtitle?: string;
|
|
63
|
-
contactEmail: string;
|
|
64
|
-
contactPhone: string;
|
|
65
|
-
officeAddress: OfficeAddress;
|
|
66
|
-
responseTime?: string;
|
|
67
|
-
recaptchaSiteKey?: string;
|
|
68
|
-
/** Forwarded to `<ContactPage additionalOptions>`. */
|
|
69
|
-
additionalOptions?: ContactPageProps["additionalOptions"];
|
|
70
|
-
seoTitle?: string;
|
|
71
|
-
seoDescription?: string;
|
|
72
|
-
seoKeywords?: string;
|
|
73
|
-
className?: string;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Strip a single leading top-level heading from CMS body content. The
|
|
77
|
-
* `PartnerHero` already renders the page title, so a content body that also
|
|
78
|
-
* opens with `# Title` (the natural way an author writes a page) would print
|
|
79
|
-
* the title twice. Removing the body's leading heading keeps one visible
|
|
80
|
-
* title and one `<h1>` per page. Only the *first* heading is touched — all
|
|
81
|
-
* section headings below it are preserved.
|
|
82
|
-
*
|
|
83
|
-
* Exported for unit testing only; not re-exported from the package barrel.
|
|
84
|
-
*/
|
|
85
|
-
declare function stripLeadingHeading(content: string, format?: string): string;
|
|
86
|
-
declare function PartnersPage(props: PartnersPageProps): react_jsx_runtime.JSX.Element;
|
|
87
|
-
|
|
88
|
-
export { PartnersPage, type PartnersPageProps, stripLeadingHeading };
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { ContactCategory, ContactPageProps } from './contact.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Office address shape consumed by `<ContactPage>`. Mirrored here as a
|
|
6
|
-
* local type so we don't widen `contact.tsx`'s public surface just for
|
|
7
|
-
* this consumer — keeps the contact module's exports unchanged.
|
|
8
|
-
*/
|
|
9
|
-
interface OfficeAddress {
|
|
10
|
-
line1: string;
|
|
11
|
-
line2: string;
|
|
12
|
-
line3: string;
|
|
13
|
-
country: string;
|
|
14
|
-
}
|
|
15
|
-
interface PartnersPageProps {
|
|
16
|
-
/** Product name (e.g. `"VibeControls"`). Falls back to SDK config. */
|
|
17
|
-
productName?: string;
|
|
18
|
-
/** Hero headline. Default: `"Partner with us"`. */
|
|
19
|
-
heroTitle?: string;
|
|
20
|
-
/** Hero subtitle / pitch line. */
|
|
21
|
-
heroSubtitle?: string;
|
|
22
|
-
/**
|
|
23
|
-
* Tag filter for the marketing-copy body. Default: `"partner"`. The
|
|
24
|
-
* component fetches the FIRST published `ProductContentPage` whose
|
|
25
|
-
* tags array contains this tag and renders its body via
|
|
26
|
-
* `ContentRenderer`. Self-hides if none exist.
|
|
27
|
-
*/
|
|
28
|
-
contentTag?: string;
|
|
29
|
-
/**
|
|
30
|
-
* Pin a specific content page by slug. If set, overrides `contentTag`.
|
|
31
|
-
* Useful when multiple partner pages exist and you want to render one
|
|
32
|
-
* canonical version per route.
|
|
33
|
-
*/
|
|
34
|
-
contentSlug?: string;
|
|
35
|
-
/**
|
|
36
|
-
* Tag filter for the downloadable documents. Default: `"partner"`.
|
|
37
|
-
* Combined with the implicit `category === "DOCUMENT"` filter — only
|
|
38
|
-
* Press Kit assets that match BOTH are rendered as cards. Self-hides
|
|
39
|
-
* when empty.
|
|
40
|
-
*/
|
|
41
|
-
documentsTag?: string;
|
|
42
|
-
/** Documents-section heading. Default: `"Partner Documents"`. */
|
|
43
|
-
documentsTitle?: string;
|
|
44
|
-
/** Documents-section subtitle / lead. */
|
|
45
|
-
documentsSubtitle?: string;
|
|
46
|
-
/**
|
|
47
|
-
* Whether to render the "Become a partner" contact form. Default: `true`.
|
|
48
|
-
* Set to `false` for a documents-only / read-only partner landing page.
|
|
49
|
-
*/
|
|
50
|
-
showContactForm?: boolean;
|
|
51
|
-
/**
|
|
52
|
-
* Inquiry-category options for the embedded `<ContactPage>` dropdown.
|
|
53
|
-
* Default: `{ value: "partnership", label: "Partner program" }` (a single,
|
|
54
|
-
* required option so every submission is tagged for partner triage). Pass an
|
|
55
|
-
* **array** to offer multiple selectable partner tracks (Referral, Reseller,
|
|
56
|
-
* MSP, …). Pass `false` to disable the dropdown entirely.
|
|
57
|
-
*/
|
|
58
|
-
contactCategory?: ContactCategory | ContactCategory[] | false;
|
|
59
|
-
/** Heading shown above the form. Default: `"Become a partner"`. */
|
|
60
|
-
formTitle?: string;
|
|
61
|
-
/** Subtitle / lead above the form. */
|
|
62
|
-
formSubtitle?: string;
|
|
63
|
-
contactEmail: string;
|
|
64
|
-
contactPhone: string;
|
|
65
|
-
officeAddress: OfficeAddress;
|
|
66
|
-
responseTime?: string;
|
|
67
|
-
recaptchaSiteKey?: string;
|
|
68
|
-
/** Forwarded to `<ContactPage additionalOptions>`. */
|
|
69
|
-
additionalOptions?: ContactPageProps["additionalOptions"];
|
|
70
|
-
seoTitle?: string;
|
|
71
|
-
seoDescription?: string;
|
|
72
|
-
seoKeywords?: string;
|
|
73
|
-
className?: string;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Strip a single leading top-level heading from CMS body content. The
|
|
77
|
-
* `PartnerHero` already renders the page title, so a content body that also
|
|
78
|
-
* opens with `# Title` (the natural way an author writes a page) would print
|
|
79
|
-
* the title twice. Removing the body's leading heading keeps one visible
|
|
80
|
-
* title and one `<h1>` per page. Only the *first* heading is touched — all
|
|
81
|
-
* section headings below it are preserved.
|
|
82
|
-
*
|
|
83
|
-
* Exported for unit testing only; not re-exported from the package barrel.
|
|
84
|
-
*/
|
|
85
|
-
declare function stripLeadingHeading(content: string, format?: string): string;
|
|
86
|
-
declare function PartnersPage(props: PartnersPageProps): react_jsx_runtime.JSX.Element;
|
|
87
|
-
|
|
88
|
-
export { PartnersPage, type PartnersPageProps, stripLeadingHeading };
|