前端修复: - 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个页面全部渲染正常
286 lines
12 KiB
HTML
286 lines
12 KiB
HTML
<!doctype html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=390, height=844, initial-scale=1, viewport-fit=cover">
|
|
<title>暖记 — 周概览</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Caveat:wght@400;600;700&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="../css/tokens.css">
|
|
<link rel="stylesheet" href="../css/components.css">
|
|
<style>
|
|
body {
|
|
width: 390px; height: 844px;
|
|
overflow: hidden; background: var(--bg);
|
|
position: relative;
|
|
}
|
|
|
|
/* Global focus styles */
|
|
button:focus-visible, a:focus-visible, [role="tab"]:focus-visible {
|
|
box-shadow: 0 0 0 3px var(--focus-ring);
|
|
outline: none;
|
|
}
|
|
|
|
.content-area {
|
|
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;
|
|
}
|
|
.content-area::-webkit-scrollbar { display: none; }
|
|
|
|
.week-header {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
margin-bottom: var(--space-5);
|
|
}
|
|
.week-title {
|
|
font-family: var(--font-display);
|
|
font-size: var(--text-2xl); font-weight: 700;
|
|
}
|
|
.week-nav { display: flex; gap: var(--space-2); }
|
|
.week-nav button {
|
|
min-width: 44px; min-height: 44px; border-radius: 50%;
|
|
border: 1.5px solid var(--border); background: var(--surface);
|
|
display: flex; align-items: center; justify-content: center;
|
|
cursor: pointer; color: var(--fg);
|
|
transition: all var(--motion-fast);
|
|
}
|
|
.week-nav button:hover { border-color: var(--accent); color: var(--accent); }
|
|
.week-nav button svg { width: 18px; height: 18px; }
|
|
|
|
/* Week strip */
|
|
.week-strip {
|
|
display: flex; gap: 4px; margin-bottom: var(--space-5);
|
|
}
|
|
.week-day {
|
|
flex: 1; text-align: center; padding: var(--space-3) 0;
|
|
border-radius: var(--radius-md); cursor: pointer;
|
|
transition: all var(--motion-fast);
|
|
min-height: 44px;
|
|
}
|
|
.week-day:hover { background: var(--surface-warm); }
|
|
.week-day .wd-name { font-size: 11px; color: var(--meta); margin-bottom: 4px; }
|
|
.week-day .wd-num {
|
|
font-family: var(--font-display); font-size: var(--text-lg);
|
|
font-weight: 700; color: var(--fg-2);
|
|
}
|
|
.week-day .wd-mood { font-size: 16px; margin-top: 4px; }
|
|
.week-day.today {
|
|
background: var(--accent); border-radius: var(--radius-md);
|
|
}
|
|
.week-day.today .wd-name { color: rgba(255,248,240,0.85); }
|
|
.week-day.today .wd-num { color: var(--accent-on); }
|
|
.week-day.has-entry .wd-num::after {
|
|
content: ''; display: block; width: 4px; height: 4px;
|
|
border-radius: 50%; background: var(--accent); margin: 4px auto 0;
|
|
}
|
|
.week-day.today.has-entry .wd-num::after { background: white; }
|
|
|
|
/* Day cards */
|
|
.day-card {
|
|
background: var(--surface); border-radius: var(--radius-md);
|
|
padding: var(--space-4); margin-bottom: var(--space-3);
|
|
box-shadow: var(--elev-soft); border: 1px solid var(--border-soft);
|
|
cursor: pointer; transition: all var(--motion-fast);
|
|
}
|
|
.day-card:hover { transform: translateY(-1px); }
|
|
.day-card-header {
|
|
display: flex; justify-content: space-between; align-items: center;
|
|
margin-bottom: var(--space-3);
|
|
}
|
|
.day-card-header .date {
|
|
font-size: var(--text-sm); font-weight: 600; color: var(--fg-2);
|
|
}
|
|
.day-card-header .mood-weather {
|
|
display: flex; gap: var(--space-2); align-items: center;
|
|
font-size: var(--text-sm);
|
|
}
|
|
.day-card-body {
|
|
font-size: var(--text-sm); color: var(--muted); line-height: 1.6;
|
|
display: -webkit-box; -webkit-line-clamp: 3;
|
|
-webkit-box-orient: vertical; overflow: hidden;
|
|
}
|
|
.day-card-tags {
|
|
display: flex; gap: var(--space-2); margin-top: var(--space-3);
|
|
flex-wrap: wrap;
|
|
}
|
|
.day-tag {
|
|
padding: 3px 10px; border-radius: var(--radius-pill);
|
|
font-size: 11px; font-weight: 500;
|
|
}
|
|
.day-card-photo {
|
|
width: 100%; height: 80px; border-radius: var(--radius-sm);
|
|
margin-top: var(--space-3); object-fit: cover;
|
|
}
|
|
.photo-placeholder {
|
|
width: 100%; height: 80px; border-radius: var(--radius-sm);
|
|
background: linear-gradient(135deg, var(--surface-warm), var(--border-soft));
|
|
display: flex; align-items: center; justify-content: center;
|
|
margin-top: var(--space-3); font-size: 24px;
|
|
}
|
|
|
|
/* Week summary */
|
|
.week-summary {
|
|
background: var(--surface); border-radius: var(--radius-md);
|
|
padding: var(--space-5); margin-bottom: var(--space-5);
|
|
box-shadow: var(--elev-soft); border: 1px solid var(--border-soft);
|
|
}
|
|
.week-summary h4 {
|
|
font-family: var(--font-display); font-size: var(--text-base);
|
|
font-weight: 600; margin-bottom: var(--space-4);
|
|
}
|
|
.summary-row {
|
|
display: flex; gap: var(--space-4); margin-bottom: var(--space-3);
|
|
}
|
|
.summary-item {
|
|
flex: 1; text-align: center;
|
|
}
|
|
.summary-item .val {
|
|
font-family: var(--font-display); font-size: var(--text-xl);
|
|
font-weight: 700;
|
|
}
|
|
.summary-item .val.accent { color: var(--accent); }
|
|
.summary-item .val.green { color: var(--secondary); }
|
|
.summary-item .desc {
|
|
font-size: var(--text-xs); color: var(--muted); margin-top: 2px;
|
|
}
|
|
.mood-dist {
|
|
display: flex; gap: var(--space-2); margin-top: var(--space-4);
|
|
}
|
|
.mood-seg {
|
|
height: 8px; border-radius: 4px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="content-area">
|
|
|
|
<div class="week-header anim-fade">
|
|
<div class="week-title">本周概览</div>
|
|
<div class="week-nav">
|
|
<button aria-label="上一周"><svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M11 14l-5-5 5-5"/></svg></button>
|
|
<button aria-label="下一周"><svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M7 4l5 5-5 5"/></svg></button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Week strip - using standardized 5 moods -->
|
|
<div class="week-strip anim-fade" style="animation-delay: 0.1s">
|
|
<div class="week-day has-entry">
|
|
<div class="wd-name">一</div><div class="wd-num">25</div><div class="wd-mood">😊</div>
|
|
</div>
|
|
<div class="week-day has-entry">
|
|
<div class="wd-name">二</div><div class="wd-num">26</div><div class="wd-mood">😐</div>
|
|
</div>
|
|
<div class="week-day has-entry">
|
|
<div class="wd-name">三</div><div class="wd-num">27</div><div class="wd-mood">😊</div>
|
|
</div>
|
|
<div class="week-day has-entry">
|
|
<div class="wd-name">四</div><div class="wd-num">28</div><div class="wd-mood">😊</div>
|
|
</div>
|
|
<div class="week-day has-entry">
|
|
<div class="wd-name">五</div><div class="wd-num">29</div><div class="wd-mood">😊</div>
|
|
</div>
|
|
<div class="week-day has-entry">
|
|
<div class="wd-name">六</div><div class="wd-num">30</div><div class="wd-mood">😊</div>
|
|
</div>
|
|
<div class="week-day today has-entry">
|
|
<div class="wd-name">日</div><div class="wd-num">31</div><div class="wd-mood">😊</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Week summary -->
|
|
<div class="week-summary anim-fade" style="animation-delay: 0.15s">
|
|
<h4>本周总结</h4>
|
|
<div class="summary-row">
|
|
<div class="summary-item">
|
|
<div class="val accent">6</div><div class="desc">记录天数</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div class="val green">7</div><div class="desc">日记篇数</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div class="val">12</div><div class="desc">使用贴纸</div>
|
|
</div>
|
|
</div>
|
|
<div class="mood-dist">
|
|
<div class="mood-seg" style="flex:3;background:var(--secondary)"></div>
|
|
<div class="mood-seg" style="flex:2;background:var(--tertiary)"></div>
|
|
<div class="mood-seg" style="flex:1;background:#5B7DB1"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Day cards - using standardized 5 moods -->
|
|
<div class="day-card anim-fade" style="animation-delay: 0.2s">
|
|
<div class="day-card-header">
|
|
<span class="date">周日 · 5月31日</span>
|
|
<div class="mood-weather">😊 ☀️</div>
|
|
</div>
|
|
<div class="day-card-body">今天下午去图书馆自习,阳光从窗外洒进来,暖暖的。喝了抹茶拿铁,虽然期末压力大但看到窗外的樱花还在开,觉得一切都会好的。</div>
|
|
<div class="day-card-tags">
|
|
<span class="day-tag" style="background:var(--secondary-soft);color:#2D7D46">学习</span>
|
|
<span class="day-tag" style="background:var(--tertiary-soft);color:#B8860B">美食</span>
|
|
</div>
|
|
<div class="photo-placeholder">📚</div>
|
|
</div>
|
|
|
|
<div class="day-card anim-fade" style="animation-delay: 0.25s">
|
|
<div class="day-card-header">
|
|
<span class="date">周六 · 5月30日</span>
|
|
<div class="mood-weather">😊 🌤</div>
|
|
</div>
|
|
<div class="day-card-body">今天在图书馆自习,窗外的阳光洒进来,暖暖的。复习了高数第三章,做了两套模拟题感觉还不错。</div>
|
|
<div class="day-card-tags">
|
|
<span class="day-tag" style="background:var(--secondary-soft);color:#2D7D46">学习</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="day-card anim-fade" style="animation-delay: 0.3s">
|
|
<div class="day-card-header">
|
|
<span class="date">周五 · 5月29日</span>
|
|
<div class="mood-weather">😊 ☀️</div>
|
|
</div>
|
|
<div class="day-card-body">考完试和舍友们去吃了火锅庆祝,大家都好开心,聊了很多有趣的事。这学期终于结束了!</div>
|
|
<div class="day-card-tags">
|
|
<span class="day-tag" style="background:var(--rose-soft);color:#9B4D4D">朋友</span>
|
|
<span class="day-tag" style="background:var(--tertiary-soft);color:#B8860B">美食</span>
|
|
</div>
|
|
<div class="photo-placeholder">🍲</div>
|
|
</div>
|
|
|
|
<div style="height: var(--space-8)"></div>
|
|
</div>
|
|
|
|
<!-- Tab bar -->
|
|
<nav class="tab-bar" role="tablist">
|
|
<button class="tab-item" role="tab" aria-label="首页" aria-selected="false">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><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>
|
|
<span>首页</span>
|
|
</button>
|
|
<button class="tab-item active" role="tab" aria-label="日历" aria-selected="true">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><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>
|
|
<span>日历</span>
|
|
</button>
|
|
<button class="tab-item" role="tab" aria-label="写日记" aria-selected="false" style="position:relative">
|
|
<div style="width:44px;height:44px;border-radius:50%;background:var(--accent);display:flex;align-items:center;justify-content:center;margin-top:-16px;box-shadow:0 4px 12px var(--shadow-accent)">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="var(--accent-on)" stroke-width="2.5" stroke-linecap="round" style="width:22px;height:22px" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>
|
|
</div>
|
|
<span style="margin-top:2px">写日记</span>
|
|
</button>
|
|
<button class="tab-item" role="tab" aria-label="发现" aria-selected="false">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
|
<span>发现</span>
|
|
</button>
|
|
<button class="tab-item" role="tab" aria-label="我的" aria-selected="false">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
|
|
<span>我的</span>
|
|
</button>
|
|
</nav>
|
|
|
|
<div class="dynamic-island" aria-hidden="true"></div>
|
|
<div class="home-indicator" style="position:absolute;bottom:8px;left:50%;transform:translateX(-50%);z-index:101" aria-hidden="true"></div>
|
|
|
|
<script src="../js/theme-switcher.js"></script>
|
|
</body>
|
|
</html>
|