feat:重构的 UI 搞

This commit is contained in:
amos
2025-12-22 13:36:09 +08:00
parent b97578706b
commit 728d9cb5e0

670
healthflow_minimal_ui.html Normal file
View File

@@ -0,0 +1,670 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HealthFlow - 极致简约健康管理</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color: #f8fafc;
--card-bg: #ffffff;
--text-primary: #0f172a;
--text-secondary: #64748b;
--border-color: #e2e8f0;
--accent-green: #059669;
--accent-red: #dc2626;
--card-padding: 20px;
--border-radius: 16px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background-color: var(--bg-color);
color: var(--text-primary);
display: flex;
justify-content: center;
min-height: 100vh;
overflow-x: hidden;
}
.app-container {
width: 100%;
max-width: 450px;
min-height: 100vh;
position: relative;
background: white;
padding-bottom: 80px;
}
.screen {
display: none;
padding: 24px;
animation: fadeIn 0.3s ease-in-out;
}
.screen.active {
display: block;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
header {
margin-bottom: 32px;
}
h1 {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.5px;
}
.subtitle {
font-size: 14px;
color: var(--text-secondary);
margin-top: 4px;
}
.card {
position: relative;
background: var(--card-bg);
border-radius: var(--border-radius);
padding: 24px;
margin-bottom: 24px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02), 0 10px 15px -3px rgba(15, 23, 42, 0.05);
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
cursor: pointer;
border: 1px solid rgba(226, 232, 240, 0.8);
overflow: hidden;
}
.card:active {
transform: scale(0.97);
}
.card-accent {
position: absolute;
left: 0;
top: 24px;
bottom: 24px;
width: 4px;
background: var(--accent-green);
border-radius: 0 4px 4px 0;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 8px;
}
.card-title {
font-weight: 700;
font-size: 19px;
letter-spacing: -0.3px;
color: var(--text-primary);
}
.card-status {
font-size: 14px;
font-weight: 600;
color: var(--accent-green);
opacity: 0.9;
}
.card-dates {
font-size: 14px;
font-weight: 500;
color: var(--text-secondary);
margin-bottom: 18px;
}
.progress-container {
height: 6px;
background: #f1f5f9;
border-radius: 10px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background: var(--text-primary);
width: 0%;
border-radius: 10px;
transition: width 0.8s cubic-bezier(0.4, 0, 0.2, 1);
}
.dashboard {
display: flex;
justify-content: space-between;
margin-bottom: 40px;
padding: 10px 0;
}
.stat-item {
text-align: left;
}
.stat-value {
font-size: 22px;
font-weight: 700;
display: block;
}
.stat-label {
font-size: 12px;
color: var(--text-secondary);
text-transform: uppercase;
}
.week-list {
margin-top: 24px;
}
.week-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 0;
border-bottom: 1px solid var(--border-color);
}
.week-info {
display: flex;
flex-direction: column;
}
.week-name {
font-weight: 500;
}
.week-date {
font-size: 12px;
color: var(--text-secondary);
}
.week-result {
font-weight: 600;
color: var(--accent-green);
}
.week-result.gain {
color: var(--accent-red);
}
.hero-weight {
text-align: center;
margin: 60px 0;
}
.hero-value {
font-size: 72px;
font-weight: 700;
letter-spacing: -2px;
}
.hero-unit {
font-size: 24px;
color: var(--text-secondary);
margin-left: 4px;
}
.btn-group {
display: flex;
flex-direction: column;
gap: 12px;
}
.btn-outline {
width: 100%;
padding: 16px;
border: 1px solid var(--text-primary);
background: transparent;
color: var(--text-primary);
border-radius: var(--border-radius);
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.btn-outline:active {
background: var(--text-primary);
color: white;
}
.stamp {
position: absolute;
top: 50%;
right: -10px;
transform: translateY(-50%) rotate(-15deg);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
user-select: none;
pointer-events: none;
z-index: 0;
opacity: 0.12;
mix-blend-mode: darken;
}
.stamp svg {
width: 80px;
height: 80px;
margin-bottom: -5px;
}
.stamp .stamp-text {
font-weight: 850;
font-size: 32px;
letter-spacing: 2px;
white-space: nowrap;
}
.stamp-pass {
color: var(--accent-green);
}
.stamp-fail {
color: var(--accent-red);
}
.profile-header {
display: flex;
align-items: center;
gap: 20px;
margin-bottom: 40px;
}
.avatar {
width: 72px;
height: 72px;
border-radius: 50%;
background: #e2e8f0;
border: 3px solid white;
box-shadow: 0 10px 15px -3px rgba(15, 23, 42, 0.1);
}
.user-info h2 {
font-size: 24px;
font-weight: 800;
letter-spacing: -0.5px;
}
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
margin-bottom: 24px;
}
.dark-card {
background: var(--text-primary);
color: white;
padding: 32px 24px;
border-radius: var(--border-radius);
position: relative;
overflow: hidden;
border: none;
}
.year-badge {
position: absolute;
top: 0;
right: 0;
background: rgba(255, 255, 255, 0.1);
padding: 8px 16px;
border-radius: 0 0 0 16px;
font-size: 12px;
font-weight: 600;
}
/* 表单样式 */
.form-group {
margin-bottom: 24px;
}
.form-label {
display: block;
font-size: 13px;
font-weight: 600;
color: var(--text-secondary);
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.form-input {
width: 100%;
padding: 16px;
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
font-size: 16px;
font-family: inherit;
color: var(--text-primary);
background: var(--card-bg);
transition: border-color 0.2s;
}
.form-input:focus {
outline: none;
border-color: var(--text-primary);
}
/* 悬浮按钮 (FAB) - 约束在容器内 */
.fab {
position: absolute;
bottom: 100px;
right: 24px;
width: 60px;
height: 60px;
background: var(--text-primary);
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
font-weight: 500;
box-shadow: 0 10px 15px -3px rgba(15, 23, 42, 0.25);
cursor: pointer;
z-index: 99;
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.fab:active {
transform: scale(0.9);
}
.bottom-nav {
position: fixed;
bottom: 0;
width: 100%;
max-width: 450px;
height: 80px;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
border-top: 1px solid var(--border-color);
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
z-index: 100;
}
.nav-item {
flex: 1;
text-align: center;
color: var(--text-secondary);
cursor: pointer;
padding: 10px 0;
font-weight: 500;
font-size: 12px;
display: flex;
flex-direction: column;
align-items: center;
}
.nav-item.active {
color: var(--text-primary);
}
.nav-icon {
display: block;
margin-bottom: 4px;
font-size: 20px;
}
</style>
</head>
<body>
<div class="app-container">
<!-- 页面 1: 首页 -->
<div id="home" class="screen active">
<header>
<h1>HealthFlow</h1>
<p class="subtitle">追踪你的健康演变</p>
</header>
<div class="card" onclick="showScreen('epoch-detail')">
<div class="card-accent"></div>
<div class="card-header">
<span class="card-title">寒武纪元</span>
<span class="card-status">进行中</span>
</div>
<p class="card-dates">2025.12.21 - 2026.02.14</p>
<div class="progress-container">
<div class="progress-bar" style="width: 25%"></div>
</div>
</div>
<!-- 右下角悬浮按钮 -->
<div class="fab" onclick="showScreen('create-epoch')">+</div>
<div class="card">
<div class="card-header">
<span class="card-title">创世纪元</span>
</div>
<div class="stamp stamp-pass">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round">
<path d="M20 6L9 17l-5-5" />
</svg>
<span class="stamp-text">合格</span>
</div>
<p class="card-dates">2025.10.01 - 2025.12.20</p>
<div class="progress-container">
<div class="progress-bar" style="width: 100%"></div>
</div>
</div>
</div>
<!-- 页面 2: 创建纪元 -->
<div id="create-epoch" class="screen">
<header>
<div style="cursor:pointer; margin-bottom: 8px;" onclick="showScreen('home')">← 取消</div>
<h1>开启新纪元</h1>
<p class="subtitle">为你的健康阶段设定一个开端</p>
</header>
<div class="form-group">
<label class="form-label">纪元名称</label>
<input type="text" class="form-input" placeholder="例如:盛夏减脂阶段">
</div>
<div class="form-group">
<label class="form-label">起始日期</label>
<input type="date" class="form-input">
</div>
<div class="form-group">
<label class="form-label">截止日期</label>
<input type="date" class="form-input">
</div>
<div style="margin-top: 40px;">
<button class="btn-outline" style="background: var(--text-primary); color: white;"
onclick="showScreen('home')">确认开启</button>
</div>
</div>
<!-- 页面 3: 计划 -->
<div id="plans" class="screen">
<header>
<h1>计划中心</h1>
<p class="subtitle">专注于本阶段的周计划</p>
</header>
<div style="margin-bottom: 32px;">
<p class="stat-label" style="margin-bottom: 16px;">正在进行中</p>
<div class="card" onclick="showScreen('week-detail')">
<div class="card-accent" style="background: var(--accent-green);"></div>
<div class="card-header">
<span class="card-title">寒武纪元 - 第 2 周</span>
<span class="card-status">第 12 天</span>
</div>
<p class="card-dates">目标: 82.8 kg (还差 0.2 kg)</p>
<div class="progress-container">
<div class="progress-bar" style="width: 85%; background: var(--accent-green);"></div>
</div>
</div>
</div>
<div>
<p class="stat-label" style="margin-bottom: 12px;">后续序列</p>
<div class="week-item">
<div class="week-info">
<span class="week-name">第 3 周</span>
<span class="week-date">01.04 - 01.10</span>
</div>
<span class="week-result" style="color: var(--text-secondary)">待启动</span>
</div>
</div>
</div>
<!-- 页面 4: 详情 -->
<div id="epoch-detail" class="screen">
<header>
<div style="cursor:pointer; margin-bottom: 8px;" onclick="showScreen('home')">← 返回</div>
<h1>寒武纪元</h1>
<p class="subtitle">2025.12.21 - 2026.02.14</p>
</header>
<div class="dashboard">
<div class="stat-item">
<span class="stat-value">85.0</span>
<span class="stat-label">初始</span>
</div>
<div class="stat-item">
<span class="stat-value">75.0</span>
<span class="stat-label">目标</span>
</div>
<div class="stat-item">
<span class="stat-value">-2.4</span>
<span class="stat-label">已减</span>
</div>
</div>
<div class="week-list">
<div class="week-item" onclick="showScreen('week-detail')" style="position:relative; overflow:hidden;">
<div class="week-info">
<span class="week-name">第一周</span>
<span class="week-date">12.21 - 12.27</span>
</div>
<div class="stamp stamp-fail" style="right: 50px;">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
<span class="stamp-text" style="font-size: 16px;">不合格</span>
</div>
<span class="week-result" style="color: var(--accent-red)">+0.5 kg</span>
</div>
</div>
</div>
<!-- 页面 5: 周计划详情 -->
<div id="week-detail" class="screen">
<header>
<div style="cursor:pointer; margin-bottom: 8px;" onclick="showScreen('plans')">← 返回</div>
<h1>第一周计划</h1>
<p class="subtitle">正在为了本周目标努力</p>
</header>
<div class="hero-weight">
<span class="hero-value">82.6</span>
<span class="hero-unit">kg</span>
<p class="subtitle">当前体重记录</p>
</div>
<div class="btn-group">
<button class="btn-outline" style="background: var(--text-primary); color: white;">添加体重记录</button>
<button class="btn-outline">修改周目标</button>
</div>
<div class="week-list" style="margin-top: 40px;">
<p class="stat-label">本周指标</p>
<div class="week-item">
<span class="week-name">周初始</span>
<span class="week-name">83.8 kg</span>
</div>
<div class="week-item">
<span class="week-name">周目标</span>
<span class="week-name">82.8 kg</span>
</div>
</div>
</div>
<!-- 页面 6: 我的 -->
<div id="profile" class="screen">
<header>
<h1>个人中心</h1>
</header>
<div class="profile-header">
<div class="avatar"><img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Amos" alt="avatar"
style="width:100%; height:100%; border-radius:50%;"></div>
<div class="user-info">
<h2>Amos</h2>
<p class="subtitle">坚持 452 天</p>
</div>
</div>
<div class="stats-grid">
<div class="card" style="margin-bottom:0; padding:20px;">
<span class="stat-label">今年减重</span>
<span class="stat-value" style="color:var(--accent-green); margin-top:8px;">12.5 kg</span>
</div>
<div class="card" style="margin-bottom:0; padding:20px;">
<span class="stat-label">总减重</span>
<span class="stat-value" style="margin-top:8px;">24.8 kg</span>
</div>
</div>
<div class="dark-card">
<div class="year-badge">2025 PROGRESS</div>
<span class="stat-label">今年剩余天数</span>
<div class="stat-value" style="font-size:42px; margin-top:8px;">09 <small
style="font-size:18px; opacity:0.7;">DAYS</small></div>
</div>
<div style="margin-top:40px;">
<div class="week-item"><span class="week-name" style="color:var(--accent-red)">退出登录</span></div>
</div>
</div>
<nav class="bottom-nav">
<div class="nav-item active" onclick="showScreen('home')"><span class="nav-icon"></span>纪元</div>
<div class="nav-item" onclick="showScreen('plans')"><span class="nav-icon"></span>计划</div>
<div class="nav-item" onclick="showScreen('profile')"><span class="nav-icon"></span>我的</div>
</nav>
</div>
<script>
function showScreen(screenId) {
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
document.getElementById(screenId).classList.add('active');
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
if (screenId === 'home' || screenId === 'create-epoch') {
document.querySelectorAll('.nav-item')[0].classList.add('active');
} else if (screenId === 'plans' || screenId === 'week-detail' || screenId === 'epoch-detail') {
document.querySelectorAll('.nav-item')[1].classList.add('active');
} else if (screenId === 'profile') {
document.querySelectorAll('.nav-item')[2].classList.add('active');
}
window.scrollTo(0, 0);
}
</script>
</body>
</html>