Files
nj/docs/opendesign/index.html
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

612 lines
21 KiB
HTML
Raw Permalink 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.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>暖记 — 多终端手账App 设计稿</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&family=Nunito:wght@400;500;600;700&display=swap');
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #FFF8F0;
--surface: #FFFFFF;
--fg: #2D2420;
--fg-2: #5C4F47;
--muted: #7A6D63;
--meta: #8B7E74;
--border: #E8DDD4;
--border-soft: #F0E8DF;
--accent: #E07A5F;
--accent-on: #FFF8F0;
--accent-hover: #D06A4F;
--accent-glow: rgba(224, 122, 95, 0.25);
--secondary: #81B29A;
--secondary-soft: #D4E8DC;
--tertiary: #F2CC8F;
--rose: #D4A5A5;
--focus-ring: 0 0 0 3px rgba(224, 122, 95, 0.45);
--shadow-accent: 0 4px 14px rgba(224, 122, 95, 0.25);
--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);
--font-display: 'Quicksand', 'Nunito', sans-serif;
--font-body: 'Nunito', sans-serif;
}
[data-theme="pine"] {
--bg: #F2F3F0;
--surface: #FFFFFF;
--fg: #23272F;
--fg-2: #484E58;
--muted: #6E7380;
--meta: #8A8F9A;
--border: #D5D2CD;
--border-soft: #E3E1DC;
--accent: #4A7B9D;
--accent-on: #FFFFFF;
--accent-hover: #3F6A8A;
--accent-glow: rgba(74, 123, 157, 0.25);
--secondary: #5B9E7A;
--secondary-soft: #D6E8DE;
--tertiary: #C49A3C;
--rose: #7A8B6A;
--focus-ring: 0 0 0 3px rgba(74, 123, 157, 0.45);
--shadow-accent: 0 4px 14px rgba(74, 123, 157, 0.25);
--elev-soft: 0 2px 12px rgba(35, 39, 47, 0.06);
--elev-medium: 0 4px 20px rgba(35, 39, 47, 0.08);
--elev-float: 0 8px 32px rgba(35, 39, 47, 0.12);
}
html { -webkit-font-smoothing: antialiased; scroll-behavior: smooth; }
body {
font-family: var(--font-body);
background: linear-gradient(180deg, var(--bg) 0%, var(--tertiary-soft, #FFE8D6) 50%, var(--bg) 100%);
color: var(--fg);
min-height: 100vh;
}
/* Header */
.hero {
text-align: center;
padding: 80px 24px 60px;
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
top: -50%;
left: -20%;
width: 140%;
height: 200%;
background: radial-gradient(ellipse at center, color-mix(in oklab, var(--accent) 6%, transparent) 0%, transparent 60%);
pointer-events: none;
}
.hero-badge {
display: inline-flex; align-items: center; gap: 8px;
padding: 6px 16px; border-radius: 999px;
background: color-mix(in oklab, var(--accent) 10%, transparent);
color: var(--accent); font-size: 13px;
font-weight: 600; margin-bottom: 20px;
}
.hero h1 {
font-family: var(--font-display);
font-size: clamp(36px, 5vw, 56px);
font-weight: 700; letter-spacing: 1px;
margin-bottom: 12px;
}
.hero h1 span { color: var(--accent); }
.hero .subtitle {
font-size: clamp(15px, 2vw, 18px);
color: var(--muted); max-width: 500px;
margin: 0 auto 32px; line-height: 1.6;
}
.hero-meta {
display: flex; justify-content: center;
gap: 24px; flex-wrap: wrap;
}
.hero-meta span {
display: flex; align-items: center; gap: 6px;
font-size: 14px; color: var(--fg-2);
}
.hero-meta .dot {
width: 8px; height: 8px; border-radius: 50%;
}
/* Platform tabs */
.platform-tabs {
display: flex;
justify-content: center;
gap: 8px;
margin-bottom: 32px;
}
.platform-tab {
padding: 10px 24px;
border-radius: 999px;
border: 1.5px solid var(--border);
background: var(--surface);
font-family: var(--font-display);
font-size: 14px;
font-weight: 600;
color: var(--muted);
cursor: pointer;
transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.platform-tab:hover { border-color: var(--accent); color: var(--accent); }
.platform-tab.active { background: var(--accent); color: var(--accent-on); border-color: var(--accent); }
.platform-section { display: none; }
.platform-section.active { display: block; }
/* Tablet frame */
.tablet-frame {
width: 480px;
height: 360px;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(45,36,32,0.12), 0 0 0 1px var(--border-soft);
background: white;
transition: box-shadow 0.3s;
}
.tablet-card:hover .tablet-frame {
box-shadow: var(--shadow-accent), 0 0 0 1px var(--accent);
}
.tablet-frame iframe {
width: 1024px;
height: 768px;
border: none;
transform: scale(0.469);
transform-origin: top left;
pointer-events: none;
}
.tablet-card {
flex-shrink: 0;
scroll-snap-align: start;
width: 480px;
cursor: pointer;
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.tablet-card:hover { transform: translateY(-8px); }
/* Desktop frame */
.desktop-frame {
width: 640px;
height: 400px;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(45,36,32,0.12), 0 0 0 1px var(--border-soft);
background: white;
transition: box-shadow 0.3s;
}
.desktop-card:hover .desktop-frame {
box-shadow: var(--shadow-accent), 0 0 0 1px var(--accent);
}
.desktop-frame iframe {
width: 1440px;
height: 900px;
border: none;
transform: scale(0.444);
transform-origin: top left;
pointer-events: none;
}
.desktop-card {
flex-shrink: 0;
scroll-snap-align: start;
width: 640px;
cursor: pointer;
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.desktop-card:hover { transform: translateY(-8px); }
/* Section */
.section {
max-width: 1400px;
margin: 0 auto;
padding: 40px 24px;
}
.section-title {
font-family: var(--font-display);
font-size: 28px; font-weight: 700;
margin-bottom: 8px;
}
.section-desc {
font-size: 15px; color: var(--muted);
margin-bottom: 32px;
}
/* Screen gallery */
.screen-gallery {
display: flex;
gap: 32px;
overflow-x: auto;
padding-bottom: 24px;
scroll-snap-type: x mandatory;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
.screen-gallery::-webkit-scrollbar { height: 6px; }
.screen-gallery::-webkit-scrollbar-track { background: transparent; }
.screen-gallery::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.screen-card {
flex-shrink: 0;
scroll-snap-align: start;
width: 240px;
cursor: pointer;
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.screen-card:hover { transform: translateY(-8px); }
.screen-frame {
width: 240px;
height: 520px;
border-radius: 28px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(45,36,32,0.12), 0 0 0 1px var(--border-soft);
position: relative;
background: white;
transition: box-shadow 0.3s;
}
.screen-card:hover .screen-frame {
box-shadow: var(--shadow-accent), 0 0 0 1px var(--accent);
}
.screen-frame iframe {
width: 390px;
height: 844px;
border: none;
transform: scale(0.615);
transform-origin: top left;
pointer-events: none;
}
.screen-label {
margin-top: 16px;
text-align: center;
}
.screen-label .name {
font-family: var(--font-display);
font-size: 15px; font-weight: 600;
color: var(--fg);
}
.screen-label .desc {
font-size: 12px; color: var(--muted);
margin-top: 2px;
}
/* Device showcase */
.device-showcase {
display: flex;
justify-content: center;
gap: 48px;
flex-wrap: wrap;
padding: 40px 0;
}
.device-col {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}
.device-frame-wrapper {
border-radius: 28px;
overflow: hidden;
box-shadow: 0 8px 40px rgba(45,36,32,0.12);
border: 1px solid var(--border-soft);
transition: box-shadow 0.3s;
}
.device-frame-wrapper:hover {
box-shadow: var(--shadow-accent);
}
.device-frame-wrapper iframe {
border: none;
display: block;
}
.device-label {
font-family: var(--font-display);
font-size: 15px; font-weight: 600;
color: var(--fg-2);
}
.device-sub {
font-size: 12px; color: var(--muted);
}
/* Design tokens */
.tokens-section {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 16px;
margin-top: 24px;
}
.token-card {
background: var(--surface);
border-radius: 14px;
padding: 16px;
border: 1px solid var(--border-soft);
box-shadow: 0 2px 8px rgba(45,36,32,0.04);
}
.token-swatch {
width: 100%;
aspect-ratio: 1.4;
border-radius: 10px;
margin-bottom: 10px;
}
.token-name {
font-family: var(--font-display);
font-size: 13px; font-weight: 600;
margin-bottom: 2px;
}
.token-value {
font-size: 12px; color: var(--muted);
font-family: ui-monospace, monospace;
}
/* Footer */
footer {
text-align: center;
padding: 60px 24px 40px;
color: var(--muted);
font-size: 14px;
}
footer a { color: var(--accent); text-decoration: none; }
/* Responsive */
@media (max-width: 768px) {
.hero { padding: 60px 20px 40px; }
.section { padding: 24px 16px; }
.screen-gallery { gap: 20px; }
.screen-card { width: 200px; }
.screen-frame { width: 200px; height: 434px; }
.screen-frame iframe { transform: scale(0.513); }
.device-showcase { gap: 32px; }
}
</style>
</head>
<body>
<!-- Hero -->
<header class="hero">
<div class="hero-badge">Design System v1.0</div>
<h1><span>暖记</span> · 手账日记</h1>
<p class="subtitle">用温暖的方式记录每一天。面向学生的多终端手账日记App融合日记记录、贴纸装饰、模板系统、心情追踪、登录注册、发现探索与搜索。</p>
<div class="hero-meta">
<span><span class="dot" style="background:var(--accent)"></span>温暖治愈风</span>
<span><span class="dot" style="background:var(--secondary)"></span>iOS / Android / iPad / Desktop</span>
<span><span class="dot" style="background:var(--tertiary)"></span>27 页面 · 3 终端</span>
<span><span class="dot" style="background:var(--rose)"></span>学生向</span>
</div>
</header>
<!-- Platform tabs -->
<div class="platform-tabs" style="margin-top:-20px; position:relative; z-index:10">
<button class="platform-tab active" onclick="switchPlatform('mobile', this)">手机端</button>
<button class="platform-tab" onclick="switchPlatform('tablet', this)">平板端</button>
<button class="platform-tab" onclick="switchPlatform('desktop', this)">桌面端</button>
</div>
<!-- Mobile Screens -->
<section class="section platform-section active" id="mobile-section">
<div class="section-title">手机端 · 14个页面</div>
<div class="section-desc">iOS / Android — 从启动到日常使用的完整流程,含登录注册、发现探索、搜索筛选</div>
<div class="screen-gallery" id="gallery">
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/splash.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">启动页</div><div class="desc">品牌展示 · 进入引导</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/onboarding.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">引导页</div><div class="desc">3步了解核心功能</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/home-daily.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">首页 · 日记流</div><div class="desc">心情 · 今日日记 · 历史</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/editor.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">手账编辑器</div><div class="desc">文字 · 贴纸 · 画笔 · 照片</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/calendar.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">日历视图</div><div class="desc">月历 · 心情 · 时间轴</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/mood-tracker.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">心情追踪</div><div class="desc">心情趋势 · 天气 · 洞察</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/stickers.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">贴纸素材库</div><div class="desc">分类浏览 · 素材包 · 收藏</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/templates.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">模板画廊</div><div class="desc">日/周/月视图模板</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/weekly.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">周概览</div><div class="desc">一周七天 · 总结统计</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/monthly.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">月度概览</div><div class="desc">心情色彩日历 · 精选</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/profile.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">个人中心</div><div class="desc">成就 · 设置 · 同步</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/login.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">登录/注册</div><div class="desc">手机号+社交登录+注册切换</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/discover.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">发现页</div><div class="desc">搜索+热门话题+精选模板+达人日记</div></div>
</div>
<div class="screen-card">
<div class="screen-frame"><iframe src="screens/search.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">搜索结果</div><div class="desc">搜索历史+结果分类筛选</div></div>
</div>
</div>
</section>
<!-- Tablet Screens -->
<section class="section platform-section" id="tablet-section">
<div class="section-title">平板端 · 6个页面</div>
<div class="section-desc">iPad 1024×768 — 侧边栏导航 + 双列布局 + 分栏编辑器 + 登录注册 + 发现搜索</div>
<div class="screen-gallery">
<div class="tablet-card">
<div class="tablet-frame"><iframe src="screens/tablet/home-daily.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">首页日记流</div><div class="desc">侧边栏 + 双列内容 + 心情选择</div></div>
</div>
<div class="tablet-card">
<div class="tablet-frame"><iframe src="screens/tablet/editor.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">手账编辑器</div><div class="desc">宽画布 + 右侧贴纸面板</div></div>
</div>
<div class="tablet-card">
<div class="tablet-frame"><iframe src="screens/tablet/calendar.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">日历视图</div><div class="desc">月历 + 时间轴双栏并排</div></div>
</div>
<div class="tablet-card">
<div class="tablet-frame"><iframe src="screens/tablet/login.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">登录/注册</div><div class="desc">宽屏双栏登录 + 社交账号</div></div>
</div>
<div class="tablet-card">
<div class="tablet-frame"><iframe src="screens/tablet/discover.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">发现页</div><div class="desc">热门话题 + 精选模板 + 达人日记</div></div>
</div>
<div class="tablet-card">
<div class="tablet-frame"><iframe src="screens/tablet/search.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">搜索结果</div><div class="desc">搜索历史 + 结果分类筛选</div></div>
</div>
</div>
</section>
<!-- Desktop Screens -->
<section class="section platform-section" id="desktop-section">
<div class="section-title">桌面端 · 6个页面</div>
<div class="section-desc">1440×900 — 固定侧边栏 + 多列布局 + 高信息密度 + 登录注册 + 发现搜索</div>
<div class="screen-gallery">
<div class="desktop-card">
<div class="desktop-frame"><iframe src="screens/desktop/home-daily.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">首页日记流</div><div class="desc">侧边栏 + 日记流 + 心情/统计面板</div></div>
</div>
<div class="desktop-card">
<div class="desktop-frame"><iframe src="screens/desktop/editor.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">手账编辑器</div><div class="desc">工具条 + 全宽画布 + 右侧属性面板</div></div>
</div>
<div class="desktop-card">
<div class="desktop-frame"><iframe src="screens/desktop/calendar.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">日历视图</div><div class="desc">统计 + 月历 + 日记详情三栏</div></div>
</div>
<div class="desktop-card">
<div class="desktop-frame"><iframe src="screens/desktop/login.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">登录/注册</div><div class="desc">桌面端全屏登录 + 社交账号</div></div>
</div>
<div class="desktop-card">
<div class="desktop-frame"><iframe src="screens/desktop/discover.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">发现页</div><div class="desc">热门话题 + 精选模板 + 达人日记</div></div>
</div>
<div class="desktop-card">
<div class="desktop-frame"><iframe src="screens/desktop/search.html" loading="lazy"></iframe></div>
<div class="screen-label"><div class="name">搜索结果</div><div class="desc">搜索历史 + 结果分类筛选</div></div>
</div>
</div>
</section>
<!-- Design Tokens -->
<section class="section">
<div class="section-title">视觉系统</div>
<div class="section-desc">暖记的色彩体系与排版规则</div>
<div class="tokens-section">
<div class="token-card">
<div class="token-swatch" style="background:#FFF8F0;border:1px solid #E8DDD4"></div>
<div class="token-name">Background</div>
<div class="token-value">#FFF8F0</div>
</div>
<div class="token-card">
<div class="token-swatch" style="background:#E07A5F"></div>
<div class="token-name">Accent</div>
<div class="token-value">#E07A5F</div>
</div>
<div class="token-card">
<div class="token-swatch" style="background:#81B29A"></div>
<div class="token-name">Secondary</div>
<div class="token-value">#81B29A</div>
</div>
<div class="token-card">
<div class="token-swatch" style="background:#F2CC8F"></div>
<div class="token-name">Tertiary</div>
<div class="token-value">#F2CC8F</div>
</div>
<div class="token-card">
<div class="token-swatch" style="background:#D4A5A5"></div>
<div class="token-name">Rose</div>
<div class="token-value">#D4A5A5</div>
</div>
<div class="token-card">
<div class="token-swatch" style="background:#2D2420"></div>
<div class="token-name">Foreground</div>
<div class="token-value">#2D2420</div>
</div>
<div class="token-card">
<div class="token-swatch" style="background:#8B7E74"></div>
<div class="token-name">Muted</div>
<div class="token-value">#8B7E74</div>
</div>
<div class="token-card">
<div class="token-swatch" style="background:#E8DDD4"></div>
<div class="token-name">Border</div>
<div class="token-value">#E8DDD4</div>
</div>
</div>
</section>
<!-- Footer -->
<footer>
<p>暖记 Warm Notes — 多终端手账日记App设计稿</p>
<p style="margin-top:8px">27 页面 · 手机 14 + 平板 6 + 桌面 6 · 温暖治愈视觉系统</p>
</footer>
<script>
function switchPlatform(platform, btn) {
document.querySelectorAll('.platform-section').forEach(s => s.classList.remove('active'));
document.querySelectorAll('.platform-tab').forEach(t => t.classList.remove('active'));
document.getElementById(platform + '-section').classList.add('active');
btn.classList.add('active');
}
</script>
<script src="js/theme-switcher.js"></script>
</body>
</html>