diff --git a/docs/plans/2026-02-24-ui-ux-optimization.md b/docs/plans/2026-02-24-ui-ux-optimization.md new file mode 100644 index 0000000..374651f --- /dev/null +++ b/docs/plans/2026-02-24-ui-ux-optimization.md @@ -0,0 +1,1175 @@ +# UI/UE/UX 全面优化实施计划 + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** 提升网站的无障碍性、性能、用户体验、响应式设计、SEO 和安全性,达到金融级标准。 + +**Architecture:** 采用渐进式优化策略,从高优先级的无障碍性和性能优化开始,逐步推进到用户体验、响应式设计、SEO 和安全性优化。每个优化点都遵循 TDD 原则,确保质量。 + +**Tech Stack:** Next.js 15, React 19, TypeScript, Tailwind CSS, Framer Motion, Zod + +--- + +## 优先级说明 + +- ⭐⭐⭐⭐⭐ 立即实施(第一阶段) +- ⭐⭐⭐⭐ 短期实施(第二阶段) +- ⭐⭐⭐ 长期实施(第三阶段) + +--- + +## 第一阶段:无障碍性优化(立即实施) + +### Task 1: 表单标签关联优化 + +**Files:** +- Modify: `src/components/sections/contact-section.tsx:1-200` +- Test: `e2e-tests/tests/test_contact_form.py` + +**Step 1: 添加 useId hook** + +```tsx +// src/components/sections/contact-section.tsx +import { useState, useEffect, useRef, useId } from 'react'; + +export function ContactSection() { + const nameInputId = useId(); + const phoneInputId = useId(); + const emailInputId = useId(); + const messageInputId = useId(); + + // ... existing code +} +``` + +**Step 2: 关联标签和输入框** + +```tsx +// 姓名字段 +
+ + + {errors.name && ( + + )} +
+``` + +**Step 3: 对所有字段重复 Step 2** + +为 phone、email、message 字段添加相同的优化。 + +**Step 4: 运行无障碍性测试** + +Run: `pytest e2e-tests/tests/test_contact_form.py -v` + +Expected: PASS + +**Step 5: 提交** + +```bash +git add src/components/sections/contact-section.tsx +git commit -m "feat(a11y): add proper label associations and ARIA attributes to contact form" +``` + +--- + +### Task 2: 图片无障碍性优化 + +**Files:** +- Modify: `src/components/sections/about-section.tsx:1-150` +- Modify: `src/components/sections/products-section.tsx:1-200` +- Modify: `src/components/sections/cases-section.tsx:1-200` + +**Step 1: 检查所有图片元素** + +Run: `grep -r " + +// ✅ 之后 +诺瓦隆公司团队合影 +``` + +**Step 3: 使用 Next.js Image 组件** + +```tsx +import Image from 'next/image'; + +产品展示 +``` + +**Step 4: 提交** + +```bash +git add src/components/sections/*.tsx +git commit -m "feat(a11y): add alt attributes and optimize images with Next.js Image component" +``` + +--- + +### Task 3: 键盘导航优化 + +**Files:** +- Modify: `src/components/layout/header.tsx:1-100` +- Modify: `src/components/layout/mobile-menu.tsx:1-80` +- Test: `e2e-tests/tests/test_navigation.py` + +**Step 1: 添加键盘导航支持** + +```tsx +// header.tsx +const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + // 触发点击事件 + } +}; + + +``` + +**Step 2: 添加焦点管理** + +```tsx +import { useRef, useEffect } from 'react'; + +const menuRef = useRef(null); + +useEffect(() => { + if (isOpen && menuRef.current) { + menuRef.current.focus(); + } +}, [isOpen]); +``` + +**Step 3: 运行键盘导航测试** + +Run: `pytest e2e-tests/tests/test_navigation.py -v` + +Expected: PASS + +**Step 4: 提交** + +```bash +git add src/components/layout/*.tsx +git commit -m "feat(a11y): add keyboard navigation support and focus management" +``` + +--- + +### Task 4: ARIA 标签完善 + +**Files:** +- Modify: `src/components/sections/hero-section.tsx:1-200` +- Modify: `src/components/sections/services-section.tsx:1-150` +- Modify: `src/components/sections/products-section.tsx:1-200` + +**Step 1: 添加语义化标签** + +```tsx +// hero-section.tsx +
+

+ 诺瓦隆金融科技 +

+
+``` + +**Step 2: 添加按钮标签** + +```tsx + +``` + +**Step 3: 添加区域标签** + +```tsx +
+

我们的服务

