@burdenoff/website-sdk 0.0.0-dev

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.
Files changed (119) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +357 -0
  3. package/dist/analytics/index.d.mts +27 -0
  4. package/dist/analytics/index.d.ts +27 -0
  5. package/dist/analytics/index.js +36 -0
  6. package/dist/analytics/index.js.map +1 -0
  7. package/dist/analytics/index.mjs +34 -0
  8. package/dist/analytics/index.mjs.map +1 -0
  9. package/dist/client/index.d.mts +29 -0
  10. package/dist/client/index.d.ts +29 -0
  11. package/dist/client/index.js +261 -0
  12. package/dist/client/index.js.map +1 -0
  13. package/dist/client/index.mjs +255 -0
  14. package/dist/client/index.mjs.map +1 -0
  15. package/dist/components/contact.d.mts +144 -0
  16. package/dist/components/contact.d.ts +144 -0
  17. package/dist/components/contact.js +806 -0
  18. package/dist/components/contact.js.map +1 -0
  19. package/dist/components/contact.mjs +780 -0
  20. package/dist/components/contact.mjs.map +1 -0
  21. package/dist/components/electron-download.d.mts +32 -0
  22. package/dist/components/electron-download.d.ts +32 -0
  23. package/dist/components/electron-download.js +131 -0
  24. package/dist/components/electron-download.js.map +1 -0
  25. package/dist/components/electron-download.mjs +108 -0
  26. package/dist/components/electron-download.mjs.map +1 -0
  27. package/dist/components/launch-countdown.d.mts +15 -0
  28. package/dist/components/launch-countdown.d.ts +15 -0
  29. package/dist/components/launch-countdown.js +89 -0
  30. package/dist/components/launch-countdown.js.map +1 -0
  31. package/dist/components/launch-countdown.mjs +87 -0
  32. package/dist/components/launch-countdown.mjs.map +1 -0
  33. package/dist/components/newsletter.d.mts +155 -0
  34. package/dist/components/newsletter.d.ts +155 -0
  35. package/dist/components/newsletter.js +880 -0
  36. package/dist/components/newsletter.js.map +1 -0
  37. package/dist/components/newsletter.mjs +854 -0
  38. package/dist/components/newsletter.mjs.map +1 -0
  39. package/dist/components/partners.d.mts +88 -0
  40. package/dist/components/partners.d.ts +88 -0
  41. package/dist/components/partners.js +1169 -0
  42. package/dist/components/partners.js.map +1 -0
  43. package/dist/components/partners.mjs +1143 -0
  44. package/dist/components/partners.mjs.map +1 -0
  45. package/dist/components/pricing.d.mts +194 -0
  46. package/dist/components/pricing.d.ts +194 -0
  47. package/dist/components/pricing.js +813 -0
  48. package/dist/components/pricing.js.map +1 -0
  49. package/dist/components/pricing.mjs +791 -0
  50. package/dist/components/pricing.mjs.map +1 -0
  51. package/dist/components/problems-solved.d.mts +37 -0
  52. package/dist/components/problems-solved.d.ts +37 -0
  53. package/dist/components/problems-solved.js +157 -0
  54. package/dist/components/problems-solved.js.map +1 -0
  55. package/dist/components/problems-solved.mjs +135 -0
  56. package/dist/components/problems-solved.mjs.map +1 -0
  57. package/dist/components/resource-links.d.mts +28 -0
  58. package/dist/components/resource-links.d.ts +28 -0
  59. package/dist/components/resource-links.js +229 -0
  60. package/dist/components/resource-links.js.map +1 -0
  61. package/dist/components/resource-links.mjs +227 -0
  62. package/dist/components/resource-links.mjs.map +1 -0
  63. package/dist/components/social-links.d.mts +37 -0
  64. package/dist/components/social-links.d.ts +37 -0
  65. package/dist/components/social-links.js +268 -0
  66. package/dist/components/social-links.js.map +1 -0
  67. package/dist/components/social-links.mjs +266 -0
  68. package/dist/components/social-links.mjs.map +1 -0
  69. package/dist/components/unsubscribe.d.mts +14 -0
  70. package/dist/components/unsubscribe.d.ts +14 -0
  71. package/dist/components/unsubscribe.js +538 -0
  72. package/dist/components/unsubscribe.js.map +1 -0
  73. package/dist/components/unsubscribe.mjs +517 -0
  74. package/dist/components/unsubscribe.mjs.map +1 -0
  75. package/dist/components/waitlist.d.mts +70 -0
  76. package/dist/components/waitlist.d.ts +70 -0
  77. package/dist/components/waitlist.js +864 -0
  78. package/dist/components/waitlist.js.map +1 -0
  79. package/dist/components/waitlist.mjs +841 -0
  80. package/dist/components/waitlist.mjs.map +1 -0
  81. package/dist/components/website-switcher.d.mts +27 -0
  82. package/dist/components/website-switcher.d.ts +27 -0
  83. package/dist/components/website-switcher.js +168 -0
  84. package/dist/components/website-switcher.js.map +1 -0
  85. package/dist/components/website-switcher.mjs +146 -0
  86. package/dist/components/website-switcher.mjs.map +1 -0
  87. package/dist/content/index.d.mts +247 -0
  88. package/dist/content/index.d.ts +247 -0
  89. package/dist/content/index.js +2458 -0
  90. package/dist/content/index.js.map +1 -0
  91. package/dist/content/index.mjs +2428 -0
  92. package/dist/content/index.mjs.map +1 -0
  93. package/dist/index.d.mts +72 -0
  94. package/dist/index.d.ts +72 -0
  95. package/dist/index.js +6273 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/index.mjs +6204 -0
  98. package/dist/index.mjs.map +1 -0
  99. package/dist/product/index.d.mts +94 -0
  100. package/dist/product/index.d.ts +94 -0
  101. package/dist/product/index.js +282 -0
  102. package/dist/product/index.js.map +1 -0
  103. package/dist/product/index.mjs +278 -0
  104. package/dist/product/index.mjs.map +1 -0
  105. package/dist/provider-D7Rij9UM.d.mts +86 -0
  106. package/dist/provider-D7Rij9UM.d.ts +86 -0
  107. package/dist/seo/index.d.mts +64 -0
  108. package/dist/seo/index.d.ts +64 -0
  109. package/dist/seo/index.js +61 -0
  110. package/dist/seo/index.js.map +1 -0
  111. package/dist/seo/index.mjs +59 -0
  112. package/dist/seo/index.mjs.map +1 -0
  113. package/dist/utils/index.d.mts +21 -0
  114. package/dist/utils/index.d.ts +21 -0
  115. package/dist/utils/index.js +12 -0
  116. package/dist/utils/index.js.map +1 -0
  117. package/dist/utils/index.mjs +10 -0
  118. package/dist/utils/index.mjs.map +1 -0
  119. package/package.json +168 -0
