From d6daf6250b5d836aaef89a6928e6cc38c3b96da4 Mon Sep 17 00:00:00 2001 From: Veloform Dev Date: Mon, 15 Jun 2026 17:02:11 +0000 Subject: [PATCH] =?UTF-8?q?feat(design):=20=E8=AE=BE=E8=AE=A1=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E9=87=8D=E6=9E=84=E4=B8=8E=20shadcn/ui=20=E9=9B=86?= =?UTF-8?q?=E6=88=90=20(v3.8.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 集成 shadcn/ui 组件库,添加 gradient 按钮变体与新图标 - 重构 globals.css 为 Apple HIG 风格 CSS 变量色彩系统 - 更新 tailwind.config.ts,完善字体栈与动画预设 - 可访问性改进:装饰元素 aria-hidden、触摸目标 44x44px - 文档更新:README/CHANGELOG/openspec 规范文档与原型指南 - i18n 修复:补全 configurator 相关翻译键 - 版本号同步更新至 3.8.0 变更文件:21 files changed, 1,305 insertions, 982 deletions --- .lintstagedrc.json | 3 + CHANGELOG.md | 32 + README.md | 37 +- next.config.mjs | 18 + openspec/PROJECT_GUIDELINES.md | 8 +- openspec/README.md | 25 +- openspec/SPEC.md | 15 +- openspec/architecture/component-design.md | 29 +- openspec/architecture/component-patterns.md | 144 ++-- openspec/architecture/data-flow.md | 114 +-- openspec/architecture/overview.md | 83 +- openspec/architecture/state-management.md | 6 +- openspec/design/ui-design-system.md | 221 +++-- openspec/development/coding-standards.md | 56 +- package-lock.json | 47 +- prototype/README.md | 42 +- prototype/prototype-guide.md | 289 +++---- prototype/prototype.html | 878 ++++++++++++-------- src/lib/i18n/en.ts | 15 +- src/lib/i18n/zh-CN.ts | 6 +- tailwind.config.ts | 219 ++--- 21 files changed, 1305 insertions(+), 982 deletions(-) diff --git a/.lintstagedrc.json b/.lintstagedrc.json index 681f620..04e0c17 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,3 +1,6 @@ +# lint-staged 配置 +# 在 git commit 前自动运行 lint 和格式化 + { "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"], "*.{json,md,css}": ["prettier --write"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 279fc17..cb50b1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.8.0] +### Added +- Integrated shadcn/ui component library (v4.11.0) with gradient button variant +- Added complete Apple-style design system in globals.css with CSS variables +- Added text-gradient-brand utility class for brand gradient text +- Added touch-target utility class (44x44px minimum) for accessibility +- Added animation utilities: float, glow-pulse, gradient-shift, fadeIn, slideUp +- Added reduced-motion media query support for accessibility +- Added prototype design specification documents: + - design-system-spec.md - Complete design token system + - component-library.md - Component classification and usage rules + - interaction-standards.md - Interaction patterns and feedback standards + +### Changed +- Refactored button.tsx to use shadcn/ui with gradient variant support +- Updated tailwind.config.ts with complete CSS variable color system +- Updated globals.css with Apple HIG color palette and design tokens +- Updated BikeTypeSelector.tsx with enhanced interaction states and animations +- Updated BuildList.tsx and SummaryPanel.tsx to use shadcn Button components +- Updated Hero.tsx, Cta.tsx, Navbar.tsx to use consistent Button styling +- Updated Features.tsx and Pricing.tsx with proper aria-hidden attributes +- Updated i18n translations (zh-CN.ts, en.ts) with missing emptyState keys +- Updated README.md with shadcn/ui in tech stack and updated directory structure +- Updated package.json version to 3.8.0 + +### Fixed +- Fixed decorative elements missing aria-hidden attributes +- Fixed button touch targets to meet WCAG 2.1 44x44px minimum requirement +- Fixed aria-pressed attribute on role="tab" elements (removed unsupported attribute) +- Fixed missing i18n translation keys for configurator empty state +- Fixed inconsistent button styling across components + ## [3.5.0] ### Added - Added Footer component with version number display diff --git a/README.md b/README.md index a50357f..c3c7b0b 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Veloform 是一款基于 Next.js、Tailwind CSS 并由 Firebase 驱动的高级 | React | v18.2.0 | UI 组件库 | | Zustand | v4.5.0 | 轻量级状态管理 | | Tailwind CSS | v3.4.0 | 样式框架 | +| shadcn/ui | v4.11.0 | 高质量 React 组件库(基于 Radix UI) | | Firebase | v10.0.0 | Firestore 数据库与 Auth 身份验证 | | Framer Motion | v10.16.4 | 动画效果 | | Lucide React | v0.294.0 | 图标库 | @@ -53,7 +54,7 @@ src/ │ ├── layout.tsx # 根布局(含 SyncProvider) │ ├── page.tsx # 首页/配置器 │ ├── providers.tsx # 全局提供者 -│ ├── globals.css # 全局样式 +│ ├── globals.css # 全局样式(Apple 设计系统) │ └── library/ │ └── page.tsx # 配置库页面 ├── components/ # UI 组件 @@ -68,23 +69,33 @@ src/ │ │ └── SummaryPanel.tsx # 汇总面板 │ ├── layout/ # 布局组件 │ │ └── Navbar.tsx # 导航栏 -│ ├── ui/ # 通用 UI 组件 -│ │ ├── Button.tsx # 按钮 -│ │ ├── Card.tsx # 卡片 -│ │ ├── ErrorBoundary.tsx # 错误边界 -│ │ ├── Modal.tsx # 模态框 -│ │ ├── OnboardingGuide.tsx # 新手引导 -│ │ ├── SupportModal.tsx # 支持模态框 -│ │ ├── ThemeToggle.tsx # 主题切换 -│ │ └── Toast.tsx # Toast 通知 +│ ├── sections/ # 页面区块组件 +│ │ ├── Hero.tsx # 首页 Hero 区块 +│ │ ├── Features.tsx # 功能特性区块 +│ │ ├── Pricing.tsx # 定价区块 +│ │ ├── Cta.tsx # 行动召唤区块 +│ │ └── Footer.tsx # 页脚 +│ ├── ui/ # shadcn/ui 组件库 +│ │ ├── button.tsx # 按钮(含 gradient 变体) +│ │ ├── card.tsx # 卡片 +│ │ ├── dialog.tsx # 对话框 +│ │ ├── input.tsx # 输入框 +│ │ └── ... # 其他 shadcn 组件 │ └── SyncProvider.tsx # 云同步提供者(Auth + Firestore) ├── lib/ # 工具库 +│ ├── stores/ # Zustand 状态管理 +│ │ ├── index.ts # 状态导出 +│ │ ├── config-store.ts # 配置状态切片 +│ │ └── ui-store.ts # UI 状态切片 +│ ├── services/ # 业务服务层 +│ │ ├── config-service.ts # 配置业务逻辑 +│ │ └── sync-service.ts # 云同步服务 │ ├── auth.ts # Firebase 认证服务 │ ├── constants.ts # 应用常量 │ ├── env.ts # 环境变量验证 │ ├── firebase-service.ts # Firebase Firestore 服务 │ ├── firebase.ts # Firebase 配置 -│ ├── store.ts # Zustand 状态管理(含选择性 hooks) +│ ├── store.ts # Zustand 状态管理(兼容层) │ ├── utils.ts # 工具函数 │ ├── toast.ts # Toast 通知 │ ├── recommended-configs.ts # 推荐配置 @@ -213,7 +224,7 @@ MIT License ## 版本信息 -当前版本:**v3.7.0** -最后更新:2026-06-08 +当前版本:**v3.8.0** +最后更新:2026-06-15 详细变更记录见 [CHANGELOG.md](./CHANGELOG.md)。 \ No newline at end of file diff --git a/next.config.mjs b/next.config.mjs index b853bff..c8f3ea6 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -3,6 +3,18 @@ import withPWA from 'next-pwa'; /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, + images: { + // 允许从这些域名加载图片 + remotePatterns: [ + { protocol: 'https', hostname: 'neeko-copilot.bytedance.net' }, + { protocol: 'https', hostname: 'images.unsplash.com' }, + ], + // 图片优化格式 + formats: ['image/avif', 'image/webp'], + // 禁用不追踪 LCP 元素图片的优化提示 + deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], + imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], + }, webpack: (config, { isServer }) => { if (isServer) { config.externals = [...(config.externals || []), 'firebase', 'firebase-admin']; @@ -15,6 +27,12 @@ const nextConfig = { net: false, tls: false, }; + + // Bundle 分析(仅在 ANALYZE=true 时启用) + if (process.env.ANALYZE === 'true') { + const { BundleAnalyzerPlugin } = require('@next/bundle-analyzer'); + config.plugins.push(new BundleAnalyzerPlugin()); + } } return config; }, diff --git a/openspec/PROJECT_GUIDELINES.md b/openspec/PROJECT_GUIDELINES.md index 7aa36bf..23d3953 100644 --- a/openspec/PROJECT_GUIDELINES.md +++ b/openspec/PROJECT_GUIDELINES.md @@ -1,8 +1,8 @@ # Veloform 项目开发指南 > **路径**: `/openspec/PROJECT_GUIDELINES.md` -> **版本**: v3.4.1 -> **更新日期**: 2026-05-05 +> **版本**: v3.7.0 +> **更新日期**: 2026-06-09 ## 概述 @@ -320,5 +320,5 @@ A: --- **文档路径**: `/openspec/PROJECT_GUIDELINES.md` -**最后更新**: 2026-05-05 -**版本**: v3.4.1 +**最后更新**: 2026-06-09 +**版本**: v3.7.0 diff --git a/openspec/README.md b/openspec/README.md index d2219e6..fd813ec 100644 --- a/openspec/README.md +++ b/openspec/README.md @@ -1,14 +1,14 @@ # Veloform 规范文档索引 > **路径**: `/openspec/README.md` -> **版本**: v3.6.1 -> **更新日期**: 2026-06-04 +> **版本**: v3.7.0 +> **更新日期**: 2026-06-09 ## 概述 本文档是 Veloform 项目规范体系的导航入口,提供所有技术规范和开发指南的快速访问。规范文档采用分层结构,涵盖架构、API、开发、部署、安全和性能等核心领域。 -**项目版本**: v3.6.0 +**项目版本**: v3.7.0 --- @@ -23,8 +23,8 @@ | [状态管理](./architecture/state-management.md) | React 状态管理方案、Context、Zustand、Server State | 选择合适的状态管理方案 | | [组件模式](./architecture/component-patterns.md) | React 组件设计模式、Hooks 最佳实践、性能优化 | 开发可复用组件时参考 | | [组件设计规范](./architecture/component-design.md) | 组件分类、命名规范、Props 定义、可访问性 | 开发新组件时参考 | -| [ADR 索引](./architecture/adr/) | 架构决策记录索引 | 理解关键架构决策背景 | -| [规范标准化](./规范标准化.md) | 文档格式、版本管理、命名规范和维护流程 | 规范化文档编写 | +| ADR 索引(待补充) | 架构决策记录索引 | 理解关键架构决策背景 | +| 规范标准化(待补充) | 文档格式、版本管理、命名规范和维护流程 | 规范化文档编写 | ### API 规范 @@ -39,14 +39,14 @@ |------|------|----------| | [编码规范](./development/coding-standards.md) | TypeScript、React/Next.js、样式、Git 工作流、性能优化 | 编写代码时遵循 | | [测试规范](./development/testing.md) | 测试策略、框架使用、覆盖率要求、最佳实践 | 编写测试时参考 | -| [国际化规范](./development/i18n-guidelines.md) | i18n 实现、翻译文件结构、语言切换、测试 | 开发多语言功能时参考 | +| 国际化规范(待补充) | i18n 实现、翻译文件结构、语言切换、测试 | 开发多语言功能时参考 | ### 部署规范 | 文档 | 说明 | 适用场景 | |------|------|----------| | [环境配置](./deployment/environments.md) | 部署流程、环境变量、SSR 配置、监控、SEO | 部署应用时参考 | -| [CI/CD 流程](./devops/ci-cd.md) | 分支策略、自动化测试、部署流程、监控告警 | 设置 CI/CD 流水线 | +| CI/CD 流程(待补充) | 分支策略、自动化测试、部署流程、监控告警 | 设置 CI/CD 流水线 | ### 安全规范 @@ -66,7 +66,7 @@ |------|------|----------| | [UI 设计系统](./design/ui-design-system.md) | 完整的设计系统,包含颜色、字体、间距、组件规范等 | UI 开发、组件设计参考 | | [原型图说明](../prototype/prototype-guide.md) | 高拟真原型图功能说明、与实际项目映射关系 | 理解 UI 设计和交互流程 | -| [设计审查与优化建议](./design/design-review.md) | 顶级设计师视角的设计审查和优化建议 | 优化用户体验、提升设计质量 | +| 设计审查与优化建议(待补充) | 顶级设计师视角的设计审查和优化建议 | 优化用户体验、提升设计质量 | --- @@ -84,7 +84,7 @@ 1. 查看 [组件模式](./architecture/component-patterns.md) 了解 React 组件开发模式 2. 参考 [状态管理](./architecture/state-management.md) 选择合适的状态管理方案 3. 如需调用后端,查阅 [Firestore API](./api/firestore.md) -4. 如需多语言支持,参考 [国际化规范](./development/i18n-guidelines.md) +4. 如需多语言支持,参考 [编码规范](./development/coding-standards.md) 中的国际化章节(自定义 i18n hook,不依赖 next-intl) 5. 完成后按照 [测试规范](./development/testing.md) 编写测试 ### 修复 Bug @@ -166,6 +166,7 @@ | 规范版本 | 项目版本 | 更新日期 | 主要变更 | |---------|---------|---------|---------| +| v3.7.0 | 3.7.0 | 2026-06-09 | 规范文档与实际代码全面对齐:统一版本号、修正字体加载策略、补全 sections/ 组件目录、修正 i18n 实现说明、修正 Tailwind 配置示例 | | v3.6.1 | 3.6.0 | 2026-06-04 | 更新组件文档与实际代码对齐、统一版本号、完善 Button/Card/Footer 组件文档 | | v3.6.0 | 3.6.0 | 2026-06-04 | 完善规范文档体系、统一设计系统文档、优化原型说明 | | v3.5.0 | 3.5.0 | 2026-06-03 | 新增页脚组件、深色/浅色主题切换、完整主题系统 | @@ -185,10 +186,10 @@ - [英文 README](../README_EN.md) - 英文版项目说明 - [变更日志](../CHANGELOG.md) - 版本历史 - [原型图](../prototype/prototype-guide.md) - 原型说明文档 -- [设计审查](./design/design-review.md) - 设计优化建议 +- 设计审查(待补充) - 设计优化建议 --- **文档路径**: `/openspec/README.md` -**最后更新**: 2026-06-04 -**版本**: v3.6.1 \ No newline at end of file +**最后更新**: 2026-06-09 +**版本**: v3.7.0 \ No newline at end of file diff --git a/openspec/SPEC.md b/openspec/SPEC.md index 3e0ae76..4ccd735 100644 --- a/openspec/SPEC.md +++ b/openspec/SPEC.md @@ -1,8 +1,8 @@ # Veloform 规范概览 > **路径**: `/openspec/SPEC.md` -> **版本**: v3.6.1 -> **更新日期**: 2026-06-04 +> **版本**: v3.7.0 +> **更新日期**: 2026-06-09 ## 概述 @@ -61,6 +61,7 @@ src/ │ └── globals.css # 全局样式 │ ├── components/ # UI 组件 +│ ├── SyncProvider.tsx # Firebase 认证同步提供者(顶层组件) │ ├── configurator/ # 配置器相关组件 │ │ ├── BikeTypeSelector.tsx │ │ ├── BuildList.tsx @@ -74,6 +75,11 @@ src/ │ ├── layout/ # 布局组件 │ │ ├── Navbar.tsx │ │ └── Footer.tsx +│ ├── sections/ # 营销/落地页分区组件(Hero/Features/Pricing/Cta) +│ │ ├── Hero.tsx +│ │ ├── Features.tsx +│ │ ├── Pricing.tsx +│ │ └── Cta.tsx │ └── ui/ # 通用 UI 组件 │ ├── Button.tsx │ ├── Card.tsx @@ -234,6 +240,7 @@ src/ | 规范版本 | 项目版本 | 更新日期 | 说明 | |---------|---------|---------|------| +| v3.7.0 | 3.7.0 | 2026-06-09 | 规范文档与实际代码全面对齐:补全 SyncProvider/sections/ 目录、修正 i18n 说明、修正 Tailwind 配置示例、统一版本号 | | v3.6.1 | 3.6.0 | 2026-06-04 | 更新组件文档与实际代码对齐、统一版本号 | | v3.6.0 | 3.6.0 | 2026-06-04 | 完善规范文档体系、统一设计系统文档、优化原型说明、新增视觉效果规范 | | v3.5.0 | 3.5.0 | 2026-06-03 | 新增页脚组件、深色/浅色主题切换、完整主题系统 | @@ -247,5 +254,5 @@ src/ --- -**最后更新**: 2026-06-04 -**版本**: v3.6.1 +**最后更新**: 2026-06-09 +**版本**: v3.7.0 diff --git a/openspec/architecture/component-design.md b/openspec/architecture/component-design.md index 233ea2a..4e14ca3 100644 --- a/openspec/architecture/component-design.md +++ b/openspec/architecture/component-design.md @@ -1,8 +1,8 @@ # 组件设计规范 > **路径**: `/openspec/architecture/component-design.md` -> **版本**: v3.5.1 -> **更新日期**: 2026-06-01 +> **版本**: v3.7.0 +> **更新日期**: 2026-06-09 ## 概述 @@ -94,14 +94,23 @@ export default function Home() { ``` components/ -├── layout/ # 布局组件 -│ └── Navbar.tsx -├── configurator/ # 配置器相关组件 +├── SyncProvider.tsx # 顶层 Firebase 同步提供者 +├── layout/ # 布局组件 +│ ├── Navbar.tsx +│ └── Footer.tsx +├── configurator/ # 配置器相关组件 │ ├── BuildList.tsx -│ └── BikeTypeSelector.tsx -└── ui/ # 通用 UI 组件 +│ ├── BikeTypeSelector.tsx +│ └── ... +├── sections/ # 营销/落地页分区组件 +│ ├── Hero.tsx +│ ├── Features.tsx +│ ├── Pricing.tsx +│ └── Cta.tsx +└── ui/ # 通用 UI 组件 ├── Button.tsx - └── Card.tsx + ├── Card.tsx + └── ... ``` --- @@ -512,5 +521,5 @@ export function FadeInCard({ children }) { --- **文档路径**: `/openspec/architecture/component-design.md` -**最后更新**: 2026-06-01 -**版本**: v3.5.1 +**最后更新**: 2026-06-09 +**版本**: v3.7.0 diff --git a/openspec/architecture/component-patterns.md b/openspec/architecture/component-patterns.md index 6d07336..38df6c2 100644 --- a/openspec/architecture/component-patterns.md +++ b/openspec/architecture/component-patterns.md @@ -1,7 +1,7 @@ # React 组件设计模式规范 -**版本**: v3.4.1 -**日期**: 2026-05-26 +**版本**: v3.7.0 +**日期**: 2026-06-09 **项目**: Veloform --- @@ -22,10 +22,15 @@ Veloform 的组件按照职责范围分为三个类别: | 组件名 | 文件名 | 职责 | |--------|--------|------| -| BuildList | `build-list.tsx` | 显示已选配置项列表,支持删除和重新排序 | -| ComponentSelector | `component-selector.tsx` | 组件选择器,提供分类浏览和搜索功能 | -| SummaryPanel | `summary-panel.tsx` | 配置摘要面板,展示总价格和配置概要 | -| BikeTypeSelector | `bike-type-selector.tsx` | 车型选择器,支持不同车型的配置切换 | +| BuildList | `BuildList.tsx` | 显示已选配置项列表,支持删除和重新排序 | +| ComponentSelector | `ComponentSelector.tsx` | 组件选择器,提供分类浏览和搜索功能 | +| SummaryPanel | `SummaryPanel.tsx` | 配置摘要面板,展示总价格和配置概要 | +| BikeTypeSelector | `BikeTypeSelector.tsx` | 车型选择器,支持不同车型的配置切换 | +| ComponentDetailModal | `ComponentDetailModal.tsx` | 组件详情弹窗 | +| CostBreakdownChart | `CostBreakdownChart.tsx` | 成本分解图表 | +| RecommendedConfigs | `RecommendedConfigs.tsx` | 推荐配置展示 | +| ComparePanel | `ComparePanel.tsx` | 配置对比面板 | +| ShareModal | `ShareModal.tsx` | 分享配置模态框 | ### 2.2 layout 组件 @@ -33,7 +38,8 @@ Veloform 的组件按照职责范围分为三个类别: | 组件名 | 文件名 | 职责 | |--------|--------|------| -| Navbar | `navbar.tsx` | 顶部导航栏,包含 Logo、菜单和用户操作入口 | +| Navbar | `Navbar.tsx` | 顶部导航栏,包含 Logo、菜单和用户操作入口 | +| Footer | `Footer.tsx` | 页脚,包含品牌信息和导航链接 | ### 2.3 ui 组件 @@ -41,17 +47,22 @@ Veloform 的组件按照职责范围分为三个类别: | 组件名 | 文件名 | 职责 | |--------|--------|------| -| Button | `button.tsx` | 多功能按钮组件,支持变体、尺寸和状态 | -| Card | `card.tsx` | 卡片容器,提供统一的视觉容器 | -| Modal | `modal.tsx` | 模态对话框,支持自定义内容和动画 | +| Button | `Button.tsx` | 多功能按钮组件,支持变体、尺寸和状态 | +| Card | `Card.tsx` | 卡片容器,提供统一的视觉容器 | +| Modal | `Modal.tsx` | 模态对话框,支持自定义内容和动画 | +| Toast | `Toast.tsx` | 通知提示组件 | +| ThemeToggle | `ThemeToggle.tsx` | 主题切换按钮 | +| ErrorBoundary | `ErrorBoundary.tsx` | 错误边界,捕获组件级错误 | +| OnboardingGuide | `OnboardingGuide.tsx` | 新手引导组件 | +| SupportModal | `SupportModal.tsx` | 支持/帮助模态框 | ## 3. 命名规范 ### 3.1 文件命名 -- **组件文件**: 使用 kebab-case,例如 `build-list.tsx`、`component-selector.tsx` -- **工具文件**: 使用 kebab-case,例如 `firebase-service.ts`、`utils.ts` -- **类型文件**: 使用 kebab-case,例如 `index.ts` +- **组件文件**: 使用 **PascalCase**(如 `BuildList.tsx`、`ComponentSelector.tsx`、`BikeTypeSelector.tsx`) +- **工具/服务文件**: 使用 kebab-case(如 `firebase-service.ts`、`utils.ts`) +- **类型文件**: 使用 kebab-case 或 index.ts(如 `types/index.ts`) ### 3.2 组件命名 @@ -63,19 +74,36 @@ Veloform 的组件按照职责范围分为三个类别: ``` src/components/ -├── configurator/ -│ ├── build-list/ -│ │ ├── index.ts -│ │ ├── build-list.tsx -│ │ ├── build-list.test.tsx -│ │ └── build-list.module.css -│ ├── component-selector/ -│ └── ... -├── layout/ -│ └── navbar/ -└── ui/ - ├── button/ - └── ... +├── SyncProvider.tsx # 顶层 Firebase 同步提供者 +├── configurator/ # 配置器业务组件 +│ ├── BikeTypeSelector.tsx +│ ├── BuildList.tsx +│ ├── BuildList.test.tsx +│ ├── ComponentSelector.tsx +│ ├── ComponentDetailModal.tsx +│ ├── SummaryPanel.tsx +│ ├── SummaryPanel.test.tsx +│ ├── CostBreakdownChart.tsx +│ ├── RecommendedConfigs.tsx +│ ├── ComparePanel.tsx +│ └── ShareModal.tsx +├── layout/ # 布局组件 +│ ├── Navbar.tsx +│ └── Footer.tsx +├── sections/ # 营销/落地页分区组件 +│ ├── Hero.tsx +│ ├── Features.tsx +│ ├── Pricing.tsx +│ └── Cta.tsx +└── ui/ # 基础/复用 UI 组件 + ├── Button.tsx + ├── Card.tsx + ├── Modal.tsx + ├── Toast.tsx + ├── ErrorBoundary.tsx + ├── ThemeToggle.tsx + ├── OnboardingGuide.tsx + └── SupportModal.tsx ``` ## 4. Props 定义 @@ -195,41 +223,42 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; interface ConfigState { - selectedBikeType: string; - selectedComponents: Component[]; - totalPrice: number; - setSelectedBikeType: (type: string) => void; - addComponent: (component: Component) => void; - removeComponent: (componentId: string) => void; - resetConfig: () => void; + activeType: BikeType; + components: ConfigComponent[]; + setActiveType: (type: BikeType) => void; + replaceComponent: (component: ConfigComponent) => void; + setComponents: (components: ConfigComponent[]) => void; + resetToDefaults: () => void; } export const useConfigStore = create()( persist( (set) => ({ - selectedBikeType: 'road', - selectedComponents: [], - totalPrice: 0, - setSelectedBikeType: (type) => set({ selectedBikeType: type }), - addComponent: (component) => + activeType: 'Road', + components: getDefaultsForType('Road'), + setActiveType: (type) => + set({ + activeType: type, + components: getDefaultsForType(type), + configId: null, + manualConfigName: null, + }), + replaceComponent: (newComponent) => set((state) => ({ - selectedComponents: [...state.selectedComponents, component], + components: state.components.map((c) => + c.category === newComponent.category ? newComponent : c + ), })), - removeComponent: (componentId) => + setComponents: (components) => set({ components }), + resetToDefaults: () => set((state) => ({ - selectedComponents: state.selectedComponents.filter( - (c) => c.id !== componentId - ), + components: getDefaultsForType(state.activeType), + configId: null, + manualConfigName: null, })), - resetConfig: () => - set({ - selectedBikeType: 'road', - selectedComponents: [], - totalPrice: 0, - }), }), { - name: 'veloform-config', + name: 'veloform-config-storage', } ) ); @@ -241,15 +270,18 @@ export const useConfigStore = create()( import { useConfigStore } from '@/lib/store'; export function BuildList() { - const { selectedComponents, removeComponent } = useConfigStore(); + const components = useConfigStore((state) => state.components); + const setComponents = useConfigStore((state) => state.setComponents); return ( -
- {selectedComponents.map((component) => ( +
+ {components.map((component) => ( removeComponent(component.id)} + onRemove={(id) => + setComponents(components.filter((c) => c.id !== id)) + } /> ))}
@@ -290,7 +322,7 @@ export function BuildList() { ### 7.3 组件边界划分示例 ```typescript -// src/components/configurator/build-list.tsx +// src/components/configurator/BuildList.tsx 'use client'; import { motion } from 'framer-motion'; @@ -303,7 +335,7 @@ export function BuildList() { ```typescript // src/app/page.tsx -import { BuildList } from '@/components/configurator/build-list'; +import { BuildList } from '@/components/configurator/BuildList'; import { getServerComponents } from '@/lib/firebase-service'; export default async function ConfiguratorPage() { diff --git a/openspec/architecture/data-flow.md b/openspec/architecture/data-flow.md index 54650ce..fa90428 100644 --- a/openspec/architecture/data-flow.md +++ b/openspec/architecture/data-flow.md @@ -1,8 +1,8 @@ # 数据流设计 > **路径**: `/openspec/architecture/data-flow.md` -> **版本**: v3.5.1 -> **更新日期**: 2026-06-01 +> **版本**: v3.7.0 +> **更新日期**: 2026-06-09 ## 概述 @@ -26,34 +26,39 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; interface ConfigState { - activeType: BikeType; // 当前选中车型 - components: ConfigComponent[]; // 当前配置组件列表 - configId: string | null; // 当前配置 ID(已保存时) - manualConfigName: string | null;// 用户自定义配置名称 - allDbComponents: ConfigComponent[]; // 数据库组件缓存 - showLibrary: boolean; // 是否显示配置库模态框 - myConfigs: Configuration[]; // 用户保存的配置列表 - isLoggedIn: boolean; // 用户登录状态 - isSaving: boolean; // 保存操作进行中 - showComponentSelector: boolean; // 是否显示组件选择器 - editingComponentId: string; // 当前编辑的组件 ID + activeType: BikeType; // 当前选中车型 + components: ConfigComponent[]; // 当前配置组件列表 + configId: string | null; // 当前配置 ID(已保存时) + manualConfigName: string | null; // 用户自定义配置名称 + myConfigs: Configuration[]; // 用户保存的配置列表 + isSaving: boolean; // 保存操作进行中 + showComponentSelector: boolean; // 是否显示组件选择器 + editingComponentId: string; // 当前编辑的组件 ID + userId: string | null; // 当前登录用户的 Firebase UID + comparingConfigIds: string[]; // 正在对比的配置 ID 列表 } interface ConfigActions { setActiveType: (type: BikeType) => void; setComponents: (components: ConfigComponent[]) => void; - addComponent: (component: ConfigComponent) => void; - removeComponent: (id: string) => void; - updateComponent: (id: string, updates: Partial) => void; - setConfigId: (id: string | null) => void; + replaceComponent: (newComponent: ConfigComponent) => void; + loadConfiguration: (config: Configuration) => void; + resetToDefaults: () => void; setManualConfigName: (name: string | null) => void; - setShowLibrary: (show: boolean) => void; setMyConfigs: (configs: Configuration[]) => void; - setIsLoggedIn: (loggedIn: boolean) => void; - setIsSaving: (saving: boolean) => void; - setShowComponentSelector: (show: boolean) => void; - setEditingComponentId: (id: string) => void; - resetConfig: () => void; + setSaving: (saving: boolean) => void; + setConfigId: (id: string | null) => void; + setUserId: (userId: string | null) => void; + toggleComponentSelector: (componentId?: string) => void; + saveConfiguration: () => Promise; + deleteConfiguration: (configId: string) => Promise; + generateShareableLink: () => string; + exportConfiguration: () => string; + toggleCompare: (configId: string) => void; + clearCompare: () => void; + getComparingConfigs: () => Configuration[]; + getTotalCost: () => number; + getTotalWeight: () => number; } type ConfigStore = ConfigState & ConfigActions; @@ -63,54 +68,21 @@ export const useConfigStore = create()( (set, get) => ({ // 初始状态 activeType: 'Road', - components: ROAD_DEFAULT_COMPONENTS, + components: getDefaultsForType('Road'), configId: null, manualConfigName: null, - allDbComponents: [], - showLibrary: false, myConfigs: [], - isLoggedIn: false, isSaving: false, showComponentSelector: false, editingComponentId: '', + userId: null, + comparingConfigIds: [], - // Actions - setActiveType: (type) => set({ activeType: type }), - setComponents: (components) => set({ components }), - addComponent: (component) => - set((state) => ({ components: [...state.components, component] })), - removeComponent: (id) => - set((state) => ({ - components: state.components.filter((c) => c.id !== id), - })), - updateComponent: (id, updates) => - set((state) => ({ - components: state.components.map((c) => - c.id === id ? { ...c, ...updates } : c - ), - })), - setConfigId: (id) => set({ configId: id }), - setManualConfigName: (name) => set({ manualConfigName: name }), - setShowLibrary: (show) => set({ showLibrary: show }), - setMyConfigs: (configs) => set({ myConfigs: configs }), - setIsLoggedIn: (loggedIn) => set({ isLoggedIn: loggedIn }), - setIsSaving: (saving) => set({ isSaving: saving }), - setShowComponentSelector: (show) => set({ showComponentSelector: show }), - setEditingComponentId: (id) => set({ editingComponentId: id }), - resetConfig: () => set({ - activeType: 'Road', - components: ROAD_DEFAULT_COMPONENTS, - configId: null, - manualConfigName: null, - }), + // Actions 实现参见 src/lib/store.ts + // ... }), { name: 'veloform-config-storage', // localStorage key - partialize: (state) => ({ - activeType: state.activeType, - components: state.components, - manualConfigName: state.manualConfigName, - }), } ) ); @@ -171,14 +143,14 @@ graph TD B -->|props: configs| F[ComparePanel] C -->|onChange: setActiveType| A - D -->|onClick: updateComponent| A - D -->|onClick: removeComponent| A - E -->|onClick: saveConfig| G[FirebaseService] - F -->|onClick: loadConfig| A + D -->|onClick: replaceComponent| A + D -->|onClick: setComponents| A + E -->|onClick: saveConfiguration| G[FirebaseService] + F -->|onClick: toggleCompare| A - G -->|save/load| H[(Firestore)] - H -->|onAuthStateChanged| I[useAuthStore] - I -->|isLoggedIn| A + G -->|save/load/delete| H[(Firestore)] + H -->|onAuthStateChanged| I[useAuth / Firebase Auth] + I -->|userId| A ``` --- @@ -473,7 +445,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { 监听状态变化并同步到 localStorage: ```typescript -// Zustand persist middleware 已自动处理 +// Zustand persist middleware 已自动处理状态持久化 // 如需自定义同步逻辑: useEffect(() => { const config = { @@ -763,5 +735,5 @@ export function PreviewCanvas() { --- **文档路径**: `/openspec/architecture/data-flow.md` -**最后更新**: 2026-06-01 -**版本**: v3.5.1 +**最后更新**: 2026-06-09 +**版本**: v3.7.0 diff --git a/openspec/architecture/overview.md b/openspec/architecture/overview.md index 200abaa..7183ede 100644 --- a/openspec/architecture/overview.md +++ b/openspec/architecture/overview.md @@ -1,4 +1,4 @@ -# Veloform 架构概览 (v3.4.1) +# Veloform 架构概览 (v3.7.0) ## 项目概述 @@ -18,12 +18,12 @@ Veloform 是一个本地化(EN/ZH)、高性能的自行车配置器,专为 | **语言** | TypeScript | ~5.3.0 | | **样式** | Tailwind CSS (Mobile-first) | ^3.4.0 | | **状态管理** | Zustand | ^4.5.0 | -| **后端/数据库** | Firebase (Firestore) | ^10.0.0 | +| **后端/数据库** | Firebase (Firestore) | ^11.0.0 | | **动画** | Framer Motion | ^10.16.4 | | **代码检查** | ESLint + Prettier | ^9.39.1 / ^3.16.0 | | **测试** | Vitest | ^4.0.0 | | **部署** | Vercel | — | -| **国际化** | Custom I18n hook | — | +| **国际化** | Custom I18n hook(不依赖 next-intl) | — | --- @@ -58,20 +58,23 @@ export default async function ConfiguratorPage() { ``` app.tsx (root) ├── Zustand Store: useConfigStore - │ ├── state: activeType, components, isSaving, configId, showLibrary, myConfigs - │ ├── actions: setActiveType, addComponent, removeComponent, saveConfig, loadConfig - │ └── computed: configName, totalCost, baseWeight, totalWeight (via selectors) + │ ├── state: activeType, components, configId, manualConfigName, myConfigs, isSaving, + │ │ showComponentSelector, editingComponentId, userId, comparingConfigIds + │ ├── actions: setActiveType, replaceComponent, setComponents, loadConfiguration, + │ │ saveConfiguration, deleteConfiguration, toggleComponentSelector, + │ │ generateShareableLink, exportConfiguration, toggleCompare, clearCompare + │ └── computed: getTotalCost, getTotalWeight (via getters / selectors) │ ├── Navbar (Client Component) │ ├── hooks: useTheme, useLanguage - │ └── handlers: openLibrary, toggleTheme + │ └── handlers: toggleTheme, setLanguage │ ├── BuildList (Client Component) │ ├── props: components, isSaving - │ └── events: onSync, onEdit + │ └── events: onEdit, onRemove │ └── SummaryPanel (Client Component) - ├── props: name, type, weight, cost + ├── props: totalCost, totalWeight, activeType └── Framer Motion animations (panel transitions) ``` @@ -109,7 +112,7 @@ const FirebaseAuth = dynamic( - 使用 `use client` 指令明确标识客户端组件 - 服务端组件用于数据获取和布局,减少客户端 JavaScript - 使用 Zustand hooks (`useStore`) 进行状态管理,避免 prop drilling -- 组件文件名使用 `kebab-case`,导出组件使用 `PascalCase` +- 组件文件名使用 `PascalCase`(如 `BuildList.tsx`),组件导出名同样使用 `PascalCase` - 自定义 hooks 封装可复用逻辑 (`useBikeConfig`, `useAuth`, `useI18n`) --- @@ -120,29 +123,37 @@ const FirebaseAuth = dynamic( src/ ├── app/ # Next.js App Router │ ├── page.tsx # 首页/配置器 -│ ├── library/ -│ │ └── page.tsx # 配置库页面 -│ ├── layout.tsx # Root Layout -│ ├── providers.tsx # 全局提供者 -│ ├── globals.css # 全局样式 -│ └── middleware.ts # 中间件 +│ ├── layout.tsx # Root Layout +│ ├── globals.css # 全局样式 +│ └── middleware.ts # 中间件 │ -├── components/ # React 组件 -│ ├── configurator/ # 配置器组件 +├── components/ # React 组件 +│ ├── SyncProvider.tsx # 顶层同步提供者(Firebase) +│ │ +│ ├── configurator/ # 配置器业务组件 │ │ ├── BikeTypeSelector.tsx │ │ ├── BuildList.tsx +│ │ ├── BuildList.test.tsx │ │ ├── ComponentSelector.tsx │ │ ├── ComponentDetailModal.tsx │ │ ├── SummaryPanel.tsx +│ │ ├── SummaryPanel.test.tsx │ │ ├── CostBreakdownChart.tsx │ │ ├── RecommendedConfigs.tsx │ │ ├── ComparePanel.tsx │ │ └── ShareModal.tsx │ │ -│ ├── layout/ # 布局组件 -│ │ └── Navbar.tsx +│ ├── layout/ # 布局组件 +│ │ ├── Navbar.tsx +│ │ └── Footer.tsx +│ │ +│ ├── sections/ # 营销/落地页分区组件 +│ │ ├── Hero.tsx +│ │ ├── Features.tsx +│ │ ├── Pricing.tsx +│ │ └── Cta.tsx │ │ -│ └── ui/ # 基础 UI 组件 +│ └── ui/ # 基础/复用 UI 组件 │ ├── Button.tsx │ ├── Card.tsx │ ├── Modal.tsx @@ -152,27 +163,25 @@ src/ │ ├── OnboardingGuide.tsx │ └── SupportModal.tsx │ -├── lib/ # 工具库 -│ ├── i18n/ # 国际化 +├── lib/ # 工具库 +│ ├── i18n/ # 国际化(自定义 hook,不依赖 next-intl) │ │ ├── index.ts │ │ ├── en.ts │ │ └── zh-CN.ts │ │ -│ ├── store.ts # Zustand 状态管理 -│ ├── constants.ts # 应用常量 -│ ├── mock-data.ts # 模拟数据 -│ ├── recommended-configs.ts # 推荐配置 -│ ├── utils.ts # 工具函数 -│ ├── toast.ts # Toast 通知 -│ ├── firebase.ts # Firebase 配置 -│ └── firebase-service.ts # Firebase 服务 +│ ├── store.ts # Zustand 状态管理 +│ ├── constants.ts # 应用常量 +│ ├── recommended-configs.ts # 推荐配置 +│ ├── utils.ts # 工具函数 +│ ├── toast.ts # Toast 通知 +│ ├── firebase.ts # Firebase 初始化配置 +│ └── firebase-service.ts # Firebase 服务封装 │ -├── types/ # TypeScript 类型定义 +├── types/ # TypeScript 类型定义 │ └── index.ts │ -└── public/ # 静态资源 - ├── _headers # Vercel 头部配置 - └── _redirects # Vercel 重定向配置 +└── public/ # 静态资源 + └── _headers # Vercel 头部配置 ``` --- @@ -246,5 +255,5 @@ src/ --- -**最后更新**: 2026-05-26 -**版本**: v3.4.1 \ No newline at end of file +**最后更新**: 2026-06-09 +**版本**: v3.7.0 \ No newline at end of file diff --git a/openspec/architecture/state-management.md b/openspec/architecture/state-management.md index 32c9ada..b5e8848 100644 --- a/openspec/architecture/state-management.md +++ b/openspec/architecture/state-management.md @@ -1,9 +1,9 @@ # Veloform State Management Specification **文件路径**: `/workspace/openspec/architecture/state-management.md` -**版本**: v3.4.1 -**日期**: 2026-05-26 -**更新**: Zustand 状态管理规范 +**版本**: v3.7.0 +**日期**: 2026-06-09 +**更新**: Zustand 状态管理规范(使用 persist 中间件实现本地存储持久化) ## 1. 概述 diff --git a/openspec/design/ui-design-system.md b/openspec/design/ui-design-system.md index 16dc994..dc51cd1 100644 --- a/openspec/design/ui-design-system.md +++ b/openspec/design/ui-design-system.md @@ -1,8 +1,8 @@ # UI 设计系统 > **路径**: `/openspec/design/ui-design-system.md` -> **版本**: v2.1.0 -> **更新日期**: 2026-06-08 +> **版本**: v3.7.0 +> **更新日期**: 2026-06-09 ## 概述 @@ -75,10 +75,11 @@ Veloform 采用 CSS 变量系统实现深色/浅色主题切换,使用 Tailwin :root { --background: #ffffff; /* 页面主背景 */ --foreground: #1d1d1f; /* 主文本色 - Apple 深色文本 */ - --surface: #fafafa; /* 卡片/表面背景 */ - --surface-tertiary: #f5f5f7; /* 第三级表面色 */ + --surface: #f5f5f7; /* 卡片/表面背景 */ + --surface-secondary: #ffffff; /* 第二级表面色(卡片) */ + --surface-tertiary: #e5e5ea; /* 第三级表面色 */ --border: #d2d2d7; /* 默认边框 */ - --border-light: rgba(0, 0, 0, 0.06); /* 浅色边框 */ + --border-light: rgba(0, 0, 0, 0.08); /* 浅色边框 */ --muted: #6e6e73; /* 弱化文本 */ --secondary: #86868b; /* 次要文本 */ --accent: #34c759; /* 强调色 - Apple 绿色 */ @@ -92,11 +93,14 @@ Veloform 采用 CSS 变量系统实现深色/浅色主题切换,使用 Tailwin --background: #000000; /* 页面主背景 - 纯黑 */ --foreground: #ffffff; /* 主文本色 - 纯白 */ --surface: #1d1d1f; /* 卡片/表面背景 */ - --surface-tertiary: #272729; /* 第三级表面色 */ + --surface-secondary: #2c2c2e; /* 第二级表面色(卡片) */ + --surface-tertiary: #3a3a3c; /* 第三级表面色 */ --border: #3a3a3c; /* 默认边框 */ - --border-light: rgba(255, 255, 255, 0.06); /* 浅色边框 */ + --border-light: rgba(255, 255, 255, 0.08); /* 浅色边框 */ --muted: #6e6e73; /* 弱化文本 */ --secondary: #86868b; /* 次要文本 */ + --primary: #2997ff; /* 主色调 - Apple 深色蓝色 */ + --primary-hover: #409cff; /* 悬停状态 */ --accent: #30d158; /* 强调色 - Apple 深色绿色 */ } ``` @@ -148,27 +152,79 @@ const config: Config = { DEFAULT: '#0071e3', }, surface: { - DEFAULT: '#fafafa', + DEFAULT: '#f5f5f7', dark: '#1d1d1f', - light: '#fafafa', + light: '#f5f5f7', + secondary: '#ffffff', + tertiary: '#e5e5ea', }, border: { DEFAULT: '#d2d2d7', dark: '#3a3a3c', light: '#d2d2d7', }, - muted: '#6e6e73', - secondary: '#86868b', + muted: { + DEFAULT: '#6e6e73', + dark: '#6e6e73', + light: '#6e6e73', + }, accent: { DEFAULT: '#34c759', dark: '#30d158', light: '#34c759', }, + secondary: { + DEFAULT: '#86868b', + dark: '#86868b', + light: '#86868b', + }, success: '#34c759', warning: '#ff9500', error: '#ff3b30', info: '#0071e3', }, + borderRadius: { + '3xl': '1.75rem', + }, + animation: { + "fade-in": "fadeIn 0.4s ease-out", + "fade-in-up": "fadeInUp 0.8s ease-out", + "slide-up": "slideUp 0.4s ease-out", + "slide-in-right": "slideInRight 0.4s ease-out", + "scale-in": "scaleIn 0.4s cubic-bezier(0.4, 0, 0.2, 1)", + pulse: "pulse 2s ease-in-out infinite", + float: "float 8s ease-in-out infinite", + }, + keyframes: { + fadeIn: { + "0%": { opacity: "0" }, + "100%": { opacity: "1" }, + }, + fadeInUp: { + "0%": { opacity: "0", transform: "translateY(40px)" }, + "100%": { opacity: "1", transform: "translateY(0)" }, + }, + slideUp: { + "0%": { opacity: "0", transform: "translateY(10px)" }, + "100%": { opacity: "1", transform: "translateY(0)" }, + }, + slideInRight: { + "0%": { opacity: "0", transform: "translateX(40px)" }, + "100%": { opacity: "1", transform: "translateX(0)" }, + }, + scaleIn: { + "0%": { opacity: "0", transform: "scale(0.95)" }, + "100%": { opacity: "1", transform: "scale(1)" }, + }, + pulse: { + "0%, 100%": { opacity: "1" }, + "50%": { opacity: "0.5" }, + }, + float: { + "0%, 100%": { transform: "translateY(0px)" }, + "50%": { transform: "translateY(-15px)" }, + }, + }, }, }, }; @@ -178,6 +234,14 @@ const config: Config = { ## 字体系统 +### 字体加载策略 + +Veloform 不通过 Google Fonts 加载外部字体,原因是: +1. **SF Pro 系列是 Apple 专有字体**,Google Fonts 不提供,任何 `fonts.googleapis.com/css2?family=SF+Pro...` 的请求都会失败或回退到系统字体 +2. **减少不必要的网络请求**,提升 FCP(First Contentful Paint)指标 + +Apple 平台(macOS/iOS)预装 SF Pro Text/Display,其他平台通过系统字体栈优雅回退。 + ### 字体家族 ```css @@ -195,6 +259,11 @@ const config: Config = { .font-mono { font-family: 'SF Mono', 'JetBrains Mono', monospace; } + +/* 全局 body 字体栈(与 globals.css 对齐) */ +body { + font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'SF Pro Display', 'Segoe UI', sans-serif; +} ``` ### 字体权重 @@ -258,11 +327,12 @@ space-24 = 6rem /* 96px */ | 组件类型 | Padding | 示例 | |----------|---------|------| -| 按钮 (sm) | `px-4 py-2 min-h-[40px]` | 小按钮 | -| 按钮 (md) | `px-6 py-2.5 min-h-[44px]` | 默认按钮 | -| 按钮 (lg) | `px-8 py-3.5 min-h-[52px]` | 大按钮 | -| 卡片 | `p-6` | 内容卡片 | -| 模态框 | `p-6` | 模态框内容区 | +| 按钮 (sm) | `px-5 py-2 min-h-[40px]` | 小按钮 | +| 按钮 (md) | `px-7 py-3 min-h-[48px]` | 默认按钮 | +| 按钮 (lg) | `px-9 py-4 min-h-[56px]` | 大按钮 | +| 按钮 (icon) | `p-3 min-w-[48px] min-h-[48px]` | 图标按钮 | +| 卡片 | `p-8` | 内容卡片 | +| 模态框 | `p-8` | 模态框内容区 | | 输入框 | `px-3 py-2` | 表单输入 | --- @@ -275,8 +345,8 @@ space-24 = 6rem /* 96px */ .rounded-md { border-radius: 0.375rem; } /* 6px */ .rounded-lg { border-radius: 0.5rem; } /* 8px */ .rounded-xl { border-radius: 0.75rem; } /* 12px */ -.rounded-2xl { border-radius: 1rem; } /* 16px - 卡片 */ -.rounded-3xl { border-radius: 1.5rem; } /* 24px - 大卡片/Hero 图片 */ +.rounded-2xl { border-radius: 1rem; } /* 16px - 小卡片 */ +.rounded-3xl { border-radius: 1.75rem; } /* 28px - 大卡片/Hero 图片 */ .rounded-full { border-radius: 9999px; } /* 完全圆角 - 按钮 */ ``` @@ -285,12 +355,12 @@ space-24 = 6rem /* 96px */ | 元素 | 圆角 | 说明 | |------|------|------| | 按钮 | `rounded-full` | 胶囊形状 | -| 小图标容器 | `rounded-xl` | 12px | -| 卡片 | `rounded-2xl` | 16px | -| 模态框 | `rounded-2xl` | 16px | +| 小图标容器 | `rounded-2xl` | 16px | +| 卡片 | `rounded-3xl` | 28px | +| 模态框 | `rounded-3xl` | 28px | | 头像 | `rounded-full` | 圆形 | | 标签/徽章 | `rounded-full` | 胶囊形状 | -| Hero 图片 | `rounded-3xl` | 24px | +| Hero 图片 | `rounded-3xl` | 28px | --- @@ -298,20 +368,24 @@ space-24 = 6rem /* 96px */ ```css /* Apple 风格柔和阴影 */ ---shadow-card: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06); ---shadow-soft: 0 2px 10px rgba(0, 0, 0, 0.08); ---shadow-hero: 0 25px 50px -12px rgba(0, 0, 0, 0.1); +.shadow-apple { + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); +} + +.shadow-apple-lg { + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.12); +} ``` **使用场景**: | 元素 | 阴影 | 说明 | |------|------|------| -| 卡片(默认) | `shadow-sm` | 轻微浮起感 | -| 卡片(悬停) | `shadow-md` | 悬停时加深 | -| Hero 图片 | `shadow-2xl` + `shadow-black/10` | 明显层级 | -| 下拉菜单 | `shadow-lg` | 明显层级 | -| 模态框 | `shadow-2xl` | 最高层级 | +| 卡片(默认) | `shadow-apple` | 轻微浮起感 | +| 卡片(悬停) | `shadow-apple-lg` | 悬停时加深 | +| Hero 图片 | `shadow-apple-lg` | 明显层级 | +| 下拉菜单 | `shadow-apple-lg` | 明显层级 | +| 模态框 | `shadow-apple-lg` | 最高层级 | --- @@ -321,15 +395,13 @@ space-24 = 6rem /* 96px */ ```typescript animation: { - "fade-in": "fadeIn 0.3s ease-out", + "fade-in": "fadeIn 0.4s ease-out", "fade-in-up": "fadeInUp 0.8s ease-out", "slide-up": "slideUp 0.4s ease-out", "slide-in-right": "slideInRight 0.4s ease-out", "scale-in": "scaleIn 0.4s cubic-bezier(0.4, 0, 0.2, 1)", - "bounce-in": "bounceIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55)", - pulse: "pulse 1s ease-in-out infinite", - "pulse-slow": "pulseSlow 4s cubic-bezier(0.4, 0, 0.6, 1) infinite", - float: "float 6s ease-in-out infinite", + pulse: "pulse 2s ease-in-out infinite", + float: "float 8s ease-in-out infinite", }, keyframes: { fadeIn: { @@ -337,7 +409,7 @@ keyframes: { "100%": { opacity: "1" }, }, fadeInUp: { - "0%": { opacity: "0", transform: "translateY(30px)" }, + "0%": { opacity: "0", transform: "translateY(40px)" }, "100%": { opacity: "1", transform: "translateY(0)" }, }, slideUp: { @@ -352,10 +424,13 @@ keyframes: { "0%": { opacity: "0", transform: "scale(0.95)" }, "100%": { opacity: "1", transform: "scale(1)" }, }, - bounceIn: { - "0%": { opacity: "0", transform: "scale(0.3)" }, - "50%": { transform: "scale(1.05)" }, - "100%": { opacity: "1", transform: "scale(1)" }, + pulse: { + "0%, 100%": { opacity: "1" }, + "50%": { opacity: "0.5" }, + }, + float: { + "0%, 100%": { transform: "translateY(0px)" }, + "50%": { transform: "translateY(-15px)" }, }, }, ``` @@ -384,22 +459,26 @@ const spring = { ```css /* 玻璃态卡片 */ .glass-card { - @apply bg-surface/80 backdrop-blur-xl border border-border-light; + @apply bg-surface/70 backdrop-blur-2xl border border-border-light; } -/* 标准卡片 */ -.card { - @apply bg-surface rounded-2xl transition-all duration-200; +/* Apple 风格卡片 */ +.card-apple { + @apply bg-surface rounded-3xl border border-border-light; +} + +.card-apple-hover { + @apply hover:shadow-xl hover:-translate-y-1 transition-all duration-300; } /* 组件选择项 */ .component-item { - @apply flex items-center gap-4 p-4 bg-background rounded-xl cursor-pointer transition-all duration-200 hover:bg-surface-tertiary; + @apply flex items-center gap-4 p-6 bg-surface-secondary rounded-2xl cursor-pointer transition-all duration-300 hover:bg-surface-tertiary hover:shadow-md border border-border-light; } /* 标签 */ .tag { - @apply px-3 py-1 rounded-full text-xs font-medium; + @apply px-4 py-1.5 rounded-full text-xs font-semibold uppercase tracking-wider; } .tag-primary { @@ -409,6 +488,20 @@ const spring = { .tag-secondary { @apply bg-accent/10 text-accent; } + +/* 标题样式 */ +.text-apple-title { + @apply font-display font-semibold tracking-tight; +} + +.text-apple-body { + @apply font-sans font-normal; +} + +/* 渐变文本 */ +.text-gradient-primary { + @apply bg-clip-text text-transparent bg-gradient-to-r from-primary to-primary/70; +} ``` ### 按钮 (Button) @@ -427,18 +520,19 @@ const spring = { #### 尺寸 ```tsx - // px-4 py-2 min-h-[40px] - // px-6 py-2.5 min-h-[44px] - // px-8 py-3.5 min-h-[52px] - // p-2.5 min-w-[44px] min-h-[44px] + // px-5 py-2 min-h-[40px] + // px-7 py-3 min-h-[48px] + // px-9 py-4 min-h-[56px] + // p-3 min-w-[48px] min-h-[48px] ``` **样式特征**: - 圆角:`rounded-full`(胶囊形状) -- 字体:`font-medium` -- 动画:悬停缩放 `scale: 1.01`,点击缩放 `scale: 0.98` -- 过渡:`duration-150` -- 焦点:`focus:ring-2 focus:ring-primary/50` +- 字体:`font-medium`,字间距:`tracking-tight` +- 动画:悬停缩放 `scale: 1.02` + `y: -1`,点击缩放 `scale: 0.97` +- 过渡:`duration-300`,缓动:`ease: [0.4, 0, 0.2, 1]` +- 焦点:`focus:ring-4 focus:ring-primary/20` +- 阴影:主色调按钮有 `shadow-lg shadow-primary/20` ### 卡片 (Card) @@ -459,9 +553,10 @@ const spring = { ``` **样式特征**: -- 圆角:`rounded-2xl` -- 内边距:`p-6` -- 动画:悬停时 `y: -4` +- 圆角:`rounded-3xl`(28px) +- 内边距:`p-8` +- 动画:悬停时 `y: -6` +- 背景:`bg-surface-secondary` ### 模态框 (Modal) @@ -473,7 +568,7 @@ const spring = { **样式特征**: - 遮罩:`fixed inset-0 bg-black/50 backdrop-blur-sm` -- 内容:`bg-background rounded-2xl shadow-2xl` +- 内容:`bg-background rounded-3xl shadow-apple-lg` - 动画:`scaleIn` + `fadeIn` --- @@ -522,7 +617,7 @@ const spring = { ## 相关文档 -- [原型图说明](../prototype-guide.md) +- [原型图说明](../../prototype/prototype-guide.md) - [设计审查与优化建议](./design-review.md) - [组件设计规范](../architecture/component-design.md) - [编码规范](../development/coding-standards.md) @@ -533,7 +628,9 @@ const spring = { | 版本 | 日期 | 变更内容 | |------|------|---------| -| **v2.1.0** | 2026-06-08 | 参考 Apple 设计风格全面优化:更新 Hero 组件大图展示、Features 卡片布局、Pricing 定价卡片、Cta 行动号召、Navbar 和 Footer 导航组件 | +| **v3.1.0** | 2026-06-09 | 参考 Apple 设计风格优化原型:增加大图展示、充足留白、清晰视觉层次、渐变背景效果、主题切换功能 | +| v3.0.0 | 2026-06-08 | 全面 Apple 风格设计升级:新增 `surface-secondary`,优化颜色系统,加大圆角 `rounded-3xl`,新增 Apple 风格阴影,优化按钮和卡片动画,添加渐变文本和标题工具类 | +| v2.1.0 | 2026-06-08 | 参考 Apple 设计风格全面优化:更新 Hero 组件大图展示、Features 卡片布局、Pricing 定价卡片、Cta 行动号召、Navbar 和 Footer 导航组件 | | v2.0.0 | 2026-06-04 | 全面更新为 Apple 设计风格:主色调改为 #0071e3,字体改为 SF Pro,优化圆角和阴影系统 | | v1.3.0 | 2026-06-04 | 更新 Button、Card、Footer 组件文档 | | v1.2.0 | 2026-06-04 | 更新主题系统实现细节 | @@ -542,5 +639,5 @@ const spring = { --- **文档路径**: `/openspec/design/ui-design-system.md` -**最后更新**: 2026-06-08 -**版本**: v2.1.0 \ No newline at end of file +**最后更新**: 2026-06-09 +**版本**: v3.7.0 diff --git a/openspec/development/coding-standards.md b/openspec/development/coding-standards.md index cfbe60b..78ab471 100644 --- a/openspec/development/coding-standards.md +++ b/openspec/development/coding-standards.md @@ -1,4 +1,4 @@ -# 开发规范 (v3.4.1) +# 开发规范 (v3.7.0) ## 概述 @@ -553,9 +553,11 @@ export function PrimaryButton({ children, onClick }: PrimaryButtonProps) { **Tailwind 配置**: -```javascript -// tailwind.config.js -module.exports = { +```typescript +// tailwind.config.ts +import type { Config } from 'tailwindcss'; + +export default { content: [ './app/**/*.{js,ts,jsx,tsx,mdx}', './components/**/*.{js,ts,jsx,tsx,mdx}' @@ -920,32 +922,29 @@ const translations = { }; ``` -### 2. 使用 next-intl +### 2. 使用自定义 i18n hook(不依赖 next-intl) + +项目使用自定义 Zustand store + hook 实现国际化,结构如下: -```typescript -// messages/en.json -{ - "nav": { - "home": "Home", - "library": "Library" - }, - "preview": { - "weight": "Weight", - "cost": "Cost" - } -} +``` +src/lib/i18n/ +├── index.ts # useTranslation() hook 定义 + Zustand store +├── en.ts # 英文翻译 +└── zh-CN.ts # 中文翻译 ``` ```tsx // components/NavLink.tsx -import { useTranslations } from 'next-intl'; +'use client'; + +import { useTranslation } from '@/lib/i18n'; interface NavLinkProps { href: string; } export function NavLink({ href }: NavLinkProps) { - const t = useTranslations(); + const t = useTranslation(); const label = href === '/' ? t('nav.home') : t('nav.library'); return {label}; @@ -958,18 +957,17 @@ export function NavLink({ href }: NavLinkProps) { // components/LanguageSwitcher.tsx 'use client'; -import { useRouter, usePathname } from 'next/navigation'; +import { useLanguage, useSetLanguage } from '@/lib/i18n'; export function LanguageSwitcher() { - const router = useRouter(); - const pathname = usePathname(); - - const switchLocale = (locale: string) => { - router.push(pathname.replace(/^\/[a-z]{2}/, `/${locale}`)); - }; + const language = useLanguage(); + const setLanguage = useSetLanguage(); return ( - setLanguage(e.target.value as 'en' | 'zh-CN')} + > @@ -1146,5 +1144,5 @@ export function Dashboard() { --- -**最后更新**: 2026-05-26 -**版本**: v3.4.1 \ No newline at end of file +**最后更新**: 2026-06-09 +**版本**: v3.7.0 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6a922cc..462cfac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "veloform-next", - "version": "3.8.0", + "version": "3.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "veloform-next", - "version": "3.8.0", + "version": "3.7.0", "dependencies": { "@base-ui/react": "^1.5.0", "class-variance-authority": "^0.7.1", @@ -1858,9 +1858,9 @@ } }, "node_modules/@dotenvx/dotenvx": { - "version": "1.71.3", - "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.71.3.tgz", - "integrity": "sha512-WSmox5aD+XxJEUEOTk7gKLpd5+Iz9Nik89Zpbu5DijMln6LsFiv3xpNKBMc/b9sSkUlKvAblzrhik2TqKFE7NA==", + "version": "1.71.2", + "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.71.2.tgz", + "integrity": "sha512-Xj9T3Wr+Bo4ILKf9PZJBYJ4SJiZGC/pqIdzOMbX9jgAFb0oGuKkusLleYHN/N6zanZixNvmuMVWYR1T3YJuVTA==", "license": "BSD-3-Clause", "dependencies": { "commander": "^11.1.0", @@ -6648,20 +6648,20 @@ } }, "node_modules/body-parser": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", - "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", - "content-type": "^2.0.0", + "content-type": "^1.0.5", "debug": "^4.4.3", - "http-errors": "^2.0.1", - "iconv-lite": "^0.7.2", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", - "qs": "^6.15.2", - "raw-body": "^3.0.2", - "type-is": "^2.1.0" + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { "node": ">=18" @@ -6671,19 +6671,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/body-parser/node_modules/content-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", - "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/body-parser/node_modules/iconv-lite": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", @@ -14209,9 +14196,9 @@ } }, "node_modules/shadcn/node_modules/postcss-selector-parser": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", - "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.2.tgz", + "integrity": "sha512-Wjvt4scRFouioIInHf51IFNP4ltJ2EngJM+cZPGiqbKetBfmP3vpdPV8ID2S6JS6/jdo74N8+aEYH9lQr2C6sA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", diff --git a/prototype/README.md b/prototype/README.md index a85e40c..46cfec8 100644 --- a/prototype/README.md +++ b/prototype/README.md @@ -1,30 +1,16 @@ # Veloform 原型设计 > **路径**: `/prototype/README.md` -> **版本**: v4.0.0 -> **更新日期**: 2024-06-08 +> **版本**: v3.7.0 +> **更新日期**: 2026-06-09 ## 📁 目录结构 ``` prototype/ -├── README.md # 原型设计总览(本文件) -├── prototype.html # ✨ 独立原型文件(可直接打开) -├── prototype-guide.md # 原型与设计系统说明 -├── design-critique.md # 设计审视报告 -│ -├── design/ # 设计文档 -│ ├── ui-recommendations.md # UI/UX 优化建议 -│ ├── responsive-guidelines.md # 响应式设计指南 -│ ├── accessibility-guidelines.md # 可访问性指南 -│ └── design-optimization-report.md # 世界级优化报告(新) -│ -├── documentation/ # 文档资料 -│ ├── design-system-summary.md # 设计系统摘要 -│ └── component-mapping.md # 组件映射表 -│ -└── archive/ # 已废弃的原型文件 - └── README.md +├── README.md # 原型设计总览(本文件) +├── prototype.html # 独立 HTML 原型文件(可直接在浏览器中打开) +└── prototype-guide.md # 原型与设计系统说明、原型与实际代码映射 ``` ## 🎯 概述 @@ -81,7 +67,7 @@ npm run dev - [UI 设计系统](../openspec/design/ui-design-system.md) - 官方设计系统 - [设计审查](../openspec/design/design-review.md) - 设计质量评估 -## ✨ 新特性 (v4.0) +## ✨ 当前版本特性 (v3.7) 1. **世界级设计标准** - 采用 Awwwards 级别的视觉效果 @@ -107,9 +93,9 @@ npm run dev ## 🎨 设计理念 ### 视觉风格 -- **主题**: 深色模式 + 紫色渐变 -- **字体**: Poppins(标题)+ Inter(正文) -- **风格**: 现代、精致、科技感 +- **主题**: Apple 风格极简,浅色/深色双主题,蓝色(#0071e3)主色 + 绿色(#34c759)强调色 +- **字体**: 系统字体栈 -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'SF Pro Display', 'Segoe UI', sans-serif,Apple 平台自动使用 SF Pro +- **风格**: 极简主义、大图展示、充足留白、清晰视觉层次 - **层次**: 清晰的视觉层级和空间感 ### 交互原则 @@ -125,18 +111,18 @@ npm run dev ## 📋 更新日志 -### v4.0.0 (2024-06-08) -- ✨ 全新创建的世界级设计原型 +### v3.7.0 (2026-06-09) +- ✨ Apple 风格极简设计,双主题支持,完整的 Next.js + Tailwind + Firebase 技术栈 - 🎨 优化的视觉效果和动画 - 📱 完善的移动端体验 - 📚 添加国际顶级设计师视角的优化报告 ### v3.6.0 (2026-06-06) -- 原版本的更新内容... +- Apple 风格设计升级,页脚组件,主题切换功能 --- **文档路径**: `/prototype/README.md` -**最后更新**: 2024-06-08 -**版本**: v4.0.0 +**最后更新**: 2026-06-09 +**版本**: v3.7.0 diff --git a/prototype/prototype-guide.md b/prototype/prototype-guide.md index 915b5de..506b1bd 100644 --- a/prototype/prototype-guide.md +++ b/prototype/prototype-guide.md @@ -1,8 +1,8 @@ # Veloform 自行车配置器 - 原型与设计系统 > **路径**: `/prototype/prototype-guide.md` -> **版本**: v3.0.0 -> **更新日期**: 2026-06-06 +> **版本**: v3.7.0 +> **更新日期**: 2026-06-09 ## 概述 @@ -15,7 +15,7 @@ HTML 原型现在包含以下特性,与 Next.js 应用保持一致: -- ✅ 深色主题设计 +- ✅ 深色/浅色主题切换 - ✅ 车型选择器集成到主界面 - ✅ 组件配置与实时更新 - ✅ 配置汇总面板 @@ -25,9 +25,10 @@ HTML 原型现在包含以下特性,与 Next.js 应用保持一致: - ✅ 用户引导流程 - ✅ 支持与帮助 - ✅ 响应式布局设计 -- ✅ 渐变网格与噪点背景效果 +- ✅ 渐变背景效果 - ✅ 玻璃态设计元素 - ✅ 平滑过渡动画 +- ✅ Apple 设计风格(大图、留白、清晰层次) ### 使用 HTML 原型 @@ -43,7 +44,7 @@ HTML 原型是一个完全独立的文件,包含了所有必要的 HTML、CSS | 阶段 | 说明 | 状态 | |------|------|------| -| HTML 原型 | 初始高保真原型,纯 HTML/CSS/JS 实现 | ❌ 已废弃 | +| HTML 原型 | 初始高保真原型,纯 HTML/CSS/JS 实现 | ✅ 当前版本 | | Next.js 应用 | 生产级应用,完整功能实现 | ✅ 当前版本 | ### 当前项目特性 @@ -51,7 +52,7 @@ HTML 原型是一个完全独立的文件,包含了所有必要的 HTML、CSS 实际的 Next.js 应用现已包含所有原型功能,并新增以下特性: - **深色/浅色主题切换**:完整的双主题支持 - **页脚组件**:含版本号显示 -- **增强视觉效果**:渐变网格、噪点背景、玻璃态效果等 +- **增强视觉效果**:渐变背景、玻璃态效果等 - **完整的后端集成**:Firebase 认证和数据持久化 - **国际化支持**:中英文双语切换 @@ -63,60 +64,68 @@ HTML 原型是一个完全独立的文件,包含了所有必要的 HTML、CSS #### 主色调 -Veloform 采用深色主题设计,以青绿色(Teal)为主色调: +Veloform 采用 Apple 风格蓝色作为主色调: ```css :root { - /* 主色调 - 青绿色系 */ - --primary: #14b8a6; /* 主色 */ - --primary-light: #2dd4bf; /* 浅色变体 */ - --primary-dark: #0d9488; /* 深色变体 */ - - /* 背景色 */ - --background: #0a0a0b; /* 主背景(近黑色)*/ - --surface: #141415; /* 卡片/表面背景 */ - --surface-hover: #1a1a1b; /* 悬停状态背景 */ - - /* 边框 */ - --border: #27272a; /* 边框颜色 */ - - /* 文本颜色 */ - --foreground: #fafafa; /* 主文本 */ - --foreground-muted: #a1a1aa; /* 次要文本 */ - --foreground-dim: #71717a; /* 弱化文本 */ - - /* 功能色 */ - --accent: #f59e0b; /* 强调色(琥珀色)*/ - --success: #22c55e; /* 成功状态 */ - --warning: #eab308; /* 警告状态 */ - --error: #ef4444; /* 错误状态 */ + --background: #ffffff; + --foreground: #1d1d1f; + --surface: #f5f5f7; + --surface-secondary: #ffffff; + --surface-tertiary: #e5e5ea; + --border: #d2d2d7; + --border-light: rgba(0, 0, 0, 0.08); + --muted: #6e6e73; + --secondary: #86868b; + --primary: #0071e3; + --primary-hover: #0077ed; + --accent: #34c759; } ``` +#### 深色主题 + +```css +.dark { + --background: #000000; + --foreground: #ffffff; + --surface: #1d1d1f; + --surface-secondary: #2c2c2e; + --surface-tertiary: #3a3a3c; + --border: #3a3a3c; + --border-light: rgba(255, 255, 255, 0.08); + --muted: #6e6e73; + --secondary: #86868b; + --primary: #2997ff; + --primary-hover: #409cff; + --accent: #30d158; +} +``` + +> 注:阴影效果使用 CSS utility class 实现,不是 CSS 变量。 + #### 颜色使用规范 | 用途 | 颜色变量 | 示例 | |------|----------|------| | 主要按钮 | `--primary` | 保存、确认操作 | -| 次要按钮 | `--surface` + border | 取消、返回操作 | +| 次要按钮 | `--surface-secondary` + border | 取消、返回操作 | | 强调元素 | `--accent` | 价格高亮、重要提示 | -| 成功提示 | `--success` | 保存成功 Toast | -| 错误提示 | `--error` | 操作失败 Toast | -| 悬停状态 | `--surface-hover` | 卡片悬停效果 | +| 悬停状态 | `--surface-tertiary` | 卡片悬停效果 | ### 字体系统 #### 字体家族 ```css -/* 标题字体 - Space Grotesk(几何无衬线)*/ +/* 标题字体 - SF Pro Display */ h1, h2, h3, h4, h5, h6, .font-display { - font-family: 'Space Grotesk', sans-serif; + font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', sans-serif; } -/* 正文字体 - Inter(现代人文无衬线)*/ +/* 正文字体 - SF Pro Text */ body, p, span, div { - font-family: 'Inter', system-ui, sans-serif; + font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'SF Pro Display', 'Segoe UI', sans-serif; } ``` @@ -133,15 +142,9 @@ body, p, span, div { #### 字号层级 ```css -/* 基于 1.25 比例尺 */ -.text-xs { font-size: 0.75rem; } /* 12px - 辅助文字 */ -.text-sm { font-size: 0.875rem; } /* 14px - 小字 */ -.text-base { font-size: 1rem; } /* 16px - 正文 */ -.text-lg { font-size: 1.125rem; } /* 18px - 大正文 */ -.text-xl { font-size: 1.25rem; } /* 20px - 小标题 */ -.text-2xl { font-size: 1.5rem; } /* 24px - 标题 */ -.text-3xl { font-size: 1.875rem; } /* 30px - 大标题 */ -.text-4xl { font-size: 2.25rem; } /* 36px - 超大标题 */ +/* 基于 clamp 实现响应式 */ +.hero h1 { font-size: clamp(40px, 8vw, 56px); } +.section-title { font-size: clamp(28px, 5vw, 40px); } ``` ### 间距系统 @@ -170,26 +173,18 @@ body, p, span, div { .rounded-lg { border-radius: 0.75rem; } /* 12px - 卡片 */ .rounded-xl { border-radius: 1rem; } /* 16px - 大卡片 */ .rounded-2xl { border-radius: 1.5rem; } /* 24px - 模态框 */ +.rounded-3xl { border-radius: 1.75rem; } /* 28px - Hero 卡片 */ .rounded-full { border-radius: 9999px; } /* 完全圆角 - 按钮 */ ``` ### 阴影系统 ```css -.shadow-sm { - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); +.shadow-soft { + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); } -.shadow-md { - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), - 0 2px 4px -1px rgba(0, 0, 0, 0.06); -} -.shadow-lg { - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), - 0 4px 6px -2px rgba(0, 0, 0, 0.05); -} -.shadow-xl { - box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), - 0 10px 10px -5px rgba(0, 0, 0, 0.04); +.shadow-card { + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.12); } ``` @@ -198,43 +193,29 @@ body, p, span, div { #### 过渡效果 ```css -/* 标准过渡 */ -.transition-all { - transition-property: all; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 200ms; -} - -/* 快速过渡 */ -.transition-fast { - transition-duration: 150ms; +/* 标准过渡 - Apple 风格缓动 */ +.bike-card { + transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1); } -/* 慢速过渡 */ -.transition-slow { - transition-duration: 300ms; +/* 按钮过渡 */ +.btn { + transition: all 0.25s ease; } ``` #### 关键帧动画 ```css -/* 淡入动画 */ -@keyframes fadeIn { - from { opacity: 0; transform: translateY(10px); } - to { opacity: 1; transform: translateY(0); } -} - -/* 缩放进入 */ -@keyframes scaleIn { - from { opacity: 0; transform: scale(0.95); } - to { opacity: 1; transform: scale(1); } +/* 脉冲动画 */ +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } } -/* 滑动进入 */ -@keyframes slideIn { - from { opacity: 0; transform: translateX(-20px); } - to { opacity: 1; transform: translateX(0); } +/* 悬停上移 */ +.bike-card:hover { + transform: translateY(-8px); } ``` @@ -248,18 +229,32 @@ body, p, span, div { | 变体 | 样式 | 用途 | |------|------|------| -| Primary | 渐变背景 + 白色文字 | 主要操作(保存、确认) | -| Secondary | 透明背景 + 边框 | 次要操作(取消、返回) | -| Ghost | 无边框 + 悬停背景 | 轻量操作(关闭、更多) | -| Danger | 红色背景 | 危险操作(删除) | +| Primary | 主色背景 + 白色文字 | 主要操作(保存、确认) | +| Secondary | 透明背景 + 主色文字 | 次要操作(了解更多) | -#### 尺寸 +#### 样式特征 -| 尺寸 | Padding | 字体大小 | -|------|---------|----------| -| sm | 8px 16px | 14px | -| md | 12px 24px | 14px | -| lg | 16px 32px | 16px | +```css +.btn { + padding: 14px 28px; + border-radius: 9999px; + font-weight: 500; + font-size: 17px; + letter-spacing: -0.01em; +} + +.btn-primary { + background: var(--primary); + color: white; + box-shadow: 0 4px 14px rgba(0, 113, 227, 0.25); +} + +.btn-primary:hover { + background: var(--primary-hover); + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(0, 113, 227, 0.35); +} +``` ### 卡片 (Card) @@ -271,59 +266,42 @@ body, p, span, div {

卡片内容

-
``` **样式特征**: -- 背景:`var(--surface)` -- 边框:`1px solid var(--border)` -- 圆角:`12px` -- 内边距:`16px` +- 背景:`var(--surface-secondary)` +- 边框:`1px solid var(--border-light)` +- 圆角:`24px` +- 内边距:`28px` - 悬停效果:轻微上移 + 阴影加深 -### 模态框 (Modal) +### 车型选择器 (Bike Type Selector) ```html -