task-managment / src / components / Sidebar.tsx
Sidebar.tsx
Raw
"use client";

import {
  ChevronLeft,
  ChevronRight,
  Cuboid,
  FolderOpenDot,
  House,
  ListChecks,
  UsersRound,
  History,
  Menu,
} from "lucide-react";
import Link from "next/link";
import { useMemo, useState } from "react";
import { usePathname } from "next/navigation";
import { cn } from "@/lib/utils";
import {
  Sheet,
  SheetContent,
  SheetHeader,
  SheetTrigger,
} from "@/components/ui/sheet";

interface LinkItem {
  label: string;
  path: string;
  icon: React.ComponentType<{ className?: string }>;
}

const LINKS: LinkItem[] = [
  { label: "Inicio", path: "/dashboard", icon: House },
  { label: "Proyectos", path: "/dashboard/projects", icon: FolderOpenDot },
  { label: "Tareas", path: "/dashboard/tasks", icon: ListChecks },
  { label: "Inventario", path: "/dashboard/stock", icon: Cuboid },
  { label: "Usuarios", path: "/dashboard/users", icon: UsersRound },
  { label: "Historial", path: "/dashboard/log", icon: History },
];

const getCurrentPath = (path: string) =>
  "/" + path.slice(1).split("/").slice(0, 2).join("/");

const SidebarLink = ({
  link,
  isActive,
  isOpen,
}: {
  link: LinkItem;
  isActive: boolean;
  isOpen: boolean;
}) => (
  <li>
    <Link
      href={link.path}
      className={cn(
        "flex gap-3 items-center text-sm px-4 py-2 font-light rounded-md transition-colors duration-300",
        isActive
          ? isOpen
            ? "bg-primary-foreground text-primary"
            : "bg-primary-foreground text-primary"
          : "text-gray-400 hover:bg-gray-100"
      )}
      aria-label={link.label}
    >
      <link.icon className="text-3xl" />
      <p
        className={cn(
          "transition-opacity duration-1000 ease-in-out",
          isOpen ? "opacity-100" : "opacity-0 hidden"
        )}
      >
        {link.label}
      </p>
    </Link>
  </li>
);

export const Sidebar = () => {
  const [open, setOpen] = useState(true);
  const path = usePathname();
  const currentPath = useMemo(() => getCurrentPath(path), [path]);

  return (
    <aside
      className="hidden md:flex bg-background/75 border-r  flex-col justify-between  border-gray-300 transition-all duration-300 ease-in-out h-svh sticky top-0"
      style={{ minWidth: open ? "15rem" : "6.5rem" }}
    >
      <header className="relative px-2 py-4 flex min-h-[60px] justify-center items-center">
        {/* <div className={cn("absolute ")}>
          <Image
            src="/project-manager-logo.jpg"
            width={150}
            height={150}
            className="w-[120px] h-[80px] m-auto object-cover "
            alt="app logo"
          />
        </div> */}
        <h2 className={cn("text-xl text-center font-light", open ? 'block':'hidden')}>Project Manager</h2>
        <button
          onClick={() => setOpen(!open)}
          className="absolute top-4 right-[-1.9rem] bg-white flex items-center justify-center"
          aria-label="Toggle sidebar"
        >
          {open ? (
            <ChevronLeft
              size={30}
              className="border-y border-r border-gray-400 rounded-r-md"
            />
          ) : (
            <ChevronRight
              size={30}
              className="border-y border-r border-gray-400 rounded-r-md"
            />
          )}
        </button>
      </header>
      <nav className="my-auto px-6 pb-20">
        <ul className="space-y-3">
          {LINKS.map((link) => (
            <SidebarLink
              key={link.label}
              link={link}
              isActive={link.path === currentPath}
              isOpen={open}
            />
          ))}
        </ul>
      </nav>
      <footer></footer>
    </aside>
  );
};

export const MobileSidebar = () => {
  const [open, setOpen] = useState(false);
  const path = usePathname();
  const currentPath = useMemo(() => getCurrentPath(path), [path]);

  return (
    <Sheet open={open} onOpenChange={setOpen}>
      <SheetTrigger asChild>
        <button
          aria-label="Open mobile menu"
          className="grid place-content-center"
        >
          <Menu size={30} />
        </button>
      </SheetTrigger>
      <SheetContent side="right">
        <SheetHeader>
          <h2 className="text-xl font-semibold">Menú</h2>
        </SheetHeader>
        <nav className="flex items-center h-full w-full px-4">
          <ul className="space-y-5 w-full">
            {LINKS.map((link) => (
              <li key={link.label}>
                <Link
                  href={link.path}
                  onClick={() => setOpen(false)}
                  className={cn(
                    "flex gap-3 items-center px-4 py-2.5 rounded-xl transition-colors duration-300",
                    link.path === currentPath
                      ? "bg-gradient-to-r from-primary to-transparent text-white"
                      : "text-gray-600 hover:bg-gray-200"
                  )}
                  aria-label={link.label}
                >
                  <link.icon className="text-xl" />
                  <p>{link.label}</p>
                </Link>
              </li>
            ))}
          </ul>
        </nav>
      </SheetContent>
    </Sheet>
  );
};