chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { CSSProperties, FC, ReactNode } from "react";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
interface AnimatedShinyTextProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
shimmerWidth?: number;
|
||||
}
|
||||
|
||||
const AnimatedShinyTextLw: FC<AnimatedShinyTextProps> = ({
|
||||
children,
|
||||
className,
|
||||
shimmerWidth = 100,
|
||||
}) => {
|
||||
return (
|
||||
<p
|
||||
style={
|
||||
{
|
||||
"--shimmer-width": `${shimmerWidth}px`,
|
||||
} as CSSProperties
|
||||
}
|
||||
className={cn(
|
||||
"text-zinc-500",
|
||||
|
||||
// Shimmer effect
|
||||
"animate-shimmer bg-clip-text bg-no-repeat [background-position:0_0] [background-size:var(--shimmer-width)_100%] [transition:background-position_1s_cubic-bezier(.6,.6,0,1)_infinite]",
|
||||
|
||||
// Shimmer gradient
|
||||
"bg-gradient-to-r from-transparent via-black/80 via-50% to-transparent dark:via-white/80",
|
||||
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export default AnimatedShinyTextLw;
|
||||
@@ -0,0 +1,40 @@
|
||||
import { CSSProperties, FC, ReactNode } from "react";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
interface AnimatedShinyTextProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
shimmerWidth?: number;
|
||||
}
|
||||
|
||||
const AnimatedShinyText: FC<AnimatedShinyTextProps> = ({
|
||||
children,
|
||||
className,
|
||||
shimmerWidth = 100,
|
||||
}) => {
|
||||
return (
|
||||
<p
|
||||
style={
|
||||
{
|
||||
"--shimmer-width": `${shimmerWidth}px`,
|
||||
} as CSSProperties
|
||||
}
|
||||
className={cn(
|
||||
"mx-auto max-w-md text-neutral-600/70 dark:text-neutral-400/70",
|
||||
|
||||
// Shimmer effect
|
||||
"animate-shimmer bg-clip-text bg-no-repeat [background-position:0_0] [background-size:var(--shimmer-width)_100%] [transition:background-position_1s_cubic-bezier(.6,.6,0,1)_infinite]",
|
||||
|
||||
// Shimmer gradient
|
||||
"bg-gradient-to-r from-transparent via-black/80 via-50% to-transparent dark:via-white/80",
|
||||
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export default AnimatedShinyText;
|
||||
@@ -0,0 +1,124 @@
|
||||
"use client";
|
||||
|
||||
import React, { PropsWithChildren, useRef } from "react";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
export interface DockProps extends VariantProps<typeof dockVariants> {
|
||||
className?: string;
|
||||
magnification?: number;
|
||||
distance?: number;
|
||||
direction?: "top" | "middle" | "bottom";
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const DEFAULT_MAGNIFICATION = 60;
|
||||
const DEFAULT_DISTANCE = 125;
|
||||
|
||||
const dockVariants = cva(
|
||||
"mx-auto w-max mt-8 h-[58px] p-2 flex gap-2 rounded-2xl supports-backdrop-blur:bg-white/10 supports-backdrop-blur:dark:bg-black/10 backdrop-blur-md dark:border-zinc-800",
|
||||
);
|
||||
|
||||
const Dock = React.forwardRef<HTMLDivElement, DockProps>(
|
||||
(
|
||||
{
|
||||
className,
|
||||
children,
|
||||
magnification = DEFAULT_MAGNIFICATION,
|
||||
distance = DEFAULT_DISTANCE,
|
||||
direction = "bottom",
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const mouseX = useMotionValue(Infinity);
|
||||
|
||||
const renderChildren = () => {
|
||||
return React.Children.map(children, (child: any) => {
|
||||
return React.cloneElement(child, {
|
||||
mouseX: mouseX,
|
||||
magnification: magnification,
|
||||
distance: distance,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
ref={ref}
|
||||
onMouseMove={(e) => mouseX.set(e.pageX)}
|
||||
onMouseLeave={() => mouseX.set(Infinity)}
|
||||
{...props}
|
||||
className={cn(dockVariants({ className }), {
|
||||
"items-start": direction === "top",
|
||||
"items-center": direction === "middle",
|
||||
"items-end": direction === "bottom",
|
||||
})}
|
||||
>
|
||||
{renderChildren()}
|
||||
</motion.div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Dock.displayName = "Dock";
|
||||
|
||||
export interface DockIconProps {
|
||||
size?: number;
|
||||
magnification?: number;
|
||||
distance?: number;
|
||||
mouseX?: any;
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
props?: PropsWithChildren;
|
||||
}
|
||||
|
||||
const DockIcon = ({
|
||||
size,
|
||||
magnification = DEFAULT_MAGNIFICATION,
|
||||
distance = DEFAULT_DISTANCE,
|
||||
mouseX,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: DockIconProps) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
const distanceCalc = useTransform(mouseX, (val: number) => {
|
||||
const bounds = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 };
|
||||
|
||||
return val - bounds.x - bounds.width / 2;
|
||||
});
|
||||
|
||||
let widthSync = useTransform(
|
||||
distanceCalc,
|
||||
[-distance, 0, distance],
|
||||
[40, magnification, 40],
|
||||
);
|
||||
|
||||
let width = useSpring(widthSync, {
|
||||
mass: 0.1,
|
||||
stiffness: 150,
|
||||
damping: 12,
|
||||
});
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
ref={ref}
|
||||
style={{ width }}
|
||||
className={cn(
|
||||
"flex aspect-square cursor-pointer items-center justify-center rounded-full",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
DockIcon.displayName = "DockIcon";
|
||||
|
||||
export { Dock, DockIcon, dockVariants };
|
||||
@@ -0,0 +1,56 @@
|
||||
import { useId } from "react";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
interface DotPatternProps {
|
||||
width?: any;
|
||||
height?: any;
|
||||
x?: any;
|
||||
y?: any;
|
||||
cx?: any;
|
||||
cy?: any;
|
||||
cr?: any;
|
||||
className?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
export function DotPattern({
|
||||
width = 16,
|
||||
height = 16,
|
||||
x = 0,
|
||||
y = 0,
|
||||
cx = 1,
|
||||
cy = 1,
|
||||
cr = 1,
|
||||
className,
|
||||
...props
|
||||
}: DotPatternProps) {
|
||||
const id = useId();
|
||||
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className={cn(
|
||||
"pointer-events-none absolute inset-0 h-full w-full fill-neutral-400/80",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<defs>
|
||||
<pattern
|
||||
id={id}
|
||||
width={width}
|
||||
height={height}
|
||||
patternUnits="userSpaceOnUse"
|
||||
patternContentUnits="userSpaceOnUse"
|
||||
x={x}
|
||||
y={y}
|
||||
>
|
||||
<circle id="pattern-circle" cx={cx} cy={cy} r={cr} />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" strokeWidth={0} fill={`url(#${id})`} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default DotPattern;
|
||||
@@ -0,0 +1,44 @@
|
||||
"use client";
|
||||
|
||||
import { AnimatePresence, motion, Variants } from "framer-motion";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
interface GradualSpacingProps {
|
||||
text: string;
|
||||
duration?: number;
|
||||
delayMultiple?: number;
|
||||
framerProps?: Variants;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function GradualSpacing({
|
||||
text,
|
||||
duration = 0.5,
|
||||
delayMultiple = 0.04,
|
||||
framerProps = {
|
||||
hidden: { opacity: 0, x: -20 },
|
||||
visible: { opacity: 1, x: 0 },
|
||||
},
|
||||
className,
|
||||
}: GradualSpacingProps) {
|
||||
return (
|
||||
<div className="flex justify-center">
|
||||
<AnimatePresence>
|
||||
{text.split("").map((char, i) => (
|
||||
<motion.h1
|
||||
key={i}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit="hidden"
|
||||
variants={framerProps}
|
||||
transition={{ duration, delay: i * delayMultiple }}
|
||||
className={cn("drop-shadow-sm", className)}
|
||||
>
|
||||
{char === " " ? <span> </span> : char}
|
||||
</motion.h1>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import React, { CSSProperties } from "react";
|
||||
|
||||
interface RippleProps {
|
||||
mainCircleSize?: number;
|
||||
mainCircleOpacity?: number;
|
||||
numCircles?: number;
|
||||
}
|
||||
|
||||
const Ripple = React.memo(function Ripple({
|
||||
mainCircleSize = 210,
|
||||
mainCircleOpacity = 0.24,
|
||||
numCircles = 8,
|
||||
}: RippleProps) {
|
||||
return (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-white/5 [mask-image:linear-gradient(to_bottom,white,transparent)]">
|
||||
{Array.from({ length: numCircles }, (_, i) => {
|
||||
const size = mainCircleSize + i * 70;
|
||||
const opacity = mainCircleOpacity - i * 0.03;
|
||||
const animationDelay = `${i * 0.06}s`;
|
||||
const borderStyle = i === numCircles - 1 ? "dashed" : "solid";
|
||||
const borderOpacity = 5 + i * 5;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className={`absolute animate-ripple rounded-full bg-foreground/25 shadow-xl border top-1/2 left-1/2 translate-x-1/2 translate-y-1/2 [--i:${i}]`}
|
||||
style={
|
||||
{
|
||||
width: `${size}px`,
|
||||
height: `${size}px`,
|
||||
opacity: opacity,
|
||||
animationDelay: animationDelay,
|
||||
borderStyle: borderStyle,
|
||||
borderWidth: "1px",
|
||||
borderColor: `rgba(var(--foreground-rgb), ${borderOpacity / 100})`,
|
||||
} as CSSProperties
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
Ripple.displayName = "Ripple";
|
||||
|
||||
export default Ripple;
|
||||
Reference in New Issue
Block a user