Skip to content

Commit d574fb7

Browse files
ImTotemclaude
andcommitted
feat: shadcn sidebar-07 설치 + sheet resizable 복원 + URL 말줄임 수정
- sidebar-07 컴포넌트 설치 (sidebar, nav-user, app-sidebar 등) - sheet.tsx에 resizable 재추가 — resize 감도 수정 (clientX로 직접 계산) - 단축 URL 왼쪽 잘림 수정 (text-left + justify-start) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent bed0dea commit d574fb7

13 files changed

Lines changed: 1458 additions & 17 deletions

src/components/app-sidebar.tsx

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import * as React from "react"
2+
3+
import { NavMain } from "@/components/nav-main"
4+
import { NavProjects } from "@/components/nav-projects"
5+
import { NavUser } from "@/components/nav-user"
6+
import { TeamSwitcher } from "@/components/team-switcher"
7+
import {
8+
Sidebar,
9+
SidebarContent,
10+
SidebarFooter,
11+
SidebarHeader,
12+
SidebarRail,
13+
} from "@/components/ui/sidebar"
14+
import { GalleryVerticalEndIcon, AudioLinesIcon, TerminalIcon, TerminalSquareIcon, BotIcon, BookOpenIcon, Settings2Icon, FrameIcon, PieChartIcon, MapIcon } from "lucide-react"
15+
16+
// This is sample data.
17+
const data = {
18+
user: {
19+
name: "shadcn",
20+
email: "m@example.com",
21+
avatar: "/avatars/shadcn.jpg",
22+
},
23+
teams: [
24+
{
25+
name: "Acme Inc",
26+
logo: (
27+
<GalleryVerticalEndIcon
28+
/>
29+
),
30+
plan: "Enterprise",
31+
},
32+
{
33+
name: "Acme Corp.",
34+
logo: (
35+
<AudioLinesIcon
36+
/>
37+
),
38+
plan: "Startup",
39+
},
40+
{
41+
name: "Evil Corp.",
42+
logo: (
43+
<TerminalIcon
44+
/>
45+
),
46+
plan: "Free",
47+
},
48+
],
49+
navMain: [
50+
{
51+
title: "Playground",
52+
url: "#",
53+
icon: (
54+
<TerminalSquareIcon
55+
/>
56+
),
57+
isActive: true,
58+
items: [
59+
{
60+
title: "History",
61+
url: "#",
62+
},
63+
{
64+
title: "Starred",
65+
url: "#",
66+
},
67+
{
68+
title: "Settings",
69+
url: "#",
70+
},
71+
],
72+
},
73+
{
74+
title: "Models",
75+
url: "#",
76+
icon: (
77+
<BotIcon
78+
/>
79+
),
80+
items: [
81+
{
82+
title: "Genesis",
83+
url: "#",
84+
},
85+
{
86+
title: "Explorer",
87+
url: "#",
88+
},
89+
{
90+
title: "Quantum",
91+
url: "#",
92+
},
93+
],
94+
},
95+
{
96+
title: "Documentation",
97+
url: "#",
98+
icon: (
99+
<BookOpenIcon
100+
/>
101+
),
102+
items: [
103+
{
104+
title: "Introduction",
105+
url: "#",
106+
},
107+
{
108+
title: "Get Started",
109+
url: "#",
110+
},
111+
{
112+
title: "Tutorials",
113+
url: "#",
114+
},
115+
{
116+
title: "Changelog",
117+
url: "#",
118+
},
119+
],
120+
},
121+
{
122+
title: "Settings",
123+
url: "#",
124+
icon: (
125+
<Settings2Icon
126+
/>
127+
),
128+
items: [
129+
{
130+
title: "General",
131+
url: "#",
132+
},
133+
{
134+
title: "Team",
135+
url: "#",
136+
},
137+
{
138+
title: "Billing",
139+
url: "#",
140+
},
141+
{
142+
title: "Limits",
143+
url: "#",
144+
},
145+
],
146+
},
147+
],
148+
projects: [
149+
{
150+
name: "Design Engineering",
151+
url: "#",
152+
icon: (
153+
<FrameIcon
154+
/>
155+
),
156+
},
157+
{
158+
name: "Sales & Marketing",
159+
url: "#",
160+
icon: (
161+
<PieChartIcon
162+
/>
163+
),
164+
},
165+
{
166+
name: "Travel",
167+
url: "#",
168+
icon: (
169+
<MapIcon
170+
/>
171+
),
172+
},
173+
],
174+
}
175+
176+
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
177+
return (
178+
<Sidebar collapsible="icon" {...props}>
179+
<SidebarHeader>
180+
<TeamSwitcher teams={data.teams} />
181+
</SidebarHeader>
182+
<SidebarContent>
183+
<NavMain items={data.navMain} />
184+
<NavProjects projects={data.projects} />
185+
</SidebarContent>
186+
<SidebarFooter>
187+
<NavUser user={data.user} />
188+
</SidebarFooter>
189+
<SidebarRail />
190+
</Sidebar>
191+
)
192+
}

