-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.tsx
More file actions
108 lines (95 loc) · 3.28 KB
/
Copy pathindex.tsx
File metadata and controls
108 lines (95 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
"use client";
import { Suspense } from "react";
import dynamic from "next/dynamic";
import Link from "next/link";
import { usePathname } from "next/navigation";
import Logo from "@/assets/logo.svg";
import { CATEGORY } from "@/constants/category";
import { MINUTE } from "@/constants/time";
import { queryClient } from "@/lib/tanstack";
import { useMobileMenuStore } from "@/lib/zustand/mobile-menu";
import { getCategories } from "@/services/category";
import { Spinner } from "@linkyboard/components";
import { cn } from "@linkyboard/utils";
import type { LucideIcon } from "lucide-react";
import { Book, Grid3X3, Home } from "lucide-react";
const RecentTopicList = dynamic(() => import("./recent-topic-list"), {
ssr: false,
loading: () => <Spinner className="mx-auto" />,
});
interface NavItem {
icon: LucideIcon;
label: string;
href: string;
active?: boolean;
}
const navItems: NavItem[] = [
{ icon: Home, label: "대시보드", href: "/dashboard" },
{ icon: Book, label: "라이브러리", href: "/library" },
{ icon: Grid3X3, label: "토픽 보드", href: "/topic" },
];
export default function Sidebar() {
const pathname = usePathname();
const { isOpen, close } = useMobileMenuStore();
const onMouseEnter = (href: string) => {
if (href === "/library") {
queryClient.prefetchQuery({
queryKey: [CATEGORY.GET_CATEGORIES],
queryFn: getCategories,
staleTime: MINUTE,
});
}
};
return (
<>
{/* Sidebar */}
<aside
className={cn(
"bg-sidebar border-sidebar-border w-70 fixed z-50 h-screen overflow-y-auto border-r p-6 transition-transform duration-300",
"lg:sticky lg:top-0 lg:translate-x-0",
isOpen ? "translate-x-0" : "-translate-x-full"
)}
>
{/* Logo */}
<Link
href="/dashboard"
className="border-sidebar-border mb-8 flex items-center gap-3 border-b pb-4"
>
<Logo className="size-10" />
<div className="text-primary text-2xl font-bold">LinkyBoard</div>
</Link>
{/* Navigation */}
<nav className="mb-8">
{navItems.map((item) => (
<Link
key={item.label}
href={item.href}
onMouseEnter={() => onMouseEnter(item.href)}
className={cn(
"mb-2 flex items-center gap-3 rounded-md px-4 py-3 transition-all duration-300",
pathname.startsWith(item.href)
? "bg-sidebar-primary text-sidebar-primary-foreground"
: "text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
)}
onClick={close}
>
<item.icon size={20} />
<span>{item.label}</span>
</Link>
))}
</nav>
{/* Recent Topics */}
<div className="mt-8">
<div className="text-muted-foreground mb-4 text-sm font-semibold uppercase tracking-wider">
나의 토픽
</div>
<Suspense fallback={<Spinner className="mx-auto" />}>
<RecentTopicList />
</Suspense>
</div>
</aside>
{/* Mobile Overlay */}
{isOpen && <div className="fixed inset-0 z-40 bg-black/50 lg:hidden" onClick={close} />}
</>
);
}