@@ -0,0 +1,89 @@
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
@@ -0,0 +1 @@
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"]}
@@ -0,0 +1,87 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/cn.ts","../../src/components/launch-countdown.tsx"],"names":[],"mappings":";;;;;;AAmBO,SAAS,MAAM,MAAA,EAA8B;AAClD,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;AC6BA,SAAS,eAAe,EAAA,EAAuB;AAC7C,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,EAAE,CAAA;AAC9B,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,GAAI,CAAA;AAC9C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,IAAA,CAAK,KAAA,CAAM,YAAA,GAAe,KAAK,CAAA;AAAA,IACrC,KAAA,EAAO,IAAA,CAAK,KAAA,CAAO,YAAA,GAAe,QAAS,IAAI,CAAA;AAAA,IAC/C,OAAA,EAAS,IAAA,CAAK,KAAA,CAAO,YAAA,GAAe,OAAQ,EAAE,CAAA;AAAA,IAC9C,SAAS,YAAA,GAAe;AAAA,GAC1B;AACF;AAEA,SAAS,OAAO,CAAA,EAAmB;AACjC,EAAA,OAAO,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AAClC;AAMO,SAAS,eAAA,CAAgB;AAAA,EAC9B,UAAA;AAAA,EACA,WAAA;AAAA,EACA,eAAA,GAAkB,mBAAA;AAAA,EAClB;AACF,CAAA,EAAyB;AACvB,EAAA,MAAM,CAAC,KAAK,MAAM,CAAA,GAAI,SAAS,MAAM,IAAA,CAAK,KAAK,CAAA;AAC/C,EAAA,MAAM,cAAc,UAAA,GAAa,GAAA;AACjC,EAAA,MAAM,cAAc,WAAA,IAAe,CAAA;AAEnC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,WAAA,EAAa;AAEjB,IAAA,MAAM,QAAA,GAAW,YAAY,MAAM;AACjC,MAAA,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAAA,IACnB,GAAG,GAAI,CAAA;AAEP,IAAA,OAAO,MAAM,cAAc,QAAQ,CAAA;AAAA,EACrC,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAO,SAAS,OAAA,EAAQ,GAAI,eAAe,WAAW,CAAA;AAEpE,EAAA,MAAM,KAAA,GAAiD;AAAA,IACrD,EAAE,KAAA,EAAO,MAAA,EAAQ,KAAA,EAAO,MAAA,CAAO,KAAK,GAAA,CAAI,IAAA,EAAM,EAAE,CAAC,CAAA,EAAE;AAAA,IACnD,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,MAAA,CAAO,KAAK,CAAA,EAAE;AAAA,IACvC,EAAE,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,MAAA,CAAO,OAAO,CAAA,EAAE;AAAA,IAC3C,EAAE,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,MAAA,CAAO,OAAO,CAAA;AAAE,GAC7C;AAEA,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA,CAAG,4BAAA,EAA8B,SAAS,CAAA;AAAA,MACrD,IAAA,EAAK,OAAA;AAAA,MACL,YAAA,EACE,WAAA,KAAgB,WAAA,GAAc,eAAA,GAAkB,CAAA,mBAAA,CAAA,CAAA;AAAA,MAGjD,QAAA,EAAA;AAAA,QAAA,CAAC,WAAA,oBACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oEAAmE,QAAA,EAAA,cAAA,EAEnF,CAAA;AAAA,wBAGF,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EACZ,QAAA,EAAA,WAAA,mBACC,IAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,EAAA;AAAA,cACT,kHAAA;AAAA,cACA;AAAA,aACF;AAAA,YAEA,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,SAAA,EAAU,sBAAA,EAAuB,aAAA,EAAY,MAAA,EAAO,CAAA;AAAA,8BAC5D,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uCAAA,EACb,QAAA,EAAA,eAAA,EACH;AAAA;AAAA;AAAA,SACF,GAEA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,qBACT,IAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YAEC,SAAA,EAAW,EAAA;AAAA,cACT;AAAA,aACF;AAAA,YAEA,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uEAAA,EACb,QAAA,EAAA,IAAA,CAAK,KAAA,EACR,CAAA;AAAA,8BACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uFAAA,EACb,eAAK,KAAA,EACR;AAAA;AAAA,WAAA;AAAA,UAVK,IAAA,CAAK;AAAA,SAYb,CAAA,EAEL,CAAA;AAAA,QAEC,CAAC,WAAA,IAAe,WAAA,wBACd,MAAA,EAAA,EAAK,SAAA,EAAU,iCAAiC,QAAA,EAAA,WAAA,EAAY;AAAA;AAAA;AAAA,GAEjE;AAEJ","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"]}
@@ -0,0 +1,155 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ /**
4
+ * Newsletter Component
5
+ * Reusable newsletter subscription component with email validation and rate limiting.
6
+ * Uses GraphQL mutations via the WebSDKClient provider.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * import { NewsletterPage } from '@burdenoff/website-sdk/components/newsletter'
11
+ *
12
+ * function Newsletter() {
13
+ * return (
14
+ * <NewsletterPage
15
+ * productName="BigConsole"
16
+ * layout="centered"
17
+ * seoTitle="Subscribe to Newsletter"
18
+ * seoDescription="Stay updated with our latest news"
19
+ * seoKeywords="newsletter, updates, news"
20
+ * />
21
+ * )
22
+ * }
23
+ * ```
24
+ */
25
+ /**
26
+ * Newsletter page component configuration props
27
+ */
28
+ interface NewsletterPageProps {
29
+ /**
30
+ * Product name (used in title and branding).
31
+ * Falls back to SDK config productId if not provided.
32
+ */
33
+ productName?: string;
34
+ /**
35
+ * Layout variant
36
+ * @default 'centered'
37
+ */
38
+ layout?: "centered" | "split";
39
+ /**
40
+ * Rate limit attempts
41
+ * @default 3
42
+ */
43
+ rateLimitAttempts?: number;
44
+ /**
45
+ * Rate limit window in minutes
46
+ * @default 15
47
+ */
48
+ rateLimitWindowMinutes?: number;
49
+ /**
50
+ * Hero section heading
51
+ * @default 'Stay Updated'
52
+ */
53
+ heroHeading?: string;
54
+ /**
55
+ * Hero section subtitle
56
+ * @default 'Subscribe to our newsletter'
57
+ */
58
+ heroSubtitle?: string;
59
+ /**
60
+ * Hero section description
61
+ */
62
+ heroDescription?: string;
63
+ /**
64
+ * Features to display (for split layout)
65
+ */
66
+ features?: Array<{
67
+ icon: React.ReactNode;
68
+ title: string;
69
+ description: string;
70
+ }>;
71
+ /**
72
+ * Success message after subscription
73
+ * @default 'Successfully subscribed to newsletter!'
74
+ */
75
+ successMessage?: string;
76
+ /**
77
+ * Error message on failure
78
+ * @default 'Failed to subscribe. Please try again.'
79
+ */
80
+ errorMessage?: string;
81
+ /**
82
+ * Rate limit error message
83
+ */
84
+ rateLimitMessage?: string;
85
+ /**
86
+ * Custom CSS class for container
87
+ */
88
+ className?: string;
89
+ /**
90
+ * SEO: Page title (optional, for SEO meta tags)
91
+ */
92
+ seoTitle?: string;
93
+ /**
94
+ * SEO: Page description (optional, for SEO meta tags)
95
+ */
96
+ seoDescription?: string;
97
+ /**
98
+ * SEO: Keywords (optional, for SEO meta tags)
99
+ */
100
+ seoKeywords?: string;
101
+ /**
102
+ * SEO: OG Image URL (optional, for SEO meta tags)
103
+ */
104
+ seoImage?: string;
105
+ /**
106
+ * SEO: Canonical URL (optional, for SEO meta tags)
107
+ */
108
+ seoUrl?: string;
109
+ /**
110
+ * reCAPTCHA site key (optional, falls back to SDK config)
111
+ */
112
+ recaptchaSiteKey?: string;
113
+ }
114
+ declare function NewsletterPage({ productName, layout, rateLimitAttempts, rateLimitWindowMinutes, heroHeading, heroSubtitle, heroDescription, features, successMessage, errorMessage, rateLimitMessage, className, seoTitle, seoDescription, seoKeywords, seoImage, seoUrl, recaptchaSiteKey, }: NewsletterPageProps): react_jsx_runtime.JSX.Element;
115
+ interface NewsletterFormProps {
116
+ /**
117
+ * Layout variant
118
+ * @default 'inline'
119
+ */
120
+ variant?: "inline" | "stacked";
121
+ /**
122
+ * Show email label
123
+ * @default false
124
+ */
125
+ showLabel?: boolean;
126
+ /**
127
+ * Show description text
128
+ * @default false
129
+ */
130
+ showDescription?: boolean;
131
+ /**
132
+ * Description text
133
+ * @default 'Subscribe to our newsletter for updates'
134
+ */
135
+ description?: string;
136
+ /**
137
+ * Button text
138
+ * @default 'Subscribe'
139
+ */
140
+ buttonText?: string;
141
+ /**
142
+ * Custom CSS class
143
+ */
144
+ className?: string;
145
+ /**
146
+ * reCAPTCHA site key (optional, falls back to SDK config)
147
+ */
148
+ recaptchaSiteKey?: string;
149
+ }
150
+ /**
151
+ * Lightweight newsletter subscription form for inline use (e.g., footers)
152
+ */
153
+ declare function NewsletterForm({ variant, showLabel, showDescription, description, buttonText, className, recaptchaSiteKey, }: NewsletterFormProps): react_jsx_runtime.JSX.Element;
154
+
155
+ export { NewsletterForm, type NewsletterFormProps, NewsletterPage, type NewsletterPageProps };
@@ -0,0 +1,155 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ /**
4
+ * Newsletter Component
5
+ * Reusable newsletter subscription component with email validation and rate limiting.
6
+ * Uses GraphQL mutations via the WebSDKClient provider.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * import { NewsletterPage } from '@burdenoff/website-sdk/components/newsletter'
11
+ *
12
+ * function Newsletter() {
13
+ * return (
14
+ * <NewsletterPage
15
+ * productName="BigConsole"
16
+ * layout="centered"
17
+ * seoTitle="Subscribe to Newsletter"
18
+ * seoDescription="Stay updated with our latest news"
19
+ * seoKeywords="newsletter, updates, news"
20
+ * />
21
+ * )
22
+ * }
23
+ * ```
24
+ */
25
+ /**
26
+ * Newsletter page component configuration props
27
+ */
28
+ interface NewsletterPageProps {
29
+ /**
30
+ * Product name (used in title and branding).
31
+ * Falls back to SDK config productId if not provided.
32
+ */
33
+ productName?: string;
34
+ /**
35
+ * Layout variant
36
+ * @default 'centered'
37
+ */
38
+ layout?: "centered" | "split";
39
+ /**
40
+ * Rate limit attempts
41
+ * @default 3
42
+ */
43
+ rateLimitAttempts?: number;
44
+ /**
45
+ * Rate limit window in minutes
46
+ * @default 15
47
+ */
48
+ rateLimitWindowMinutes?: number;
49
+ /**
50
+ * Hero section heading
51
+ * @default 'Stay Updated'
52
+ */
53
+ heroHeading?: string;
54
+ /**
55
+ * Hero section subtitle
56
+ * @default 'Subscribe to our newsletter'
57
+ */
58
+ heroSubtitle?: string;
59
+ /**
60
+ * Hero section description
61
+ */
62
+ heroDescription?: string;
63
+ /**
64
+ * Features to display (for split layout)
65
+ */
66
+ features?: Array<{
67
+ icon: React.ReactNode;
68
+ title: string;
69
+ description: string;
70
+ }>;
71
+ /**
72
+ * Success message after subscription
73
+ * @default 'Successfully subscribed to newsletter!'
74
+ */
75
+ successMessage?: string;
76
+ /**
77
+ * Error message on failure
78
+ * @default 'Failed to subscribe. Please try again.'
79
+ */
80
+ errorMessage?: string;
81
+ /**
82
+ * Rate limit error message
83
+ */
84
+ rateLimitMessage?: string;
85
+ /**
86
+ * Custom CSS class for container
87
+ */
88
+ className?: string;
89
+ /**
90
+ * SEO: Page title (optional, for SEO meta tags)
91
+ */
92
+ seoTitle?: string;
93
+ /**
94
+ * SEO: Page description (optional, for SEO meta tags)
95
+ */
96
+ seoDescription?: string;
97
+ /**
98
+ * SEO: Keywords (optional, for SEO meta tags)
99
+ */
100
+ seoKeywords?: string;
101
+ /**
102
+ * SEO: OG Image URL (optional, for SEO meta tags)
103
+ */
104
+ seoImage?: string;
105
+ /**
106
+ * SEO: Canonical URL (optional, for SEO meta tags)
107
+ */
108
+ seoUrl?: string;
109
+ /**
110
+ * reCAPTCHA site key (optional, falls back to SDK config)
111
+ */
112
+ recaptchaSiteKey?: string;
113
+ }
114
+ declare function NewsletterPage({ productName, layout, rateLimitAttempts, rateLimitWindowMinutes, heroHeading, heroSubtitle, heroDescription, features, successMessage, errorMessage, rateLimitMessage, className, seoTitle, seoDescription, seoKeywords, seoImage, seoUrl, recaptchaSiteKey, }: NewsletterPageProps): react_jsx_runtime.JSX.Element;
115
+ interface NewsletterFormProps {
116
+ /**
117
+ * Layout variant
118
+ * @default 'inline'
119
+ */
120
+ variant?: "inline" | "stacked";
121
+ /**
122
+ * Show email label
123
+ * @default false
124
+ */
125
+ showLabel?: boolean;
126
+ /**
127
+ * Show description text
128
+ * @default false
129
+ */
130
+ showDescription?: boolean;
131
+ /**
132
+ * Description text
133
+ * @default 'Subscribe to our newsletter for updates'
134
+ */
135
+ description?: string;
136
+ /**
137
+ * Button text
138
+ * @default 'Subscribe'
139
+ */
140
+ buttonText?: string;
141
+ /**
142
+ * Custom CSS class
143
+ */
144
+ className?: string;
145
+ /**
146
+ * reCAPTCHA site key (optional, falls back to SDK config)
147
+ */
148
+ recaptchaSiteKey?: string;
149
+ }
150
+ /**
151
+ * Lightweight newsletter subscription form for inline use (e.g., footers)
152
+ */
153
+ declare function NewsletterForm({ variant, showLabel, showDescription, description, buttonText, className, recaptchaSiteKey, }: NewsletterFormProps): react_jsx_runtime.JSX.Element;
154
+
155
+ export { NewsletterForm, type NewsletterFormProps, NewsletterPage, type NewsletterPageProps };