From acc8301b200173da296cbe40fc2fbe39b0a1aa4d Mon Sep 17 00:00:00 2001 From: Karlcarlo Date: Fri, 2 Oct 2026 06:14:34 +0000 Subject: [PATCH] =?UTF-8?q?=E5=90=8C=E5=AD=95=E5=91=A8=E6=82=84=E6=82=84?= =?UTF-8?q?=E8=AF=9D=E5=85=A8=E5=B1=8F=E9=A1=B5=E4=B8=89=E6=94=B9=EF=BC=9A?= =?UTF-8?q?=E6=98=9F=E5=9B=BE=20+=20=E8=81=9A=E7=84=A6=E5=8D=A1=20+=20?= =?UTF-8?q?=E6=B8=85=E5=8D=95=EF=BC=9B=E8=BF=90=E5=8A=A8=E5=8A=A9=E6=89=8B?= =?UTF-8?q?=E5=BE=85=E5=8A=9E=E6=96=87=E6=A1=88=20(v26100165)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- index.html | 11 ++++-- js/app.js | 103 +++++++++++++++++++++++++++++++++++++++++---------- mama-box.css | 46 +++++++++++++++++++++++ 3 files changed, 138 insertions(+), 22 deletions(-) diff --git a/index.html b/index.html index ab2e554..861fd27 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ 兜爸心选 · 孕育陪伴 - + @@ -1762,8 +1762,13 @@

悄悄话

不留名字,只留一句话。
听到了,就给她一个抱抱。

-
-
+ +
+
+
全部悄悄话
+

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}