342 lines
32 KiB
HTML
342 lines
32 KiB
HTML
{{define "layout"}}<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
||
<meta name="theme-color" content="#f4eedd">
|
||
<title>{{template "title" .}}</title>
|
||
<meta name="description" content="{{if .Desc}}{{.Desc}}{{else}}赛博要饭:行行好,赏口饭吃。用币安 Pay 投币施舍,留一句话上功德簿;不花钱也能丢钢镚;用 X 发一条推就能开自己的要饭站。{{end}}">
|
||
<meta property="og:title" content="{{template "title" .}}">
|
||
<meta property="og:description" content="{{if .Desc}}{{.Desc}}{{else}}行行好,赏口饭吃。投币上功德簿,丢钢镚也算爱。{{end}}">
|
||
<meta property="og:type" content="website">
|
||
{{if .OGImage}}<meta property="og:image" content="{{.OGImage}}">{{end}}
|
||
<meta name="twitter:card" content="summary">
|
||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E🥣%3C/text%3E%3C/svg%3E">
|
||
{{if .NoIndex}}<meta name="robots" content="noindex">{{end}}
|
||
<link rel="preload" href="/static/pixel.woff2" as="font" type="font/woff2" crossorigin>
|
||
<style>
|
||
@font-face{font-family:"Pixel";src:url(/static/pixel.woff2) format("woff2");font-display:swap}
|
||
:root{--ink:#1e1e2e;--paper:#f4eedd;--paper-2:#e9e1ca;--panel:#fffbf0;--panel-2:#fff3cc;--gold:#ffcc00;--gold-2:#e0a800;--red:#ff4b4b;--green:#3ec46d;--blue:#3d8bfd;--purple:#8e5cff;--muted:#4a4954;--muted-2:#6f6d66;--pf:"Pixel","PingFang SC","Noto Sans SC","Microsoft YaHei",sans-serif;--line:#d9d0b8;--frame:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='6' height='6' shape-rendering='crispEdges'%3E%3Cpath fill='%231e1e2e' d='M1 0h4v1H1zM0 1h6v1H0zM0 2h2v2H0zM4 2h2v2H4zM0 4h6v1H0zM1 5h4v1H1z'/%3E%3C/svg%3E")}
|
||
*{box-sizing:border-box}
|
||
html{-webkit-text-size-adjust:100%;overflow-x:hidden}
|
||
html,body{max-width:100%;overscroll-behavior-x:none}
|
||
@media(max-width:899px){body{overflow-x:hidden;position:relative}}
|
||
body{margin:0;color:var(--ink);background-color:var(--paper);background-image:linear-gradient(45deg,var(--paper-2) 25%,transparent 25%,transparent 75%,var(--paper-2) 75%),linear-gradient(45deg,var(--paper-2) 25%,transparent 25%,transparent 75%,var(--paper-2) 75%);background-size:16px 16px;background-position:0 0,8px 8px;font:15px/1.7 -apple-system,BlinkMacSystemFont,"PingFang SC","Noto Sans SC","Hiragino Sans GB","Microsoft YaHei","Helvetica Neue",Arial,sans-serif;min-height:100vh}
|
||
.pf,h1,h2,.brand,.ticker,.lv,.pname,.stat .v,.stat .k,.amt-btn,.btn,.tab,.amtv,.rank,.insert,.barlabel,.tag,.nav a,.name,.av,.section-title,.copy,.anchors a,.step::before,.big,.dialog,.me,.count,.card h2 .sub,.kv .k,.empty .ico{font-family:var(--pf)}
|
||
.pf12{font-size:12px}
|
||
a{color:var(--blue)}
|
||
.num{font-variant-numeric:tabular-nums}
|
||
.accent{color:var(--gold-2)}
|
||
.page{max-width:1080px;margin:0 auto;padding:0 16px 96px}
|
||
@media(min-width:900px){.page{padding-bottom:40px}}
|
||
.px{border:4px solid transparent;border-image:var(--frame) 2 / 4px stretch;image-rendering:pixelated;background-clip:padding-box}
|
||
.nav{display:flex;align-items:center;gap:6px;height:64px}
|
||
.sfx{background:none;border:0;font-size:18px;line-height:1;padding:8px 6px;cursor:pointer;min-width:36px;min-height:36px;opacity:.85;flex:none}.sfx.off{opacity:.45}
|
||
.sfx.idle{animation:sfxnudge 1.2s ease-in-out infinite}@keyframes sfxnudge{0%,100%{transform:scale(1)}50%{transform:scale(1.18)}}@media(prefers-reduced-motion:reduce){.sfx.idle{animation:none}}
|
||
.nav>*{flex:none}
|
||
@media(max-width:430px){.nav{gap:4px}.nav .brand{font-size:22px;margin-right:2px}.sfx{min-width:28px;padding:6px 2px;font-size:16px}.nav a.link{padding:8px 5px;font-size:15px}.nav a.pill{padding:6px 10px;font-size:15px}
|
||
.nav a.navrank span{display:none}.nav a.navrank::before{content:"🏆";font-size:16px}}
|
||
.brand{display:flex;align-items:center;gap:8px;font-size:24px;line-height:1;color:var(--ink);text-decoration:none;white-space:nowrap;margin-right:6px}
|
||
.brand .px-coin{width:28px;height:28px;flex:none}
|
||
.nav .sp{flex:1}
|
||
.nav a.link{color:var(--ink);text-decoration:none;font-size:16px;padding:8px 8px;white-space:nowrap}
|
||
.nav a.link:hover{background:var(--panel-2)}
|
||
.nav a.pill{color:var(--ink);background:var(--gold);font-size:16px;padding:6px 12px;text-decoration:none;white-space:nowrap;box-shadow:3px 3px 0 var(--ink)}
|
||
.nav a.pill:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--ink)}
|
||
@media(max-width:420px){.hide-sm{display:none}.nav a.pill{font-size:12px;padding:6px 10px}.nav a.link{font-size:12px;padding:8px 5px}}
|
||
.ticker{overflow:hidden;contain:paint;touch-action:pan-y;background:var(--ink);color:var(--gold);font-size:12px;line-height:1.5;padding:6px 0;margin:0 0 16px;white-space:nowrap;box-shadow:3px 3px 0 rgba(30,30,46,.25)}
|
||
.ticker-in{display:inline-block;animation:tick 34s linear infinite}
|
||
.ticker-in span{padding:0 10px}
|
||
@keyframes tick{to{transform:translateX(-50%)}}
|
||
@media(prefers-reduced-motion:reduce){.ticker-in,.sprite .bowl,.sprite .eyes,.sprite .tear,.blink,.jump .sprite,.dialog .cursor,.flycoin{animation:none!important}}
|
||
.layout{display:grid;gap:18px}
|
||
@media(min-width:900px){.layout{grid-template-columns:400px minmax(0,1fr);gap:24px;align-items:start}.col-l{position:sticky;top:16px}.layout.cols2{grid-template-columns:1fr 1fr}}
|
||
.col-l,.col-r{display:grid;gap:18px;min-width:0}
|
||
.narrow{max-width:560px;margin:0 auto}
|
||
.card{background:var(--panel);padding:18px;box-shadow:4px 4px 0 var(--ink)}
|
||
.card h2{font-size:18px;margin:0 0 12px;display:flex;align-items:center;gap:8px;flex-wrap:wrap;line-height:1.3}
|
||
.card h2 .sub{color:var(--muted);font-size:12px}
|
||
h1{font-size:24px;margin:0 0 8px;line-height:1.3}
|
||
/* 角色卡 */
|
||
.char-top{display:flex;gap:16px;align-items:flex-start}
|
||
.sprite-wrap{flex:none;width:96px;display:grid;place-items:end center}
|
||
.sprite{width:96px;height:auto;image-rendering:pixelated}
|
||
@media(min-width:900px){.char-top .sprite-wrap,.char-top .sprite{width:120px}}
|
||
.sprite .bowl{animation:shake 1s steps(1) infinite}
|
||
@keyframes shake{0%,100%{transform:translateY(0)}50%{transform:translateY(-1px)}}
|
||
.sprite .eyes{animation:blink 4s steps(1) infinite}
|
||
@keyframes blink{0%,90%{opacity:1}91%,96%{opacity:0}97%,100%{opacity:1}}
|
||
.sprite .tear{animation:tear 2.4s steps(1) infinite}
|
||
@keyframes tear{0%{transform:translateY(0)}33%{transform:translateY(1px)}66%{transform:translateY(2px)}}
|
||
.jump .sprite{animation:jump .9s steps(1) infinite}
|
||
@keyframes jump{0%,100%{transform:translateY(0)}50%{transform:translateY(-8px)}}
|
||
.char-info{flex:1;min-width:0}
|
||
.lvrow{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}
|
||
.lv{display:inline-block;background:var(--ink);color:var(--gold);font-size:12px;line-height:1.6;padding:2px 8px}
|
||
.lv b{color:#fff;font-weight:normal;margin-left:6px}
|
||
.lv.gold{background:var(--gold);color:var(--ink);border:2px solid var(--ink);padding:0 8px}
|
||
.pname{font-size:24px;margin:0 0 8px;line-height:1.25;word-break:break-word}
|
||
.barlabel{display:flex;justify-content:space-between;align-items:baseline;font-size:12px;color:var(--muted);margin-top:8px;line-height:1.4}
|
||
.barlabel b{color:var(--ink);font-weight:normal;margin-left:4px}
|
||
.barlabel span{font-size:12px;color:var(--muted)}
|
||
.bar{position:relative;height:14px;border:3px solid var(--ink);background:#fff;margin:2px 0 0;box-shadow:2px 2px 0 var(--ink)}
|
||
.bar span{display:block;height:100%;background:var(--green);background-image:repeating-linear-gradient(90deg,transparent 0 6px,rgba(0,0,0,.14) 6px 8px);transition:width .6s steps(12)}
|
||
.bar.hp span{background-color:var(--red)}
|
||
.xpill{display:inline-flex;align-items:center;gap:6px;font-size:13px;font-weight:700;padding:3px 8px;border:3px solid var(--ink);background:#fff;color:var(--ink);text-decoration:none;box-shadow:2px 2px 0 var(--ink);margin-top:6px}
|
||
.dialog{position:relative;margin-top:16px;background:#fff;padding:10px 26px 10px 12px;font-size:16px;line-height:1.6;box-shadow:3px 3px 0 var(--ink);min-height:44px;word-break:break-word}
|
||
.dialog::before{content:"▶";position:absolute;left:-2px;top:-14px;background:var(--gold);padding:0 6px;font-size:10px;border:3px solid var(--ink)}
|
||
.dialog .cursor{position:absolute;right:8px;bottom:6px;font-size:10px;animation:blinkc .8s steps(1) infinite}
|
||
@keyframes blinkc{50%{opacity:0}}
|
||
.more{background:none;border:0;color:var(--blue);font-size:12px;cursor:pointer;padding:6px 0 0;font-family:inherit}
|
||
/* HUD */
|
||
.stats{display:grid;grid-template-columns:1fr 1fr;gap:12px}
|
||
.stat{background:var(--panel);padding:10px 12px;min-width:0;box-shadow:3px 3px 0 var(--ink)}
|
||
.stat.main{grid-column:1/-1;background:var(--gold);display:flex;align-items:center;gap:12px}
|
||
.stat .k{font-size:12px;color:var(--muted);line-height:1.6}
|
||
.stat.main .k{color:var(--ink)}
|
||
.stat .v{font-size:24px;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.2}
|
||
.stat.main .v{font-size:36px;line-height:1.1}
|
||
.stat .v small{font-size:12px;color:var(--muted);margin-left:5px}
|
||
.stat.main .v small{color:var(--ink)}
|
||
.stat.main .bowlv{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 14px;white-space:nowrap;overflow:visible}
|
||
.stat.main .bowlv>span:first-child{min-width:0;max-width:100%;overflow:hidden;text-overflow:ellipsis}
|
||
.stat.main .bowlcoins{font-size:22px;display:inline-flex;align-items:center;gap:5px}
|
||
.stat.main .bowlcoins .px-coin{width:18px;height:18px;flex:none}
|
||
.stat.main .bowlcoins small{margin-left:0}
|
||
.stat .px-bowl{width:48px;height:auto;flex:none}
|
||
/* 表单 */
|
||
label{display:block;font-size:13px;color:var(--ink);font-weight:600;margin:14px 0 6px}
|
||
form>label:first-child,.grid2>div>label:first-child{margin-top:0}
|
||
input,textarea,select{width:100%;padding:10px 12px;border:3px solid var(--ink);background:#fff;color:var(--ink);font-size:16px;font-family:inherit;line-height:1.4;border-radius:0;box-shadow:inset 3px 3px 0 var(--paper-2)}
|
||
input::placeholder,textarea::placeholder{color:#8f8a7c}
|
||
input:focus,textarea:focus,select:focus{outline:none;border-color:var(--blue);box-shadow:3px 3px 0 var(--blue)}
|
||
textarea{resize:vertical;min-height:70px}
|
||
.hint{font-size:13px;color:var(--muted);margin-top:6px;line-height:1.6}
|
||
.err{color:var(--red);font-size:13px;margin-top:10px}
|
||
.ok{color:var(--green);font-size:13px}
|
||
.insert{text-align:center;font-size:12px;letter-spacing:.1em;color:var(--red);margin:-4px 0 12px;line-height:1.6}
|
||
.blink{animation:blinkc 1s steps(1) infinite}
|
||
.amounts{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
|
||
.amt-btn{display:flex;align-items:center;justify-content:center;gap:5px;padding:10px 4px;border:3px solid var(--ink);background:#fff;color:var(--ink);font-size:16px;white-space:nowrap;cursor:pointer;font-family:inherit;min-height:46px;box-shadow:3px 3px 0 var(--ink)}
|
||
.amt-btn .px-coin{width:16px;height:16px}
|
||
.amt-btn.on{background:var(--gold);transform:translate(2px,2px);box-shadow:1px 1px 0 var(--ink)}
|
||
.count{float:right;font-size:12px;color:var(--muted-2)}
|
||
.btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:50px;border:4px solid transparent;border-image:var(--frame) 2 / 4px stretch;image-rendering:pixelated;background-clip:padding-box;padding:10px 16px;font-size:18px;cursor:pointer;background-color:var(--gold);color:var(--ink);text-decoration:none;box-shadow:4px 4px 0 var(--ink)}
|
||
.btn:active{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--ink)}
|
||
.btn.sec{background-color:#fff}
|
||
.btn.ghost{background-color:transparent;box-shadow:none;color:var(--muted)}
|
||
.btn.danger{background-color:#fff;color:var(--red)}
|
||
.btn.sm{display:inline-flex;width:auto;min-height:40px;padding:6px 12px;font-size:14px;box-shadow:3px 3px 0 var(--ink)}
|
||
.btns{display:flex;gap:12px;flex-wrap:wrap;margin-top:14px}
|
||
.btns .btn{flex:1 1 auto;white-space:nowrap}
|
||
/* Tab */
|
||
.tabs{display:grid;grid-template-columns:repeat(3,1fr);border:3px solid var(--ink);margin-bottom:14px;background:#fff;box-shadow:3px 3px 0 var(--ink)}
|
||
.tab{border:0;border-right:3px solid var(--ink);background:transparent;color:var(--muted);font-size:16px;padding:10px 4px;cursor:pointer;white-space:nowrap}
|
||
.tab:last-child{border-right:0}
|
||
.tab.on{background:var(--gold);color:var(--ink)}
|
||
.panel{display:none}.panel.on{display:block}
|
||
/* 榜单 / 功德簿 */
|
||
.list{list-style:none;margin:0;padding:0}
|
||
.item{display:flex;align-items:center;gap:10px;padding:10px 0;border-top:3px dotted var(--line)}
|
||
.item:first-child{border-top:0;padding-top:2px}
|
||
.av{width:36px;height:36px;flex:none;display:grid;place-items:center;font-size:16px;background:hsl(var(--h) 75% 86%);color:hsl(var(--h) 55% 28%);border:3px solid var(--ink);box-shadow:2px 2px 0 var(--ink)}
|
||
.av.sq{background:#fff;font-size:20px;color:var(--ink)}
|
||
.rank{width:30px;flex:none;text-align:center;font-size:16px;color:var(--muted)}
|
||
.rank.m{font-size:20px}
|
||
.body{flex:1;min-width:0}
|
||
.name{display:flex;align-items:center;gap:6px;min-width:0;font-size:16px}
|
||
.name>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||
.name a{color:inherit;text-decoration:none}
|
||
.sub{font-size:13px;color:var(--muted);margin-top:1px}
|
||
.amtv{white-space:nowrap;font-size:18px}
|
||
.feed .item{flex-wrap:wrap}
|
||
.bubble{flex-basis:100%;margin:8px 0 0 46px;background:#fff;border:3px solid var(--ink);padding:6px 10px;font-size:14px;line-height:1.6;word-break:break-word;position:relative;box-shadow:2px 2px 0 var(--ink)}
|
||
.bubble::before{content:"";position:absolute;left:-9px;top:8px;border:3px solid transparent;border-right-color:var(--ink);border-width:4px 6px 4px 0}
|
||
.bubble.blocked{color:var(--muted-2);letter-spacing:2px}
|
||
.time{font-size:12px;color:var(--muted);white-space:nowrap}
|
||
.me{font-size:10px;color:var(--ink);background:var(--gold);border:2px solid var(--ink);padding:0 5px;flex:none}
|
||
.empty{text-align:center;color:var(--muted);padding:24px 12px;font-size:14px}
|
||
.fold>summary{list-style:none;cursor:pointer;-webkit-tap-highlight-color:transparent}.fold>summary::-webkit-details-marker{display:none}
|
||
.fold>summary h2{margin:0;display:flex;align-items:center;gap:8px}.fold>summary .caret{margin-left:auto;font-size:18px;transition:transform .15s}.fold[open]>summary .caret{transform:rotate(90deg)}
|
||
.fold[open]>summary h2{margin-bottom:12px}
|
||
.pager{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:12px;font-family:var(--pf);font-size:14px}
|
||
.pager a,.pager span.cur,.pager span.dis{display:inline-flex;align-items:center;justify-content:center;min-width:36px;min-height:36px;padding:0 10px;border:3px solid var(--ink);background:#fff;color:var(--ink);text-decoration:none;box-shadow:2px 2px 0 var(--ink)}
|
||
.pager span.cur{background:var(--gold)}.pager span.dis{opacity:.4;box-shadow:none}
|
||
.empty .ico{font-size:32px;margin-bottom:6px}
|
||
.empty .sprite{width:72px}
|
||
.cta{text-align:center}
|
||
.cta p{color:var(--ink);margin:0 0 12px;font-size:14px}
|
||
.fab{position:fixed;left:16px;right:16px;bottom:calc(16px + env(safe-area-inset-bottom));z-index:20;display:none}
|
||
.fab.show{display:block}
|
||
@media(min-width:900px){.fab{display:none!important}}
|
||
.notice{background:var(--panel-2);border:3px solid var(--ink);padding:10px 12px;font-size:14px;line-height:1.6;box-shadow:3px 3px 0 var(--ink)}
|
||
.notice.ok{background:#dff7e8}
|
||
.notice.bad{background:#ffe1e1}
|
||
.code{background:#fff;border:2px solid var(--ink);padding:1px 6px;font-size:13px;word-break:break-all}
|
||
.copy{cursor:pointer;border:3px solid var(--ink);background:#fff;color:var(--ink);padding:6px 10px;min-height:36px;font-size:12px;flex:none;box-shadow:2px 2px 0 var(--ink)}
|
||
.kv{display:grid;grid-template-columns:auto 1fr;gap:10px 14px;font-size:14px;align-items:center}
|
||
.kv .k{color:var(--muted)}
|
||
.kv .v{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
||
.qr{display:block;margin:8px auto;background:#fff;padding:8px;width:240px;height:240px;border:3px solid var(--ink);box-shadow:3px 3px 0 var(--ink);image-rendering:pixelated}
|
||
.steps{counter-reset:s;display:grid;gap:18px}
|
||
.step{position:relative;padding-left:44px}
|
||
.step::before{counter-increment:s;content:counter(s);position:absolute;left:0;top:-2px;width:30px;height:30px;background:var(--gold);color:var(--ink);border:3px solid var(--ink);font-size:14px;display:grid;place-items:center;box-shadow:2px 2px 0 var(--ink)}
|
||
.step h2{margin-bottom:8px}
|
||
.big{font-size:36px;line-height:1.2}
|
||
.big small{font-size:12px;color:var(--muted);margin-left:6px}
|
||
.spin{width:44px;height:44px;border:4px solid var(--line);border-top-color:var(--ink);margin:12px auto 16px;animation:spin 1s steps(8) infinite}
|
||
@keyframes spin{to{transform:rotate(360deg)}}
|
||
.center{text-align:center}
|
||
.tag{display:inline-block;padding:0 6px;font-size:12px;line-height:1.6;border:2px solid var(--ink);color:var(--ink);white-space:nowrap;background:#fff}
|
||
.tag.paid{background:#dff7e8}.tag.claimed{background:var(--panel-2)}.tag.bad{background:#ffe1e1;color:var(--red);border-color:var(--red)}
|
||
.grid2{display:grid;gap:0 14px}@media(min-width:600px){.grid2{grid-template-columns:1fr 1fr}}
|
||
.emojis{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
|
||
.emojis button{font-size:20px;background:#fff;border:3px solid var(--ink);padding:3px 7px;cursor:pointer;line-height:1.3;box-shadow:2px 2px 0 var(--ink)}
|
||
.anchors{display:flex;gap:10px;overflow-x:auto;padding:2px 2px 6px;-webkit-overflow-scrolling:touch;scrollbar-width:none}
|
||
.anchors::-webkit-scrollbar{display:none}
|
||
.anchors a{flex:none;font-size:12px;line-height:1.8;color:var(--ink);text-decoration:none;border:3px solid var(--ink);padding:4px 10px;background:#fff;box-shadow:2px 2px 0 var(--ink)}
|
||
.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:10px;flex-basis:100%;padding-left:46px}
|
||
.actions form,.inline form{display:inline}
|
||
.section-title{font-size:12px;color:var(--muted);letter-spacing:.1em;margin:22px 0 8px;line-height:1.6}
|
||
.xavatar{width:40px;height:40px;border:3px solid var(--ink);vertical-align:middle;margin-right:6px;image-rendering:auto;object-fit:cover;background:#fff}
|
||
.av.img{object-fit:cover;background:#fff}
|
||
.xh{font-size:12px;color:var(--muted);font-family:var(--pf);flex:none}
|
||
.badge{font-size:14px;flex:none;letter-spacing:-2px}
|
||
.coinrow{display:flex;align-items:center;gap:10px;margin-top:14px;flex-wrap:wrap}
|
||
.js .col-l>.donate-card{display:none}
|
||
#modalForm .donate-card{box-shadow:none;border:0;padding:0;background:transparent}
|
||
#modalForm .donate-card h2{padding-right:44px}
|
||
.coinrow .coins b{color:var(--ink);font-size:16px}
|
||
.coinbtn .px-coin{width:16px;height:16px}
|
||
.coinbtn:disabled{opacity:.6;cursor:default}
|
||
.flycoin{position:fixed;z-index:50;font-size:28px;animation:fly .9s ease-out forwards;pointer-events:none}
|
||
@keyframes fly{0%{transform:translate(-50%,0) scale(1);opacity:1}60%{transform:translate(-50%,-90px) scale(1.3);opacity:1}100%{transform:translate(-50%,-140px) scale(.6);opacity:0}}
|
||
.hdr{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.hdr .body{flex:1 1 220px;min-width:0}
|
||
.hdr-actions{display:flex;gap:8px;margin-left:auto;flex:none}.hdr-actions form{display:contents}
|
||
@media(max-width:599px){.hdr-actions{flex-basis:100%;margin-left:0}.hdr-actions .btn{flex:1}}
|
||
.toast{position:fixed;left:50%;bottom:calc(84px + env(safe-area-inset-bottom));transform:translateX(-50%);background:var(--ink);color:var(--gold);padding:8px 14px;font-family:var(--pf);font-size:14px;z-index:60;box-shadow:3px 3px 0 rgba(0,0,0,.25)}
|
||
.tabs.four{grid-template-columns:repeat(4,1fr)}
|
||
.tabs.four .tab{font-size:14px;padding:10px 2px}
|
||
.tab.on::before{content:"▶";font-size:8px;margin-right:3px}
|
||
.toggle{display:inline-flex;border:3px solid var(--ink);margin-bottom:10px;background:#fff}
|
||
.toggle button{border:0;background:transparent;font-family:var(--pf);font-size:12px;padding:8px 12px;min-height:36px;cursor:pointer;color:var(--muted)}
|
||
.toggle button.on{background:var(--ink);color:var(--gold)}
|
||
.bubble.reply{background:var(--panel-2);margin-top:6px}
|
||
.profrow{display:flex;align-items:center;gap:12px;margin:12px 0}
|
||
.profrow .xavatar{width:56px;height:56px;margin:0}
|
||
.codebox{display:flex;align-items:center;gap:10px;margin:8px 0 12px}
|
||
.codebox .code.big{font-size:24px;padding:6px 12px;font-family:var(--pf)}
|
||
.sharebox{margin-top:14px}
|
||
.sharebox img{display:block;max-width:100%;border:3px solid var(--ink);box-shadow:4px 4px 0 var(--ink)}
|
||
.modal{position:fixed;inset:0;background:rgba(30,30,46,.6);z-index:100;display:flex;align-items:flex-end;justify-content:center}
|
||
.modal[hidden]{display:none}
|
||
.modal-box{position:relative;width:100%;max-height:92vh;overflow:auto;background:var(--panel);padding:18px 16px calc(18px + env(safe-area-inset-bottom));border-top:4px solid var(--ink);box-shadow:0 -6px 0 var(--ink)}
|
||
@media(min-width:600px){.modal{align-items:center;padding:20px}.modal-box{width:520px;max-height:90vh;border:4px solid var(--ink);box-shadow:6px 6px 0 var(--ink)}}
|
||
.modal-x{position:absolute;right:10px;top:8px;width:36px;height:36px;border:3px solid var(--ink);background:#fff;font-family:var(--pf);font-size:16px;cursor:pointer;box-shadow:2px 2px 0 var(--ink);z-index:1}
|
||
.spin-inline{display:inline-block;width:14px;height:14px;border:3px solid var(--line);border-top-color:var(--ink);border-radius:50%;animation:spin 1s steps(8) infinite;vertical-align:-2px;margin-right:4px}
|
||
.paypanel .qr{width:200px;height:200px}
|
||
.paypanel .big{font-size:32px}
|
||
footer{color:var(--muted);font-size:13px;text-align:center;margin-top:32px;line-height:1.9}
|
||
footer a{color:var(--muted)}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
{{if .HasBGM}}<audio id="bgm" src="/static/bgm.m4a" loop preload="none" playsinline></audio>{{end}}
|
||
<div class="page">
|
||
<nav class="nav">
|
||
<a class="brand" href="{{.HomePath}}"{{if ne .HomePath "/"}} title="回到刚才看的碗"{{end}}>{{template "coin"}}<span>{{.SiteTitle}}</span></a>
|
||
<span class="sp"></span>
|
||
<button class="sfx" id="sfxBtn" type="button" aria-label="声音开关" title="声音">🔊</button>
|
||
<a class="link navrank" href="/rank" aria-label="排行榜" title="排行榜"><span>排行榜</span></a>
|
||
{{if .Me}}<a class="link" href="/manage">我的后台</a>{{else}}<a class="link" href="/login"><span class="hide-sm">站长</span>登录</a>{{end}}
|
||
{{if .Me}}<a class="pill px" href="/{{.Me.Slug}}">我的站</a>{{else if .SubsitesEnabled}}<a class="pill px" href="/new">开通要饭站</a>{{end}}
|
||
</nav>
|
||
<div class="ticker" aria-hidden="true"><div class="ticker-in"><span>🙏 行行好,赏口饭吃</span><span>🪙 一毛也是爱</span><span>💸 投币就上榜</span><span>📜 留一句话刻功德簿</span><span>🏚 发条推就能开自己的要饭站</span><span>👾 赛博丐帮,人人有碗</span><span>🙏 行行好,赏口饭吃</span><span>🪙 一毛也是爱</span><span>💸 投币就上榜</span><span>📜 留一句话刻功德簿</span><span>🏚 发条推就能开自己的要饭站</span><span>👾 赛博丐帮,人人有碗</span></div></div>
|
||
{{template "content" .}}
|
||
<footer>
|
||
{{.SiteTitle}} · 赛博丐帮,行行好<br>
|
||
{{if or .AuthorX .AuthorGitHub}}作者{{if .AuthorX}} <a href="{{.AuthorX}}" target="_blank" rel="noopener">𝕏 @{{lastSeg .AuthorX}}</a>{{end}}{{if .AuthorGitHub}} · <a href="{{.AuthorGitHub}}" target="_blank" rel="noopener">GitHub {{lastSeg .AuthorGitHub}}</a>{{end}}<br>{{end}}
|
||
收款由 <a href="{{.RepoURL}}" target="_blank" rel="noopener">BinancePayTool</a> 驱动 · 字体 <a href="https://github.com/TakWolf/fusion-pixel-font" target="_blank" rel="noopener">缝合怪像素字体</a>
|
||
</footer>
|
||
</div>
|
||
<script>
|
||
// 声音:背景音乐(/static/bgm.m4a 循环)+ 8-bit 音效(Web Audio 现场合成,不加载文件)。一个开关管全部,记 localStorage(sfx),默认开。
|
||
// 浏览器不让页面一打开就出声:先尝试自动播放,被拦就等用户第一次触屏/点击/按键再起。音效首次出声也必须在用户手势里创建 AudioContext(iOS 限制)。
|
||
// 背景音乐也解码进同一个 AudioContext 里循环播放(AudioBufferSourceNode,无缝循环):和 <audio> 元素分开走的话,iOS 上音效一起音频会话就会把音乐打断重来。
|
||
// 解码不了(极少数浏览器没有 AAC 解码器)才退回 <audio> 元素。
|
||
var BGM_VOL=0.45;
|
||
window.sfx=(function(){var ctx,on=true,C=window.AudioContext||window.webkitAudioContext,buf=null,src=null,el=null,bytes=null,elMode=false,loading=false,unlocked=false;try{on=localStorage.getItem('sfx')!=='0'}catch(e){}
|
||
function ac(){if(!C)return null;if(!ctx){try{ctx=new C()}catch(e){return null}}if(ctx.state==='suspended'){try{ctx.resume()}catch(e){}}return ctx}
|
||
// 在用户手势里解锁:resume + 放一个空 buffer(老 iOS 的解锁套路)
|
||
function unlock(){var c=ac();if(!c)return;try{var b=c.createBuffer(1,1,22050),s=c.createBufferSource();s.buffer=b;s.connect(c.destination);s.start(0);unlocked=true}catch(e){}}
|
||
var paint=function(){};
|
||
// 下载一次:字节既喂给 <audio>(手势里能立刻响)也喂给 decodeAudioData(解码完切到 Web Audio 无缝循环)
|
||
function loadBgm(){if(bytes||loading)return;el=el||document.getElementById('bgm');if(!el)return;loading=true;
|
||
fetch(el.getAttribute('src')).then(function(r){if(!r.ok)throw 0;return r.arrayBuffer()}).then(function(ab){bytes=ab;
|
||
try{el.src=URL.createObjectURL(new Blob([ab],{type:'audio/mp4'}))}catch(e){}
|
||
var c=C&&ac();if(!c){elMode=true;loading=false;startBgm();return}
|
||
return new Promise(function(res,rej){var p=c.decodeAudioData(ab.slice(0),res,rej);if(p&&p.then)p.then(res,rej)}).then(function(b){buf=b;loading=false;startBgm()})})
|
||
.catch(function(){loading=false;elMode=true;startBgm()})}
|
||
function elPlay(){if(!el||!el.paused)return;el.volume=BGM_VOL;var p=el.play();if(p&&p.then)p.then(paint,function(){})}
|
||
function startBgm(){if(!on)return;
|
||
if(elMode||!buf){ // 还没解码好(或解码不了):先用 <audio> 顶上,只有在手势里才播得出来
|
||
if(bytes)elPlay();return}
|
||
var c=ac();if(!c)return;
|
||
if(c.state!=='running'){var r=c.resume&&c.resume();if(r&&r.then)r.then(function(){if(c.state==='running'&&!src)startBgm();paint()},function(){});return}
|
||
if(src)return;
|
||
var off=0;if(el&&!el.paused){off=el.currentTime%buf.duration;el.pause()} // 从 <audio> 接力,不从头来
|
||
var s=c.createBufferSource(),g=c.createGain();s.buffer=buf;s.loop=true;g.gain.value=BGM_VOL;s.connect(g);g.connect(c.destination);s.start(0,off);src=s;paint()}
|
||
function stopBgm(){if(src){try{src.stop()}catch(e){}src=null}if(el)el.pause();paint()}
|
||
function playingNow(){if(src)return ctx&&ctx.state==='running';return !!(el&&!el.paused)}
|
||
function armBgm(){['pointerdown','touchend','click','keydown'].forEach(function(t){document.addEventListener(t,function(){if(!on)return;unlock();loadBgm();startBgm()},{passive:true})})}
|
||
function tone(f,t0,dur,type,vol){var c=ac();if(!c)return;var o=c.createOscillator(),g=c.createGain(),t=c.currentTime+t0;o.type=type||'square';o.frequency.setValueAtTime(f,t);
|
||
g.gain.setValueAtTime(0.0001,t);g.gain.exponentialRampToValueAtTime(vol||0.22,t+0.012);g.gain.exponentialRampToValueAtTime(0.0001,t+dur);o.connect(g);g.connect(c.destination);o.start(t);o.stop(t+dur+0.03)}
|
||
function play(seq){if(!on)return;try{seq.forEach(function(n){tone(n[0],n[1],n[2],n[3],n[4])})}catch(e){}}
|
||
var S={
|
||
warm:function(){if(on)ac()},
|
||
click:function(){play([[740,0,0.045,'square',0.12]])},
|
||
coin:function(){play([[988,0,0.07,'square',0.25],[1319,0.07,0.32,'square',0.25]])},
|
||
ok:function(){play([[523,0,0.09],[659,0.09,0.09],[784,0.18,0.09],[1047,0.27,0.38,'square',0.26]])},
|
||
fail:function(){play([[196,0,0.1,'sawtooth',0.16],[147,0.1,0.26,'sawtooth',0.16]])},
|
||
levelup:function(){play([[659,0,0.08],[784,0.08,0.08],[988,0.16,0.08],[1319,0.24,0.08],[1568,0.32,0.4,'square',0.26]])},
|
||
enabled:function(){return on},
|
||
playing:function(){return src?'webaudio':(el&&!el.paused?'element':'')},
|
||
toggle:function(){on=!on;try{localStorage.setItem('sfx',on?'1':'0')}catch(e){}if(on){S.coin();loadBgm();startBgm()}else{stopBgm()}paint();return on}};
|
||
document.addEventListener('DOMContentLoaded',function(){if(on)loadBgm();armBgm();
|
||
var b=document.getElementById('sfxBtn');if(!b)return;
|
||
// 三态:🔊 在放 / 🔈 开着但还没放(浏览器拦了自动播放,点一下就放)/ 🔇 静音
|
||
var hasBgm=!!document.getElementById('bgm'); // 没放音乐文件时只有音效,喇叭只有开/关两态
|
||
paint=function(){var p=on&&(!hasBgm||playingNow());b.textContent=!on?'🔇':(p?'🔊':'🔈');b.classList.toggle('off',!on);b.classList.toggle('idle',on&&!p);b.title=!on?'声音:关':(p?'声音:开(点击静音)':'点一下开始播放')};paint();
|
||
b.addEventListener('click',function(){if(on&&!playingNow()){loadBgm();startBgm();return}S.toggle()})});
|
||
document.addEventListener('click',function(ev){var b=ev.target.closest('.btn,.tab,.amt-btn,.copy,.pill,.toggle button,.link');if(!b||b.disabled)return;ac();if(b.id!=='coinbtn')S.click()},true);
|
||
return S})();
|
||
(function(){
|
||
// 复制按钮(全站委托)
|
||
document.addEventListener('click',function(ev){var b=ev.target.closest('.copy');if(!b||b.id==='nextText')return;var src=b.dataset.copyFrom;var t=src?document.getElementById(src).value:b.dataset.copy;var o=b.textContent;
|
||
function done(){b.textContent='已复制';setTimeout(function(){b.textContent=o},1500)}
|
||
(navigator.clipboard?navigator.clipboard.writeText(t):Promise.reject()).then(done,function(){var i=document.createElement('input');i.value=t;document.body.appendChild(i);i.select();try{document.execCommand('copy')}catch(e){}i.remove();done()})});
|
||
// 付款面板:轮询到账、回填/自报、成功态
|
||
window.initPayPanel=function(pp,onDone){
|
||
var code=pp.dataset.code,site=pp.dataset.site,amount=pp.dataset.amount,status=pp.dataset.status,stop=false,fails=0;
|
||
function success(amt){stop=true;if(window.sfx)sfx.ok();var sp=document.querySelector('.sprite');pp.innerHTML='<div class="center"><div class="sprite-wrap jump" style="margin:0 auto 8px">'+(sp?sp.outerHTML:'🥣')+'</div><div class="insert">★ THANK YOU ★</div><h2 class="center" style="justify-content:center">🙏 功德 +'+(amt||amount)+'</h2><p class="hint">你的名号和留言已刻上功德簿</p><div class="btns"><a class="btn" href="'+site+'#feed" onclick="if(location.pathname===this.pathname){location.hash=\'feed\';location.reload();return false}">看看功德簿</a><a class="btn sec" href="/d/'+code+'">分享卡片</a></div></div>';if(onDone)onDone('paid')}
|
||
function setStatus(html){var st=pp.querySelector('#ppStatus');if(st)st.innerHTML=html}
|
||
function apply(j){if(!j||!j.status)return;if(j.status==='paid'){success(j.amount)}else if(j.status==='claimed'&&status!=='claimed'){status='claimed';setStatus('<div class="notice" style="margin-top:12px"><span class="spin-inline"></span> 已提交,等站长确认后上榜。本页会自动更新。</div>')}else if(['expired','failed','rejected','closed'].indexOf(j.status)>=0){stop=true;setStatus('<div class="notice bad" style="margin-top:12px">这笔施舍已'+({expired:'过期',failed:'下单失败',rejected:'被站长拒绝',closed:'关闭'})[j.status]+',请回到页面重新投币。</div>')}}
|
||
function tick(){if(stop)return;fetch('/d/'+code+'/status',{cache:'no-store'}).then(function(r){return r.json()}).then(function(j){fails=0;apply(j)}).catch(function(){if(++fails>=20)stop=true})}
|
||
var timer=setInterval(function(){if(stop){clearInterval(timer);return}tick()},3000);
|
||
pp.addEventListener('submit',function(ev){var f=ev.target.closest('.claimf');if(!f)return;ev.preventDefault();var fd=new FormData(f);fd.append('ajax','1');var btn=f.querySelector('button');btn.disabled=true;var err=f.querySelector('.claim-err');err.textContent='';
|
||
fetch(f.getAttribute('action'),{method:'POST',body:fd}).then(function(r){return r.json()}).then(function(j){btn.disabled=false;if(j.status==='paid'){success()}else if(j.ok&&j.status==='claimed'){apply({status:'claimed'})}else{if(window.sfx)sfx.fail();err.textContent=j.msg||'没成功,再试试'}}).catch(function(){btn.disabled=false;if(window.sfx)sfx.fail();err.textContent='网络开小差了'})});
|
||
return function(){stop=true;clearInterval(timer)}
|
||
};
|
||
var pp=document.getElementById('paypanel');if(pp)window.initPayPanel(pp);
|
||
})();
|
||
</script>
|
||
{{block "scripts" .}}{{end}}
|
||
</body>
|
||
</html>{{end}}
|
||
{{define "pager"}}{{if gt .Pages 1}}<nav class="pager" aria-label="分页">
|
||
{{if .HasPrev}}<a href="{{.URL .Prev}}">‹ 上一页</a>{{else}}<span class="dis">‹ 上一页</span>{{end}}
|
||
{{range .Nums}}{{if eq . $.Page}}<span class="cur">{{.}}</span>{{else}}<a href="{{$.URL .}}">{{.}}</a>{{end}}{{end}}
|
||
{{if .HasNext}}<a href="{{.URL .Next}}">下一页 ›</a>{{else}}<span class="dis">下一页 ›</span>{{end}}
|
||
<span class="hint" style="margin-left:auto">{{.Page}}/{{.Pages}} 页</span>
|
||
</nav>{{end}}{{end}}
|