feat: add Ripple component and its demo example to MagicuiPage
This commit is contained in:
parent
fd6126f0c1
commit
625bee14ef
@ -4,6 +4,7 @@ import { DotPatternDemo } from '@/components/magicui/example/dot-pattern-example
|
||||
import { GridPatternDemo } from '@/components/magicui/example/grid-pattern-example';
|
||||
import { HeroVideoDialogDemoTopInBottomOut } from '@/components/magicui/example/hero-video-dialog-example';
|
||||
import { MarqueeDemoVertical } from '@/components/magicui/example/marquee-example';
|
||||
import { RippleDemo } from '@/components/magicui/example/ripple-example';
|
||||
|
||||
/**
|
||||
* Magic UI Components Showcase Page
|
||||
@ -15,9 +16,12 @@ export default async function MagicuiPage() {
|
||||
<div className="mx-auto space-y-8">
|
||||
<DotPatternDemo />
|
||||
<GridPatternDemo />
|
||||
<RippleDemo />
|
||||
<BentoDemo />
|
||||
<MarqueeDemoVertical />
|
||||
<AnimatedListDemo />
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
<MarqueeDemoVertical />
|
||||
<AnimatedListDemo />
|
||||
</div>
|
||||
<HeroVideoDialogDemoTopInBottomOut />
|
||||
</div>
|
||||
);
|
||||
|
12
src/components/magicui/example/ripple-example.tsx
Normal file
12
src/components/magicui/example/ripple-example.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { Ripple } from "@/components/magicui/ripple";
|
||||
|
||||
export function RippleDemo() {
|
||||
return (
|
||||
<div className="relative flex h-[500px] w-full flex-col items-center justify-center overflow-hidden rounded-lg border bg-background">
|
||||
<p className="z-10 whitespace-pre-wrap text-center text-5xl font-medium tracking-tighter text-white">
|
||||
Ripple
|
||||
</p>
|
||||
<Ripple />
|
||||
</div>
|
||||
);
|
||||
}
|
59
src/components/magicui/ripple.tsx
Normal file
59
src/components/magicui/ripple.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
import React, { ComponentPropsWithoutRef, CSSProperties } from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface RippleProps extends ComponentPropsWithoutRef<"div"> {
|
||||
mainCircleSize?: number;
|
||||
mainCircleOpacity?: number;
|
||||
numCircles?: number;
|
||||
}
|
||||
|
||||
export const Ripple = React.memo(function Ripple({
|
||||
mainCircleSize = 210,
|
||||
mainCircleOpacity = 0.24,
|
||||
numCircles = 8,
|
||||
className,
|
||||
...props
|
||||
}: RippleProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"pointer-events-none absolute inset-0 select-none [mask-image:linear-gradient(to_bottom,white,transparent)]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{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 border bg-foreground/25 shadow-xl`}
|
||||
style={
|
||||
{
|
||||
"--i": i,
|
||||
width: `${size}px`,
|
||||
height: `${size}px`,
|
||||
opacity,
|
||||
animationDelay,
|
||||
borderStyle,
|
||||
borderWidth: "1px",
|
||||
borderColor: `hsl(var(--foreground), ${borderOpacity / 100})`,
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%) scale(1)",
|
||||
} as CSSProperties
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
Ripple.displayName = "Ripple";
|
@ -130,7 +130,14 @@
|
||||
transform: translateY(calc(-100% - var(--gap)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
--animate-ripple: ripple var(--duration,2s) ease calc(var(--i, 0)*.2s) infinite
|
||||
;
|
||||
@keyframes ripple {
|
||||
0%, 100% {
|
||||
transform: translate(-50%, -50%) scale(1);}
|
||||
50% {
|
||||
transform: translate(-50%, -50%) scale(0.9);}}}
|
||||
|
||||
:root {
|
||||
--radius: 0.5rem;
|
||||
@ -283,4 +290,4 @@ body {
|
||||
--primary: var(--color-amber-500);
|
||||
--primary-foreground: var(--color-amber-50);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user