1+ 'use client' ;
2+
3+ import { ReactNode , useState } from 'react' ;
4+ import Link from 'next/link' ;
5+ import { usePathname } from 'next/navigation' ;
6+ import {
7+ LayoutDashboard ,
8+ Package ,
9+ ShoppingCart ,
10+ Users ,
11+ BarChart3 ,
12+ Settings ,
13+ Menu ,
14+ X ,
15+ Bell ,
16+ Search ,
17+ LogOut ,
18+ ChevronDown ,
19+ TrendingUp ,
20+ Store ,
21+ Truck
22+ } from 'lucide-react' ;
23+
24+ interface AdminLayoutProps {
25+ children : ReactNode ;
26+ }
27+
28+ export default function AdminLayout ( { children } : AdminLayoutProps ) {
29+ const pathname = usePathname ( ) ;
30+ const [ isSidebarOpen , setIsSidebarOpen ] = useState ( false ) ;
31+ const [ isProfileOpen , setIsProfileOpen ] = useState ( false ) ;
32+
33+ const menuItems = [
34+ {
35+ title : '대시보드' ,
36+ href : '/admin' ,
37+ icon : LayoutDashboard ,
38+ badge : null
39+ } ,
40+ {
41+ title : '상품 관리' ,
42+ href : '/admin/products' ,
43+ icon : Package ,
44+ badge : '152'
45+ } ,
46+ {
47+ title : '주문 관리' ,
48+ href : '/admin/orders' ,
49+ icon : ShoppingCart ,
50+ badge : '12' ,
51+ badgeColor : 'bg-orange-500'
52+ } ,
53+ {
54+ title : '배송 관리' ,
55+ href : '/admin/delivery' ,
56+ icon : Truck ,
57+ badge : '8' ,
58+ badgeColor : 'bg-blue-500'
59+ } ,
60+ {
61+ title : '고객 관리' ,
62+ href : '/admin/users' ,
63+ icon : Users ,
64+ badge : null
65+ } ,
66+ {
67+ title : '매출 분석' ,
68+ href : '/admin/analytics' ,
69+ icon : BarChart3 ,
70+ badge : null
71+ } ,
72+ {
73+ title : '매장 설정' ,
74+ href : '/admin/store' ,
75+ icon : Store ,
76+ badge : null
77+ } ,
78+ {
79+ title : '시스템 설정' ,
80+ href : '/admin/settings' ,
81+ icon : Settings ,
82+ badge : null
83+ }
84+ ] ;
85+
86+ const isActive = ( href : string ) => {
87+ if ( href === '/admin' ) {
88+ return pathname === '/admin' ;
89+ }
90+ return pathname . startsWith ( href ) ;
91+ } ;
92+
93+ return (
94+ < div className = "min-h-screen bg-gray-50" >
95+ { /* Mobile Sidebar Backdrop */ }
96+ { isSidebarOpen && (
97+ < div
98+ className = "fixed inset-0 bg-black/50 z-40 lg:hidden"
99+ onClick = { ( ) => setIsSidebarOpen ( false ) }
100+ />
101+ ) }
102+
103+ { /* Sidebar */ }
104+ < aside
105+ className = { `fixed top-0 left-0 z-50 h-full w-64 bg-white border-r border-gray-200 transform transition-transform duration-200 ease-in-out ${
106+ isSidebarOpen ? 'translate-x-0' : '-translate-x-full'
107+ } lg:translate-x-0`}
108+ >
109+ { /* Logo */ }
110+ < div className = "flex items-center justify-between h-16 px-6 border-b border-gray-200" >
111+ < div className = "flex items-center gap-2" >
112+ < div className = "w-8 h-8 bg-gradient-to-br from-orange-500 to-pink-500 rounded-lg flex items-center justify-center text-white font-bold" >
113+ Q
114+ </ div >
115+ < span className = "font-bold text-gray-900" > 퀵마트 관리자</ span >
116+ </ div >
117+ < button
118+ onClick = { ( ) => setIsSidebarOpen ( false ) }
119+ className = "lg:hidden p-1 hover:bg-gray-100 rounded-lg"
120+ >
121+ < X className = "w-5 h-5 text-gray-500" />
122+ </ button >
123+ </ div >
124+
125+ { /* Navigation */ }
126+ < nav className = "p-4 space-y-1" >
127+ { menuItems . map ( ( item ) => {
128+ const Icon = item . icon ;
129+ const active = isActive ( item . href ) ;
130+
131+ return (
132+ < Link
133+ key = { item . href }
134+ href = { item . href }
135+ className = { `flex items-center justify-between px-3 py-2.5 rounded-lg transition-all ${
136+ active
137+ ? 'bg-orange-50 text-orange-600 font-medium'
138+ : 'text-gray-700 hover:bg-gray-100'
139+ } `}
140+ >
141+ < div className = "flex items-center gap-3" >
142+ < Icon className = { `w-5 h-5 ${ active ? 'text-orange-600' : 'text-gray-400' } ` } />
143+ < span > { item . title } </ span >
144+ </ div >
145+ { item . badge && (
146+ < span
147+ className = { `px-2 py-0.5 text-xs font-medium rounded-full text-white ${
148+ item . badgeColor || 'bg-gray-500'
149+ } `}
150+ >
151+ { item . badge }
152+ </ span >
153+ ) }
154+ </ Link >
155+ ) ;
156+ } ) }
157+ </ nav >
158+
159+ { /* Bottom Section */ }
160+ < div className = "absolute bottom-0 left-0 right-0 p-4 border-t border-gray-200" >
161+ < div className = "bg-gradient-to-br from-orange-50 to-pink-50 rounded-lg p-4" >
162+ < div className = "flex items-center gap-2 mb-2" >
163+ < TrendingUp className = "w-5 h-5 text-orange-500" />
164+ < span className = "text-sm font-medium text-gray-900" > 매출 증가</ span >
165+ </ div >
166+ < p className = "text-xs text-gray-600 mb-3" >
167+ 이번 달 매출이 지난달 대비 32% 증가했습니다!
168+ </ p >
169+ < button className = "w-full py-2 bg-gradient-to-r from-orange-500 to-pink-500 text-white text-sm font-medium rounded-lg hover:shadow-md transition-shadow" >
170+ 상세 보기
171+ </ button >
172+ </ div >
173+ </ div >
174+ </ aside >
175+
176+ { /* Main Content Area */ }
177+ < div className = "lg:ml-64" >
178+ { /* Top Header */ }
179+ < header className = "sticky top-0 z-30 bg-white border-b border-gray-200" >
180+ < div className = "flex items-center justify-between h-16 px-4 lg:px-6" >
181+ { /* Left Section */ }
182+ < div className = "flex items-center gap-4" >
183+ < button
184+ onClick = { ( ) => setIsSidebarOpen ( true ) }
185+ className = "lg:hidden p-2 hover:bg-gray-100 rounded-lg"
186+ >
187+ < Menu className = "w-5 h-5 text-gray-600" />
188+ </ button >
189+
190+ { /* Search Bar */ }
191+ < div className = "relative hidden sm:block" >
192+ < Search className = "absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
193+ < input
194+ type = "text"
195+ placeholder = "검색어를 입력하세요..."
196+ className = "pl-10 pr-4 py-2 w-64 bg-gray-50 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-orange-500 focus:border-transparent"
197+ />
198+ </ div >
199+ </ div >
200+
201+ { /* Right Section */ }
202+ < div className = "flex items-center gap-2" >
203+ { /* Notifications */ }
204+ < button className = "relative p-2 hover:bg-gray-100 rounded-lg" >
205+ < Bell className = "w-5 h-5 text-gray-600" />
206+ < span className = "absolute top-1 right-1 w-2 h-2 bg-red-500 rounded-full" />
207+ </ button >
208+
209+ { /* Profile Dropdown */ }
210+ < div className = "relative" >
211+ < button
212+ onClick = { ( ) => setIsProfileOpen ( ! isProfileOpen ) }
213+ className = "flex items-center gap-3 p-2 hover:bg-gray-100 rounded-lg"
214+ >
215+ < div className = "w-8 h-8 bg-gradient-to-br from-orange-400 to-pink-400 rounded-full flex items-center justify-center text-white text-sm font-medium" >
216+ 관
217+ </ div >
218+ < div className = "hidden sm:block text-left" >
219+ < p className = "text-sm font-medium text-gray-900" > 관리자</ p >
220+ < p className = "text-xs text-gray-500" > admin@quickmart.com</ p >
221+ </ div >
222+ < ChevronDown className = "w-4 h-4 text-gray-400" />
223+ </ button >
224+
225+ { /* Dropdown Menu */ }
226+ { isProfileOpen && (
227+ < div className = "absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border border-gray-200 py-1" >
228+ < Link
229+ href = "/admin/profile"
230+ className = "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
231+ >
232+ 프로필 설정
233+ </ Link >
234+ < Link
235+ href = "/admin/security"
236+ className = "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
237+ >
238+ 보안 설정
239+ </ Link >
240+ < hr className = "my-1 border-gray-200" />
241+ < button className = "w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-red-50 flex items-center gap-2" >
242+ < LogOut className = "w-4 h-4" />
243+ 로그아웃
244+ </ button >
245+ </ div >
246+ ) }
247+ </ div >
248+ </ div >
249+ </ div >
250+ </ header >
251+
252+ { /* Page Content */ }
253+ < main className = "p-4 lg:p-6" >
254+ { children }
255+ </ main >
256+ </ div >
257+ </ div >
258+ ) ;
259+ }
0 commit comments