同孕周悄悄话全屏页三改:星图 + 聚焦卡 + 清单;运动助手待办文案 (v26100165)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
11
index.html
11
index.html
@@ -7,7 +7,7 @@
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title>兜爸心选 · 孕育陪伴</title>
|
||||
<!-- V:26100164 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
|
||||
<!-- V:26100165 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
|
||||
<link rel="stylesheet" href="mama-box.css">
|
||||
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
|
||||
<!-- 共享助手:授权/跳商城/位置上报(分享卡片同步,见 docs/h5-auth-standard.md 第四节) -->
|
||||
@@ -1762,8 +1762,13 @@
|
||||
</header>
|
||||
<h2 class="whp-title" id="whpTitle">悄悄话</h2>
|
||||
<p class="whp-sub">不留名字,只留一句话。<br>听到了,就给她一个抱抱。</p>
|
||||
<div class="whp-hero" id="whpHero"></div>
|
||||
<div class="whp-flow" id="whpFlow"></div>
|
||||
<!-- 2026-10-02 三改(用户:「多人提交时看得不清晰……配色没问题,创意呈现上调整」):
|
||||
上 = 星图:每句悄悄话一颗星,抱抱越多越大越亮,连成今晚的星座;点星星 → 中间聚焦卡换成那一句(也会自动轮播)。
|
||||
下 = 全部悄悄话:单列清单,一行一句,人再多也清楚。 -->
|
||||
<div class="whp-sky2" id="whpSky" role="group" aria-label="今晚的星星,每颗是一句悄悄话"></div>
|
||||
<div class="whp-focus" id="whpFocus" aria-live="polite"></div>
|
||||
<div class="whp-lh"><b>全部悄悄话</b><span id="whpCount"></span></div>
|
||||
<div class="whp-list" id="whpList"></div>
|
||||
<p class="whp-end" id="whpEnd"></p>
|
||||
</div>
|
||||
<div class="whp-bar">
|
||||
|
||||
103
js/app.js
103
js/app.js
@@ -3,7 +3,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
|
||||
var VER = '26100164';
|
||||
var VER = '26100165';
|
||||
const $ = (s, c) => (c || document).querySelector(s);
|
||||
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
|
||||
|
||||
@@ -3339,39 +3339,101 @@
|
||||
return '<button class="whp-hug' + (it.hugged ? ' on' : '') + '" type="button" data-hug="' + esc(it.id) + '" aria-label="给她一个抱抱">' +
|
||||
HEART + '<b>' + (it.hugs || '') + '</b></button>';
|
||||
}
|
||||
function bubble(it, i) {
|
||||
/* 抱抱越多越亮越大:三档 */
|
||||
const lv = it.mine ? 'mine' : it.hugs >= 25 ? 'l3' : it.hugs >= 10 ? 'l2' : 'l1';
|
||||
const side = ['a', 'b', 'c'][i % 3];
|
||||
return '<div class="whp-b ' + lv + ' ' + side + '" style="--d:' + ((i * 0.7) % 4).toFixed(1) + 's;--i:' + i + '">' +
|
||||
(it.mine ? '<span class="whp-mine">我说的</span>' : '') +
|
||||
'<p>' + esc(it.text) + '</p>' +
|
||||
'<div class="whp-meta"><span>孕 ' + it.week + ' 周 · ' + esc(it.ago) + '</span>' + hugBtn(it) + '</div></div>';
|
||||
/* 星图 + 聚焦卡 + 清单(三改)。星星位置按 id 哈希定在网格里再抖一抖,同一句每次出现在同一处 */
|
||||
let fi = 0, focT = null, focHold = false;
|
||||
const hsh = s => { let h = 7; for (const c of String(s)) h = (h * 31 + c.charCodeAt(0)) >>> 0; return h; };
|
||||
function paintSky(l) {
|
||||
const n = l.length, cols = n > 12 ? 5 : 4, rows = Math.max(2, Math.ceil(n / cols));
|
||||
const pts = l.map((it, i) => {
|
||||
const h = hsh(it.id), c = i % cols, r = Math.floor(i / cols);
|
||||
/* 蛇形排列,连线不来回横穿 */
|
||||
const cc = r % 2 ? cols - 1 - c : c;
|
||||
const x = ((cc + .5 + ((h % 100) / 100 - .5) * .62) / cols) * 100;
|
||||
const y = ((r + .5 + (((h >> 8) % 100) / 100 - .5) * .55) / rows) * 100;
|
||||
const sz = it.mine ? 13 : Math.round(5 + Math.min(it.hugs || 0, 40) / 40 * 11);
|
||||
return { x, y, sz, it, i };
|
||||
});
|
||||
$('#whpSky').innerHTML =
|
||||
'<svg class="whs-lines" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true"><polyline points="' +
|
||||
pts.map(p => p.x.toFixed(1) + ',' + p.y.toFixed(1)).join(' ') + '"/></svg>' +
|
||||
pts.map(p => '<button type="button" class="whs-star' + (p.it.mine ? ' mine' : '') + (p.i === fi ? ' on' : '') +
|
||||
'" data-fi="' + p.i + '" style="left:' + p.x.toFixed(1) + '%;top:' + p.y.toFixed(1) + '%;--s:' + p.sz + 'px;--tw:' + ((hsh(p.it.id) % 30) / 10).toFixed(1) + 's" aria-label="' +
|
||||
esc(p.it.text) + '"><i></i></button>').join('');
|
||||
}
|
||||
function paintFocus(anim) {
|
||||
const l = list(), it = l[fi];
|
||||
const box = $('#whpFocus');
|
||||
if (!it) { box.innerHTML = ''; return; }
|
||||
box.innerHTML =
|
||||
'<div class="whf-top"><span class="whf-no">' + (it.mine ? '<em>我说的</em>' : '') + 'No.' + (fi + 1) + ' / ' + l.length + '</span>' +
|
||||
'<span class="whf-nav"><button type="button" data-fn="-1" aria-label="上一句">‹</button><button type="button" data-fn="1" aria-label="下一句">›</button></span></div>' +
|
||||
'<p class="whf-q' + (anim ? ' in' : '') + '">' + esc(it.text) + '</p>' +
|
||||
'<div class="whp-meta"><span>孕 ' + it.week + ' 周 · ' + esc(it.ago) + '</span>' + hugBtn(it) + '</div>';
|
||||
$$('.whs-star', $('#whpSky')).forEach(s => s.classList.toggle('on', +s.dataset.fi === fi));
|
||||
}
|
||||
function focusTo(i, user) {
|
||||
const n = list().length;
|
||||
if (!n) return;
|
||||
fi = (i + n) % n;
|
||||
if (user) focHold = true; // 用户自己点过就不再自动轮播,免得正要抱抱时换走
|
||||
paintFocus(true);
|
||||
}
|
||||
function paintList(l) {
|
||||
$('#whpCount').textContent = l.length + ' 句 · 最新在上';
|
||||
$('#whpList').innerHTML = l.map((it, i) => {
|
||||
const lv = it.mine ? 'mine' : it.hugs >= 25 ? 'l3' : it.hugs >= 10 ? 'l2' : 'l1';
|
||||
return '<div class="whl ' + lv + '"><button type="button" class="whl-t" data-fi="' + i + '">' +
|
||||
(it.mine ? '<em>我说的</em>' : '') + esc(it.text) + '</button>' +
|
||||
'<div class="whp-meta"><span>孕 ' + it.week + ' 周 · ' + esc(it.ago) + '</span>' + hugBtn(it) + '</div></div>';
|
||||
}).join('');
|
||||
}
|
||||
function paintPage() {
|
||||
const l = list().slice();
|
||||
const l = list();
|
||||
$('#whpTag').textContent = data ? '孕 ' + data.week + ' 周 · 前后一周的妈妈' : '';
|
||||
/* 北京时间 18 点后 / 5 点前叫「今晚」,其余「今天」 */
|
||||
const bh = (new Date().getUTCHours() + 8) % 24, night = bh >= 18 || bh < 5;
|
||||
$('#whpTitle').innerHTML = (night ? '今晚' : '今天') + ',<b>' + l.length + '</b> 句<br>悄悄话';
|
||||
$('#whpTitle').innerHTML = (night ? '今晚' : '今天') + ',<b>' + l.length + '</b> 句悄悄话';
|
||||
$('#whpEnd').textContent = night ? '— 都在这里了,晚安 —' : '— 都在这里了 —';
|
||||
/* 主角:抱抱最多的一句(不选自己的) */
|
||||
let top = null;
|
||||
l.forEach(x => { if (!x.mine && (!top || x.hugs > top.hugs)) top = x; });
|
||||
$('#whpHero').innerHTML = top
|
||||
? '<div class="whp-hq">' + esc(top.text) + '</div><div class="whp-meta"><span>孕 ' + top.week + ' 周 · ' + esc(top.ago) + ' · 抱抱最多</span>' + hugBtn(top) + '</div>'
|
||||
: '';
|
||||
$('#whpFlow').innerHTML = l.filter(x => x !== top).map(bubble).join('');
|
||||
/* 第一次聚焦:抱抱最多的那句(不选自己的) */
|
||||
fi = 0;
|
||||
l.forEach((x, i) => { if (!x.mine && x.hugs > (l[fi].mine ? -1 : l[fi].hugs)) fi = i; });
|
||||
paintSky(l);
|
||||
paintFocus(false);
|
||||
paintList(l);
|
||||
$('#whpLeft').textContent = !data ? '' : !oid() || !data.canPost ? '填好预产期,就能说一句' : data.left ? '今天还能说 ' + data.left + ' 句' : '今天的 3 句说完啦,明天再来';
|
||||
}
|
||||
page.addEventListener('click', e => {
|
||||
const st = e.target.closest('[data-fi]');
|
||||
if (st) {
|
||||
haptic();
|
||||
focusTo(+st.dataset.fi, true);
|
||||
if (st.classList.contains('whl-t')) $('#whpScroll').scrollTo({ top: $('#whpSky').offsetTop - 70, behavior: 'smooth' });
|
||||
return;
|
||||
}
|
||||
const nb = e.target.closest('[data-fn]');
|
||||
if (nb) { haptic(); focusTo(fi + +nb.dataset.fn, true); }
|
||||
});
|
||||
/* 聚焦卡左右滑切换 */
|
||||
let tx = null;
|
||||
$('#whpFocus').addEventListener('touchstart', e => { tx = e.touches[0].clientX; }, { passive: true });
|
||||
$('#whpFocus').addEventListener('touchend', e => {
|
||||
if (tx == null) return;
|
||||
const dx = e.changedTouches[0].clientX - tx; tx = null;
|
||||
if (Math.abs(dx) > 40) focusTo(fi + (dx < 0 ? 1 : -1), true);
|
||||
});
|
||||
function openPage() {
|
||||
paintPage();
|
||||
page.classList.add('show');
|
||||
page.setAttribute('aria-hidden', 'false');
|
||||
$('#whpScroll').scrollTop = 0;
|
||||
haptic();
|
||||
focHold = false;
|
||||
clearInterval(focT);
|
||||
if (!(window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches))
|
||||
focT = setInterval(() => { if (!focHold && !document.hidden && list().length > 1) focusTo(fi + 1); }, 6000);
|
||||
}
|
||||
function closePage() {
|
||||
clearInterval(focT);
|
||||
page.classList.remove('show');
|
||||
page.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
@@ -3427,6 +3489,7 @@
|
||||
const o = oid();
|
||||
if (!o) { toast('登录后就能给她抱抱啦'); return; }
|
||||
if (b.classList.contains('on')) { toast('你已经抱过她啦'); return; }
|
||||
focHold = true;
|
||||
const id = b.dataset.hug;
|
||||
const it = list().find(x => x.id === id);
|
||||
haptic();
|
||||
@@ -3491,7 +3554,8 @@
|
||||
paintEntry();
|
||||
paintPage();
|
||||
closeModal();
|
||||
$('#whpScroll').scrollTo({ top: $('#whpFlow').offsetTop - 80, behavior: 'smooth' });
|
||||
fi = 0; focHold = true; paintFocus(true);
|
||||
$('#whpScroll').scrollTo({ top: $('#whpSky').offsetTop - 70, behavior: 'smooth' });
|
||||
toast('发出去啦,同孕周妈妈会给你抱抱的');
|
||||
})
|
||||
.catch(() => toast('网络不太好,再试一次'))
|
||||
@@ -4311,6 +4375,7 @@
|
||||
[/估重/, '算一算宝宝有多重', '拿最近一次 B 超数据就能估'],
|
||||
[/起名/, '给宝宝想一个名字', '挑几个喜欢的字,和家人一起选'],
|
||||
[/档案/, '翻翻孕期档案', '把这周的变化记进档案里'],
|
||||
[/运动/, '做 10 分钟孕期运动', '散散步、拉伸一下,身体会轻松些'],
|
||||
];
|
||||
function todoLine(name) {
|
||||
for (const [re, t, d] of FP_TODO) if (re.test(name)) return [t, d];
|
||||
|
||||
46
mama-box.css
46
mama-box.css
@@ -3701,3 +3701,49 @@ a.skip:focus{left:16px;top:16px}
|
||||
.gi-pr .gi-coin{flex:none;width:15px;height:15px;background:url(assets/img/dou-coin.svg?v=20261002) center/contain no-repeat}
|
||||
.gi-pr span{font-family:"DIN Alternate","DIN Condensed","Bahnschrift","Arial Rounded MT Bold",Arial,sans-serif;font-variant-numeric:tabular-nums;letter-spacing:-.02em;font-size:15px;font-weight:800;color:var(--ink)}
|
||||
.gi-pr small{font-size:10.5px;font-weight:600;color:var(--ink);opacity:.55}
|
||||
|
||||
/* ---------- 同孕周悄悄话 · 三改:星图 + 聚焦卡 + 清单(2026-10-02)----------
|
||||
配色不变(用户:「配色没问题」),只换呈现:人多时不再是一堆左右乱飘、大小不一的气泡。 */
|
||||
.whp-title{margin-top:18px;font-size:28px;line-height:1.2}
|
||||
.whp-title b{font-size:40px}
|
||||
.whp-sub{margin-top:8px;font-size:12.5px}
|
||||
.whp-sky2{position:relative;height:190px;margin:18px -6px 0}
|
||||
.whs-lines{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
|
||||
.whs-lines polyline{fill:none;stroke:rgba(255,226,190,.22);stroke-width:1;vector-effect:non-scaling-stroke;stroke-dasharray:3 4}
|
||||
.whs-star{position:absolute;width:36px;height:36px;margin:-18px 0 0 -18px;display:grid;place-items:center;border-radius:50%}
|
||||
.whs-star i{display:block;width:var(--s);height:var(--s);border-radius:50%;background:#FFF6E6;
|
||||
box-shadow:0 0 calc(var(--s) * .8) calc(var(--s) * .2) rgba(255,226,190,.55);animation:whTw2 3.2s ease-in-out infinite alternate;animation-delay:calc(var(--tw) * -1)}
|
||||
.whs-star.mine i{background:#FFD596;box-shadow:0 0 14px 4px rgba(255,200,120,.7)}
|
||||
.whs-star.on i{background:#fff;animation:none;box-shadow:0 0 0 3px rgba(255,255,255,.18),0 0 18px 6px rgba(255,214,170,.75)}
|
||||
.whs-star.on::after{content:"";position:absolute;inset:2px;border-radius:50%;border:1.5px solid rgba(255,226,190,.7);animation:whRing 2s ease-out infinite}
|
||||
@keyframes whTw2{from{opacity:.55;transform:scale(.85)}to{opacity:1;transform:scale(1)}}
|
||||
.whp-focus{position:relative;margin-top:14px;padding:16px 18px 14px;border-radius:22px;min-height:150px;
|
||||
background:linear-gradient(150deg,rgba(255,226,190,.16),rgba(255,160,140,.06));border:1px solid rgba(255,226,190,.22);
|
||||
box-shadow:0 20px 50px -20px rgba(255,170,130,.35)}
|
||||
.whp-focus:empty{display:none}
|
||||
.whf-top{display:flex;align-items:center;justify-content:space-between}
|
||||
.whf-no{font-size:11px;letter-spacing:1px;color:rgba(255,226,190,.7);font-variant-numeric:tabular-nums}
|
||||
.whf-no em,.whl-t em{font-style:normal;display:inline-block;margin-right:6px;font-size:10.5px;font-weight:700;letter-spacing:1px;padding:1px 7px;border-radius:99px;background:#FFD596;color:#5A3714;vertical-align:1px}
|
||||
.whf-nav{display:flex;gap:6px}
|
||||
.whf-nav button{width:28px;height:28px;border-radius:50%;background:rgba(255,255,255,.08);color:rgba(255,255,255,.75);font-size:18px;line-height:26px}
|
||||
.whf-q{margin:12px 0 0;font-size:23px;line-height:1.45;font-weight:800;color:#FFF4E6;letter-spacing:.5px;min-height:66px}
|
||||
.whf-q.in{animation:whFq .45s var(--ease) both}
|
||||
@keyframes whFq{from{opacity:0;transform:translateY(8px);filter:blur(3px)}}
|
||||
.whp-focus .whp-meta{margin-top:12px}
|
||||
.whp-lh{display:flex;align-items:baseline;justify-content:space-between;margin:30px 2px 4px}
|
||||
.whp-lh b{font-size:15px;font-weight:700;color:rgba(255,255,255,.9);letter-spacing:1px}
|
||||
.whp-lh span{font-size:11.5px;color:rgba(255,255,255,.4)}
|
||||
.whp-list{display:flex;flex-direction:column}
|
||||
.whl{position:relative;padding:14px 0 12px 16px;border-bottom:1px solid rgba(255,255,255,.07)}
|
||||
.whl::before{content:"";position:absolute;left:2px;top:22px;width:5px;height:5px;border-radius:50%;background:rgba(255,246,230,.45)}
|
||||
.whl.l2::before{background:rgba(255,246,230,.8);box-shadow:0 0 6px rgba(255,226,190,.6)}
|
||||
.whl.l3::before{width:7px;height:7px;left:1px;top:21px;background:#fff;box-shadow:0 0 10px 2px rgba(255,214,170,.8)}
|
||||
.whl.mine{margin:6px 0;padding-right:12px;border-radius:16px;border-bottom:0;background:linear-gradient(140deg,rgba(255,214,150,.18),rgba(255,170,110,.08));box-shadow:inset 0 0 0 1px rgba(255,214,150,.35)}
|
||||
.whl.mine::before{left:6px;background:#FFD596;box-shadow:0 0 8px rgba(255,200,120,.8)}
|
||||
.whl.mine .whl-t{padding-left:4px}
|
||||
.whl-t{display:block;width:100%;text-align:left;font-size:15.5px;line-height:1.55;font-weight:500;color:rgba(255,255,255,.86)}
|
||||
.whl.l3 .whl-t,.whl.mine .whl-t{font-weight:700;color:#fff}
|
||||
.whl .whp-meta{margin-top:6px}
|
||||
.whl .whp-hug{height:26px;padding:0 10px;font-size:12px}
|
||||
@media (prefers-reduced-motion:reduce){.whs-star i,.whs-star.on::after,.whf-q.in{animation:none!important}}
|
||||
.whf-nav button{display:grid;place-items:center;padding:0;line-height:1}
|
||||
|
||||
Reference in New Issue
Block a user