@braintwopoint0/playback-commons 0.1.21 → 0.2.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/email/index.d.ts +44 -0
- package/dist/email/index.js +46 -0
- package/dist/email/index.js.map +1 -0
- package/dist/ui/index.d.ts +112 -2
- package/dist/ui/index.js +497 -57
- package/dist/ui/index.js.map +1 -1
- package/package.json +14 -3
package/dist/ui/index.js
CHANGED
|
@@ -2364,69 +2364,507 @@ function LumaSpin() {
|
|
|
2364
2364
|
}
|
|
2365
2365
|
|
|
2366
2366
|
// src/ui/footer.tsx
|
|
2367
|
+
import * as React26 from "react";
|
|
2367
2368
|
import Image2 from "next/image";
|
|
2368
2369
|
import Link2 from "next/link";
|
|
2369
2370
|
import { jsx as jsx35, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2371
|
+
var DEFAULT_SOCIALS = [
|
|
2372
|
+
{
|
|
2373
|
+
label: "Instagram",
|
|
2374
|
+
href: "https://www.instagram.com/playback_global",
|
|
2375
|
+
src: "/assets/instagram.png"
|
|
2376
|
+
},
|
|
2377
|
+
{
|
|
2378
|
+
label: "YouTube",
|
|
2379
|
+
href: "https://youtube.com/@playback_global",
|
|
2380
|
+
src: "/assets/youtube.png"
|
|
2381
|
+
},
|
|
2382
|
+
{
|
|
2383
|
+
label: "TikTok",
|
|
2384
|
+
href: "https://www.tiktok.com/@playback_global",
|
|
2385
|
+
src: "/assets/tiktok.png"
|
|
2386
|
+
},
|
|
2387
|
+
{
|
|
2388
|
+
label: "LinkedIn",
|
|
2389
|
+
href: "https://www.linkedin.com/company/playbacksports/",
|
|
2390
|
+
src: "/assets/linkedin.png"
|
|
2391
|
+
}
|
|
2392
|
+
];
|
|
2393
|
+
function NewsletterForm({
|
|
2394
|
+
onSubmit
|
|
2395
|
+
}) {
|
|
2396
|
+
const [email, setEmail] = React26.useState("");
|
|
2397
|
+
const [state, setState] = React26.useState("idle");
|
|
2398
|
+
const handle = async (e) => {
|
|
2399
|
+
e.preventDefault();
|
|
2400
|
+
const ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim());
|
|
2401
|
+
if (!ok) {
|
|
2402
|
+
setState("error");
|
|
2403
|
+
return;
|
|
2404
|
+
}
|
|
2405
|
+
try {
|
|
2406
|
+
if (onSubmit) await onSubmit(email.trim());
|
|
2407
|
+
setState("sent");
|
|
2408
|
+
setEmail("");
|
|
2409
|
+
} catch {
|
|
2410
|
+
setState("error");
|
|
2411
|
+
}
|
|
2412
|
+
};
|
|
2413
|
+
return /* @__PURE__ */ jsxs19(
|
|
2414
|
+
"form",
|
|
2415
|
+
{
|
|
2416
|
+
onSubmit: handle,
|
|
2417
|
+
noValidate: true,
|
|
2418
|
+
"aria-label": "Subscribe to updates",
|
|
2419
|
+
className: "w-full max-w-md",
|
|
2420
|
+
children: [
|
|
2421
|
+
/* @__PURE__ */ jsx35(
|
|
2422
|
+
"label",
|
|
2423
|
+
{
|
|
2424
|
+
htmlFor: "footer-newsletter",
|
|
2425
|
+
className: "block text-[12px] uppercase tracking-[0.14em] text-[rgba(214,213,201,0.44)] mb-3",
|
|
2426
|
+
children: "Stay in the loop"
|
|
2427
|
+
}
|
|
2428
|
+
),
|
|
2429
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex flex-col sm:flex-row gap-2", children: [
|
|
2430
|
+
/* @__PURE__ */ jsx35(
|
|
2431
|
+
"input",
|
|
2432
|
+
{
|
|
2433
|
+
id: "footer-newsletter",
|
|
2434
|
+
type: "email",
|
|
2435
|
+
inputMode: "email",
|
|
2436
|
+
autoComplete: "email",
|
|
2437
|
+
required: true,
|
|
2438
|
+
value: email,
|
|
2439
|
+
onChange: (e) => {
|
|
2440
|
+
setEmail(e.target.value);
|
|
2441
|
+
if (state !== "idle") setState("idle");
|
|
2442
|
+
},
|
|
2443
|
+
placeholder: "you@club.com",
|
|
2444
|
+
"aria-invalid": state === "error",
|
|
2445
|
+
"aria-describedby": "footer-newsletter-feedback",
|
|
2446
|
+
className: cn(
|
|
2447
|
+
"flex-1 h-11 rounded-full bg-[var(--surface-1,#0f1512)] border px-4 text-[14px] text-[var(--timberwolf)] placeholder:text-[rgba(214,213,201,0.44)]",
|
|
2448
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--timberwolf)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--night)]",
|
|
2449
|
+
state === "error" ? "border-[rgba(237,106,106,0.5)]" : "border-[rgba(214,213,201,0.08)]"
|
|
2450
|
+
)
|
|
2451
|
+
}
|
|
2452
|
+
),
|
|
2453
|
+
/* @__PURE__ */ jsx35(
|
|
2454
|
+
"button",
|
|
2410
2455
|
{
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
width: 50,
|
|
2415
|
-
className: "h-9 w-9"
|
|
2456
|
+
type: "submit",
|
|
2457
|
+
className: "inline-flex items-center justify-center h-11 px-5 rounded-full bg-[var(--timberwolf)] text-[var(--night)] text-[14px] font-medium hover:bg-[var(--ash-grey)] transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--timberwolf)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--night)]",
|
|
2458
|
+
children: "Subscribe"
|
|
2416
2459
|
}
|
|
2417
2460
|
)
|
|
2418
|
-
}
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2461
|
+
] }),
|
|
2462
|
+
/* @__PURE__ */ jsxs19(
|
|
2463
|
+
"p",
|
|
2464
|
+
{
|
|
2465
|
+
id: "footer-newsletter-feedback",
|
|
2466
|
+
className: cn(
|
|
2467
|
+
"mt-2 text-[13px] min-h-[1.25rem]",
|
|
2468
|
+
state === "sent" && "text-[var(--timberwolf)]",
|
|
2469
|
+
state === "error" && "text-[rgb(237,106,106)]",
|
|
2470
|
+
state === "idle" && "text-[rgba(214,213,201,0.44)]"
|
|
2471
|
+
),
|
|
2472
|
+
role: state === "error" ? "alert" : void 0,
|
|
2473
|
+
children: [
|
|
2474
|
+
state === "sent" && "Thanks \u2014 we\u2019ll be in touch.",
|
|
2475
|
+
state === "error" && "Please enter a valid email address.",
|
|
2476
|
+
state === "idle" && "Monthly notes on product, network, and matches."
|
|
2477
|
+
]
|
|
2478
|
+
}
|
|
2479
|
+
)
|
|
2480
|
+
]
|
|
2481
|
+
}
|
|
2482
|
+
);
|
|
2483
|
+
}
|
|
2484
|
+
function FooterLinkItem({ link }) {
|
|
2485
|
+
const classes = "text-[14px] text-[rgba(214,213,201,0.64)] hover:text-[var(--timberwolf)] transition-colors rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--timberwolf)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--surface-0,#0a100d)]";
|
|
2486
|
+
if (link.external) {
|
|
2487
|
+
return /* @__PURE__ */ jsx35(
|
|
2488
|
+
"a",
|
|
2489
|
+
{
|
|
2490
|
+
href: link.href,
|
|
2491
|
+
target: "_blank",
|
|
2492
|
+
rel: "noopener noreferrer",
|
|
2493
|
+
className: classes,
|
|
2494
|
+
children: link.label
|
|
2495
|
+
}
|
|
2496
|
+
);
|
|
2497
|
+
}
|
|
2498
|
+
return /* @__PURE__ */ jsx35(Link2, { href: link.href, className: classes, children: link.label });
|
|
2499
|
+
}
|
|
2500
|
+
function Footer({
|
|
2501
|
+
columns,
|
|
2502
|
+
socials = DEFAULT_SOCIALS,
|
|
2503
|
+
newsletter = false,
|
|
2504
|
+
tagline = "You PLAY. We BACK.",
|
|
2505
|
+
showTagline = true,
|
|
2506
|
+
logoSrc = "/branding/PLAYBACK-Text.png",
|
|
2507
|
+
logoAlt = "PLAYBACK",
|
|
2508
|
+
siteName = "PLAYBACK",
|
|
2509
|
+
creditHref = "https://www.braintwopoint0.com",
|
|
2510
|
+
creditLabel = "Built by BRAIN2.0",
|
|
2511
|
+
newsletterAction,
|
|
2512
|
+
className
|
|
2513
|
+
} = {}) {
|
|
2514
|
+
const hasColumns = columns && columns.length > 0;
|
|
2515
|
+
return /* @__PURE__ */ jsxs19(
|
|
2516
|
+
"footer",
|
|
2517
|
+
{
|
|
2518
|
+
id: "footer",
|
|
2519
|
+
className: cn(
|
|
2520
|
+
"mt-24 border-t border-[rgba(214,213,201,0.08)] bg-[var(--surface-0,#0a100d)]",
|
|
2521
|
+
className
|
|
2522
|
+
),
|
|
2523
|
+
"aria-labelledby": "footer-heading",
|
|
2524
|
+
children: [
|
|
2525
|
+
/* @__PURE__ */ jsxs19("h2", { id: "footer-heading", className: "sr-only", children: [
|
|
2526
|
+
siteName,
|
|
2527
|
+
" site footer"
|
|
2528
|
+
] }),
|
|
2529
|
+
/* @__PURE__ */ jsxs19("div", { className: "mx-auto max-w-[1400px] px-6 sm:px-10", children: [
|
|
2530
|
+
/* @__PURE__ */ jsxs19(
|
|
2531
|
+
"div",
|
|
2532
|
+
{
|
|
2533
|
+
className: cn(
|
|
2534
|
+
"grid grid-cols-1 gap-12 py-16",
|
|
2535
|
+
newsletter ? "lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)] lg:items-end" : ""
|
|
2536
|
+
),
|
|
2537
|
+
children: [
|
|
2538
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-8", children: [
|
|
2539
|
+
/* @__PURE__ */ jsx35(
|
|
2540
|
+
Link2,
|
|
2541
|
+
{
|
|
2542
|
+
href: "/",
|
|
2543
|
+
className: "inline-flex items-center gap-3 rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--timberwolf)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--night)]",
|
|
2544
|
+
"aria-label": `${siteName} home`,
|
|
2545
|
+
children: /* @__PURE__ */ jsx35(
|
|
2546
|
+
Image2,
|
|
2547
|
+
{
|
|
2548
|
+
src: logoSrc,
|
|
2549
|
+
alt: logoAlt,
|
|
2550
|
+
width: 200,
|
|
2551
|
+
height: 40,
|
|
2552
|
+
className: "h-7 w-auto"
|
|
2553
|
+
}
|
|
2554
|
+
)
|
|
2555
|
+
}
|
|
2556
|
+
),
|
|
2557
|
+
showTagline && tagline ? /* @__PURE__ */ jsx35("p", { className: "font-semibold text-[clamp(28px,3.6vw,44px)] leading-[1.05] tracking-[-0.035em] text-[var(--timberwolf)] max-w-[18ch]", children: tagline }) : null
|
|
2558
|
+
] }),
|
|
2559
|
+
newsletter ? /* @__PURE__ */ jsx35("div", { className: "lg:justify-self-end w-full lg:max-w-md", children: /* @__PURE__ */ jsx35(NewsletterForm, { onSubmit: newsletterAction }) }) : null
|
|
2560
|
+
]
|
|
2561
|
+
}
|
|
2562
|
+
),
|
|
2563
|
+
hasColumns ? /* @__PURE__ */ jsx35("div", { className: "border-t border-[rgba(214,213,201,0.08)] py-14", children: /* @__PURE__ */ jsx35("div", { className: "grid grid-cols-2 gap-x-6 gap-y-10 md:grid-cols-4", children: columns.map((col) => /* @__PURE__ */ jsxs19("nav", { "aria-label": col.title, children: [
|
|
2564
|
+
/* @__PURE__ */ jsx35("p", { className: "text-[12px] uppercase tracking-[0.14em] text-[rgba(214,213,201,0.44)] mb-4", children: col.title }),
|
|
2565
|
+
/* @__PURE__ */ jsx35("ul", { className: "flex flex-col gap-3", children: col.links.map((link) => /* @__PURE__ */ jsx35("li", { children: /* @__PURE__ */ jsx35(FooterLinkItem, { link }) }, `${col.title}-${link.label}`)) })
|
|
2566
|
+
] }, col.title)) }) }) : null,
|
|
2567
|
+
/* @__PURE__ */ jsxs19("div", { className: "border-t border-[rgba(214,213,201,0.08)] py-6 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
2568
|
+
/* @__PURE__ */ jsx35("ul", { className: "flex items-center gap-2", children: socials.map(({ label, href, src }) => /* @__PURE__ */ jsx35("li", { children: /* @__PURE__ */ jsx35(
|
|
2569
|
+
"a",
|
|
2570
|
+
{
|
|
2571
|
+
href,
|
|
2572
|
+
target: "_blank",
|
|
2573
|
+
rel: "noopener noreferrer",
|
|
2574
|
+
"aria-label": `${siteName} on ${label}`,
|
|
2575
|
+
className: "inline-flex items-center justify-center h-9 w-9 rounded-full hover:bg-[var(--surface-1,#0f1512)] transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--timberwolf)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--night)]",
|
|
2576
|
+
children: /* @__PURE__ */ jsx35(
|
|
2577
|
+
Image2,
|
|
2578
|
+
{
|
|
2579
|
+
src,
|
|
2580
|
+
alt: "",
|
|
2581
|
+
width: 20,
|
|
2582
|
+
height: 20,
|
|
2583
|
+
className: "h-[18px] w-[18px] object-contain opacity-80 hover:opacity-100 transition-opacity"
|
|
2584
|
+
}
|
|
2585
|
+
)
|
|
2586
|
+
}
|
|
2587
|
+
) }, label)) }),
|
|
2588
|
+
/* @__PURE__ */ jsxs19("p", { className: "text-[13px] text-[rgba(214,213,201,0.44)] order-last sm:order-none", children: [
|
|
2589
|
+
"\xA9 ",
|
|
2590
|
+
(/* @__PURE__ */ new Date()).getFullYear(),
|
|
2591
|
+
" ",
|
|
2592
|
+
siteName,
|
|
2593
|
+
". All rights reserved."
|
|
2594
|
+
] }),
|
|
2595
|
+
/* @__PURE__ */ jsx35(
|
|
2596
|
+
"a",
|
|
2597
|
+
{
|
|
2598
|
+
href: creditHref,
|
|
2599
|
+
target: "_blank",
|
|
2600
|
+
rel: "noopener noreferrer",
|
|
2601
|
+
className: "text-[13px] text-[rgba(214,213,201,0.44)] hover:text-[var(--timberwolf)] transition-colors rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--timberwolf)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--night)]",
|
|
2602
|
+
children: creditLabel
|
|
2603
|
+
}
|
|
2604
|
+
)
|
|
2605
|
+
] })
|
|
2606
|
+
] })
|
|
2607
|
+
]
|
|
2608
|
+
}
|
|
2609
|
+
);
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
// src/ui/footer-credits-bar.tsx
|
|
2613
|
+
import Image3 from "next/image";
|
|
2614
|
+
import { Fragment as Fragment5, jsx as jsx36, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2615
|
+
var DEFAULT_SOCIALS2 = [
|
|
2616
|
+
{
|
|
2617
|
+
label: "Instagram",
|
|
2618
|
+
href: "https://www.instagram.com/playback_global",
|
|
2619
|
+
src: "/assets/instagram.png"
|
|
2620
|
+
},
|
|
2621
|
+
{
|
|
2622
|
+
label: "YouTube",
|
|
2623
|
+
href: "https://youtube.com/@playback_global",
|
|
2624
|
+
src: "/assets/youtube.png"
|
|
2625
|
+
},
|
|
2626
|
+
{
|
|
2627
|
+
label: "TikTok",
|
|
2628
|
+
href: "https://www.tiktok.com/@playback_global",
|
|
2629
|
+
src: "/assets/tiktok.png"
|
|
2630
|
+
},
|
|
2631
|
+
{
|
|
2632
|
+
label: "LinkedIn",
|
|
2633
|
+
href: "https://www.linkedin.com/company/playbacksports/",
|
|
2634
|
+
src: "/assets/linkedin.png"
|
|
2635
|
+
}
|
|
2636
|
+
];
|
|
2637
|
+
function FooterCreditsBar({
|
|
2638
|
+
socials = DEFAULT_SOCIALS2,
|
|
2639
|
+
companyName = "PLAYBACK",
|
|
2640
|
+
creditHref = "https://www.braintwopoint0.com",
|
|
2641
|
+
showCredit = true,
|
|
2642
|
+
copyrightYear,
|
|
2643
|
+
className
|
|
2644
|
+
} = {}) {
|
|
2645
|
+
const year = copyrightYear ?? (/* @__PURE__ */ new Date()).getFullYear();
|
|
2646
|
+
return /* @__PURE__ */ jsxs20(
|
|
2647
|
+
"div",
|
|
2648
|
+
{
|
|
2649
|
+
className: cn(
|
|
2650
|
+
"border-t py-6 grid grid-cols-1 gap-4 sm:grid-cols-2 sm:items-center",
|
|
2651
|
+
"border-[rgba(214,213,201,0.08)]",
|
|
2652
|
+
className
|
|
2653
|
+
),
|
|
2654
|
+
children: [
|
|
2655
|
+
/* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-4 sm:justify-self-start", children: [
|
|
2656
|
+
/* @__PURE__ */ jsx36("ul", { className: "flex items-center gap-2", children: socials.map(({ label, href, src }) => /* @__PURE__ */ jsx36("li", { children: /* @__PURE__ */ jsx36(
|
|
2657
|
+
"a",
|
|
2658
|
+
{
|
|
2659
|
+
href,
|
|
2660
|
+
target: "_blank",
|
|
2661
|
+
rel: "noopener noreferrer",
|
|
2662
|
+
"aria-label": `${companyName} on ${label}`,
|
|
2663
|
+
className: cn(
|
|
2664
|
+
"inline-flex items-center justify-center h-10 w-10 rounded-full",
|
|
2665
|
+
"hover:bg-[var(--surface-1,#0f1512)] transition-colors",
|
|
2666
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--timberwolf)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--night)]"
|
|
2667
|
+
),
|
|
2668
|
+
children: /* @__PURE__ */ jsx36(
|
|
2669
|
+
Image3,
|
|
2670
|
+
{
|
|
2671
|
+
src,
|
|
2672
|
+
alt: "",
|
|
2673
|
+
width: 24,
|
|
2674
|
+
height: 24,
|
|
2675
|
+
className: "h-[22px] w-[22px] object-contain opacity-80 hover:opacity-100 transition-opacity"
|
|
2676
|
+
}
|
|
2677
|
+
)
|
|
2678
|
+
}
|
|
2679
|
+
) }, label)) }),
|
|
2680
|
+
showCredit ? /* @__PURE__ */ jsxs20(Fragment5, { children: [
|
|
2681
|
+
/* @__PURE__ */ jsx36(
|
|
2682
|
+
"span",
|
|
2683
|
+
{
|
|
2684
|
+
"aria-hidden": true,
|
|
2685
|
+
className: "h-5 w-px bg-[rgba(214,213,201,0.16)] flex-shrink-0"
|
|
2686
|
+
}
|
|
2687
|
+
),
|
|
2688
|
+
/* @__PURE__ */ jsx36(
|
|
2689
|
+
"a",
|
|
2690
|
+
{
|
|
2691
|
+
href: creditHref,
|
|
2692
|
+
target: "_blank",
|
|
2693
|
+
rel: "noopener noreferrer",
|
|
2694
|
+
"aria-label": "Built by BRAIN2.0",
|
|
2695
|
+
className: cn(
|
|
2696
|
+
"text-[13px] text-[rgba(214,213,201,0.44)] hover:text-[var(--timberwolf)] transition-colors rounded-sm",
|
|
2697
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--timberwolf)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--night)]",
|
|
2698
|
+
"whitespace-nowrap"
|
|
2699
|
+
),
|
|
2700
|
+
children: /* @__PURE__ */ jsxs20("span", { "aria-hidden": true, children: [
|
|
2701
|
+
"Built by",
|
|
2702
|
+
" ",
|
|
2703
|
+
/* @__PURE__ */ jsxs20("span", { style: { fontFamily: "AvertaStd-Semibold" }, children: [
|
|
2704
|
+
"BRAIN",
|
|
2705
|
+
/* @__PURE__ */ jsx36("span", { style: { fontFamily: "AvertaStd-Thin" }, children: "2.0" })
|
|
2706
|
+
] })
|
|
2707
|
+
] })
|
|
2708
|
+
}
|
|
2709
|
+
)
|
|
2710
|
+
] }) : null
|
|
2711
|
+
] }),
|
|
2712
|
+
/* @__PURE__ */ jsxs20("p", { className: "text-[13px] text-[rgba(214,213,201,0.44)] text-center sm:text-right sm:justify-self-end", children: [
|
|
2713
|
+
"\xA9 ",
|
|
2714
|
+
year,
|
|
2715
|
+
" ",
|
|
2716
|
+
companyName,
|
|
2717
|
+
". All rights reserved."
|
|
2718
|
+
] })
|
|
2719
|
+
]
|
|
2720
|
+
}
|
|
2721
|
+
);
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
// src/ui/newsletter-form.tsx
|
|
2725
|
+
import * as React27 from "react";
|
|
2726
|
+
import { jsx as jsx37, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2727
|
+
function NewsletterForm2({
|
|
2728
|
+
endpoint = "/api/newsletter/subscribe",
|
|
2729
|
+
source = "footer",
|
|
2730
|
+
role,
|
|
2731
|
+
placeholder = "you@club.com",
|
|
2732
|
+
ariaLabel = "Subscribe to updates",
|
|
2733
|
+
submitLabel = "Subscribe",
|
|
2734
|
+
sendingLabel = "Subscribing\u2026",
|
|
2735
|
+
className
|
|
2736
|
+
}) {
|
|
2737
|
+
const [email, setEmail] = React27.useState("");
|
|
2738
|
+
const [website, setWebsite] = React27.useState("");
|
|
2739
|
+
const [state, setState] = React27.useState("idle");
|
|
2740
|
+
const inFlight = React27.useRef(false);
|
|
2741
|
+
const onSubmit = async (e) => {
|
|
2742
|
+
e.preventDefault();
|
|
2743
|
+
if (inFlight.current) return;
|
|
2744
|
+
const trimmed = email.trim();
|
|
2745
|
+
const ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed);
|
|
2746
|
+
if (!ok) {
|
|
2747
|
+
setState("error");
|
|
2748
|
+
return;
|
|
2749
|
+
}
|
|
2750
|
+
inFlight.current = true;
|
|
2751
|
+
setState("sending");
|
|
2752
|
+
try {
|
|
2753
|
+
const res = await fetch(endpoint, {
|
|
2754
|
+
method: "POST",
|
|
2755
|
+
headers: { "Content-Type": "application/json" },
|
|
2756
|
+
body: JSON.stringify({
|
|
2757
|
+
email: trimmed,
|
|
2758
|
+
source,
|
|
2759
|
+
...role ? { role } : {},
|
|
2760
|
+
website
|
|
2761
|
+
})
|
|
2762
|
+
});
|
|
2763
|
+
if (res.ok) {
|
|
2764
|
+
setState("sent");
|
|
2765
|
+
setEmail("");
|
|
2766
|
+
} else if (res.status === 429) {
|
|
2767
|
+
setState("rate_limited");
|
|
2768
|
+
} else {
|
|
2769
|
+
setState("error");
|
|
2770
|
+
}
|
|
2771
|
+
} catch {
|
|
2772
|
+
setState("error");
|
|
2773
|
+
} finally {
|
|
2774
|
+
inFlight.current = false;
|
|
2775
|
+
}
|
|
2776
|
+
};
|
|
2777
|
+
const feedbackId = React27.useId();
|
|
2778
|
+
const inputId = React27.useId();
|
|
2779
|
+
return /* @__PURE__ */ jsxs21(
|
|
2780
|
+
"form",
|
|
2781
|
+
{
|
|
2782
|
+
onSubmit,
|
|
2783
|
+
noValidate: true,
|
|
2784
|
+
"aria-label": ariaLabel,
|
|
2785
|
+
className: cn("w-full max-w-md", className),
|
|
2786
|
+
children: [
|
|
2787
|
+
/* @__PURE__ */ jsx37("label", { htmlFor: inputId, className: "sr-only", children: "Email address" }),
|
|
2788
|
+
/* @__PURE__ */ jsxs21(
|
|
2789
|
+
"div",
|
|
2790
|
+
{
|
|
2791
|
+
"aria-hidden": true,
|
|
2792
|
+
className: "absolute left-[-10000px] top-auto h-px w-px overflow-hidden",
|
|
2793
|
+
children: [
|
|
2794
|
+
/* @__PURE__ */ jsx37("label", { htmlFor: `${inputId}-website`, children: "Website" }),
|
|
2795
|
+
/* @__PURE__ */ jsx37(
|
|
2796
|
+
"input",
|
|
2797
|
+
{
|
|
2798
|
+
type: "text",
|
|
2799
|
+
id: `${inputId}-website`,
|
|
2800
|
+
name: "website",
|
|
2801
|
+
tabIndex: -1,
|
|
2802
|
+
autoComplete: "off",
|
|
2803
|
+
value: website,
|
|
2804
|
+
onChange: (e) => setWebsite(e.target.value)
|
|
2805
|
+
}
|
|
2806
|
+
)
|
|
2807
|
+
]
|
|
2808
|
+
}
|
|
2809
|
+
),
|
|
2810
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex flex-col sm:flex-row gap-2", children: [
|
|
2811
|
+
/* @__PURE__ */ jsx37(
|
|
2812
|
+
"input",
|
|
2813
|
+
{
|
|
2814
|
+
id: inputId,
|
|
2815
|
+
type: "email",
|
|
2816
|
+
inputMode: "email",
|
|
2817
|
+
autoComplete: "email",
|
|
2818
|
+
required: true,
|
|
2819
|
+
disabled: state === "sending",
|
|
2820
|
+
value: email,
|
|
2821
|
+
onChange: (e) => {
|
|
2822
|
+
setEmail(e.target.value);
|
|
2823
|
+
if (state === "error" || state === "rate_limited") setState("idle");
|
|
2824
|
+
},
|
|
2825
|
+
placeholder,
|
|
2826
|
+
"aria-invalid": state === "error",
|
|
2827
|
+
"aria-describedby": feedbackId,
|
|
2828
|
+
className: cn(
|
|
2829
|
+
"flex-1 h-11 rounded-full bg-[var(--surface-1,#0f1512)] border px-4 text-[14px] text-[var(--timberwolf)] placeholder:text-[rgba(214,213,201,0.44)]",
|
|
2830
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--timberwolf)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--night)]",
|
|
2831
|
+
"disabled:opacity-60",
|
|
2832
|
+
state === "error" ? "border-[rgba(237,106,106,0.5)]" : "border-[rgba(214,213,201,0.08)]"
|
|
2833
|
+
)
|
|
2834
|
+
}
|
|
2835
|
+
),
|
|
2836
|
+
/* @__PURE__ */ jsx37(
|
|
2837
|
+
"button",
|
|
2838
|
+
{
|
|
2839
|
+
type: "submit",
|
|
2840
|
+
disabled: state === "sending",
|
|
2841
|
+
className: "inline-flex items-center justify-center h-11 px-5 rounded-full bg-[var(--timberwolf)] text-[var(--night)] text-[14px] font-medium hover:bg-[var(--ash-grey)] transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--timberwolf)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--night)] disabled:opacity-60 disabled:cursor-not-allowed",
|
|
2842
|
+
children: state === "sending" ? sendingLabel : submitLabel
|
|
2843
|
+
}
|
|
2844
|
+
)
|
|
2845
|
+
] }),
|
|
2846
|
+
/* @__PURE__ */ jsxs21(
|
|
2847
|
+
"p",
|
|
2848
|
+
{
|
|
2849
|
+
id: feedbackId,
|
|
2850
|
+
"aria-live": "polite",
|
|
2851
|
+
className: cn(
|
|
2852
|
+
"mt-2 text-[13px] min-h-[1.25rem]",
|
|
2853
|
+
state === "sent" && "text-[var(--timberwolf)]",
|
|
2854
|
+
(state === "error" || state === "rate_limited") && "text-[rgb(237,106,106)]",
|
|
2855
|
+
(state === "idle" || state === "sending") && "text-[rgba(214,213,201,0.44)]"
|
|
2856
|
+
),
|
|
2857
|
+
role: state === "error" || state === "rate_limited" ? "alert" : void 0,
|
|
2858
|
+
children: [
|
|
2859
|
+
state === "sent" && "Thanks \u2014 we\u2019ll be in touch.",
|
|
2860
|
+
state === "error" && "Please enter a valid email address.",
|
|
2861
|
+
state === "rate_limited" && "Too many attempts. Try again in a minute."
|
|
2862
|
+
]
|
|
2863
|
+
}
|
|
2864
|
+
)
|
|
2865
|
+
]
|
|
2866
|
+
}
|
|
2867
|
+
);
|
|
2430
2868
|
}
|
|
2431
2869
|
export {
|
|
2432
2870
|
AnimatedTooltip,
|
|
@@ -2470,6 +2908,7 @@ export {
|
|
|
2470
2908
|
FadeIn,
|
|
2471
2909
|
FlipWords,
|
|
2472
2910
|
Footer,
|
|
2911
|
+
FooterCreditsBar,
|
|
2473
2912
|
HeroHighlight,
|
|
2474
2913
|
Highlight,
|
|
2475
2914
|
HoverCard,
|
|
@@ -2479,6 +2918,7 @@ export {
|
|
|
2479
2918
|
Input,
|
|
2480
2919
|
Label,
|
|
2481
2920
|
LumaSpin,
|
|
2921
|
+
NewsletterForm2 as NewsletterForm,
|
|
2482
2922
|
PageShell,
|
|
2483
2923
|
Popover,
|
|
2484
2924
|
PopoverAnchor,
|