@potenlab/ui 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +756 -0
- package/package.json +8 -3
- package/template/admin/README.md +36 -0
- package/template/admin/_gitignore +41 -0
- package/template/admin/components.json +23 -0
- package/template/admin/docs/changes.json +295 -0
- package/template/admin/docs/dev-plan.md +822 -0
- package/template/admin/docs/frontend-plan.md +874 -0
- package/template/admin/docs/prd.md +408 -0
- package/template/admin/docs/progress.json +777 -0
- package/template/admin/docs/test-plan.md +790 -0
- package/template/admin/docs/ui-ux-plan.md +1664 -0
- package/template/admin/eslint.config.mjs +18 -0
- package/template/admin/next.config.ts +7 -0
- package/template/admin/package.json +43 -0
- package/template/admin/postcss.config.mjs +7 -0
- package/template/admin/public/avatars/user1.svg +4 -0
- package/template/admin/public/avatars/user2.svg +4 -0
- package/template/admin/public/avatars/user3.svg +4 -0
- package/template/admin/public/avatars/user4.svg +4 -0
- package/template/admin/public/avatars/user5.svg +4 -0
- package/template/admin/public/file.svg +1 -0
- package/template/admin/public/globe.svg +1 -0
- package/template/admin/public/next.svg +1 -0
- package/template/admin/public/profile/img1.svg +7 -0
- package/template/admin/public/profile/img2.svg +7 -0
- package/template/admin/public/profile/img3.svg +7 -0
- package/template/admin/public/vercel.svg +1 -0
- package/template/admin/public/window.svg +1 -0
- package/template/admin/src/app/favicon.ico +0 -0
- package/template/admin/src/app/layout.tsx +38 -0
- package/template/admin/src/app/page.tsx +5 -0
- package/template/admin/src/app/users/[id]/page.tsx +10 -0
- package/template/admin/src/components/layouts/app-sidebar.tsx +152 -0
- package/template/admin/src/components/user-management/profile-images.tsx +69 -0
- package/template/admin/src/components/user-management/user-detail-form.tsx +143 -0
- package/template/admin/src/features/user-management/components/user-columns.tsx +101 -0
- package/template/admin/src/features/user-management/components/user-detail.tsx +79 -0
- package/template/admin/src/features/user-management/components/user-list.tsx +74 -0
- package/template/admin/src/features/user-management/types/index.ts +113 -0
- package/template/admin/src/features/user-management/utils/format.ts +2 -0
- package/template/admin/src/lib/mock-data.ts +131 -0
- package/template/admin/src/styles/globals.css +26 -0
- package/template/admin/tsconfig.json +34 -0
|
@@ -0,0 +1,1664 @@
|
|
|
1
|
+
# UI/UX Design Plan
|
|
2
|
+
|
|
3
|
+
Generated: 2026-03-04
|
|
4
|
+
Source PRD: template/docs/prd.md
|
|
5
|
+
Design System: Potenlab Admin Design System
|
|
6
|
+
Platform: Desktop-only (1920px target)
|
|
7
|
+
Tech Stack: Next.js 16 (App Router), TypeScript, shadcn/ui, Tailwind CSS 4, Lucide React, Bun
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Executive Summary
|
|
12
|
+
|
|
13
|
+
This UI/UX design plan covers a **frontend-only** admin dashboard for managing users of a fitness/workout matching platform. The interface consists of two primary views: a **User Management List** (dashboard) and a **User Detail** page, connected by a persistent sidebar navigation.
|
|
14
|
+
|
|
15
|
+
The design follows a custom brand identity derived from Figma design tokens, centered around a teal (`#509594`) primary palette. The aesthetic is clean, professional, and data-oriented -- optimized for admin efficiency on desktop screens. All data is static/mock with no backend integration.
|
|
16
|
+
|
|
17
|
+
Key design decisions:
|
|
18
|
+
- **Fixed sidebar + scrollable content area** layout for persistent navigation
|
|
19
|
+
- **Custom teal brand color** (#509594) applied across shadcn/ui component overrides
|
|
20
|
+
- **Pretendard Variable + Inter** font pairing for Korean/English bilingual support
|
|
21
|
+
- **Desktop-only** design at 1920px -- no responsive breakpoints required
|
|
22
|
+
- **WCAG 2.1 AA** compliance for accessibility
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 1. User Research
|
|
27
|
+
|
|
28
|
+
### 1.1 Problem Statement
|
|
29
|
+
|
|
30
|
+
**Business Goal:** Provide admin staff with an efficient interface to view, manage, and edit user accounts on a fitness/workout matching platform.
|
|
31
|
+
|
|
32
|
+
**User Need:** Admin users need to quickly scan a large user base, locate specific users, view detailed profiles, and make edits to user information -- all within a structured, low-friction interface.
|
|
33
|
+
|
|
34
|
+
**Design Challenge:** How might we design a data-dense admin interface that remains visually clear, scannable, and efficient for daily administrative tasks without overwhelming the operator?
|
|
35
|
+
|
|
36
|
+
### 1.2 User Personas
|
|
37
|
+
|
|
38
|
+
#### Primary Persona: Jimin Park -- Platform Operations Manager
|
|
39
|
+
|
|
40
|
+
| Attribute | Details |
|
|
41
|
+
|-----------|---------|
|
|
42
|
+
| **Demographics** | Age 32, operations manager at fitness tech startup, high tech-savviness |
|
|
43
|
+
| **Goals** | Quickly review user accounts, update user profiles, monitor platform growth |
|
|
44
|
+
| **Pain Points** | Slow-loading dashboards, unclear data tables, too many clicks to reach detail pages |
|
|
45
|
+
| **Behaviors** | Uses admin panel 4-6 hours daily, manages 100,000+ user accounts, prefers keyboard shortcuts |
|
|
46
|
+
| **Quote** | "I need to find a user, check their info, and move on -- in under 30 seconds." |
|
|
47
|
+
|
|
48
|
+
#### Secondary Persona: Soyeon Lee -- Customer Support Lead
|
|
49
|
+
|
|
50
|
+
| Attribute | Details |
|
|
51
|
+
|-----------|---------|
|
|
52
|
+
| **Demographics** | Age 27, support team lead, moderate tech-savviness |
|
|
53
|
+
| **Goals** | Look up user details when handling support tickets, verify account information |
|
|
54
|
+
| **Pain Points** | Difficulty finding specific users, unclear field labels, no visual feedback on actions |
|
|
55
|
+
| **Behaviors** | Uses admin panel intermittently (1-2 hours daily), often cross-references with support tickets |
|
|
56
|
+
| **Quote** | "When a user calls in, I need to pull up their profile instantly and see everything at a glance." |
|
|
57
|
+
|
|
58
|
+
#### Tertiary Persona: Donghyun Kim -- Junior Admin
|
|
59
|
+
|
|
60
|
+
| Attribute | Details |
|
|
61
|
+
|-----------|---------|
|
|
62
|
+
| **Demographics** | Age 24, recently hired admin assistant, lower tech-savviness |
|
|
63
|
+
| **Goals** | Learn the system quickly, perform assigned tasks without errors |
|
|
64
|
+
| **Pain Points** | Unfamiliar navigation patterns, fear of accidentally deleting data, unclear save states |
|
|
65
|
+
| **Behaviors** | Uses admin panel a few times per week, follows step-by-step procedures |
|
|
66
|
+
| **Quote** | "I want to make sure I'm clicking the right thing before anything changes." |
|
|
67
|
+
|
|
68
|
+
### 1.3 User Journey Map
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
Journey: Admin reviews and edits a user profile
|
|
72
|
+
|
|
73
|
+
Stage 1: Access Dashboard
|
|
74
|
+
|- Actions: Logs in, lands on User Management List page
|
|
75
|
+
|- Thoughts: "Let me see what's going on with our users today."
|
|
76
|
+
|- Emotions: Neutral
|
|
77
|
+
|- Pain Points: Slow load times, unclear initial state
|
|
78
|
+
|- Opportunities: Fast-loading static page, clear data summary with badge count
|
|
79
|
+
|
|
80
|
+
Stage 2: Scan User Table
|
|
81
|
+
|- Actions: Scrolls through table, reads columns, sorts by date
|
|
82
|
+
|- Thoughts: "I need to find that specific user from the support ticket."
|
|
83
|
+
|- Emotions: Focused
|
|
84
|
+
|- Pain Points: Too many columns, small text, hard to distinguish rows
|
|
85
|
+
|- Opportunities: Clear row hover states, readable font sizes, alternating cues
|
|
86
|
+
|
|
87
|
+
Stage 3: Search / Filter
|
|
88
|
+
|- Actions: Types in search bar, switches tabs to narrow down
|
|
89
|
+
|- Thoughts: "Let me filter this down to find them faster."
|
|
90
|
+
|- Emotions: Slightly impatient
|
|
91
|
+
|- Pain Points: No real-time feedback on search (static), tab labels unclear
|
|
92
|
+
|- Opportunities: Visible search input with clear placeholder, active tab styling
|
|
93
|
+
|
|
94
|
+
Stage 4: Navigate to User Detail
|
|
95
|
+
|- Actions: Clicks on a user row, navigates to detail page
|
|
96
|
+
|- Thoughts: "I need to see their full profile."
|
|
97
|
+
|- Emotions: Purposeful
|
|
98
|
+
|- Pain Points: Unclear that rows are clickable, no loading indicator
|
|
99
|
+
|- Opportunities: Row hover cursor change, smooth page transition
|
|
100
|
+
|
|
101
|
+
Stage 5: Review and Edit
|
|
102
|
+
|- Actions: Reviews profile fields, changes dropdown values, toggles settings
|
|
103
|
+
|- Thoughts: "I need to update their region and save."
|
|
104
|
+
|- Emotions: Careful, attentive
|
|
105
|
+
|- Pain Points: Too many fields at once, unclear which fields are editable
|
|
106
|
+
|- Opportunities: Clear input/select styling, organized field grouping, prominent save button
|
|
107
|
+
|
|
108
|
+
Stage 6: Save and Return
|
|
109
|
+
|- Actions: Clicks "Save Changes", returns to list
|
|
110
|
+
|- Thoughts: "Done. Next user."
|
|
111
|
+
|- Emotions: Satisfied (if smooth), frustrated (if unclear)
|
|
112
|
+
|- Pain Points: No save confirmation, unclear navigation back
|
|
113
|
+
|- Opportunities: Visual save feedback, sidebar navigation always available
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 1.4 Competitive Analysis
|
|
117
|
+
|
|
118
|
+
| Competitor | Strengths | Weaknesses | Opportunity |
|
|
119
|
+
|------------|-----------|------------|-------------|
|
|
120
|
+
| Django Admin | Familiar patterns, auto-generated from models | Dated UI, minimal customization, dense layout | Modern visual design with same data density |
|
|
121
|
+
| Retool | Flexible layout builder, good component library | Complex setup, generic appearance | Purpose-built UI with branded identity |
|
|
122
|
+
| AdminJS | Node.js native, good React integration | Limited design control, sparse documentation | Full design control with shadcn/ui components |
|
|
123
|
+
| Forest Admin | Clean table views, good filtering | Expensive, opinionated layout | Custom teal brand with similar clean aesthetic |
|
|
124
|
+
| Strapi Admin | Good content management UI, plugin ecosystem | Content-focused (not user management), heavy | Lightweight, focused user management interface |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 2. Information Architecture
|
|
129
|
+
|
|
130
|
+
### 2.1 Sitemap
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
Potenlab Admin
|
|
134
|
+
|-- / (User Management List - Dashboard)
|
|
135
|
+
| |-- Card Container
|
|
136
|
+
| | |-- Header (Title + Badge + Subtitle + Write Button)
|
|
137
|
+
| | |-- Divider
|
|
138
|
+
| | |-- Tab Navigation (All, Tab, Tab)
|
|
139
|
+
| | |-- Search Bar
|
|
140
|
+
| | |-- Pagination Controls
|
|
141
|
+
| | |-- Data Table (User rows)
|
|
142
|
+
|
|
|
143
|
+
|-- /users/[id] (User Detail)
|
|
144
|
+
| |-- Card Container
|
|
145
|
+
| | |-- Header (Title + Subtitle + Save Changes Button)
|
|
146
|
+
| | |-- Divider
|
|
147
|
+
| | |-- Section: Basic Info
|
|
148
|
+
| | | |-- Profile Images (3x)
|
|
149
|
+
| | | |-- One-Line Intro (text input)
|
|
150
|
+
| | | |-- Row 1: Role, Nickname, Phone, Age
|
|
151
|
+
| | | |-- Row 2: Gender, Exercise Style, Gym Relocation, Region
|
|
152
|
+
| | | |-- Row 3: Bench, Deadlift, Squat
|
|
153
|
+
| | |-- Divider
|
|
154
|
+
| | |-- Section: Other Settings
|
|
155
|
+
| | |-- Toggle: Profile Public
|
|
156
|
+
| | |-- Toggle: Match & Chat Notification
|
|
157
|
+
| | |-- Toggle: Marketing Notification
|
|
158
|
+
|
|
|
159
|
+
|-- Sidebar (Persistent, all pages)
|
|
160
|
+
|-- Header: "ADMIN" + admin user ID
|
|
161
|
+
|-- Nav: Home
|
|
162
|
+
|-- Nav: User (accordion)
|
|
163
|
+
| |-- User Management (active)
|
|
164
|
+
|-- Nav: Match (accordion)
|
|
165
|
+
| |-- Match Management
|
|
166
|
+
|-- Nav: Admin (accordion)
|
|
167
|
+
| |-- Notice Management
|
|
168
|
+
| |-- Report Management
|
|
169
|
+
| |-- Terms Management
|
|
170
|
+
|-- Footer: Logout
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 2.2 Navigation Structure
|
|
174
|
+
|
|
175
|
+
**Primary Navigation (Sidebar -- persistent):**
|
|
176
|
+
|
|
177
|
+
| Item | Priority | Icon (Lucide) | Target | Accordion |
|
|
178
|
+
|------|----------|---------------|--------|-----------|
|
|
179
|
+
| Home | High | `Home` | / | No |
|
|
180
|
+
| User | High | `Users` | -- | Yes (parent) |
|
|
181
|
+
| -- User Management | High | (dot/indicator) | / | Sub-item |
|
|
182
|
+
| Match | Medium | `Gamepad2` | -- | Yes (parent) |
|
|
183
|
+
| -- Match Management | Medium | (dot/indicator) | /matches | Sub-item |
|
|
184
|
+
| Admin | Medium | `Shield` | -- | Yes (parent) |
|
|
185
|
+
| -- Notice Management | Low | (dot/indicator) | /notices | Sub-item |
|
|
186
|
+
| -- Report Management | Low | (dot/indicator) | /reports | Sub-item |
|
|
187
|
+
| -- Terms Management | Low | (dot/indicator) | /terms | Sub-item |
|
|
188
|
+
|
|
189
|
+
**Footer Navigation:**
|
|
190
|
+
|
|
191
|
+
| Item | Icon (Lucide) | Action |
|
|
192
|
+
|------|---------------|--------|
|
|
193
|
+
| Logout | `LogOut` | Trigger logout (UI only) |
|
|
194
|
+
|
|
195
|
+
**In-Page Navigation:**
|
|
196
|
+
|
|
197
|
+
| Element | Location | Behavior |
|
|
198
|
+
|---------|----------|----------|
|
|
199
|
+
| Tab bar | Dashboard card | Switches tab state (All / Tab / Tab) |
|
|
200
|
+
| Pagination | Dashboard card | Navigates table pages |
|
|
201
|
+
| User row click | Dashboard table | Navigates to /users/[id] |
|
|
202
|
+
| Back (sidebar) | User Detail | Click "User Management" in sidebar to return |
|
|
203
|
+
|
|
204
|
+
### 2.3 Content Hierarchy
|
|
205
|
+
|
|
206
|
+
| Page | Primary Content | Secondary Content | Tertiary |
|
|
207
|
+
|------|----------------|-------------------|----------|
|
|
208
|
+
| Dashboard | Data Table (user rows) | Header (title, badge, subtitle) | Tabs, Search, Pagination |
|
|
209
|
+
| User Detail | Form Fields (basic info) | Toggle Settings (other settings) | Header, Profile Images |
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 3. User Flows
|
|
214
|
+
|
|
215
|
+
### 3.1 Core Flow: View User List
|
|
216
|
+
|
|
217
|
+
**Goal:** Admin views the paginated list of all users
|
|
218
|
+
**Entry Point:** Application root `/`
|
|
219
|
+
**Success Criteria:** Table renders with 5 mock data rows, pagination visible
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
[Admin opens app]
|
|
223
|
+
|
|
|
224
|
+
v
|
|
225
|
+
[Sidebar loads + Dashboard page renders]
|
|
226
|
+
|
|
|
227
|
+
v
|
|
228
|
+
[Header displays: "User Management" + badge "100,000" + subtitle]
|
|
229
|
+
|
|
|
230
|
+
v
|
|
231
|
+
[Tabs default to "All" (active state)]
|
|
232
|
+
|
|
|
233
|
+
v
|
|
234
|
+
[Search bar visible with placeholder]
|
|
235
|
+
|
|
|
236
|
+
v
|
|
237
|
+
[Pagination controls render: << < 1/1 > >> + page jump + items per page]
|
|
238
|
+
|
|
|
239
|
+
v
|
|
240
|
+
[Data table renders 5 rows of mock data]
|
|
241
|
+
|
|
|
242
|
+
v
|
|
243
|
+
[SUCCESS: Admin can see the user list]
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Edge Cases:**
|
|
247
|
+
- Empty table state: Display "No users found" message centered in table body
|
|
248
|
+
- Single page: Pagination buttons visually present but disabled (muted state)
|
|
249
|
+
|
|
250
|
+
### 3.2 Core Flow: Navigate to User Detail
|
|
251
|
+
|
|
252
|
+
**Goal:** Admin clicks a user row and views their detail page
|
|
253
|
+
**Entry Point:** Dashboard table row
|
|
254
|
+
**Success Criteria:** User detail page loads with pre-filled form fields
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
[Admin is on Dashboard]
|
|
258
|
+
|
|
|
259
|
+
v
|
|
260
|
+
[Hovers over table row]
|
|
261
|
+
|
|
|
262
|
+
v
|
|
263
|
+
[Row highlights with hover state (cursor: pointer)]
|
|
264
|
+
|
|
|
265
|
+
v
|
|
266
|
+
[Admin clicks row]
|
|
267
|
+
|
|
|
268
|
+
v
|
|
269
|
+
[Next.js navigates to /users/[id]]
|
|
270
|
+
|
|
|
271
|
+
v
|
|
272
|
+
[User Detail page renders with sidebar active state updated]
|
|
273
|
+
|
|
|
274
|
+
v
|
|
275
|
+
[Form fields pre-filled with mock data]
|
|
276
|
+
|
|
|
277
|
+
v
|
|
278
|
+
[SUCCESS: Admin sees user detail]
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Edge Cases:**
|
|
282
|
+
- Click on "Delete" text in row: Should trigger delete action, NOT navigate to detail
|
|
283
|
+
- Click on avatar: Should navigate to detail (same as row click)
|
|
284
|
+
|
|
285
|
+
### 3.3 Core Flow: Edit User Detail
|
|
286
|
+
|
|
287
|
+
**Goal:** Admin modifies user fields and clicks Save
|
|
288
|
+
**Entry Point:** User Detail page `/users/[id]`
|
|
289
|
+
**Success Criteria:** Fields are editable, Save button is visible and clickable
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
[Admin is on User Detail page]
|
|
293
|
+
|
|
|
294
|
+
v
|
|
295
|
+
[Reviews Basic Info section]
|
|
296
|
+
|
|
|
297
|
+
v
|
|
298
|
+
[Clicks on a text input field]
|
|
299
|
+
|
|
|
300
|
+
v
|
|
301
|
+
[Field receives focus (border changes to primary color)]
|
|
302
|
+
|
|
|
303
|
+
v
|
|
304
|
+
[Admin types new value]
|
|
305
|
+
|
|
|
306
|
+
v
|
|
307
|
+
[Admin clicks dropdown (e.g., Role)]
|
|
308
|
+
|
|
|
309
|
+
v
|
|
310
|
+
[Select menu opens with options]
|
|
311
|
+
|
|
|
312
|
+
v
|
|
313
|
+
[Admin selects new option]
|
|
314
|
+
|
|
|
315
|
+
v
|
|
316
|
+
[Admin toggles a setting in Other Settings]
|
|
317
|
+
|
|
|
318
|
+
v
|
|
319
|
+
[Toggle animates to new state]
|
|
320
|
+
|
|
|
321
|
+
v
|
|
322
|
+
[Admin clicks "Save Changes" button]
|
|
323
|
+
|
|
|
324
|
+
v
|
|
325
|
+
[Button shows brief feedback (UI only)]
|
|
326
|
+
|
|
|
327
|
+
v
|
|
328
|
+
[SUCCESS: Admin has edited the form]
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Error States:**
|
|
332
|
+
- No validation errors needed (UI only, static data)
|
|
333
|
+
- Save button always enabled (no dirty-state tracking required)
|
|
334
|
+
|
|
335
|
+
### 3.4 Core Flow: Sidebar Navigation
|
|
336
|
+
|
|
337
|
+
**Goal:** Admin navigates between sections using sidebar
|
|
338
|
+
**Entry Point:** Any page
|
|
339
|
+
**Success Criteria:** Accordion expands, sub-menu highlights, page navigates
|
|
340
|
+
|
|
341
|
+
```
|
|
342
|
+
[Admin sees sidebar with collapsed sections]
|
|
343
|
+
|
|
|
344
|
+
v
|
|
345
|
+
[Clicks on "User" accordion header]
|
|
346
|
+
|
|
|
347
|
+
v
|
|
348
|
+
[Accordion expands, reveals "User Management" sub-item]
|
|
349
|
+
|
|
|
350
|
+
v
|
|
351
|
+
[Sub-item shows with active state (#EEF2F6 background)]
|
|
352
|
+
|
|
|
353
|
+
v
|
|
354
|
+
[Admin clicks "Match" accordion header]
|
|
355
|
+
|
|
|
356
|
+
v
|
|
357
|
+
[Match section expands, User section may remain open or collapse]
|
|
358
|
+
|
|
|
359
|
+
v
|
|
360
|
+
["Match Management" sub-item visible]
|
|
361
|
+
|
|
|
362
|
+
v
|
|
363
|
+
[Admin clicks "Logout" in footer]
|
|
364
|
+
|
|
|
365
|
+
v
|
|
366
|
+
[UI only: no action, but button provides click feedback]
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### 3.5 Core Flow: Search Users
|
|
370
|
+
|
|
371
|
+
**Goal:** Admin types a search keyword
|
|
372
|
+
**Entry Point:** Dashboard search bar
|
|
373
|
+
**Success Criteria:** Search input accepts text, placeholder disappears on focus
|
|
374
|
+
|
|
375
|
+
```
|
|
376
|
+
[Admin clicks search bar]
|
|
377
|
+
|
|
|
378
|
+
v
|
|
379
|
+
[Input receives focus, border highlights]
|
|
380
|
+
|
|
|
381
|
+
v
|
|
382
|
+
[Placeholder "Enter search keyword" disappears as user types]
|
|
383
|
+
|
|
|
384
|
+
v
|
|
385
|
+
[Admin types search term]
|
|
386
|
+
|
|
|
387
|
+
v
|
|
388
|
+
[UI only: no filtering occurs, text remains in input]
|
|
389
|
+
|
|
|
390
|
+
v
|
|
391
|
+
[SUCCESS: Search input is functional as a UI element]
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### 3.6 Core Flow: Delete User
|
|
395
|
+
|
|
396
|
+
**Goal:** Admin clicks delete on a table row
|
|
397
|
+
**Entry Point:** Dashboard table "Delete" column
|
|
398
|
+
**Success Criteria:** Delete text is clickable with hover feedback
|
|
399
|
+
|
|
400
|
+
```
|
|
401
|
+
[Admin sees "Delete" text in teal (#509594) on table row]
|
|
402
|
+
|
|
|
403
|
+
v
|
|
404
|
+
[Hovers over "Delete" text]
|
|
405
|
+
|
|
|
406
|
+
v
|
|
407
|
+
[Text shows underline or opacity change on hover]
|
|
408
|
+
|
|
|
409
|
+
v
|
|
410
|
+
[Admin clicks "Delete"]
|
|
411
|
+
|
|
|
412
|
+
v
|
|
413
|
+
[UI only: no actual deletion, click event captured]
|
|
414
|
+
|
|
|
415
|
+
v
|
|
416
|
+
[SUCCESS: Delete action is accessible]
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## 4. Design System
|
|
422
|
+
|
|
423
|
+
### 4.1 Color Palette
|
|
424
|
+
|
|
425
|
+
#### Brand Colors (from Figma Design Tokens)
|
|
426
|
+
|
|
427
|
+
| Token | Hex | RGB | Usage | WCAG on White |
|
|
428
|
+
|-------|-----|-----|-------|---------------|
|
|
429
|
+
| Primary | `#509594` | rgb(80, 149, 148) | Buttons, active tab, action text, links | 3.15:1 (use on large text / UI only) |
|
|
430
|
+
| Primary Light | `#B9D5D4` | rgb(185, 213, 212) | Pagination buttons | Decorative only |
|
|
431
|
+
| Primary Hover | `#3F7A79` | rgb(63, 122, 121) | Hover state for primary buttons | 4.87:1 (AA for large text) |
|
|
432
|
+
| Primary Active | `#357070` | rgb(53, 112, 112) | Active/pressed state for primary | 5.52:1 (AA) |
|
|
433
|
+
|
|
434
|
+
#### Neutral Colors (from Figma Design Tokens)
|
|
435
|
+
|
|
436
|
+
| Token | Hex | Usage |
|
|
437
|
+
|-------|-----|-------|
|
|
438
|
+
| Background | `#FCFCFC` | Page background |
|
|
439
|
+
| White | `#FFFFFF` | Card background, sidebar background |
|
|
440
|
+
| Gray/200 | `#E2E8F0` | Borders, table dividers, input borders |
|
|
441
|
+
| Gray/400 | `#A0AEC0` | Placeholder text, section labels |
|
|
442
|
+
| Gray/700 | `#2D3748` | Select text, dropdown values |
|
|
443
|
+
| Gray/800 | `#1A202C` | Inactive tab text |
|
|
444
|
+
| Grayscale/600 | `#9DA0A8` | Subtitle text |
|
|
445
|
+
| Grayscale/800 | `#5A5E6A` | Sidebar menu text, pagination separator |
|
|
446
|
+
| Grayscale/900 | `#3B3F4A` | Table cell text |
|
|
447
|
+
| Black | `#000000` | Headings, body text |
|
|
448
|
+
|
|
449
|
+
#### Surface Colors (from Figma Design Tokens)
|
|
450
|
+
|
|
451
|
+
| Token | Hex | Usage |
|
|
452
|
+
|-------|-----|-------|
|
|
453
|
+
| Gray/2 | `#EFF1F4` | Dividers, inactive tab background |
|
|
454
|
+
| Table Header BG | `#F9FAFC` | Table header row background |
|
|
455
|
+
| Sidebar Selected BG | `#EEF2F6` | Active sidebar sub-menu, secondary button bg |
|
|
456
|
+
|
|
457
|
+
#### Semantic Colors (from Figma Design Tokens)
|
|
458
|
+
|
|
459
|
+
| Token | Hex | Usage |
|
|
460
|
+
|-------|-----|-------|
|
|
461
|
+
| Badge Green BG | `#C6F6D5` | Count badge background |
|
|
462
|
+
| Badge Green Text | `#22543D` | Count badge text |
|
|
463
|
+
| Error | `#EF4444` | Error states (reserved, not in current Figma) |
|
|
464
|
+
| Warning | `#F59E0B` | Warning states (reserved) |
|
|
465
|
+
| Info | `#3B82F6` | Toggle ON state (blue) |
|
|
466
|
+
| Toggle OFF | `#CBD5E0` | Toggle OFF state (gray) |
|
|
467
|
+
|
|
468
|
+
#### Color Contrast Compliance Notes
|
|
469
|
+
|
|
470
|
+
| Combination | Ratio | WCAG Level | Notes |
|
|
471
|
+
|-------------|-------|------------|-------|
|
|
472
|
+
| Black (#000000) on White (#FFFFFF) | 21:1 | AAA | Headings, body text |
|
|
473
|
+
| Grayscale/900 (#3B3F4A) on White (#FFFFFF) | 9.21:1 | AAA | Table cell text |
|
|
474
|
+
| Gray/400 (#A0AEC0) on White (#FFFFFF) | 2.64:1 | Fails for small text | Use only for placeholder / non-essential text, pair with labels |
|
|
475
|
+
| Gray/800 (#1A202C) on Gray/2 (#EFF1F4) | 13.0:1 | AAA | Inactive tab text on inactive bg |
|
|
476
|
+
| White (#FFFFFF) on Primary (#509594) | 3.15:1 | AA for large text (18px+) | Button text is 18px SemiBold -- passes AA for large text |
|
|
477
|
+
| Badge Green Text (#22543D) on Badge Green BG (#C6F6D5) | 7.05:1 | AAA | Badge text |
|
|
478
|
+
| Grayscale/600 (#9DA0A8) on White (#FFFFFF) | 3.01:1 | AA for large text | Subtitle at 18px -- passes AA for large text |
|
|
479
|
+
|
|
480
|
+
**Accessibility Note on Primary Color:**
|
|
481
|
+
The primary teal `#509594` on white has a contrast ratio of approximately 3.15:1, which passes WCAG AA for **large text** (18px bold / 24px regular). Since the PRD specifies button text at 18px SemiBold, this meets the AA threshold. For any small text usage of primary color, consider using the darker `#3F7A79` variant (4.87:1) or `#357070` (5.52:1) to ensure compliance.
|
|
482
|
+
|
|
483
|
+
### 4.2 Typography
|
|
484
|
+
|
|
485
|
+
#### Font Families
|
|
486
|
+
|
|
487
|
+
```css
|
|
488
|
+
/* Primary -- UI headings, labels, body */
|
|
489
|
+
--font-primary: 'Pretendard Variable', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
490
|
+
|
|
491
|
+
/* Secondary -- Inputs, buttons, sidebar menu, badges */
|
|
492
|
+
--font-secondary: 'Inter', 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
493
|
+
|
|
494
|
+
/* Monospace -- Code blocks if needed */
|
|
495
|
+
--font-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', Consolas, monospace;
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
#### Type Scale (from Figma Design Tokens)
|
|
499
|
+
|
|
500
|
+
| Style | Font Family | Size | Weight | Line Height | Letter Spacing | Usage |
|
|
501
|
+
|-------|-------------|------|--------|-------------|----------------|-------|
|
|
502
|
+
| Page Title | Pretendard Variable | 32px / 2rem | SemiBold (600) | 1.25 (40px) | -0.02em | Page headings ("User Management") |
|
|
503
|
+
| Section Label | Pretendard Variable | 20px / 1.25rem | Bold (700) | 1.3 (26px) | 0 | Section titles ("Basic Info") |
|
|
504
|
+
| Field Label | Pretendard Variable | 20px / 1.25rem | SemiBold (600) | 1.3 (26px) | 0 | Form field labels |
|
|
505
|
+
| Subtitle | Pretendard Variable | 18px / 1.125rem | Medium (500) | 1.4 (25.2px) | 0 | Page subtitles |
|
|
506
|
+
| Body | Pretendard Variable | 14px / 0.875rem | Regular (400) | 1.5 (21px) | 0 | Table cell text, general body |
|
|
507
|
+
| Sidebar Title | Pretendard Variable | 24px / 1.5rem | SemiBold (600) | 1.25 (30px) | 0.05em | "ADMIN" title |
|
|
508
|
+
| Sidebar Menu | Inter / Noto Sans KR | 16px / 1rem | Regular (400) | 1.5 (24px) | 0 | Navigation menu items |
|
|
509
|
+
| Button Text | Inter | 18px / 1.125rem | SemiBold (600) | 1 (18px) | 0 | Button labels |
|
|
510
|
+
| Input Text | Inter / Noto Sans KR | 18px / 1.125rem | Regular (400) | 1.4 (25.2px) | 0 | Form input values |
|
|
511
|
+
| Badge | Inter | 18px / 1.125rem | Bold (700) | 1 (18px) | 0 | Count badges |
|
|
512
|
+
| Pagination Current | (inherit) | 20px / 1.25rem | Bold (700) | 1.25 | 0 | Current page number |
|
|
513
|
+
| Pagination Total | (inherit) | 16px / 1rem | Regular (400) | 1.25 | 0 | Total page, separator |
|
|
514
|
+
|
|
515
|
+
#### Font Loading Strategy
|
|
516
|
+
|
|
517
|
+
```html
|
|
518
|
+
<!-- Pretendard Variable from CDN -->
|
|
519
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/variable/pretendardvariable.css" />
|
|
520
|
+
|
|
521
|
+
<!-- Inter from Google Fonts (or Next.js font optimization) -->
|
|
522
|
+
<!-- Use next/font/google for Inter to leverage automatic optimization -->
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
```typescript
|
|
526
|
+
// app/layout.tsx
|
|
527
|
+
import { Inter } from 'next/font/google';
|
|
528
|
+
|
|
529
|
+
const inter = Inter({
|
|
530
|
+
subsets: ['latin'],
|
|
531
|
+
variable: '--font-inter',
|
|
532
|
+
display: 'swap',
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// Pretendard loaded via CSS @font-face or CDN link
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### 4.3 Spacing System
|
|
539
|
+
|
|
540
|
+
Base unit: **4px**. All spacing values are multiples of 4px as specified in the Figma design.
|
|
541
|
+
|
|
542
|
+
```css
|
|
543
|
+
--space-0: 0px; /* None */
|
|
544
|
+
--space-1: 4px; /* Tight inline elements */
|
|
545
|
+
--space-2: 8px; /* Compact gaps (icon + text) */
|
|
546
|
+
--space-3: 12px; /* Cozy (related items) */
|
|
547
|
+
--space-4: 16px; /* Default (tab padding horizontal, input padding) */
|
|
548
|
+
--space-5: 20px; /* Content area top padding */
|
|
549
|
+
--space-6: 24px; /* Form field gaps between columns */
|
|
550
|
+
--space-8: 32px; /* Card padding, section gaps */
|
|
551
|
+
--space-10: 40px; /* Button height (pagination, primary) */
|
|
552
|
+
--space-12: 48px; /* Input height (search, page jump), section spacing */
|
|
553
|
+
--space-13: 52px; /* Tab height, detail input height */
|
|
554
|
+
--space-14: 56px; /* Table header row height */
|
|
555
|
+
--space-15: 60px; /* Table body row height */
|
|
556
|
+
--space-16: 64px; /* Large vertical spacing */
|
|
557
|
+
--space-25: 100px; /* Toggle settings gap */
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
#### Layout-Specific Spacing
|
|
561
|
+
|
|
562
|
+
| Element | Property | Value |
|
|
563
|
+
|---------|----------|-------|
|
|
564
|
+
| Sidebar | Width | 300px |
|
|
565
|
+
| Content area | Left offset | 324px (300px sidebar + 24px gap) |
|
|
566
|
+
| Content area | Top padding | 20px |
|
|
567
|
+
| Card | Padding | 32px |
|
|
568
|
+
| Card | Border radius | 8px |
|
|
569
|
+
| Form field gap | Column gap | 24px |
|
|
570
|
+
| Form field gap | Row gap | 24px |
|
|
571
|
+
| Tab | Height | 52px |
|
|
572
|
+
| Tab | Horizontal padding | 16px |
|
|
573
|
+
| Tab | Border radius | 6px |
|
|
574
|
+
| Search input | Height | 48px |
|
|
575
|
+
| Search input | Border radius | 6px |
|
|
576
|
+
| Primary button | Height | 40px |
|
|
577
|
+
| Primary button | Border radius | 8px |
|
|
578
|
+
| Pagination button | Height | 40px |
|
|
579
|
+
| Pagination button | Border radius | 6px |
|
|
580
|
+
| Table header row | Height | 56px |
|
|
581
|
+
| Table body row | Height | 60px |
|
|
582
|
+
| Detail input | Height | 52px |
|
|
583
|
+
| Detail input | Border radius | 6px |
|
|
584
|
+
| Detail input | Horizontal padding | 16px |
|
|
585
|
+
| Profile image | Size | 116px x 116px |
|
|
586
|
+
| Profile image | Border radius | 8px |
|
|
587
|
+
| Avatar (table) | Size | 22px (circular) |
|
|
588
|
+
| Toggle switch | Size | 44px x 24px |
|
|
589
|
+
|
|
590
|
+
### 4.4 Border Radius
|
|
591
|
+
|
|
592
|
+
```css
|
|
593
|
+
--radius-sm: 4px; /* Small UI elements */
|
|
594
|
+
--radius-md: 6px; /* Inputs, tabs, pagination buttons, selects */
|
|
595
|
+
--radius-lg: 8px; /* Cards, primary buttons, profile images */
|
|
596
|
+
--radius-xl: 12px; /* Modals (if needed) */
|
|
597
|
+
--radius-full: 9999px; /* Avatars, pills, toggle switches */
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### 4.5 Borders
|
|
601
|
+
|
|
602
|
+
```css
|
|
603
|
+
--border-default: 1px solid #E2E8F0; /* Card borders, input borders, table borders */
|
|
604
|
+
--border-divider: 1px solid #EFF1F4; /* Section dividers within cards */
|
|
605
|
+
--border-table: 1px solid #E2E8F0; /* Table container border, row separators */
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### 4.6 Shadows
|
|
609
|
+
|
|
610
|
+
The Figma design uses a flat/minimal shadow approach. Shadows are subtle or absent.
|
|
611
|
+
|
|
612
|
+
```css
|
|
613
|
+
--shadow-none: none; /* Default for cards (border-defined) */
|
|
614
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); /* Subtle lift (optional hover) */
|
|
615
|
+
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07); /* Dropdown menus */
|
|
616
|
+
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1); /* Modals/overlays */
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### 4.7 CSS Custom Properties (globals.css)
|
|
620
|
+
|
|
621
|
+
```css
|
|
622
|
+
@layer base {
|
|
623
|
+
:root {
|
|
624
|
+
/* Brand Colors */
|
|
625
|
+
--primary: 80 149 148; /* #509594 */
|
|
626
|
+
--primary-foreground: 255 255 255; /* #FFFFFF */
|
|
627
|
+
--primary-light: 185 213 212; /* #B9D5D4 */
|
|
628
|
+
|
|
629
|
+
/* Backgrounds */
|
|
630
|
+
--background: 252 252 252; /* #FCFCFC */
|
|
631
|
+
--card: 255 255 255; /* #FFFFFF */
|
|
632
|
+
--sidebar: 255 255 255; /* #FFFFFF */
|
|
633
|
+
|
|
634
|
+
/* Borders */
|
|
635
|
+
--border: 226 232 240; /* #E2E8F0 */
|
|
636
|
+
--divider: 239 241 244; /* #EFF1F4 */
|
|
637
|
+
|
|
638
|
+
/* Text */
|
|
639
|
+
--foreground: 0 0 0; /* #000000 */
|
|
640
|
+
--muted-foreground: 90 94 106; /* #5A5E6A */
|
|
641
|
+
--placeholder: 160 174 192; /* #A0AEC0 */
|
|
642
|
+
--table-cell: 59 63 74; /* #3B3F4A */
|
|
643
|
+
--section-label: 160 174 192; /* #A0AEC0 */
|
|
644
|
+
--subtitle: 157 160 168; /* #9DA0A8 */
|
|
645
|
+
|
|
646
|
+
/* Surfaces */
|
|
647
|
+
--muted: 238 242 246; /* #EEF2F6 */
|
|
648
|
+
--table-header: 249 250 252; /* #F9FAFC */
|
|
649
|
+
--inactive-tab: 239 241 244; /* #EFF1F4 */
|
|
650
|
+
|
|
651
|
+
/* Semantic */
|
|
652
|
+
--badge-green-bg: 198 246 213; /* #C6F6D5 */
|
|
653
|
+
--badge-green-text: 34 84 61; /* #22543D */
|
|
654
|
+
--info: 59 130 246; /* #3B82F6 (toggle ON) */
|
|
655
|
+
--toggle-off: 203 213 224; /* #CBD5E0 */
|
|
656
|
+
|
|
657
|
+
/* Accent */
|
|
658
|
+
--accent: 185 213 212; /* #B9D5D4 */
|
|
659
|
+
--accent-foreground: 0 0 0; /* #000000 */
|
|
660
|
+
|
|
661
|
+
/* Radius */
|
|
662
|
+
--radius: 8px;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
---
|
|
668
|
+
|
|
669
|
+
## 5. Component Library
|
|
670
|
+
|
|
671
|
+
### 5.1 Buttons
|
|
672
|
+
|
|
673
|
+
#### Variants (shadcn/ui `Button` overrides)
|
|
674
|
+
|
|
675
|
+
| Variant | Background | Text Color | Border | Height | Radius | Font | Usage |
|
|
676
|
+
|---------|------------|------------|--------|--------|--------|------|-------|
|
|
677
|
+
| `primary` | `#509594` | `#FFFFFF` | none | 40px | 8px | Inter 18px SemiBold | "Write", "Save Changes" |
|
|
678
|
+
| `primary` (hover) | `#3F7A79` | `#FFFFFF` | none | 40px | 8px | -- | Hover state |
|
|
679
|
+
| `primary` (active) | `#357070` | `#FFFFFF` | none | 40px | 8px | -- | Pressed state |
|
|
680
|
+
| `primary` (disabled) | `#509594` @ 50% opacity | `#FFFFFF` | none | 40px | 8px | -- | Disabled state |
|
|
681
|
+
| `secondary` | `#EEF2F6` | `#000000` | none | 48px | 6px | Inter 18px SemiBold | "Go" button |
|
|
682
|
+
| `pagination` | `#B9D5D4` | `#509594` | none | 40px | 6px | -- | `<<` `<` `>` `>>` |
|
|
683
|
+
| `pagination` (hover) | `#A0C4C3` | `#3F7A79` | none | 40px | 6px | -- | Hover state |
|
|
684
|
+
| `pagination` (disabled) | `#B9D5D4` @ 50% opacity | `#509594` @ 50% | none | 40px | 6px | -- | Disabled (no more pages) |
|
|
685
|
+
| `ghost` | transparent | `#509594` | none | auto | 0 | Body 14px | "Delete" action in table |
|
|
686
|
+
| `ghost` (hover) | transparent | `#3F7A79` | none | auto | 0 | underline | Hover state |
|
|
687
|
+
| `outline` | transparent | `#000000` | 1px `#E2E8F0` | 40px | 6px | -- | Reserved |
|
|
688
|
+
|
|
689
|
+
**Button Icon Placement:**
|
|
690
|
+
- "Write" button: `Pencil` icon left of text, 8px gap
|
|
691
|
+
- "Save Changes" button: `Pencil` icon left of text, 8px gap
|
|
692
|
+
- Pagination buttons: Icon only (no text), centered
|
|
693
|
+
|
|
694
|
+
**Accessibility:**
|
|
695
|
+
- Minimum touch/click target: 40px x 40px (met by all button heights)
|
|
696
|
+
- Focus ring: 2px offset, `#509594` color, `outline-offset: 2px`
|
|
697
|
+
- Disabled state: `opacity: 0.5`, `cursor: not-allowed`, `pointer-events: none`
|
|
698
|
+
- All icon-only buttons must have `aria-label` (e.g., "Go to first page", "Previous page")
|
|
699
|
+
|
|
700
|
+
### 5.2 Form Elements
|
|
701
|
+
|
|
702
|
+
#### Text Input (shadcn/ui `Input` overrides)
|
|
703
|
+
|
|
704
|
+
| State | Border | Background | Text Color | Placeholder Color |
|
|
705
|
+
|-------|--------|------------|------------|-------------------|
|
|
706
|
+
| Default | 1px `#E2E8F0` | `#FFFFFF` | `#000000` | `#A0AEC0` |
|
|
707
|
+
| Hover | 1px `#CBD5E0` | `#FFFFFF` | `#000000` | `#A0AEC0` |
|
|
708
|
+
| Focus | 1px `#509594` | `#FFFFFF` | `#000000` | -- |
|
|
709
|
+
| Disabled | 1px `#E2E8F0` | `#F9FAFC` | `#A0AEC0` | `#A0AEC0` |
|
|
710
|
+
|
|
711
|
+
**Specifications:**
|
|
712
|
+
- Dashboard search: 48px height, 6px radius, full width
|
|
713
|
+
- Detail form inputs: 52px height, 6px radius, 16px horizontal padding
|
|
714
|
+
- Font: Inter Regular 18px
|
|
715
|
+
- Focus ring: 2px `#509594` ring with 2px offset (or replace border color)
|
|
716
|
+
|
|
717
|
+
#### Select / Dropdown (shadcn/ui `Select` overrides)
|
|
718
|
+
|
|
719
|
+
| State | Border | Background | Text Color | Chevron |
|
|
720
|
+
|-------|--------|------------|------------|---------|
|
|
721
|
+
| Default | 1px `#E2E8F0` | `#FFFFFF` | `#2D3748` | `ChevronDown` `#A0AEC0` |
|
|
722
|
+
| Hover | 1px `#CBD5E0` | `#FFFFFF` | `#2D3748` | `ChevronDown` `#2D3748` |
|
|
723
|
+
| Focus/Open | 1px `#509594` | `#FFFFFF` | `#2D3748` | `ChevronUp` `#509594` |
|
|
724
|
+
| Disabled | 1px `#E2E8F0` | `#F9FAFC` | `#A0AEC0` | `ChevronDown` `#CBD5E0` |
|
|
725
|
+
|
|
726
|
+
**Specifications:**
|
|
727
|
+
- Detail form selects: 52px height, 6px radius
|
|
728
|
+
- Items per page dropdown (dashboard): 48px height, 96px width
|
|
729
|
+
- Right padding: 48px (space for chevron icon area)
|
|
730
|
+
- Dropdown menu: white bg, `#E2E8F0` border, 6px radius, `shadow-md`
|
|
731
|
+
- Dropdown item hover: `#EEF2F6` background
|
|
732
|
+
|
|
733
|
+
#### Switch / Toggle (shadcn/ui `Switch` overrides)
|
|
734
|
+
|
|
735
|
+
| State | Track BG | Thumb | Thumb Position |
|
|
736
|
+
|-------|----------|-------|----------------|
|
|
737
|
+
| OFF | `#CBD5E0` | `#FFFFFF` | Left |
|
|
738
|
+
| OFF (hover) | `#B0BEC5` | `#FFFFFF` | Left |
|
|
739
|
+
| ON | `#3B82F6` (blue) | `#FFFFFF` | Right |
|
|
740
|
+
| ON (hover) | `#2563EB` | `#FFFFFF` | Right |
|
|
741
|
+
| Disabled OFF | `#CBD5E0` @ 50% | `#FFFFFF` | Left |
|
|
742
|
+
| Disabled ON | `#3B82F6` @ 50% | `#FFFFFF` | Right |
|
|
743
|
+
|
|
744
|
+
**Specifications:**
|
|
745
|
+
- Track size: 44px x 24px
|
|
746
|
+
- Thumb size: 20px (with 2px inset from track edge)
|
|
747
|
+
- Transition: 200ms ease-in-out for thumb slide
|
|
748
|
+
- Label: Text to the left of toggle, 16px Regular
|
|
749
|
+
|
|
750
|
+
### 5.3 Card (shadcn/ui `Card` overrides)
|
|
751
|
+
|
|
752
|
+
| Property | Value |
|
|
753
|
+
|----------|-------|
|
|
754
|
+
| Background | `#FFFFFF` |
|
|
755
|
+
| Border | 1px `#E2E8F0` |
|
|
756
|
+
| Border radius | 8px |
|
|
757
|
+
| Padding | 32px |
|
|
758
|
+
| Shadow | none (border-defined containers) |
|
|
759
|
+
|
|
760
|
+
**Usage:** Main content container on both Dashboard and User Detail pages.
|
|
761
|
+
|
|
762
|
+
### 5.4 Table (shadcn/ui `Table` overrides)
|
|
763
|
+
|
|
764
|
+
#### Table Container
|
|
765
|
+
- Background: `#FFFFFF`
|
|
766
|
+
- Border: 1px `#E2E8F0`
|
|
767
|
+
- Border radius: 0px (square corners per Figma)
|
|
768
|
+
- Overflow: hidden
|
|
769
|
+
|
|
770
|
+
#### Table Header (`TableHeader`)
|
|
771
|
+
- Background: `#F9FAFC`
|
|
772
|
+
- Row height: 56px
|
|
773
|
+
- Text: 14px, SemiBold (600), `#3B3F4A`
|
|
774
|
+
- Vertical alignment: center
|
|
775
|
+
- Bottom border: 1px `#E2E8F0`
|
|
776
|
+
|
|
777
|
+
#### Table Row (`TableRow`)
|
|
778
|
+
- Row height: 60px
|
|
779
|
+
- Text: 14px, Regular (400), `#3B3F4A`
|
|
780
|
+
- Bottom border: 1px `#E2E8F0`
|
|
781
|
+
- Hover state: `#F9FAFC` background, `cursor: pointer`
|
|
782
|
+
- Vertical alignment: center
|
|
783
|
+
|
|
784
|
+
#### Table Cell (`TableCell`)
|
|
785
|
+
- Padding: 0 16px
|
|
786
|
+
- Vertical alignment: center
|
|
787
|
+
|
|
788
|
+
#### Column Specifications
|
|
789
|
+
|
|
790
|
+
| Column | Width | Content | Special |
|
|
791
|
+
|--------|-------|---------|---------|
|
|
792
|
+
| Nickname | flex-1 | Text | -- |
|
|
793
|
+
| Grade | flex-1 | Text | -- |
|
|
794
|
+
| Avatar | 80px fixed | 22px circular image centered | `Avatar` component |
|
|
795
|
+
| Phone Number | flex-1 | Text | -- |
|
|
796
|
+
| Age | flex-1 | Text | -- |
|
|
797
|
+
| Gender | flex-1 | Text | -- |
|
|
798
|
+
| Region | flex-1 | Text | -- |
|
|
799
|
+
| Join Date | flex-1 | Text + sort icon | `ChevronDown`/`ChevronUp` icon |
|
|
800
|
+
| Withdrawal Date | flex-1 | Text + sort icon | `ChevronDown`/`ChevronUp` icon |
|
|
801
|
+
| Delete | 57px fixed | Teal text link | `ghost` button, `#509594` |
|
|
802
|
+
|
|
803
|
+
### 5.5 Badge (shadcn/ui `Badge` overrides)
|
|
804
|
+
|
|
805
|
+
#### Green Count Badge
|
|
806
|
+
- Background: `#C6F6D5`
|
|
807
|
+
- Text: `#22543D`, Inter Bold 18px
|
|
808
|
+
- Padding: 4px 12px
|
|
809
|
+
- Border radius: 9999px (pill)
|
|
810
|
+
- Content: Formatted number (e.g., "100,000")
|
|
811
|
+
|
|
812
|
+
### 5.6 Tabs (shadcn/ui `Tabs` overrides)
|
|
813
|
+
|
|
814
|
+
| State | Background | Text Color | Font | Border Radius |
|
|
815
|
+
|-------|------------|------------|------|---------------|
|
|
816
|
+
| Active | `#509594` | `#FFFFFF` | Pretendard SemiBold | 6px |
|
|
817
|
+
| Inactive | `#EEF2F6` | `#1A202C` | Pretendard Medium | 6px |
|
|
818
|
+
| Hover (inactive) | `#E2E8F0` | `#1A202C` | Pretendard Medium | 6px |
|
|
819
|
+
|
|
820
|
+
**Specifications:**
|
|
821
|
+
- Tab height: 52px
|
|
822
|
+
- Horizontal padding: 16px
|
|
823
|
+
- Gap between tabs: 8px
|
|
824
|
+
- Tab list: no bottom border (custom styled, not underline variant)
|
|
825
|
+
|
|
826
|
+
### 5.7 Pagination Controls
|
|
827
|
+
|
|
828
|
+
**Left Group:**
|
|
829
|
+
- Navigation buttons: `<<` (ChevronsLeft), `<` (ChevronLeft), `>` (ChevronRight), `>>` (ChevronsRight)
|
|
830
|
+
- Button style: `pagination` variant (40px square, `#B9D5D4` bg, 6px radius)
|
|
831
|
+
- Page indicator between `<` and `>`: "1 / 1"
|
|
832
|
+
- Current page: 20px Bold
|
|
833
|
+
- Separator "/": 16px Regular `#5A5E6A`
|
|
834
|
+
- Total pages: 16px Regular `#5A5E6A`
|
|
835
|
+
|
|
836
|
+
**Right Group:**
|
|
837
|
+
- Page jump input: 100px width, 48px height, placeholder "Page", 6px radius
|
|
838
|
+
- "Go" button: `secondary` variant, 48px height
|
|
839
|
+
- Items per page: `Select` dropdown, 96px width, 48px height, "10 items" default
|
|
840
|
+
|
|
841
|
+
### 5.8 Sidebar (shadcn/ui `Sidebar` + `Accordion` overrides)
|
|
842
|
+
|
|
843
|
+
#### Sidebar Container
|
|
844
|
+
- Width: 300px
|
|
845
|
+
- Height: 100vh (fixed)
|
|
846
|
+
- Position: fixed left
|
|
847
|
+
- Background: `#FFFFFF`
|
|
848
|
+
- Border right: 1px `#E2E8F0`
|
|
849
|
+
- Padding: 24px
|
|
850
|
+
|
|
851
|
+
#### Sidebar Header
|
|
852
|
+
- Title: "ADMIN" -- Pretendard 24px SemiBold, letter-spacing 0.05em
|
|
853
|
+
- Subtitle: Admin user ID -- 14px Regular `#9DA0A8`
|
|
854
|
+
- Bottom spacing: 32px
|
|
855
|
+
|
|
856
|
+
#### Sidebar Navigation (Accordion)
|
|
857
|
+
- Menu item height: 48px
|
|
858
|
+
- Menu item text: Inter/Noto Sans KR 16px Regular `#5A5E6A`
|
|
859
|
+
- Menu item icon: 20px Lucide icon, `#5A5E6A`
|
|
860
|
+
- Menu item hover: `#F9FAFC` background
|
|
861
|
+
- Accordion trigger: Chevron icon on right side, rotates 180deg on expand
|
|
862
|
+
- Sub-menu item: Indented 40px from left
|
|
863
|
+
- Sub-menu active state: `#EEF2F6` background, `#509594` text, left border or dot indicator
|
|
864
|
+
- Sub-menu item height: 44px
|
|
865
|
+
|
|
866
|
+
#### Sidebar Footer
|
|
867
|
+
- Border top: 1px `#E2E8F0`
|
|
868
|
+
- Padding top: 16px
|
|
869
|
+
- Logout button: `LogOut` icon + "Logout" text, centered, 16px Regular `#5A5E6A`
|
|
870
|
+
- Logout hover: `#EF4444` text color (red hint for destructive action)
|
|
871
|
+
|
|
872
|
+
### 5.9 Separator (shadcn/ui `Separator` overrides)
|
|
873
|
+
|
|
874
|
+
- Color: `#EFF1F4`
|
|
875
|
+
- Height: 1px
|
|
876
|
+
- Full width of parent container
|
|
877
|
+
- Margin: 24px vertical (between header and content sections)
|
|
878
|
+
|
|
879
|
+
### 5.10 Avatar (shadcn/ui `Avatar` overrides)
|
|
880
|
+
|
|
881
|
+
- Table avatar: 22px x 22px, circular (`border-radius: 9999px`)
|
|
882
|
+
- Fallback: First letter of nickname, `#EEF2F6` bg, `#5A5E6A` text
|
|
883
|
+
- Profile images (detail page): 116px x 116px, 8px border radius (NOT circular)
|
|
884
|
+
|
|
885
|
+
### 5.11 Label (shadcn/ui `Label` overrides)
|
|
886
|
+
|
|
887
|
+
- Field labels: Pretendard 20px SemiBold `#101010`
|
|
888
|
+
- Margin bottom: 8px (below label, above input)
|
|
889
|
+
|
|
890
|
+
### 5.12 Tooltip (shadcn/ui `Tooltip`)
|
|
891
|
+
|
|
892
|
+
- Background: `#1A202C`
|
|
893
|
+
- Text: `#FFFFFF`, 14px Regular
|
|
894
|
+
- Padding: 8px 12px
|
|
895
|
+
- Border radius: 6px
|
|
896
|
+
- Arrow: included
|
|
897
|
+
- Delay: 300ms show, 100ms hide
|
|
898
|
+
- Usage: Icon-only buttons (pagination), optional hover hints
|
|
899
|
+
|
|
900
|
+
---
|
|
901
|
+
|
|
902
|
+
## 6. Page Layouts
|
|
903
|
+
|
|
904
|
+
### 6.1 Global Layout Structure
|
|
905
|
+
|
|
906
|
+
```
|
|
907
|
+
+------------------------------------------------------------------+
|
|
908
|
+
| Browser Viewport (1920px) |
|
|
909
|
+
+----------+-------------------------------------------------------+
|
|
910
|
+
| | |
|
|
911
|
+
| Sidebar | Content Area |
|
|
912
|
+
| 300px | (offset 324px from left) |
|
|
913
|
+
| fixed | (padding-top: 20px) |
|
|
914
|
+
| | |
|
|
915
|
+
| +------+ | +------------------------------------------------+ |
|
|
916
|
+
| |ADMIN | | | Card Container (white, 8px radius, border) | |
|
|
917
|
+
| |admin | | | | |
|
|
918
|
+
| |ID | | | [Page-specific content] | |
|
|
919
|
+
| +------+ | | | |
|
|
920
|
+
| |Home | | | | |
|
|
921
|
+
| |User v | | | | |
|
|
922
|
+
| | User | | | | |
|
|
923
|
+
| | Mgmt | | | | |
|
|
924
|
+
| |Match v| | | | |
|
|
925
|
+
| | Match | | | | |
|
|
926
|
+
| | Mgmt | | | | |
|
|
927
|
+
| |Admin v| | | | |
|
|
928
|
+
| | Notice| | | | |
|
|
929
|
+
| | Report| | | | |
|
|
930
|
+
| | Terms | | +------------------------------------------------+ |
|
|
931
|
+
| | | | |
|
|
932
|
+
| +------+ | |
|
|
933
|
+
| |Logout | | |
|
|
934
|
+
| +------+ | |
|
|
935
|
+
+----------+-------------------------------------------------------+
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
### 6.2 Responsive Considerations
|
|
939
|
+
|
|
940
|
+
Per the PRD, the design is **desktop-only at 1920px**. No responsive breakpoints are required. However, the following minimum considerations apply:
|
|
941
|
+
|
|
942
|
+
| Breakpoint | Behavior |
|
|
943
|
+
|------------|----------|
|
|
944
|
+
| >= 1440px | Full layout as designed |
|
|
945
|
+
| 1280px - 1439px | Content area compresses, table columns may use ellipsis |
|
|
946
|
+
| < 1280px | Not supported (out of scope per PRD) |
|
|
947
|
+
|
|
948
|
+
---
|
|
949
|
+
|
|
950
|
+
## 7. Wireframes
|
|
951
|
+
|
|
952
|
+
### 7.1 User Management List (Dashboard) -- Desktop
|
|
953
|
+
|
|
954
|
+
```
|
|
955
|
+
+---------------------------+-----------------------------------------------------------+
|
|
956
|
+
| SIDEBAR (300px) | CONTENT AREA |
|
|
957
|
+
| | |
|
|
958
|
+
| +---------------------+ | +-------------------------------------------------------+|
|
|
959
|
+
| | ADMIN | | | User Management [100,000] [ Write btn ] ||
|
|
960
|
+
| | admin@potenlab.com | | | User list management page ||
|
|
961
|
+
| +---------------------+ | | ||
|
|
962
|
+
| | | | | ---------------------------------------------------- ||
|
|
963
|
+
| | Home | | | ||
|
|
964
|
+
| | | | | [All] [Tab] [Tab] ||
|
|
965
|
+
| | v User | | | ||
|
|
966
|
+
| | > User Mgmt [*] | | | +---------------------------------------------------+||
|
|
967
|
+
| | | | | | Enter search keyword (search) |||
|
|
968
|
+
| | v Match | | | +---------------------------------------------------+||
|
|
969
|
+
| | > Match Mgmt | | | ||
|
|
970
|
+
| | | | | [<<] [<] 1 / 1 [>] [>>] [Page] [Go] [10 items] ||
|
|
971
|
+
| | v Admin | | | ||
|
|
972
|
+
| | > Notice Mgmt | | | +---------------------------------------------------+||
|
|
973
|
+
| | > Report Mgmt | | | | Nick | Grade | Avt | Phone | Age | Gen | Reg | |||
|
|
974
|
+
| | > Terms Mgmt | | | | | | | | | | | |||
|
|
975
|
+
| | | | | | | | | | | | Join|Wdr |||
|
|
976
|
+
| | | | | | | | | | | | Date|Date|||
|
|
977
|
+
| | | | | | | | | | | | |Del |||
|
|
978
|
+
| | | | | |------+-------+-----+-------+-----+-----+-----+----|||
|
|
979
|
+
| | | | | | Nick | Mania | (o) | 010.. | 99 | M | Gang| |||
|
|
980
|
+
| | | | | |Here | | | 1234 | | | nam | |||
|
|
981
|
+
| | | | | | | | | 1234 | | | |Nov |||
|
|
982
|
+
| | | | | | | | | | | | |Del |||
|
|
983
|
+
| | | | | |------+-------+-----+-------+-----+-----+-----+----|||
|
|
984
|
+
| | | | | | (repeat 4 more rows...) |||
|
|
985
|
+
| | | | | +---------------------------------------------------+||
|
|
986
|
+
| +---------------------+ | +-------------------------------------------------------+|
|
|
987
|
+
| | Logout | | |
|
|
988
|
+
| +---------------------+ | |
|
|
989
|
+
+---------------------------+-----------------------------------------------------------+
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
#### Detailed Annotations -- Dashboard
|
|
993
|
+
|
|
994
|
+
**A. Header Area:**
|
|
995
|
+
```
|
|
996
|
+
+-------------------------------------------------------+
|
|
997
|
+
| [Title: "User Management"] [Badge: "100,000"] |
|
|
998
|
+
| 32px SemiBold black Green pill badge |
|
|
999
|
+
| |
|
|
1000
|
+
| [Subtitle: "User list management page"] | [Write]
|
|
1001
|
+
| 18px Medium #9DA0A8 | Teal btn w/ Pencil icon
|
|
1002
|
+
| | Top-right aligned
|
|
1003
|
+
+-------------------------------------------------------+
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
**B. Tabs Area:**
|
|
1007
|
+
```
|
|
1008
|
+
+-------------------------------------------------------+
|
|
1009
|
+
| [All] [Tab] [Tab] |
|
|
1010
|
+
| Active: Inactive: Inactive: |
|
|
1011
|
+
| bg #509594 bg #EEF2F6 bg #EEF2F6 |
|
|
1012
|
+
| text white text #1A202C text #1A202C |
|
|
1013
|
+
| 52px h 52px h 52px h |
|
|
1014
|
+
| 6px radius 6px radius 6px radius |
|
|
1015
|
+
+-------------------------------------------------------+
|
|
1016
|
+
```
|
|
1017
|
+
|
|
1018
|
+
**C. Pagination Controls:**
|
|
1019
|
+
```
|
|
1020
|
+
+-------------------------------------------------------+
|
|
1021
|
+
| [<<] [<] 1 / 1 [>] [>>] [Page][Go][10 v] |
|
|
1022
|
+
| 40x40 20px/16px 40x40 100px 48h 96px |
|
|
1023
|
+
| #B9D5D4 Bold/Reg #B9D5D4 input btn sel |
|
|
1024
|
+
+-------------------------------------------------------+
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
**D. Table:**
|
|
1028
|
+
```
|
|
1029
|
+
+----+------+-----+---+-------+-----+-----+-----+------+------+-----+
|
|
1030
|
+
| # | Nick | Grd | A | Phone | Age | Gen | Reg | Join | Wdr | Del |
|
|
1031
|
+
| | | | v | | | | | v | v | |
|
|
1032
|
+
+----+------+-----+---+-------+-----+-----+-----+------+------+-----+ <- #F9FAFC bg, 56px
|
|
1033
|
+
| 1 | Nick | Man |(o)| 010.. | 99 | M | Gan | Nov | Nov | Del |
|
|
1034
|
+
| | Here | ia | | 1234 | | ale | nam | 1,22 | 1,22 | ete | <- White bg, 60px
|
|
1035
|
+
+----+------+-----+---+-------+-----+-----+-----+------+------+-----+
|
|
1036
|
+
| 2 | ... | ... |...| ... | ... | ... | ... | ... | ... | Del |
|
|
1037
|
+
+----+------+-----+---+-------+-----+-----+-----+------+------+-----+
|
|
1038
|
+
```
|
|
1039
|
+
- Column "A v" = Avatar (80px fixed, centered circle)
|
|
1040
|
+
- Column "Del" = Delete (57px fixed, teal ghost text)
|
|
1041
|
+
- "v" on Join/Wdr = sort icon (ChevronDown)
|
|
1042
|
+
|
|
1043
|
+
### 7.2 User Detail Page -- Desktop
|
|
1044
|
+
|
|
1045
|
+
```
|
|
1046
|
+
+---------------------------+-----------------------------------------------------------+
|
|
1047
|
+
| SIDEBAR (300px) | CONTENT AREA |
|
|
1048
|
+
| | |
|
|
1049
|
+
| (same sidebar as above) | +-------------------------------------------------------+|
|
|
1050
|
+
| | | User Management [ Save Changes btn ] ||
|
|
1051
|
+
| | | You can edit user information. ||
|
|
1052
|
+
| | | ||
|
|
1053
|
+
| | | ---------------------------------------------------- ||
|
|
1054
|
+
| | | ||
|
|
1055
|
+
| | | Basic Info (section label, #A0AEC0, 20px Bold) ||
|
|
1056
|
+
| | | ||
|
|
1057
|
+
| | | +--------+ +--------+ +--------+ ||
|
|
1058
|
+
| | | | IMG 1 | | IMG 2 | | IMG 3 | 116x116px ea ||
|
|
1059
|
+
| | | | 116px | | 116px | | 116px | 8px radius ||
|
|
1060
|
+
| | | +--------+ +--------+ +--------+ ||
|
|
1061
|
+
| | | ||
|
|
1062
|
+
| | | One-Line Intro ||
|
|
1063
|
+
| | | +---------------------------------------------------+||
|
|
1064
|
+
| | | | This is the one-line intro content. |||
|
|
1065
|
+
| | | +---------------------------------------------------+||
|
|
1066
|
+
| | | ||
|
|
1067
|
+
| | | +----------+ +----------+ +----------+ +----------+ ||
|
|
1068
|
+
| | | | Role | | Nickname | | Phone | | Age | ||
|
|
1069
|
+
| | | | [User v] | | [Attack..] | [01012..] | [24 yrs] | ||
|
|
1070
|
+
| | | +----------+ +----------+ +----------+ +----------+ ||
|
|
1071
|
+
| | | ||
|
|
1072
|
+
| | | +----------+ +----------+ +----------+ +----------+ ||
|
|
1073
|
+
| | | | Gender | | Ex.Style | | Gym Relo | | Region | ||
|
|
1074
|
+
| | | | [Male v] | | [Body..v]| | [Avail.v]| | [Seoul.v]| ||
|
|
1075
|
+
| | | +----------+ +----------+ +----------+ +----------+ ||
|
|
1076
|
+
| | | ||
|
|
1077
|
+
| | | +----------+ +----------+ +----------+ ||
|
|
1078
|
+
| | | | Bench | | Deadlift | | Squat | ||
|
|
1079
|
+
| | | | [100kg] | | [100kg] | | [100kg] | ||
|
|
1080
|
+
| | | +----------+ +----------+ +----------+ ||
|
|
1081
|
+
| | | ||
|
|
1082
|
+
| | | ---------------------------------------------------- ||
|
|
1083
|
+
| | | ||
|
|
1084
|
+
| | | Other Settings (section label, #A0AEC0, 20px Bold) ||
|
|
1085
|
+
| | | ||
|
|
1086
|
+
| | | Profile Public [OFF] Match&Chat [ON] Mktg [OFF] ||
|
|
1087
|
+
| | | (--o) (o--) (--o) ||
|
|
1088
|
+
| | | 100px gap 100px gap ||
|
|
1089
|
+
| | | ||
|
|
1090
|
+
| | +-------------------------------------------------------+|
|
|
1091
|
+
+---------------------------+-----------------------------------------------------------+
|
|
1092
|
+
```
|
|
1093
|
+
|
|
1094
|
+
#### Detailed Annotations -- User Detail
|
|
1095
|
+
|
|
1096
|
+
**A. Header Area:**
|
|
1097
|
+
```
|
|
1098
|
+
+-------------------------------------------------------+
|
|
1099
|
+
| [Title: "User Management"] |
|
|
1100
|
+
| 32px SemiBold black |
|
|
1101
|
+
| | [Save Changes]
|
|
1102
|
+
| [Subtitle: "You can edit user information."] | Teal btn w/ Pencil icon
|
|
1103
|
+
| 18px Medium #9DA0A8 | Top-right aligned
|
|
1104
|
+
+-------------------------------------------------------+
|
|
1105
|
+
```
|
|
1106
|
+
|
|
1107
|
+
**B. Basic Info Section:**
|
|
1108
|
+
```
|
|
1109
|
+
Section Label: "Basic Info"
|
|
1110
|
+
- Font: Pretendard 20px Bold
|
|
1111
|
+
- Color: #A0AEC0
|
|
1112
|
+
- Margin bottom: 24px
|
|
1113
|
+
|
|
1114
|
+
Profile Images: 3 images in horizontal row
|
|
1115
|
+
- Each: 116x116px, 8px radius
|
|
1116
|
+
- Gap between images: 16px
|
|
1117
|
+
- Margin bottom: 24px
|
|
1118
|
+
|
|
1119
|
+
One-Line Intro:
|
|
1120
|
+
- Label: "One-Line Intro" (20px SemiBold #101010)
|
|
1121
|
+
- Input: full-width, 52px height, 6px radius
|
|
1122
|
+
- Margin bottom: 24px
|
|
1123
|
+
|
|
1124
|
+
Field Rows:
|
|
1125
|
+
- 4 columns per row (except row 3 = 3 columns)
|
|
1126
|
+
- Equal width, 24px gap
|
|
1127
|
+
- Each field: Label (20px SemiBold) above Input/Select (52px height)
|
|
1128
|
+
- Row gap: 24px
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
**C. Other Settings Section:**
|
|
1132
|
+
```
|
|
1133
|
+
Section Label: "Other Settings"
|
|
1134
|
+
- Font: Pretendard 20px Bold
|
|
1135
|
+
- Color: #A0AEC0
|
|
1136
|
+
- Margin bottom: 24px
|
|
1137
|
+
|
|
1138
|
+
Toggle Layout: Horizontal, 100px gap between items
|
|
1139
|
+
Each toggle:
|
|
1140
|
+
- Label text (left) + Switch component (right)
|
|
1141
|
+
- or Label text above, switch beside
|
|
1142
|
+
- Switch: 44x24px
|
|
1143
|
+
- ON: Blue (#3B82F6) track, white thumb right
|
|
1144
|
+
- OFF: Gray (#CBD5E0) track, white thumb left
|
|
1145
|
+
```
|
|
1146
|
+
|
|
1147
|
+
---
|
|
1148
|
+
|
|
1149
|
+
## 8. Micro-interactions and Animation Guidelines
|
|
1150
|
+
|
|
1151
|
+
### 8.1 Animation Timing
|
|
1152
|
+
|
|
1153
|
+
| Type | Duration | Easing | Usage |
|
|
1154
|
+
|------|----------|--------|-------|
|
|
1155
|
+
| Micro | 150ms | `ease-out` | Button hover, focus ring, link hover |
|
|
1156
|
+
| Small | 200ms | `ease-in-out` | Toggle switch thumb, tab switch, row hover |
|
|
1157
|
+
| Medium | 300ms | `ease-in-out` | Accordion expand/collapse, dropdown open/close, tooltip |
|
|
1158
|
+
| Large | 400ms | `ease-in-out` | Page transitions (if applicable) |
|
|
1159
|
+
|
|
1160
|
+
### 8.2 Specific Interactions
|
|
1161
|
+
|
|
1162
|
+
#### Button Hover
|
|
1163
|
+
```css
|
|
1164
|
+
.btn-primary:hover {
|
|
1165
|
+
background-color: #3F7A79;
|
|
1166
|
+
transition: background-color 150ms ease-out;
|
|
1167
|
+
}
|
|
1168
|
+
.btn-primary:active {
|
|
1169
|
+
background-color: #357070;
|
|
1170
|
+
transform: scale(0.98);
|
|
1171
|
+
transition: all 100ms ease-out;
|
|
1172
|
+
}
|
|
1173
|
+
```
|
|
1174
|
+
|
|
1175
|
+
#### Table Row Hover
|
|
1176
|
+
```css
|
|
1177
|
+
.table-row:hover {
|
|
1178
|
+
background-color: #F9FAFC;
|
|
1179
|
+
cursor: pointer;
|
|
1180
|
+
transition: background-color 150ms ease-out;
|
|
1181
|
+
}
|
|
1182
|
+
```
|
|
1183
|
+
|
|
1184
|
+
#### Toggle Switch
|
|
1185
|
+
```css
|
|
1186
|
+
.switch-thumb {
|
|
1187
|
+
transition: transform 200ms ease-in-out;
|
|
1188
|
+
}
|
|
1189
|
+
.switch-track {
|
|
1190
|
+
transition: background-color 200ms ease-in-out;
|
|
1191
|
+
}
|
|
1192
|
+
/* ON state */
|
|
1193
|
+
.switch[data-state="checked"] .switch-thumb {
|
|
1194
|
+
transform: translateX(20px);
|
|
1195
|
+
}
|
|
1196
|
+
```
|
|
1197
|
+
|
|
1198
|
+
#### Accordion Expand/Collapse
|
|
1199
|
+
```css
|
|
1200
|
+
.accordion-content {
|
|
1201
|
+
transition: height 300ms ease-in-out, opacity 200ms ease-in-out;
|
|
1202
|
+
}
|
|
1203
|
+
.accordion-trigger .chevron {
|
|
1204
|
+
transition: transform 300ms ease-in-out;
|
|
1205
|
+
}
|
|
1206
|
+
.accordion-trigger[data-state="open"] .chevron {
|
|
1207
|
+
transform: rotate(180deg);
|
|
1208
|
+
}
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
#### Tab Switch
|
|
1212
|
+
```css
|
|
1213
|
+
.tab-trigger {
|
|
1214
|
+
transition: background-color 200ms ease-in-out, color 200ms ease-in-out;
|
|
1215
|
+
}
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
#### Input Focus
|
|
1219
|
+
```css
|
|
1220
|
+
.input:focus {
|
|
1221
|
+
border-color: #509594;
|
|
1222
|
+
outline: none;
|
|
1223
|
+
box-shadow: 0 0 0 2px rgba(80, 149, 148, 0.2);
|
|
1224
|
+
transition: border-color 150ms ease-out, box-shadow 150ms ease-out;
|
|
1225
|
+
}
|
|
1226
|
+
```
|
|
1227
|
+
|
|
1228
|
+
#### Delete Text Hover
|
|
1229
|
+
```css
|
|
1230
|
+
.delete-action:hover {
|
|
1231
|
+
text-decoration: underline;
|
|
1232
|
+
color: #3F7A79;
|
|
1233
|
+
transition: color 150ms ease-out;
|
|
1234
|
+
}
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
#### Sidebar Menu Item Hover
|
|
1238
|
+
```css
|
|
1239
|
+
.sidebar-menu-item:hover {
|
|
1240
|
+
background-color: #F9FAFC;
|
|
1241
|
+
transition: background-color 150ms ease-out;
|
|
1242
|
+
}
|
|
1243
|
+
.sidebar-menu-item.active {
|
|
1244
|
+
background-color: #EEF2F6;
|
|
1245
|
+
color: #509594;
|
|
1246
|
+
}
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
#### Page Jump Input Focus
|
|
1250
|
+
```css
|
|
1251
|
+
.page-jump:focus {
|
|
1252
|
+
border-color: #509594;
|
|
1253
|
+
transition: border-color 150ms ease-out;
|
|
1254
|
+
}
|
|
1255
|
+
```
|
|
1256
|
+
|
|
1257
|
+
### 8.3 Loading and Empty States
|
|
1258
|
+
|
|
1259
|
+
Even though data is static/mock, define these for completeness:
|
|
1260
|
+
|
|
1261
|
+
| State | Component | Behavior |
|
|
1262
|
+
|-------|-----------|----------|
|
|
1263
|
+
| Table loading | Skeleton rows | 5 rows of pulsing gray blocks matching column widths |
|
|
1264
|
+
| Empty table | Message | "No users found" centered in table area, `#9DA0A8` text |
|
|
1265
|
+
| Image loading | Skeleton | 116x116px pulsing gray block |
|
|
1266
|
+
| Avatar fallback | Initial | First letter of nickname in `#EEF2F6` circle |
|
|
1267
|
+
|
|
1268
|
+
---
|
|
1269
|
+
|
|
1270
|
+
## 9. Accessibility Checklist
|
|
1271
|
+
|
|
1272
|
+
### 9.1 WCAG 2.1 AA Requirements
|
|
1273
|
+
|
|
1274
|
+
#### Perceivable
|
|
1275
|
+
|
|
1276
|
+
- [x] All images have alt text (profile images, avatars)
|
|
1277
|
+
- [x] Color contrast meets 4.5:1 for normal text (Black on white = 21:1, Grayscale/900 on white = 9.21:1)
|
|
1278
|
+
- [x] Color contrast meets 3:1 for large text 18px+ (Primary on white = 3.15:1, used at 18px SemiBold)
|
|
1279
|
+
- [x] Information not conveyed by color alone (active tab has both color AND background change, toggle has position indicator)
|
|
1280
|
+
- [x] Text resizable up to 200% without loss of content (desktop-only, but layout should not break)
|
|
1281
|
+
- [x] All form fields have visible labels
|
|
1282
|
+
- [x] Placeholder text is supplementary, not the only label
|
|
1283
|
+
|
|
1284
|
+
#### Operable
|
|
1285
|
+
|
|
1286
|
+
- [x] All functionality accessible via keyboard
|
|
1287
|
+
- [x] Tab order follows logical reading order (sidebar -> content, top to bottom, left to right)
|
|
1288
|
+
- [x] No keyboard traps (accordion sections, select dropdowns can be exited with Escape)
|
|
1289
|
+
- [x] Skip links provided: "Skip to main content" link before sidebar
|
|
1290
|
+
- [x] Focus indicators visible: 2px `#509594` ring with offset on all interactive elements
|
|
1291
|
+
- [x] Minimum click/touch target: 40px height on all buttons (44px on toggles)
|
|
1292
|
+
- [x] Focus visible on all interactive elements (buttons, inputs, links, tabs, toggles, accordion triggers)
|
|
1293
|
+
|
|
1294
|
+
#### Understandable
|
|
1295
|
+
|
|
1296
|
+
- [x] Language specified in HTML (`lang="ko"` or `lang="en"` as appropriate)
|
|
1297
|
+
- [x] Form labels clearly associated with inputs via `htmlFor`/`id` pairing
|
|
1298
|
+
- [x] Error messages descriptive (reserved for future, not needed in static UI)
|
|
1299
|
+
- [x] Consistent navigation (sidebar is the same on every page)
|
|
1300
|
+
- [x] Consistent identification (same components styled the same way everywhere)
|
|
1301
|
+
|
|
1302
|
+
#### Robust
|
|
1303
|
+
|
|
1304
|
+
- [x] Valid, semantic HTML markup (heading hierarchy: h1 for page title, h2 for sections)
|
|
1305
|
+
- [x] ARIA labels on icon-only buttons (`aria-label="Go to first page"`, etc.)
|
|
1306
|
+
- [x] ARIA roles on custom components (shadcn/ui provides these via Radix primitives)
|
|
1307
|
+
- [x] `role="table"`, `role="row"`, `role="columnheader"`, `role="cell"` on data table
|
|
1308
|
+
- [x] `aria-expanded` on accordion triggers
|
|
1309
|
+
- [x] `aria-selected` on active tab
|
|
1310
|
+
- [x] `aria-checked` on toggle switches
|
|
1311
|
+
- [x] Works with screen readers (NVDA, VoiceOver) -- shadcn/ui Radix primitives handle this
|
|
1312
|
+
|
|
1313
|
+
### 9.2 Keyboard Navigation Map
|
|
1314
|
+
|
|
1315
|
+
| Component | Key | Action |
|
|
1316
|
+
|-----------|-----|--------|
|
|
1317
|
+
| Skip link | Tab (first element) | Focus skip link, Enter to jump to main content |
|
|
1318
|
+
| Sidebar menu | Tab / Shift+Tab | Navigate between menu items |
|
|
1319
|
+
| Accordion | Enter / Space | Toggle expand/collapse |
|
|
1320
|
+
| Accordion | Arrow Up/Down | Navigate between accordion items |
|
|
1321
|
+
| Tabs | Arrow Left/Right | Switch between tabs |
|
|
1322
|
+
| Tabs | Enter / Space | Activate tab |
|
|
1323
|
+
| Table row | Tab | Focus row (or first interactive element in row) |
|
|
1324
|
+
| Table row | Enter | Navigate to user detail (same as click) |
|
|
1325
|
+
| Delete action | Enter / Space | Trigger delete action |
|
|
1326
|
+
| Pagination buttons | Tab + Enter | Navigate pages |
|
|
1327
|
+
| Input fields | Tab | Focus field |
|
|
1328
|
+
| Select dropdown | Enter / Space | Open dropdown |
|
|
1329
|
+
| Select dropdown | Arrow Up/Down | Navigate options |
|
|
1330
|
+
| Select dropdown | Enter | Select option |
|
|
1331
|
+
| Select dropdown | Escape | Close dropdown |
|
|
1332
|
+
| Toggle switch | Space | Toggle ON/OFF |
|
|
1333
|
+
| Buttons | Enter / Space | Activate button |
|
|
1334
|
+
|
|
1335
|
+
### 9.3 Screen Reader Announcements
|
|
1336
|
+
|
|
1337
|
+
| Element | Announcement |
|
|
1338
|
+
|---------|-------------|
|
|
1339
|
+
| Page title | "User Management, heading level 1" |
|
|
1340
|
+
| Badge | "Total users: 100,000" (use `aria-label`) |
|
|
1341
|
+
| Active tab | "All, tab, selected, 1 of 3" |
|
|
1342
|
+
| Table | "User management table, 10 columns, 5 rows" |
|
|
1343
|
+
| Sort button | "Join Date, sortable column, sort ascending" |
|
|
1344
|
+
| Delete action | "Delete user NicknameHere, button" |
|
|
1345
|
+
| Toggle | "Profile Public, switch, off" / "Match notification, switch, on" |
|
|
1346
|
+
| Pagination | "Page 1 of 1" (use `aria-live="polite"` region) |
|
|
1347
|
+
|
|
1348
|
+
### 9.4 Color Accessibility Verification
|
|
1349
|
+
|
|
1350
|
+
| Element | Foreground | Background | Ratio | WCAG Level | Status |
|
|
1351
|
+
|---------|------------|------------|-------|------------|--------|
|
|
1352
|
+
| Page title | `#000000` | `#FFFFFF` | 21:1 | AAA | Pass |
|
|
1353
|
+
| Subtitle | `#9DA0A8` | `#FFFFFF` | 3.01:1 | AA Large (18px) | Pass |
|
|
1354
|
+
| Section label | `#A0AEC0` | `#FFFFFF` | 2.64:1 | -- | Decorative label; pair with semantic heading for SR |
|
|
1355
|
+
| Table cell text | `#3B3F4A` | `#FFFFFF` | 9.21:1 | AAA | Pass |
|
|
1356
|
+
| Button text | `#FFFFFF` | `#509594` | 3.15:1 | AA Large (18px SemiBold) | Pass |
|
|
1357
|
+
| Badge text | `#22543D` | `#C6F6D5` | 7.05:1 | AAA | Pass |
|
|
1358
|
+
| Inactive tab text | `#1A202C` | `#EEF2F6` | 13.83:1 | AAA | Pass |
|
|
1359
|
+
| Sidebar text | `#5A5E6A` | `#FFFFFF` | 5.32:1 | AA | Pass |
|
|
1360
|
+
| Placeholder text | `#A0AEC0` | `#FFFFFF` | 2.64:1 | -- | Placeholder only, label provides accessible name |
|
|
1361
|
+
| Delete action | `#509594` | `#FFFFFF` | 3.15:1 | AA Large (14px) | Needs underline or icon for non-color indicator |
|
|
1362
|
+
|
|
1363
|
+
**Remediation for Delete Action:**
|
|
1364
|
+
The "Delete" text at 14px with `#509594` on white (3.15:1) does not meet AA for normal text (needs 4.5:1). Options:
|
|
1365
|
+
1. Add underline to provide non-color visual affordance (text-decoration: underline)
|
|
1366
|
+
2. Use darker shade `#3F7A79` (4.87:1) -- meets AA for normal text
|
|
1367
|
+
3. Add a trash icon beside text for additional visual cue
|
|
1368
|
+
|
|
1369
|
+
**Recommendation:** Use `#3F7A79` for delete text AND add underline on hover. This ensures both color contrast compliance and clear interactive affordance.
|
|
1370
|
+
|
|
1371
|
+
---
|
|
1372
|
+
|
|
1373
|
+
## 10. Implementation Guidelines
|
|
1374
|
+
|
|
1375
|
+
### 10.1 Design Token to CSS Variable Mapping
|
|
1376
|
+
|
|
1377
|
+
| Design Token | CSS Variable | Tailwind v4 | shadcn Variable |
|
|
1378
|
+
|--------------|--------------|-------------|-----------------|
|
|
1379
|
+
| Primary `#509594` | `--primary` | `bg-primary` / `text-primary` | `--primary` |
|
|
1380
|
+
| Primary Light `#B9D5D4` | `--accent` | `bg-accent` | `--accent` |
|
|
1381
|
+
| Background `#FCFCFC` | `--background` | `bg-background` | `--background` |
|
|
1382
|
+
| White `#FFFFFF` | `--card` | `bg-card` | `--card` |
|
|
1383
|
+
| Border `#E2E8F0` | `--border` | `border-border` | `--border` |
|
|
1384
|
+
| Divider `#EFF1F4` | `--divider` | Custom: `border-divider` | Custom |
|
|
1385
|
+
| Table Header `#F9FAFC` | `--table-header` | Custom: `bg-table-header` | Custom |
|
|
1386
|
+
| Sidebar Selected `#EEF2F6` | `--muted` | `bg-muted` | `--muted` |
|
|
1387
|
+
| Gray/400 `#A0AEC0` | `--placeholder` | Custom: `text-placeholder` | Custom |
|
|
1388
|
+
| Grayscale/600 `#9DA0A8` | `--subtitle` | Custom: `text-subtitle` | Custom |
|
|
1389
|
+
| Grayscale/800 `#5A5E6A` | `--muted-foreground` | `text-muted-foreground` | `--muted-foreground` |
|
|
1390
|
+
| Grayscale/900 `#3B3F4A` | `--table-cell` | Custom: `text-table-cell` | Custom |
|
|
1391
|
+
| Black `#000000` | `--foreground` | `text-foreground` | `--foreground` |
|
|
1392
|
+
| Badge BG `#C6F6D5` | `--badge-green-bg` | Custom | Custom |
|
|
1393
|
+
| Badge Text `#22543D` | `--badge-green-text` | Custom | Custom |
|
|
1394
|
+
|
|
1395
|
+
### 10.2 Tailwind CSS 4 Configuration
|
|
1396
|
+
|
|
1397
|
+
```css
|
|
1398
|
+
/* globals.css */
|
|
1399
|
+
@import "tailwindcss";
|
|
1400
|
+
|
|
1401
|
+
@theme {
|
|
1402
|
+
/* Custom colors extending Tailwind */
|
|
1403
|
+
--color-primary: #509594;
|
|
1404
|
+
--color-primary-hover: #3F7A79;
|
|
1405
|
+
--color-primary-active: #357070;
|
|
1406
|
+
--color-primary-light: #B9D5D4;
|
|
1407
|
+
--color-background: #FCFCFC;
|
|
1408
|
+
--color-surface: #FFFFFF;
|
|
1409
|
+
--color-border: #E2E8F0;
|
|
1410
|
+
--color-divider: #EFF1F4;
|
|
1411
|
+
--color-table-header: #F9FAFC;
|
|
1412
|
+
--color-sidebar-selected: #EEF2F6;
|
|
1413
|
+
--color-placeholder: #A0AEC0;
|
|
1414
|
+
--color-subtitle: #9DA0A8;
|
|
1415
|
+
--color-muted-fg: #5A5E6A;
|
|
1416
|
+
--color-table-cell: #3B3F4A;
|
|
1417
|
+
--color-inactive-tab: #EFF1F4;
|
|
1418
|
+
--color-inactive-tab-text: #1A202C;
|
|
1419
|
+
--color-badge-green-bg: #C6F6D5;
|
|
1420
|
+
--color-badge-green-text: #22543D;
|
|
1421
|
+
--color-toggle-on: #3B82F6;
|
|
1422
|
+
--color-toggle-off: #CBD5E0;
|
|
1423
|
+
--color-delete-text: #3F7A79;
|
|
1424
|
+
|
|
1425
|
+
/* Font families */
|
|
1426
|
+
--font-pretendard: 'Pretendard Variable', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
1427
|
+
--font-inter: 'Inter', 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
1428
|
+
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
|
|
1429
|
+
}
|
|
1430
|
+
```
|
|
1431
|
+
|
|
1432
|
+
### 10.3 Component File Structure
|
|
1433
|
+
|
|
1434
|
+
```
|
|
1435
|
+
src/components/
|
|
1436
|
+
ui/ # shadcn/ui base components (auto-generated, then customized)
|
|
1437
|
+
accordion.tsx
|
|
1438
|
+
avatar.tsx
|
|
1439
|
+
badge.tsx
|
|
1440
|
+
button.tsx # Add primary, secondary, pagination, ghost variants
|
|
1441
|
+
card.tsx
|
|
1442
|
+
input.tsx # Override height, border, placeholder styles
|
|
1443
|
+
label.tsx
|
|
1444
|
+
pagination.tsx
|
|
1445
|
+
select.tsx # Override height, border, chevron styles
|
|
1446
|
+
separator.tsx # Override color to #EFF1F4
|
|
1447
|
+
sidebar.tsx # Override width to 300px
|
|
1448
|
+
switch.tsx # Override size to 44x24px, ON color blue
|
|
1449
|
+
table.tsx # Override header bg, row heights
|
|
1450
|
+
tabs.tsx # Override active/inactive styles
|
|
1451
|
+
tooltip.tsx
|
|
1452
|
+
|
|
1453
|
+
app-sidebar.tsx # Sidebar with ADMIN header, accordion nav, logout footer
|
|
1454
|
+
page-header.tsx # Reusable: title + badge + subtitle + action button
|
|
1455
|
+
user-table.tsx # Table with columns, mock data rows, pagination
|
|
1456
|
+
user-detail-form.tsx # Form with Basic Info + Other Settings sections
|
|
1457
|
+
```
|
|
1458
|
+
|
|
1459
|
+
### 10.4 Component Implementation Notes
|
|
1460
|
+
|
|
1461
|
+
#### app-sidebar.tsx
|
|
1462
|
+
- Uses shadcn/ui `Sidebar` + `Accordion` components
|
|
1463
|
+
- Fixed 300px width, full viewport height
|
|
1464
|
+
- `SidebarHeader`: "ADMIN" title + admin ID subtitle
|
|
1465
|
+
- `SidebarContent`: Accordion with Home, User, Match, Admin sections
|
|
1466
|
+
- `SidebarFooter`: Logout button with `Separator` above
|
|
1467
|
+
- Active state tracked via Next.js `usePathname()`
|
|
1468
|
+
- Sub-menu items use `Link` from `next/link`
|
|
1469
|
+
|
|
1470
|
+
#### page-header.tsx
|
|
1471
|
+
- Accepts props: `title`, `subtitle`, `badgeCount?`, `actionLabel`, `actionIcon`, `onAction`
|
|
1472
|
+
- Flex layout: title+badge+subtitle left, action button right
|
|
1473
|
+
- Badge only rendered when `badgeCount` provided
|
|
1474
|
+
- `Separator` component below header content
|
|
1475
|
+
|
|
1476
|
+
#### user-table.tsx
|
|
1477
|
+
- shadcn/ui `Table` with custom column definitions
|
|
1478
|
+
- 5 rows of hardcoded mock data from `lib/mock-data.ts`
|
|
1479
|
+
- Row `onClick` navigates to `/users/[id]` using `useRouter().push()`
|
|
1480
|
+
- Delete column `onClick` stops propagation (prevents row navigation)
|
|
1481
|
+
- Pagination controls above table as flex row with space-between
|
|
1482
|
+
- Sort icons on Join Date and Withdrawal Date columns (visual only)
|
|
1483
|
+
|
|
1484
|
+
#### user-detail-form.tsx
|
|
1485
|
+
- Sections: Basic Info, Other Settings
|
|
1486
|
+
- Uses CSS Grid for field rows: `grid-cols-4` with `gap-6` (24px)
|
|
1487
|
+
- Row 3 uses `grid-cols-3`
|
|
1488
|
+
- Each field: `Label` above `Input` or `Select`
|
|
1489
|
+
- Profile images: flex row with 3 `img` elements
|
|
1490
|
+
- Toggles: flex row with `100px` gap, each toggle = label + `Switch`
|
|
1491
|
+
|
|
1492
|
+
### 10.5 Mock Data Structure
|
|
1493
|
+
|
|
1494
|
+
```typescript
|
|
1495
|
+
// src/lib/mock-data.ts
|
|
1496
|
+
|
|
1497
|
+
export interface User {
|
|
1498
|
+
id: string;
|
|
1499
|
+
nickname: string;
|
|
1500
|
+
grade: string;
|
|
1501
|
+
avatar: string; // URL or placeholder path
|
|
1502
|
+
phone: string;
|
|
1503
|
+
age: string;
|
|
1504
|
+
gender: string;
|
|
1505
|
+
region: string;
|
|
1506
|
+
joinDate: string;
|
|
1507
|
+
withdrawalDate: string;
|
|
1508
|
+
role: string;
|
|
1509
|
+
exerciseStyle: string;
|
|
1510
|
+
gymRelocation: string;
|
|
1511
|
+
bench: string;
|
|
1512
|
+
deadlift: string;
|
|
1513
|
+
squat: string;
|
|
1514
|
+
intro: string;
|
|
1515
|
+
profileImages: string[]; // Array of 3 image URLs
|
|
1516
|
+
settings: {
|
|
1517
|
+
profilePublic: boolean;
|
|
1518
|
+
matchChatNotification: boolean;
|
|
1519
|
+
marketingNotification: boolean;
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
export const mockUsers: User[] = [
|
|
1524
|
+
{
|
|
1525
|
+
id: "1",
|
|
1526
|
+
nickname: "NicknameHere",
|
|
1527
|
+
grade: "Mania",
|
|
1528
|
+
avatar: "/avatars/user1.jpg",
|
|
1529
|
+
phone: "010-1234-1234",
|
|
1530
|
+
age: "Born 1999",
|
|
1531
|
+
gender: "Male",
|
|
1532
|
+
region: "Gangnam-gu",
|
|
1533
|
+
joinDate: "Nov 1, 2022",
|
|
1534
|
+
withdrawalDate: "Nov 1, 2022",
|
|
1535
|
+
role: "User",
|
|
1536
|
+
exerciseStyle: "Bodybuilding",
|
|
1537
|
+
gymRelocation: "Available",
|
|
1538
|
+
bench: "100kg",
|
|
1539
|
+
deadlift: "100kg",
|
|
1540
|
+
squat: "100kg",
|
|
1541
|
+
intro: "This is the one-line intro content.",
|
|
1542
|
+
profileImages: [
|
|
1543
|
+
"/profile/img1.jpg",
|
|
1544
|
+
"/profile/img2.jpg",
|
|
1545
|
+
"/profile/img3.jpg",
|
|
1546
|
+
],
|
|
1547
|
+
settings: {
|
|
1548
|
+
profilePublic: false,
|
|
1549
|
+
matchChatNotification: true,
|
|
1550
|
+
marketingNotification: false,
|
|
1551
|
+
},
|
|
1552
|
+
},
|
|
1553
|
+
// ... repeat for 5 total rows
|
|
1554
|
+
];
|
|
1555
|
+
|
|
1556
|
+
export const totalUserCount = 100000;
|
|
1557
|
+
```
|
|
1558
|
+
|
|
1559
|
+
### 10.6 Asset Specifications
|
|
1560
|
+
|
|
1561
|
+
| Asset Type | Format | Size | Notes |
|
|
1562
|
+
|------------|--------|------|-------|
|
|
1563
|
+
| Icons (Lucide) | SVG (inline React) | 16px, 20px, 24px | Imported from `lucide-react` |
|
|
1564
|
+
| Avatars (table) | WebP/PNG | 22x22px (rendered), 44x44px (source @2x) | Circular crop |
|
|
1565
|
+
| Profile images | WebP/PNG | 116x116px (rendered), 232x232px (source @2x) | 8px border radius |
|
|
1566
|
+
| Logo/Brand mark | SVG | As needed | If sidebar header needs a logo |
|
|
1567
|
+
| Favicon | ICO/PNG | 16x16, 32x32, 180x180 | Standard set |
|
|
1568
|
+
|
|
1569
|
+
### 10.7 Next.js App Router Structure
|
|
1570
|
+
|
|
1571
|
+
```typescript
|
|
1572
|
+
// app/layout.tsx
|
|
1573
|
+
// - Wraps all pages with SidebarProvider + AppSidebar + main content area
|
|
1574
|
+
// - Loads Pretendard Variable (CSS) and Inter (next/font)
|
|
1575
|
+
// - Sets <html lang="ko"> for Korean platform
|
|
1576
|
+
// - Applies global CSS variables
|
|
1577
|
+
|
|
1578
|
+
// app/page.tsx
|
|
1579
|
+
// - Dashboard: User Management List
|
|
1580
|
+
// - Contains: PageHeader + Tabs + SearchBar + Pagination + UserTable
|
|
1581
|
+
|
|
1582
|
+
// app/users/[id]/page.tsx
|
|
1583
|
+
// - User Detail page
|
|
1584
|
+
// - Contains: PageHeader + UserDetailForm
|
|
1585
|
+
// - Receives `params.id` to select mock user (or default to first)
|
|
1586
|
+
```
|
|
1587
|
+
|
|
1588
|
+
### 10.8 Key Tailwind Utility Classes Reference
|
|
1589
|
+
|
|
1590
|
+
| Design Element | Tailwind Classes |
|
|
1591
|
+
|----------------|-----------------|
|
|
1592
|
+
| Card container | `bg-white border border-border rounded-lg p-8` |
|
|
1593
|
+
| Page title | `font-pretendard text-[32px] font-semibold text-black` |
|
|
1594
|
+
| Subtitle | `font-pretendard text-[18px] font-medium text-subtitle` |
|
|
1595
|
+
| Section label | `font-pretendard text-[20px] font-bold text-placeholder` |
|
|
1596
|
+
| Field label | `font-pretendard text-[20px] font-semibold text-[#101010]` |
|
|
1597
|
+
| Primary button | `bg-primary hover:bg-primary-hover text-white font-inter text-[18px] font-semibold h-10 px-4 rounded-lg` |
|
|
1598
|
+
| Secondary button | `bg-sidebar-selected text-black font-inter text-[18px] font-semibold h-12 px-4 rounded-md` |
|
|
1599
|
+
| Pagination button | `bg-primary-light text-primary h-10 w-10 rounded-md` |
|
|
1600
|
+
| Input (dashboard) | `h-12 border border-border rounded-md px-4 font-inter text-[18px] placeholder:text-placeholder` |
|
|
1601
|
+
| Input (detail) | `h-[52px] border border-border rounded-md px-4 font-inter text-[18px]` |
|
|
1602
|
+
| Table header | `bg-table-header h-14 text-[14px] font-semibold text-table-cell` |
|
|
1603
|
+
| Table row | `h-[60px] text-[14px] text-table-cell hover:bg-table-header cursor-pointer` |
|
|
1604
|
+
| Active tab | `bg-primary text-white font-semibold h-[52px] px-4 rounded-md` |
|
|
1605
|
+
| Inactive tab | `bg-inactive-tab text-inactive-tab-text font-medium h-[52px] px-4 rounded-md` |
|
|
1606
|
+
| Badge | `bg-badge-green-bg text-badge-green-text font-inter text-[18px] font-bold px-3 py-1 rounded-full` |
|
|
1607
|
+
| Separator | `bg-divider h-px w-full` |
|
|
1608
|
+
| Toggle (track) | `w-[44px] h-[24px] rounded-full` |
|
|
1609
|
+
| Avatar (table) | `w-[22px] h-[22px] rounded-full` |
|
|
1610
|
+
| Profile image | `w-[116px] h-[116px] rounded-lg object-cover` |
|
|
1611
|
+
| Sidebar | `w-[300px] h-screen fixed left-0 bg-white border-r border-border` |
|
|
1612
|
+
| Content area | `ml-[324px] pt-5 pr-8 pb-8` |
|
|
1613
|
+
|
|
1614
|
+
---
|
|
1615
|
+
|
|
1616
|
+
## 11. Design Decisions Log
|
|
1617
|
+
|
|
1618
|
+
| Decision | Rationale | Alternatives Considered |
|
|
1619
|
+
|----------|-----------|------------------------|
|
|
1620
|
+
| Fixed sidebar (not collapsible) | PRD specifies 300px fixed sidebar; desktop-only design eliminates need for collapse | Collapsible sidebar with hamburger toggle |
|
|
1621
|
+
| Teal (#509594) as primary | Matches Figma design tokens; conveys trust and wellness (appropriate for fitness platform) | Blue (#3B82F6), Green (#22C55E) |
|
|
1622
|
+
| Pretendard Variable for headings | Korean-optimized variable font with excellent weight range; specified in PRD | Noto Sans KR, Spoqa Han Sans |
|
|
1623
|
+
| Inter for UI elements | Excellent readability at small sizes, pairs well with Pretendard; specified in PRD | SF Pro, Roboto |
|
|
1624
|
+
| Blue (#3B82F6) for toggle ON state | Standard toggle pattern; distinguishes from teal primary to avoid confusion | Teal (#509594), Green (#22C55E) |
|
|
1625
|
+
| No border-radius on table container | Matches Figma spec; creates visual contrast with rounded card container | 8px radius matching card |
|
|
1626
|
+
| Darker teal (#3F7A79) for delete text | Improves contrast ratio from 3.15:1 to 4.87:1 for AA compliance at 14px | Original #509594 with underline only |
|
|
1627
|
+
| 4px base spacing unit | Industry standard, aligns with all Figma measurements as clean multiples | 8px base unit |
|
|
1628
|
+
| shadcn/ui as component foundation | Copy-paste model allows full customization while providing accessible Radix primitives | Headless UI, custom components from scratch |
|
|
1629
|
+
| No responsive design | PRD explicitly states desktop-only at 1920px; out of scope | Mobile-first responsive |
|
|
1630
|
+
| Section labels in #A0AEC0 (gray) | Matches Figma tokens; creates visual hierarchy where labels are subordinate to content | Black section labels, primary color labels |
|
|
1631
|
+
| Accordion sidebar navigation | Matches Figma design; scales well for growing number of admin sections | Flat list, mega menu, breadcrumb nav |
|
|
1632
|
+
|
|
1633
|
+
---
|
|
1634
|
+
|
|
1635
|
+
## 12. Next Steps
|
|
1636
|
+
|
|
1637
|
+
1. [ ] Review and approve this UI/UX design plan
|
|
1638
|
+
2. [ ] Initialize Next.js 16 project with Bun
|
|
1639
|
+
3. [ ] Install and configure shadcn/ui with custom theme
|
|
1640
|
+
4. [ ] Set up Tailwind CSS 4 with design token variables
|
|
1641
|
+
5. [ ] Load Pretendard Variable and Inter fonts
|
|
1642
|
+
6. [ ] Build shadcn/ui component overrides (button variants, table, input, etc.)
|
|
1643
|
+
7. [ ] Implement global layout (sidebar + content area)
|
|
1644
|
+
8. [ ] Build app-sidebar component with accordion navigation
|
|
1645
|
+
9. [ ] Build User Management List (dashboard) page
|
|
1646
|
+
10. [ ] Build User Detail page with form fields
|
|
1647
|
+
11. [ ] Add mock data and wire up static interactions
|
|
1648
|
+
12. [ ] Conduct accessibility audit (keyboard nav, screen reader, contrast)
|
|
1649
|
+
13. [ ] Final visual QA against Figma designs
|
|
1650
|
+
14. [ ] Developer handoff documentation finalization
|
|
1651
|
+
|
|
1652
|
+
---
|
|
1653
|
+
|
|
1654
|
+
## References
|
|
1655
|
+
|
|
1656
|
+
- [WCAG 2.1 Quick Reference](https://www.w3.org/WAI/WCAG21/quickref/)
|
|
1657
|
+
- [shadcn/ui Documentation](https://ui.shadcn.com/)
|
|
1658
|
+
- [Radix UI Primitives](https://www.radix-ui.com/)
|
|
1659
|
+
- [Tailwind CSS v4 Documentation](https://tailwindcss.com/docs)
|
|
1660
|
+
- [Lucide React Icons](https://lucide.dev/)
|
|
1661
|
+
- [Pretendard Font](https://github.com/orioncactus/pretendard)
|
|
1662
|
+
- [Inter Font](https://rsms.me/inter/)
|
|
1663
|
+
- [Next.js App Router](https://nextjs.org/docs/app)
|
|
1664
|
+
- Figma Design: [Admin Design System](https://www.figma.com/design/zBw8h8Qv20EnLw0sx4s7si/Admin-Design-System)
|