src/components/nav-main.tsx

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"use client"
2+
3+
import {
4+
Collapsible,
5+
CollapsibleContent,
6+
CollapsibleTrigger,
7+
} from "@/components/ui/collapsible"
8+
import {
9+
SidebarGroup,
10+
SidebarGroupLabel,
11+
SidebarMenu,
12+
SidebarMenuButton,
13+
SidebarMenuItem,
14+
SidebarMenuSub,
15+
SidebarMenuSubButton,
16+
SidebarMenuSubItem,
17+
} from "@/components/ui/sidebar"
18+
import { ChevronRightIcon } from "lucide-react"
19+
20+
export function NavMain({
21+
items,
22+
}: {
23+
items: {
24+
title: string
25+
url: string
26+
icon?: React.ReactNode
27+
isActive?: boolean
28+
items?: {
29+
title: string
30+
url: string
31+
}[]
32+
}[]
33+
}) {
34+
return (
35+
<SidebarGroup>
36+
<SidebarGroupLabel>Platform</SidebarGroupLabel>
37+
<SidebarMenu>
38+
{items.map((item) => (
39+
<Collapsible
40+
key={item.title}
41+
defaultOpen={item.isActive}
42+
className="group/collapsible"
43+
render={<SidebarMenuItem />}
44+
>
45+
<CollapsibleTrigger
46+
render={<SidebarMenuButton tooltip={item.title} />}
47+
>
48+
{item.icon}
49+
<span>{item.title}</span>
50+
<ChevronRightIcon className="ml-auto transition-transform duration-200 group-data-open/collapsible:rotate-90" />
51+
</CollapsibleTrigger>
52+
<CollapsibleContent>
53+
<SidebarMenuSub>
54+
{item.items?.map((subItem) => (
55+
<SidebarMenuSubItem key={subItem.title}>
56+
<SidebarMenuSubButton render={<a href={subItem.url} />}>
57+
<span>{subItem.title}</span>
58+
</SidebarMenuSubButton>
59+
</SidebarMenuSubItem>
60+
))}
61+
</SidebarMenuSub>
62+
</CollapsibleContent>
63+
</Collapsible>
64+
))}
65+
</SidebarMenu>
66+
</SidebarGroup>
67+
)
68+
}

src/components/nav-projects.tsx

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import {
2+
DropdownMenu,
3+
DropdownMenuContent,
4+
DropdownMenuItem,
5+
DropdownMenuSeparator,
6+
DropdownMenuTrigger,
7+
} from "@/components/ui/dropdown-menu"
8+
import {
9+
SidebarGroup,
10+
SidebarGroupLabel,
11+
SidebarMenu,
12+
SidebarMenuAction,
13+
SidebarMenuButton,
14+
SidebarMenuItem,
15+
useSidebar,
16+
} from "@/components/ui/sidebar"
17+
import { MoreHorizontalIcon, FolderIcon, ArrowRightIcon, Trash2Icon } from "lucide-react"
18+
19+
export function NavProjects({
20+
projects,
21+
}: {
22+
projects: {
23+
name: string
24+
url: string
25+
icon: React.ReactNode
26+
}[]
27+
}) {
28+
const { isMobile } = useSidebar()
29+
return (
30+
<SidebarGroup className="group-data-[collapsible=icon]:hidden">
31+
<SidebarGroupLabel>Projects</SidebarGroupLabel>
32+
<SidebarMenu>
33+
{projects.map((item) => (
34+
<SidebarMenuItem key={item.name}>
35+
<SidebarMenuButton render={<a href={item.url} />}>
36+
{item.icon}
37+
<span>{item.name}</span>
38+
</SidebarMenuButton>
39+
<DropdownMenu>
40+
<DropdownMenuTrigger
41+
render={
42+
<SidebarMenuAction
43+
showOnHover
44+
className="aria-expanded:bg-muted"
45+
/>
46+
}
47+
>
48+
<MoreHorizontalIcon
49+
/>
50+
<span className="sr-only">More</span>
51+
</DropdownMenuTrigger>
52+
<DropdownMenuContent
53+
className="w-48 rounded-lg"
54+
side={isMobile ? "bottom" : "right"}
55+
align={isMobile ? "end" : "start"}
56+
>
57+
<DropdownMenuItem>
58+
<FolderIcon className="text-muted-foreground" />
59+
<span>View Project</span>
60+
</DropdownMenuItem>
61+
<DropdownMenuItem>
62+
<ArrowRightIcon className="text-muted-foreground" />
63+
<span>Share Project</span>
64+
</DropdownMenuItem>
65+
<DropdownMenuSeparator />
66+
<DropdownMenuItem>
67+
<Trash2Icon className="text-muted-foreground" />
68+
<span>Delete Project</span>
69+
</DropdownMenuItem>
70+
</DropdownMenuContent>
71+
</DropdownMenu>
72+
</SidebarMenuItem>
73+
))}
74+
<SidebarMenuItem>
75+
<SidebarMenuButton className="text-sidebar-foreground/70">
76+
<MoreHorizontalIcon className="text-sidebar-foreground/70" />
77+
<span>More</span>
78+
</SidebarMenuButton>
79+
</SidebarMenuItem>
80+
</SidebarMenu>
81+
</SidebarGroup>
82+
)
83+
}

0 commit comments

Comments
 (0)