● Zion Boggan
repos/Drophawk/frontend/components/layout/Sidebar.tsx
zionboggan.com ↗
102 lines · tsx
History for this file →
1
"use client";
2
 
3
import Link from "next/link";
4
import { usePathname } from "next/navigation";
5
import { motion } from "framer-motion";
6
import { PanelLeftClose, PanelLeft } from "lucide-react";
7
import { NAV } from "./nav";
8
import { Wordmark } from "./BrandMark";
9
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
10
import { useUiStore } from "@/stores/ui";
11
import { cn } from "@/lib/utils";
12
 
13
export function Sidebar() {
14
  const pathname = usePathname();
15
  const collapsed = useUiStore((s) => s.sidebarCollapsed);
16
  const toggle = useUiStore((s) => s.toggleSidebar);
17
 
18
  return (
19
    <aside
20
      className={cn(
21
        "sticky top-0 hidden h-dvh shrink-0 flex-col border-r border-[var(--color-border-subtle)] bg-[var(--color-bg-inset)] md:flex",
22
        "transition-[width] duration-[var(--duration-base)]",
23
        collapsed ? "w-[68px]" : "w-[232px]",
24
      )}
25
    >
26
      <div className={cn("flex h-16 items-center px-4", collapsed && "justify-center px-0")}>
27
        <Link href="/" className="rounded-[var(--radius-sm)]" aria-label="DropHawk home">
28
          <Wordmark collapsed={collapsed} />
29
        </Link>
30
      </div>
31
 
32
      <nav className="flex flex-1 flex-col gap-1 px-3" aria-label="Primary">
33
        {NAV.map((item) => {
34
          const active = item.href === "/" ? pathname === "/" : pathname.startsWith(item.href);
35
          const link = (
36
            <Link
37
              key={item.href}
38
              href={item.ready ? item.href : "#"}
39
              aria-current={active ? "page" : undefined}
40
              aria-disabled={!item.ready || undefined}
41
              className={cn(
42
                "group relative flex items-center gap-3 rounded-[var(--radius)] px-3 py-2 text-sm font-medium",
43
                "transition-colors duration-[var(--duration-fast)]",
44
                collapsed && "justify-center px-0",
45
                active
46
                  ? "text-[var(--color-fg-primary)]"
47
                  : "text-[var(--color-fg-tertiary)] hover:bg-[var(--color-bg-elevated)] hover:text-[var(--color-fg-primary)]",
48
                !item.ready && "cursor-not-allowed opacity-45 hover:bg-transparent",
49
              )}
50
              onClick={!item.ready ? (e) => e.preventDefault() : undefined}
51
            >
52
              {active ? (
53
                <motion.span
54
                  layoutId="nav-active"
55
                  className="absolute inset-0 -z-10 rounded-[var(--radius)] bg-[var(--color-accent-teal-soft)]"
56
                  transition={{ type: "spring", stiffness: 480, damping: 36 }}
57
                />
58
              ) : null}
59
              {active ? (
60
                <span className="absolute left-0 top-1/2 h-5 w-0.5 -translate-y-1/2 rounded-full bg-[var(--color-accent-teal)]" />
61
              ) : null}
62
              <item.icon
63
                className={cn("h-[18px] w-[18px] shrink-0", active && "text-[var(--color-accent-teal)]")}
64
                aria-hidden
65
              />
66
              {!collapsed ? (
67
                <span className="flex-1">{item.label}</span>
68
              ) : null}
69
              {!collapsed && !item.ready ? (
70
                <span className="rounded-full bg-[var(--color-bg-overlay)] px-1.5 py-0.5 text-[10px] text-[var(--color-fg-tertiary)]">
71
                  soon
72
                </span>
73
              ) : null}
74
            </Link>
75
          );
76
          return collapsed ? (
77
            <Tooltip key={item.href}>
78
              <TooltipTrigger asChild>{link}</TooltipTrigger>
79
              <TooltipContent side="right">{item.label}</TooltipContent>
80
            </Tooltip>
81
          ) : (
82
            link
83
          );
84
        })}
85
      </nav>
86
 
87
      <button
88
        type="button"
89
        onClick={toggle}
90
        className={cn(
91
          "m-3 flex items-center gap-3 rounded-[var(--radius)] px-3 py-2 text-sm text-[var(--color-fg-tertiary)]",
92
          "transition-colors hover:bg-[var(--color-bg-elevated)] hover:text-[var(--color-fg-primary)]",
93
          collapsed && "justify-center px-0",
94
        )}
95
        aria-label={collapsed ? "Expand sidebar" : "Collapse sidebar"}
96
      >
97
        {collapsed ? <PanelLeft className="h-[18px] w-[18px]" /> : <PanelLeftClose className="h-[18px] w-[18px]" />}
98
        {!collapsed ? <span>Collapse</span> : null}
99
      </button>
100
    </aside>
101
  );
102
}