diff --git a/.cursor/plans/ui_design_modern_ai_chat.plan.md b/.cursor/plans/ui_design_modern_ai_chat.plan.md new file mode 100644 index 00000000..1a10759f --- /dev/null +++ b/.cursor/plans/ui_design_modern_ai_chat.plan.md @@ -0,0 +1,2285 @@ +# Plan: Modern AI Chat UI Design + +## Tổng quan kiến trúc UI + +Dự án sẽ có 2 ứng dụng web chính với design language thống nhất: + +### Web Client (User-facing) + +- **Mục đích**: Chat interface cho end users tương tác với AI +- **Design inspiration**: x.ai Grok, OpenAI ChatGPT +- **Key features**: + - Minimalistic và intuitive + - Dark mode as default với light mode option + - Real-time chat với typing indicators + - Message history và conversation management + - Multi-modal input (text, voice future) + +### Web Admin (Admin-facing) + +- **Mục đích**: Dashboard quản lý users, analytics, system settings +- **Design inspiration**: Modern admin dashboards với AI-powered insights +- **Key features**: + - Analytics dashboard với charts/graphs + - User management với advanced filtering + - System monitoring và health checks + - Content moderation tools + - Configuration management +```mermaid +graph TB + subgraph Design System + Colors[Color Palette
Dark + Light Mode] + Typo[Typography
System Fonts] + Comp[Components
Radix UI] + Icons[Icons
Lucide React] + end + + subgraph Web Client + Auth1[Authentication] + Chat[Chat Interface] + History[Conversation History] + Settings1[User Settings] + end + + subgraph Web Admin + Dashboard[Analytics Dashboard] + Users[User Management] + Monitor[System Monitoring] + Settings2[Admin Settings] + end + + Colors --> Web Client + Colors --> Web Admin + Typo --> Web Client + Typo --> Web Admin + Comp --> Web Client + Comp --> Web Admin + Icons --> Web Client + Icons --> Web Admin +``` + + +## I. Design System Foundation + +### 1.1 Color Palette + +#### Dark Mode (Primary Theme) + +Dựa trên research, dark mode giảm eye strain 67% và là xu hướng chính cho AI chat interfaces. + +**Background Colors:** + +```css +--bg-primary: #0A0A0A /* Main background - Almost black */ +--bg-secondary: #121212 /* Card/Panel background - Dark grey (better depth) */ +--bg-tertiary: #1A1A1A /* Hover states */ +--bg-elevated: #242424 /* Elevated surfaces (modals, dropdowns) */ +``` + +**Text Colors (WCAG Compliant):** + +```css +--text-primary: #FAFAFA /* Primary text - Off-white (4.5:1 contrast) */ +--text-secondary: #E0E0E0 /* Secondary text - Light grey */ +--text-tertiary: #A0A0A0 /* Tertiary/disabled text */ +--text-inverse: #1A1A1A /* Text on light backgrounds */ +``` + +**Brand/Accent Colors:** + +```css +--accent-primary: #3B82F6 /* Primary blue - CTAs, links */ +--accent-secondary: #8B5CF6 /* Purple - Highlights */ +--accent-success: #10B981 /* Green - Success states */ +--accent-warning: #F59E0B /* Amber - Warnings */ +--accent-error: #EF4444 /* Red - Errors */ +--accent-info: #06B6D4 /* Cyan - Info */ +``` + +**Chat Specific Colors:** + +```css +--chat-user-bubble: #2563EB /* User message - Deep blue */ +--chat-ai-bubble: #374151 /* AI message - Dark grey */ +--chat-user-text: #FFFFFF /* White text on blue */ +--chat-ai-text: #F3F4F6 /* Light text on grey */ +--chat-timestamp: #9CA3AF /* Timestamp grey */ +--chat-divider: #1F2937 /* Divider between messages */ +``` + +**Border Colors:** + +```css +--border-primary: #2A2A2A /* Default borders */ +--border-secondary: #3A3A3A /* Hover borders */ +--border-focus: #3B82F6 /* Focus state - Blue */ +``` + +#### Light Mode (Secondary Theme) + +```css +/* Light mode variants */ +--bg-primary-light: #FFFFFF +--bg-secondary-light: #F9FAFB +--bg-tertiary-light: #F3F4F6 +--text-primary-light: #111827 +--text-secondary-light: #4B5563 +--border-primary-light: #E5E7EB +``` + +**Semantic Color Usage:** + +- Primary blue (#3B82F6): CTAs, primary buttons, active states +- Purple (#8B5CF6): Premium features, AI-related highlights +- Success green (#10B981): Confirmations, success messages +- Warning amber (#F59E0B): Warnings, caution states +- Error red (#EF4444): Errors, destructive actions + +### 1.2 Typography + +Theo OpenAI guidelines, sử dụng **system fonts** để ensure readability và accessibility. + +**Font Stack:** + +```css +--font-sans: + -apple-system, + BlinkMacSystemFont, + "SF Pro Display", /* iOS/macOS */ + "Segoe UI", /* Windows */ + Roboto, /* Android */ + "Helvetica Neue", + Arial, + sans-serif; + +--font-mono: + "SF Mono", + Consolas, + "Liberation Mono", + Menlo, + monospace; +``` + +**Type Scale (Tailwind-based):** + +```css +/* Display - Headers */ +--text-6xl: 3.75rem / 1 /* 60px - Hero titles */ +--text-5xl: 3rem / 1 /* 48px - Page titles */ +--text-4xl: 2.25rem / 1.1 /* 36px - Section headers */ +--text-3xl: 1.875rem / 1.2 /* 30px - Card headers */ + +/* Body */ +--text-2xl: 1.5rem / 1.3 /* 24px - Large body */ +--text-xl: 1.25rem / 1.4 /* 20px - Emphasized text */ +--text-lg: 1.125rem / 1.5 /* 18px - Large body */ +--text-base: 1rem / 1.5 /* 16px - Default body */ +--text-sm: 0.875rem / 1.5 /* 14px - Small text */ +--text-xs: 0.75rem / 1.5 /* 12px - Captions */ +``` + +**Font Weights:** + +```css +--font-light: 300 /* Light text */ +--font-normal: 400 /* Body text */ +--font-medium: 500 /* Emphasized */ +--font-semibold: 600 /* Headings */ +--font-bold: 700 /* Strong emphasis */ +``` + +**Chat Typography:** + +- Message text: 16px (text-base), regular weight +- Timestamps: 12px (text-xs), light weight +- User names: 14px (text-sm), medium weight +- System messages: 14px (text-sm), italic + +### 1.3 Spacing & Layout + +**Base Unit: 4px (0.25rem)** + +**Spacing Scale:** + +```css +--space-0: 0 /* 0px */ +--space-1: 0.25rem /* 4px */ +--space-2: 0.5rem /* 8px */ +--space-3: 0.75rem /* 12px */ +--space-4: 1rem /* 16px */ +--space-5: 1.25rem /* 20px */ +--space-6: 1.5rem /* 24px */ +--space-8: 2rem /* 32px */ +--space-10: 2.5rem /* 40px */ +--space-12: 3rem /* 48px */ +--space-16: 4rem /* 64px */ +--space-20: 5rem /* 80px */ +``` + +**Container Widths:** + +```css +--container-sm: 640px /* Small devices */ +--container-md: 768px /* Medium devices */ +--container-lg: 1024px /* Large devices */ +--container-xl: 1280px /* Extra large */ +--container-2xl: 1536px /* 2X large */ + +/* Chat specific */ +--chat-max-width: 768px /* Max width for chat messages */ +--sidebar-width: 280px /* Conversation history sidebar */ +``` + +**Border Radius:** + +```css +--radius-sm: 0.25rem /* 4px - Small elements */ +--radius-md: 0.5rem /* 8px - Buttons, inputs */ +--radius-lg: 0.75rem /* 12px - Cards */ +--radius-xl: 1rem /* 16px - Large cards */ +--radius-2xl: 1.5rem /* 24px - Modals */ +--radius-full: 9999px /* Full round - Avatars, pills */ +``` + +**Shadows (Dark Mode Optimized):** + +```css +--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5); +--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.5); +--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.6); +--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.7); +--shadow-glow: 0 0 20px rgba(59, 130, 246, 0.3); /* Blue glow for focus */ +``` + +### 1.4 Grid System + +**Responsive Breakpoints:** + +```css +--screen-sm: 640px /* Mobile landscape */ +--screen-md: 768px /* Tablet */ +--screen-lg: 1024px /* Desktop */ +--screen-xl: 1280px /* Large desktop */ +--screen-2xl: 1536px /* Extra large desktop */ +``` + +**Layout Patterns:** + +- **Single Column (Mobile)**: < 768px - Full width content +- **Two Column (Tablet)**: 768px - 1024px - Sidebar + Main +- **Three Column (Desktop)**: > 1024px - Sidebar + Main + Panel + +### 1.5 Animation & Transitions + +**Timing Functions:** + +```css +--ease-in: cubic-bezier(0.4, 0, 1, 1); +--ease-out: cubic-bezier(0, 0, 0.2, 1); +--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); +--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); +``` + +**Duration:** + +```css +--duration-fast: 150ms /* Hover effects */ +--duration-normal: 250ms /* Default transitions */ +--duration-slow: 350ms /* Complex animations */ +--duration-slower: 500ms /* Page transitions */ +``` + +**Common Transitions:** + +```css +/* Smooth hover */ +transition: all var(--duration-fast) var(--ease-out); + +/* Button press */ +transition: transform var(--duration-fast) var(--ease-in-out); + +/* Modal open */ +transition: opacity var(--duration-normal) var(--ease-in-out), + transform var(--duration-normal) var(--ease-spring); +``` + +**Micro-interactions (2026 Trend):** + +- Button hover: Subtle scale (1.02) + brightness +- Card hover: Lift effect (translateY -2px) + shadow +- Input focus: Glow effect (box-shadow) + border color +- Message send: Slide up + fade in +- Typing indicator: Pulsing dots animation + +## II. Component Library + +### 2.1 Core Components (Radix UI based) + +#### Button + +**Variants:** + +```typescript +// Primary - Main CTAs + + +// Secondary - Less emphasis + + +// Ghost - Minimal + + +// Danger - Destructive actions + +``` + +**Sizes:** + +- `xs`: 28px height, 12px text, 12px padding +- `sm`: 32px height, 14px text, 16px padding +- `md`: 40px height, 16px text, 20px padding (default) +- `lg`: 48px height, 18px text, 24px padding +- `xl`: 56px height, 20px text, 28px padding + +**States:** + +- Default: Normal appearance +- Hover: Brightness 110%, slight scale (1.02) +- Active: Brightness 90%, scale (0.98) +- Focus: Blue glow shadow +- Disabled: Opacity 50%, cursor not-allowed +- Loading: Spinner icon, disabled state + +**Implementation:** + +```css +/* Primary Button */ +.btn-primary { + background: var(--accent-primary); + color: white; + border-radius: var(--radius-md); + padding: var(--space-3) var(--space-5); + font-weight: var(--font-medium); + transition: all var(--duration-fast) var(--ease-out); +} + +.btn-primary:hover { + filter: brightness(1.1); + transform: scale(1.02); +} + +.btn-primary:focus-visible { + outline: none; + box-shadow: var(--shadow-glow); +} +``` + +#### Input Fields + +**Types:** + +- Text Input +- Textarea +- Select +- Multi-select +- Date Picker +- Search (with icon) + +**Structure:** + +```tsx +
+ + + We'll never share your email +
+``` + +**Styles:** + +```css +.input { + background: var(--bg-secondary); + border: 1px solid var(--border-primary); + color: var(--text-primary); + border-radius: var(--radius-md); + padding: var(--space-3) var(--space-4); + font-size: var(--text-base); + transition: all var(--duration-fast) var(--ease-out); +} + +.input:focus { + border-color: var(--accent-primary); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); + outline: none; +} + +.input::placeholder { + color: var(--text-tertiary); +} + +.input-hint { + color: var(--text-tertiary); + font-size: var(--text-sm); + margin-top: var(--space-1); +} +``` + +**States:** + +- Default +- Focus (blue border + glow) +- Error (red border + error message) +- Success (green border + checkmark) +- Disabled (grey + cursor not-allowed) + +#### Card + +**Variants:** + +```tsx +// Default Card + + + Card Title + Card description + + + Content goes here + + + Footer actions + + + +// Interactive Card (hover effect) + + ... + + +// Bordered Card + + ... + +``` + +**Styles:** + +```css +.card { + background: var(--bg-secondary); + border-radius: var(--radius-lg); + padding: var(--space-6); + transition: all var(--duration-normal) var(--ease-out); +} + +.card.hover:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-lg); +} + +.card-header { + margin-bottom: var(--space-4); +} + +.card-title { + font-size: var(--text-xl); + font-weight: var(--font-semibold); + color: var(--text-primary); +} + +.card-description { + font-size: var(--text-sm); + color: var(--text-secondary); + margin-top: var(--space-1); +} +``` + +#### Modal/Dialog + +**Structure:** + +```tsx + + + + + + + Dialog Title + + Dialog description text + + +
+ {/* Content */} +
+ + + + +
+
+``` + +**Animation:** + +```css +/* Overlay fade in */ +@keyframes overlay-fade { + from { opacity: 0; } + to { opacity: 1; } +} + +/* Content scale + fade */ +@keyframes content-show { + from { + opacity: 0; + transform: translate(-50%, -48%) scale(0.96); + } + to { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } +} + +.dialog-overlay { + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(8px); + animation: overlay-fade var(--duration-normal) var(--ease-out); +} + +.dialog-content { + background: var(--bg-elevated); + border-radius: var(--radius-2xl); + box-shadow: var(--shadow-xl); + animation: content-show var(--duration-normal) var(--ease-spring); +} +``` + +#### Avatar + +**Sizes:** + +- `xs`: 24px +- `sm`: 32px +- `md`: 40px (default) +- `lg`: 48px +- `xl`: 64px + +**States:** + +- Image loaded +- Fallback (initials) +- Loading (skeleton) +- Status indicator (online/offline/away) +```tsx + + + JD + +``` + + +### 2.2 Chat-Specific Components + +#### Message Bubble + +**Structure:** + +```tsx +
+
+ You + 2:30 PM +
+
+

