Files
mama-box/demo/gc-v2/index.html
2026-11-01 23:59:31 +00:00

566 lines
39 KiB
HTML
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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
<title>孕妈广场</title>
<!-- 效果稿 V2 · 广场地图:首屏是一张俯视小广场插画(SVG),三个分类 = 广场上的三个角落;往下是该角落的话题和笔记。演示页,不接后端。 -->
<style>
:root{
--brand:#F4593C;--ink:#2E2521;--ink-2:#6E625B;--muted:#A08F86;--line:#EFE3D8;
--bg:#FAF4EC;--fam:#E0566F;--work:#3A72B8;--baby:#2E8A7C;
--zc:#F4593C;
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0;height:100%;overflow:hidden;overscroll-behavior:none}
body{background:var(--bg);font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Noto Sans CJK SC","Segoe UI",Roboto,sans-serif;
color:var(--ink);-webkit-font-smoothing:antialiased;font-size:14px;line-height:1.5;-webkit-text-size-adjust:100%}
.hide{display:none!important}
button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:pointer}
#sc{position:fixed;inset:0;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior:none;background:var(--bg)}
#sc::-webkit-scrollbar{display:none}
/* ---------- 顶栏 ---------- */
.top{position:sticky;top:0;z-index:30;padding-top:env(safe-area-inset-top);background:rgba(250,244,236,.88);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);transition:box-shadow .2s}
.top.on{box-shadow:0 4px 14px rgba(150,110,80,.10)}
.nav{display:flex;align-items:center;height:46px;padding:0 8px}
.nav .bk{width:36px;height:36px;display:grid;place-items:center;border-radius:50%}
.nav .bk:active{background:rgba(0,0,0,.05)}
.nav h1{flex:1;margin:0;text-align:center;font-size:17px;font-weight:800;letter-spacing:1px}
.nav .mine{height:30px;padding:0 11px;border-radius:15px;font-size:12.5px;font-weight:700;color:#8A6E5E;background:#F1E5D8}
.ver{position:absolute;left:50%;transform:translateX(-50%);bottom:-1px;font-size:11px;color:#C4B2A6;letter-spacing:.5px;white-space:nowrap;line-height:1}
/* ---------- 欢迎语 ---------- */
.hello{padding:8px 18px 2px;display:flex;align-items:flex-end;justify-content:space-between;gap:10px}
.hello h2{margin:0;font-size:20px;font-weight:800;line-height:1.3;letter-spacing:.5px}
.hello h2 em{font-style:normal;color:var(--brand)}
.hello p{margin:3px 0 0;font-size:12.5px;color:var(--muted)}
.hello .wx{flex:none;text-align:right;font-size:11px;color:#B39A8A;line-height:1.35}
.hello .wx b{display:block;font-size:15px;color:#8C6F5C;font-weight:700}
/* ---------- 广场地图 ---------- */
.mapw{position:relative;margin:10px 12px 0;border-radius:26px;overflow:hidden;box-shadow:0 14px 30px -18px rgba(140,90,50,.45),0 0 0 1px rgba(200,170,140,.25);background:#F3E6D5}
.map{position:relative;width:100%;aspect-ratio:351/440}
.map svg.ground{position:absolute;inset:0;width:100%;height:100%;display:block}
.pin{position:absolute;transform:translate(-50%,-50%)}
/* 角落热区 */
.zone{position:absolute;border-radius:50%;transform:translate(-50%,-50%)}
.zone .halo{position:absolute;inset:0;border-radius:50%;border:2px dashed var(--zc);opacity:0;transform:scale(.92);transition:opacity .3s,transform .3s}
.map.f-family .z-family .halo,.map.f-work .z-work .halo,.map.f-baby .z-baby .halo{opacity:.75;transform:scale(1);animation:spin 26s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
/* 招牌 */
.sign{position:absolute;transform:translate(-50%,-50%);display:flex;flex-direction:column;align-items:center;pointer-events:none;z-index:4}
.sign b{display:block;padding:4px 10px 4px;border-radius:10px;background:#FFFDF9;color:var(--zc);font-size:12.5px;font-weight:800;letter-spacing:.5px;white-space:nowrap;
box-shadow:0 3px 0 rgba(0,0,0,.06),0 6px 14px -6px rgba(110,70,40,.35);border:1.5px solid color-mix(in srgb,var(--zc) 28%,#fff);transition:background .25s,color .25s}
.sign small{margin-top:3px;padding:1px 7px;border-radius:8px;background:rgba(255,253,249,.82);font-size:11px;color:#8C7466;white-space:nowrap}
.map.f-family .s-family b,.map.f-work .s-work b,.map.f-baby .s-baby b,.map.f-all .s-all b{background:var(--zc);color:#fff;border-color:var(--zc)}
/* 妈妈 */
.mom{position:absolute;width:34px;height:34px;margin:-17px 0 0 -17px;z-index:3;transition:filter .3s,opacity .3s}
.mom i{display:block;width:100%;height:100%;border-radius:50%;border:2.5px solid #fff;background:#EADBCB center/cover no-repeat;
box-shadow:0 5px 8px -3px rgba(90,55,30,.45);animation:breathe 3.4s ease-in-out infinite;transform-origin:50% 80%}
.mom::after{content:"";position:absolute;left:50%;bottom:-5px;width:26px;height:7px;margin-left:-13px;border-radius:50%;background:rgba(90,60,30,.18);filter:blur(1.5px);z-index:-1;animation:shadow 3.4s ease-in-out infinite}
.mom.sm{width:28px;height:28px;margin:-14px 0 0 -14px}
@keyframes breathe{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-2px) scale(1.06)}}
@keyframes shadow{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(.85);opacity:.7}}
/* 对话气泡 */
.bub{position:absolute;z-index:6;max-width:150px;padding:6px 10px 7px;border-radius:14px;background:#fff;font-size:12px;line-height:1.42;color:#3F3430;font-weight:600;
box-shadow:0 8px 18px -8px rgba(100,60,30,.4);transition:opacity .35s,transform .35s,filter .3s;pointer-events:none}
.bub::before{content:"";position:absolute;width:10px;height:10px;background:#fff;transform:rotate(45deg);border-radius:2px}
.bub.tl::before{left:12px;bottom:-4px}.bub.tr::before{right:12px;bottom:-4px}.bub.br::before{right:34px;top:-4px}
.bub span{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;position:relative}
.bub em{font-style:normal;color:var(--zc);font-weight:800}
.bub.out span{opacity:.15;transform:translateY(3px)}
.bub span{transition:opacity .3s,transform .3s}
.map:not(.f-all) .dim{opacity:.45;filter:grayscale(.6)}
.map:not(.f-all) .bub.dim{opacity:0;transform:scale(.9)}
/* 喷泉水波 */
.rip{transform-origin:center;transform-box:fill-box;animation:rip 3.6s ease-out infinite}
.rip.r2{animation-delay:1.2s}.rip.r3{animation-delay:2.4s}
@keyframes rip{0%{transform:scale(.35);opacity:.9}100%{transform:scale(1.25);opacity:0}}
.leaf{transform-origin:center;transform-box:fill-box;animation:sway 6s ease-in-out infinite}
@keyframes sway{0%,100%{transform:rotate(0)}50%{transform:rotate(3deg)}}
.bird{animation:peck 2.8s ease-in-out infinite;transform-box:fill-box;transform-origin:center}
@keyframes peck{0%,70%,100%{transform:translate(0,0)}78%{transform:translate(1.5px,1px)}86%{transform:translate(0,0)}}
/* 投稿信箱(地图上) */
.box{position:absolute;z-index:5;display:flex;flex-direction:column;align-items:center;transform:translate(-50%,-50%)}
.box .mb{position:relative;width:46px;height:62px}
.box .mb svg{display:block;width:100%;height:100%;overflow:visible;animation:wob 4.5s ease-in-out infinite;transform-origin:50% 100%}
@keyframes wob{0%,86%,100%{transform:rotate(0)}90%{transform:rotate(-4deg)}94%{transform:rotate(3deg)}}
.box .tag{margin-top:2px;padding:3px 8px;border-radius:9px;background:#fff;font-size:11px;font-weight:800;color:var(--brand);white-space:nowrap;box-shadow:0 4px 10px -5px rgba(120,60,30,.5);line-height:1.35;text-align:center}
.box .tag small{display:block;font-size:11px;font-weight:600;color:#A07C68}
.box:active .mb{transform:scale(.95)}
/* 地图下方路牌(分类快捷切换) */
.posts{display:flex;gap:6px;padding:12px 12px 2px}
.posts button{flex:1;min-width:0;height:36px;border-radius:12px;background:#F2E7DA;color:#8A7468;font-size:13.5px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:4px;transition:all .2s;white-space:nowrap}
.posts button i{width:7px;height:7px;border-radius:50%;background:var(--zc);flex:none}
.posts button.on{background:var(--zc);color:#fff;box-shadow:0 6px 14px -7px var(--zc)}
.posts button.on i{background:#fff}
/* ---------- 列表 ---------- */
.sec{padding:20px 16px 0}
.sec-h{display:flex;align-items:center;gap:8px;margin-bottom:10px}
.sec-h h3{margin:0;font-size:17px;font-weight:800;letter-spacing:.3px;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sec-h h3 em{font-style:normal;color:var(--zc)}
.live{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);flex:none}
.live .dot{width:7px;height:7px;border-radius:50%;background:#58B37A;box-shadow:0 0 0 3px rgba(88,179,122,.2);animation:pulse 1.8s ease-in-out infinite}
@keyframes pulse{50%{box-shadow:0 0 0 6px rgba(88,179,122,0)}}
.stack{display:flex}
.stack i{width:20px;height:20px;border-radius:50%;border:1.5px solid #fff;margin-left:-6px;background:#EADBCB center/cover}
.stack i:first-child{margin-left:0}
/* 话题:广场石板 */
.tps{display:flex;flex-direction:column;gap:8px}
.tp{display:flex;align-items:center;gap:11px;padding:10px 12px 10px 10px;border-radius:18px;background:#fff;text-align:left;box-shadow:0 1px 0 rgba(160,120,90,.08)}
.tp:active{transform:scale(.99)}
.tp .ph{position:relative;flex:none;width:52px;height:52px;border-radius:14px;overflow:hidden;background:var(--tl)}
.tp .ph img{width:100%;height:100%;object-fit:cover;display:block}
.tp .ph b{position:absolute;inset:0;display:grid;place-items:center;font-size:26px;font-weight:900;color:var(--ti);font-family:"STKaiti","KaiTi","Kaiti SC",serif}
.tp .ph img+b{display:none}
.tp .tx{flex:1;min-width:0}
.tp .nm{font-size:14.5px;font-weight:700;line-height:1.4;color:var(--ink);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.tp .mt{display:flex;align-items:center;gap:6px;margin-top:4px;font-size:11.5px;color:var(--muted)}
.tp .mt .k{padding:0 6px;border-radius:6px;font-weight:700;color:var(--ti);background:var(--tl);line-height:18px}
.tp .mt .hot{color:#E86A3A;font-weight:700}
.tp .go{flex:none;width:28px;height:28px;border-radius:50%;display:grid;place-items:center;background:#F7EFE6;color:#B49C8C}
.more{display:block;width:100%;margin-top:8px;height:38px;border-radius:14px;background:transparent;border:1.5px dashed #E2CFBE;color:#9C8172;font-size:13px;font-weight:700}
/* 笔记:长椅上的分享 */
.nts{display:flex;flex-direction:column;gap:12px}
.nt{display:flex;gap:12px;padding:12px;border-radius:20px;background:#fff;text-align:left;box-shadow:0 1px 0 rgba(160,120,90,.08)}
.nt:active{transform:scale(.99)}
.nt .pic{flex:none;width:104px;height:138px;border-radius:14px;overflow:hidden;background:#EFE4D8;position:relative}
.nt .pic img{width:100%;height:100%;object-fit:cover;display:block}
.nt .cv{flex:none;width:104px;height:138px;border-radius:14px;position:relative;overflow:hidden;padding:12px 10px;background:linear-gradient(160deg,var(--c1),var(--c2));color:var(--ti);display:flex;flex-direction:column;justify-content:flex-end}
.nt .cv b{position:relative;z-index:1;font-size:15px;font-weight:900;line-height:1.3}
.nt .cv small{position:relative;z-index:1;font-size:11px;margin-top:4px;opacity:.8;line-height:1.35}
.nt .cv .wm{position:absolute;right:-6px;top:-10px;font-size:76px;font-weight:900;line-height:1;color:#fff;opacity:.55;font-family:"STKaiti","KaiTi","Kaiti SC",serif}
.nt .bd{flex:1;min-width:0;display:flex;flex-direction:column}
.nt .tg{align-self:flex-start;max-width:100%;font-size:11.5px;font-weight:700;color:var(--ti);background:var(--tl);padding:0 7px;border-radius:7px;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nt h4{margin:6px 0 0;font-size:15px;font-weight:800;line-height:1.42;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.nt p{margin:4px 0 0;font-size:13px;color:var(--ink-2);line-height:1.55;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.nt .ft{margin-top:auto;padding-top:6px;display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);min-width:0}
.nt .ft i{width:22px;height:22px;border-radius:50%;flex:none;background:#EADBCB center/cover}
.nt .ft .au{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#7A6A61}
.nt .ft .st{flex:none}
.nt .ft .lk{margin-left:auto;flex:none;display:flex;align-items:center;gap:3px}
/* 投稿明信片 */
.card-mail{position:relative;display:flex;align-items:center;gap:12px;width:100%;padding:14px 14px 14px 16px;border-radius:20px;text-align:left;overflow:hidden;
background:repeating-linear-gradient(-45deg,#F4593C 0 8px,#fff 8px 16px,#3A72B8 16px 24px,#fff 24px 32px);}
.card-mail::before{content:"";position:absolute;inset:5px;border-radius:16px;background:#FFFBF5}
.card-mail>*{position:relative}
.card-mail .tx{flex:1;min-width:0}
.card-mail .tx b{display:block;font-size:15px;font-weight:800}
.card-mail .tx span{display:block;margin-top:2px;font-size:12.5px;color:var(--ink-2)}
.card-mail .tx span em{font-style:normal;font-weight:800;color:var(--brand)}
.card-mail .stamp{flex:none;width:62px;height:70px;padding:4px;background:#fff;border-radius:4px;border:2px dashed #F3B9A6;transform:rotate(4deg);box-shadow:0 3px 8px -4px rgba(0,0,0,.2)}
.card-mail .stamp div{height:100%;border-radius:2px;background:linear-gradient(160deg,#FFB08F,#F4593C);color:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;line-height:1.15}
.card-mail .stamp b{font-size:17px;font-weight:900}
.card-mail .stamp small{font-size:11px;font-weight:700;opacity:.95}
.foot{padding:22px 16px calc(28px + env(safe-area-inset-bottom));text-align:center;font-size:11px;color:#C1AFA2}
</style>
</head>
<body>
<div id="sc">
<div class="top" id="top">
<div class="nav">
<button class="bk" id="back" aria-label="返回"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#2E2521" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5l-7 7 7 7"/></svg></button>
<h1>孕妈广场</h1>
<button class="mine" id="mine">我的投稿</button>
</div>
<div class="ver">效果稿 V2 · 广场地图</div>
</div>
<div class="hello">
<div>
<h2><span id="tod">午后</span>的小广场,<br>有 <em id="nowN">0</em> 位妈妈在聊</h2>
<p>点亭子、长椅或大树,去那个角落坐坐</p>
</div>
<div class="wx"><b id="clock">14:30</b><span id="wxs">晴 · 微风</span></div>
</div>
<div class="mapw">
<div class="map f-all" id="map">
<svg class="ground" viewBox="0 0 351 440" preserveAspectRatio="none" aria-hidden="true">
<defs>
<pattern id="tile" width="22" height="22" patternUnits="userSpaceOnUse">
<rect width="22" height="22" fill="#F4E8D8"/>
<path d="M0 .5H22M.5 0V22" stroke="#EADAC6" stroke-width="1"/>
<rect x="3" y="3" width="2" height="2" rx="1" fill="#EFE0CD"/>
</pattern>
<pattern id="grass" width="14" height="14" patternUnits="userSpaceOnUse">
<rect width="14" height="14" fill="#CFE3BD"/>
<path d="M3 5l1-2 1 2M10 11l1-2 1 2" stroke="#B9D6A3" stroke-width="1" fill="none" stroke-linecap="round"/>
</pattern>
<pattern id="deck" width="351" height="9" patternUnits="userSpaceOnUse">
<rect width="351" height="9" fill="#EBD3B5"/>
<path d="M0 8.5H351" stroke="#DDBF9C" stroke-width="1"/>
</pattern>
<radialGradient id="water" cx=".42" cy=".38" r=".7">
<stop offset="0" stop-color="#E4F4F4"/><stop offset=".6" stop-color="#BFE1E3"/><stop offset="1" stop-color="#9FCFD3"/>
</radialGradient>
<linearGradient id="roof" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#FAC6CE"/><stop offset="1" stop-color="#EA8C9D"/>
</linearGradient>
<radialGradient id="glow"><stop offset="0" stop-color="#FFF4C8" stop-opacity=".95"/><stop offset="1" stop-color="#FFE59A" stop-opacity="0"/></radialGradient>
<filter id="sh" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="3" dy="5" stdDeviation="3.5" flood-color="#6B4526" flood-opacity=".22"/></filter>
<filter id="sh2" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="2" dy="3" stdDeviation="2" flood-color="#6B4526" flood-opacity=".2"/></filter>
</defs>
<!-- 地砖 -->
<rect width="351" height="440" fill="url(#tile)"/>
<!-- 草坪 -->
<path d="M-10 -10H205C214 30 196 60 170 74C150 88 160 130 150 160C138 196 96 214 56 206C24 200 4 214 -10 230Z" fill="url(#grass)" stroke="#B2CF9C" stroke-width="2"/>
<path d="M-10 268C30 262 70 270 110 280C160 292 190 320 198 360C204 396 196 420 210 450H-10Z" fill="url(#grass)" stroke="#B2CF9C" stroke-width="2"/>
<path d="M262 -10H361V120C340 128 318 118 300 104C282 90 268 60 262 30Z" fill="url(#grass)" stroke="#B2CF9C" stroke-width="2"/>
<path d="M268 330C292 316 330 318 361 326V450H250C244 410 248 352 268 330Z" fill="url(#grass)" stroke="#B2CF9C" stroke-width="2"/>
<!-- 小路 -->
<g fill="none" stroke-linecap="round">
<path d="M176 222C140 190 116 160 92 112M176 222C220 214 260 206 300 200M176 222C150 262 128 300 106 346M176 222C210 270 240 320 300 350" stroke="#E2CCB0" stroke-width="30"/>
<path d="M176 222C140 190 116 160 92 112M176 222C220 214 260 206 300 200M176 222C150 262 128 300 106 346M176 222C210 270 240 320 300 350" stroke="#F6EBDC" stroke-width="25"/>
<path d="M176 222C140 190 116 160 92 112M176 222C150 262 128 300 106 346M176 222C210 270 240 320 300 350" stroke="#EAD8C2" stroke-width="2" stroke-dasharray="1 9"/>
</g>
<!-- 花坛小点 -->
<g>
<circle cx="30" cy="40" r="11" fill="#B6D49F"/><circle cx="26" cy="37" r="2.4" fill="#F7A9B7"/><circle cx="34" cy="42" r="2.4" fill="#FFD27A"/><circle cx="29" cy="45" r="2" fill="#fff"/>
<circle cx="190" cy="30" r="9" fill="#B6D49F"/><circle cx="187" cy="28" r="2.2" fill="#FFD27A"/><circle cx="193" cy="33" r="2.2" fill="#F7A9B7"/>
<circle cx="330" cy="400" r="12" fill="#A9CC92"/><circle cx="326" cy="396" r="2.5" fill="#F7A9B7"/><circle cx="335" cy="402" r="2.5" fill="#fff"/><circle cx="329" cy="406" r="2.2" fill="#FFD27A"/>
<circle cx="24" cy="420" r="10" fill="#A9CC92"/><circle cx="21" cy="417" r="2.2" fill="#fff"/><circle cx="27" cy="422" r="2.2" fill="#F7A9B7"/>
<circle cx="336" cy="30" r="13" fill="#A9CC92" filter="url(#sh2)"/><circle cx="332" cy="26" r="5" fill="#BEDCA8"/>
<circle cx="226" cy="410" r="10" fill="#A9CC92" filter="url(#sh2)"/><circle cx="223" cy="407" r="4" fill="#BEDCA8"/>
</g>
<!-- 中心喷泉 -->
<g>
<circle cx="176" cy="222" r="62" fill="#F1E2CF" stroke="#E3CDB2" stroke-width="2"/>
<circle cx="176" cy="222" r="52" fill="none" stroke="#E9D6BF" stroke-width="12" stroke-dasharray="9 3"/>
<circle cx="176" cy="222" r="38" fill="#EBDAC4" filter="url(#sh2)"/>
<circle cx="176" cy="222" r="33" fill="url(#water)"/>
<circle class="rip" cx="176" cy="222" r="28" fill="none" stroke="#fff" stroke-width="1.4" opacity=".8"/>
<circle class="rip r2" cx="176" cy="222" r="28" fill="none" stroke="#fff" stroke-width="1.4" opacity=".8"/>
<circle class="rip r3" cx="176" cy="222" r="28" fill="none" stroke="#fff" stroke-width="1.4" opacity=".8"/>
<circle cx="176" cy="222" r="10" fill="#F2E5D4" stroke="#E0CBB0" stroke-width="1.5"/>
<circle cx="176" cy="222" r="4.5" fill="#CDEBEE"/>
<circle cx="174.5" cy="220.5" r="1.6" fill="#fff"/>
</g>
<!-- 鸽子 -->
<g class="bird"><ellipse cx="236" cy="252" rx="5" ry="3.4" fill="#C9C3C0"/><circle cx="240.5" cy="250.6" r="2" fill="#A9A19D"/><path d="M242.4 250.6l1.6.4-1.6.6z" fill="#E59A5B"/></g>
<g class="bird" style="animation-delay:1.3s"><ellipse cx="226" cy="262" rx="4.6" ry="3.2" fill="#D6D0CC"/><circle cx="222" cy="260.6" r="1.9" fill="#B2AAA6"/><path d="M220.2 260.6l-1.5.4 1.5.6z" fill="#E59A5B"/></g>
<!-- 家庭婚姻亭(八角亭俯视) -->
<g>
<polygon points="92,58 130,74 146,112 130,150 92,166 54,150 38,112 54,74" fill="#EEDCCB" stroke="#E2CBB3" stroke-width="2" transform="translate(0 2)"/>
<g filter="url(#sh)">
<polygon points="92,66 124,79 137,112 124,145 92,158 60,145 47,112 60,79" fill="url(#roof)"/>
</g>
<g stroke="#DC7487" stroke-width="1.6" opacity=".8">
<path d="M92 112L92 66M92 112L124 79M92 112L137 112M92 112L124 145M92 112L92 158M92 112L60 145M92 112L47 112M92 112L60 79"/>
</g>
<polygon points="92,66 124,79 137,112 124,145 92,158 60,145 47,112 60,79" fill="none" stroke="#FCE3E7" stroke-width="2.5" stroke-linejoin="round"/>
<polygon points="92,90 107.5,96.5 114,112 107.5,127.5 92,134 76.5,127.5 70,112 76.5,96.5" fill="#F8B4C0" opacity=".55"/>
<circle cx="92" cy="112" r="5" fill="#F5D07A" stroke="#E2A94A" stroke-width="1.5"/>
<g fill="#F5D07A"><circle cx="92" cy="66" r="2.2"/><circle cx="124" cy="79" r="2.2"/><circle cx="137" cy="112" r="2.2"/><circle cx="124" cy="145" r="2.2"/><circle cx="92" cy="158" r="2.2"/><circle cx="60" cy="145" r="2.2"/><circle cx="47" cy="112" r="2.2"/><circle cx="60" cy="79" r="2.2"/></g>
</g>
<!-- 职场长椅:木平台 + 遮阳伞 + 两张长椅 + 路灯 -->
<g>
<rect x="246" y="150" width="96" height="106" rx="10" fill="url(#deck)" stroke="#D8B994" stroke-width="2"/>
<!-- 长椅 1(上) -->
<g filter="url(#sh2)">
<rect x="258" y="158" width="72" height="16" rx="3" fill="#C99A6E"/>
<rect x="258" y="158" width="72" height="5" rx="2" fill="#9E7150"/>
<path d="M258 167.5H330M258 171.5H330" stroke="#B5875E" stroke-width="1"/>
</g>
<!-- 长椅 2(下) -->
<g filter="url(#sh2)">
<rect x="258" y="232" width="72" height="16" rx="3" fill="#C99A6E"/>
<rect x="258" y="243" width="72" height="5" rx="2" fill="#9E7150"/>
<path d="M258 236.5H330M258 240.5H330" stroke="#B5875E" stroke-width="1"/>
</g>
<!-- 遮阳伞 -->
<g filter="url(#sh)">
<circle cx="294" cy="203" r="26" fill="#fff"/>
<path d="M294 203L294 177A26 26 0 0 1 312.4 184.6ZM294 203L320 203A26 26 0 0 1 312.4 221.4ZM294 203L294 229A26 26 0 0 1 275.6 221.4ZM294 203L268 203A26 26 0 0 1 275.6 184.6Z" fill="#8EB1DD"/>
<circle cx="294" cy="203" r="26" fill="none" stroke="#6E95C8" stroke-width="1.5"/>
<circle cx="294" cy="203" r="3" fill="#3A72B8"/>
</g>
<!-- 路灯 -->
<circle cx="338" cy="148" r="16" fill="url(#glow)"/>
<circle cx="338" cy="148" r="4.5" fill="#FFF6D8" stroke="#C9B48A" stroke-width="1.5"/>
<!-- 盆栽 -->
<circle cx="252" cy="262" r="8" fill="#B88B66" filter="url(#sh2)"/><circle cx="252" cy="262" r="6.5" fill="#8FC08F"/><circle cx="250" cy="260" r="2.5" fill="#A9D3A3"/>
</g>
<!-- 经验树下:环形长椅 + 大树 -->
<g>
<ellipse cx="112" cy="362" rx="66" ry="60" fill="#5D7F57" opacity=".14"/>
<circle cx="104" cy="352" r="55" fill="none" stroke="#C69C73" stroke-width="9" stroke-dasharray="7 2"/>
<circle cx="104" cy="352" r="59.5" fill="none" stroke="#A97E58" stroke-width="1.2"/>
<g class="leaf" filter="url(#sh)">
<circle cx="104" cy="352" r="44" fill="#7FB394"/>
<circle cx="80" cy="336" r="22" fill="#8CC0A0"/>
<circle cx="124" cy="334" r="20" fill="#8CC0A0"/>
<circle cx="118" cy="374" r="22" fill="#78AC8D"/>
<circle cx="84" cy="372" r="18" fill="#86BA9A"/>
<circle cx="98" cy="344" r="18" fill="#9DCDAF"/>
<circle cx="90" cy="336" r="8" fill="#B4DCC2"/>
<circle cx="120" cy="330" r="6" fill="#B4DCC2"/>
<circle cx="112" cy="366" r="5" fill="#A7D3B6"/>
</g>
<!-- 小灌木 -->
<circle cx="196" cy="326" r="10" fill="#9BC48C" filter="url(#sh2)"/><circle cx="193" cy="323" r="4" fill="#B5D8A6"/>
</g>
<!-- 路灯们 -->
<circle cx="140" cy="178" r="13" fill="url(#glow)"/><circle cx="140" cy="178" r="3.8" fill="#FFF6D8" stroke="#C9B48A" stroke-width="1.4"/>
<circle cx="222" cy="300" r="13" fill="url(#glow)"/><circle cx="222" cy="300" r="3.8" fill="#FFF6D8" stroke="#C9B48A" stroke-width="1.4"/>
</svg>
<!-- 热区 -->
<button class="zone z-family" data-cat="family" style="--zc:var(--fam);left:26.2%;top:25.5%;width:30%;aspect-ratio:1" aria-label="家庭婚姻亭"><i class="halo"></i></button>
<button class="zone z-work" data-cat="work" style="--zc:var(--work);left:83.8%;top:46%;width:33%;aspect-ratio:1" aria-label="职场长椅"><i class="halo"></i></button>
<button class="zone z-baby" data-cat="baby" style="--zc:var(--baby);left:29.6%;top:80%;width:36%;aspect-ratio:1" aria-label="经验树下"><i class="halo"></i></button>
<button class="zone z-all" data-cat="" style="left:50.1%;top:50.5%;width:20%;aspect-ratio:1" aria-label="全部"></button>
<!-- 招牌 -->
<div class="sign s-family" style="--zc:var(--fam);left:26.2%;top:25.5%"><b>家庭婚姻亭</b><small id="cnt-family"></small></div>
<div class="sign s-work" style="--zc:var(--work);left:83.8%;top:37.6%"><b>职场长椅</b><small id="cnt-work"></small></div>
<div class="sign s-baby" style="--zc:var(--baby);left:29.6%;top:80%"><b>经验树下</b><small id="cnt-baby"></small></div>
<div class="sign s-all" style="--zc:var(--brand);left:50.1%;top:50.5%"><b style="font-size:11.5px;padding:2px 8px">全部</b></div>
<div id="moms"></div>
<!-- 投稿信箱 -->
<button class="box" id="mailbox" style="left:80.5%;top:12.5%" aria-label="投稿信箱">
<span class="mb">
<svg viewBox="0 0 46 62">
<ellipse cx="23" cy="59" rx="16" ry="3" fill="rgba(90,50,20,.22)"/>
<rect x="20" y="38" width="6" height="21" rx="1.5" fill="#8C5B3E"/>
<path d="M6 18C6 9 13 4 23 4S40 9 40 18V40H6Z" fill="#F4593C"/>
<path d="M6 18C6 9 13 4 23 4S40 9 40 18V22H6Z" fill="#FF7A58"/>
<rect x="12" y="25" width="22" height="3.5" rx="1.75" fill="#B9361F"/>
<rect x="15" y="20.5" width="16" height="9" rx="1" fill="#FFF7EA" transform="rotate(-6 23 25)"/>
<path d="M15.5 21.2L23 26l7.5-5.8" stroke="#F0B9A6" stroke-width="1" fill="none" transform="rotate(-6 23 25)"/>
<rect x="12" y="25" width="22" height="2" fill="#B9361F" opacity=".0"/>
<text x="23" y="37" text-anchor="middle" font-size="7" font-weight="800" fill="#fff" font-family="sans-serif">投稿</text>
<rect x="40" y="10" width="2.5" height="18" rx="1" fill="#C9472C"/>
<path d="M42.5 10H50V16H42.5Z" fill="#FFD25E"/>
</svg>
</span>
<span class="tag">投稿信箱<small>选中得 ¥30+500兜豆</small></span>
</button>
</div>
</div>
<div class="posts" id="posts"></div>
<div class="sec">
<div class="sec-h"><h3 id="tpH"></h3><span class="live"><span class="stack" id="tpStack"></span></span></div>
<div class="tps" id="tps"></div>
<button class="more hide" id="more"></button>
</div>
<div class="sec">
<div class="sec-h"><h3 id="ntH"></h3><span class="live"><span class="dot"></span><span id="ntLive"></span></span></div>
<div class="nts" id="nts"></div>
</div>
<div class="foot">示例占位内容 · 数字仅作演示</div>
</div>
<script src="../../guangchang/topics.js"></script>
<script src="../../guangchang/data.js"></script>
<script>
(function () {
var $ = function (s) { return document.querySelector(s); };
var T = window.GC_TOPICS || [], D = window.GC_DATA || {};
var H = location.hash;
var CAT = {
family: { name: '家庭婚姻亭', short: '家庭婚姻', col: '#E0566F', tl: '#FFEDF1', ti: '#C23A55' },
work: { name: '职场长椅', short: '职场', col: '#3A72B8', tl: '#E9F1FB', ti: '#2F64A8' },
baby: { name: '经验树下', short: '经验', col: '#2E8A7C', tl: '#E3F3EF', ti: '#21705F' }
};
var ORDER = ['family', 'work', 'baby'];
var cur = '';
var esc = function (s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); };
var hs = function (s) { var x = 7; for (var i = 0; i < s.length; i++) x = (x * 31 + s.charCodeAt(i)) | 0; return Math.abs(x); };
var POOL = [];
for (var i = 1; i <= 22; i++) POOL.push('m' + (i < 10 ? '0' : '') + i);
for (i = 1; i <= 14; i++) POOL.push('p' + (i < 10 ? '0' : '') + i);
var av = function (name) { return '../../assets/img/mom/' + POOL[hs(name || '妈妈') % POOL.length] + '.jpg'; };
var fmt = function (n) { return n >= 10000 ? (n / 10000).toFixed(1).replace(/\.0$/, '') + '万' : String(n).replace(/\B(?=(\d{3})+$)/g, ','); };
var go = function (q) { location.href = '../../guangchang/' + q + H; };
/* 话题按分类 + 笔记(带 话题id-序号) */
var BY = { family: [], work: [], baby: [] };
T.forEach(function (t) { if (BY[t.cat]) BY[t.cat].push(t); });
var NOTES = { family: [], work: [], baby: [] };
T.forEach(function (t) {
var d = D[t.id]; if (!d || !BY[t.cat]) return;
d.notes.forEach(function (n, k) { NOTES[t.cat].push({ n: n, t: t, id: t.id + '-' + (k + 1), k: k }); });
});
/* 每类:带照片的排前面一些,并按 序号 轮流穿插不同话题 */
ORDER.forEach(function (c) {
NOTES[c].sort(function (a, b) { return (a.k - b.k) || ((b.n.photo ? 1 : 0) - (a.n.photo ? 1 : 0)) || (hs(a.id) % 97 - hs(b.id) % 97); });
});
var talkOf = function (c) { return BY[c].reduce(function (s, t) { return s + t.talk; }, 0); };
/* 统计 */
var all = 0;
ORDER.forEach(function (c) { var n = talkOf(c); all += n; $('#cnt-' + c).textContent = fmt(n) + ' 人在聊'; });
$('#nowN').textContent = fmt(all);
var d0 = new Date(Date.now() + (new Date().getTimezoneOffset() + 480) * 6e4), hh = d0.getHours(); /* 一律按北京时间 */
$('#clock').textContent = (hh < 10 ? '0' : '') + hh + ':' + (d0.getMinutes() < 10 ? '0' : '') + d0.getMinutes();
$('#tod').textContent = hh < 5 ? '深夜' : hh < 9 ? '清晨' : hh < 12 ? '上午' : hh < 14 ? '中午' : hh < 18 ? '午后' : hh < 20 ? '傍晚' : '夜里';
if (hh >= 18 || hh < 5) $('#wxs').textContent = '晚风 · 微凉';
/* ---------- 地图上的妈妈和气泡 ---------- */
/* 坐标:map 宽 351 高 440 的百分比 */
var P = function (x, y) { return 'left:' + (x / 351 * 100).toFixed(2) + '%;top:' + (y / 440 * 100).toFixed(2) + '%'; };
var SPOTS = {
family: { moms: [[42, 176, 0], [80, 186, 1], [150, 148, 0], [30, 70, 1]], bub: { x: 20, y: 54, cls: 'tl', w: 150 } },
work: { moms: [[254, 202, 1], [334, 212, 0], [300, 244, 0]], bub: { x: 194, y: 262, cls: 'br', w: 150 } },
baby: { moms: [[192, 380, 0], [56, 408, 1], [150, 410, 1]], bub: { x: 178, y: 360, cls: 'tl', w: 150 } }
};
var BUBIX = { family: 0, work: 0, baby: 0 };
var momsHTML = '';
ORDER.forEach(function (c) {
var s = SPOTS[c], ns = NOTES[c];
s.moms.forEach(function (m, j) {
var a = ns[(j * 5 + 2) % ns.length].n.author;
momsHTML += '<span class="mom' + (m[2] ? ' sm' : '') + ' m-' + c + '" style="' + P(m[0], m[1]) + '"><i style="background-image:url(' + av(a) + ');animation-delay:' + (-(j * 0.9 + ORDER.indexOf(c) * 0.5)).toFixed(1) + 's"></i></span>';
});
var b = s.bub;
/* 气泡锚点:tl = 尾巴在左下,框在锚点右上方;tr = 尾巴在右下 */
var st = 'left:' + (b.x / 351 * 100).toFixed(2) + '%;' + (b.cls === 'br' ? 'top:' + (b.y / 440 * 100).toFixed(2) + '%' : 'bottom:' + ((440 - b.y) / 440 * 100).toFixed(2) + '%');
momsHTML += '<div class="bub ' + b.cls + ' b-' + c + '" style="--zc:' + CAT[c].col + ';' + st + ';width:' + b.w + 'px"><span></span></div>';
});
$('#moms').innerHTML = momsHTML;
function setBub(c) {
var list = BY[c], t = list[BUBIX[c] % list.length];
var el = $('.b-' + c + ' span');
el.innerHTML = '<em>#</em>' + esc(t.name);
}
ORDER.forEach(setBub);
var tick = 0;
setInterval(function () {
var c = ORDER[tick++ % 3];
if (cur && c !== cur) c = cur;
var b = $('.b-' + c); b.classList.add('out');
setTimeout(function () { BUBIX[c]++; setBub(c); b.classList.remove('out'); }, 320);
}, 2200);
/* ---------- 路牌 ---------- */
$('#posts').innerHTML = [['', '全部', '#F4593C']].concat(ORDER.map(function (c) { return [c, CAT[c].short, CAT[c].col]; })).map(function (x) {
return '<button data-cat="' + x[0] + '" style="--zc:' + x[2] + '"><i></i>' + x[1] + '</button>';
}).join('');
/* ---------- 列表 ---------- */
var expanded = false;
function topicRow(t) {
var c = CAT[t.cat], d = D[t.id];
var who = d ? d.notes.slice(0, 3).map(function (n) { return '<i style="background-image:url(' + av(n.author) + ')"></i>'; }).join('') : '';
return '<button class="tp" data-t="' + t.id + '" style="--tl:' + c.tl + ';--ti:' + c.ti + '">' +
'<span class="ph">' + (t.ph ? '<img loading="lazy" src="../../' + t.ph + '" alt="">' : '') + '<b>' + esc(t.g) + '</b></span>' +
'<span class="tx"><span class="nm">' + esc(t.name) + '</span>' +
'<span class="mt">' + (cur ? '' : '<span class="k">' + c.short + '</span>') + (t.hot ? '<span class="hot">热聊</span>' : '') +
'<span class="stack">' + who + '</span><span>' + fmt(t.talk) + ' 人在聊</span></span></span>' +
'<span class="go"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"><path d="M9 5l7 7-7 7"/></svg></span></button>';
}
function noteCard(o) {
var n = o.n, t = o.t, c = CAT[t.cat];
var vis = n.photo ? '<span class="pic"><img loading="lazy" src="../../guangchang/' + n.photo + '" alt=""></span>'
: '<span class="cv" style="--c1:' + t.c[0] + ';--c2:' + t.c[1] + '"><span class="wm">' + esc(t.g) + '</span><b>' + esc(n.cover) + '</b><small>' + esc(n.coverSub || '') + '</small></span>';
return '<button class="nt" data-t="' + t.id + '" data-n="' + o.id + '" style="--tl:' + c.tl + ';--ti:' + c.ti + '">' + vis +
'<span class="bd"><span class="tg"># ' + esc(t.name) + '</span><h4>' + esc(n.title) + '</h4><p>' + esc((n.body || '').replace(/\n/g, ' ')) + '</p>' +
'<span class="ft"><i style="background-image:url(' + av(n.author) + ')"></i><span class="au">' + esc(n.author) + '</span><span class="st">· ' + esc(n.stage) + '</span>' +
'<span class="lk"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M12 20s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.6-7 10-7 10z"/></svg>' + fmt(n.likes) + '</span></span></span></button>';
}
var MAIL = '<button class="card-mail" id="mailcard"><span class="tx"><b>给广场写一封信</b><span>你的故事被选中,送 <em>¥30 现金 + 500 兜豆</em></span></span><span class="stamp"><div><b>¥30</b><small>+500兜豆</small></div></span></button>';
function render() {
var map = $('#map');
map.className = 'map f-' + (cur || 'all');
ORDER.forEach(function (c) {
var dim = cur && c !== cur;
document.querySelectorAll('.m-' + c + ',.b-' + c).forEach(function (el) { el.classList.toggle('dim', !!dim); });
});
document.querySelectorAll('#posts button').forEach(function (b) { b.classList.toggle('on', b.dataset.cat === cur); });
var col = cur ? CAT[cur].col : '#F4593C';
document.documentElement.style.setProperty('--zc', col);
var tops;
if (cur) tops = BY[cur].slice().sort(function (a, b) { return b.hot - a.hot || b.talk - a.talk; });
else { tops = []; for (var k = 0; k < 10; k++) ORDER.forEach(function (c) { var l = BY[c].slice().sort(function (a, b) { return b.hot - a.hot || b.talk - a.talk; }); if (l[k]) tops.push(l[k]); }); }
var lim = expanded ? tops.length : 4;
$('#tpH').innerHTML = cur ? '此刻在<em>' + CAT[cur].name + '</em>聊' : '此刻<em>广场上</em>在聊';
var tl = (cur ? BY[cur] : T).slice(0, 4);
$('#tpStack').innerHTML = tl.map(function (t) { return '<i style="background-image:url(' + av(t.id + t.name) + ')"></i>'; }).join('');
$('#tps').innerHTML = tops.slice(0, lim).map(topicRow).join('');
var mb = $('#more');
mb.classList.toggle('hide', tops.length <= 4);
mb.textContent = expanded ? '收起' : '这个角落还有 ' + (tops.length - 4) + ' 个话题';
var ns;
if (cur) ns = NOTES[cur].slice(0, 18);
else { ns = []; for (k = 0; ns.length < 21; k++) { var any = false; ORDER.forEach(function (c) { if (NOTES[c][k]) { ns.push(NOTES[c][k]); any = true; } }); if (!any) break; } }
$('#ntH').innerHTML = cur ? '坐在' + CAT[cur].short + '角落的分享' : '大家刚写下的';
$('#ntLive').textContent = fmt(cur ? Math.round(talkOf(cur) / 37) : Math.round(all / 37)) + ' 人正在看';
var h = ns.map(noteCard);
h.splice(Math.min(3, h.length), 0, MAIL);
$('#nts').innerHTML = h.join('');
}
function setCat(c) {
if (c === cur) c = c ? '' : c;
cur = c; expanded = false; render();
if (cur) { BUBIX[cur]++; setBub(cur); }
}
document.addEventListener('click', function (e) {
var z = e.target.closest('[data-cat]');
if (z) { setCat(z.dataset.cat); return; }
var n = e.target.closest('[data-n]');
if (n) { go('?t=' + n.dataset.t + '&n=' + n.dataset.n); return; }
var t = e.target.closest('[data-t]');
if (t) { go('?t=' + t.dataset.t); return; }
if (e.target.closest('#more')) { expanded = !expanded; render(); return; }
if (e.target.closest('#mailbox,#mailcard')) { go(cur ? '?c=' + cur : ''); return; }
});
$('#mine').addEventListener('click', function () { go('?mine=1'); });
$('#back').addEventListener('click', function () { history.length > 1 ? history.back() : location.href = '../../' + location.hash; });
var sc = $('#sc');
sc.addEventListener('scroll', function () { $('#top').classList.toggle('on', sc.scrollTop > 4); }, { passive: true });
/* 禁止下拉回弹:往上找能朝该方向滚的容器,找不到才拦 */
var sx = 0, sy = 0;
document.addEventListener('touchstart', function (e) { if (e.touches.length !== 1) return; sx = e.touches[0].clientX; sy = e.touches[0].clientY; }, { passive: true });
document.addEventListener('touchmove', function (e) {
if (e.touches.length !== 1) { if (e.cancelable) e.preventDefault(); return; }
var dx = e.touches[0].clientX - sx, dy = e.touches[0].clientY - sy;
if (Math.abs(dy) <= Math.abs(dx)) return;
var el = e.target;
while (el && el !== document.body && el !== document.documentElement) {
if (el.nodeType === 1) {
var oy = getComputedStyle(el).overflowY;
if ((oy === 'auto' || oy === 'scroll') && el.scrollHeight > el.clientHeight + 1) {
if (dy > 0 && el.scrollTop > 0) return;
if (dy < 0 && el.scrollTop + el.clientHeight < el.scrollHeight - 1) return;
}
}
el = el.parentNode;
}
if (e.cancelable) e.preventDefault();
}, { passive: false });
render();
})();
</script>
</body>
</html>