+
+``` + +**Step 4: 提交** + +```bash +git add src/components/sections/*.tsx +git commit -m "feat(a11y): add comprehensive ARIA labels and semantic HTML" +``` + +--- + +## 第二阶段:性能优化(立即实施) + +### Task 5: 图片懒加载优化 + +**Files:** +- Modify: `src/components/sections/about-section.tsx:1-150` +- Modify: `src/components/sections/products-section.tsx:1-200` +- Create: `src/components/ui/optimized-image.tsx` + +**Step 1: 创建优化图片组件** + +```tsx +// src/components/ui/optimized-image.tsx +'use client'; + +import Image from 'next/image'; +import { useState } from 'react'; + +interface OptimizedImageProps { + src: string; + alt: string; + width: number; + height: number; + className?: string; + priority?: boolean; +} + +export function OptimizedImage({ + src, + alt, + width, + height, + className = '', + priority = false +}: OptimizedImageProps) { + const [isLoading, setIsLoading] = useState(true); + + return ( +
+ {isLoading && ( +
+ )} + {alt} setIsLoading(false)} + className={`transition-opacity duration-300 ${ + isLoading ? 'opacity-0' : 'opacity-100' + }`} + /> +
+ ); +} +``` + +**Step 2: 替换现有图片** + +```tsx +// about-section.tsx +import { OptimizedImage } from '@/components/ui/optimized-image'; + + +``` + +**Step 3: 提交** + +```bash +git add src/components/ui/optimized-image.tsx src/components/sections/*.tsx +git commit -m "perf: implement optimized image component with lazy loading" +``` + +--- + +### Task 6: 组件懒加载优化 + +**Files:** +- Modify: `src/app/(marketing)/page.tsx:1-50` + +**Step 1: 使用 dynamic import** + +```tsx +import dynamic from 'next/dynamic'; +import { HeroSection } from '@/components/sections/hero-section'; + +const AboutSection = dynamic( + () => import('@/components/sections/about-section').then(mod => ({ default: mod.AboutSection })), + { loading: () => } +); + +const ServicesSection = dynamic( + () => import('@/components/sections/services-section').then(mod => ({ default: mod.ServicesSection })), + { loading: () => } +); + +function SectionSkeleton() { + return ( +
+
+
+
+
+
+
+ ); +} +``` + +**Step 2: 提交** + +```bash +git add src/app/\(marketing\)/page.tsx +git commit -m "perf: implement dynamic imports for non-critical sections" +``` + +--- + +### Task 7: 字体优化 + +**Files:** +- Modify: `src/app/layout.tsx:1-50` + +**Step 1: 使用 Next.js 字体优化** + +```tsx +import { Inter } from 'next/font/google'; + +const inter = Inter({ + subsets: ['latin'], + display: 'swap', + variable: '--font-inter', +}); + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + {children} + + + ); +} +``` + +**Step 2: 提交** + +```bash +git add src/app/layout.tsx +git commit -m "perf: optimize font loading with Next.js font optimization" +``` + +--- + +## 第三阶段:用户体验优化(立即实施) + +### Task 8: 加载状态优化 + +**Files:** +- Create: `src/components/ui/loading-skeleton.tsx` +- Modify: `src/components/sections/contact-section.tsx:1-200` + +**Step 1: 创建骨架屏组件** + +```tsx +// src/components/ui/loading-skeleton.tsx +export function LoadingSkeleton({ className = '' }: { className?: string }) { + return ( +
+ ); +} + +export function FormSkeleton() { + return ( +
+ + + + +
+ ); +} +``` + +**Step 2: 在表单中使用** + +```tsx +// contact-section.tsx +import { FormSkeleton } from '@/components/ui/loading-skeleton'; + +{isSubmitting ? ( + +) : ( +
...
+)} +``` + +**Step 3: 提交** + +```bash +git add src/components/ui/loading-skeleton.tsx src/components/sections/contact-section.tsx +git commit -m "feat(ux): add loading skeletons for better user experience" +``` + +--- + +### Task 9: 错误处理优化 + +**Files:** +- Create: `src/components/ui/error-boundary.tsx` +- Modify: `src/app/(marketing)/layout.tsx:1-50` + +**Step 1: 创建错误边界** + +```tsx +// src/components/ui/error-boundary.tsx +'use client'; + +import { Component, ReactNode } from 'react'; + +interface Props { + children: ReactNode; + fallback?: ReactNode; +} + +interface State { + hasError: boolean; +} + +export class ErrorBoundary extends Component { + constructor(props: Props) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError() { + return { hasError: true }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error('Error caught by boundary:', error, errorInfo); + } + + render() { + if (this.state.hasError) { + return this.props.fallback || ( +
+
+

出错了

+

抱歉,页面出现了问题

+ +
+
+ ); + } + + return this.props.children; + } +} +``` + +**Step 2: 在布局中使用** + +```tsx +// layout.tsx +import { ErrorBoundary } from '@/components/ui/error-boundary'; + + + {children} + +``` + +**Step 3: 提交** + +```bash +git add src/components/ui/error-boundary.tsx src/app/\(marketing\)/layout.tsx +git commit -m "feat(ux): add error boundary for graceful error handling" +``` + +--- + +### Task 10: 成功反馈优化 + +**Files:** +- Create: `src/components/ui/toast.tsx` +- Modify: `src/components/sections/contact-section.tsx:1-200` + +**Step 1: 创建 Toast 组件** + +```tsx +// src/components/ui/toast.tsx +'use client'; + +import { useEffect, useState } from 'react'; +import { CheckCircle2, X } from 'lucide-react'; + +interface ToastProps { + message: string; + type?: 'success' | 'error' | 'info'; + duration?: number; + onClose: () => void; +} + +export function Toast({ + message, + type = 'success', + duration = 3000, + onClose +}: ToastProps) { + const [isVisible, setIsVisible] = useState(true); + + useEffect(() => { + const timer = setTimeout(() => { + setIsVisible(false); + setTimeout(onClose, 300); + }, duration); + + return () => clearTimeout(timer); + }, [duration, onClose]); + + const icons = { + success: , + error: , + info: + }; + + return ( +
+ {icons[type]} +

{message}

+ +
+ ); +} +``` + +**Step 2: 在表单中使用** + +```tsx +// contact-section.tsx +import { Toast } from '@/components/ui/toast'; + +const [showToast, setShowToast] = useState(false); + +{showToast && ( + setShowToast(false)} + /> +)} +``` + +**Step 3: 提交** + +```bash +git add src/components/ui/toast.tsx src/components/sections/contact-section.tsx +git commit -m "feat(ux): add toast notifications for user feedback" +``` + +--- + +## 第四阶段:响应式设计优化(短期实施) + +### Task 11: 移动端触摸优化 + +**Files:** +- Modify: `src/components/ui/button.tsx:1-50` +- Modify: `src/components/ui/input.tsx:1-50` + +**Step 1: 增加触摸目标大小** + +```tsx +// button.tsx + +``` + +**Step 2: 优化输入框大小** + +```tsx +// input.tsx + +``` + +**Step 3: 提交** + +```bash +git add src/components/ui/button.tsx src/components/ui/input.tsx +git commit -m "feat(responsive): optimize touch targets for mobile devices" +``` + +--- + +### Task 12: 响应式字体优化 + +**Files:** +- Modify: `src/app/globals.css:1-100` + +**Step 1: 添加响应式字体** + +```css +/* globals.css */ +html { + font-size: 16px; +} + +@media (min-width: 640px) { + html { + font-size: 17px; + } +} + +@media (min-width: 1024px) { + html { + font-size: 18px; + } +} +``` + +**Step 2: 提交** + +```bash +git add src/app/globals.css +git commit -m "feat(responsive): add responsive font sizing" +``` + +--- + +## 第五阶段:SEO 优化(短期实施) + +### Task 13: Meta 标签优化 + +**Files:** +- Modify: `src/app/layout.tsx:1-50` +- Create: `src/app/(marketing)/about/metadata.ts` + +**Step 1: 添加全局 metadata** + +```tsx +// layout.tsx +import { Metadata } from 'next'; + +export const metadata: Metadata = { + title: { + default: '诺瓦隆 - 金融科技解决方案', + template: '%s | 诺瓦隆' + }, + description: '诺瓦隆是专业的金融科技服务提供商,致力于为证券、基金、银行等金融机构提供创新的技术解决方案。', + keywords: ['金融科技', '证券', '基金', '银行', '投资', '风险管理'], + authors: [{ name: '诺瓦隆' }], + creator: '诺瓦隆', + publisher: '诺瓦隆', + robots: { + index: true, + follow: true + }, + openGraph: { + type: 'website', + locale: 'zh_CN', + url: 'https://novalon.com', + siteName: '诺瓦隆', + title: '诺瓦隆 - 金融科技解决方案', + description: '专业的金融科技服务提供商', + images: [ + { + url: '/og-image.jpg', + width: 1200, + height: 630, + alt: '诺瓦隆' + } + ] + }, + twitter: { + card: 'summary_large_image', + title: '诺瓦隆 - 金融科技解决方案', + description: '专业的金融科技服务提供商', + images: ['/og-image.jpg'] + } +}; +``` + +**Step 2: 提交** + +```bash +git add src/app/layout.tsx +git commit -m "feat(seo): add comprehensive metadata for SEO optimization" +``` + +--- + +### Task 14: 结构化数据优化 + +**Files:** +- Create: `src/components/seo/structured-data.tsx` +- Modify: `src/app/layout.tsx:1-50` + +**Step 1: 创建结构化数据组件** + +```tsx +// src/components/seo/structured-data.tsx +export function OrganizationSchema() { + const schema = { + "@context": "https://schema.org", + "@type": "Organization", + "name": "诺瓦隆", + "url": "https://novalon.com", + "logo": "https://novalon.com/logo.svg", + "description": "专业的金融科技服务提供商", + "address": { + "@type": "PostalAddress", + "addressCountry": "CN", + "addressLocality": "北京" + }, + "contactPoint": { + "@type": "ContactPoint", + "telephone": "+86-10-12345678", + "contactType": "customer service" + } + }; + + return ( +