@saasflare/ui 3.2.0 → 3.3.0
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/index.d.mts +1131 -2
- package/dist/index.d.ts +1131 -2
- package/dist/index.js +2178 -4
- package/dist/index.mjs +2140 -9
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3,15 +3,15 @@ import { Calendar } from './chunk-XNDTCYSO.mjs';
|
|
|
3
3
|
import { buttonVariants, Button } from './chunk-2ONA6OMO.mjs';
|
|
4
4
|
export { Button, buttonVariants } from './chunk-2ONA6OMO.mjs';
|
|
5
5
|
export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './chunk-5C65JNGY.mjs';
|
|
6
|
-
import { useSaasflareMotion, springGentle, springBouncy, spring } from './chunk-OZAWULTM.mjs';
|
|
6
|
+
import { useSaasflareMotion, springGentle, springBouncy, spring, noMotion } from './chunk-OZAWULTM.mjs';
|
|
7
7
|
export { fadeIn, noMotion, scaleIn, slideDown, slideUp, spring, springBouncy, springGentle, springStiff, useSaasflareMotion } from './chunk-OZAWULTM.mjs';
|
|
8
|
-
import { CaretDownIcon, CheckIcon, CaretUpIcon, CircleIcon, CaretRightIcon, XIcon, CircleNotchIcon, XCircleIcon, WarningIcon, InfoIcon, CheckCircleIcon, DotsThreeIcon, MagnifyingGlassIcon, CaretLeftIcon, SidebarSimpleIcon, ArrowUpIcon, TiktokLogoIcon, DribbbleLogoIcon, GitlabLogoIcon, StripeLogoIcon, PaypalLogoIcon, RedditLogoIcon, SlackLogoIcon, MediumLogoIcon, LinkedinLogoIcon, FacebookLogoIcon, DiscordLogoIcon, XLogoIcon, MicrosoftOutlookLogoIcon, AppleLogoIcon, GithubLogoIcon, GoogleLogoIcon, SunIcon, MoonIcon, MonitorIcon } from './chunk-GI6VN7XU.mjs';
|
|
8
|
+
import { CaretDownIcon, CheckIcon, CaretUpIcon, CircleIcon, CaretRightIcon, XIcon, CircleNotchIcon, XCircleIcon, WarningIcon, InfoIcon, CheckCircleIcon, DotsThreeIcon, MagnifyingGlassIcon, CaretLeftIcon, SidebarSimpleIcon, PauseIcon, PlayIcon, ArrowUpIcon, TiktokLogoIcon, DribbbleLogoIcon, GitlabLogoIcon, StripeLogoIcon, PaypalLogoIcon, RedditLogoIcon, SlackLogoIcon, MediumLogoIcon, LinkedinLogoIcon, FacebookLogoIcon, DiscordLogoIcon, XLogoIcon, MicrosoftOutlookLogoIcon, AppleLogoIcon, GithubLogoIcon, GoogleLogoIcon, SunIcon, MoonIcon, MonitorIcon } from './chunk-GI6VN7XU.mjs';
|
|
9
9
|
export { ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, CaretDownIcon, CaretLeftIcon, CaretRightIcon, CaretUpIcon, CheckCircleIcon, CheckIcon, CircleIcon, CircleNotchIcon, DotsSixVerticalIcon, DotsThreeIcon, IconBase, InfoIcon, MagnifyingGlassIcon, MinusIcon, MonitorIcon, MoonIcon, PauseIcon, PlayIcon, QuotesIcon, SidebarSimpleIcon, SunIcon, WarningIcon, XCircleIcon, XIcon } from './chunk-GI6VN7XU.mjs';
|
|
10
|
-
import { useSaasflareProps, cn } from './chunk-RMQBB72G.mjs';
|
|
10
|
+
import { useSaasflareProps, cn, useReducedMotion } from './chunk-RMQBB72G.mjs';
|
|
11
11
|
export { SaasflareProvider, SaasflareScript, SaasflareShell, SmoothScrollProvider, cn, useAnimation, useLocalStorage, useReducedMotion, useSaasflareProps, useSaasflareTheme } from './chunk-RMQBB72G.mjs';
|
|
12
12
|
import * as React5 from 'react';
|
|
13
|
-
import React5__default, { useState, useCallback, useMemo, useRef, useEffect, Suspense } from 'react';
|
|
14
|
-
import { m, useMotionValue, useSpring, useTransform, AnimatePresence } from 'motion/react';
|
|
13
|
+
import React5__default, { createContext, useState, useCallback, useMemo, useRef, useEffect, Children, Suspense, useContext } from 'react';
|
|
14
|
+
import { m, useMotionValue, useSpring, useTransform, AnimatePresence, useInView, useScroll } from 'motion/react';
|
|
15
15
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
16
16
|
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
|
|
17
17
|
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
@@ -294,6 +294,30 @@ function useFocusTrap(active) {
|
|
|
294
294
|
}, [active]);
|
|
295
295
|
return setRef;
|
|
296
296
|
}
|
|
297
|
+
function useCountdown(target) {
|
|
298
|
+
const targetMs = new Date(target).getTime();
|
|
299
|
+
const calculate = () => {
|
|
300
|
+
const diff = Math.max(0, targetMs - Date.now());
|
|
301
|
+
return {
|
|
302
|
+
days: Math.floor(diff / (1e3 * 60 * 60 * 24)),
|
|
303
|
+
hours: Math.floor(diff / (1e3 * 60 * 60) % 24),
|
|
304
|
+
minutes: Math.floor(diff / (1e3 * 60) % 60),
|
|
305
|
+
seconds: Math.floor(diff / 1e3 % 60),
|
|
306
|
+
totalMs: diff,
|
|
307
|
+
isExpired: diff <= 0
|
|
308
|
+
};
|
|
309
|
+
};
|
|
310
|
+
const [value, setValue] = useState(calculate);
|
|
311
|
+
useEffect(() => {
|
|
312
|
+
const timer = setInterval(() => {
|
|
313
|
+
const next = calculate();
|
|
314
|
+
setValue(next);
|
|
315
|
+
if (next.isExpired) clearInterval(timer);
|
|
316
|
+
}, 1e3);
|
|
317
|
+
return () => clearInterval(timer);
|
|
318
|
+
}, [targetMs]);
|
|
319
|
+
return value;
|
|
320
|
+
}
|
|
297
321
|
function useFileDialog(options = {}) {
|
|
298
322
|
const { accept, multiple = false, directory = false, capture, onChange } = options;
|
|
299
323
|
const [files, setFiles] = useState([]);
|
|
@@ -3250,10 +3274,10 @@ var Observer = class {
|
|
|
3250
3274
|
});
|
|
3251
3275
|
}
|
|
3252
3276
|
};
|
|
3253
|
-
this.custom = (
|
|
3277
|
+
this.custom = (jsx120, data) => {
|
|
3254
3278
|
const id = (data == null ? void 0 : data.id) || toastsCounter++;
|
|
3255
3279
|
this.create({
|
|
3256
|
-
jsx:
|
|
3280
|
+
jsx: jsx120(id),
|
|
3257
3281
|
id,
|
|
3258
3282
|
...data
|
|
3259
3283
|
});
|
|
@@ -8330,6 +8354,2113 @@ function AuroraBackground({
|
|
|
8330
8354
|
}
|
|
8331
8355
|
);
|
|
8332
8356
|
}
|
|
8357
|
+
function formatTime(s) {
|
|
8358
|
+
if (!isFinite(s) || s < 0) return "0:00";
|
|
8359
|
+
const m37 = Math.floor(s / 60);
|
|
8360
|
+
const sec = Math.floor(s % 60);
|
|
8361
|
+
return `${m37}:${String(sec).padStart(2, "0")}`;
|
|
8362
|
+
}
|
|
8363
|
+
function AudioPlayer({
|
|
8364
|
+
src,
|
|
8365
|
+
title,
|
|
8366
|
+
className,
|
|
8367
|
+
surface,
|
|
8368
|
+
radius,
|
|
8369
|
+
animated
|
|
8370
|
+
}) {
|
|
8371
|
+
const sf = useSaasflareProps({ surface, radius, animated });
|
|
8372
|
+
const audioRef = useRef(null);
|
|
8373
|
+
const [playing, setPlaying] = useState(false);
|
|
8374
|
+
const [current, setCurrent] = useState(0);
|
|
8375
|
+
const [duration, setDuration] = useState(0);
|
|
8376
|
+
const toggle = useCallback(() => {
|
|
8377
|
+
const audio = audioRef.current;
|
|
8378
|
+
if (!audio) return;
|
|
8379
|
+
if (playing) {
|
|
8380
|
+
audio.pause();
|
|
8381
|
+
} else {
|
|
8382
|
+
audio.play();
|
|
8383
|
+
}
|
|
8384
|
+
setPlaying(!playing);
|
|
8385
|
+
}, [playing]);
|
|
8386
|
+
useEffect(() => {
|
|
8387
|
+
const audio = audioRef.current;
|
|
8388
|
+
if (!audio) return;
|
|
8389
|
+
const onTime = () => setCurrent(audio.currentTime);
|
|
8390
|
+
const onMeta = () => setDuration(audio.duration);
|
|
8391
|
+
const onEnded = () => setPlaying(false);
|
|
8392
|
+
audio.addEventListener("timeupdate", onTime);
|
|
8393
|
+
audio.addEventListener("loadedmetadata", onMeta);
|
|
8394
|
+
audio.addEventListener("ended", onEnded);
|
|
8395
|
+
return () => {
|
|
8396
|
+
audio.removeEventListener("timeupdate", onTime);
|
|
8397
|
+
audio.removeEventListener("loadedmetadata", onMeta);
|
|
8398
|
+
audio.removeEventListener("ended", onEnded);
|
|
8399
|
+
};
|
|
8400
|
+
}, []);
|
|
8401
|
+
const seek = useCallback((e) => {
|
|
8402
|
+
const audio = audioRef.current;
|
|
8403
|
+
if (!audio) return;
|
|
8404
|
+
audio.currentTime = Number(e.target.value);
|
|
8405
|
+
}, []);
|
|
8406
|
+
const progress = duration > 0 ? current / duration * 100 : 0;
|
|
8407
|
+
return /* @__PURE__ */ jsxs(
|
|
8408
|
+
"div",
|
|
8409
|
+
{
|
|
8410
|
+
"data-slot": "audio-player",
|
|
8411
|
+
"data-surface": sf.surface,
|
|
8412
|
+
"data-radius": sf.radius,
|
|
8413
|
+
className: cn(
|
|
8414
|
+
"flex items-center gap-3 rounded-xl border surface-card px-4 py-3",
|
|
8415
|
+
"transition-all duration-200 hover:shadow-md",
|
|
8416
|
+
className
|
|
8417
|
+
),
|
|
8418
|
+
children: [
|
|
8419
|
+
/* @__PURE__ */ jsx("audio", { ref: audioRef, src, preload: "metadata" }),
|
|
8420
|
+
/* @__PURE__ */ jsx(
|
|
8421
|
+
"button",
|
|
8422
|
+
{
|
|
8423
|
+
type: "button",
|
|
8424
|
+
onClick: toggle,
|
|
8425
|
+
className: "flex size-9 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground transition-colors hover:bg-primary/90",
|
|
8426
|
+
"aria-label": playing ? "Pause" : "Play",
|
|
8427
|
+
children: playing ? /* @__PURE__ */ jsx(PauseIcon, { weight: sf.iconWeight, className: "size-4" }) : /* @__PURE__ */ jsx(PlayIcon, { weight: sf.iconWeight, className: "ml-0.5 size-4" })
|
|
8428
|
+
}
|
|
8429
|
+
),
|
|
8430
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-1", children: [
|
|
8431
|
+
title && /* @__PURE__ */ jsx("span", { className: "text-xs font-medium truncate", children: title }),
|
|
8432
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
8433
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] tabular-nums text-muted-foreground", children: formatTime(current) }),
|
|
8434
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
|
|
8435
|
+
/* @__PURE__ */ jsx("div", { className: "h-1 rounded-full bg-muted", children: /* @__PURE__ */ jsx(
|
|
8436
|
+
"div",
|
|
8437
|
+
{
|
|
8438
|
+
className: "h-1 rounded-full bg-primary transition-[width]",
|
|
8439
|
+
style: { width: `${progress}%` }
|
|
8440
|
+
}
|
|
8441
|
+
) }),
|
|
8442
|
+
/* @__PURE__ */ jsx(
|
|
8443
|
+
"input",
|
|
8444
|
+
{
|
|
8445
|
+
type: "range",
|
|
8446
|
+
min: 0,
|
|
8447
|
+
max: duration || 0,
|
|
8448
|
+
value: current,
|
|
8449
|
+
onChange: seek,
|
|
8450
|
+
className: "absolute inset-0 h-1 w-full cursor-pointer opacity-0",
|
|
8451
|
+
"aria-label": "Seek"
|
|
8452
|
+
}
|
|
8453
|
+
)
|
|
8454
|
+
] }),
|
|
8455
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] tabular-nums text-muted-foreground", children: formatTime(duration) })
|
|
8456
|
+
] })
|
|
8457
|
+
] })
|
|
8458
|
+
]
|
|
8459
|
+
}
|
|
8460
|
+
);
|
|
8461
|
+
}
|
|
8462
|
+
var COL_MAP = {
|
|
8463
|
+
2: "md:grid-cols-2",
|
|
8464
|
+
3: "md:grid-cols-3",
|
|
8465
|
+
4: "md:grid-cols-4"
|
|
8466
|
+
};
|
|
8467
|
+
function BentoGrid({
|
|
8468
|
+
children,
|
|
8469
|
+
columns = 3,
|
|
8470
|
+
gap = 4,
|
|
8471
|
+
className
|
|
8472
|
+
}) {
|
|
8473
|
+
return /* @__PURE__ */ jsx(
|
|
8474
|
+
"div",
|
|
8475
|
+
{
|
|
8476
|
+
className: cn(
|
|
8477
|
+
"grid grid-cols-1",
|
|
8478
|
+
COL_MAP[columns],
|
|
8479
|
+
className
|
|
8480
|
+
),
|
|
8481
|
+
style: { gap: `${gap * 0.25}rem` },
|
|
8482
|
+
"data-slot": "bento-grid",
|
|
8483
|
+
children
|
|
8484
|
+
}
|
|
8485
|
+
);
|
|
8486
|
+
}
|
|
8487
|
+
var COL_SPAN_MAP = {
|
|
8488
|
+
1: "",
|
|
8489
|
+
2: "md:col-span-2",
|
|
8490
|
+
3: "md:col-span-3",
|
|
8491
|
+
4: "md:col-span-4"
|
|
8492
|
+
};
|
|
8493
|
+
var ROW_SPAN_MAP = {
|
|
8494
|
+
1: "",
|
|
8495
|
+
2: "md:row-span-2",
|
|
8496
|
+
3: "md:row-span-3"
|
|
8497
|
+
};
|
|
8498
|
+
function BentoGridItem({
|
|
8499
|
+
children,
|
|
8500
|
+
colSpan = 1,
|
|
8501
|
+
rowSpan = 1,
|
|
8502
|
+
index = 0,
|
|
8503
|
+
className,
|
|
8504
|
+
surface,
|
|
8505
|
+
radius,
|
|
8506
|
+
animated
|
|
8507
|
+
}) {
|
|
8508
|
+
const sf = useSaasflareProps({ surface, radius, animated });
|
|
8509
|
+
const reduced = useReducedMotion();
|
|
8510
|
+
return /* @__PURE__ */ jsx(
|
|
8511
|
+
m.div,
|
|
8512
|
+
{
|
|
8513
|
+
initial: reduced ? false : { opacity: 0, y: 16 },
|
|
8514
|
+
whileInView: reduced ? void 0 : { opacity: 1, y: 0 },
|
|
8515
|
+
viewport: { once: true, margin: "-60px" },
|
|
8516
|
+
transition: reduced ? noMotion : { ...springGentle, delay: index * 0.08 },
|
|
8517
|
+
"data-slot": "bento-grid-item",
|
|
8518
|
+
"data-surface": sf.surface,
|
|
8519
|
+
"data-radius": sf.radius,
|
|
8520
|
+
className: cn(
|
|
8521
|
+
"rounded-xl border surface-card p-6 text-card-foreground",
|
|
8522
|
+
"transition-all duration-200 hover:-translate-y-px hover:shadow-md",
|
|
8523
|
+
"motion-reduce:hover:transform-none",
|
|
8524
|
+
COL_SPAN_MAP[colSpan],
|
|
8525
|
+
ROW_SPAN_MAP[rowSpan],
|
|
8526
|
+
className
|
|
8527
|
+
),
|
|
8528
|
+
children
|
|
8529
|
+
}
|
|
8530
|
+
);
|
|
8531
|
+
}
|
|
8532
|
+
function BlurFade({
|
|
8533
|
+
children,
|
|
8534
|
+
delay = 0,
|
|
8535
|
+
blur = 8,
|
|
8536
|
+
yOffset = 12,
|
|
8537
|
+
duration = 0.5,
|
|
8538
|
+
once = true,
|
|
8539
|
+
className
|
|
8540
|
+
}) {
|
|
8541
|
+
const reduced = useReducedMotion();
|
|
8542
|
+
const ref = useRef(null);
|
|
8543
|
+
const isInView = useInView(ref, { once, margin: "-50px" });
|
|
8544
|
+
if (reduced) {
|
|
8545
|
+
return /* @__PURE__ */ jsx("div", { className, children });
|
|
8546
|
+
}
|
|
8547
|
+
return /* @__PURE__ */ jsx(
|
|
8548
|
+
m.div,
|
|
8549
|
+
{
|
|
8550
|
+
ref,
|
|
8551
|
+
initial: { opacity: 0, y: yOffset, filter: `blur(${blur}px)` },
|
|
8552
|
+
animate: isInView ? { opacity: 1, y: 0, filter: "blur(0px)" } : { opacity: 0, y: yOffset, filter: `blur(${blur}px)` },
|
|
8553
|
+
transition: { duration, delay, ease: "easeOut" },
|
|
8554
|
+
className: cn("will-change-[opacity,transform,filter]", className),
|
|
8555
|
+
"data-slot": "blur-fade",
|
|
8556
|
+
children
|
|
8557
|
+
}
|
|
8558
|
+
);
|
|
8559
|
+
}
|
|
8560
|
+
function BorderBeam({
|
|
8561
|
+
color = "hsl(var(--primary))",
|
|
8562
|
+
colorFrom = "transparent",
|
|
8563
|
+
duration = 6,
|
|
8564
|
+
size = 150,
|
|
8565
|
+
borderRadius = "inherit",
|
|
8566
|
+
className
|
|
8567
|
+
}) {
|
|
8568
|
+
const reduced = useReducedMotion();
|
|
8569
|
+
if (reduced) return null;
|
|
8570
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8571
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
8572
|
+
@keyframes sf-border-beam {
|
|
8573
|
+
0% { offset-distance: 0%; }
|
|
8574
|
+
100% { offset-distance: 100%; }
|
|
8575
|
+
}
|
|
8576
|
+
` }),
|
|
8577
|
+
/* @__PURE__ */ jsx(
|
|
8578
|
+
"div",
|
|
8579
|
+
{
|
|
8580
|
+
className: cn("pointer-events-none absolute inset-0", className),
|
|
8581
|
+
style: { borderRadius },
|
|
8582
|
+
"aria-hidden": "true",
|
|
8583
|
+
"data-slot": "border-beam",
|
|
8584
|
+
children: /* @__PURE__ */ jsx(
|
|
8585
|
+
"div",
|
|
8586
|
+
{
|
|
8587
|
+
style: {
|
|
8588
|
+
position: "absolute",
|
|
8589
|
+
inset: 0,
|
|
8590
|
+
borderRadius,
|
|
8591
|
+
/* The beam travels along the rect path */
|
|
8592
|
+
offsetPath: `rect(0 auto auto 0 round ${borderRadius})`,
|
|
8593
|
+
animation: `sf-border-beam ${duration}s linear infinite`,
|
|
8594
|
+
background: `linear-gradient(to left, ${color}, ${colorFrom})`,
|
|
8595
|
+
width: size,
|
|
8596
|
+
height: size,
|
|
8597
|
+
opacity: 0.7,
|
|
8598
|
+
filter: "blur(4px)"
|
|
8599
|
+
}
|
|
8600
|
+
}
|
|
8601
|
+
)
|
|
8602
|
+
}
|
|
8603
|
+
)
|
|
8604
|
+
] });
|
|
8605
|
+
}
|
|
8606
|
+
function Compare({
|
|
8607
|
+
before,
|
|
8608
|
+
after,
|
|
8609
|
+
beforeLabel,
|
|
8610
|
+
afterLabel,
|
|
8611
|
+
initialPosition = 50,
|
|
8612
|
+
aspectRatio = "16/9",
|
|
8613
|
+
className
|
|
8614
|
+
}) {
|
|
8615
|
+
const [position, setPosition] = useState(initialPosition);
|
|
8616
|
+
const containerRef = useRef(null);
|
|
8617
|
+
const dragging = useRef(false);
|
|
8618
|
+
const updatePosition = useCallback((clientX) => {
|
|
8619
|
+
if (!containerRef.current) return;
|
|
8620
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
8621
|
+
const x = Math.max(0, Math.min(clientX - rect.left, rect.width));
|
|
8622
|
+
setPosition(x / rect.width * 100);
|
|
8623
|
+
}, []);
|
|
8624
|
+
const onPointerDown = useCallback(
|
|
8625
|
+
(e) => {
|
|
8626
|
+
dragging.current = true;
|
|
8627
|
+
e.target.setPointerCapture(e.pointerId);
|
|
8628
|
+
updatePosition(e.clientX);
|
|
8629
|
+
},
|
|
8630
|
+
[updatePosition]
|
|
8631
|
+
);
|
|
8632
|
+
const onPointerMove = useCallback(
|
|
8633
|
+
(e) => {
|
|
8634
|
+
if (!dragging.current) return;
|
|
8635
|
+
updatePosition(e.clientX);
|
|
8636
|
+
},
|
|
8637
|
+
[updatePosition]
|
|
8638
|
+
);
|
|
8639
|
+
const onPointerUp = useCallback(() => {
|
|
8640
|
+
dragging.current = false;
|
|
8641
|
+
}, []);
|
|
8642
|
+
const onKeyDown = useCallback((e) => {
|
|
8643
|
+
if (e.key === "ArrowLeft") setPosition((p) => Math.max(0, p - 2));
|
|
8644
|
+
else if (e.key === "ArrowRight") setPosition((p) => Math.min(100, p + 2));
|
|
8645
|
+
}, []);
|
|
8646
|
+
return /* @__PURE__ */ jsxs(
|
|
8647
|
+
"div",
|
|
8648
|
+
{
|
|
8649
|
+
ref: containerRef,
|
|
8650
|
+
className: cn(
|
|
8651
|
+
"relative select-none overflow-hidden rounded-xl border shadow-sm",
|
|
8652
|
+
className
|
|
8653
|
+
),
|
|
8654
|
+
style: { aspectRatio },
|
|
8655
|
+
onPointerDown,
|
|
8656
|
+
onPointerMove,
|
|
8657
|
+
onPointerUp,
|
|
8658
|
+
"data-slot": "compare",
|
|
8659
|
+
children: [
|
|
8660
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0", children: after }),
|
|
8661
|
+
/* @__PURE__ */ jsx(
|
|
8662
|
+
"div",
|
|
8663
|
+
{
|
|
8664
|
+
className: "absolute inset-0 overflow-hidden",
|
|
8665
|
+
style: { width: `${position}%` },
|
|
8666
|
+
children: /* @__PURE__ */ jsx(
|
|
8667
|
+
"div",
|
|
8668
|
+
{
|
|
8669
|
+
className: "h-full",
|
|
8670
|
+
style: { width: containerRef.current?.offsetWidth ?? "100%" },
|
|
8671
|
+
children: before
|
|
8672
|
+
}
|
|
8673
|
+
)
|
|
8674
|
+
}
|
|
8675
|
+
),
|
|
8676
|
+
/* @__PURE__ */ jsx(
|
|
8677
|
+
"div",
|
|
8678
|
+
{
|
|
8679
|
+
className: "absolute inset-y-0 z-10 flex w-1 cursor-col-resize items-center bg-white shadow-lg",
|
|
8680
|
+
style: { left: `${position}%`, transform: "translateX(-50%)" },
|
|
8681
|
+
role: "slider",
|
|
8682
|
+
"aria-label": "Comparison slider",
|
|
8683
|
+
"aria-valuenow": Math.round(position),
|
|
8684
|
+
"aria-valuemin": 0,
|
|
8685
|
+
"aria-valuemax": 100,
|
|
8686
|
+
tabIndex: 0,
|
|
8687
|
+
onKeyDown,
|
|
8688
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-white shadow-md", children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M4 1L1 7L4 13M10 1L13 7L10 13", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
|
|
8689
|
+
}
|
|
8690
|
+
),
|
|
8691
|
+
beforeLabel && /* @__PURE__ */ jsx("span", { className: "absolute left-3 top-3 rounded-md bg-black/50 px-2 py-1 text-xs font-medium text-white backdrop-blur-sm", children: beforeLabel }),
|
|
8692
|
+
afterLabel && /* @__PURE__ */ jsx("span", { className: "absolute right-3 top-3 rounded-md bg-black/50 px-2 py-1 text-xs font-medium text-white backdrop-blur-sm", children: afterLabel })
|
|
8693
|
+
]
|
|
8694
|
+
}
|
|
8695
|
+
);
|
|
8696
|
+
}
|
|
8697
|
+
function seeded(seed) {
|
|
8698
|
+
const x = Math.sin(seed * 9301 + 49297) * 233280;
|
|
8699
|
+
return x - Math.floor(x);
|
|
8700
|
+
}
|
|
8701
|
+
function Confetti({
|
|
8702
|
+
active,
|
|
8703
|
+
count = 40,
|
|
8704
|
+
colors = [
|
|
8705
|
+
"hsl(var(--primary))",
|
|
8706
|
+
"hsl(var(--chart-1))",
|
|
8707
|
+
"hsl(var(--chart-2))",
|
|
8708
|
+
"hsl(var(--chart-3))",
|
|
8709
|
+
"hsl(var(--chart-4))"
|
|
8710
|
+
],
|
|
8711
|
+
duration = 3e3,
|
|
8712
|
+
onComplete,
|
|
8713
|
+
className
|
|
8714
|
+
}) {
|
|
8715
|
+
const reduced = useReducedMotion();
|
|
8716
|
+
const [visible, setVisible] = useState(false);
|
|
8717
|
+
useEffect(() => {
|
|
8718
|
+
if (!active || reduced) return;
|
|
8719
|
+
setVisible(true);
|
|
8720
|
+
const timer = setTimeout(() => {
|
|
8721
|
+
setVisible(false);
|
|
8722
|
+
onComplete?.();
|
|
8723
|
+
}, duration);
|
|
8724
|
+
return () => clearTimeout(timer);
|
|
8725
|
+
}, [active, reduced, duration, onComplete]);
|
|
8726
|
+
const particles = useMemo(
|
|
8727
|
+
() => Array.from({ length: count }, (_, i) => {
|
|
8728
|
+
const r = (s) => seeded(i * 100 + s);
|
|
8729
|
+
return {
|
|
8730
|
+
id: i,
|
|
8731
|
+
color: colors[i % colors.length],
|
|
8732
|
+
x: 50 + (r(1) - 0.5) * 60,
|
|
8733
|
+
endX: (r(2) - 0.5) * 200,
|
|
8734
|
+
endY: -(100 + r(3) * 300),
|
|
8735
|
+
size: 4 + r(4) * 6,
|
|
8736
|
+
rotation: r(5) * 720,
|
|
8737
|
+
delay: r(6) * 0.3,
|
|
8738
|
+
animDuration: 1.5 + r(7) * 1.5
|
|
8739
|
+
};
|
|
8740
|
+
}),
|
|
8741
|
+
[count, colors]
|
|
8742
|
+
);
|
|
8743
|
+
if (!visible || reduced) return null;
|
|
8744
|
+
return /* @__PURE__ */ jsxs(
|
|
8745
|
+
"div",
|
|
8746
|
+
{
|
|
8747
|
+
className: cn("pointer-events-none fixed inset-0 z-[9999] overflow-hidden", className),
|
|
8748
|
+
"aria-hidden": "true",
|
|
8749
|
+
"data-slot": "confetti",
|
|
8750
|
+
children: [
|
|
8751
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
8752
|
+
@keyframes sf-confetti-burst {
|
|
8753
|
+
0% {
|
|
8754
|
+
transform: translate(0, 0) rotate(0deg);
|
|
8755
|
+
opacity: 1;
|
|
8756
|
+
}
|
|
8757
|
+
100% {
|
|
8758
|
+
transform: translate(var(--cx), var(--cy)) rotate(var(--cr));
|
|
8759
|
+
opacity: 0;
|
|
8760
|
+
}
|
|
8761
|
+
}
|
|
8762
|
+
` }),
|
|
8763
|
+
particles.map((p) => /* @__PURE__ */ jsx(
|
|
8764
|
+
"div",
|
|
8765
|
+
{
|
|
8766
|
+
style: {
|
|
8767
|
+
position: "absolute",
|
|
8768
|
+
left: `${p.x}%`,
|
|
8769
|
+
bottom: 0,
|
|
8770
|
+
width: p.size,
|
|
8771
|
+
height: p.size * 0.6,
|
|
8772
|
+
backgroundColor: p.color,
|
|
8773
|
+
borderRadius: p.id % 3 === 0 ? "50%" : "1px",
|
|
8774
|
+
["--cx"]: `${p.endX}px`,
|
|
8775
|
+
["--cy"]: `${p.endY}px`,
|
|
8776
|
+
["--cr"]: `${p.rotation}deg`,
|
|
8777
|
+
animation: `sf-confetti-burst ${p.animDuration}s cubic-bezier(0.25, 0.46, 0.45, 0.94) ${p.delay}s forwards`
|
|
8778
|
+
}
|
|
8779
|
+
},
|
|
8780
|
+
p.id
|
|
8781
|
+
))
|
|
8782
|
+
]
|
|
8783
|
+
}
|
|
8784
|
+
);
|
|
8785
|
+
}
|
|
8786
|
+
function pad(n) {
|
|
8787
|
+
return String(Math.max(0, Math.floor(n))).padStart(2, "0");
|
|
8788
|
+
}
|
|
8789
|
+
function Countdown({
|
|
8790
|
+
days,
|
|
8791
|
+
hours,
|
|
8792
|
+
minutes,
|
|
8793
|
+
seconds,
|
|
8794
|
+
showLabels = true,
|
|
8795
|
+
className
|
|
8796
|
+
}) {
|
|
8797
|
+
const units = [
|
|
8798
|
+
{ value: days, label: "Days" },
|
|
8799
|
+
{ value: hours, label: "Hours" },
|
|
8800
|
+
{ value: minutes, label: "Minutes" },
|
|
8801
|
+
{ value: seconds, label: "Seconds" }
|
|
8802
|
+
];
|
|
8803
|
+
return /* @__PURE__ */ jsx(
|
|
8804
|
+
"div",
|
|
8805
|
+
{
|
|
8806
|
+
className: cn("flex items-center gap-2 md:gap-3", className),
|
|
8807
|
+
"data-slot": "countdown",
|
|
8808
|
+
role: "timer",
|
|
8809
|
+
"aria-label": `${days} days, ${hours} hours, ${minutes} minutes, ${seconds} seconds`,
|
|
8810
|
+
children: units.map((unit, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 md:gap-3", children: [
|
|
8811
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
8812
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-14 items-center justify-center rounded-lg border bg-card text-2xl font-bold tabular-nums shadow-sm md:size-16 md:text-3xl", children: pad(unit.value) }),
|
|
8813
|
+
showLabels && /* @__PURE__ */ jsx("span", { className: "mt-1.5 text-[10px] uppercase tracking-wider text-muted-foreground", children: unit.label })
|
|
8814
|
+
] }),
|
|
8815
|
+
i < units.length - 1 && /* @__PURE__ */ jsx("span", { className: "mb-5 text-xl font-bold text-muted-foreground", "aria-hidden": "true", children: ":" })
|
|
8816
|
+
] }, unit.label))
|
|
8817
|
+
}
|
|
8818
|
+
);
|
|
8819
|
+
}
|
|
8820
|
+
function SafariMock({
|
|
8821
|
+
children,
|
|
8822
|
+
url = "https://example.com",
|
|
8823
|
+
className
|
|
8824
|
+
}) {
|
|
8825
|
+
return /* @__PURE__ */ jsxs(
|
|
8826
|
+
"div",
|
|
8827
|
+
{
|
|
8828
|
+
className: cn("overflow-hidden rounded-xl border bg-background shadow-xl", className),
|
|
8829
|
+
"data-slot": "safari-mock",
|
|
8830
|
+
children: [
|
|
8831
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b bg-muted/50 px-4 py-3", children: [
|
|
8832
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-1.5", children: [
|
|
8833
|
+
/* @__PURE__ */ jsx("div", { className: "size-3 rounded-full bg-[#ff5f57]" }),
|
|
8834
|
+
/* @__PURE__ */ jsx("div", { className: "size-3 rounded-full bg-[#febc2e]" }),
|
|
8835
|
+
/* @__PURE__ */ jsx("div", { className: "size-3 rounded-full bg-[#28c840]" })
|
|
8836
|
+
] }),
|
|
8837
|
+
/* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-md flex-1 items-center justify-center rounded-md bg-background/80 px-3 py-1 text-xs text-muted-foreground", children: [
|
|
8838
|
+
/* @__PURE__ */ jsx(
|
|
8839
|
+
"svg",
|
|
8840
|
+
{
|
|
8841
|
+
className: "mr-1.5 size-3 text-muted-foreground/50",
|
|
8842
|
+
fill: "none",
|
|
8843
|
+
stroke: "currentColor",
|
|
8844
|
+
viewBox: "0 0 24 24",
|
|
8845
|
+
"aria-hidden": "true",
|
|
8846
|
+
children: /* @__PURE__ */ jsx(
|
|
8847
|
+
"path",
|
|
8848
|
+
{
|
|
8849
|
+
strokeLinecap: "round",
|
|
8850
|
+
strokeLinejoin: "round",
|
|
8851
|
+
strokeWidth: 2,
|
|
8852
|
+
d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
|
|
8853
|
+
}
|
|
8854
|
+
)
|
|
8855
|
+
}
|
|
8856
|
+
),
|
|
8857
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: url })
|
|
8858
|
+
] })
|
|
8859
|
+
] }),
|
|
8860
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-hidden", children })
|
|
8861
|
+
]
|
|
8862
|
+
}
|
|
8863
|
+
);
|
|
8864
|
+
}
|
|
8865
|
+
function IPhoneMock({
|
|
8866
|
+
children,
|
|
8867
|
+
className
|
|
8868
|
+
}) {
|
|
8869
|
+
return /* @__PURE__ */ jsxs(
|
|
8870
|
+
"div",
|
|
8871
|
+
{
|
|
8872
|
+
className: cn(
|
|
8873
|
+
"relative mx-auto w-[280px] rounded-[2.5rem] border-[6px] border-foreground/10 bg-background p-1.5 shadow-xl",
|
|
8874
|
+
className
|
|
8875
|
+
),
|
|
8876
|
+
"data-slot": "iphone-mock",
|
|
8877
|
+
children: [
|
|
8878
|
+
/* @__PURE__ */ jsx("div", { className: "absolute left-1/2 top-2 z-10 h-5 w-24 -translate-x-1/2 rounded-full bg-foreground/10" }),
|
|
8879
|
+
/* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[2rem] bg-background", children: [
|
|
8880
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-2 text-[10px] font-semibold text-foreground", children: [
|
|
8881
|
+
/* @__PURE__ */ jsx("span", { children: "9:41" }),
|
|
8882
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
8883
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-0.5", children: [
|
|
8884
|
+
/* @__PURE__ */ jsx("div", { className: "h-2 w-0.5 rounded-sm bg-foreground" }),
|
|
8885
|
+
/* @__PURE__ */ jsx("div", { className: "h-2.5 w-0.5 rounded-sm bg-foreground" }),
|
|
8886
|
+
/* @__PURE__ */ jsx("div", { className: "h-3 w-0.5 rounded-sm bg-foreground" }),
|
|
8887
|
+
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-0.5 rounded-sm bg-foreground" })
|
|
8888
|
+
] }),
|
|
8889
|
+
/* @__PURE__ */ jsx("span", { className: "ml-1", children: "100%" })
|
|
8890
|
+
] })
|
|
8891
|
+
] }),
|
|
8892
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-hidden", children })
|
|
8893
|
+
] }),
|
|
8894
|
+
/* @__PURE__ */ jsx("div", { className: "mx-auto mt-1.5 h-1 w-28 rounded-full bg-foreground/20" })
|
|
8895
|
+
]
|
|
8896
|
+
}
|
|
8897
|
+
);
|
|
8898
|
+
}
|
|
8899
|
+
var DockContext = createContext(null);
|
|
8900
|
+
function useDock() {
|
|
8901
|
+
const ctx = useContext(DockContext);
|
|
8902
|
+
if (!ctx) throw new Error("DockItem must be used within a Dock");
|
|
8903
|
+
return ctx;
|
|
8904
|
+
}
|
|
8905
|
+
function Dock({
|
|
8906
|
+
children,
|
|
8907
|
+
magnification = 1.5,
|
|
8908
|
+
distance = 100,
|
|
8909
|
+
className,
|
|
8910
|
+
surface,
|
|
8911
|
+
radius,
|
|
8912
|
+
animated
|
|
8913
|
+
}) {
|
|
8914
|
+
const sf = useSaasflareProps({ surface, radius, animated });
|
|
8915
|
+
const reduced = useReducedMotion();
|
|
8916
|
+
const mouseX = useMotionValue(Infinity);
|
|
8917
|
+
return /* @__PURE__ */ jsx(DockContext.Provider, { value: { mouseX, magnification, distance, reduced }, children: /* @__PURE__ */ jsx(
|
|
8918
|
+
m.nav,
|
|
8919
|
+
{
|
|
8920
|
+
onMouseMove: (e) => mouseX.set(e.pageX),
|
|
8921
|
+
onMouseLeave: () => mouseX.set(Infinity),
|
|
8922
|
+
"data-slot": "dock",
|
|
8923
|
+
"data-surface": sf.surface,
|
|
8924
|
+
"data-radius": sf.radius,
|
|
8925
|
+
className: cn(
|
|
8926
|
+
"mx-auto flex h-14 items-end gap-2 rounded-2xl border surface-card px-3 pb-2",
|
|
8927
|
+
className
|
|
8928
|
+
),
|
|
8929
|
+
role: "toolbar",
|
|
8930
|
+
"aria-label": "Dock",
|
|
8931
|
+
children
|
|
8932
|
+
}
|
|
8933
|
+
) });
|
|
8934
|
+
}
|
|
8935
|
+
var BASE_SIZE = 40;
|
|
8936
|
+
function DockItem({
|
|
8937
|
+
children,
|
|
8938
|
+
label,
|
|
8939
|
+
onClick,
|
|
8940
|
+
className
|
|
8941
|
+
}) {
|
|
8942
|
+
const { mouseX, magnification, distance, reduced } = useDock();
|
|
8943
|
+
const ref = useRef(null);
|
|
8944
|
+
const distanceFromMouse = useTransform(mouseX, (val) => {
|
|
8945
|
+
const bounds = ref.current?.getBoundingClientRect();
|
|
8946
|
+
if (!bounds) return distance + 1;
|
|
8947
|
+
return val - (bounds.x + bounds.width / 2);
|
|
8948
|
+
});
|
|
8949
|
+
const maxSize = BASE_SIZE * magnification;
|
|
8950
|
+
const sizeTransform = useTransform(
|
|
8951
|
+
distanceFromMouse,
|
|
8952
|
+
[-distance, 0, distance],
|
|
8953
|
+
[BASE_SIZE, maxSize, BASE_SIZE]
|
|
8954
|
+
);
|
|
8955
|
+
const size = useSpring(sizeTransform, { stiffness: 300, damping: 25 });
|
|
8956
|
+
return /* @__PURE__ */ jsxs(
|
|
8957
|
+
m.button,
|
|
8958
|
+
{
|
|
8959
|
+
ref,
|
|
8960
|
+
onClick,
|
|
8961
|
+
style: reduced ? { width: BASE_SIZE, height: BASE_SIZE } : { width: size, height: size },
|
|
8962
|
+
className: cn(
|
|
8963
|
+
"relative flex items-center justify-center rounded-xl bg-muted transition-colors hover:bg-muted/80",
|
|
8964
|
+
"group",
|
|
8965
|
+
className
|
|
8966
|
+
),
|
|
8967
|
+
"aria-label": label,
|
|
8968
|
+
"data-slot": "dock-item",
|
|
8969
|
+
children: [
|
|
8970
|
+
children,
|
|
8971
|
+
/* @__PURE__ */ jsx(
|
|
8972
|
+
"span",
|
|
8973
|
+
{
|
|
8974
|
+
className: "pointer-events-none absolute -top-9 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md bg-popover px-2 py-1 text-xs text-popover-foreground shadow-md opacity-0 transition-opacity group-hover:opacity-100",
|
|
8975
|
+
role: "tooltip",
|
|
8976
|
+
children: label
|
|
8977
|
+
}
|
|
8978
|
+
)
|
|
8979
|
+
]
|
|
8980
|
+
}
|
|
8981
|
+
);
|
|
8982
|
+
}
|
|
8983
|
+
function FeatureCard({
|
|
8984
|
+
icon,
|
|
8985
|
+
title,
|
|
8986
|
+
description,
|
|
8987
|
+
className,
|
|
8988
|
+
surface,
|
|
8989
|
+
radius,
|
|
8990
|
+
animated
|
|
8991
|
+
}) {
|
|
8992
|
+
const sf = useSaasflareProps({ surface, radius, animated });
|
|
8993
|
+
return /* @__PURE__ */ jsxs(
|
|
8994
|
+
"div",
|
|
8995
|
+
{
|
|
8996
|
+
"data-slot": "feature-card",
|
|
8997
|
+
"data-surface": sf.surface,
|
|
8998
|
+
"data-radius": sf.radius,
|
|
8999
|
+
className: cn(
|
|
9000
|
+
"rounded-xl border surface-card p-6",
|
|
9001
|
+
"transition-all duration-200 hover:-translate-y-px hover:shadow-md",
|
|
9002
|
+
"motion-reduce:hover:transform-none",
|
|
9003
|
+
className
|
|
9004
|
+
),
|
|
9005
|
+
children: [
|
|
9006
|
+
icon && /* @__PURE__ */ jsx("div", { className: "mb-4 flex size-10 items-center justify-center rounded-lg bg-primary/10 text-primary [&_svg]:size-5", children: icon }),
|
|
9007
|
+
/* @__PURE__ */ jsx("h3", { className: "text-base font-semibold", children: title }),
|
|
9008
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: description })
|
|
9009
|
+
]
|
|
9010
|
+
}
|
|
9011
|
+
);
|
|
9012
|
+
}
|
|
9013
|
+
function FlipWords({
|
|
9014
|
+
words,
|
|
9015
|
+
interval = 2500,
|
|
9016
|
+
className
|
|
9017
|
+
}) {
|
|
9018
|
+
const reduced = useReducedMotion();
|
|
9019
|
+
const [index, setIndex] = useState(0);
|
|
9020
|
+
const next = useCallback(() => {
|
|
9021
|
+
setIndex((prev) => (prev + 1) % words.length);
|
|
9022
|
+
}, [words.length]);
|
|
9023
|
+
useEffect(() => {
|
|
9024
|
+
if (reduced || words.length <= 1) return;
|
|
9025
|
+
const timer = setInterval(next, interval);
|
|
9026
|
+
return () => clearInterval(timer);
|
|
9027
|
+
}, [reduced, words.length, interval, next]);
|
|
9028
|
+
const longestWord = useMemo(
|
|
9029
|
+
() => words.reduce((a, b) => a.length >= b.length ? a : b, ""),
|
|
9030
|
+
[words]
|
|
9031
|
+
);
|
|
9032
|
+
if (reduced) {
|
|
9033
|
+
return /* @__PURE__ */ jsx("span", { className, children: words[0] });
|
|
9034
|
+
}
|
|
9035
|
+
return /* @__PURE__ */ jsxs(
|
|
9036
|
+
"span",
|
|
9037
|
+
{
|
|
9038
|
+
className: cn("relative inline-block text-left align-baseline", className),
|
|
9039
|
+
"data-slot": "flip-words",
|
|
9040
|
+
children: [
|
|
9041
|
+
/* @__PURE__ */ jsx("span", { className: "invisible", "aria-hidden": "true", children: longestWord }),
|
|
9042
|
+
/* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
|
|
9043
|
+
m.span,
|
|
9044
|
+
{
|
|
9045
|
+
initial: { y: "100%", opacity: 0 },
|
|
9046
|
+
animate: { y: 0, opacity: 1 },
|
|
9047
|
+
exit: { y: "-100%", opacity: 0 },
|
|
9048
|
+
transition: springBouncy,
|
|
9049
|
+
className: "absolute inset-0",
|
|
9050
|
+
"aria-live": "polite",
|
|
9051
|
+
children: words[index]
|
|
9052
|
+
},
|
|
9053
|
+
words[index]
|
|
9054
|
+
) })
|
|
9055
|
+
]
|
|
9056
|
+
}
|
|
9057
|
+
);
|
|
9058
|
+
}
|
|
9059
|
+
function GalleryLightbox({
|
|
9060
|
+
images,
|
|
9061
|
+
open,
|
|
9062
|
+
index,
|
|
9063
|
+
onClose,
|
|
9064
|
+
onIndexChange,
|
|
9065
|
+
className
|
|
9066
|
+
}) {
|
|
9067
|
+
const sf = useSaasflareProps();
|
|
9068
|
+
const prev = useCallback(() => {
|
|
9069
|
+
onIndexChange((index - 1 + images.length) % images.length);
|
|
9070
|
+
}, [index, images.length, onIndexChange]);
|
|
9071
|
+
const next = useCallback(() => {
|
|
9072
|
+
onIndexChange((index + 1) % images.length);
|
|
9073
|
+
}, [index, images.length, onIndexChange]);
|
|
9074
|
+
useEffect(() => {
|
|
9075
|
+
if (!open) return;
|
|
9076
|
+
const onKey = (e) => {
|
|
9077
|
+
if (e.key === "Escape") onClose();
|
|
9078
|
+
if (e.key === "ArrowLeft") prev();
|
|
9079
|
+
if (e.key === "ArrowRight") next();
|
|
9080
|
+
};
|
|
9081
|
+
window.addEventListener("keydown", onKey);
|
|
9082
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
9083
|
+
}, [open, onClose, prev, next]);
|
|
9084
|
+
useEffect(() => {
|
|
9085
|
+
if (open) {
|
|
9086
|
+
document.body.style.overflow = "hidden";
|
|
9087
|
+
return () => {
|
|
9088
|
+
document.body.style.overflow = "";
|
|
9089
|
+
};
|
|
9090
|
+
}
|
|
9091
|
+
}, [open]);
|
|
9092
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsxs(
|
|
9093
|
+
m.div,
|
|
9094
|
+
{
|
|
9095
|
+
initial: { opacity: 0 },
|
|
9096
|
+
animate: { opacity: 1 },
|
|
9097
|
+
exit: { opacity: 0 },
|
|
9098
|
+
className: cn(
|
|
9099
|
+
"fixed inset-0 z-50 flex items-center justify-center bg-black/90 backdrop-blur-sm",
|
|
9100
|
+
className
|
|
9101
|
+
),
|
|
9102
|
+
onClick: onClose,
|
|
9103
|
+
role: "dialog",
|
|
9104
|
+
"aria-modal": "true",
|
|
9105
|
+
"aria-label": "Image gallery",
|
|
9106
|
+
"data-slot": "gallery-lightbox",
|
|
9107
|
+
children: [
|
|
9108
|
+
/* @__PURE__ */ jsx(
|
|
9109
|
+
"button",
|
|
9110
|
+
{
|
|
9111
|
+
type: "button",
|
|
9112
|
+
onClick: onClose,
|
|
9113
|
+
className: "absolute right-4 top-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
|
|
9114
|
+
"aria-label": "Close gallery",
|
|
9115
|
+
children: /* @__PURE__ */ jsx(XIcon, { weight: sf.iconWeight, className: "size-6" })
|
|
9116
|
+
}
|
|
9117
|
+
),
|
|
9118
|
+
images.length > 1 && /* @__PURE__ */ jsx(
|
|
9119
|
+
"button",
|
|
9120
|
+
{
|
|
9121
|
+
type: "button",
|
|
9122
|
+
onClick: (e) => {
|
|
9123
|
+
e.stopPropagation();
|
|
9124
|
+
prev();
|
|
9125
|
+
},
|
|
9126
|
+
className: "absolute left-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
|
|
9127
|
+
"aria-label": "Previous image",
|
|
9128
|
+
children: /* @__PURE__ */ jsx(CaretLeftIcon, { weight: sf.iconWeight, className: "size-6" })
|
|
9129
|
+
}
|
|
9130
|
+
),
|
|
9131
|
+
/* @__PURE__ */ jsx(
|
|
9132
|
+
m.img,
|
|
9133
|
+
{
|
|
9134
|
+
src: images[index],
|
|
9135
|
+
alt: `Image ${index + 1} of ${images.length}`,
|
|
9136
|
+
initial: { opacity: 0, scale: 0.95 },
|
|
9137
|
+
animate: { opacity: 1, scale: 1 },
|
|
9138
|
+
exit: { opacity: 0, scale: 0.95 },
|
|
9139
|
+
transition: { duration: 0.2 },
|
|
9140
|
+
className: "max-h-[85vh] max-w-[90vw] rounded-lg object-contain",
|
|
9141
|
+
onClick: (e) => e.stopPropagation()
|
|
9142
|
+
},
|
|
9143
|
+
index
|
|
9144
|
+
),
|
|
9145
|
+
images.length > 1 && /* @__PURE__ */ jsx(
|
|
9146
|
+
"button",
|
|
9147
|
+
{
|
|
9148
|
+
type: "button",
|
|
9149
|
+
onClick: (e) => {
|
|
9150
|
+
e.stopPropagation();
|
|
9151
|
+
next();
|
|
9152
|
+
},
|
|
9153
|
+
className: "absolute right-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
|
|
9154
|
+
"aria-label": "Next image",
|
|
9155
|
+
children: /* @__PURE__ */ jsx(CaretRightIcon, { weight: sf.iconWeight, className: "size-6" })
|
|
9156
|
+
}
|
|
9157
|
+
),
|
|
9158
|
+
images.length > 1 && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full bg-black/50 px-3 py-1 text-sm text-white backdrop-blur-sm", children: [
|
|
9159
|
+
index + 1,
|
|
9160
|
+
" / ",
|
|
9161
|
+
images.length
|
|
9162
|
+
] })
|
|
9163
|
+
]
|
|
9164
|
+
}
|
|
9165
|
+
) });
|
|
9166
|
+
}
|
|
9167
|
+
function useMousePosition(options = {}) {
|
|
9168
|
+
const { ref, enabled = true, useRAF = true } = options;
|
|
9169
|
+
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
9170
|
+
const rafRef = useRef(void 0);
|
|
9171
|
+
const updatePosition = useCallback(
|
|
9172
|
+
(clientX, clientY) => {
|
|
9173
|
+
const perform = () => {
|
|
9174
|
+
if (ref?.current) {
|
|
9175
|
+
const rect = ref.current.getBoundingClientRect();
|
|
9176
|
+
setPosition({ x: clientX - rect.left, y: clientY - rect.top });
|
|
9177
|
+
} else {
|
|
9178
|
+
setPosition({ x: clientX, y: clientY });
|
|
9179
|
+
}
|
|
9180
|
+
};
|
|
9181
|
+
if (useRAF) {
|
|
9182
|
+
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
9183
|
+
rafRef.current = requestAnimationFrame(perform);
|
|
9184
|
+
} else {
|
|
9185
|
+
perform();
|
|
9186
|
+
}
|
|
9187
|
+
},
|
|
9188
|
+
[ref, useRAF]
|
|
9189
|
+
);
|
|
9190
|
+
useEffect(() => {
|
|
9191
|
+
if (!enabled) return;
|
|
9192
|
+
const target = ref?.current ?? window;
|
|
9193
|
+
const handler = (event) => {
|
|
9194
|
+
const e = event;
|
|
9195
|
+
updatePosition(e.clientX, e.clientY);
|
|
9196
|
+
};
|
|
9197
|
+
target.addEventListener("mousemove", handler, { passive: true });
|
|
9198
|
+
return () => {
|
|
9199
|
+
target.removeEventListener("mousemove", handler);
|
|
9200
|
+
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
9201
|
+
};
|
|
9202
|
+
}, [ref, enabled, updatePosition]);
|
|
9203
|
+
return position;
|
|
9204
|
+
}
|
|
9205
|
+
function GlowingEffect({
|
|
9206
|
+
color = "hsl(var(--primary))",
|
|
9207
|
+
spread = 150,
|
|
9208
|
+
blur = 20,
|
|
9209
|
+
opacity = 0.4,
|
|
9210
|
+
borderRadius = "inherit",
|
|
9211
|
+
className
|
|
9212
|
+
}) {
|
|
9213
|
+
const reduced = useReducedMotion();
|
|
9214
|
+
const ref = useRef(null);
|
|
9215
|
+
const pos = useMousePosition({ ref, enabled: !reduced });
|
|
9216
|
+
const [hovered, setHovered] = useState(false);
|
|
9217
|
+
if (reduced) return null;
|
|
9218
|
+
return /* @__PURE__ */ jsx(
|
|
9219
|
+
"div",
|
|
9220
|
+
{
|
|
9221
|
+
ref,
|
|
9222
|
+
className: cn("pointer-events-none absolute inset-0", className),
|
|
9223
|
+
style: { borderRadius },
|
|
9224
|
+
onMouseEnter: () => setHovered(true),
|
|
9225
|
+
onMouseLeave: () => setHovered(false),
|
|
9226
|
+
"aria-hidden": "true",
|
|
9227
|
+
"data-slot": "glowing-effect",
|
|
9228
|
+
children: /* @__PURE__ */ jsx(
|
|
9229
|
+
"div",
|
|
9230
|
+
{
|
|
9231
|
+
className: "absolute inset-0 transition-opacity duration-300",
|
|
9232
|
+
style: {
|
|
9233
|
+
opacity: hovered ? opacity : 0,
|
|
9234
|
+
background: `radial-gradient(${spread}px circle at ${pos.x}px ${pos.y}px, ${color}, transparent 70%)`,
|
|
9235
|
+
filter: `blur(${blur}px)`,
|
|
9236
|
+
borderRadius,
|
|
9237
|
+
/* Mask to show glow only on borders, not fill */
|
|
9238
|
+
maskImage: `
|
|
9239
|
+
linear-gradient(black, black),
|
|
9240
|
+
linear-gradient(black, black)
|
|
9241
|
+
`,
|
|
9242
|
+
maskComposite: "exclude",
|
|
9243
|
+
WebkitMaskComposite: "xor",
|
|
9244
|
+
maskClip: "border-box, content-box",
|
|
9245
|
+
WebkitMaskClip: "border-box, content-box",
|
|
9246
|
+
padding: "2px"
|
|
9247
|
+
}
|
|
9248
|
+
}
|
|
9249
|
+
)
|
|
9250
|
+
}
|
|
9251
|
+
);
|
|
9252
|
+
}
|
|
9253
|
+
function GradientText({
|
|
9254
|
+
children,
|
|
9255
|
+
colors = [
|
|
9256
|
+
"hsl(var(--primary))",
|
|
9257
|
+
"hsl(var(--chart-1))",
|
|
9258
|
+
"hsl(var(--chart-2))"
|
|
9259
|
+
],
|
|
9260
|
+
animate = true,
|
|
9261
|
+
speed = 6,
|
|
9262
|
+
angle = 90,
|
|
9263
|
+
className
|
|
9264
|
+
}) {
|
|
9265
|
+
const reduced = useReducedMotion();
|
|
9266
|
+
const shouldAnimate = animate && !reduced;
|
|
9267
|
+
const gradient = `linear-gradient(${angle}deg, ${colors.join(", ")}, ${colors[0]})`;
|
|
9268
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9269
|
+
shouldAnimate && /* @__PURE__ */ jsx("style", { children: `
|
|
9270
|
+
@keyframes sf-gradient-shift {
|
|
9271
|
+
0% { background-position: 0% 50%; }
|
|
9272
|
+
50% { background-position: 100% 50%; }
|
|
9273
|
+
100% { background-position: 0% 50%; }
|
|
9274
|
+
}
|
|
9275
|
+
` }),
|
|
9276
|
+
/* @__PURE__ */ jsx(
|
|
9277
|
+
"span",
|
|
9278
|
+
{
|
|
9279
|
+
className: cn(
|
|
9280
|
+
"bg-clip-text text-transparent",
|
|
9281
|
+
className
|
|
9282
|
+
),
|
|
9283
|
+
style: {
|
|
9284
|
+
backgroundImage: gradient,
|
|
9285
|
+
backgroundSize: shouldAnimate ? "200% 200%" : "100% 100%",
|
|
9286
|
+
...shouldAnimate && {
|
|
9287
|
+
animation: `sf-gradient-shift ${speed}s ease infinite`
|
|
9288
|
+
}
|
|
9289
|
+
},
|
|
9290
|
+
"data-slot": "gradient-text",
|
|
9291
|
+
children
|
|
9292
|
+
}
|
|
9293
|
+
)
|
|
9294
|
+
] });
|
|
9295
|
+
}
|
|
9296
|
+
function HeroVideoDialog({
|
|
9297
|
+
videoSrc,
|
|
9298
|
+
thumbnailSrc,
|
|
9299
|
+
thumbnailAlt,
|
|
9300
|
+
aspectRatio = "16/9",
|
|
9301
|
+
className
|
|
9302
|
+
}) {
|
|
9303
|
+
const reduced = useReducedMotion();
|
|
9304
|
+
const sf = useSaasflareProps();
|
|
9305
|
+
const [open, setOpen] = useState(false);
|
|
9306
|
+
const close = useCallback(() => setOpen(false), []);
|
|
9307
|
+
const onKeyDown = useCallback(
|
|
9308
|
+
(e) => {
|
|
9309
|
+
if (e.key === "Escape") close();
|
|
9310
|
+
},
|
|
9311
|
+
[close]
|
|
9312
|
+
);
|
|
9313
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9314
|
+
/* @__PURE__ */ jsxs(
|
|
9315
|
+
"button",
|
|
9316
|
+
{
|
|
9317
|
+
type: "button",
|
|
9318
|
+
onClick: () => setOpen(true),
|
|
9319
|
+
className: cn(
|
|
9320
|
+
"group relative w-full cursor-pointer overflow-hidden rounded-xl border shadow-lg",
|
|
9321
|
+
className
|
|
9322
|
+
),
|
|
9323
|
+
style: { aspectRatio },
|
|
9324
|
+
"aria-label": `Play video: ${thumbnailAlt}`,
|
|
9325
|
+
"data-slot": "hero-video-dialog",
|
|
9326
|
+
children: [
|
|
9327
|
+
/* @__PURE__ */ jsx(
|
|
9328
|
+
"img",
|
|
9329
|
+
{
|
|
9330
|
+
src: thumbnailSrc,
|
|
9331
|
+
alt: thumbnailAlt,
|
|
9332
|
+
className: "size-full object-cover transition-transform duration-300 group-hover:scale-105"
|
|
9333
|
+
}
|
|
9334
|
+
),
|
|
9335
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/20 transition-colors group-hover:bg-black/30", children: /* @__PURE__ */ jsx("div", { className: "flex size-16 items-center justify-center rounded-full bg-white/90 shadow-xl backdrop-blur-sm transition-transform group-hover:scale-110", children: /* @__PURE__ */ jsx(PlayIcon, { weight: sf.iconWeight, className: "ml-1 size-7 text-foreground" }) }) })
|
|
9336
|
+
]
|
|
9337
|
+
}
|
|
9338
|
+
),
|
|
9339
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsxs(
|
|
9340
|
+
m.div,
|
|
9341
|
+
{
|
|
9342
|
+
initial: reduced ? { opacity: 1 } : { opacity: 0 },
|
|
9343
|
+
animate: { opacity: 1 },
|
|
9344
|
+
exit: reduced ? { opacity: 0 } : { opacity: 0 },
|
|
9345
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm",
|
|
9346
|
+
onClick: close,
|
|
9347
|
+
onKeyDown,
|
|
9348
|
+
role: "dialog",
|
|
9349
|
+
"aria-modal": "true",
|
|
9350
|
+
"aria-label": "Video player",
|
|
9351
|
+
tabIndex: -1,
|
|
9352
|
+
children: [
|
|
9353
|
+
/* @__PURE__ */ jsx(
|
|
9354
|
+
"button",
|
|
9355
|
+
{
|
|
9356
|
+
type: "button",
|
|
9357
|
+
onClick: close,
|
|
9358
|
+
className: "absolute right-4 top-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
|
|
9359
|
+
"aria-label": "Close video",
|
|
9360
|
+
children: /* @__PURE__ */ jsx(XIcon, { weight: sf.iconWeight, className: "size-6" })
|
|
9361
|
+
}
|
|
9362
|
+
),
|
|
9363
|
+
/* @__PURE__ */ jsx(
|
|
9364
|
+
m.div,
|
|
9365
|
+
{
|
|
9366
|
+
initial: reduced ? false : { scale: 0.9, opacity: 0 },
|
|
9367
|
+
animate: { scale: 1, opacity: 1 },
|
|
9368
|
+
exit: reduced ? { opacity: 0 } : { scale: 0.9, opacity: 0 },
|
|
9369
|
+
transition: reduced ? noMotion : springBouncy,
|
|
9370
|
+
className: "w-full max-w-5xl px-4",
|
|
9371
|
+
onClick: (e) => e.stopPropagation(),
|
|
9372
|
+
children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-xl", style: { aspectRatio }, children: /* @__PURE__ */ jsx(
|
|
9373
|
+
"iframe",
|
|
9374
|
+
{
|
|
9375
|
+
src: videoSrc,
|
|
9376
|
+
className: "size-full",
|
|
9377
|
+
allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
|
|
9378
|
+
allowFullScreen: true,
|
|
9379
|
+
title: thumbnailAlt
|
|
9380
|
+
}
|
|
9381
|
+
) })
|
|
9382
|
+
}
|
|
9383
|
+
)
|
|
9384
|
+
]
|
|
9385
|
+
}
|
|
9386
|
+
) })
|
|
9387
|
+
] });
|
|
9388
|
+
}
|
|
9389
|
+
function Hotspot({ children, className }) {
|
|
9390
|
+
return /* @__PURE__ */ jsx("div", { className: cn("relative", className), "data-slot": "hotspot", children });
|
|
9391
|
+
}
|
|
9392
|
+
function HotspotMarker({
|
|
9393
|
+
x,
|
|
9394
|
+
y,
|
|
9395
|
+
label,
|
|
9396
|
+
description,
|
|
9397
|
+
color = "hsl(var(--primary))",
|
|
9398
|
+
className
|
|
9399
|
+
}) {
|
|
9400
|
+
const [hovered, setHovered] = useState(false);
|
|
9401
|
+
return /* @__PURE__ */ jsxs(
|
|
9402
|
+
"div",
|
|
9403
|
+
{
|
|
9404
|
+
className: cn("absolute z-10", className),
|
|
9405
|
+
style: { left: `${x}%`, top: `${y}%`, transform: "translate(-50%, -50%)" },
|
|
9406
|
+
onMouseEnter: () => setHovered(true),
|
|
9407
|
+
onMouseLeave: () => setHovered(false),
|
|
9408
|
+
"data-slot": "hotspot-marker",
|
|
9409
|
+
children: [
|
|
9410
|
+
/* @__PURE__ */ jsx(
|
|
9411
|
+
"div",
|
|
9412
|
+
{
|
|
9413
|
+
className: "absolute inset-0 animate-ping rounded-full opacity-30",
|
|
9414
|
+
style: { backgroundColor: color, width: 24, height: 24, margin: -4 },
|
|
9415
|
+
"aria-hidden": "true"
|
|
9416
|
+
}
|
|
9417
|
+
),
|
|
9418
|
+
/* @__PURE__ */ jsx(
|
|
9419
|
+
"button",
|
|
9420
|
+
{
|
|
9421
|
+
type: "button",
|
|
9422
|
+
className: "relative size-4 rounded-full border-2 border-background shadow-md",
|
|
9423
|
+
style: { backgroundColor: color },
|
|
9424
|
+
"aria-label": label
|
|
9425
|
+
}
|
|
9426
|
+
),
|
|
9427
|
+
hovered && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-full left-1/2 mb-2 -translate-x-1/2 whitespace-nowrap rounded-lg bg-popover px-3 py-2 text-sm shadow-lg", children: [
|
|
9428
|
+
/* @__PURE__ */ jsx("p", { className: "font-semibold text-popover-foreground", children: label }),
|
|
9429
|
+
description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description })
|
|
9430
|
+
] })
|
|
9431
|
+
]
|
|
9432
|
+
}
|
|
9433
|
+
);
|
|
9434
|
+
}
|
|
9435
|
+
function ImageSwapHover({
|
|
9436
|
+
src,
|
|
9437
|
+
hoverSrc,
|
|
9438
|
+
alt,
|
|
9439
|
+
aspectRatio = "1/1",
|
|
9440
|
+
className
|
|
9441
|
+
}) {
|
|
9442
|
+
return /* @__PURE__ */ jsxs(
|
|
9443
|
+
"div",
|
|
9444
|
+
{
|
|
9445
|
+
className: cn("group relative overflow-hidden rounded-xl", className),
|
|
9446
|
+
style: { aspectRatio },
|
|
9447
|
+
"data-slot": "image-swap-hover",
|
|
9448
|
+
children: [
|
|
9449
|
+
/* @__PURE__ */ jsx(
|
|
9450
|
+
"img",
|
|
9451
|
+
{
|
|
9452
|
+
src,
|
|
9453
|
+
alt,
|
|
9454
|
+
className: "absolute inset-0 size-full object-cover transition-opacity duration-300 group-hover:opacity-0"
|
|
9455
|
+
}
|
|
9456
|
+
),
|
|
9457
|
+
/* @__PURE__ */ jsx(
|
|
9458
|
+
"img",
|
|
9459
|
+
{
|
|
9460
|
+
src: hoverSrc,
|
|
9461
|
+
alt,
|
|
9462
|
+
className: "absolute inset-0 size-full object-cover opacity-0 transition-opacity duration-300 group-hover:opacity-100",
|
|
9463
|
+
"aria-hidden": "true"
|
|
9464
|
+
}
|
|
9465
|
+
)
|
|
9466
|
+
]
|
|
9467
|
+
}
|
|
9468
|
+
);
|
|
9469
|
+
}
|
|
9470
|
+
function Marquee({
|
|
9471
|
+
children,
|
|
9472
|
+
reverse = false,
|
|
9473
|
+
speed = 40,
|
|
9474
|
+
pauseOnHover = true,
|
|
9475
|
+
gap = 48,
|
|
9476
|
+
repeat = 2,
|
|
9477
|
+
vertical = false,
|
|
9478
|
+
className
|
|
9479
|
+
}) {
|
|
9480
|
+
const reduced = useReducedMotion();
|
|
9481
|
+
if (reduced) {
|
|
9482
|
+
return /* @__PURE__ */ jsx(
|
|
9483
|
+
"div",
|
|
9484
|
+
{
|
|
9485
|
+
className: cn(
|
|
9486
|
+
"flex items-center overflow-hidden",
|
|
9487
|
+
vertical ? "flex-col" : "flex-row",
|
|
9488
|
+
className
|
|
9489
|
+
),
|
|
9490
|
+
style: { gap },
|
|
9491
|
+
"data-slot": "marquee",
|
|
9492
|
+
children
|
|
9493
|
+
}
|
|
9494
|
+
);
|
|
9495
|
+
}
|
|
9496
|
+
const animationName = vertical ? "marquee-vertical" : "marquee-horizontal";
|
|
9497
|
+
const direction = reverse ? "reverse" : "normal";
|
|
9498
|
+
return /* @__PURE__ */ jsxs(
|
|
9499
|
+
"div",
|
|
9500
|
+
{
|
|
9501
|
+
className: cn(
|
|
9502
|
+
"group relative flex overflow-hidden",
|
|
9503
|
+
vertical ? "flex-col" : "flex-row",
|
|
9504
|
+
className
|
|
9505
|
+
),
|
|
9506
|
+
"data-slot": "marquee",
|
|
9507
|
+
children: [
|
|
9508
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
9509
|
+
@keyframes marquee-horizontal {
|
|
9510
|
+
from { transform: translateX(0); }
|
|
9511
|
+
to { transform: translateX(-100%); }
|
|
9512
|
+
}
|
|
9513
|
+
@keyframes marquee-vertical {
|
|
9514
|
+
from { transform: translateY(0); }
|
|
9515
|
+
to { transform: translateY(-100%); }
|
|
9516
|
+
}
|
|
9517
|
+
` }),
|
|
9518
|
+
Array.from({ length: repeat }, (_, i) => /* @__PURE__ */ jsx(
|
|
9519
|
+
"div",
|
|
9520
|
+
{
|
|
9521
|
+
className: cn(
|
|
9522
|
+
"flex shrink-0 items-center",
|
|
9523
|
+
vertical ? "flex-col" : "flex-row",
|
|
9524
|
+
pauseOnHover && "group-hover:[animation-play-state:paused]"
|
|
9525
|
+
),
|
|
9526
|
+
style: {
|
|
9527
|
+
gap,
|
|
9528
|
+
animation: `${animationName} ${speed}s linear infinite`,
|
|
9529
|
+
animationDirection: direction
|
|
9530
|
+
},
|
|
9531
|
+
"aria-hidden": i > 0,
|
|
9532
|
+
children
|
|
9533
|
+
},
|
|
9534
|
+
i
|
|
9535
|
+
))
|
|
9536
|
+
]
|
|
9537
|
+
}
|
|
9538
|
+
);
|
|
9539
|
+
}
|
|
9540
|
+
function MouseGradientBlob({
|
|
9541
|
+
size = 500,
|
|
9542
|
+
colors = ["hsl(var(--primary))", "hsl(var(--chart-2))"],
|
|
9543
|
+
opacity = 0.15,
|
|
9544
|
+
blur = 80,
|
|
9545
|
+
className
|
|
9546
|
+
}) {
|
|
9547
|
+
const reduced = useReducedMotion();
|
|
9548
|
+
const mouseX = useMotionValue(0);
|
|
9549
|
+
const mouseY = useMotionValue(0);
|
|
9550
|
+
const blobX = useSpring(mouseX, { stiffness: 150, damping: 20 });
|
|
9551
|
+
const blobY = useSpring(mouseY, { stiffness: 150, damping: 20 });
|
|
9552
|
+
const onMouseMove = useCallback(
|
|
9553
|
+
(e) => {
|
|
9554
|
+
const target = e.currentTarget;
|
|
9555
|
+
const rect = target.getBoundingClientRect();
|
|
9556
|
+
mouseX.set(e.clientX - rect.left - size / 2);
|
|
9557
|
+
mouseY.set(e.clientY - rect.top - size / 2);
|
|
9558
|
+
},
|
|
9559
|
+
[mouseX, mouseY, size]
|
|
9560
|
+
);
|
|
9561
|
+
useEffect(() => {
|
|
9562
|
+
const parent = document.querySelector("[data-blob-container]");
|
|
9563
|
+
if (!parent || reduced) return;
|
|
9564
|
+
parent.addEventListener("mousemove", onMouseMove, { passive: true });
|
|
9565
|
+
return () => parent.removeEventListener("mousemove", onMouseMove);
|
|
9566
|
+
}, [onMouseMove, reduced]);
|
|
9567
|
+
if (reduced) return null;
|
|
9568
|
+
return /* @__PURE__ */ jsx(
|
|
9569
|
+
"div",
|
|
9570
|
+
{
|
|
9571
|
+
"data-blob-container": true,
|
|
9572
|
+
className: cn("pointer-events-none absolute inset-0 overflow-hidden", className),
|
|
9573
|
+
"aria-hidden": "true",
|
|
9574
|
+
children: /* @__PURE__ */ jsx(
|
|
9575
|
+
m.div,
|
|
9576
|
+
{
|
|
9577
|
+
style: {
|
|
9578
|
+
x: blobX,
|
|
9579
|
+
y: blobY,
|
|
9580
|
+
width: size,
|
|
9581
|
+
height: size,
|
|
9582
|
+
background: `radial-gradient(circle, ${colors[0]} 0%, ${colors[1]} 50%, transparent 70%)`,
|
|
9583
|
+
opacity,
|
|
9584
|
+
filter: `blur(${blur}px)`,
|
|
9585
|
+
borderRadius: "50%",
|
|
9586
|
+
position: "absolute",
|
|
9587
|
+
top: 0,
|
|
9588
|
+
left: 0
|
|
9589
|
+
}
|
|
9590
|
+
}
|
|
9591
|
+
)
|
|
9592
|
+
}
|
|
9593
|
+
);
|
|
9594
|
+
}
|
|
9595
|
+
function MovingBorder({
|
|
9596
|
+
children,
|
|
9597
|
+
colors = ["hsl(var(--primary))", "hsl(var(--chart-1))", "hsl(var(--chart-2))"],
|
|
9598
|
+
duration = 6,
|
|
9599
|
+
borderWidth = 1.5,
|
|
9600
|
+
borderRadius = "0.75rem",
|
|
9601
|
+
className
|
|
9602
|
+
}) {
|
|
9603
|
+
const reduced = useReducedMotion();
|
|
9604
|
+
const gradientStops = [...colors, colors[0]].join(", ");
|
|
9605
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9606
|
+
!reduced && /* @__PURE__ */ jsx("style", { children: `
|
|
9607
|
+
@keyframes sf-border-rotate {
|
|
9608
|
+
from { --sf-border-angle: 0deg; }
|
|
9609
|
+
to { --sf-border-angle: 360deg; }
|
|
9610
|
+
}
|
|
9611
|
+
@property --sf-border-angle {
|
|
9612
|
+
syntax: "<angle>";
|
|
9613
|
+
initial-value: 0deg;
|
|
9614
|
+
inherits: false;
|
|
9615
|
+
}
|
|
9616
|
+
` }),
|
|
9617
|
+
/* @__PURE__ */ jsx(
|
|
9618
|
+
"div",
|
|
9619
|
+
{
|
|
9620
|
+
className: cn("relative", className),
|
|
9621
|
+
style: {
|
|
9622
|
+
padding: borderWidth,
|
|
9623
|
+
borderRadius,
|
|
9624
|
+
background: reduced ? `linear-gradient(135deg, ${gradientStops})` : `conic-gradient(from var(--sf-border-angle, 0deg), ${gradientStops})`,
|
|
9625
|
+
...reduced ? {} : { animation: `sf-border-rotate ${duration}s linear infinite` }
|
|
9626
|
+
},
|
|
9627
|
+
"data-slot": "moving-border",
|
|
9628
|
+
children: /* @__PURE__ */ jsx(
|
|
9629
|
+
"div",
|
|
9630
|
+
{
|
|
9631
|
+
className: "relative bg-background",
|
|
9632
|
+
style: { borderRadius: `calc(${borderRadius} - ${borderWidth}px)` },
|
|
9633
|
+
children
|
|
9634
|
+
}
|
|
9635
|
+
)
|
|
9636
|
+
}
|
|
9637
|
+
)
|
|
9638
|
+
] });
|
|
9639
|
+
}
|
|
9640
|
+
var VARIANTS = {
|
|
9641
|
+
fade: {
|
|
9642
|
+
initial: { opacity: 0 },
|
|
9643
|
+
animate: { opacity: 1 },
|
|
9644
|
+
exit: { opacity: 0 }
|
|
9645
|
+
},
|
|
9646
|
+
slideUp: {
|
|
9647
|
+
initial: { opacity: 0, y: 16 },
|
|
9648
|
+
animate: { opacity: 1, y: 0 },
|
|
9649
|
+
exit: { opacity: 0, y: -16 }
|
|
9650
|
+
},
|
|
9651
|
+
slideDown: {
|
|
9652
|
+
initial: { opacity: 0, y: -16 },
|
|
9653
|
+
animate: { opacity: 1, y: 0 },
|
|
9654
|
+
exit: { opacity: 0, y: 16 }
|
|
9655
|
+
},
|
|
9656
|
+
scale: {
|
|
9657
|
+
initial: { opacity: 0, scale: 0.96 },
|
|
9658
|
+
animate: { opacity: 1, scale: 1 },
|
|
9659
|
+
exit: { opacity: 0, scale: 0.96 }
|
|
9660
|
+
}
|
|
9661
|
+
};
|
|
9662
|
+
function PageTransition({
|
|
9663
|
+
children,
|
|
9664
|
+
variant = "fade",
|
|
9665
|
+
duration = 0.3,
|
|
9666
|
+
transitionKey,
|
|
9667
|
+
className
|
|
9668
|
+
}) {
|
|
9669
|
+
const reduced = useReducedMotion();
|
|
9670
|
+
if (reduced) {
|
|
9671
|
+
return /* @__PURE__ */ jsx("div", { className, children });
|
|
9672
|
+
}
|
|
9673
|
+
const preset = VARIANTS[variant];
|
|
9674
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
|
|
9675
|
+
m.div,
|
|
9676
|
+
{
|
|
9677
|
+
initial: preset.initial,
|
|
9678
|
+
animate: preset.animate,
|
|
9679
|
+
exit: preset.exit,
|
|
9680
|
+
transition: { duration, ease: "easeInOut" },
|
|
9681
|
+
className: cn("will-change-[opacity,transform]", className),
|
|
9682
|
+
children
|
|
9683
|
+
},
|
|
9684
|
+
transitionKey
|
|
9685
|
+
) });
|
|
9686
|
+
}
|
|
9687
|
+
function ParallaxSection({
|
|
9688
|
+
children,
|
|
9689
|
+
speed = 0.5,
|
|
9690
|
+
className
|
|
9691
|
+
}) {
|
|
9692
|
+
const reduced = useReducedMotion();
|
|
9693
|
+
const ref = useRef(null);
|
|
9694
|
+
const { scrollYProgress } = useScroll({
|
|
9695
|
+
target: ref,
|
|
9696
|
+
offset: ["start end", "end start"]
|
|
9697
|
+
});
|
|
9698
|
+
const offset = (1 - speed) * 100;
|
|
9699
|
+
const y = useTransform(scrollYProgress, [0, 1], [`-${offset}px`, `${offset}px`]);
|
|
9700
|
+
if (reduced) {
|
|
9701
|
+
return /* @__PURE__ */ jsx("div", { className, children });
|
|
9702
|
+
}
|
|
9703
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn("relative overflow-hidden", className), "data-slot": "parallax-section", children: /* @__PURE__ */ jsx(m.div, { style: { y }, children }) });
|
|
9704
|
+
}
|
|
9705
|
+
function seededRandom(seed) {
|
|
9706
|
+
const x = Math.sin(seed * 9301 + 49297) * 233280;
|
|
9707
|
+
return x - Math.floor(x);
|
|
9708
|
+
}
|
|
9709
|
+
function ParticlesBackground({
|
|
9710
|
+
count = 20,
|
|
9711
|
+
color = "hsl(var(--primary))",
|
|
9712
|
+
maxSize = 4,
|
|
9713
|
+
minSize = 1,
|
|
9714
|
+
maxOpacity = 0.3,
|
|
9715
|
+
speed = 1,
|
|
9716
|
+
className
|
|
9717
|
+
}) {
|
|
9718
|
+
const reduced = useReducedMotion();
|
|
9719
|
+
const particles = useMemo(
|
|
9720
|
+
() => Array.from({ length: count }, (_, i) => {
|
|
9721
|
+
const r = (seed) => seededRandom(i * 100 + seed);
|
|
9722
|
+
const size = minSize + r(1) * (maxSize - minSize);
|
|
9723
|
+
const duration = (15 + r(2) * 25) / speed;
|
|
9724
|
+
const delay = r(3) * -duration;
|
|
9725
|
+
return {
|
|
9726
|
+
id: i,
|
|
9727
|
+
size,
|
|
9728
|
+
x: r(4) * 100,
|
|
9729
|
+
y: r(5) * 100,
|
|
9730
|
+
opacity: 0.05 + r(6) * maxOpacity,
|
|
9731
|
+
duration,
|
|
9732
|
+
delay,
|
|
9733
|
+
driftX: (r(7) - 0.5) * 40,
|
|
9734
|
+
driftY: -20 - r(8) * 40
|
|
9735
|
+
};
|
|
9736
|
+
}),
|
|
9737
|
+
[count, minSize, maxSize, maxOpacity, speed]
|
|
9738
|
+
);
|
|
9739
|
+
if (reduced) return null;
|
|
9740
|
+
return /* @__PURE__ */ jsxs(
|
|
9741
|
+
"div",
|
|
9742
|
+
{
|
|
9743
|
+
className: cn("pointer-events-none absolute inset-0 overflow-hidden", className),
|
|
9744
|
+
"aria-hidden": "true",
|
|
9745
|
+
"data-slot": "particles-background",
|
|
9746
|
+
children: [
|
|
9747
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
9748
|
+
@keyframes sf-particle-drift {
|
|
9749
|
+
0%, 100% { transform: translate(0, 0); }
|
|
9750
|
+
50% { transform: translate(var(--drift-x), var(--drift-y)); }
|
|
9751
|
+
}
|
|
9752
|
+
` }),
|
|
9753
|
+
particles.map((p) => /* @__PURE__ */ jsx(
|
|
9754
|
+
"div",
|
|
9755
|
+
{
|
|
9756
|
+
style: {
|
|
9757
|
+
position: "absolute",
|
|
9758
|
+
left: `${p.x}%`,
|
|
9759
|
+
top: `${p.y}%`,
|
|
9760
|
+
width: p.size,
|
|
9761
|
+
height: p.size,
|
|
9762
|
+
backgroundColor: color,
|
|
9763
|
+
borderRadius: "50%",
|
|
9764
|
+
opacity: p.opacity,
|
|
9765
|
+
["--drift-x"]: `${p.driftX}px`,
|
|
9766
|
+
["--drift-y"]: `${p.driftY}px`,
|
|
9767
|
+
animation: `sf-particle-drift ${p.duration}s ease-in-out ${p.delay}s infinite`
|
|
9768
|
+
}
|
|
9769
|
+
},
|
|
9770
|
+
p.id
|
|
9771
|
+
))
|
|
9772
|
+
]
|
|
9773
|
+
}
|
|
9774
|
+
);
|
|
9775
|
+
}
|
|
9776
|
+
function RetroGrid({
|
|
9777
|
+
gridColor = "hsl(var(--border))",
|
|
9778
|
+
gridSize = 60,
|
|
9779
|
+
angle = 65,
|
|
9780
|
+
opacity = 0.4,
|
|
9781
|
+
className
|
|
9782
|
+
}) {
|
|
9783
|
+
return /* @__PURE__ */ jsx(
|
|
9784
|
+
"div",
|
|
9785
|
+
{
|
|
9786
|
+
className: cn("pointer-events-none absolute inset-0 overflow-hidden", className),
|
|
9787
|
+
"aria-hidden": "true",
|
|
9788
|
+
"data-slot": "retro-grid",
|
|
9789
|
+
children: /* @__PURE__ */ jsx(
|
|
9790
|
+
"div",
|
|
9791
|
+
{
|
|
9792
|
+
style: {
|
|
9793
|
+
position: "absolute",
|
|
9794
|
+
inset: 0,
|
|
9795
|
+
backgroundImage: `
|
|
9796
|
+
linear-gradient(to right, ${gridColor} 1px, transparent 1px),
|
|
9797
|
+
linear-gradient(to bottom, ${gridColor} 1px, transparent 1px)
|
|
9798
|
+
`,
|
|
9799
|
+
backgroundSize: `${gridSize}px ${gridSize}px`,
|
|
9800
|
+
opacity,
|
|
9801
|
+
transform: `perspective(500px) rotateX(${angle}deg)`,
|
|
9802
|
+
transformOrigin: "bottom center",
|
|
9803
|
+
maskImage: "linear-gradient(to bottom, transparent 0%, black 30%, black 70%, transparent 100%)",
|
|
9804
|
+
WebkitMaskImage: "linear-gradient(to bottom, transparent 0%, black 30%, black 70%, transparent 100%)"
|
|
9805
|
+
}
|
|
9806
|
+
}
|
|
9807
|
+
)
|
|
9808
|
+
}
|
|
9809
|
+
);
|
|
9810
|
+
}
|
|
9811
|
+
var DIRECTION_OFFSET = {
|
|
9812
|
+
up: { x: 0, y: 24 },
|
|
9813
|
+
down: { x: 0, y: -24 },
|
|
9814
|
+
left: { x: -24, y: 0 },
|
|
9815
|
+
right: { x: 24, y: 0 },
|
|
9816
|
+
none: { x: 0, y: 0 }
|
|
9817
|
+
};
|
|
9818
|
+
function RevealOnScroll({
|
|
9819
|
+
children,
|
|
9820
|
+
direction = "up",
|
|
9821
|
+
delay = 0,
|
|
9822
|
+
rootMargin = "-80px",
|
|
9823
|
+
once = true,
|
|
9824
|
+
className
|
|
9825
|
+
}) {
|
|
9826
|
+
const reduced = useReducedMotion();
|
|
9827
|
+
const ref = useRef(null);
|
|
9828
|
+
const isInView = useInView(ref, { once, margin: rootMargin });
|
|
9829
|
+
if (reduced) {
|
|
9830
|
+
return /* @__PURE__ */ jsx("div", { className, children });
|
|
9831
|
+
}
|
|
9832
|
+
const offset = DIRECTION_OFFSET[direction];
|
|
9833
|
+
return /* @__PURE__ */ jsx(
|
|
9834
|
+
m.div,
|
|
9835
|
+
{
|
|
9836
|
+
ref,
|
|
9837
|
+
initial: { opacity: 0, x: offset.x, y: offset.y },
|
|
9838
|
+
animate: isInView ? { opacity: 1, x: 0, y: 0 } : { opacity: 0, x: offset.x, y: offset.y },
|
|
9839
|
+
transition: { ...springGentle, delay },
|
|
9840
|
+
className: cn("will-change-[opacity,transform]", className),
|
|
9841
|
+
"data-slot": "reveal-on-scroll",
|
|
9842
|
+
children
|
|
9843
|
+
}
|
|
9844
|
+
);
|
|
9845
|
+
}
|
|
9846
|
+
function ShimmerButton({
|
|
9847
|
+
children,
|
|
9848
|
+
shimmerColor = "rgba(255,255,255,0.2)",
|
|
9849
|
+
speed = 2.5,
|
|
9850
|
+
background = "hsl(var(--primary))",
|
|
9851
|
+
className,
|
|
9852
|
+
...props
|
|
9853
|
+
}) {
|
|
9854
|
+
const reduced = useReducedMotion();
|
|
9855
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9856
|
+
!reduced && /* @__PURE__ */ jsx("style", { children: `
|
|
9857
|
+
@keyframes sf-shimmer-slide {
|
|
9858
|
+
from { transform: translateX(-100%) rotate(-15deg); }
|
|
9859
|
+
to { transform: translateX(200%) rotate(-15deg); }
|
|
9860
|
+
}
|
|
9861
|
+
` }),
|
|
9862
|
+
/* @__PURE__ */ jsxs(
|
|
9863
|
+
"button",
|
|
9864
|
+
{
|
|
9865
|
+
className: cn(
|
|
9866
|
+
"relative inline-flex h-10 items-center justify-center overflow-hidden rounded-md px-6 text-sm font-medium text-primary-foreground shadow-sm transition-all hover:brightness-110",
|
|
9867
|
+
className
|
|
9868
|
+
),
|
|
9869
|
+
style: { background },
|
|
9870
|
+
"data-slot": "shimmer-button",
|
|
9871
|
+
...props,
|
|
9872
|
+
children: [
|
|
9873
|
+
!reduced && /* @__PURE__ */ jsx(
|
|
9874
|
+
"div",
|
|
9875
|
+
{
|
|
9876
|
+
className: "pointer-events-none absolute inset-0",
|
|
9877
|
+
style: {
|
|
9878
|
+
background: `linear-gradient(
|
|
9879
|
+
-15deg,
|
|
9880
|
+
transparent 30%,
|
|
9881
|
+
${shimmerColor} 50%,
|
|
9882
|
+
transparent 70%
|
|
9883
|
+
)`,
|
|
9884
|
+
backgroundSize: "200% 100%",
|
|
9885
|
+
animation: `sf-shimmer-slide ${speed}s ease-in-out infinite`
|
|
9886
|
+
},
|
|
9887
|
+
"aria-hidden": "true"
|
|
9888
|
+
}
|
|
9889
|
+
),
|
|
9890
|
+
/* @__PURE__ */ jsx("span", { className: "relative z-10", children })
|
|
9891
|
+
]
|
|
9892
|
+
}
|
|
9893
|
+
)
|
|
9894
|
+
] });
|
|
9895
|
+
}
|
|
9896
|
+
var PROVIDERS = {
|
|
9897
|
+
google: {
|
|
9898
|
+
label: "Google",
|
|
9899
|
+
bg: "bg-white hover:bg-gray-50 border",
|
|
9900
|
+
fg: "text-gray-700",
|
|
9901
|
+
icon: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18A10.96 10.96 0 001 12c0 1.77.42 3.45 1.18 4.93l3.66-2.84z M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
|
9902
|
+
},
|
|
9903
|
+
apple: {
|
|
9904
|
+
label: "Apple",
|
|
9905
|
+
bg: "bg-black hover:bg-gray-900",
|
|
9906
|
+
fg: "text-white",
|
|
9907
|
+
icon: "M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.8-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"
|
|
9908
|
+
},
|
|
9909
|
+
github: {
|
|
9910
|
+
label: "GitHub",
|
|
9911
|
+
bg: "bg-[#24292f] hover:bg-[#1b1f23]",
|
|
9912
|
+
fg: "text-white",
|
|
9913
|
+
icon: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
|
|
9914
|
+
},
|
|
9915
|
+
microsoft: {
|
|
9916
|
+
label: "Microsoft",
|
|
9917
|
+
bg: "bg-white hover:bg-gray-50 border",
|
|
9918
|
+
fg: "text-gray-700",
|
|
9919
|
+
icon: "M3 3h8v8H3V3zm10 0h8v8h-8V3zM3 13h8v8H3v-8zm10 0h8v8h-8v-8z"
|
|
9920
|
+
},
|
|
9921
|
+
twitter: {
|
|
9922
|
+
label: "X (Twitter)",
|
|
9923
|
+
bg: "bg-black hover:bg-gray-900",
|
|
9924
|
+
fg: "text-white",
|
|
9925
|
+
icon: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"
|
|
9926
|
+
}
|
|
9927
|
+
};
|
|
9928
|
+
function SocialButton({
|
|
9929
|
+
provider,
|
|
9930
|
+
label: labelOverride,
|
|
9931
|
+
iconOnly = false,
|
|
9932
|
+
className,
|
|
9933
|
+
...props
|
|
9934
|
+
}) {
|
|
9935
|
+
const config = PROVIDERS[provider];
|
|
9936
|
+
const displayLabel = labelOverride ?? `Continue with ${config.label}`;
|
|
9937
|
+
return /* @__PURE__ */ jsxs(
|
|
9938
|
+
"button",
|
|
9939
|
+
{
|
|
9940
|
+
type: "button",
|
|
9941
|
+
className: cn(
|
|
9942
|
+
"inline-flex items-center justify-center gap-3 rounded-lg px-4 py-2.5 text-sm font-medium transition-colors",
|
|
9943
|
+
config.bg,
|
|
9944
|
+
config.fg,
|
|
9945
|
+
iconOnly && "px-2.5",
|
|
9946
|
+
className
|
|
9947
|
+
),
|
|
9948
|
+
"aria-label": displayLabel,
|
|
9949
|
+
"data-slot": "social-button",
|
|
9950
|
+
...props,
|
|
9951
|
+
children: [
|
|
9952
|
+
/* @__PURE__ */ jsx("svg", { className: "size-5", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: config.icon }) }),
|
|
9953
|
+
!iconOnly && /* @__PURE__ */ jsx("span", { children: displayLabel })
|
|
9954
|
+
]
|
|
9955
|
+
}
|
|
9956
|
+
);
|
|
9957
|
+
}
|
|
9958
|
+
function SpotlightCard({
|
|
9959
|
+
children,
|
|
9960
|
+
spotlightColor = "hsl(var(--primary))",
|
|
9961
|
+
spotlightSize = 250,
|
|
9962
|
+
spotlightOpacity = 0.08,
|
|
9963
|
+
className,
|
|
9964
|
+
surface,
|
|
9965
|
+
radius,
|
|
9966
|
+
animated
|
|
9967
|
+
}) {
|
|
9968
|
+
const sf = useSaasflareProps({ surface, radius, animated });
|
|
9969
|
+
const reduced = useReducedMotion();
|
|
9970
|
+
const cardRef = useRef(null);
|
|
9971
|
+
const position = useMousePosition({ ref: cardRef, enabled: !reduced });
|
|
9972
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
9973
|
+
return /* @__PURE__ */ jsxs(
|
|
9974
|
+
m.div,
|
|
9975
|
+
{
|
|
9976
|
+
ref: cardRef,
|
|
9977
|
+
onMouseEnter: reduced ? void 0 : () => setIsHovered(true),
|
|
9978
|
+
onMouseLeave: reduced ? void 0 : () => setIsHovered(false),
|
|
9979
|
+
"data-slot": "spotlight-card",
|
|
9980
|
+
"data-surface": sf.surface,
|
|
9981
|
+
"data-radius": sf.radius,
|
|
9982
|
+
className: cn(
|
|
9983
|
+
"relative overflow-hidden rounded-xl border surface-card p-6 text-card-foreground",
|
|
9984
|
+
"transition-all duration-200 hover:-translate-y-px hover:shadow-md",
|
|
9985
|
+
"motion-reduce:hover:transform-none",
|
|
9986
|
+
className
|
|
9987
|
+
),
|
|
9988
|
+
children: [
|
|
9989
|
+
!reduced && /* @__PURE__ */ jsx(
|
|
9990
|
+
"div",
|
|
9991
|
+
{
|
|
9992
|
+
className: "pointer-events-none absolute inset-0 transition-opacity duration-300",
|
|
9993
|
+
style: {
|
|
9994
|
+
opacity: isHovered ? 1 : 0,
|
|
9995
|
+
background: `radial-gradient(${spotlightSize}px circle at ${position.x}px ${position.y}px, ${spotlightColor} 0%, transparent 70%)`,
|
|
9996
|
+
...spotlightOpacity < 1 && { opacity: isHovered ? spotlightOpacity : 0 }
|
|
9997
|
+
},
|
|
9998
|
+
"aria-hidden": "true"
|
|
9999
|
+
}
|
|
10000
|
+
),
|
|
10001
|
+
/* @__PURE__ */ jsx("div", { className: "relative z-10", children })
|
|
10002
|
+
]
|
|
10003
|
+
}
|
|
10004
|
+
);
|
|
10005
|
+
}
|
|
10006
|
+
function StatCard({
|
|
10007
|
+
value,
|
|
10008
|
+
label,
|
|
10009
|
+
icon,
|
|
10010
|
+
className,
|
|
10011
|
+
surface,
|
|
10012
|
+
radius,
|
|
10013
|
+
animated
|
|
10014
|
+
}) {
|
|
10015
|
+
const sf = useSaasflareProps({ surface, radius, animated });
|
|
10016
|
+
return /* @__PURE__ */ jsxs(
|
|
10017
|
+
"div",
|
|
10018
|
+
{
|
|
10019
|
+
"data-slot": "stat-card",
|
|
10020
|
+
"data-surface": sf.surface,
|
|
10021
|
+
"data-radius": sf.radius,
|
|
10022
|
+
className: cn(
|
|
10023
|
+
"flex flex-col items-center rounded-xl border surface-card p-6 text-center",
|
|
10024
|
+
"transition-all duration-200 hover:-translate-y-px hover:shadow-md",
|
|
10025
|
+
"motion-reduce:hover:transform-none",
|
|
10026
|
+
className
|
|
10027
|
+
),
|
|
10028
|
+
children: [
|
|
10029
|
+
icon && /* @__PURE__ */ jsx("div", { className: "mb-3 text-primary [&_svg]:size-6", children: icon }),
|
|
10030
|
+
/* @__PURE__ */ jsx("p", { className: "text-3xl font-bold tracking-tight", children: value }),
|
|
10031
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: label })
|
|
10032
|
+
]
|
|
10033
|
+
}
|
|
10034
|
+
);
|
|
10035
|
+
}
|
|
10036
|
+
function Steps({
|
|
10037
|
+
children,
|
|
10038
|
+
current = 0,
|
|
10039
|
+
direction = "horizontal",
|
|
10040
|
+
className
|
|
10041
|
+
}) {
|
|
10042
|
+
const items = Children.toArray(children);
|
|
10043
|
+
return /* @__PURE__ */ jsx(
|
|
10044
|
+
"div",
|
|
10045
|
+
{
|
|
10046
|
+
className: cn(
|
|
10047
|
+
"flex",
|
|
10048
|
+
direction === "horizontal" ? "flex-row items-start" : "flex-col",
|
|
10049
|
+
className
|
|
10050
|
+
),
|
|
10051
|
+
"data-slot": "steps",
|
|
10052
|
+
role: "list",
|
|
10053
|
+
children: items.map((child, i) => {
|
|
10054
|
+
const status = i < current ? "completed" : i === current ? "active" : "pending";
|
|
10055
|
+
const isLast = i === items.length - 1;
|
|
10056
|
+
return /* @__PURE__ */ jsxs(
|
|
10057
|
+
"div",
|
|
10058
|
+
{
|
|
10059
|
+
className: cn(
|
|
10060
|
+
"flex",
|
|
10061
|
+
direction === "horizontal" ? "flex-1 flex-col items-center" : "flex-row gap-4"
|
|
10062
|
+
),
|
|
10063
|
+
role: "listitem",
|
|
10064
|
+
"aria-current": status === "active" ? "step" : void 0,
|
|
10065
|
+
children: [
|
|
10066
|
+
/* @__PURE__ */ jsxs("div", { className: cn(
|
|
10067
|
+
"flex items-center",
|
|
10068
|
+
direction === "horizontal" ? "w-full" : "flex-col"
|
|
10069
|
+
), children: [
|
|
10070
|
+
/* @__PURE__ */ jsx(
|
|
10071
|
+
"div",
|
|
10072
|
+
{
|
|
10073
|
+
className: cn(
|
|
10074
|
+
"flex size-9 shrink-0 items-center justify-center rounded-full border-2 text-sm font-semibold transition-colors",
|
|
10075
|
+
status === "completed" && "border-primary bg-primary text-primary-foreground",
|
|
10076
|
+
status === "active" && "border-primary bg-background text-primary",
|
|
10077
|
+
status === "pending" && "border-muted-foreground/30 bg-background text-muted-foreground"
|
|
10078
|
+
),
|
|
10079
|
+
children: status === "completed" ? /* @__PURE__ */ jsx("svg", { className: "size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) }) : child.props.icon ?? i + 1
|
|
10080
|
+
}
|
|
10081
|
+
),
|
|
10082
|
+
!isLast && /* @__PURE__ */ jsx(
|
|
10083
|
+
"div",
|
|
10084
|
+
{
|
|
10085
|
+
className: cn(
|
|
10086
|
+
direction === "horizontal" ? "h-0.5 flex-1" : "w-0.5 min-h-8 flex-1",
|
|
10087
|
+
status === "completed" ? "bg-primary" : "bg-border"
|
|
10088
|
+
)
|
|
10089
|
+
}
|
|
10090
|
+
)
|
|
10091
|
+
] }),
|
|
10092
|
+
/* @__PURE__ */ jsxs("div", { className: cn(
|
|
10093
|
+
direction === "horizontal" ? "mt-2 text-center" : "pb-8"
|
|
10094
|
+
), children: [
|
|
10095
|
+
/* @__PURE__ */ jsx("p", { className: cn(
|
|
10096
|
+
"text-sm font-medium",
|
|
10097
|
+
status === "pending" && "text-muted-foreground"
|
|
10098
|
+
), children: child.props.title }),
|
|
10099
|
+
child.props.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: child.props.description })
|
|
10100
|
+
] })
|
|
10101
|
+
]
|
|
10102
|
+
},
|
|
10103
|
+
i
|
|
10104
|
+
);
|
|
10105
|
+
})
|
|
10106
|
+
}
|
|
10107
|
+
);
|
|
10108
|
+
}
|
|
10109
|
+
function Step(_props) {
|
|
10110
|
+
return null;
|
|
10111
|
+
}
|
|
10112
|
+
function StickyScrollReveal({
|
|
10113
|
+
items,
|
|
10114
|
+
className
|
|
10115
|
+
}) {
|
|
10116
|
+
const reduced = useReducedMotion();
|
|
10117
|
+
const containerRef = useRef(null);
|
|
10118
|
+
if (reduced) {
|
|
10119
|
+
return /* @__PURE__ */ jsx("div", { className: cn("space-y-16", className), "data-slot": "sticky-scroll-reveal", children: items.map((item, i) => /* @__PURE__ */ jsxs("div", { className: "grid gap-8 md:grid-cols-2", children: [
|
|
10120
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
10121
|
+
/* @__PURE__ */ jsx("h3", { className: "text-2xl font-bold", children: item.title }),
|
|
10122
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: item.description })
|
|
10123
|
+
] }),
|
|
10124
|
+
item.content && /* @__PURE__ */ jsx("div", { className: "rounded-xl border bg-muted/50 p-4", children: item.content })
|
|
10125
|
+
] }, i)) });
|
|
10126
|
+
}
|
|
10127
|
+
return /* @__PURE__ */ jsx(
|
|
10128
|
+
"div",
|
|
10129
|
+
{
|
|
10130
|
+
ref: containerRef,
|
|
10131
|
+
className: cn("relative", className),
|
|
10132
|
+
"data-slot": "sticky-scroll-reveal",
|
|
10133
|
+
children: /* @__PURE__ */ jsxs("div", { className: "relative grid gap-8 md:grid-cols-2", children: [
|
|
10134
|
+
/* @__PURE__ */ jsx("div", { className: "relative md:h-fit", children: /* @__PURE__ */ jsx("div", { className: "sticky top-32 space-y-24", children: items.map((item, i) => /* @__PURE__ */ jsx(
|
|
10135
|
+
StickyItem,
|
|
10136
|
+
{
|
|
10137
|
+
item,
|
|
10138
|
+
index: i,
|
|
10139
|
+
total: items.length,
|
|
10140
|
+
containerRef
|
|
10141
|
+
},
|
|
10142
|
+
i
|
|
10143
|
+
)) }) }),
|
|
10144
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-24", children: items.map((item, i) => /* @__PURE__ */ jsx("div", { className: "sticky top-32", children: /* @__PURE__ */ jsx(
|
|
10145
|
+
StickyContent,
|
|
10146
|
+
{
|
|
10147
|
+
content: item.content,
|
|
10148
|
+
index: i,
|
|
10149
|
+
total: items.length,
|
|
10150
|
+
containerRef
|
|
10151
|
+
}
|
|
10152
|
+
) }, i)) })
|
|
10153
|
+
] })
|
|
10154
|
+
}
|
|
10155
|
+
);
|
|
10156
|
+
}
|
|
10157
|
+
function StickyItem({
|
|
10158
|
+
item,
|
|
10159
|
+
index,
|
|
10160
|
+
total,
|
|
10161
|
+
containerRef
|
|
10162
|
+
}) {
|
|
10163
|
+
const { scrollYProgress } = useScroll({
|
|
10164
|
+
target: containerRef,
|
|
10165
|
+
offset: ["start start", "end end"]
|
|
10166
|
+
});
|
|
10167
|
+
const sectionStart = index / total;
|
|
10168
|
+
const sectionEnd = (index + 1) / total;
|
|
10169
|
+
const opacity = useTransform(
|
|
10170
|
+
scrollYProgress,
|
|
10171
|
+
[sectionStart, sectionStart + 0.05, sectionEnd - 0.05, sectionEnd],
|
|
10172
|
+
[0.3, 1, 1, 0.3]
|
|
10173
|
+
);
|
|
10174
|
+
return /* @__PURE__ */ jsxs(m.div, { style: { opacity }, children: [
|
|
10175
|
+
/* @__PURE__ */ jsx("h3", { className: "text-2xl font-bold", children: item.title }),
|
|
10176
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: item.description })
|
|
10177
|
+
] });
|
|
10178
|
+
}
|
|
10179
|
+
function StickyContent({
|
|
10180
|
+
content,
|
|
10181
|
+
index,
|
|
10182
|
+
total,
|
|
10183
|
+
containerRef
|
|
10184
|
+
}) {
|
|
10185
|
+
const { scrollYProgress } = useScroll({
|
|
10186
|
+
target: containerRef,
|
|
10187
|
+
offset: ["start start", "end end"]
|
|
10188
|
+
});
|
|
10189
|
+
const sectionStart = index / total;
|
|
10190
|
+
const sectionEnd = (index + 1) / total;
|
|
10191
|
+
const opacity = useTransform(
|
|
10192
|
+
scrollYProgress,
|
|
10193
|
+
[sectionStart, sectionStart + 0.05, sectionEnd - 0.05, sectionEnd],
|
|
10194
|
+
[0, 1, 1, 0]
|
|
10195
|
+
);
|
|
10196
|
+
if (!content) return null;
|
|
10197
|
+
return /* @__PURE__ */ jsx(
|
|
10198
|
+
m.div,
|
|
10199
|
+
{
|
|
10200
|
+
style: { opacity },
|
|
10201
|
+
className: "overflow-hidden rounded-xl border bg-muted/50 p-4",
|
|
10202
|
+
children: content
|
|
10203
|
+
}
|
|
10204
|
+
);
|
|
10205
|
+
}
|
|
10206
|
+
function TeamCard({
|
|
10207
|
+
name,
|
|
10208
|
+
role,
|
|
10209
|
+
photo,
|
|
10210
|
+
bio,
|
|
10211
|
+
socials,
|
|
10212
|
+
className,
|
|
10213
|
+
surface,
|
|
10214
|
+
radius,
|
|
10215
|
+
animated
|
|
10216
|
+
}) {
|
|
10217
|
+
const sf = useSaasflareProps({ surface, radius, animated });
|
|
10218
|
+
return /* @__PURE__ */ jsxs(
|
|
10219
|
+
"div",
|
|
10220
|
+
{
|
|
10221
|
+
"data-slot": "team-card",
|
|
10222
|
+
"data-surface": sf.surface,
|
|
10223
|
+
"data-radius": sf.radius,
|
|
10224
|
+
className: cn(
|
|
10225
|
+
"flex flex-col items-center rounded-xl border surface-card p-6 text-center",
|
|
10226
|
+
"transition-all duration-200 hover:-translate-y-px hover:shadow-md",
|
|
10227
|
+
"motion-reduce:hover:transform-none",
|
|
10228
|
+
className
|
|
10229
|
+
),
|
|
10230
|
+
children: [
|
|
10231
|
+
photo && /* @__PURE__ */ jsx(
|
|
10232
|
+
"img",
|
|
10233
|
+
{
|
|
10234
|
+
src: photo,
|
|
10235
|
+
alt: name,
|
|
10236
|
+
className: "mb-4 size-24 rounded-full object-cover"
|
|
10237
|
+
}
|
|
10238
|
+
),
|
|
10239
|
+
/* @__PURE__ */ jsx("h3", { className: "text-base font-semibold", children: name }),
|
|
10240
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: role }),
|
|
10241
|
+
bio && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: bio }),
|
|
10242
|
+
socials && socials.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 flex gap-2", children: socials.map((s) => /* @__PURE__ */ jsx(
|
|
10243
|
+
"a",
|
|
10244
|
+
{
|
|
10245
|
+
href: s.url,
|
|
10246
|
+
target: "_blank",
|
|
10247
|
+
rel: "noopener noreferrer",
|
|
10248
|
+
className: "rounded-md p-2 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
10249
|
+
"aria-label": s.label,
|
|
10250
|
+
children: s.icon
|
|
10251
|
+
},
|
|
10252
|
+
s.label
|
|
10253
|
+
)) })
|
|
10254
|
+
]
|
|
10255
|
+
}
|
|
10256
|
+
);
|
|
10257
|
+
}
|
|
10258
|
+
function TestimonialCard({
|
|
10259
|
+
quote,
|
|
10260
|
+
name,
|
|
10261
|
+
role,
|
|
10262
|
+
avatar,
|
|
10263
|
+
rating,
|
|
10264
|
+
className,
|
|
10265
|
+
surface,
|
|
10266
|
+
radius,
|
|
10267
|
+
animated
|
|
10268
|
+
}) {
|
|
10269
|
+
const sf = useSaasflareProps({ surface, radius, animated });
|
|
10270
|
+
return /* @__PURE__ */ jsxs(
|
|
10271
|
+
"div",
|
|
10272
|
+
{
|
|
10273
|
+
"data-slot": "testimonial-card",
|
|
10274
|
+
"data-surface": sf.surface,
|
|
10275
|
+
"data-radius": sf.radius,
|
|
10276
|
+
className: cn(
|
|
10277
|
+
"flex flex-col rounded-xl border surface-card p-6",
|
|
10278
|
+
"transition-all duration-200 hover:-translate-y-px hover:shadow-md",
|
|
10279
|
+
"motion-reduce:hover:transform-none",
|
|
10280
|
+
className
|
|
10281
|
+
),
|
|
10282
|
+
children: [
|
|
10283
|
+
rating && /* @__PURE__ */ jsx("div", { className: "mb-3 flex gap-0.5", "aria-label": `${rating} out of 5 stars`, children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx(
|
|
10284
|
+
"svg",
|
|
10285
|
+
{
|
|
10286
|
+
className: cn("size-4", i < rating ? "text-warning" : "text-muted-foreground/20"),
|
|
10287
|
+
viewBox: "0 0 20 20",
|
|
10288
|
+
fill: "currentColor",
|
|
10289
|
+
"aria-hidden": "true",
|
|
10290
|
+
children: /* @__PURE__ */ jsx("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" })
|
|
10291
|
+
},
|
|
10292
|
+
i
|
|
10293
|
+
)) }),
|
|
10294
|
+
/* @__PURE__ */ jsxs("blockquote", { className: "flex-1 text-sm leading-relaxed text-foreground", children: [
|
|
10295
|
+
"\u201C",
|
|
10296
|
+
quote,
|
|
10297
|
+
"\u201D"
|
|
10298
|
+
] }),
|
|
10299
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-3", children: [
|
|
10300
|
+
avatar && /* @__PURE__ */ jsx(
|
|
10301
|
+
"img",
|
|
10302
|
+
{
|
|
10303
|
+
src: avatar,
|
|
10304
|
+
alt: name,
|
|
10305
|
+
className: "size-10 rounded-full object-cover"
|
|
10306
|
+
}
|
|
10307
|
+
),
|
|
10308
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
10309
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: name }),
|
|
10310
|
+
role && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: role })
|
|
10311
|
+
] })
|
|
10312
|
+
] })
|
|
10313
|
+
]
|
|
10314
|
+
}
|
|
10315
|
+
);
|
|
10316
|
+
}
|
|
10317
|
+
function TextGenerateEffect({
|
|
10318
|
+
text,
|
|
10319
|
+
stagger = 0.05,
|
|
10320
|
+
duration = 0.4,
|
|
10321
|
+
once = true,
|
|
10322
|
+
as: Tag = "p",
|
|
10323
|
+
className
|
|
10324
|
+
}) {
|
|
10325
|
+
const reduced = useReducedMotion();
|
|
10326
|
+
const ref = useRef(null);
|
|
10327
|
+
const isInView = useInView(ref, { once, margin: "-50px" });
|
|
10328
|
+
const words = useMemo(() => text.split(/\s+/), [text]);
|
|
10329
|
+
if (reduced) {
|
|
10330
|
+
return /* @__PURE__ */ jsx(Tag, { className, children: text });
|
|
10331
|
+
}
|
|
10332
|
+
return /* @__PURE__ */ jsx(
|
|
10333
|
+
Tag,
|
|
10334
|
+
{
|
|
10335
|
+
ref,
|
|
10336
|
+
className: cn("inline", className),
|
|
10337
|
+
"data-slot": "text-generate-effect",
|
|
10338
|
+
children: words.map((word, i) => /* @__PURE__ */ jsxs(
|
|
10339
|
+
m.span,
|
|
10340
|
+
{
|
|
10341
|
+
initial: { opacity: 0, filter: "blur(4px)" },
|
|
10342
|
+
animate: isInView ? { opacity: 1, filter: "blur(0px)" } : { opacity: 0, filter: "blur(4px)" },
|
|
10343
|
+
transition: { duration, delay: i * stagger },
|
|
10344
|
+
className: "inline-block",
|
|
10345
|
+
children: [
|
|
10346
|
+
word,
|
|
10347
|
+
i < words.length - 1 && "\xA0"
|
|
10348
|
+
]
|
|
10349
|
+
},
|
|
10350
|
+
`${word}-${i}`
|
|
10351
|
+
))
|
|
10352
|
+
}
|
|
10353
|
+
);
|
|
10354
|
+
}
|
|
10355
|
+
function Timeline({ children, className }) {
|
|
10356
|
+
const reduced = useReducedMotion();
|
|
10357
|
+
const containerRef = useRef(null);
|
|
10358
|
+
const { scrollYProgress } = useScroll({
|
|
10359
|
+
target: containerRef,
|
|
10360
|
+
offset: ["start 80%", "end 50%"]
|
|
10361
|
+
});
|
|
10362
|
+
const beamHeight = useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
|
|
10363
|
+
return /* @__PURE__ */ jsxs(
|
|
10364
|
+
"div",
|
|
10365
|
+
{
|
|
10366
|
+
ref: containerRef,
|
|
10367
|
+
className: cn("relative", className),
|
|
10368
|
+
"data-slot": "timeline",
|
|
10369
|
+
children: [
|
|
10370
|
+
/* @__PURE__ */ jsx("div", { className: "absolute left-4 top-0 h-full w-0.5 bg-border md:left-1/2 md:-translate-x-px" }),
|
|
10371
|
+
!reduced && /* @__PURE__ */ jsx(
|
|
10372
|
+
m.div,
|
|
10373
|
+
{
|
|
10374
|
+
className: "absolute left-4 top-0 w-0.5 bg-primary md:left-1/2 md:-translate-x-px",
|
|
10375
|
+
style: { height: beamHeight }
|
|
10376
|
+
}
|
|
10377
|
+
),
|
|
10378
|
+
/* @__PURE__ */ jsx("div", { className: "relative space-y-12", children })
|
|
10379
|
+
]
|
|
10380
|
+
}
|
|
10381
|
+
);
|
|
10382
|
+
}
|
|
10383
|
+
function TimelineItem({
|
|
10384
|
+
title,
|
|
10385
|
+
date,
|
|
10386
|
+
children,
|
|
10387
|
+
className
|
|
10388
|
+
}) {
|
|
10389
|
+
const reduced = useReducedMotion();
|
|
10390
|
+
return /* @__PURE__ */ jsxs(
|
|
10391
|
+
m.div,
|
|
10392
|
+
{
|
|
10393
|
+
initial: reduced ? false : { opacity: 0, y: 16 },
|
|
10394
|
+
whileInView: { opacity: 1, y: 0 },
|
|
10395
|
+
viewport: { once: true, margin: "-80px" },
|
|
10396
|
+
transition: reduced ? { duration: 0 } : { duration: 0.5, ease: "easeOut" },
|
|
10397
|
+
className: cn("relative pl-12 md:pl-0", className),
|
|
10398
|
+
"data-slot": "timeline-item",
|
|
10399
|
+
children: [
|
|
10400
|
+
/* @__PURE__ */ jsx("div", { className: "absolute left-[11px] top-1.5 size-3 rounded-full border-2 border-primary bg-background md:left-1/2 md:-translate-x-1.5" }),
|
|
10401
|
+
/* @__PURE__ */ jsxs("div", { className: "md:ml-[calc(50%+2rem)] md:max-w-[calc(50%-3rem)]", children: [
|
|
10402
|
+
date && /* @__PURE__ */ jsx("span", { className: "mb-1 block text-sm text-muted-foreground", children: date }),
|
|
10403
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: title }),
|
|
10404
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1 text-muted-foreground", children })
|
|
10405
|
+
] })
|
|
10406
|
+
]
|
|
10407
|
+
}
|
|
10408
|
+
);
|
|
10409
|
+
}
|
|
10410
|
+
function TracingBeam({
|
|
10411
|
+
children,
|
|
10412
|
+
color = "hsl(var(--primary))",
|
|
10413
|
+
trackColor = "hsl(var(--border))",
|
|
10414
|
+
className
|
|
10415
|
+
}) {
|
|
10416
|
+
const reduced = useReducedMotion();
|
|
10417
|
+
const containerRef = useRef(null);
|
|
10418
|
+
const { scrollYProgress } = useScroll({
|
|
10419
|
+
target: containerRef,
|
|
10420
|
+
offset: ["start 20%", "end 80%"]
|
|
10421
|
+
});
|
|
10422
|
+
const beamHeight = useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
|
|
10423
|
+
const dotY = useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
|
|
10424
|
+
if (reduced) {
|
|
10425
|
+
return /* @__PURE__ */ jsx("div", { className: cn("border-l-2 border-primary/30 pl-8", className), children });
|
|
10426
|
+
}
|
|
10427
|
+
return /* @__PURE__ */ jsxs(
|
|
10428
|
+
"div",
|
|
10429
|
+
{
|
|
10430
|
+
ref: containerRef,
|
|
10431
|
+
className: cn("relative pl-10", className),
|
|
10432
|
+
"data-slot": "tracing-beam",
|
|
10433
|
+
children: [
|
|
10434
|
+
/* @__PURE__ */ jsx(
|
|
10435
|
+
"div",
|
|
10436
|
+
{
|
|
10437
|
+
className: "absolute left-3 top-0 h-full w-px",
|
|
10438
|
+
style: { backgroundColor: trackColor }
|
|
10439
|
+
}
|
|
10440
|
+
),
|
|
10441
|
+
/* @__PURE__ */ jsx(
|
|
10442
|
+
m.div,
|
|
10443
|
+
{
|
|
10444
|
+
className: "absolute left-3 top-0 w-px",
|
|
10445
|
+
style: { height: beamHeight, backgroundColor: color }
|
|
10446
|
+
}
|
|
10447
|
+
),
|
|
10448
|
+
/* @__PURE__ */ jsx(
|
|
10449
|
+
m.div,
|
|
10450
|
+
{
|
|
10451
|
+
className: "absolute left-[9px] size-1.5 rounded-full",
|
|
10452
|
+
style: {
|
|
10453
|
+
top: dotY,
|
|
10454
|
+
backgroundColor: color,
|
|
10455
|
+
boxShadow: `0 0 8px ${color}`
|
|
10456
|
+
}
|
|
10457
|
+
}
|
|
10458
|
+
),
|
|
10459
|
+
children
|
|
10460
|
+
]
|
|
10461
|
+
}
|
|
10462
|
+
);
|
|
10463
|
+
}
|
|
8333
10464
|
|
|
8334
10465
|
// src/types/theme-props.ts
|
|
8335
10466
|
var PALETTES = [
|
|
@@ -8443,7 +10574,7 @@ function StatefulButton({
|
|
|
8443
10574
|
}
|
|
8444
10575
|
);
|
|
8445
10576
|
}
|
|
8446
|
-
var
|
|
10577
|
+
var PROVIDERS2 = [
|
|
8447
10578
|
"google",
|
|
8448
10579
|
"github",
|
|
8449
10580
|
"apple",
|
|
@@ -8921,4 +11052,4 @@ function UserAvatar({ src, name, initials, size = "md", className }) {
|
|
|
8921
11052
|
] });
|
|
8922
11053
|
}
|
|
8923
11054
|
|
|
8924
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnimatedTooltip, AppleAuthButton, AspectRatio, AuroraBackground, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, BarList, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Callout, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryBar, Checkbox, CodeBlock, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, Combobox, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxList, ComboboxSeparator, ComboboxTrigger, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DataToolbar, DataToolbarActions, DataToolbarFilters, DataToolbarSearch, DatePicker, DateRangePicker, DirectionProvider2 as DirectionProvider, DiscordAuthButton, DribbbleAuthButton, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Dropzone, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, FacebookAuthButton, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GitHubAuthButton, GitLabAuthButton, GoogleAuthButton, HoverCard, HoverCardContent, HoverCardTrigger, Icons, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Item9 as Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label5 as Label, LinkedInAuthButton, MediumAuthButton, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MetricCard, MicrosoftAuthButton, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NotificationCenter, NumberInput, PALETTES, PageHeader, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PayPalAuthButton, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PricingCard, Progress, ProgressCircle, RADII, RadioGroup4 as RadioGroup, RadioGroupItem, Rating, RedditAuthButton,
|
|
11055
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnimatedTooltip, AppleAuthButton, AspectRatio, AudioPlayer, AuroraBackground, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, BarList, BentoGrid, BentoGridItem, BlurFade, BorderBeam, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Callout, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryBar, Checkbox, CodeBlock, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, Combobox, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxList, ComboboxSeparator, ComboboxTrigger, Compare, Confetti, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, Countdown, DataToolbar, DataToolbarActions, DataToolbarFilters, DataToolbarSearch, DatePicker, DateRangePicker, DirectionProvider2 as DirectionProvider, DiscordAuthButton, Dock, DockItem, DribbbleAuthButton, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Dropzone, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, FacebookAuthButton, FeatureCard, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FlipWords, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GalleryLightbox, GitHubAuthButton, GitLabAuthButton, GlowingEffect, GoogleAuthButton, GradientText, HeroVideoDialog, Hotspot, HotspotMarker, HoverCard, HoverCardContent, HoverCardTrigger, IPhoneMock, Icons, ImageSwapHover, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Item9 as Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label5 as Label, LinkedInAuthButton, Marquee, MediumAuthButton, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MetricCard, MicrosoftAuthButton, MouseGradientBlob, MovingBorder, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NotificationCenter, NumberInput, PALETTES, PageHeader, PageTransition, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, ParallaxSection, ParticlesBackground, PayPalAuthButton, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PricingCard, Progress, ProgressCircle, RADII, RadioGroup4 as RadioGroup, RadioGroupItem, Rating, RedditAuthButton, RetroGrid, RevealOnScroll, PROVIDERS2 as SOCIAL_AUTH_PROVIDERS, STYLES, SafariMock, ScrollArea, ScrollBar, ScrollToTopButton, SearchField, SectionCard, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator5 as Separator, SettingsSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, ShimmerButton, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, SlackAuthButton, Slider, SocialAuthButton, SocialButton, SparkChart, Spinner, SpotlightCard, StatCard, StatefulButton, Step, Steps, StickyScrollReveal, StripeAuthButton, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TagInput, TeamCard, TestimonialCard, TextGenerateEffect, Textarea, ThemeModeMultiToggle, ThemeModeToggle, TikTokAuthButton, Timeline, TimelineItem, Toaster3 as Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopLoadingBar, TracingBeam, Tracker, TreeView, TypewriterText, UserAvatar, XAuthButton, badgeVariants, buttonGroupVariants, navigationMenuTriggerStyle, toggleVariants, useCountdown, useDirection2 as useDirection, useDisclosure, useFileDialog, useFocusTrap, useFormField, useInterval, useIsMobile, useMeasure, useMergedRef, usePagination, useSidebar };
|