Files
wx_pbzc/pages/index/index.wxss
T
lc 0464eeaba6 feat(timer): 训练页改版 hero 风格 + 进度环刻度 + 醒目姿态提示气泡
- progress-ring: canvas 新增秒刻度层(四分位加粗), 环内加 subText, 移除组件内 statusText
- timer.wxml: 环下方状态词 + 目标信息卡(今日目标·第N天›静态箭头) + 运行提示; 进度环传 ticks/subText
- timer.js: 派生 ringTicks/ringSubText/statusText/goalLine/runningTip/tipType/tipIcon, 各生命周期计算下发
- timer.wxss: 按钮贴底(flex-start+margin-top:auto), 新增 .timer-status/.goal-card/.timer-tip 气泡卡片(主色左边框+小三角+tipPulse 呼吸), 文字放大加粗
- 姿态提示分语义: posture/phase(主色) / done(成功色), 图标用 peopleFill/successFill
- 状态机/计时/循环FSM/呼吸环/彩带/弹窗/语音震动常亮全部保留
- 另含 index 进度地图右上角奖杯图标删除(quest-trophy 样式清理)
2026-08-11 15:38:37 +08:00

458 lines
9.0 KiB
Plaintext
Raw 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.
/* ===== 全宽渐变头图 hero ===== */
/* 负 margin 抵消 container 的 24rpx 内边距,让头图左右贯穿并贴到导航栏底边;
底部留大内边距给下方 quest-card 负 margin 上浮叠住。文字统一白色,图标用
*White 变体(若有)。hero 用 opacity-only 动画,避免 transform 把 .container
变成 containing block 而破坏弹窗定位(同 app.wxss pageIn 思路)。 */
.hero {
margin: -24rpx -24rpx 0;
padding: 24rpx 24rpx 72rpx;
background: linear-gradient(160deg, var(--primary) 0%, var(--primary-light) 100%);
color: #fff;
position: relative;
overflow: hidden;
animation: heroFade 0.4s ease both;
}
.hero::after {
content: '';
position: absolute;
right: -60rpx;
top: -60rpx;
width: 240rpx;
height: 240rpx;
border-radius: 50%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.18), transparent 70%);
pointer-events: none;
}
@keyframes heroFade {
from { opacity: 0; }
to { opacity: 1; }
}
/* 顶部行:圆形头像 + 时间问候 */
.hero-top {
display: flex;
align-items: center;
gap: 18rpx;
}
.hero-avatar {
width: 84rpx;
height: 84rpx;
flex-shrink: 0;
border-radius: 50%;
overflow: hidden;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
border: 3rpx solid rgba(255, 255, 255, 0.6);
}
.hero-avatar-img {
width: 100%;
height: 100%;
border-radius: 50%;
display: block;
}
/* 有头像时去掉白底,只留浅描边,避免深色头像边缘露白缝 */
.hero-avatar.has-avatar {
background: transparent;
border-color: rgba(255, 255, 255, 0.85);
}
.hero-user {
display: flex;
flex-direction: row;
align-items: center;
gap: 14rpx;
min-width: 0;
}
.hero-greet {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.92);
font-weight: 500;
}
/* 挑战主句:时长强调色 + 「敢不敢」白字 */
.hero-challenge {
margin-top: 28rpx;
display: flex;
align-items: baseline;
flex-wrap: wrap;
}
.hero-time {
font-size: 48rpx;
font-weight: 800;
color: #FFE3C2;
letter-spacing: 1rpx;
margin-right: 12rpx;
font-variant-numeric: tabular-nums;
}
.hero-cta-text {
font-size: 44rpx;
font-weight: 800;
color: #fff;
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
line-height: 1.2;
}
.hero-social {
margin-top: 0;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.9);
}
/* ===== 闯关进度地图(上浮卡片) ===== */
.quest-card {
margin-top: -56rpx;
margin-left: 0;
margin-right: 0;
position: relative;
z-index: 2;
}
.quest-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24rpx;
}
.quest-title {
font-size: 32rpx;
font-weight: 700;
color: var(--text);
}
.quest-sub {
font-size: 24rpx;
font-weight: 400;
color: var(--text-secondary);
margin-left: 12rpx;
}
.quest-map {
display: flex;
align-items: center;
padding: 8rpx 4rpx;
}
.q-node {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
font-weight: 700;
background: var(--bg-soft);
color: var(--text-secondary);
}
.q-node.done {
background: var(--primary);
color: #fff;
}
.q-node.now {
background: linear-gradient(135deg, var(--primary), var(--primary-light));
color: #fff;
box-shadow: 0 0 0 6rpx rgba(var(--primary-rgb), 0.18);
animation: qPulse 1.6s ease-in-out infinite;
}
.q-node.final {
background: #FFF3E0;
font-size: 30rpx;
}
.q-link {
flex: 1;
height: 4rpx;
background: var(--bg-soft);
margin: 0 2rpx;
}
.q-link.done {
background: var(--primary);
}
.quest-tip {
display: block;
margin-top: 20rpx;
font-size: 24rpx;
font-weight: 600;
color: var(--primary);
}
@keyframes qPulse {
0% { box-shadow: 0 0 0 4rpx rgba(var(--primary-rgb), 0.28); }
70% { box-shadow: 0 0 0 12rpx rgba(var(--primary-rgb), 0); }
100% { box-shadow: 0 0 0 4rpx rgba(var(--primary-rgb), 0); }
}
/* ===== 计时环 dial ===== */
.timer-wrap {
text-align: center;
margin: 32rpx 0 8rpx;
}
.dial {
width: 320rpx;
height: 320rpx;
border-radius: 50%;
margin: 0 auto;
position: relative;
background: radial-gradient(circle at 35% 30%, #ffffff, #f4f6f2 70%);
box-shadow: inset 0 4rpx 14rpx rgba(var(--primary-rgb), 0.12), 0 10rpx 24rpx rgba(var(--primary-rgb), 0.12);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
animation: ringBreathe 3s ease-in-out infinite;
}
/* 虚线刻度环 */
.dial::before {
content: '';
position: absolute;
inset: 14rpx;
border-radius: 50%;
border: 2rpx dashed rgba(var(--primary-rgb), 0.28);
}
.dial-time {
font-size: 84rpx;
font-weight: 800;
color: var(--primary);
font-variant-numeric: tabular-nums;
letter-spacing: -1rpx;
line-height: 1;
max-width: 280rpx;
text-align: center;
white-space: nowrap;
overflow: hidden;
}
.dial-label {
font-size: 24rpx;
color: var(--text-secondary);
margin-top: 8rpx;
}
.benefit {
margin-top: 20rpx;
font-size: 28rpx;
color: var(--text-secondary);
}
.benefit-hl {
color: var(--primary);
font-weight: 700;
font-size: 30rpx;
}
@keyframes ringBreathe {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.02); }
}
/* ===== action buttons ===== */
.action-buttons {
display: flex;
flex-direction: column;
gap: 24rpx;
margin: 8rpx 0 8rpx;
}
/* 自由训练 / 循环训练 并排一行 */
.action-row {
display: flex;
gap: 16rpx;
}
.action-row .action-cell {
flex: 1;
min-width: 0; /* 防止图标+文字在窄屏撑破 flex 项 */
}
/* 主按钮脉冲发光(加在 ui-btn 宿主上,__usePrivacyCheck__ 不影响) */
@keyframes ctaPulse {
0%, 100% { box-shadow: 0 8rpx 20rpx rgba(var(--primary-rgb), 0.35); }
50% { box-shadow: 0 8rpx 30rpx rgba(var(--primary-rgb), 0.6); }
}
/* ===== picker ===== */
.picker-title {
font-size: 34rpx;
font-weight: 600;
color: var(--text);
display: block;
text-align: center;
margin-bottom: 32rpx;
}
.preset-grid {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
margin-bottom: 28rpx;
}
.preset-item {
flex: 0 0 calc(33.33% - 12rpx);
box-sizing: border-box;
background: var(--bg-soft);
border: 2rpx solid transparent;
border-radius: 16rpx;
padding: 20rpx 0;
text-align: center;
display: flex;
flex-direction: column;
transition: all 0.2s ease;
}
.preset-item:active {
transform: scale(0.94);
}
.preset-item.selected {
background: var(--primary-bg);
border: 2rpx solid var(--primary);
}
.preset-num {
font-size: 36rpx;
font-weight: 700;
color: var(--text);
line-height: 1.1;
}
.preset-item.selected .preset-num {
color: var(--primary);
}
.preset-unit {
font-size: 20rpx;
color: var(--text-secondary);
margin-top: 2rpx;
line-height: 1;
}
.custom-input-row {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 28rpx;
}
.custom-label {
font-size: 28rpx;
color: var(--text-secondary);
line-height: 1;
}
.custom-input {
width: 160rpx;
height: 64rpx;
background: var(--bg-soft);
border-radius: 12rpx;
text-align: center;
font-size: 32rpx;
font-weight: 600;
color: var(--primary);
margin: 0 16rpx;
}
.picker-cancel {
display: block;
text-align: center;
font-size: 28rpx;
color: var(--text-secondary);
padding: 12rpx 0;
margin-top: 8rpx;
}
/* ===== circuit (循环训练) config panel ===== */
.picker-sub {
display: block;
text-align: center;
font-size: 24rpx;
color: var(--text-secondary);
margin: -18rpx 0 24rpx;
}
.circuit-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 8rpx;
border-bottom: 1rpx solid var(--border);
}
.circuit-row-label {
font-size: 30rpx;
color: var(--text);
font-weight: 500;
}
.stepper {
display: flex;
align-items: center;
gap: 20rpx;
}
.stepper-btn {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: var(--bg-soft);
color: var(--primary);
font-size: 40rpx;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
transition: transform 0.12s ease, opacity 0.12s ease;
}
.stepper-btn:active {
transform: scale(0.9);
opacity: 0.8;
}
.stepper-val {
min-width: 124rpx;
text-align: center;
font-size: 32rpx;
font-weight: 700;
color: var(--text);
font-variant-numeric: tabular-nums;
}
/* ===== 训练完成高亮 (3 秒后淡出) ===== */
/* 这个 class 落在 <ui-card> 宿主节点上(ui-card.wxss 已把宿主设为 display:block
否则 border/box-shadow 只会碎成两根竖条、transform 完全不生效)。
描边用 box-shadow 的 spread 而非 borderborder 会撑大宿主 8rpx,高亮出现/消失
时整页布局跳动;box-shadow 不占布局空间。宿主自身无圆角,必须补上与内部卡片
一致的 24rpx,否则描边会是直角框套在圆角卡片外面。 */
.just-completed {
animation: justCompletedPulse 1s ease-in-out 2;
border-radius: 24rpx;
box-shadow: 0 0 0 4rpx var(--primary), 0 4rpx 24rpx rgba(var(--primary-rgb), 0.3);
}
@keyframes justCompletedPulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.02); }
}