feat: Cải thiện giao diện trang chủ với thành phần Banner thông báo, cập nhật cấu trúc điều hướng và tối ưu hóa màu sắc cho phong cách tối giản.

This commit is contained in:
Ho Ngoc Hai
2026-01-04 18:15:36 +07:00
parent f989a2f7d7
commit d404689531
4 changed files with 357 additions and 211 deletions

View File

@@ -0,0 +1,94 @@
'use client';
import React from 'react';
import { X } from 'lucide-react';
import { Button } from '@/features/shared/components/ui/button';
/**
* EN: Announcement Banner props
* VI: Props cho Announcement Banner
*/
export interface AnnouncementBannerProps {
/** Announcement title / Tiêu đề thông báo */
title: string;
/** Announcement description / Mô tả thông báo */
description: string;
/** Link text / Text link */
linkText: string;
/** Link URL / URL link */
linkUrl: string;
/** Show close button / Hiển thị button đóng */
showClose?: boolean;
/** On close callback / Callback khi đóng */
onClose?: () => void;
/** Additional CSS classes / CSS classes bổ sung */
className?: string;
}
/**
* EN: Announcement Banner - Clean banner for news/announcements (x.ai style)
* VI: Announcement Banner - Banner sạch sẽ cho tin tức/thông báo (phong cách x.ai)
*
* @example
* ```tsx
* <AnnouncementBanner
* title="New Feature Released"
* description="Check out our latest AI capabilities"
* linkText="Learn more"
* linkUrl="/news"
* />
* ```
*/
export function AnnouncementBanner({
title,
description,
linkText,
linkUrl,
showClose = false,
onClose,
className,
}: AnnouncementBannerProps) {
return (
<div className={`bg-black/40 backdrop-blur-sm border-b border-white/5 ${className}`}>
<div className="container mx-auto px-6">
<div className="flex items-center justify-between py-3">
<div className="flex items-center space-x-4">
<div className="flex items-center space-x-2">
<span className="text-xs text-text-tertiary uppercase tracking-wider font-medium">
News
</span>
</div>
<div className="hidden sm:block w-px h-4 bg-white/20" />
<div className="flex items-center space-x-3">
<h3 className="text-sm font-medium text-white">
{title}
</h3>
<span className="text-xs text-text-secondary">
{description}
</span>
</div>
</div>
<div className="flex items-center space-x-4">
<a
href={linkUrl}
className="text-xs text-text-secondary hover:text-white transition-colors underline"
>
{linkText}
</a>
{showClose && onClose && (
<Button
variant="ghost"
size="sm"
onPress={onClose}
className="p-1 h-auto hover:bg-white/10"
>
<X className="h-3 w-3" />
</Button>
)}
</div>
</div>
</div>
</div>
);
}

View File

@@ -24,76 +24,82 @@ export interface NavigationHeaderProps {
}
/**
* EN: Navigation Header - Responsive header with brand logo, theme toggle, and language switcher
* VI: Navigation Header - Header responsive với logo, theme toggle và language switcher
*
* EN: Navigation Header - Clean x.ai style navigation
* VI: Navigation Header - Navigation theo phong cách x.ai sạch sẽ
*
* Features:
* - Sticky header with glassmorphism
* - Responsive design (mobile menu)
* - Brand logo integration
* - Theme toggle
* - Language switcher
* - Clean minimal design
* - Navigation menu items
* - CTA button
*
* - Responsive design
*
* @example
* ```tsx
* <NavigationHeader
* showCTA
* ctaText="Get Started"
* onCTAClick={() => router.push('/auth/login')}
* />
* <NavigationHeader />
* ```
*/
export function NavigationHeader({
showCTA = true,
ctaText = 'Get Started',
onCTAClick,
className,
}: NavigationHeaderProps) {
export function NavigationHeader({ className }: { className?: string }) {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const navItems = [
{ name: 'Grok', href: '/chat' },
{ name: 'API', href: '/api' },
{ name: 'Company', href: '/company' },
{ name: 'Careers', href: '/careers' },
{ name: 'News', href: '/news' },
];
return (
<header
className={cn(
'sticky top-0 z-50 w-full border-b border-white/10',
'bg-bg-primary/30 backdrop-blur-2xl',
'sticky top-0 z-50 w-full border-b border-white/5',
'bg-black/20 backdrop-blur-sm',
'transition-all duration-normal',
className
)}
>
<div className="container mx-auto px-4">
<div className="container mx-auto px-6">
{/* EN: Main header content / VI: Nội dung header chính */}
<div className="flex h-16 items-center justify-between">
<div className="flex h-14 items-center justify-between">
{/* EN: Logo / VI: Logo */}
<BrandLogoLink variant="wordmark" size="sm" href="/" />
{/* EN: Desktop Navigation / VI: Navigation desktop */}
<nav className="hidden md:flex items-center gap-4">
<ThemeToggle />
<LanguageSwitcher />
{showCTA && (
<Button
variant="brand"
size="md"
onPress={onCTAClick}
className="ml-2"
<nav className="hidden md:flex items-center space-x-8">
{navItems.map((item) => (
<a
key={item.name}
href={item.href}
className="text-text-secondary hover:text-white transition-colors text-sm font-medium"
>
{ctaText}
</Button>
)}
{item.name}
</a>
))}
</nav>
{/* EN: CTA Button / VI: Button CTA */}
<div className="hidden md:flex items-center">
<Button
variant="ghost"
size="sm"
onPress={() => window.location.href = '/chat'}
className="text-white border border-white/20 hover:bg-white/10 transition-all"
>
Try Grok
</Button>
</div>
{/* EN: Mobile Menu Button / VI: Button menu mobile */}
<button
className="md:hidden p-2 hover:bg-bg-tertiary rounded-md transition-colors"
className="md:hidden p-2 hover:bg-white/5 rounded-md transition-colors"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
aria-label="Toggle mobile menu"
aria-expanded={mobileMenuOpen}
>
{mobileMenuOpen ? (
<X className="h-6 w-6" />
<X className="h-5 w-5 text-white" />
) : (
<Menu className="h-6 w-6" />
<Menu className="h-5 w-5 text-white" />
)}
</button>
</div>
@@ -101,27 +107,33 @@ export function NavigationHeader({
{/* EN: Mobile Menu / VI: Menu mobile */}
{mobileMenuOpen && (
<div
className="md:hidden py-4 space-y-4 border-t border-border-primary animate-fadeIn"
className="md:hidden py-4 space-y-4 border-t border-white/5 animate-fadeIn"
role="navigation"
aria-label="Mobile navigation"
>
<div className="flex items-center justify-between gap-4">
<ThemeToggle />
<LanguageSwitcher />
</div>
{showCTA && (
<Button
variant="brand"
size="lg"
onPress={() => {
onCTAClick?.();
setMobileMenuOpen(false);
}}
className="w-full"
>
{ctaText}
</Button>
)}
<nav className="flex flex-col space-y-4">
{navItems.map((item) => (
<a
key={item.name}
href={item.href}
className="text-text-secondary hover:text-white transition-colors text-sm font-medium py-2"
onClick={() => setMobileMenuOpen(false)}
>
{item.name}
</a>
))}
</nav>
<Button
variant="ghost"
size="sm"
onPress={() => {
window.location.href = '/chat';
setMobileMenuOpen(false);
}}
className="text-white border border-white/20 hover:bg-white/10 transition-all w-full mt-4"
>
Try Grok
</Button>
</div>
)}
</div>