refact: update ui

This commit is contained in:
2026-03-25 14:06:37 +08:00
parent 276160d769
commit d13cb64567
28 changed files with 2451 additions and 250 deletions

View File

@@ -8,6 +8,7 @@ export default function MarketingNavbar() {
const location = useLocation();
const [showLangMenu, setShowLangMenu] = useState(false);
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const [scrolled, setScrolled] = useState(false);
const langMenuRef = useRef<HTMLDivElement>(null);
const isHome = location.pathname === '/';
@@ -34,53 +35,73 @@ export default function MarketingNavbar() {
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
useEffect(() => {
const handleScroll = () => setScrolled(window.scrollY > 10);
window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return (
<nav className="h-16 bg-white border-b border-gray-200 flex items-center justify-between px-6 flex-shrink-0 z-[60] relative">
<Link to="/" className="flex items-center gap-2">
<img src="/texpixel-app-icon.svg" alt="TexPixel" className="w-8 h-8" />
<span className="text-xl font-bold text-gray-900 tracking-tight">TexPixel</span>
<nav
className={`h-16 flex items-center justify-between px-6 flex-shrink-0 z-[60] relative transition-all duration-300 ${
scrolled
? 'bg-white/90 backdrop-blur-md border-b border-cream-300 shadow-sm'
: 'bg-transparent border-b border-transparent'
}`}
>
<Link to="/" className="flex items-center gap-2.5 group">
<img src="/texpixel-app-icon.svg" alt="TexPixel" className="w-8 h-8 transition-transform group-hover:scale-110 duration-200" />
<span className="text-xl font-display font-bold text-ink tracking-tight">TexPixel</span>
</Link>
<div className="hidden md:flex items-center gap-6">
{navLinks.map((link) => (
<Link
key={link.to}
to={link.to}
className={`text-sm font-medium transition-colors ${
location.pathname === link.to ? 'text-blue-600' : 'text-gray-700 hover:text-gray-900'
}`}
>
{link.label}
</Link>
))}
<div className="hidden md:flex items-center gap-1">
{navLinks.map((link) => {
const isActive = location.pathname === link.to;
return (
<Link
key={link.to}
to={link.to}
className={`relative px-4 py-2 text-sm font-medium rounded-lg transition-colors duration-200 ${
isActive
? 'text-coral-600 bg-coral-50'
: 'text-ink-secondary hover:text-ink hover:bg-cream-200/60'
}`}
>
{link.label}
</Link>
);
})}
{anchorLinks.map((link) => (
<a
key={link.href}
href={link.href}
className="text-sm font-medium text-gray-700 hover:text-gray-900 transition-colors"
className="px-4 py-2 text-sm font-medium text-ink-secondary hover:text-ink hover:bg-cream-200/60 rounded-lg transition-colors duration-200"
>
{link.label}
</a>
))}
</div>
<div className="flex items-center gap-3">
<div className="flex items-center gap-2">
{/* Language Switcher */}
<div className="relative" ref={langMenuRef}>
<button
onClick={() => setShowLangMenu(!showLangMenu)}
className="flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg text-gray-700 text-sm font-medium transition-colors"
className="flex items-center gap-1.5 px-3 py-2 hover:bg-cream-200/60 rounded-lg text-ink-secondary text-sm font-medium transition-colors"
>
<Languages size={18} />
<Languages size={16} />
<span className="hidden sm:inline">{language === 'en' ? 'EN' : '中文'}</span>
<ChevronDown size={14} className={`transition-transform duration-200 ${showLangMenu ? 'rotate-180' : ''}`} />
<ChevronDown size={12} className={`transition-transform duration-200 ${showLangMenu ? 'rotate-180' : ''}`} />
</button>
{showLangMenu && (
<div className="absolute right-0 top-full mt-2 w-32 bg-white rounded-xl shadow-lg border border-gray-200 py-1 z-50">
<div className="absolute right-0 top-full mt-2 w-36 bg-white rounded-xl shadow-lg border border-cream-300 py-1.5 z-50">
{(['en', 'zh'] as const).map((lang) => (
<button
key={lang}
onClick={() => { setLanguage(lang); setShowLangMenu(false); }}
className={`w-full flex items-center justify-between px-4 py-2 text-sm transition-colors hover:bg-gray-50 ${language === lang ? 'text-blue-600 font-medium' : 'text-gray-700'}`}
className={`w-full flex items-center justify-between px-4 py-2.5 text-sm transition-colors hover:bg-cream-100 ${
language === lang ? 'text-coral-600 font-semibold' : 'text-ink-secondary'
}`}
>
{lang === 'en' ? 'English' : '简体中文'}
{language === lang && <Check size={14} />}
@@ -92,29 +113,46 @@ export default function MarketingNavbar() {
<Link
to="/app"
className="hidden sm:inline-flex items-center px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors"
className="hidden sm:inline-flex items-center px-5 py-2 btn-primary text-sm rounded-lg"
>
{t.marketing.nav.launchApp}
</Link>
<button className="md:hidden p-2" onClick={() => setMobileMenuOpen(!mobileMenuOpen)}>
{mobileMenuOpen ? <X size={20} /> : <Menu size={20} />}
<button className="md:hidden p-2 text-ink-secondary hover:text-ink" onClick={() => setMobileMenuOpen(!mobileMenuOpen)}>
{mobileMenuOpen ? <X size={22} /> : <Menu size={22} />}
</button>
</div>
{/* Mobile menu */}
{mobileMenuOpen && (
<div className="absolute top-16 left-0 right-0 bg-white border-b border-gray-200 shadow-lg md:hidden z-50 py-4 px-6 flex flex-col gap-3">
<div className="absolute top-16 left-0 right-0 bg-white/95 backdrop-blur-md border-b border-cream-300 shadow-lg md:hidden z-50 py-3 px-6 flex flex-col gap-1">
{navLinks.map((link) => (
<Link key={link.to} to={link.to} className="text-sm font-medium text-gray-700 py-2" onClick={() => setMobileMenuOpen(false)}>
<Link
key={link.to}
to={link.to}
className={`text-sm font-medium py-2.5 px-3 rounded-lg transition-colors ${
location.pathname === link.to ? 'text-coral-600 bg-coral-50' : 'text-ink-secondary hover:bg-cream-200/60'
}`}
onClick={() => setMobileMenuOpen(false)}
>
{link.label}
</Link>
))}
{anchorLinks.map((link) => (
<a key={link.href} href={link.href} className="text-sm font-medium text-gray-700 py-2" onClick={() => setMobileMenuOpen(false)}>
<a
key={link.href}
href={link.href}
className="text-sm font-medium text-ink-secondary py-2.5 px-3 rounded-lg hover:bg-cream-200/60"
onClick={() => setMobileMenuOpen(false)}
>
{link.label}
</a>
))}
<Link to="/app" className="text-sm font-medium text-blue-600 py-2" onClick={() => setMobileMenuOpen(false)}>
<Link
to="/app"
className="text-sm font-semibold text-coral-600 py-2.5 px-3"
onClick={() => setMobileMenuOpen(false)}
>
{t.marketing.nav.launchApp}
</Link>
</div>