diff --git a/index.html b/index.html
index ab2e554..861fd27 100644
--- a/index.html
+++ b/index.html
@@ -7,7 +7,7 @@
diff --git a/js/app.js b/js/app.js
index 12ad884..d73dc05 100644
--- a/js/app.js
+++ b/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 '
';
}
- 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 '
' +
- (it.mine ? '
我说的' : '') +
- '
' + esc(it.text) + '
' +
- '
孕 ' + it.week + ' 周 · ' + esc(it.ago) + '' + hugBtn(it) + '
';
+ /* 星图 + 聚焦卡 + 清单(三改)。星星位置按 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 =
+ '
' +
+ pts.map(p => '
').join('');
+ }
+ function paintFocus(anim) {
+ const l = list(), it = l[fi];
+ const box = $('#whpFocus');
+ if (!it) { box.innerHTML = ''; return; }
+ box.innerHTML =
+ '
' + (it.mine ? '我说的' : '') + 'No.' + (fi + 1) + ' / ' + l.length + '' +
+ '
' +
+ '
' + esc(it.text) + '
' +
+ '
孕 ' + it.week + ' 周 · ' + esc(it.ago) + '' + hugBtn(it) + '
';
+ $$('.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 '
' +
+ '
孕 ' + it.week + ' 周 · ' + esc(it.ago) + '' + hugBtn(it) + '
';
+ }).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 ? '今晚' : '今天') + ',
' + l.length + ' 句
悄悄话';
+ $('#whpTitle').innerHTML = (night ? '今晚' : '今天') + ',
' + l.length + ' 句悄悄话';
$('#whpEnd').textContent = night ? '— 都在这里了,晚安 —' : '— 都在这里了 —';
- /* 主角:抱抱最多的一句(不选自己的) */
- let top = null;
- l.forEach(x => { if (!x.mine && (!top || x.hugs > top.hugs)) top = x; });
- $('#whpHero').innerHTML = top
- ? '
' + esc(top.text) + '
孕 ' + top.week + ' 周 · ' + esc(top.ago) + ' · 抱抱最多' + hugBtn(top) + '
'
- : '';
- $('#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];
diff --git a/mama-box.css b/mama-box.css
index 46df836..c6c2913 100644
--- a/mama-box.css
+++ b/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}