前端修复: - 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个页面全部渲染正常
457 lines
15 KiB
HTML
457 lines
15 KiB
HTML
<!doctype html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=1024, height=768, initial-scale=1">
|
|
<title>暖记 — 平板端首页</title>
|
|
<link rel="stylesheet" href="../css/tokens.css">
|
|
<link rel="stylesheet" href="../css/components.css">
|
|
<link rel="stylesheet" href="shared.css">
|
|
<style>
|
|
body {
|
|
width: 1024px;
|
|
height: 768px;
|
|
overflow: hidden;
|
|
background: var(--bg);
|
|
font-family: var(--font-body);
|
|
}
|
|
|
|
.main-content { height: 768px; }
|
|
|
|
.content-inner {
|
|
padding: var(--space-8) var(--space-8);
|
|
max-width: none;
|
|
}
|
|
|
|
/* Greeting */
|
|
.greeting { margin-bottom: var(--space-5); }
|
|
.greeting-date {
|
|
font-size: var(--text-sm);
|
|
color: var(--muted);
|
|
font-weight: 500;
|
|
margin-bottom: var(--space-1);
|
|
}
|
|
.greeting-text {
|
|
font-family: var(--font-display);
|
|
font-size: var(--text-3xl);
|
|
font-weight: 700;
|
|
color: var(--fg);
|
|
}
|
|
.greeting-text span { color: var(--accent); }
|
|
|
|
.streak-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 6px 14px;
|
|
background: var(--tertiary-soft);
|
|
border-radius: var(--radius-pill);
|
|
font-size: var(--text-sm);
|
|
font-weight: 600;
|
|
color: #B8860B;
|
|
margin-bottom: var(--space-5);
|
|
}
|
|
|
|
/* Mood + Today card row */
|
|
.top-row {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: var(--space-5);
|
|
margin-bottom: var(--space-6);
|
|
}
|
|
|
|
.mood-section {
|
|
background: var(--surface);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-5);
|
|
box-shadow: var(--elev-soft);
|
|
border: 1px solid var(--border-soft);
|
|
}
|
|
.mood-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: var(--space-4);
|
|
}
|
|
.mood-header span {
|
|
font-size: var(--text-base);
|
|
font-weight: 600;
|
|
color: var(--fg-2);
|
|
}
|
|
.mood-header .weather {
|
|
font-size: var(--text-sm);
|
|
color: var(--muted);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
}
|
|
.mood-options {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
.mood-opt {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 4px;
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
padding: var(--space-2) var(--space-3);
|
|
border-radius: var(--radius-sm);
|
|
transition: all var(--motion-fast) var(--ease-bounce);
|
|
}
|
|
.mood-opt:hover { background: var(--surface-warm); }
|
|
.mood-opt.selected { background: var(--surface-warm); }
|
|
.mood-opt .face { font-size: 32px; }
|
|
.mood-opt .label { font-size: var(--text-xs); color: var(--muted); }
|
|
.mood-opt.selected .label { color: var(--accent); font-weight: 600; }
|
|
|
|
/* Today card */
|
|
.today-card {
|
|
background: linear-gradient(135deg, var(--accent) 0%, var(--tertiary) 100%);
|
|
border-radius: var(--radius-lg);
|
|
padding: var(--space-6);
|
|
position: relative;
|
|
overflow: hidden;
|
|
cursor: pointer;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
}
|
|
.today-card:hover { transform: translateY(-2px); transition: transform var(--motion-fast) var(--ease-bounce); }
|
|
.today-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: -30px;
|
|
right: -30px;
|
|
width: 140px;
|
|
height: 140px;
|
|
border-radius: 50%;
|
|
background: rgba(255,255,255,0.12);
|
|
}
|
|
.today-card::after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: -20px;
|
|
left: 40px;
|
|
width: 90px;
|
|
height: 90px;
|
|
border-radius: 50%;
|
|
background: rgba(255,255,255,0.08);
|
|
}
|
|
.today-card .label {
|
|
font-size: var(--text-sm);
|
|
color: var(--accent-on);
|
|
font-weight: 500;
|
|
margin-bottom: var(--space-2);
|
|
opacity: 0.85;
|
|
}
|
|
.today-card .title {
|
|
font-family: var(--font-display);
|
|
font-size: var(--text-xl);
|
|
font-weight: 700;
|
|
color: var(--accent-on);
|
|
margin-bottom: var(--space-2);
|
|
}
|
|
.today-card .prompt {
|
|
font-size: var(--text-sm);
|
|
color: var(--accent-on);
|
|
opacity: 0.7;
|
|
}
|
|
.today-card .write-btn {
|
|
position: absolute;
|
|
bottom: var(--space-5);
|
|
right: var(--space-5);
|
|
width: 52px;
|
|
height: 52px;
|
|
border-radius: 50%;
|
|
background: white;
|
|
border: none;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
cursor: pointer;
|
|
transition: transform var(--motion-fast) var(--ease-bounce);
|
|
}
|
|
.today-card .write-btn:hover { transform: scale(1.1); }
|
|
.today-card .write-btn svg { width: 24px; height: 24px; color: var(--accent); }
|
|
|
|
/* Quick stats */
|
|
.quick-stats {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: var(--space-4);
|
|
margin-bottom: var(--space-6);
|
|
}
|
|
.stat-card {
|
|
background: var(--surface);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-4) var(--space-5);
|
|
box-shadow: var(--elev-soft);
|
|
border: 1px solid var(--border-soft);
|
|
}
|
|
.stat-card .num {
|
|
font-family: var(--font-display);
|
|
font-size: var(--text-2xl);
|
|
font-weight: 700;
|
|
}
|
|
.stat-card .num.accent { color: var(--accent); }
|
|
.stat-card .num.green { color: var(--secondary); }
|
|
.stat-card .label {
|
|
font-size: var(--text-sm);
|
|
color: var(--muted);
|
|
margin-top: 4px;
|
|
}
|
|
|
|
/* Entries */
|
|
.recent-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: var(--space-4);
|
|
}
|
|
.recent-header h3 {
|
|
font-family: var(--font-display);
|
|
font-size: var(--text-lg);
|
|
font-weight: 700;
|
|
}
|
|
.recent-header a {
|
|
font-size: var(--text-sm);
|
|
color: var(--accent);
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.entries-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: var(--space-4);
|
|
}
|
|
|
|
.entry-card {
|
|
background: var(--surface);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-4);
|
|
box-shadow: var(--elev-soft);
|
|
border: 1px solid var(--border-soft);
|
|
cursor: pointer;
|
|
transition: transform var(--motion-fast) var(--ease-standard);
|
|
}
|
|
.entry-card:hover { transform: translateY(-2px); }
|
|
.entry-top {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
margin-bottom: var(--space-3);
|
|
}
|
|
.entry-date {
|
|
font-size: var(--text-xs);
|
|
color: var(--muted);
|
|
}
|
|
.entry-mood { font-size: 20px; }
|
|
.entry-title {
|
|
font-family: var(--font-display);
|
|
font-size: var(--text-md);
|
|
font-weight: 600;
|
|
color: var(--fg);
|
|
margin-bottom: var(--space-2);
|
|
}
|
|
.entry-excerpt {
|
|
font-size: var(--text-sm);
|
|
color: var(--muted);
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
line-height: 1.5;
|
|
}
|
|
.entry-preview-thumb {
|
|
width: 100%;
|
|
height: 80px;
|
|
border-radius: var(--radius-sm);
|
|
margin-top: var(--space-3);
|
|
background: var(--surface-warm);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 28px;
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(12px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
.anim-fade { animation: fadeIn 0.5s var(--ease-standard) both; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<!-- Sidebar -->
|
|
<nav class="sidebar" role="navigation" aria-label="主导航">
|
|
<div class="sidebar-brand">
|
|
<div class="sidebar-logo">📖</div>
|
|
<div>
|
|
<div class="sidebar-brand-text">暖记</div>
|
|
<div class="sidebar-brand-sub">Warm Notes</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sidebar-nav">
|
|
<button class="sidebar-nav-item active" role="button" aria-label="首页">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
|
|
首页
|
|
</button>
|
|
<button class="sidebar-nav-item" role="button" aria-label="日历">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
|
|
日历
|
|
</button>
|
|
<button class="sidebar-nav-item" role="button" aria-label="心情追踪">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"/></svg>
|
|
心情追踪
|
|
</button>
|
|
<button class="sidebar-nav-item" role="button" aria-label="贴纸库">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="3" y="3" width="18" height="18" rx="3"/><circle cx="9" cy="10" r="1.5" fill="currentColor"/><circle cx="15" cy="10" r="1.5" fill="currentColor"/><path d="M9 15c.8.8 2.2 1.2 3 1.2s2.2-.4 3-1.2"/></svg>
|
|
贴纸库
|
|
</button>
|
|
<button class="sidebar-nav-item" role="button" aria-label="模板">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
|
|
模板
|
|
</button>
|
|
<button class="sidebar-nav-item" role="button" aria-label="发现">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
|
发现
|
|
</button>
|
|
</div>
|
|
|
|
<button class="sidebar-write-btn" aria-label="写日记">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg>
|
|
写日记
|
|
</button>
|
|
|
|
<div class="sidebar-footer">
|
|
<div class="sidebar-avatar">🐱</div>
|
|
<div>
|
|
<div class="sidebar-user-name">小暖</div>
|
|
<div class="sidebar-user-streak">连续记录 12 天</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Main Content -->
|
|
<main class="main-content" role="main">
|
|
<div class="content-inner">
|
|
|
|
<!-- Greeting -->
|
|
<div class="greeting anim-fade">
|
|
<div class="greeting-date">2026年5月31日 · 星期日</div>
|
|
<div class="greeting-text">下午好,<span>小暖</span></div>
|
|
</div>
|
|
|
|
<div class="streak-badge anim-fade" style="animation-delay:0.05s">
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="#B8860B"><path d="M8 1l2 5h5l-4 3 1.5 5L8 11 3.5 14 5 9 1 6h5z"/></svg>
|
|
连续记录 12 天
|
|
</div>
|
|
|
|
<!-- Mood + Today card row -->
|
|
<div class="top-row anim-fade" style="animation-delay:0.1s">
|
|
<div class="mood-section">
|
|
<div class="mood-header">
|
|
<span>今天心情如何?</span>
|
|
<div class="weather">
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="var(--tertiary)">
|
|
<circle cx="8" cy="8" r="5"/>
|
|
</svg>
|
|
晴 26°
|
|
</div>
|
|
</div>
|
|
<div class="mood-options">
|
|
<button class="mood-opt" aria-label="开心"><span class="face">😊</span><span class="label">开心</span></button>
|
|
<button class="mood-opt" aria-label="平静"><span class="face">😌</span><span class="label">平静</span></button>
|
|
<button class="mood-opt selected" aria-label="幸福"><span class="face">🥰</span><span class="label">幸福</span></button>
|
|
<button class="mood-opt" aria-label="疲惫"><span class="face">😴</span><span class="label">疲惫</span></button>
|
|
<button class="mood-opt" aria-label="低落"><span class="face">😔</span><span class="label">低落</span></button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="today-card">
|
|
<div>
|
|
<div class="label">今天的日记</div>
|
|
<div class="title">写点什么吧...</div>
|
|
<div class="prompt">记录一个温暖的瞬间,或者今天发生的小事</div>
|
|
</div>
|
|
<button class="write-btn" aria-label="开始写日记">
|
|
<svg viewBox="0 0 24 24" fill="none"><path d="M11 5v12M5 11h12" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick stats -->
|
|
<div class="quick-stats anim-fade" style="animation-delay:0.15s">
|
|
<div class="stat-card">
|
|
<div class="num accent">28</div>
|
|
<div class="label">本月日记</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="num green">12</div>
|
|
<div class="label">连续天数</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="num">156</div>
|
|
<div class="label">总日记数</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent entries -->
|
|
<div class="recent-header anim-fade" style="animation-delay:0.2s">
|
|
<h3>最近记录</h3>
|
|
<a href="#">查看全部</a>
|
|
</div>
|
|
|
|
<div class="entries-grid anim-fade" style="animation-delay:0.25s">
|
|
<div class="entry-card">
|
|
<div class="entry-top">
|
|
<div class="entry-date">5月30日 · 周六</div>
|
|
<div class="entry-mood">😊</div>
|
|
</div>
|
|
<div class="entry-title">图书馆的午后</div>
|
|
<div class="entry-excerpt">今天在图书馆自习,窗外的阳光洒进来,暖暖的。复习了高数第三章...</div>
|
|
<div class="entry-preview-thumb" style="background:var(--surface-warm)">🌸</div>
|
|
</div>
|
|
<div class="entry-card">
|
|
<div class="entry-top">
|
|
<div class="entry-date">5月29日 · 周五</div>
|
|
<div class="entry-mood">🥰</div>
|
|
</div>
|
|
<div class="entry-title">和舍友的火锅局</div>
|
|
<div class="entry-excerpt">考完试和舍友们去吃了火锅庆祝,大家都好开心,聊了很多有趣的事...</div>
|
|
<div class="entry-preview-thumb" style="background:var(--secondary-soft)">🍃</div>
|
|
</div>
|
|
<div class="entry-card">
|
|
<div class="entry-top">
|
|
<div class="entry-date">5月28日 · 周四</div>
|
|
<div class="entry-mood">😌</div>
|
|
</div>
|
|
<div class="entry-title">期末考试第一天</div>
|
|
<div class="entry-excerpt">终于考完了英语,感觉发挥还可以。明天继续加油!给自己打个气...</div>
|
|
<div class="entry-preview-thumb" style="background:var(--tertiary-soft)">📝</div>
|
|
</div>
|
|
<div class="entry-card">
|
|
<div class="entry-top">
|
|
<div class="entry-date">5月27日 · 周三</div>
|
|
<div class="entry-mood">😌</div>
|
|
</div>
|
|
<div class="entry-title">夜跑打卡</div>
|
|
<div class="entry-excerpt">晚上去操场跑了三圈,吹着晚风特别舒服。回来洗了个热水澡...</div>
|
|
<div class="entry-preview-thumb" style="background:var(--rose-soft)">🌙</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</main>
|
|
|
|
<script src="../../js/theme-switcher.js"></script>
|
|
</body>
|
|
</html>
|