Hello, how can I help you?

+
+
+ +
+ +
+
+ AI Assistant + 2:31 PM +
+
+

I can help you with...

+
+
+
+``` + +**Styles:** + +```css +/* User Message (Right aligned, blue) */ +.message.user { + display: flex; + flex-direction: column; + align-items: flex-end; + margin-bottom: var(--space-4); +} + +.message.user .message-bubble { + background: var(--chat-user-bubble); + color: var(--chat-user-text); + border-radius: var(--radius-lg) var(--radius-lg) var(--radius-sm) var(--radius-lg); + padding: var(--space-3) var(--space-4); + max-width: 70%; + word-wrap: break-word; +} + +/* AI Message (Left aligned, grey) */ +.message.ai { + display: flex; + gap: var(--space-3); + margin-bottom: var(--space-4); +} + +.message.ai .message-bubble { + background: var(--chat-ai-bubble); + color: var(--chat-ai-text); + border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) var(--radius-sm); + padding: var(--space-3) var(--space-4); + max-width: 70%; +} + +/* Message Header */ +.message-header { + display: flex; + align-items: center; + gap: var(--space-2); + margin-bottom: var(--space-1); +} + +.message-author { + font-size: var(--text-sm); + font-weight: var(--font-medium); + color: var(--text-secondary); +} + +.message-time { + font-size: var(--text-xs); + color: var(--chat-timestamp); +} +``` + +**Message Animations:** + +```css +/* Slide up + fade in */ +@keyframes message-in { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.message { + animation: message-in var(--duration-normal) var(--ease-out); +} +``` + +#### Typing Indicator + +```tsx +
+
+
+
+
+``` +```css +.typing-indicator { + display: flex; + gap: 4px; + padding: var(--space-3); +} + +.typing-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--text-tertiary); + animation: typing 1.4s infinite; +} + +.typing-dot:nth-child(2) { + animation-delay: 0.2s; +} + +.typing-dot:nth-child(3) { + animation-delay: 0.4s; +} + +@keyframes typing { + 0%, 60%, 100% { + opacity: 0.3; + transform: scale(0.8); + } + 30% { + opacity: 1; + transform: scale(1); + } +} +``` + +#### Chat Input + +```tsx +
+
+ + +