Create

Create button effect when the client's click on the create new.

Installation

Run the following command

It will create a new file create.tsx inside the components/buttons/create.tsx directory.

mkdir -p components/buttons && touch components/buttons/create.tsx

Paste the code

Open the newly created file and paste the following code:

"use client";
 
import { AnimatePresence, motion } from "framer-motion";
import {
  BellRing,
  ClipboardList,
  Flag,
  Folder,
  Plus,
  StickyNote,
  Trophy,
  X,
} from "lucide-react";
import { useState } from "react";
 
const transition = { type: "spring", bounce: 0, duration: 0.4 };
 
const Items = [
  {
    name: "Project",
    icon: Folder,
  },
  {
    name: "Task",
    icon: ClipboardList,
  },
  {
    name: "Note",
    icon: StickyNote,
  },
  {
    name: "Goal",
    icon: Trophy,
  },
  {
    name: "Milestone",
    icon: Flag,
  },
  {
    name: "Reminder",
    icon: BellRing,
  },
];
 
const CreateNew = () => {
  const [status, setStatus] = useState<string>("idle");
  const isOpen = status === "open";
  const isHovered = status === "hovered";
 
  return (
    <div className="size-full center">
      <AnimatePresence>
        {isOpen || isHovered ? (
          <motion.div
            layoutId="Wrapper"
            style={{ borderRadius: 22 }}
            className="bg-primary tracking-tight text-primary-foreground"
          >
            <div className="flex w-full items-center justify-between py-2.5 pl-5 pr-2.5">
              <motion.span layoutId="create-new" className="relative">
                Create New
              </motion.span>
              <div className="relative">
                <AnimatePresence>
                  {isHovered && (
                    <motion.p
                      initial={{ opacity: 0, x: 10 }}
                      animate={{ opacity: 1, x: 0 }}
                      exit={{ opacity: 0, x: 10 }}
                      className="absolute -left-11 top-0.5 text-sm "
                    >
                      Close
                    </motion.p>
                  )}
                </AnimatePresence>
                <motion.button
                  layout
                  onClick={() => setStatus("idle")}
                  initial={{ opacity: 0, x: -20, y: 10 }}
                  animate={{ opacity: 1, x: 0, y: 0 }}
                  exit={{ opacity: 0, x: -20, y: 10 }}
                  transition={{ ...transition, delay: 0.15 }}
                  whileTap={{
                    scale: 0.9,
                    transition: { ...transition, duration: 0.2 },
                  }}
                  onHoverStart={() => setStatus("hovered")}
                  onHoverEnd={() => setStatus("open")}
                  className="size-6 flex items-center justify-center rounded-full bg-background"
                >
                  <X className="size-4 text-tight text-secondary-foreground" />
                </motion.button>
              </div>
            </div>
            <motion.div
              initial={{ opacity: 0 }}
              animate={isHovered ? { opacity: 1, scale: 0.95 } : { opacity: 1 }}
              exit={{ opacity: 0 }}
              className="flex flex-col gap-2.5 rounded-[22px] bg-muted-foreground p-2.5 border"
            >
              <div className="grid grid-cols-3 gap-2.5 ">
                {Items.map((item, index) => (
                  <button
                    key={index}
                    className="size-24 grid cursor-pointer place-items-center rounded-2xl bg-background transition duration-500 ease-in-out hover:bg-background hover:duration-200 active:scale-90"
                  >
                    <div className="flex flex-col items-center gap-1">
                      <item.icon className="text-muted-foreground" />
                      <p className="text-[#6b6967]">{item.name}</p>
                    </div>
                  </button>
                ))}
              </div>
            </motion.div>
          </motion.div>
        ) : (
          <motion.button
            layoutId="Wrapper"
            onClick={() => setStatus("open")}
            whileTap={{ scale: 0.95 }}
            style={{ borderRadius: 22 }}
            className="flex items-center gap-1.5 bg-primary text-primary-foreground px-5 py-2.5 tracking-tight"
          >
            <motion.div
              layout
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              transition={{ ...transition, delay: 0.05 }}
            >
              <Plus className="size-4" />
            </motion.div>
            <motion.span layoutId="create-new" className="relative">
              Create New
            </motion.span>
          </motion.button>
        )}
      </AnimatePresence>
    </div>
  );
};
 
export default CreateNew;

Usage

In the directory you want to use, do the following:

import Create from "@/components/buttons/create";
 
const MyButtons = () => {
  return (
    <div>
      {/* your other content*/}
 
      <Create text="Create" />
 
      {/* your other content*/}
    </div>
  );
};
 
export default MyButtons;

Credits

Built by Bossadi Zenith