Files
nj/docs/opendesign/warm-notes-design-spec.md
iven b320641d9c
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
fix(app): 全链路验证修复 — 编译错误/CORS/迁移/启动脚本
前端修复:
- calendar_page: 移除不存在的 JournalEntry.content getter
- responsive_scaffold: 移除不存在的 notchThickness 参数
- splash_page: SingleTickerProvider → TickerProvider (多 AnimationController)
- profile_page: UserRoleType.name → .code (修复运行时崩溃)
- 导入缺失的 user.dart

后端修复:
- class_service: generate_class_code 取 UUID 后6位(随机部分)避免碰撞
- diary_role_seed: 移除不存在的 id 列,使用复合主键 ON CONFLICT

基础设施:
- config/default.toml: CORS 改为通配符(开发模式)
- scripts/dev.sh: 统一启动脚本(自动清理端口)
- docs/opendesign/: Open Design 设计规格 HTML 原型稿

验证结果: flutter analyze 0 error, cargo test 77/77 通过, 17个页面全部渲染正常
2026-06-02 01:03:58 +08:00

1122 lines
35 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 暖记 (Warm Notes) — 完整设计规格文档
> **面向 LLM 的设计还原参考** — 本文档包含暖记手账日记 App 的完整视觉系统、组件规范、布局结构、交互状态和响应式行为。前端开发者(或 AI 编码助手)应以此文档为设计还原的唯一依据。
---
## 1. 项目概览
| 属性 | 值 |
|------|------|
| App 名称 | 暖记 (Warm Notes) |
| 定位 | 面向学生的多终端手账日记 App |
| 视觉风格 | 温暖治愈 / 手绘插画风 |
| 目标平台 | iOS、Android、iPad/平板、桌面客户端 |
| 设计稿页面 | 27 页面(手机 14 + 平板 6 + 桌面 6 + 启动页 1 |
| 主题系统 | 双主题:暖阳(默认)+ 松风 + 各自暗色模式 |
| 技术约束 | 手机视口 390×844iPhone 15 Pro平板 1024×768桌面 1440×900 |
---
## 2. 设计 Token 系统
### 2.1 颜色系统
#### 主题 1暖阳 (Warm Sun) — 默认
```css
:root {
/* Surface 表面 */
--bg: #FFF8F0; /* 页面背景:暖白 */
--surface: #FFFFFF; /* 卡片/面板背景:纯白 */
--surface-warm: #FFF3E6; /* 温暖表面:浅橙,用于 hover 态和选中态背景 */
/* Foreground 前景 */
--fg: #2D2420; /* 主文字:深棕黑 */
--fg-2: #5C4F47; /* 次要文字:中棕 */
--muted: #7A6D63; /* 辅助文字:灰棕 */
--meta: #8B7E74; /* 元数据/标签文字:浅灰棕 */
/* Border 边框 */
--border: #E8DDD4; /* 标准边框 */
--border-soft: #F0E8DF; /* 柔和边框:分隔线、卡片边框 */
/* Accent 主色调 — 柔和珊瑚/赤陶橙 */
--accent: #E07A5F; /* 主强调色:珊瑚橙 */
--accent-on: #FFF8F0; /* 主强调色上的文字色 */
--accent-hover: #D06A4F; /* 主强调色 hover 态 */
--accent-active: #C05A3F; /* 主强调色 active/按下态 */
--accent-glow: rgba(224, 122, 95, 0.25); /* 强调色光晕 */
/* Secondary 辅助色 — 鼠尾草绿 */
--secondary: #81B29A;
--secondary-soft: #D4E8DC; /* 浅绿背景 */
/* Tertiary 第三色 — 暖金 */
--tertiary: #F2CC8F;
--tertiary-soft: #FBE8C8; /* 浅金背景 */
/* Rose 玫瑰色 */
--rose: #D4A5A5;
--rose-soft: #F0DADA; /* 浅玫瑰背景 */
/* Semantic 语义色 */
--success: #5A9E7E; /* 成功/正向 */
--warn: #D4A843; /* 警告 */
--danger: #C93D3D; /* 危险/错误 */
}
```
#### 主题 2松风 (Pine Wind) — 男学生向
激活方式:`document.documentElement.setAttribute('data-theme', 'pine')`
```css
[data-theme="pine"] {
--bg: #F2F3F0; /* 冷灰白背景 */
--surface: #FFFFFF;
--surface-warm: #E9EAE6;
--fg: #23272F; /* 深灰黑文字 */
--fg-2: #484E58;
--muted: #6E7380;
--meta: #8A8F9A;
--border: #D5D2CD;
--border-soft: #E3E1DC;
--accent: #4A7B9D; /* 钢蓝色主强调 */
--accent-on: #FFFFFF;
--accent-hover: #3F6A8A;
--accent-active: #345A78;
--accent-glow: rgba(74, 123, 157, 0.25);
--secondary: #5B9E7A; /* 森林绿 */
--secondary-soft: #D6E8DE;
--tertiary: #C49A3C; /* 琥珀金 */
--tertiary-soft: #F0E4C8;
--rose: #7A8B6A; /* 橄榄绿 */
--rose-soft: #E0E8D8;
}
```
#### 暗色模式
通过 `@media (prefers-color-scheme: dark)` 自动切换。暖阳暗色:
```css
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) {
--bg: #1A1614;
--surface: #2A2520;
--surface-warm: #332D28;
--fg: #F0E8DF;
--fg-2: #C4B8AA;
--muted: #9B8E82;
--meta: #7A6D63;
--border: #3A3530;
--border-soft: #302B26;
--accent: #E8907A; /* 暗色下珊瑚橙偏亮 */
--accent-on: #1A1614;
/* ...其余 token 自动适配 */
}
}
```
**关键实现要点:**
- 颜色系统全部通过 CSS 自定义属性Custom Properties定义主题切换只需切换 `data-theme` 属性
- 所有组件和页面必须引用 CSS 变量,禁止硬编码颜色值
- 暗色模式跟随系统偏好自动切换,无需用户手动操作
---
### 2.2 字体排版
```css
/* 字体家族 */
--font-display: "Quicksand", "Nunito", "SF Pro Rounded", -apple-system, system-ui, sans-serif;
--font-body: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
--font-mono: ui-monospace, "JetBrains Mono", monospace;
--font-handwritten: "Caveat", "Kalam", cursive;
/* 字号阶梯 */
--text-xs: 11px; /* 极小标签、元数据 */
--text-sm: 13px; /* 小号文字、辅助信息 */
--text-base: 15px; /* 正文基准 */
--text-md: 17px; /* 中号,强调正文 */
--text-lg: 20px; /* 小标题 */
--text-xl: 24px; /* 区域标题 */
--text-2xl: 30px; /* 页面标题 */
--text-3xl: 38px; /* 大标题 */
--text-4xl: 48px; /* 超大标题/展示用 */
/* 行高 */
--leading-body: 1.6; /* 正文行高 */
--leading-tight: 1.25; /* 紧凑行高,用于标题 */
```
**字体使用规则:**
- **Display (Quicksand)** — 页面标题、区域标题、Tab 标签、按钮文字。特征:圆润、几何感、友好
- **Body (Nunito)** — 正文段落、列表内容、描述文字。特征:清晰、可读性好
- **Handwritten (Caveat)** — 装饰性文字、心情区域标题、手写风标签。特征:手写感、温暖
- **Mono** — 仅用于数据展示、时间戳
**实现注意事项:**
- Quicksand 和 Nunito 需从 Google Fonts 加载:`https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&family=Nunito:wght@400;500;600;700&display=swap`
- Caveat 手写字体:`https://fonts.googleapis.com/css2?family=Caveat:wght@400;600;700&display=swap`
- 字重使用Regular (400), Medium (500), SemiBold (600), Bold (700)
- 全局开启字体平滑:`-webkit-font-smoothing: antialiased`
---
### 2.3 间距系统
```css
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 20px;
--space-6: 24px;
--space-8: 32px;
--space-10: 40px;
--space-12: 48px;
```
**间距使用规则:**
- `space-1` (4px):图标与文字间距、微调
- `space-2` (8px)紧凑元素间距、Checkbox 与文字
- `space-3` (12px):同行元素间距、内边距紧凑
- `space-4` (16px):标准卡片内边距、表单项间距
- `space-5` (20px):页面水平内边距、卡片间距
- `space-6` (24px):区域分隔、大卡片内边距
- `space-8` (32px):大区域分隔
- `space-10` (40px):页面级间距
---
### 2.4 圆角
```css
--radius-sm: 10px; /* 小元素:输入框、小卡片 */
--radius-md: 16px; /* 标准卡片 */
--radius-lg: 22px; /* 大卡片、特殊区域 */
--radius-xl: 28px; /* 全宽面板、底部弹窗 */
--radius-pill: 9999px; /* 胶囊按钮、标签、头像 */
```
**关键规则:**
- 所有卡片和交互元素都有明显的圆角(最小 10px
- 按钮统一使用 pill 圆角(全圆)
- 不使用直角矩形(除特殊装饰元素外)
---
### 2.5 阴影与高度
```css
--elev-soft: 0 2px 12px rgba(45, 36, 32, 0.06); /* 轻浮起:卡片默认 */
--elev-medium: 0 4px 20px rgba(45, 36, 32, 0.08); /* 中浮起:悬浮面板 */
--elev-float: 0 8px 32px rgba(45, 36, 32, 0.12); /* 高浮起:弹窗、模态 */
--shadow-accent: 0 4px 14px rgba(224, 122, 95, 0.25); /* 强调色阴影 */
--shadow-accent-hover: 0 6px 20px rgba(224, 122, 95, 0.35);
--shadow-input-focus: 0 0 0 3px rgba(224, 122, 95, 0.2);
--focus-ring: 0 0 0 3px rgba(224, 122, 95, 0.45); /* 焦点环 */
```
---
### 2.6 运动与动画
```css
--motion-fast: 150ms; /* 快速过渡:按钮、颜色变化 */
--motion-base: 250ms; /* 基准动画 */
--ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1); /* 弹性缓动:悬停、缩放 */
--ease-standard: cubic-bezier(0.2, 0, 0, 1); /* 标准缓动:位移、透明度 */
```
**动画系统:**
```css
/* 页面进入动画 */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
.anim-fade { animation: fadeIn 0.5s var(--ease-standard) both; }
@keyframes slideUp {
from { opacity: 0; transform: translateY(40px); }
to { opacity: 1; transform: translateY(0); }
}
.anim-slide { animation: slideUp 0.6s var(--ease-bounce) both; }
@keyframes scaleIn {
from { opacity: 0; transform: scale(0.9); }
to { opacity: 1; transform: scale(1); }
}
.anim-scale { animation: scaleIn 0.4s var(--ease-bounce) both; }
/* 装饰浮动动画 */
@keyframes float {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-10px) rotate(5deg); }
}
```
**动画延迟阶梯(用于列表/卡片错落进入):**
- 第 1 项:`animation-delay: 0.1s`
- 第 2 项:`animation-delay: 0.15s`
- 第 3 项:`animation-delay: 0.2s`
- 递增 0.05s
---
### 2.7 布局常量
```css
--container-max: 390px; /* 手机最大内容宽度 */
--safe-top: 54px; /* iOS 顶部安全区(含 Dynamic Island */
--safe-bottom: 34px; /* iOS 底部安全区(含 Home Indicator */
--tab-height: 56px; /* 底部 Tab 栏高度 */
--touch-min: 44px; /* 最小触控区域WCAG 2.5.8 */
```
---
## 3. 组件规范
### 3.1 iOS 设备框架
手机端页面以 iPhone 15 Pro 为基准:
```
视口: 390 × 844 px
Dynamic Island: 居中, 126×36px, 黑色圆角矩形, top:12px
状态栏: 高度 54px (--safe-top), 包含时间(左)、信号/电池图标(右)
Home Indicator: 底部居中, 134×5px, 半透明, 距底部 8px
```
**实现要点:**
- 每个手机屏幕页面固定 `width: 390px; height: 844px; overflow: hidden`
- 内容区域上留 `--safe-top`,下留 `--tab-height + --safe-bottom`
- Dynamic Island 使用绝对定位 + `z-index: 200`
---
### 3.2 状态栏 (Status Bar)
```html
<div class="status-bar">
<span class="time">9:41</span>
<div class="icons">
<!-- 信号、WiFi、电池 SVG 图标 -->
</div>
</div>
```
样式:
- `display: flex; justify-content: space-between; align-items: center`
- `padding: 14px 28px 0; height: var(--safe-top)`
- `font-size: var(--text-sm); font-weight: 600`
- 时间使用 `font-variant-numeric: tabular-nums` 保证等宽数字
---
### 3.3 底部 Tab 栏 (Bottom Tab Bar)
```html
<nav class="tab-bar" role="tablist">
<button class="tab-item active" role="tab" aria-selected="true">
<svg>...</svg>
<span>首页</span>
</button>
<!-- 5 个 tab首页、日历、写日记中间突出、发现、我的 -->
</nav>
```
样式规则:
```
位置: absolute, bottom:0, width:100%
高度: calc(var(--tab-height) + var(--safe-bottom)) = 90px
背景: var(--surface)
上边框: 1px solid var(--border-soft)
布局: flex, justify-content: space-around
```
**Tab Item 样式:**
- 默认态:`color: var(--muted)`
- 选中态:`color: var(--accent)`,添加 `.active`
- 图标尺寸24×24px
- 文字:`font-size: var(--text-xs)` (11px)
- 最小触控区域44px
**中间「写日记」按钮特殊处理:**
- 使用独立圆形按钮,向上突出 tab 栏
- `width: 44px; height: 44px; border-radius: 50%`
- `background: var(--accent)`
- `margin-top: -16px`(向上突出)
- 添加 `box-shadow: 0 4px 12px var(--shadow-accent)` 增强浮起感
- 图标颜色:`var(--accent-on)`(即背景色上方的文字色)
---
### 3.4 按钮 (Buttons)
#### 主要按钮 (Primary)
```html
<button class="btn btn-primary">保存</button>
<!---->
<button class="enter-btn">开始记录</button>
```
样式:
```
padding: 14px 28px (标准) / 16px 48px (大型)
border-radius: var(--radius-pill) = 9999px
background: var(--accent)
color: var(--accent-on)
font-family: var(--font-display)
font-size: var(--text-md) / var(--text-lg)
font-weight: 600-700
min-height: 44px (满足触控要求)
box-shadow: 0 4px 14px var(--shadow-accent)
transition: all var(--motion-fast)
```
交互状态:
| 状态 | 样式 |
|------|------|
| Default | `background: var(--accent)` |
| Hover | `background: var(--accent-hover); transform: translateY(-1px ~ -2px); box-shadow: 增大` |
| Active | `background: var(--accent-active); transform: scale(0.97 ~ 0.98)` |
| Focus | `box-shadow: var(--focus-ring)` |
| Disabled | `opacity: 0.5; cursor: not-allowed` |
#### 次要按钮 (Secondary)
```
background: var(--surface)
color: var(--fg)
border: 1.5px solid var(--border)
Hover → border-color: var(--accent); color: var(--accent)
```
#### 幽灵按钮 (Ghost)
```
background: transparent
color: var(--muted)
Hover → color: var(--accent)
```
---
### 3.5 卡片 (Cards)
#### 标准卡片
```html
<div class="card">
<!-- 内容 -->
</div>
```
```
background: var(--surface)
border-radius: var(--radius-md) = 16px
padding: var(--space-5) = 20px
box-shadow: var(--elev-soft)
border: 1px solid var(--border-soft)
```
#### 日记条目卡片 (Entry Card)
```html
<div class="entry-card">
<div class="entry-preview">🌸</div>
<div class="entry-info">
<div class="entry-date">5月30日 · 周六</div>
<div class="entry-title">图书馆的午后</div>
<div class="entry-excerpt">今天在图书馆自习...</div>
</div>
<div class="entry-mood">😊</div>
</div>
```
布局:
```
display: flex; gap: var(--space-4) = 16px
预览缩略图: 72×72px, border-radius: 10px, flex-shrink: 0
标题: font-family: var(--font-display); font-weight: 600; 单行截断
摘要: 两行截断 (-webkit-line-clamp: 2)
交互: Hover → translateY(-1px); Active → scale(0.98)
```
#### 今日日记卡片 (Today Card) — 渐变特殊卡片
```
background: linear-gradient(135deg, var(--accent) 0%, var(--tertiary) 100%)
border-radius: var(--radius-lg) = 22px
padding: var(--space-6) = 24px
```
装饰圆形:
- 右上角120×120px, `rgba(255,255,255,0.12)`, 位置 `top: -30px; right: -30px`
- 左下角80×80px, `rgba(255,255,255,0.08)`, 位置 `bottom: -20px; left: 40px`
写按钮(浮动在右下角):
```
position: absolute; bottom: 20px; right: 20px
width: 48px; height: 48px; border-radius: 50%
background: white; box-shadow: 0 4px 12px rgba(0,0,0,0.1)
Hover → scale(1.1)
```
---
### 3.6 输入框 (Input Fields)
```html
<div class="input-group">
<span class="input-icon"><!-- SVG 图标 --></span>
<input type="tel" placeholder="请输入手机号" aria-label="手机号">
</div>
```
样式:
```
height: 50px
padding: 0 16px 0 46px (左侧留出图标空间)
border: 1.5px solid var(--border)
border-radius: var(--radius-pill)
font-family: var(--font-body); font-size: var(--text-base)
background: var(--surface)
transition: border-color var(--motion-fast)
```
交互状态:
| 状态 | 样式 |
|------|------|
| Default | `border: 1.5px solid var(--border)` |
| Focus | `border-color: var(--accent); box-shadow: var(--shadow-input-focus)` |
| Placeholder | `color: var(--meta)` |
**带操作按钮的输入框(验证码):**
- 输入框 `padding-right: 110px`
- 操作按钮:`position: absolute; right: 6px`, `color: var(--accent)`
- 倒计时态:`opacity: 0.6; disabled`
**密码切换按钮:**
- `position: absolute; right: 14px`
- 触控区域:`min-height: 44px; min-width: 44px`(满足 WCAG
---
### 3.7 标签/Chip
```html
<button class="chip active">全部</button>
<button class="chip">风景</button>
```
```
padding: 6px 14px
border-radius: var(--radius-pill)
font-size: var(--text-sm) = 13px; font-weight: 500
background: var(--surface); color: var(--fg-2); border: 1px solid var(--border)
Active → background: var(--accent); color: var(--accent-on); border-color: var(--accent)
```
---
### 3.8 心情选择器 (Mood Selector)
```html
<div class="mood-options">
<button class="mood-opt selected">
<span class="face">😊</span>
<span class="label">开心</span>
</button>
<!-- 5 个心情:开心😊、平静😐、难过😢、生气😡、思考🤔 -->
</div>
```
布局:
```
display: flex; justify-content: space-between
每个选项: display: flex; flex-direction: column; align-items: center; gap: 4px
最小触控: min-width: 44px; min-height: 44px
```
状态:
- Default: `background: none`
- Hover: `background: var(--surface-warm)`
- Selected: `background: var(--surface-warm); .label { color: var(--accent); font-weight: 600 }`
---
### 3.9 社交登录按钮
```html
<div class="social-row">
<button class="social-btn wechat"><!-- 微信 SVG --></button>
<button class="social-btn apple"><!-- Apple SVG --></button>
<button class="social-btn google"><!-- Google SVG --></button>
</div>
```
```
尺寸: 56×56px, border-radius: 50%
间距: gap: var(--space-5) = 20px
Hover → translateY(-2px); box-shadow: var(--elev-soft)
Active → scale(0.95)
```
品牌色:
- 微信:`background: #07C160; border-color: #07C160`Hover → `#06AD56`
- Apple`background: #1D1D1F; border-color: #1D1D1F`Hover → `#333`
- Google`background: var(--surface)`(白色背景)
---
### 3.10 顶部导航栏 (Top Nav)
```
display: flex; align-items: center; justify-content: space-between
padding: var(--space-4) var(--space-5)
标题: font-family: var(--font-display); font-size: var(--text-xl); font-weight: 700
操作按钮: width: var(--touch-min) = 44px; height: 44px; border-radius: pill
背景: var(--surface)
```
---
### 3.11 日期/时间条 (Date Strip) — 编辑器内
```
position: absolute; top: calc(var(--safe-top) + 44px)
display: flex; justify-content: space-between; align-items: center
padding: var(--space-2) var(--space-4)
background: var(--surface)
```
---
### 3.12 月历导航 (Month Navigation)
```html
<div class="month-header">
<div class="month-title">2026年5月</div>
<div class="month-nav">
<button><!-- 左箭头 --></button>
<button><!-- 右箭头 --></button>
</div>
</div>
```
导航按钮:
```
min-width: 44px; min-height: 44px
border-radius: 50%; border: 1.5px solid var(--border)
background: var(--surface)
Hover → border-color: var(--accent); color: var(--accent)
```
---
### 3.13 视图切换 (View Toggle)
```html
<div class="view-toggle">
<button class="active"></button>
<button></button>
</div>
```
```
display: flex; background: var(--surface)
border-radius: var(--radius-pill); padding: 3px
border: 1px solid var(--border-soft)
Active button: background: var(--accent); color: var(--accent-on); box-shadow: var(--elev-soft)
```
---
## 4. 页面结构与布局
### 4.1 手机端页面390×844
每个手机屏幕的通用结构:
```html
<body style="width:390px; height:844px; overflow:hidden; background:var(--bg); position:relative">
<!-- Dynamic Island绝对定位z-index:200 -->
<div class="dynamic-island"></div>
<!-- 内容区域 -->
<div class="content-area" style="position:absolute; top:0; left:0; right:0;
bottom:calc(var(--tab-height) + var(--safe-bottom)); overflow-y:auto;
padding:0 var(--space-5); padding-top:calc(var(--safe-top) + var(--space-2));
scrollbar-width:none">
<!-- 页面内容 -->
</div>
<!-- 底部 Tab 栏绝对定位z-index:100 -->
<nav class="tab-bar">...</nav>
<!-- Home Indicator绝对定位底部居中 -->
<div class="home-indicator"></div>
</body>
```
**内容区域计算:**
- 可用高度844 - 54 (safe-top) - 56 (tab-height) - 34 (safe-bottom) = 700px
- 水平内边距:`var(--space-5)` = 20px
---
### 4.2 启动页 (Splash)
**布局:** 全屏居中
- 背景:渐变 `linear-gradient(165deg, var(--bg) 0%, var(--tertiary-soft) 40%, accent混合50%透明 100%)`
- App 图标120×120px, `border-radius: 32px`, 渐变背景 + 白色半透明装饰圆
- 品牌名42px, `font-weight: 700`, `letter-spacing: 2px`
- 副标题:`var(--text-md)`, `var(--muted)`
- 进入按钮:底部 `calc(var(--safe-bottom) + 40px)`
- 装饰元素:浮动星星/圆圈,`opacity: 0.08~0.25`, `animation: float 4~6s`
---
### 4.3 引导页 (Onboarding)
- 3 步水平滑动
- 每步包含:插图区域 + 标题 + 描述 + 进度指示器
- 底部:跳过/下一步/开始使用按钮
---
### 4.4 首页日记流 (Home Daily)
**内容层级(从上到下):**
1. 问候语区域(日期 + 问候 + 搜索按钮)
2. 连续记录徽章streak badge
3. 心情选择区域(卡片包裹)
4. 今日日记卡片(渐变特殊卡片 + 写按钮)
5. 快速统计3 列统计卡片)
6. 最近记录标题(标题 + "查看全部"链接)
7. 日记条目卡片列表
**统计卡片布局:**
```
display: flex; gap: var(--space-3)
每个 stat-card: flex:1; text-align:center
数字: var(--text-2xl) = 30px; font-weight:700
标签: var(--text-xs) = 11px; color: var(--muted)
```
---
### 4.5 手账编辑器 (Editor)
**布局层级:**
1. 顶部工具栏:返回/日期/保存按钮
2. 日期 & 心情条
3. 画布区域(可滚动)
4. 底部工具面板(文字/贴纸/画笔/照片/模板 Tab 切换)
**工具栏:**
```
height: calc(var(--safe-top) + 44px)
background: var(--surface); border-bottom: 1px solid var(--border-soft)
按钮: min-width/min-height: 36px; border-radius: pill
保存按钮: background: var(--accent); color: var(--accent-on)
```
---
### 4.6 日历视图 (Calendar)
**内容层级:**
1. 月份标题 + 前后导航
2. 视图切换(月/周)
3. 星期行(日 一 二 三 四 五 六)
4. 日期网格7 列 grid
5. 心情色彩标记(每个有日记的日期显示对应心情颜色)
6. 时间轴/日记详情
**日历网格:**
```
display: grid; grid-template-columns: repeat(7, 1fr)
日期单元格: aspect-ratio:1; display:flex; align-items:center; justify-content:center
当前日期: background:var(--accent); color:var(--accent-on); border-radius:50%
有日记日期: 底部小圆点标记,颜色对应心情
```
---
### 4.7 登录/注册 (Login)
**布局:** 上下分区
- 上部品牌区域Logo + 名称 + 标语),带装饰元素和渐变背景
- 下部:表单区域(圆角顶部覆盖),包含输入框和按钮
**表单切换逻辑:**
- 默认显示登录态(手机号 + 验证码 + 登录按钮)
- 点击「立即注册」切换为注册态(增加昵称、密码、协议勾选)
- 通过 `.is-register` 类控制字段显隐
**社交登录区域:**
- 分隔线:`display:flex; align-items:center; gap`, 两侧 `flex:1``1px` 横线
- 三个圆形社交按钮微信、Apple、Google
---
### 4.8 发现页 (Discover)
**内容层级:**
1. 搜索栏
2. 热门话题标签(横向滚动 chips
3. 精选模板(横向滚动卡片)
4. 达人日记(瀑布流/列表)
---
### 4.9 搜索结果页 (Search)
**内容层级:**
1. 搜索输入框(带返回按钮)
2. 搜索历史标签
3. 结果分类筛选 tabs
4. 搜索结果列表
---
## 5. 多平台适配规则
### 5.1 平板端 (iPad 1024×768)
**布局差异:**
- 使用侧边栏导航替代底部 Tab 栏
- 内容区域采用双列布局
- 编辑器使用分栏模式(左侧画布 + 右侧工具面板)
- 日历采用月历 + 时间轴双栏并排
**关键适配代码:**
```css
@media (min-width: 768px) {
/* 侧边栏导航 */
.sidebar { width: 240px; position: fixed; left: 0; top: 0; bottom: 0; }
.main-content { margin-left: 240px; }
/* 双列网格 */
.content-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
/* 编辑器分栏 */
.editor-layout { display: grid; grid-template-columns: 1fr 320px; }
}
```
### 5.2 桌面端 (1440×900)
**布局差异:**
- 固定侧边栏(宽 280px+ 多列内容区
- 编辑器全宽画布 + 右侧属性面板
- 日历三栏布局(统计 + 月历 + 日记详情)
- 更高的信息密度:更多内容可见区域
**关键适配代码:**
```css
@media (min-width: 1024px) {
.sidebar { width: 280px; }
.content-grid { grid-template-columns: repeat(3, 1fr); }
.editor-layout { grid-template-columns: 1fr 380px; }
.calendar-layout { grid-template-columns: 280px 1fr 380px; }
}
```
---
## 6. 主题切换系统
### 工作原理
1. **默认主题**暖阳Warm Sun`:root` 直接定义
2. **松风主题**:通过 `data-theme="pine"` 属性切换
3. **暗色模式**`@media (prefers-color-scheme: dark)` 自动响应
4. **持久化**`localStorage.setItem('warmnotes-theme', themeId)`
5. **跨 Tab 同步**`window.addEventListener('storage', ...)` 监听变化
### 切换按钮
- 固定位置:`position:fixed; top:8px; right:8px; z-index:10000`
- 外观:圆角胶囊,包含色点 + 主题名称
- 点击循环切换:暖阳 → 松风 → 暖阳
---
## 7. 无障碍 (Accessibility)
### 已实现的 WCAG 要点
1. **触控区域**:所有交互元素 `min-height: 44px`(满足 WCAG 2.5.8
2. **焦点环**`box-shadow: var(--focus-ring)` 统一在 `:focus-visible` 显示
3. **ARIA 标签**:所有按钮带 `aria-label`Tab 栏使用 `role="tablist"` / `role="tab"` / `aria-selected`
4. **语义 HTML**`<nav>``<button>``<form>``<label>` 正确使用
5. **装饰元素隐藏**`aria-hidden="true"` 标记所有装饰性 SVG
6. **减弱动画**`@media (prefers-reduced-motion: reduce)` 将所有动画降至最小
7. **颜色对比度**:前景色 `#2D2420``#FFF8F0` 背景上对比度约 10.5:1满足 AAA
---
## 8. CSS 参考实现 — :root 自定义属性
将以下代码直接用于项目 `:root`,所有组件引用变量即可:
```css
:root {
/* Surface */
--bg: #FFF8F0;
--surface: #FFFFFF;
--surface-warm: #FFF3E6;
/* Text */
--fg: #2D2420;
--fg-2: #5C4F47;
--muted: #7A6D63;
--meta: #8B7E74;
/* Borders */
--border: #E8DDD4;
--border-soft: #F0E8DF;
/* Colors */
--accent: #E07A5F;
--accent-on: #FFF8F0;
--accent-hover: #D06A4F;
--accent-active: #C05A3F;
--accent-glow: rgba(224, 122, 95, 0.25);
--secondary: #81B29A;
--secondary-soft: #D4E8DC;
--tertiary: #F2CC8F;
--tertiary-soft: #FBE8C8;
--rose: #D4A5A5;
--rose-soft: #F0DADA;
--success: #5A9E7E;
--warn: #D4A843;
--danger: #C93D3D;
/* Typography */
--font-display: "Quicksand", "Nunito", "SF Pro Rounded", -apple-system, system-ui, sans-serif;
--font-body: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
--font-mono: ui-monospace, "JetBrains Mono", monospace;
--font-handwritten: "Caveat", "Kalam", cursive;
--text-xs: 11px; --text-sm: 13px; --text-base: 15px; --text-md: 17px;
--text-lg: 20px; --text-xl: 24px; --text-2xl: 30px; --text-3xl: 38px; --text-4xl: 48px;
--leading-body: 1.6; --leading-tight: 1.25;
/* Spacing */
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
--space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px; --space-12: 48px;
/* Radius */
--radius-sm: 10px; --radius-md: 16px; --radius-lg: 22px; --radius-xl: 28px; --radius-pill: 9999px;
/* Elevation */
--elev-soft: 0 2px 12px rgba(45, 36, 32, 0.06);
--elev-medium: 0 4px 20px rgba(45, 36, 32, 0.08);
--elev-float: 0 8px 32px rgba(45, 36, 32, 0.12);
--shadow-accent: 0 4px 14px rgba(224, 122, 95, 0.25);
--shadow-accent-hover: 0 6px 20px rgba(224, 122, 95, 0.35);
--shadow-input-focus: 0 0 0 3px rgba(224, 122, 95, 0.2);
--focus-ring: 0 0 0 3px rgba(224, 122, 95, 0.45);
--bg-frosted: rgba(255, 248, 240, 0.85);
/* Touch */
--touch-min: 44px;
/* Motion */
--motion-fast: 150ms; --motion-base: 250ms;
--ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
/* Layout */
--container-max: 390px; --safe-top: 54px; --safe-bottom: 34px; --tab-height: 56px;
}
```
---
## 9. 完整页面清单
### 手机端 (14 页面)
| # | 文件 | 名称 | 描述 | 主要组件 |
|---|------|------|------|---------|
| 1 | splash.html | 启动页 | 品牌展示 + 进入引导 | App图标、品牌名、进入按钮、浮动装饰 |
| 2 | onboarding.html | 引导页 | 3 步核心功能介绍 | 滑动卡片、进度条、跳过/下一步 |
| 3 | home-daily.html | 首页日记流 | 心情+今日日记+历史 | 问候语、心情选择、今日卡片、统计、日记列表、Tab栏 |
| 4 | editor.html | 手账编辑器 | 文字/贴纸/画笔/照片 | 工具栏、日期条、画布、底部工具面板 |
| 5 | calendar.html | 日历视图 | 月历+心情+时间轴 | 月份导航、视图切换、日历网格、时间轴 |
| 6 | mood-tracker.html | 心情追踪 | 心情趋势+天气+洞察 | 图表、趋势线、统计卡片 |
| 7 | stickers.html | 贴纸素材库 | 分类+素材包+收藏 | 分类Tab、素材网格、收藏标记 |
| 8 | templates.html | 模板画廊 | 日/周/月模板 | 模板预览卡片、分类筛选 |
| 9 | weekly.html | 周概览 | 七天总结 | 周日历、每日摘要 |
| 10 | monthly.html | 月度概览 | 心情色彩日历+精选 | 心情日历、精选日记 |
| 11 | profile.html | 个人中心 | 成就+设置+同步 | 用户信息、成就列表、设置项 |
| 12 | login.html | 登录/注册 | 手机号+社交登录 | 品牌区、输入框、社交按钮、登录/注册切换 |
| 13 | discover.html | 发现页 | 热门话题+模板+达人日记 | 搜索栏、话题chips、推荐卡片 |
| 14 | search.html | 搜索结果 | 历史+分类筛选 | 搜索框、历史标签、结果列表 |
### 平板端 (6 页面)
| # | 文件 | 名称 | 布局差异 |
|---|------|------|---------|
| 1 | tablet/home-daily.html | 首页日记流 | 侧边栏导航 + 双列内容 |
| 2 | tablet/editor.html | 手账编辑器 | 宽画布 + 右侧贴纸面板 |
| 3 | tablet/calendar.html | 日历视图 | 月历 + 时间轴双栏并排 |
| 4 | tablet/login.html | 登录/注册 | 宽屏双栏登录布局 |
| 5 | tablet/discover.html | 发现页 | 多列推荐布局 |
| 6 | tablet/search.html | 搜索结果 | 筛选面板 + 多列结果 |
### 桌面端 (6 页面)
| # | 文件 | 名称 | 布局差异 |
|---|------|------|---------|
| 1 | desktop/home-daily.html | 首页日记流 | 固定侧边栏 + 日记流 + 心情/统计面板 |
| 2 | desktop/editor.html | 手账编辑器 | 工具条 + 全宽画布 + 右侧属性面板 |
| 3 | desktop/calendar.html | 日历视图 | 统计 + 月历 + 日记详情三栏 |
| 4 | desktop/login.html | 登录/注册 | 全屏居中登录卡片 |
| 5 | desktop/discover.html | 发现页 | 多列网格推荐 |
| 6 | desktop/search.html | 搜索结果 | 侧边筛选 + 多列结果 |
---
## 10. 交互行为规范
### 10.1 登录/注册流程
1. 默认显示登录模式
2. 输入手机号(仅数字,自动过滤非数字字符)
3. 点击「获取验证码」→ 按钮进入 60 秒倒计时
4. 输入验证码(仅数字)
5. 点击「登录」提交表单
6. 切换到注册模式:增加昵称、密码(可切换显隐)、协议勾选
7. 社交登录微信、Apple、Google 三个圆形按钮
### 10.2 心情选择
1. 每日首次进入首页弹出心情选择
2. 5 个固定心情:开心😊、平静😐、难过😢、生气😡、思考🤔
3. 选中态:背景变色 + 标签高亮为 accent 色
4. 天气信息显示在右侧
### 10.3 日记卡片交互
1. 今日日记卡片:点击打开编辑器
2. 浮动写按钮hover 放大 1.1 倍
3. 历史日记条目hover 微上浮 1pxactive 缩放 0.98
### 10.4 编辑器交互
1. 顶部工具栏固定
2. 画布区域可自由滚动
3. 底部工具面板通过 Tab 切换(文字/贴纸/画笔/照片/模板)
4. 保存按钮:点击保存
### 10.5 日历交互
1. 月份切换:左右箭头
2. 视图切换:月/周模式
3. 日期点击:显示当日日记详情
4. 有日记的日期显示心情颜色标记
---
## 11. 设计还原注意事项(前端开发者必读)
### 11.1 必须遵守
1. **所有颜色必须用 CSS 变量** — 禁止硬编码 `#E07A5F` 等色值,必须写 `var(--accent)`
2. **字体加载** — Quicksand、Nunito、Caveat 从 Google Fonts CDN 加载,需在 HTML head 中引入
3. **最小触控区域 44px** — 所有按钮、链接、可点击元素
4. **圆角** — 最小 10px按钮统一 pill (9999px)
5. **卡片阴影** — 使用 `var(--elev-soft)` 系列,不要自定义阴影
6. **间距使用 space 变量** — 不要用 `margin: 15px` 这种近似值
7. **动画缓动** — 交互类用 `--ease-bounce`,过渡类用 `--ease-standard`
8. **安全区** — 顶部留 54px (Dynamic Island),底部留 34px (Home Indicator)
9. **焦点可见** — 所有可交互元素 `focus-visible` 时显示 `var(--focus-ring)`
### 11.2 常见偏差
| 设计稿 | 常见实现偏差 | 正确做法 |
|--------|------------|---------|
| 圆角 16px 卡片 | 写成 8px 或 12px | `border-radius: var(--radius-md)` = 16px |
| Pill 按钮 | 写成 `border-radius: 20px` | `border-radius: var(--radius-pill)` = 9999px |
| 温暖白背景 | 写成 `#FFFFFF``#FAFAFA` | `var(--bg)` = `#FFF8F0` |
| 珊瑚橙按钮 | 写成 `#FF6B35``#E8734A` | `var(--accent)` = `#E07A5F` |
| 20px 页面边距 | 写成 `padding: 16px` | `padding: 0 var(--space-5)` = 20px |
| 弹性按钮 hover | 直接 `transform: scale(1.05)` | `translateY(-1px)` + `box-shadow` 增强 |
| Tab 栏高度 | 写成 49px | `var(--tab-height)` = 56px |
| 中间 Tab 突出 | 不突出或突出不够 | `margin-top: -16px` + 圆形 accent 按钮 |
### 11.3 渐变使用场景
仅以下场景使用渐变:
1. **启动页背景**`linear-gradient(165deg, var(--bg) 0%, var(--tertiary-soft) 40%, accent-mix 100%)`
2. **今日日记卡片**`linear-gradient(135deg, var(--accent) 0%, var(--tertiary) 100%)`
3. **App 图标**`linear-gradient(135deg, var(--accent) 0%, var(--tertiary) 100%)`
4. **概览页 hero 背景**`radial-gradient(ellipse at center, accent-mix-6% 0%, transparent 60%)`
其他所有卡片/面板使用纯色 `var(--surface)` 背景。
---
## 12. 文件结构参考
```
warm-notes/
├── index.html # 多平台概览页launcher
├── css/
│ ├── tokens.css # 设计 Token颜色、字体、间距等
│ ├── components.css # 共享组件样式Tab栏、按钮、卡片等
│ └── editor-common.css # 编辑器共享样式
├── js/
│ └── theme-switcher.js # 主题切换逻辑
├── screens/
│ ├── splash.html # 启动页
│ ├── onboarding.html # 引导页
│ ├── home-daily.html # 首页日记流
│ ├── editor.html # 手账编辑器
│ ├── calendar.html # 日历视图
│ ├── mood-tracker.html # 心情追踪
│ ├── stickers.html # 贴纸素材库
│ ├── templates.html # 模板画廊
│ ├── weekly.html # 周概览
│ ├── monthly.html # 月度概览
│ ├── profile.html # 个人中心
│ ├── login.html # 登录/注册
│ ├── discover.html # 发现页
│ ├── search.html # 搜索结果
│ ├── tablet/ # 平板端适配
│ │ ├── shared.css
│ │ ├── home-daily.html
│ │ ├── editor.html
│ │ ├── calendar.html
│ │ ├── login.html
│ │ ├── discover.html
│ │ └── search.html
│ └── desktop/ # 桌面端适配
│ ├── shared.css
│ ├── home-daily.html
│ ├── editor.html
│ ├── calendar.html
│ ├── login.html
│ ├── discover.html
│ └── search.html
```