Skip to content

Commit

Permalink
feat: install magic ui dock
Browse files Browse the repository at this point in the history
  • Loading branch information
Laughing0900 committed Jul 23, 2024
1 parent d139173 commit c612b55
Showing 1 changed file with 126 additions and 0 deletions.
126 changes: 126 additions & 0 deletions src/components/ui/dock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
"use client";

import { cva } from "class-variance-authority";
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
import React, { PropsWithChildren, useRef } from "react";
import { cn } from "@/lib/utils";
import type { VariantProps } from "class-variance-authority";

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 = 140;

const dockVariants = cva(
"mx-auto w-max mt-8 h-[58px] p-2 flex gap-2 rounded-2xl border supports-backdrop-blur:bg-white/10 supports-backdrop-blur:dark:bg-black/10 backdrop-blur-md"
);

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 = ({
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;
});

const widthSync = useTransform(
distanceCalc,
[-distance, 0, distance],
[40, magnification, 40]
);

const 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 comments on commit c612b55

Please sign in to comment.