HomeComponentProgress Card

Progress Card

Published Nov 20, 2024
By Vishal Karangale
tailwindCss
framer motion

Forge Your Gaming Legend

With your ambitions in sight, we’re ready to craft a personalized gaming strategy. Our advanced system adapts to your playstyle and pace to help you achieve your goals.

Your Unique Gaming Strategy

85% Match

This plan includes tailored challenges, immersive quests, and skill building missions to ensure you level up with confidence and precision.

Component Props

Expandable Card Wrapper

PropTypeDefault
steps
ReactNode[]
-

Base Component

Copy and paste the following base component in your project
Make sure to install all the required dependencies

HoverButton.tsx
"use client";
 
import type { Variants } from "framer-motion";
import type React from "react";
import type { ReactNode } from "react";
 
import { AnimatePresence, motion } from "framer-motion";
import { useState } from "react";
import { twMerge } from "tailwind-merge";
 
import { SegmentedLoader } from "../../Other/Progress";
 
interface ProgressCardProps {
  steps: ReactNode[];
}
 
const slideVariants: Variants = {
  enter: (direction: number) => ({
    x: direction > 0 ? 300 : -300,
    opacity: 0,
  }),
  center: {
    zIndex: 1,
    x: 0,
    opacity: 1,
  },
  exit: (direction: number) => ({
    zIndex: 0,
    x: direction < 0 ? 300 : -300,
    opacity: 0,
  }),
};
 
const ProgressCard: React.FC<ProgressCardProps> = ({ steps }) => {
  const [currentStep, setCurrentStep] = useState<number>(0);
  const [direction, setDirection] = useState<number>(0);
 
  const handleNext = (): void => {
    if (currentStep < steps.length - 1) {
      setDirection(1);
      setCurrentStep((prev) => prev + 1);
    }
  };
 
  const handlePrevious = (): void => {
    if (currentStep > 0) {
      setDirection(-1);
      setCurrentStep((prev) => prev - 1);
    }
  };
 
  return (
    <motion.div 
      layout
      transition={{ duration: 0.3, ease: "easeInOut" }}
      className="mx-auto w-full max-w-lg rounded-xl bg-[#111111] shadow-lg flex flex-col overflow-hidden"
    >
      <div className="p-4">
        <SegmentedLoader
          currentStep={currentStep}
          totalSteps={steps.length}
          height="h-2"
        />
      </div>
      <motion.div 
        layout 
        className="relative overflow-hidden"
      >
        <AnimatePresence initial={false} custom={direction} mode="popLayout">
          <motion.div
            layout
            key={currentStep}
            custom={direction}
            variants={slideVariants}
            initial="enter"
            animate="center"
            exit="exit"
            transition={{
              layout: {
                duration: 0.3,
                ease: "easeInOut"
              },
              x: { type: "spring", stiffness: 300, damping: 30, duration: 0.1 },
              opacity: { duration: 0.1 },
            }}
            className="w-full top-0 left-0"
          >
            {steps[currentStep]}
          </motion.div>
        </AnimatePresence>
      </motion.div>
      <motion.div 
        layout
        className="flex justify-between border-[#222222] border-t-2 bg-[#0f0f0f] p-4"
      >
        <button
          type="button"
          onClick={handlePrevious}
          disabled={currentStep === 0}
          className={twMerge(
            `relative w-max rounded-xl border-0 px-4 py-3 text-sm z-0 flex items-center justify-center gap-2 overflow-hidden bg-[#191e1f] border-[#292d2e] font-semibold capitalize text-white-a12 transition-transform duration-300
            disabled:opacity-50 disabled:cursor-not-allowed hover:scale-105 active:scale-95`,
          )}
        >
          Previous
        </button>
        <button
          type="button"
          onClick={handleNext}
          disabled={currentStep === steps.length - 1}
          className={twMerge(
            `relative w-max rounded-xl border-0 px-4 py-3 text-sm z-0 flex items-center justify-center gap-2 overflow-hidden bg-[#191e1f] border-[#292d2e] font-semibold capitalize text-white-a12 transition-transform duration-300
            disabled:opacity-50 disabled:cursor-not-allowed hover:scale-105 active:scale-95`,
          )}
        >
          Next
        </button>
      </motion.div>
    </motion.div>
  );
};
 
export default ProgressCard;
Built with Next.js