+
{children}
);
};
-const BentoCard = ({
- name,
+export const BentoGridItem = ({
className,
- background,
- Icon,
+ title,
description,
- href,
- cta,
+ header,
+ icon,
}: {
- name: string;
- className: string;
- background: ReactNode;
- Icon: any;
- description: string;
- href: string;
- cta: string;
-}) => (
-
-
{background}
-
-
-
{name}
-
{description}
-
-
+ className?: string;
+ title?: string | React.ReactNode;
+ description?: string | React.ReactNode;
+ header?: React.ReactNode;
+ icon?: React.ReactNode;
+}) => {
+ return (
-
+ {header}
+
+ {icon}
+
+ {title}
+
+
+ {description}
+
+
-
-
-);
-
-export { BentoCard, BentoGrid };
+ );
+};
diff --git a/packages/shadcn/src/components/ui/blur-fade.tsx b/packages/shadcn/src/components/ui/blur-fade.tsx
deleted file mode 100644
index 6b452be..0000000
--- a/packages/shadcn/src/components/ui/blur-fade.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-'use client';
-
-import { AnimatePresence, motion, useInView, UseInViewOptions, Variants } from 'framer-motion';
-import { useRef } from 'react';
-
-type MarginType = UseInViewOptions['margin'];
-
-interface BlurFadeProps {
- children: React.ReactNode;
- className?: string;
- variant?: {
- hidden: { y: number };
- visible: { y: number };
- };
- duration?: number;
- delay?: number;
- yOffset?: number;
- inView?: boolean;
- inViewMargin?: MarginType;
- blur?: string;
-}
-
-export default function BlurFade({
- children,
- className,
- variant,
- duration = 0.4,
- delay = 0,
- yOffset = 6,
- inView = false,
- inViewMargin = '-50px',
- blur = '6px',
-}: BlurFadeProps) {
- const ref = useRef(null);
- const inViewResult = useInView(ref, { once: true, margin: inViewMargin });
- const isInView = !inView || inViewResult;
- const defaultVariants: Variants = {
- hidden: { y: yOffset, opacity: 0, filter: `blur(${blur})` },
- visible: { y: -yOffset, opacity: 1, filter: `blur(0px)` },
- };
- const combinedVariants = variant || defaultVariants;
- return (
-
-
- {children}
-
-
- );
-}
diff --git a/packages/shadcn/src/components/ui/blur-in.tsx b/packages/shadcn/src/components/ui/blur-in.tsx
deleted file mode 100644
index fdefec6..0000000
--- a/packages/shadcn/src/components/ui/blur-in.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-'use client';
-
-import { motion } from 'framer-motion';
-
-import { cn } from '../../lib/utils';
-
-interface BlurIntProps {
- word: string;
- className?: string;
- variant?: {
- hidden: { filter: string; opacity: number };
- visible: { filter: string; opacity: number };
- };
- duration?: number;
-}
-const BlurIn = ({ word, className, variant, duration = 1 }: BlurIntProps) => {
- const defaultVariants = {
- hidden: { filter: 'blur(10px)', opacity: 0 },
- visible: { filter: 'blur(0px)', opacity: 1 },
- };
- const combinedVariants = variant || defaultVariants;
-
- return (
-
- {word}
-
- );
-};
-
-export default BlurIn;
diff --git a/packages/shadcn/src/components/ui/border-beam.tsx b/packages/shadcn/src/components/ui/border-beam.tsx
deleted file mode 100644
index bbcf308..0000000
--- a/packages/shadcn/src/components/ui/border-beam.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import { cn } from '../../lib/utils';
-
-interface BorderBeamProps {
- className?: string;
- size?: number;
- duration?: number;
- borderWidth?: number;
- anchor?: number;
- colorFrom?: string;
- colorTo?: string;
- delay?: number;
-}
-
-export const BorderBeam = ({
- className,
- size = 200,
- duration = 15,
- anchor = 90,
- borderWidth = 1.5,
- colorFrom = '#ffaa40',
- colorTo = '#9c40ff',
- delay = 0,
-}: BorderBeamProps) => {
- return (
-
- );
-};
diff --git a/packages/shadcn/src/components/ui/box-reveal.tsx b/packages/shadcn/src/components/ui/box-reveal.tsx
deleted file mode 100644
index fafc06e..0000000
--- a/packages/shadcn/src/components/ui/box-reveal.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-'use client';
-
-import { motion, useAnimation, useInView } from 'framer-motion';
-import { useEffect, useRef } from 'react';
-
-interface BoxRevealProps {
- children: JSX.Element;
- width?: 'fit-content' | '100%';
- boxColor?: string;
- duration?: number;
-}
-
-export const BoxReveal = ({
- children,
- width = 'fit-content',
- boxColor,
- duration,
-}: BoxRevealProps) => {
- const mainControls = useAnimation();
- const slideControls = useAnimation();
-
- const ref = useRef(null);
- const isInView = useInView(ref, { once: true });
-
- useEffect(() => {
- if (isInView) {
- slideControls.start('visible');
- mainControls.start('visible');
- } else {
- slideControls.start('hidden');
- mainControls.start('hidden');
- }
- }, [isInView, mainControls, slideControls]);
-
- return (
-
-
- {children}
-
-
-
-
- );
-};
-
-export default BoxReveal;
diff --git a/packages/shadcn/src/components/ui/breadcrumb.tsx b/packages/shadcn/src/components/ui/breadcrumb.tsx
index a84befb..e137796 100644
--- a/packages/shadcn/src/components/ui/breadcrumb.tsx
+++ b/packages/shadcn/src/components/ui/breadcrumb.tsx
@@ -1,3 +1,4 @@
+// @ts-nocheck
import { ChevronRightIcon, DotsHorizontalIcon } from '@radix-ui/react-icons';
import { Slot } from '@radix-ui/react-slot';
import * as React from 'react';
diff --git a/packages/shadcn/src/components/ui/button.tsx b/packages/shadcn/src/components/ui/button.tsx
index b50d59a..1891099 100644
--- a/packages/shadcn/src/components/ui/button.tsx
+++ b/packages/shadcn/src/components/ui/button.tsx
@@ -1,3 +1,4 @@
+// @ts-nocheck
import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';
import * as React from 'react';
diff --git a/packages/shadcn/src/components/ui/calendar.tsx b/packages/shadcn/src/components/ui/calendar.tsx
index 8013173..de65810 100644
--- a/packages/shadcn/src/components/ui/calendar.tsx
+++ b/packages/shadcn/src/components/ui/calendar.tsx
@@ -1,3 +1,4 @@
+// @ts-nocheck
'use client';
import * as React from 'react';
diff --git a/packages/shadcn/src/components/ui/canvas-reveal-effect.tsx b/packages/shadcn/src/components/ui/canvas-reveal-effect.tsx
new file mode 100644
index 0000000..b72f5eb
--- /dev/null
+++ b/packages/shadcn/src/components/ui/canvas-reveal-effect.tsx
@@ -0,0 +1,278 @@
+// @ts-nocheck
+'use client';
+import { Canvas, useFrame, useThree } from '@react-three/fiber';
+import React, { useMemo, useRef } from 'react';
+import * as THREE from 'three';
+import { cn } from '../../lib/utils';
+
+export const CanvasRevealEffect = ({
+ animationSpeed = 0.4,
+ opacities = [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1],
+ colors = [[0, 255, 255]],
+ containerClassName,
+ dotSize,
+ showGradient = true,
+}: {
+ /**
+ * 0.1 - slower
+ * 1.0 - faster
+ */
+ animationSpeed?: number;
+ opacities?: number[];
+ colors?: number[][];
+ containerClassName?: string;
+ dotSize?: number;
+ showGradient?: boolean;
+}) => {
+ return (
+
+
+
+
+ {showGradient &&
}
+
+ );
+};
+
+interface DotMatrixProps {
+ colors?: number[][];
+ opacities?: number[];
+ totalSize?: number;
+ dotSize?: number;
+ shader?: string;
+ center?: ('x' | 'y')[];
+}
+
+const DotMatrix: React.FC
= ({
+ colors = [[0, 0, 0]],
+ opacities = [0.04, 0.04, 0.04, 0.04, 0.04, 0.08, 0.08, 0.08, 0.08, 0.14],
+ totalSize = 4,
+ dotSize = 2,
+ shader = '',
+ center = ['x', 'y'],
+}) => {
+ const uniforms = React.useMemo(() => {
+ let colorsArray = [colors[0], colors[0], colors[0], colors[0], colors[0], colors[0]];
+ if (colors.length === 2) {
+ colorsArray = [colors[0], colors[0], colors[0], colors[1], colors[1], colors[1]];
+ } else if (colors.length === 3) {
+ colorsArray = [colors[0], colors[0], colors[1], colors[1], colors[2], colors[2]];
+ }
+
+ return {
+ u_colors: {
+ value: colorsArray.map((color) => [color[0] / 255, color[1] / 255, color[2] / 255]),
+ type: 'uniform3fv',
+ },
+ u_opacities: {
+ value: opacities,
+ type: 'uniform1fv',
+ },
+ u_total_size: {
+ value: totalSize,
+ type: 'uniform1f',
+ },
+ u_dot_size: {
+ value: dotSize,
+ type: 'uniform1f',
+ },
+ };
+ }, [colors, opacities, totalSize, dotSize]);
+
+ return (
+
+ );
+};
+
+type Uniforms = {
+ [key: string]: {
+ value: number[] | number[][] | number;
+ type: string;
+ };
+};
+const ShaderMaterial = ({
+ source,
+ uniforms,
+ maxFps = 60,
+}: {
+ source: string;
+ hovered?: boolean;
+ maxFps?: number;
+ uniforms: Uniforms;
+}) => {
+ const { size } = useThree();
+ const ref = useRef();
+ let lastFrameTime = 0;
+
+ useFrame(({ clock }) => {
+ if (!ref.current) return;
+ const timestamp = clock.getElapsedTime();
+ if (timestamp - lastFrameTime < 1 / maxFps) {
+ return;
+ }
+ lastFrameTime = timestamp;
+
+ const material: any = ref.current.material;
+ const timeLocation = material.uniforms.u_time;
+ timeLocation.value = timestamp;
+ });
+
+ const getUniforms = () => {
+ const preparedUniforms: any = {};
+
+ for (const uniformName in uniforms) {
+ const uniform: any = uniforms[uniformName];
+
+ switch (uniform.type) {
+ case 'uniform1f':
+ preparedUniforms[uniformName] = { value: uniform.value, type: '1f' };
+ break;
+ case 'uniform3f':
+ preparedUniforms[uniformName] = {
+ value: new THREE.Vector3().fromArray(uniform.value),
+ type: '3f',
+ };
+ break;
+ case 'uniform1fv':
+ preparedUniforms[uniformName] = { value: uniform.value, type: '1fv' };
+ break;
+ case 'uniform3fv':
+ preparedUniforms[uniformName] = {
+ value: uniform.value.map((v: number[]) => new THREE.Vector3().fromArray(v)),
+ type: '3fv',
+ };
+ break;
+ case 'uniform2f':
+ preparedUniforms[uniformName] = {
+ value: new THREE.Vector2().fromArray(uniform.value),
+ type: '2f',
+ };
+ break;
+ default:
+ console.error(`Invalid uniform type for '${uniformName}'.`);
+ break;
+ }
+ }
+
+ preparedUniforms['u_time'] = { value: 0, type: '1f' };
+ preparedUniforms['u_resolution'] = {
+ value: new THREE.Vector2(size.width * 2, size.height * 2),
+ }; // Initialize u_resolution
+ return preparedUniforms;
+ };
+
+ // Shader material
+ const material = useMemo(() => {
+ const materialObject = new THREE.ShaderMaterial({
+ vertexShader: `
+ precision mediump float;
+ in vec2 coordinates;
+ uniform vec2 u_resolution;
+ out vec2 fragCoord;
+ void main(){
+ float x = position.x;
+ float y = position.y;
+ gl_Position = vec4(x, y, 0.0, 1.0);
+ fragCoord = (position.xy + vec2(1.0)) * 0.5 * u_resolution;
+ fragCoord.y = u_resolution.y - fragCoord.y;
+ }
+ `,
+ fragmentShader: source,
+ uniforms: getUniforms(),
+ glslVersion: THREE.GLSL3,
+ blending: THREE.CustomBlending,
+ blendSrc: THREE.SrcAlphaFactor,
+ blendDst: THREE.OneFactor,
+ });
+
+ return materialObject;
+ }, [size.width, size.height, source]);
+
+ return (
+
+
+
+
+ );
+};
+
+const Shader: React.FC = ({ source, uniforms, maxFps = 60 }) => {
+ return (
+
+ );
+};
+interface ShaderProps {
+ source: string;
+ uniforms: {
+ [key: string]: {
+ value: number[] | number[][] | number;
+ type: string;
+ };
+ };
+ maxFps?: number;
+}
diff --git a/packages/shadcn/src/components/ui/card-hover-effect.tsx b/packages/shadcn/src/components/ui/card-hover-effect.tsx
new file mode 100644
index 0000000..c3f282e
--- /dev/null
+++ b/packages/shadcn/src/components/ui/card-hover-effect.tsx
@@ -0,0 +1,100 @@
+// @ts-nocheck
+import { AnimatePresence, motion } from 'framer-motion';
+import Link from 'next/link';
+import { useState } from 'react';
+import { cn } from '../../lib/utils';
+
+export const HoverEffect = ({
+ items,
+ className,
+}: {
+ items: {
+ title: string;
+ description: string;
+ link: string;
+ }[];
+ className?: string;
+}) => {
+ let [hoveredIndex, setHoveredIndex] = useState(null);
+
+ return (
+
+ {items.map((item, idx) => (
+
setHoveredIndex(idx)}
+ onMouseLeave={() => setHoveredIndex(null)}
+ >
+
+ {hoveredIndex === idx && (
+
+ )}
+
+
+ {item.title}
+ {item.description}
+
+
+ ))}
+
+ );
+};
+
+export const Card = ({
+ className,
+ children,
+}: {
+ className?: string;
+ children: React.ReactNode;
+}) => {
+ return (
+
+ );
+};
+export const CardTitle = ({
+ className,
+ children,
+}: {
+ className?: string;
+ children: React.ReactNode;
+}) => {
+ return (
+ {children}
+ );
+};
+export const CardDescription = ({
+ className,
+ children,
+}: {
+ className?: string;
+ children: React.ReactNode;
+}) => {
+ return (
+
+ {children}
+
+ );
+};
diff --git a/packages/shadcn/src/components/ui/card-spotlight.tsx b/packages/shadcn/src/components/ui/card-spotlight.tsx
new file mode 100644
index 0000000..78aec40
--- /dev/null
+++ b/packages/shadcn/src/components/ui/card-spotlight.tsx
@@ -0,0 +1,71 @@
+// @ts-nocheck
+'use client';
+
+import { motion, useMotionTemplate, useMotionValue } from 'framer-motion';
+import React, { MouseEvent as ReactMouseEvent, useState } from 'react';
+import { cn } from '../../lib/utils';
+import { CanvasRevealEffect } from './canvas-reveal-effect';
+
+export const CardSpotlight = ({
+ children,
+ radius = 350,
+ color = '#262626',
+ className,
+ ...props
+}: {
+ radius?: number;
+ color?: string;
+ children: React.ReactNode;
+} & React.HTMLAttributes) => {
+ const mouseX = useMotionValue(0);
+ const mouseY = useMotionValue(0);
+ function handleMouseMove({ currentTarget, clientX, clientY }: ReactMouseEvent) {
+ let { left, top } = currentTarget.getBoundingClientRect();
+
+ mouseX.set(clientX - left);
+ mouseY.set(clientY - top);
+ }
+
+ const [isHovering, setIsHovering] = useState(false);
+ const handleMouseEnter = () => setIsHovering(true);
+ const handleMouseLeave = () => setIsHovering(false);
+ return (
+
+
+ {isHovering && (
+
+ )}
+
+ {children}
+
+ );
+};
diff --git a/packages/shadcn/src/components/ui/card-stack.tsx b/packages/shadcn/src/components/ui/card-stack.tsx
new file mode 100644
index 0000000..44c6843
--- /dev/null
+++ b/packages/shadcn/src/components/ui/card-stack.tsx
@@ -0,0 +1,70 @@
+'use client';
+import { motion } from 'framer-motion';
+import { useEffect, useState } from 'react';
+
+let interval: any;
+
+type Card = {
+ id: number;
+ name: string;
+ designation: string;
+ content: React.ReactNode;
+};
+
+export const CardStack = ({
+ items,
+ offset,
+ scaleFactor,
+}: {
+ items: Card[];
+ offset?: number;
+ scaleFactor?: number;
+}) => {
+ const CARD_OFFSET = offset || 10;
+ const SCALE_FACTOR = scaleFactor || 0.06;
+ const [cards, setCards] = useState(items);
+
+ useEffect(() => {
+ startFlipping();
+
+ return () => clearInterval(interval);
+ }, []);
+ const startFlipping = () => {
+ interval = setInterval(() => {
+ setCards((prevCards: Card[]) => {
+ const newArray = [...prevCards]; // create a copy of the array
+ newArray.unshift(newArray.pop()!); // move the last element to the front
+ return newArray;
+ });
+ }, 5000);
+ };
+
+ return (
+
+ {cards.map((card, index) => {
+ return (
+
+ {card.content}
+
+
{card.name}
+
+ {card.designation}
+
+
+
+ );
+ })}
+
+ );
+};
diff --git a/packages/shadcn/src/components/ui/card.tsx b/packages/shadcn/src/components/ui/card.tsx
index 872964f..666e925 100644
--- a/packages/shadcn/src/components/ui/card.tsx
+++ b/packages/shadcn/src/components/ui/card.tsx
@@ -1,3 +1,4 @@
+// @ts-nocheck
import * as React from 'react';
import { cn } from '../../lib/utils';
diff --git a/packages/shadcn/src/components/ui/carousel.tsx b/packages/shadcn/src/components/ui/carousel.tsx
index 37e2a6a..a376102 100644
--- a/packages/shadcn/src/components/ui/carousel.tsx
+++ b/packages/shadcn/src/components/ui/carousel.tsx
@@ -1,3 +1,4 @@
+// @ts-nocheck
'use client';
import { ArrowLeftIcon, ArrowRightIcon } from '@radix-ui/react-icons';
diff --git a/packages/shadcn/src/components/ui/chart.tsx b/packages/shadcn/src/components/ui/chart.tsx
index 5cbb4aa..2b9eb3e 100644
--- a/packages/shadcn/src/components/ui/chart.tsx
+++ b/packages/shadcn/src/components/ui/chart.tsx
@@ -1,3 +1,4 @@
+// @ts-nocheck
'use client';
import * as React from 'react';
@@ -131,7 +132,7 @@ const ChartTooltipContent = React.forwardRef<
}
const [item] = payload;
- const key = `${labelKey || item?.dataKey || item?.name || 'value'}`;
+ const key = `${labelKey || item.dataKey || item.name || 'value'}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const value =
!labelKey && typeof label === 'string'
diff --git a/packages/shadcn/src/components/ui/checkbox.tsx b/packages/shadcn/src/components/ui/checkbox.tsx
index 9d7302f..375e154 100644
--- a/packages/shadcn/src/components/ui/checkbox.tsx
+++ b/packages/shadcn/src/components/ui/checkbox.tsx
@@ -1,3 +1,4 @@
+// @ts-nocheck
'use client';
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
diff --git a/packages/shadcn/src/components/ui/client-tweet-card.tsx b/packages/shadcn/src/components/ui/client-tweet-card.tsx
deleted file mode 100644
index fa81b4b..0000000
--- a/packages/shadcn/src/components/ui/client-tweet-card.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-'use client';
-
-import { TweetProps, useTweet } from 'react-tweet';
-
-import { MagicTweet, TweetNotFound, TweetSkeleton } from '@/components/magicui/tweet-card';
-
-const ClientTweetCard = ({
- id,
- apiUrl,
- fallback = ,
- components,
- fetchOptions,
- onError,
- ...props
-}: TweetProps & { className?: string }) => {
- const { data, error, isLoading } = useTweet(id, apiUrl, fetchOptions);
-
- if (isLoading) return fallback;
- if (error || !data) {
- const NotFound = components?.TweetNotFound || TweetNotFound;
- return ;
- }
-
- return ;
-};
-
-export default ClientTweetCard;
diff --git a/packages/shadcn/src/components/ui/code-comparison.tsx b/packages/shadcn/src/components/ui/code-comparison.tsx
deleted file mode 100644
index 5d378a1..0000000
--- a/packages/shadcn/src/components/ui/code-comparison.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-'use client';
-
-import { FileIcon } from 'lucide-react';
-import { useTheme } from 'next-themes';
-import { useEffect, useState } from 'react';
-import { codeToHtml } from 'shiki';
-
-interface CodeComparisonProps {
- beforeCode: string;
- afterCode: string;
- language: string;
- filename: string;
- lightTheme: string;
- darkTheme: string;
-}
-
-export default function CodeComparison({
- beforeCode,
- afterCode,
- language,
- filename,
- lightTheme,
- darkTheme,
-}: CodeComparisonProps) {
- const { theme, systemTheme } = useTheme();
- const [highlightedBefore, setHighlightedBefore] = useState('');
- const [highlightedAfter, setHighlightedAfter] = useState('');
-
- useEffect(() => {
- const currentTheme = theme === 'system' ? systemTheme : theme;
- const selectedTheme = currentTheme === 'dark' ? darkTheme : lightTheme;
-
- async function highlightCode() {
- const before = await codeToHtml(beforeCode, {
- lang: language,
- theme: selectedTheme,
- });
- const after = await codeToHtml(afterCode, {
- lang: language,
- theme: selectedTheme,
- });
- setHighlightedBefore(before);
- setHighlightedAfter(after);
- }
-
- highlightCode();
- }, [theme, systemTheme, beforeCode, afterCode, language, lightTheme, darkTheme]);
-
- const renderCode = (code: string, highlighted: string) => {
- if (highlighted) {
- return (
-
- );
- } else {
- return (
-
- {code}
-
- );
- }
- };
- return (
-
-
-
-
-
-
- {filename}
- before
-
- {renderCode(beforeCode, highlightedBefore)}
-
-
-
-
- {filename}
- after
-
- {renderCode(afterCode, highlightedAfter)}
-
-
-
- VS
-
-
-
- );
-}
diff --git a/packages/shadcn/src/components/ui/command.tsx b/packages/shadcn/src/components/ui/command.tsx
index 2c6a30e..d84ce86 100644
--- a/packages/shadcn/src/components/ui/command.tsx
+++ b/packages/shadcn/src/components/ui/command.tsx
@@ -1,3 +1,4 @@
+// @ts-nocheck
'use client';
import { type DialogProps } from '@radix-ui/react-dialog';
diff --git a/packages/shadcn/src/components/ui/compare.tsx b/packages/shadcn/src/components/ui/compare.tsx
new file mode 100644
index 0000000..30733c8
--- /dev/null
+++ b/packages/shadcn/src/components/ui/compare.tsx
@@ -0,0 +1,237 @@
+// @ts-nocheck
+'use client';
+import { IconDotsVertical } from '@tabler/icons-react';
+import { AnimatePresence, motion } from 'framer-motion';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { cn } from '../../lib/utils';
+import { SparklesCore } from './sparkles';
+
+interface CompareProps {
+ firstImage?: string;
+ secondImage?: string;
+ className?: string;
+ firstImageClassName?: string;
+ secondImageClassname?: string;
+ initialSliderPercentage?: number;
+ slideMode?: 'hover' | 'drag';
+ showHandlebar?: boolean;
+ autoplay?: boolean;
+ autoplayDuration?: number;
+}
+export const Compare = ({
+ firstImage = '',
+ secondImage = '',
+ className,
+ firstImageClassName,
+ secondImageClassname,
+ initialSliderPercentage = 50,
+ slideMode = 'hover',
+ showHandlebar = true,
+ autoplay = false,
+ autoplayDuration = 5000,
+}: CompareProps) => {
+ const [sliderXPercent, setSliderXPercent] = useState(initialSliderPercentage);
+ const [isDragging, setIsDragging] = useState(false);
+
+ const sliderRef = useRef(null);
+
+ const [isMouseOver, setIsMouseOver] = useState(false);
+
+ const autoplayRef = useRef(null);
+
+ const startAutoplay = useCallback(() => {
+ if (!autoplay) return;
+
+ const startTime = Date.now();
+ const animate = () => {
+ const elapsedTime = Date.now() - startTime;
+ const progress = (elapsedTime % (autoplayDuration * 2)) / autoplayDuration;
+ const percentage = progress <= 1 ? progress * 100 : (2 - progress) * 100;
+
+ setSliderXPercent(percentage);
+ autoplayRef.current = setTimeout(animate, 16); // ~60fps
+ };
+
+ animate();
+ }, [autoplay, autoplayDuration]);
+
+ const stopAutoplay = useCallback(() => {
+ if (autoplayRef.current) {
+ clearTimeout(autoplayRef.current);
+ autoplayRef.current = null;
+ }
+ }, []);
+
+ useEffect(() => {
+ startAutoplay();
+ return () => stopAutoplay();
+ }, [startAutoplay, stopAutoplay]);
+
+ function mouseEnterHandler() {
+ setIsMouseOver(true);
+ stopAutoplay();
+ }
+
+ function mouseLeaveHandler() {
+ setIsMouseOver(false);
+ if (slideMode === 'hover') {
+ setSliderXPercent(initialSliderPercentage);
+ }
+ if (slideMode === 'drag') {
+ setIsDragging(false);
+ }
+ startAutoplay();
+ }
+
+ const handleStart = useCallback(
+ (clientX: number) => {
+ if (slideMode === 'drag') {
+ setIsDragging(true);
+ }
+ },
+ [slideMode],
+ );
+
+ const handleEnd = useCallback(() => {
+ if (slideMode === 'drag') {
+ setIsDragging(false);
+ }
+ }, [slideMode]);
+
+ const handleMove = useCallback(
+ (clientX: number) => {
+ if (!sliderRef.current) return;
+ if (slideMode === 'hover' || (slideMode === 'drag' && isDragging)) {
+ const rect = sliderRef.current.getBoundingClientRect();
+ const x = clientX - rect.left;
+ const percent = (x / rect.width) * 100;
+ requestAnimationFrame(() => {
+ setSliderXPercent(Math.max(0, Math.min(100, percent)));
+ });
+ }
+ },
+ [slideMode, isDragging],
+ );
+
+ const handleMouseDown = useCallback(
+ (e: React.MouseEvent) => handleStart(e.clientX),
+ [handleStart],
+ );
+ const handleMouseUp = useCallback(() => handleEnd(), [handleEnd]);
+ const handleMouseMove = useCallback((e: React.MouseEvent) => handleMove(e.clientX), [handleMove]);
+
+ const handleTouchStart = useCallback(
+ (e: React.TouchEvent) => {
+ if (!autoplay) {
+ handleStart(e.touches[0].clientX);
+ }
+ },
+ [handleStart, autoplay],
+ );
+
+ const handleTouchEnd = useCallback(() => {
+ if (!autoplay) {
+ handleEnd();
+ }
+ }, [handleEnd, autoplay]);
+
+ const handleTouchMove = useCallback(
+ (e: React.TouchEvent) => {
+ if (!autoplay) {
+ handleMove(e.touches[0].clientX);
+ }
+ },
+ [handleMove, autoplay],
+ );
+
+ return (
+
+
+
+
+
+
+
+
+ {showHandlebar && (
+
+
+
+ )}
+
+
+
+
+ {firstImage ? (
+
+
+
+ ) : null}
+
+
+
+
+ {secondImage ? (
+
+ ) : null}
+
+
+ );
+};
+
+const MemoizedSparklesCore = React.memo(SparklesCore);
diff --git a/packages/shadcn/src/components/ui/confetti.tsx b/packages/shadcn/src/components/ui/confetti.tsx
deleted file mode 100644
index 140cb97..0000000
--- a/packages/shadcn/src/components/ui/confetti.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-import type {
- GlobalOptions as ConfettiGlobalOptions,
- CreateTypes as ConfettiInstance,
- Options as ConfettiOptions,
-} from 'canvas-confetti';
-import confetti from 'canvas-confetti';
-import type { ReactNode } from 'react';
-import React, {
- createContext,
- forwardRef,
- useCallback,
- useEffect,
- useImperativeHandle,
- useMemo,
- useRef,
-} from 'react';
-
-import { Button, ButtonProps } from './button';
-
-type Api = {
- fire: (options?: ConfettiOptions) => void;
-};
-
-type Props = React.ComponentPropsWithRef<'canvas'> & {
- options?: ConfettiOptions;
- globalOptions?: ConfettiGlobalOptions;
- manualstart?: boolean;
- children?: ReactNode;
-};
-
-export type ConfettiRef = Api | null;
-
-const ConfettiContext = createContext({} as Api);
-
-const Confetti = forwardRef((props, ref) => {
- const {
- options,
- globalOptions = { resize: true, useWorker: true },
- manualstart = false,
- children,
- ...rest
- } = props;
- const instanceRef = useRef(null); // confetti instance
-
- const canvasRef = useCallback(
- // https://react.dev/reference/react-dom/components/common#ref-callback
- // https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
- (node: HTMLCanvasElement) => {
- if (node !== null) {
- //