+
{/* 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() {