DocDoeAI / src /components /clean /layout /CleanSidebar.tsx
asnannp's picture
deploy: sync backend to Space root (learn-lesson HF cache fix)
65d68f5
Raw History Blame Contribute Delete
4.21 kB
"use client";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
import {
BookOpen,
CalendarDays,
ChartNoAxesColumnIncreasing,
ChevronRight,
MessageSquareText,
UserRound,
X,
} from "lucide-react";
import { useAuth } from "@/lib/auth/useAuth";
import { cn } from "@/lib/utils";
const navigation = [
{ label: "Today", href: "/tuition", icon: CalendarDays },
{ label: "Learn Anything", href: "/learn-anything", icon: BookOpen },
{ label: "Study Chat", href: "/study-chat", icon: MessageSquareText },
{ label: "Progress", href: "/progress", icon: ChartNoAxesColumnIncreasing },
{ label: "Profile", href: "/profile", icon: UserRound },
] as const;
function isActive(pathname: string, href: string) {
return pathname === href || pathname.startsWith(`${href}/`);
}
export interface CleanSidebarProps {
onNavigate?: () => void;
onClose?: () => void;
}
export function CleanSidebar({ onNavigate, onClose }: CleanSidebarProps) {
const pathname = usePathname() ?? "";
const { user } = useAuth();
const displayName = user?.name?.trim() || "Student";
const initials = displayName
.split(/\s+/)
.map((word) => word[0])
.join("")
.slice(0, 2)
.toUpperCase();
return (
<aside className="flex h-full w-full flex-col border-r border-[#E7E4DE] bg-[#FBFAF7] text-[#171717]">
<div className="flex h-16 items-center gap-3 border-b border-[#E7E4DE] px-4">
<span className="flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-[#171717]">
<Image src="/docdoe-logo-mark.png" alt="DocDoe" width={22} height={22} className="object-contain" priority />
</span>
<div className="min-w-0 flex-1">
<p className="truncate text-[15px] font-bold">DocDoe</p>
<p className="text-[10px] font-medium text-[#77736C]">Private tuition workspace</p>
</div>
{onClose ? (
<button
type="button"
onClick={onClose}
aria-label="Close navigation"
className="inline-flex size-9 items-center justify-center rounded-lg text-[#77736C] transition hover:bg-[#F0EEE8] hover:text-[#171717] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#171717]/20"
>
<X className="size-[18px]" strokeWidth={1.8} />
</button>
) : null}
</div>
<nav className="flex-1 space-y-1 overflow-y-auto px-3 py-5" aria-label="DocDoe navigation">
{navigation.map((item) => {
const active = isActive(pathname, item.href);
const Icon = item.icon;
return (
<Link
key={item.href}
href={item.href}
onClick={onNavigate}
aria-current={active ? "page" : undefined}
className={cn(
"group flex min-h-11 items-center gap-3 rounded-lg px-3 text-[13px] font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#171717]/20",
active
? "bg-[#171717] text-white"
: "text-[#5F5B55] hover:bg-[#F0EEE8] hover:text-[#171717]",
)}
>
<Icon className="size-[18px] shrink-0" strokeWidth={1.8} />
<span className="truncate">{item.label}</span>
<ChevronRight className={cn("ml-auto size-4", active ? "text-white/65" : "text-[#B4B0A8]")} />
</Link>
);
})}
</nav>
<Link
href="/profile"
onClick={onNavigate}
className="m-3 flex items-center gap-3 border-t border-[#E7E4DE] px-1 pt-4"
>
<span className="flex size-9 shrink-0 items-center justify-center rounded-full border border-[#DAD6CE] bg-white text-[11px] font-bold">
{initials || "ST"}
</span>
<span className="min-w-0 flex-1">
<span className="block truncate text-[13px] font-semibold">{displayName}</span>
<span className="block text-[10px] text-[#858078]">Student profile</span>
</span>
<ChevronRight className="size-4 text-[#B4B0A8]" />
</Link>
</aside>
);
}