feat: 移动端UI精致化优化

- 添加页面过渡动画(淡入+滑动)
- 优化统计卡片视觉,添加渐变色和微动效
- 实现列表项左滑删除手势(编辑+删除按钮)
- 优化底部导航,缩小高度并添加点击波纹效果
- 改进空状态,添加插画和引导按钮

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Developer
2026-03-18 16:48:42 +08:00
co-authored by Claude
parent af3fcbea96
commit 349760b60c
6 changed files with 466 additions and 40 deletions
+236 -22
View File
@@ -564,24 +564,77 @@ textarea:focus-visible {
text-align: left;
border: 1px solid rgba(148, 163, 184, 0.12);
background: rgba(255, 255, 255, 0.82);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45), 0 2px 8px rgba(15, 23, 42, 0.04);
cursor: pointer;
transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition), background var(--transition);
}
.stat-card:hover {
transform: translateY(-1px);
box-shadow: var(--shadow-xs);
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
}
.stat-card:active {
transform: translateY(0) scale(0.98);
}
.stat-card.active {
border-color: rgba(37, 99, 235, 0.3);
background: rgba(240, 246, 255, 0.96);
box-shadow: 0 10px 24px rgba(37, 99, 235, 0.08);
box-shadow: 0 10px 28px rgba(37, 99, 235, 0.12);
}
/* Income stat card with gradient */
.stat-card:has(.income) {
background: linear-gradient(135deg, rgba(5, 150, 105, 0.08) 0%, rgba(5, 150, 105, 0.02) 100%);
border-color: rgba(5, 150, 105, 0.15);
}
.stat-card:has(.income):hover {
background: linear-gradient(135deg, rgba(5, 150, 105, 0.12) 0%, rgba(5, 150, 105, 0.04) 100%);
border-color: rgba(5, 150, 105, 0.22);
box-shadow: 0 8px 24px rgba(5, 150, 105, 0.1);
}
.stat-card:has(.income).active {
background: linear-gradient(135deg, rgba(5, 150, 105, 0.16) 0%, rgba(5, 150, 105, 0.06) 100%);
border-color: rgba(5, 150, 105, 0.3);
box-shadow: 0 10px 28px rgba(5, 150, 105, 0.14);
}
/* Expense stat card with gradient */
.stat-card:has(.expense) {
background: linear-gradient(135deg, rgba(220, 38, 38, 0.08) 0%, rgba(220, 38, 38, 0.02) 100%);
border-color: rgba(220, 38, 38, 0.15);
}
.stat-card:has(.expense):hover {
background: linear-gradient(135deg, rgba(220, 38, 38, 0.12) 0%, rgba(220, 38, 38, 0.04) 100%);
border-color: rgba(220, 38, 38, 0.22);
box-shadow: 0 8px 24px rgba(220, 38, 38, 0.1);
}
.stat-card:has(.expense).active {
background: linear-gradient(135deg, rgba(220, 38, 38, 0.16) 0%, rgba(220, 38, 38, 0.06) 100%);
border-color: rgba(220, 38, 38, 0.3);
box-shadow: 0 10px 28px rgba(220, 38, 38, 0.14);
}
.stat-card--balance {
background: rgba(255, 255, 255, 0.82);
background: linear-gradient(135deg, rgba(37, 99, 235, 0.08) 0%, rgba(37, 99, 235, 0.02) 100%);
border-color: rgba(37, 99, 235, 0.15);
}
.stat-card--balance:hover {
background: linear-gradient(135deg, rgba(37, 99, 235, 0.12) 0%, rgba(37, 99, 235, 0.04) 100%);
border-color: rgba(37, 99, 235, 0.22);
box-shadow: 0 8px 24px rgba(37, 99, 235, 0.1);
}
.stat-card--balance.active {
background: linear-gradient(135deg, rgba(37, 99, 235, 0.16) 0%, rgba(37, 99, 235, 0.06) 100%);
border-color: rgba(37, 99, 235, 0.3);
box-shadow: 0 10px 28px rgba(37, 99, 235, 0.14);
}
.label {
@@ -1817,31 +1870,53 @@ textarea:focus-visible {
.bottom-nav__inner {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 6px;
padding: 10px 10px 11px;
border-radius: 22px 22px 0 0;
background: rgba(255, 255, 255, 0.84);
border: 1px solid rgba(255, 255, 255, 0.66);
box-shadow: 0 -12px 30px rgba(15, 23, 42, 0.06);
gap: 4px;
padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
border-radius: 20px 20px 0 0;
background: rgba(255, 255, 255, 0.88);
border: 1px solid rgba(255, 255, 255, 0.7);
box-shadow: 0 -8px 24px rgba(15, 23, 42, 0.05);
backdrop-filter: blur(24px);
}
.bottom-nav__item {
min-height: 54px;
display: grid;
justify-items: center;
align-content: center;
gap: 4px;
padding: 7px 4px;
border-radius: 16px;
min-height: 48px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 3px;
padding: 5px 4px;
border-radius: 14px;
color: var(--text-tertiary);
cursor: pointer;
transition: background var(--transition), color var(--transition), transform var(--transition);
position: relative;
overflow: hidden;
}
.bottom-nav__item::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(37, 99, 235, 0.1);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.3s ease, height 0.3s ease;
}
.bottom-nav__item:active::before {
width: 100%;
height: 100%;
}
.bottom-nav__item span {
font-size: 0.74rem;
font-weight: 700;
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.02em;
}
.bottom-nav__item.is-active {
@@ -1849,6 +1924,18 @@ textarea:focus-visible {
color: var(--primary);
}
.bottom-nav__item.is-active::before {
display: none;
}
.bottom-nav__item .icon {
transition: transform 0.2s ease;
}
.bottom-nav__item:active .icon {
transform: scale(0.9);
}
.checkbox-label {
display: inline-flex;
align-items: center;
@@ -2191,6 +2278,133 @@ textarea:focus-visible {
to { transform: rotate(360deg); }
}
.is-spinning {
animation: spin 1s linear infinite;
/* Swipeable Item */
.swipeable-item {
position: relative;
overflow: hidden;
}
.swipeable-content {
position: relative;
z-index: 1;
background: var(--surface);
cursor: grab;
}
.swipeable-content.is-swiping {
cursor: grabbing;
}
.swipeable-actions {
position: absolute;
top: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
padding: 0 12px;
background: transparent;
z-index: 0;
}
.swipeable-action {
width: 56px;
height: 56px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 14px;
cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.swipeable-action:active {
transform: scale(0.92);
}
.swipeable-action--edit {
background: var(--primary-soft);
color: var(--primary);
}
.swipeable-action--delete {
background: var(--expense-soft);
color: var(--expense);
}
/* Empty State Enhanced */
.empty-state-enhanced {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 24px;
text-align: center;
}
.empty-state-illustration {
position: relative;
margin-bottom: 20px;
}
.empty-state-bg {
width: 80px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 24px;
background: linear-gradient(135deg, rgba(37, 99, 235, 0.1) 0%, rgba(37, 99, 235, 0.04) 100%);
color: var(--primary);
position: relative;
}
.empty-state-bg::before {
content: '';
position: absolute;
inset: -8px;
background: radial-gradient(circle, rgba(37, 99, 235, 0.08) 0%, transparent 70%);
border-radius: 50%;
z-index: -1;
}
.empty-state-title {
font-size: 1.1rem;
font-weight: 700;
color: var(--text);
margin-bottom: 8px;
}
.empty-state-description {
font-size: 0.9rem;
color: var(--text-secondary);
line-height: 1.5;
margin-bottom: 20px;
max-width: 240px;
}
.empty-state-action {
min-width: 140px;
min-height: 44px;
}
.empty-state-action .icon {
margin-right: 6px;
}
.page-transition {
opacity: 1;
transform: translateY(0);
transition: opacity 250ms ease-out, transform 250ms ease-out;
}
.page-transition--entering {
opacity: 0;
transform: translateY(12px);
}
.page-transition--active {
opacity: 1;
transform: translateY(0);
}