From 5c7c6cc9993b7b66c32241c4313896da26a6c347 Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Mon, 5 Jan 2026 18:51:49 +0700 Subject: [PATCH] =?UTF-8?q?feat:=20Th=C3=AAm=20trang=20Mood=20Board=20m?= =?UTF-8?q?=E1=BB=9Bi=20v=C3=A0=20c=E1=BA=ADp=20nh=E1=BA=ADt=20giao=20di?= =?UTF-8?q?=E1=BB=87n=20ng=C6=B0=E1=BB=9Di=20d=C3=B9ng,=20=C4=91=E1=BB=93n?= =?UTF-8?q?g=20th=E1=BB=9Di=20lo=E1=BA=A1i=20b=E1=BB=8F=20c=C3=A1c=20scrip?= =?UTF-8?q?t=20c=C5=A9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/(auth)/forgot-password/page.tsx | 7 +- apps/web-client/src/app/(auth)/login/page.tsx | 5 +- .../src/app/(auth)/register/page.tsx | 15 +- apps/web-client/src/app/mood-board/page.tsx | 56 ++ .../mood-board/sections/ButtonsSection.tsx | 113 +++ .../sections/ColorPaletteSection.tsx | 83 ++ .../sections/GlassEffectsSection.tsx | 133 ++++ .../mood-board/sections/SpacingSection.tsx | 95 +++ .../mood-board/sections/TypographySection.tsx | 101 +++ .../features/auth/components/auth-card.tsx | 15 +- .../mood-board/components/CodeBlock.tsx | 42 + .../mood-board/components/ColorSwatch.tsx | 31 + .../components/ComponentShowcase.tsx | 64 ++ .../mood-board/components/SectionWrapper.tsx | 39 + .../shared/components/ui/button/button.tsx | 14 +- .../shared/components/ui/input/input.tsx | 14 +- .../theme/components/language-switcher.tsx | 4 +- .../components/theme-toggle-enhanced.tsx | 4 +- apps/web-client/src/styles/glass.css | 25 + apps/web-client/src/styles/theme.css | 726 +++++++++--------- scripts/add-error-imports.py | 67 -- scripts/add-error-imports.sh | 42 - scripts/final-cleanup.py | 105 --- scripts/fix-bilingual-docs.py | 154 ---- scripts/fix-bilingual-docs.sh | 138 ---- 25 files changed, 1192 insertions(+), 900 deletions(-) create mode 100644 apps/web-client/src/app/mood-board/page.tsx create mode 100644 apps/web-client/src/app/mood-board/sections/ButtonsSection.tsx create mode 100644 apps/web-client/src/app/mood-board/sections/ColorPaletteSection.tsx create mode 100644 apps/web-client/src/app/mood-board/sections/GlassEffectsSection.tsx create mode 100644 apps/web-client/src/app/mood-board/sections/SpacingSection.tsx create mode 100644 apps/web-client/src/app/mood-board/sections/TypographySection.tsx create mode 100644 apps/web-client/src/features/mood-board/components/CodeBlock.tsx create mode 100644 apps/web-client/src/features/mood-board/components/ColorSwatch.tsx create mode 100644 apps/web-client/src/features/mood-board/components/ComponentShowcase.tsx create mode 100644 apps/web-client/src/features/mood-board/components/SectionWrapper.tsx delete mode 100644 scripts/add-error-imports.py delete mode 100755 scripts/add-error-imports.sh delete mode 100644 scripts/final-cleanup.py delete mode 100644 scripts/fix-bilingual-docs.py delete mode 100755 scripts/fix-bilingual-docs.sh diff --git a/apps/web-client/src/app/(auth)/forgot-password/page.tsx b/apps/web-client/src/app/(auth)/forgot-password/page.tsx index 44453ba2..964a2cc4 100644 --- a/apps/web-client/src/app/(auth)/forgot-password/page.tsx +++ b/apps/web-client/src/app/(auth)/forgot-password/page.tsx @@ -117,7 +117,7 @@ export default function ForgotPasswordPage() { -
+
@@ -239,6 +239,7 @@ export default function ForgotPasswordPage() { -
+
(
- {/* EN: Submit button with loading state / VI: Nút submit với trạng thái loading */} diff --git a/apps/web-client/src/app/mood-board/page.tsx b/apps/web-client/src/app/mood-board/page.tsx new file mode 100644 index 00000000..726112cc --- /dev/null +++ b/apps/web-client/src/app/mood-board/page.tsx @@ -0,0 +1,56 @@ +/** + * EN: Mood Board - Design System Showcase + * VI: Mood Board - Showcase Design System + * + * A comprehensive showcase of all UI components and design tokens + * Một trang showcase toàn diện cho tất cả UI components và design tokens + */ +import { Metadata } from 'next'; +import { ThemeToggle } from '@/features/theme/components/theme-toggle-enhanced'; +import TypographySection from './sections/TypographySection'; +import ColorPaletteSection from './sections/ColorPaletteSection'; +import SpacingSection from './sections/SpacingSection'; +import GlassEffectsSection from './sections/GlassEffectsSection'; +import ButtonsSection from './sections/ButtonsSection'; + +export const metadata: Metadata = { + title: 'Mood Board | Design System Showcase', + description: 'Comprehensive showcase of all UI components and design tokens', +}; + +export default function MoodBoardPage() { + return ( +
+ {/* EN: Header with sticky navigation / VI: Header với navigation sticky */} +
+
+
+

+ Mood Board +

+

+ Design System Showcase - All Components & Tokens +

+
+ + {/* EN: Theme Toggle / VI: Theme Toggle */} + +
+
+ + {/* EN: Main content with all sections / VI: Nội dung chính với tất cả sections */} +
+ + + + + +
+ + {/* EN: Footer / VI: Footer */} +
+

Design System v1.0.0 - X.ai Minimalist Theme

+
+
+ ); +} diff --git a/apps/web-client/src/app/mood-board/sections/ButtonsSection.tsx b/apps/web-client/src/app/mood-board/sections/ButtonsSection.tsx new file mode 100644 index 00000000..5a8c6376 --- /dev/null +++ b/apps/web-client/src/app/mood-board/sections/ButtonsSection.tsx @@ -0,0 +1,113 @@ +/** + * EN: Buttons Section - All button variants + * VI: Buttons Section - Tất cả button variants + */ +import SectionWrapper from '@/features/mood-board/components/SectionWrapper'; +import ComponentShowcase from '@/features/mood-board/components/ComponentShowcase'; + +export default function ButtonsSection() { + return ( + + {/* EN: Glass Buttons / VI: Glass Buttons */} + Default Glass +`} + darkBg + > +
+ + + +
+
+ + {/* EN: Primary Buttons / VI: Primary Buttons */} + + Primary Action +`} + > +
+ + +
+
+ + {/* EN: Secondary Buttons / VI: Secondary Buttons */} + + Secondary Action +`} + > +
+ + +
+
+ + {/* EN: Button Sizes / VI: Button Sizes */} + Small + +`} + darkBg + > +
+ + + + +
+
+ + {/* EN: Icon Buttons / VI: Icon Buttons */} + + × +`} + darkBg + > +
+ + + + +
+
+
+ ); +} diff --git a/apps/web-client/src/app/mood-board/sections/ColorPaletteSection.tsx b/apps/web-client/src/app/mood-board/sections/ColorPaletteSection.tsx new file mode 100644 index 00000000..6420c843 --- /dev/null +++ b/apps/web-client/src/app/mood-board/sections/ColorPaletteSection.tsx @@ -0,0 +1,83 @@ +/** + * EN: Color Palette Section - All design token colors + * VI: Color Palette Section - Tất cả color tokens từ design system + */ +import SectionWrapper from '@/features/mood-board/components/SectionWrapper'; +import ColorSwatch from '@/features/mood-board/components/ColorSwatch'; + +export default function ColorPaletteSection() { + return ( + + {/* EN: Background Colors / VI: Màu nền */} +
+

+ Background Colors +

+
+ + + + +
+
+ + {/* EN: Text Colors / VI: Màu chữ */} +
+

+ Text Colors (WCAG Compliant) +

+
+ + + + +
+
+ + {/* EN: Accent Colors / VI: Màu accent */} +
+

+ Accent Colors (X.ai Brand) +

+
+ + + + + +
+
+ + {/* EN: Border Colors / VI: Màu viền */} +
+

+ Border Colors +

+
+ + + +
+
+ + {/* EN: Chat Colors / VI: Màu chat */} +
+

+ Chat Specific Colors +

+
+ + + +
+
+
+ ); +} diff --git a/apps/web-client/src/app/mood-board/sections/GlassEffectsSection.tsx b/apps/web-client/src/app/mood-board/sections/GlassEffectsSection.tsx new file mode 100644 index 00000000..8042f644 --- /dev/null +++ b/apps/web-client/src/app/mood-board/sections/GlassEffectsSection.tsx @@ -0,0 +1,133 @@ +/** + * EN: Glass Effects Section - All glassmorphism utilities + * VI: Glass Effects Section - Tất cả glassmorphism utilities + */ +import SectionWrapper from '@/features/mood-board/components/SectionWrapper'; +import ComponentShowcase from '@/features/mood-board/components/ComponentShowcase'; + +export default function GlassEffectsSection() { + return ( + + {/* EN: Glass Card / VI: Glass Card */} + +

Glass Card

+

Ultra-minimal glassmorphism effect

+
`} + darkBg + > +
+

+ Glass Card +

+

+ Ultra-minimal glassmorphism effect with 4% opacity background and 8px + blur. +

+
+ + + {/* EN: Glass Variants / VI: Glass Variants */} + Subtle (1% bg, 4px blur)
+
Default (4% bg, 8px blur)
+
Strong (5% bg, 12px blur)
`} + darkBg + > +
+
+

+ Glass Subtle +

+

+ 1% bg, 4px blur +

+
+
+

+ Glass Card (Default) +

+

+ 4% bg, 8px blur +

+
+
+

+ Glass Strong +

+

+ 5% bg, 12px blur +

+
+
+ + + {/* EN: Glass Button / VI: Glass Button */} + + Click Me +`} + darkBg + > +
+ + + +
+
+ + {/* EN: Glass Input / VI: Glass Input */} + `} + darkBg + > +
+ + +
+
+ + {/* EN: Glass Badge / VI: Glass Badge */} + Design +Development`} + darkBg + > +
+ Design + Development + X.ai Minimal + Glassmorphism +
+
+ + ); +} diff --git a/apps/web-client/src/app/mood-board/sections/SpacingSection.tsx b/apps/web-client/src/app/mood-board/sections/SpacingSection.tsx new file mode 100644 index 00000000..43cd8922 --- /dev/null +++ b/apps/web-client/src/app/mood-board/sections/SpacingSection.tsx @@ -0,0 +1,95 @@ +/** + * EN: Spacing Section - Spacing scale and layout tokens + * VI: Spacing Section - Spacing scale và layout tokens + */ +import SectionWrapper from '@/features/mood-board/components/SectionWrapper'; +import ComponentShowcase from '@/features/mood-board/components/ComponentShowcase'; + +export default function SpacingSection() { + return ( + + {/* EN: Spacing Scale / VI: Spacing Scale */} + 0.25rem (4px)
+
0.5rem (8px)
+
1rem (16px)
+
2rem (32px)
`} + > +
+ {[ + { name: '--space-0', value: '0', px: '0px' }, + { name: '--space-1', value: '0.25rem', px: '4px' }, + { name: '--space-2', value: '0.5rem', px: '8px' }, + { name: '--space-3', value: '0.75rem', px: '12px' }, + { name: '--space-4', value: '1rem', px: '16px' }, + { name: '--space-5', value: '1.25rem', px: '20px' }, + { name: '--space-6', value: '1.5rem', px: '24px' }, + { name: '--space-8', value: '2rem', px: '32px' }, + { name: '--space-10', value: '2.5rem', px: '40px' }, + { name: '--space-12', value: '3rem', px: '48px' }, + { name: '--space-16', value: '4rem', px: '64px' }, + { name: '--space-20', value: '5rem', px: '80px' }, + ].map((token) => ( +
+
+
+ + {token.name} + + + {token.value} ({token.px}) + +
+
+ ))} +
+ + + {/* EN: Border Radius / VI: Border Radius */} + 2px - Sharp
+
4px - Buttons
+
8px - Cards
+
9999px - Avatars
`} + > +
+ {[ + { name: '--radius-sm', value: '2px', class: 'rounded-sm' }, + { name: '--radius-md', value: '4px', class: 'rounded-md' }, + { name: '--radius-lg', value: '8px', class: 'rounded-lg' }, + { name: '--radius-xl', value: '12px', class: 'rounded-xl' }, + { name: '--radius-2xl', value: '16px', class: 'rounded-2xl' }, + { name: '--radius-full', value: '9999px', class: 'rounded-full' }, + ].map((radius) => ( +
+
+

+ {radius.name} +

+ + {radius.value} + +
+ ))} +
+ + + ); +} diff --git a/apps/web-client/src/app/mood-board/sections/TypographySection.tsx b/apps/web-client/src/app/mood-board/sections/TypographySection.tsx new file mode 100644 index 00000000..dc0f9901 --- /dev/null +++ b/apps/web-client/src/app/mood-board/sections/TypographySection.tsx @@ -0,0 +1,101 @@ +/** + * EN: Typography Section - Font scales, weights, letter spacing showcase + * VI: Typography Section - Showcase font scales, weights, letter spacing + */ +import SectionWrapper from '@/features/mood-board/components/SectionWrapper'; +import ComponentShowcase from '@/features/mood-board/components/ComponentShowcase'; + +export default function TypographySection() { + return ( + + {/* EN: Font Sizes / VI: Font Sizes */} + Hero Title (56px) +

Page Title (44px)

+

Section Header (36px)

+

Body Text (16px)

+Caption (12px)`} + > +
+

+ Hero Title (--text-6xl) +

+

+ Page Title (--text-5xl) +

+

+ Section Header (--text-4xl) +

+

+ Card Header (--text-3xl) +

+

Large Body (--text-2xl)

+

Emphasized (--text-xl)

+

Large Body (--text-lg)

+

+ Default Body (--text-base) +

+

Small Text (--text-sm)

+

Caption (--text-xs)

+
+
+ + {/* EN: Font Weights / VI: Font Weights */} + Thin (100)

+

Light (300)

+

Normal (400)

+

Medium (500)

+

Semibold (600)

+

Bold (700)

+

Extra Bold (800)

+

Black (900)

`} + > +
+

Thin (--font-thin: 100)

+

+ Extra Light (--font-extralight: 200) +

+

Light (--font-light: 300)

+

Normal (--font-normal: 400)

+

Medium (--font-medium: 500)

+

Semibold (--font-semibold: 600)

+

Bold (--font-bold: 700)

+

Extra Bold (--font-extrabold: 800)

+

Black (--font-black: 900)

+
+
+ + {/* EN: Letter Spacing / VI: Letter Spacing */} + Very Tight (-0.04em)

+

Tight (-0.02em)

+

Normal (0)

+

Wide (0.02em)

+

Wider (0.04em)

`} + > +
+

+ Very Tight (--tracking-tighter: -0.04em) +

+

+ Tight (--tracking-tight: -0.02em) +

+

Normal (--tracking-normal: 0)

+

Wide (--tracking-wide: 0.02em)

+

Wider (--tracking-wider: 0.04em)

+
+
+
+ ); +} diff --git a/apps/web-client/src/features/auth/components/auth-card.tsx b/apps/web-client/src/features/auth/components/auth-card.tsx index 6abc371c..14c82207 100644 --- a/apps/web-client/src/features/auth/components/auth-card.tsx +++ b/apps/web-client/src/features/auth/components/auth-card.tsx @@ -25,7 +25,7 @@ export function AuthCard({ }: AuthCardProps) { return (
-
+
{/* EN: Logo & Header / VI: Logo & Tiêu đề */}
@@ -48,16 +48,9 @@ export function AuthCard({ {children} {footer && ( - <> -
- -
-
- {footer} -
- +
+ {footer} +
)}
diff --git a/apps/web-client/src/features/mood-board/components/CodeBlock.tsx b/apps/web-client/src/features/mood-board/components/CodeBlock.tsx new file mode 100644 index 00000000..adedbcef --- /dev/null +++ b/apps/web-client/src/features/mood-board/components/CodeBlock.tsx @@ -0,0 +1,42 @@ +/** + * EN: Code block with syntax highlighting and copy-to-clipboard + * VI: Code block với syntax highlighting và copy-to-clipboard + * + * Displays formatted code with copy functionality + * Hiển thị code đã format với tính năng copy + */ +'use client'; + +import { useState } from 'react'; + +interface CodeBlockProps { + code: string; + language: string; +} + +export default function CodeBlock({ code, language }: CodeBlockProps) { + const [copied, setCopied] = useState(false); + + const handleCopy = async () => { + await navigator.clipboard.writeText(code); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + return ( +
+ {/* EN: Copy Button / VI: Nút copy */} + + + {/* EN: Code Display / VI: Hiển thị code */} +
+                {code}
+            
+
+ ); +} diff --git a/apps/web-client/src/features/mood-board/components/ColorSwatch.tsx b/apps/web-client/src/features/mood-board/components/ColorSwatch.tsx new file mode 100644 index 00000000..0211bc47 --- /dev/null +++ b/apps/web-client/src/features/mood-board/components/ColorSwatch.tsx @@ -0,0 +1,31 @@ +/** + * EN: Color swatch component to display CSS variable colors + * VI: Component color swatch để hiển thị màu từ CSS variable + * + * Shows color preview with variable name and value + * Hiển thị preview màu với tên biến và giá trị + */ +'use client'; + +interface ColorSwatchProps { + name: string; + var: string; +} + +export default function ColorSwatch({ name, var: cssVar }: ColorSwatchProps) { + return ( +
+ {/* EN: Color Preview Box / VI: Hộp preview màu */} +
+ + {/* EN: Color Variable Name / VI: Tên biến màu */} +

{name}

+ + {/* EN: CSS Variable / VI: CSS Variable */} + {cssVar} +
+ ); +} diff --git a/apps/web-client/src/features/mood-board/components/ComponentShowcase.tsx b/apps/web-client/src/features/mood-board/components/ComponentShowcase.tsx new file mode 100644 index 00000000..bfe4a98e --- /dev/null +++ b/apps/web-client/src/features/mood-board/components/ComponentShowcase.tsx @@ -0,0 +1,64 @@ +/** + * EN: Component showcase wrapper with code preview + * VI: Wrapper showcase component kèm code preview + * + * Displays component demo with optional code snippet + * Hiển thị demo component với tùy chọn xem code snippet + */ +'use client'; + +import { useState } from 'react'; +import CodeBlock from './CodeBlock'; + +interface ComponentShowcaseProps { + title: string; + description?: string; + code: string; + children: React.ReactNode; + darkBg?: boolean; // EN: For light components on dark background / VI: Cho light components trên dark background +} + +export default function ComponentShowcase({ + title, + description, + code, + children, + darkBg = false, +}: ComponentShowcaseProps) { + const [showCode, setShowCode] = useState(false); + + return ( +
+ {/* EN: Title and description / VI: Tiêu đề và mô tả */} +
+

{title}

+ {description && ( +

{description}

+ )} +
+ + {/* EN: Component Preview Area / VI: Khu vực preview component */} +
+ {children} +
+ + {/* EN: Toggle Code Button / VI: Nút toggle code */} + + + {/* EN: Code Block / VI: Code block */} + {showCode && ( +
+ +
+ )} +
+ ); +} diff --git a/apps/web-client/src/features/mood-board/components/SectionWrapper.tsx b/apps/web-client/src/features/mood-board/components/SectionWrapper.tsx new file mode 100644 index 00000000..7949335b --- /dev/null +++ b/apps/web-client/src/features/mood-board/components/SectionWrapper.tsx @@ -0,0 +1,39 @@ +/** + * EN: Section wrapper component for Mood Board sections + * VI: Component wrapper cho các sections của Mood Board + * + * Provides consistent layout and styling for each section + * Cung cấp layout và styling nhất quán cho mỗi section + */ +import React from 'react'; + +interface SectionWrapperProps { + id: string; + title: string; + description?: string; + children: React.ReactNode; +} + +export default function SectionWrapper({ + id, + title, + description, + children, +}: SectionWrapperProps) { + return ( +
+ {/* EN: Section Header / VI: Header của section */} +
+

+ {title} +

+ {description && ( +

{description}

+ )} +
+ + {/* EN: Section Content / VI: Nội dung section */} +
{children}
+
+ ); +} diff --git a/apps/web-client/src/features/shared/components/ui/button/button.tsx b/apps/web-client/src/features/shared/components/ui/button/button.tsx index cbfb5707..8b8bc66e 100644 --- a/apps/web-client/src/features/shared/components/ui/button/button.tsx +++ b/apps/web-client/src/features/shared/components/ui/button/button.tsx @@ -79,13 +79,15 @@ const buttonVariants = cva( 'shadow-glass-md hover:shadow-glass-lg', 'hover:bg-glass-hover', ], - // Brand (X.ai blue - solid color, no gradient) + // Brand (Subtle dark glass - X.ai minimal) brand: [ - 'bg-accent-primary text-white', - 'shadow-md hover:shadow-lg', - 'hover:bg-accent-primary-hover', - 'transition-colors duration-quick', - 'focus-visible:ring-2 focus-visible:ring-accent-primary/30', + 'bg-[#1f2f3d]/95 text-white', + 'backdrop-blur-glass border border-white/10', + 'shadow-[0_2px_8px_rgba(0,0,0,0.4),inset_0_1px_1px_rgba(255,255,255,0.1)]', + 'hover:bg-[#243442] hover:border-white/15', + 'hover:shadow-[0_4px_12px_rgba(0,0,0,0.5),inset_0_1px_1px_rgba(255,255,255,0.15)]', + 'transition-all duration-quick', + 'focus-visible:ring-2 focus-visible:ring-white/20', 'focus-visible:ring-offset-2 focus-visible:ring-offset-bg-primary', ], }, diff --git a/apps/web-client/src/features/shared/components/ui/input/input.tsx b/apps/web-client/src/features/shared/components/ui/input/input.tsx index afa751ba..132a87f4 100644 --- a/apps/web-client/src/features/shared/components/ui/input/input.tsx +++ b/apps/web-client/src/features/shared/components/ui/input/input.tsx @@ -53,6 +53,12 @@ export interface InputProps extends Omit { */ type?: 'text' | 'email' | 'password' | 'search' | 'tel' | 'url' | 'number'; + /** + * Input variant + * @default 'glass' + */ + variant?: 'glass' | 'solid'; + /** * Custom className for the container */ @@ -121,6 +127,7 @@ export const Input = React.forwardRef( errorMessage, placeholder, type = 'text', + variant = 'glass', className, inputClassName, leftElement, @@ -194,8 +201,8 @@ export const Input = React.forwardRef( type={inputType} placeholder={placeholder} className={cn( - // Base glass input styles - 'glass-input', + // Base input styles + variant === 'glass' ? 'glass-input' : 'solid-input', 'w-full rounded-xl px-3 py-2', 'text-base text-text-primary placeholder:text-text-tertiary', 'transition-all duration-quick ease-smooth', @@ -203,7 +210,8 @@ export const Input = React.forwardRef( // Focus state with X.ai blue ring (X.ai Minimal Design) 'focus:outline-none focus:ring-2 focus:ring-offset-2', 'focus:ring-accent-primary/30 focus:ring-offset-bg-primary', - 'focus:bg-glass focus:border-accent-primary', + variant === 'glass' && 'focus:bg-glass focus:border-accent-primary', + variant === 'solid' && 'focus:bg-bg-primary focus:border-accent-primary', // Invalid state 'data-[invalid]:border-accent-error', diff --git a/apps/web-client/src/features/theme/components/language-switcher.tsx b/apps/web-client/src/features/theme/components/language-switcher.tsx index 1ddff76b..22cdb8dc 100644 --- a/apps/web-client/src/features/theme/components/language-switcher.tsx +++ b/apps/web-client/src/features/theme/components/language-switcher.tsx @@ -55,7 +55,7 @@ export function LanguageSwitcher() {