NEW
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
Learn more
Skip to content
Docs

Direction Card

A direction card which adapts itself on directions and distance

Loading...

Installation

CLI

pnpm dlx shadcn@latest add https://animata.design/r/widget/direction-card.json

Manual

Install dependencies

bash npm install lucide-react

Run the following command

It will create a new file called direction-card.tsx inside the components/animata/widget directory.

mkdir -p components/animata/widget && touch components/animata/widget/direction-card.tsx

Paste the code

Open the newly created file and paste the following code:

"use client";
import { ArrowUp, CornerUpLeft, CornerUpRight } from "lucide-react";
import { type ElementType, useEffect, useState } from "react";
 
import { cn } from "@/lib/utils";
 
interface Direction {
  distance: number;
  direction: string;
  to: string;
  iconType: ElementType;
}
 
interface IDirectionCardProps {
  directionValues: Direction[];
  duration?: number;
}
 
export const testDirectionProps: IDirectionCardProps = {
  directionValues: [
    {
      distance: 350,
      direction: "right",
      to: "Gurkha St.",
      iconType: CornerUpRight,
    },
    {
      distance: 700,
      direction: "left",
      to: "Rounding St.",
      iconType: CornerUpLeft,
    },
    {
      distance: 100,
      direction: "left",
      to: "Fulbari marga",
      iconType: CornerUpLeft,
    },
    {
      distance: 1000,
      direction: "straight",
      to: "hwy 16",
      iconType: ArrowUp,
    },
  ],
};
 
function DirectionCard({
  directionValues = testDirectionProps.directionValues,
  duration = 5000,
}: IDirectionCardProps) {
  const [currentIndex, setCurrentIndex] = useState(0);
  const [iconState, setIconState] = useState({
    prevIconType: directionValues[directionValues.length - 1].iconType,
    currentIconType: directionValues[0].iconType,
    nextIconType: directionValues[1].iconType,
  });
  const [progress, setProgress] = useState(0);
 
  useEffect(() => {
    //this would change the states based on direction change. Currently set to setInterval.
    const changeDirectionInterval = setInterval(() => {
      setCurrentIndex((prevIndex) => {
        const newIndex = (prevIndex + 1) % directionValues.length;
        const prev =
          newIndex === 0
            ? directionValues[directionValues.length - 1].iconType
            : directionValues[newIndex - 1].iconType;
        const next =
          newIndex === directionValues.length - 1
            ? directionValues[0].iconType
            : directionValues[newIndex + 1].iconType;
        setIconState({
          prevIconType: prev,
          currentIconType: directionValues[newIndex].iconType,
          nextIconType: next,
        });
        return newIndex;
      });
      setProgress(0);
    }, duration ?? 5000);
 
    const progressIncrement = 100 / ((duration ?? 5000) / 100);
    const progressInterval = setInterval(() => {
      setProgress((prevProgress) => {
        if (prevProgress >= 100) {
          return 100;
        }
        return prevProgress + progressIncrement;
      });
    }, 100);
 
    return () => {
      clearInterval(changeDirectionInterval);
      clearInterval(progressInterval);
    };
  }, [directionValues, duration]);
 
  const currentDirection = directionValues[currentIndex];
 
  const renderIcon = (IconComponent: ElementType, size = 52, color = "text-gray-300") => (
    <IconComponent size={size} className={cn("text-white", color)} />
  );
  return (
    <div className="direction-card flex size-52 items-start justify-between rounded-3xl bg-black p-4">
      <div className="direction-container flex h-full w-[80%] flex-col items-center justify-center gap-3">
        <p className="text-3xl font-bold text-white">
          {currentDirection.distance}
          <span className="text-black/50">m</span>
        </p>
        <p className="animate-pulse">{renderIcon(iconState.currentIconType, 52, "text-white")}</p>
        <p className="text-md h-8 w-20 text-ellipsis break-all text-center text-gray-400">
          {currentDirection.to}
        </p>
      </div>
      <div className="progress-icon-container flex h-full w-[100px] flex-row-reverse justify-around">
        <div className="relative flex flex-col justify-evenly">
          <div
            style={{ boxShadow: "inset 0px -30px 20px 0px black" }}
            className="absolute inset-0 shadow"
          />
          {renderIcon(iconState.prevIconType, 32)}
          {renderIcon(iconState.currentIconType, 32, "text-green-300")}
          {renderIcon(iconState.nextIconType, 32)}
        </div>
        <div
          style={{ height: "100%" }}
          className="progress-bar flex h-full w-[6px] items-end rounded-xl bg-gray-400"
        >
          <div
            style={{ height: `${progress}%` }}
            className="progress-bar h-full w-[6px] rounded-xl bg-green-300 shadow-glow2"
          />
        </div>
      </div>
    </div>
  );
}
 
export default DirectionCard;

Credits

Built by Aadarsh Baral