前端修复: - 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个页面全部渲染正常
35 KiB
35 KiB
暖记 (Warm Notes) — 完整设计规格文档
面向 LLM 的设计还原参考 — 本文档包含暖记手账日记 App 的完整视觉系统、组件规范、布局结构、交互状态和响应式行为。前端开发者(或 AI 编码助手)应以此文档为设计还原的唯一依据。
1. 项目概览
| 属性 | 值 |
|---|---|
| App 名称 | 暖记 (Warm Notes) |
| 定位 | 面向学生的多终端手账日记 App |
| 视觉风格 | 温暖治愈 / 手绘插画风 |
| 目标平台 | iOS、Android、iPad/平板、桌面客户端 |
| 设计稿页面 | 27 页面(手机 14 + 平板 6 + 桌面 6 + 启动页 1) |
| 主题系统 | 双主题:暖阳(默认)+ 松风 + 各自暗色模式 |
| 技术约束 | 手机视口 390×844(iPhone 15 Pro),平板 1024×768,桌面 1440×900 |
2. 设计 Token 系统
2.1 颜色系统
主题 1:暖阳 (Warm Sun) — 默认
: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')
[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) 自动切换。暖阳暗色:
@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 字体排版
/* 字体家族 */
--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 间距系统
--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 圆角
--radius-sm: 10px; /* 小元素:输入框、小卡片 */
--radius-md: 16px; /* 标准卡片 */
--radius-lg: 22px; /* 大卡片、特殊区域 */
--radius-xl: 28px; /* 全宽面板、底部弹窗 */
--radius-pill: 9999px; /* 胶囊按钮、标签、头像 */
关键规则:
- 所有卡片和交互元素都有明显的圆角(最小 10px)
- 按钮统一使用 pill 圆角(全圆)
- 不使用直角矩形(除特殊装饰元素外)
2.5 阴影与高度
--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 运动与动画
--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); /* 标准缓动:位移、透明度 */
动画系统:
/* 页面进入动画 */
@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 布局常量
--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)
<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: centerpadding: 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)
<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)
<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)
标准卡片
<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)
<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)
<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
<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)
<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 社交登录按钮
<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)
<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)
<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)
每个手机屏幕的通用结构:
<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)
内容层级(从上到下):
- 问候语区域(日期 + 问候 + 搜索按钮)
- 连续记录徽章(streak badge)
- 心情选择区域(卡片包裹)
- 今日日记卡片(渐变特殊卡片 + 写按钮)
- 快速统计(3 列统计卡片)
- 最近记录标题(标题 + "查看全部"链接)
- 日记条目卡片列表
统计卡片布局:
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)
布局层级:
- 顶部工具栏:返回/日期/保存按钮
- 日期 & 心情条
- 画布区域(可滚动)
- 底部工具面板(文字/贴纸/画笔/照片/模板 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)
内容层级:
- 月份标题 + 前后导航
- 视图切换(月/周)
- 星期行(日 一 二 三 四 五 六)
- 日期网格(7 列 grid)
- 心情色彩标记(每个有日记的日期显示对应心情颜色)
- 时间轴/日记详情
日历网格:
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)
内容层级:
- 搜索栏
- 热门话题标签(横向滚动 chips)
- 精选模板(横向滚动卡片)
- 达人日记(瀑布流/列表)
4.9 搜索结果页 (Search)
内容层级:
- 搜索输入框(带返回按钮)
- 搜索历史标签
- 结果分类筛选 tabs
- 搜索结果列表
5. 多平台适配规则
5.1 平板端 (iPad 1024×768)
布局差异:
- 使用侧边栏导航替代底部 Tab 栏
- 内容区域采用双列布局
- 编辑器使用分栏模式(左侧画布 + 右侧工具面板)
- 日历采用月历 + 时间轴双栏并排
关键适配代码:
@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)+ 多列内容区
- 编辑器全宽画布 + 右侧属性面板
- 日历三栏布局(统计 + 月历 + 日记详情)
- 更高的信息密度:更多内容可见区域
关键适配代码:
@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. 主题切换系统
工作原理
- 默认主题:暖阳(Warm Sun),
:root直接定义 - 松风主题:通过
data-theme="pine"属性切换 - 暗色模式:
@media (prefers-color-scheme: dark)自动响应 - 持久化:
localStorage.setItem('warmnotes-theme', themeId) - 跨 Tab 同步:
window.addEventListener('storage', ...)监听变化
切换按钮
- 固定位置:
position:fixed; top:8px; right:8px; z-index:10000 - 外观:圆角胶囊,包含色点 + 主题名称
- 点击循环切换:暖阳 → 松风 → 暖阳
7. 无障碍 (Accessibility)
已实现的 WCAG 要点
- 触控区域:所有交互元素
min-height: 44px(满足 WCAG 2.5.8) - 焦点环:
box-shadow: var(--focus-ring)统一在:focus-visible显示 - ARIA 标签:所有按钮带
aria-label,Tab 栏使用role="tablist"/role="tab"/aria-selected - 语义 HTML:
<nav>、<button>、<form>、<label>正确使用 - 装饰元素隐藏:
aria-hidden="true"标记所有装饰性 SVG - 减弱动画:
@media (prefers-reduced-motion: reduce)将所有动画降至最小 - 颜色对比度:前景色
#2D2420在#FFF8F0背景上对比度约 10.5:1(满足 AAA)
8. CSS 参考实现 — :root 自定义属性
将以下代码直接用于项目 :root,所有组件引用变量即可:
: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 登录/注册流程
- 默认显示登录模式
- 输入手机号(仅数字,自动过滤非数字字符)
- 点击「获取验证码」→ 按钮进入 60 秒倒计时
- 输入验证码(仅数字)
- 点击「登录」提交表单
- 切换到注册模式:增加昵称、密码(可切换显隐)、协议勾选
- 社交登录:微信、Apple、Google 三个圆形按钮
10.2 心情选择
- 每日首次进入首页弹出心情选择
- 5 个固定心情:开心😊、平静😐、难过😢、生气😡、思考🤔
- 选中态:背景变色 + 标签高亮为 accent 色
- 天气信息显示在右侧
10.3 日记卡片交互
- 今日日记卡片:点击打开编辑器
- 浮动写按钮:hover 放大 1.1 倍
- 历史日记条目:hover 微上浮 1px,active 缩放 0.98
10.4 编辑器交互
- 顶部工具栏固定
- 画布区域可自由滚动
- 底部工具面板通过 Tab 切换(文字/贴纸/画笔/照片/模板)
- 保存按钮:点击保存
10.5 日历交互
- 月份切换:左右箭头
- 视图切换:月/周模式
- 日期点击:显示当日日记详情
- 有日记的日期显示心情颜色标记
11. 设计还原注意事项(前端开发者必读)
11.1 必须遵守
- 所有颜色必须用 CSS 变量 — 禁止硬编码
#E07A5F等色值,必须写var(--accent) - 字体加载 — Quicksand、Nunito、Caveat 从 Google Fonts CDN 加载,需在 HTML head 中引入
- 最小触控区域 44px — 所有按钮、链接、可点击元素
- 圆角 — 最小 10px,按钮统一 pill (9999px)
- 卡片阴影 — 使用
var(--elev-soft)系列,不要自定义阴影 - 间距使用 space 变量 — 不要用
margin: 15px这种近似值 - 动画缓动 — 交互类用
--ease-bounce,过渡类用--ease-standard - 安全区 — 顶部留 54px (Dynamic Island),底部留 34px (Home Indicator)
- 焦点可见 — 所有可交互元素
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 渐变使用场景
仅以下场景使用渐变:
- 启动页背景:
linear-gradient(165deg, var(--bg) 0%, var(--tertiary-soft) 40%, accent-mix 100%) - 今日日记卡片:
linear-gradient(135deg, var(--accent) 0%, var(--tertiary) 100%) - App 图标:
linear-gradient(135deg, var(--accent) 0%, var(--tertiary) 100%) - 概览页 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