feat(backend): 公开页自适应满屏 + 主题切换对齐 App ThemePickerPill

- 页面 flex 撑满视口(100dvh):页眉贴顶、页脚贴底、信息区弹性填充,
  底部不再留大片空白;内容超屏时自然滚动(移动端上下滑不受影响)
- 主题切换从 ◐ 循环钮改为与 App 一致的衬衫图标 pill + 下拉单选
  (A·经典蓝 / B·琥珀 / C·酒窖,勾选态),图标 path 取自原型 icons.js #i-shirt

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
This commit is contained in:
wangjia
2026-07-07 11:55:08 +08:00
parent 47d6490bf2
commit 0de9ba7c21
2 changed files with 119 additions and 27 deletions
@@ -36,7 +36,9 @@
--glow1:rgba(124,31,44,.05); --glow2:rgba(181,134,47,.04); --seal-bg:rgba(255,253,248,.78);
}
*{box-sizing:border-box;margin:0;padding:0;}
html{background:var(--bg);height:100%;}
body{
min-height:100%;
background-color:var(--bg);
background-image:
radial-gradient(circle at 12% 0%, var(--glow1), transparent 38%),
@@ -44,9 +46,11 @@
color:var(--text);
font:var(--fs-title)/1.75 var(--font);
-webkit-font-smoothing:antialiased;
-webkit-tap-highlight-color:transparent;
transition:background-color .25s,color .25s;
}
.page{max-width:560px;margin:0 auto;padding:0 16px 40px;}
/* 自适应满屏:页眉贴顶、页脚贴底、中间信息弹性填充;内容超屏时自然滚动 */
.page{max-width:560px;margin:0 auto;padding:0 16px 24px;min-height:100vh;min-height:100dvh;display:flex;flex-direction:column;}
a{color:var(--primary);text-decoration:none;}
/* 顶部题签 */
@@ -56,11 +60,29 @@
border-bottom:1px solid var(--border);position:relative;
}
.mast a{color:var(--primary-dark);font-weight:700;letter-spacing:.3em;}
/* 主题选择器:与 App ThemePickerPill 同构(衬衫图标 + 主题名 + ▾ + 下拉单选) */
.thm{
position:absolute;right:0;top:50%;transform:translateY(-58%);width:30px;height:30px;
position:absolute;right:0;top:50%;transform:translateY(-58%);
display:flex;align-items:center;gap:6px;height:30px;padding:0 11px;
border-radius:var(--r-pill);border:1px solid var(--border);background:var(--surface);
color:var(--muted);font-size:14px;line-height:1;cursor:pointer;
color:var(--text);font-size:var(--fs-sm);font-family:var(--font);cursor:pointer;letter-spacing:0;
}
.thm svg{width:15px;height:15px;stroke:var(--muted);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;}
.thm svg.cv{width:13px;height:13px;}
.thm-menu{
position:absolute;right:0;top:calc(100% + 6px);z-index:50;min-width:136px;padding:4px;
background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);
box-shadow:0 4px 14px var(--shadow);
}
.thm-menu[hidden]{display:none;}
.thm-menu button{
display:flex;align-items:center;gap:4px;width:100%;height:36px;padding:0 10px;
border:none;background:none;color:var(--text);font-size:var(--fs-body);
font-family:var(--font);cursor:pointer;border-radius:4px;text-align:left;
}
.thm-menu button:hover{background:var(--brand50);}
.thm-menu button.on{color:var(--primary);font-weight:600;}
.thm-menu .ck{width:16px;color:var(--primary);font-weight:700;flex:none;}
/* 图片区(永远存在)+ 右上「正品」章(--accent 酒红) */
.hero{margin:18px 0 0;position:relative;animation:rise .5s ease both;}
@@ -123,8 +145,8 @@
.desc{padding:13px 2px;font-size:14px;color:var(--text);white-space:pre-wrap;text-align:justify;}
.more{display:block;text-align:center;padding:12px 0 10px;font-size:13.5px;font-weight:600;border-top:1px solid var(--border-subtle);}
/* 页脚 */
.foot{margin-top:30px;text-align:center;color:var(--muted);font-size:var(--fs-sm);line-height:2;animation:rise .5s ease .18s both;}
/* 页脚flex 撑到视口底部 */
.foot{margin-top:auto;padding-top:30px;text-align:center;color:var(--muted);font-size:var(--fs-sm);line-height:2;animation:rise .5s ease .18s both;}
.foot-rule{display:flex;align-items:center;gap:12px;margin-bottom:8px;color:var(--border);}
.foot-rule::before,.foot-rule::after{content:"";height:1px;background:var(--border);flex:1;}
.foot a{color:var(--muted);}
@@ -149,7 +171,18 @@
</head>
<body>
<div class="page">
<header class="mast"><a href="https://jiu.51yanmei.com">岩美酒库</a><button class="thm" id="thm" aria-label="切换主题"></button></header>
<header class="mast"><a href="https://jiu.51yanmei.com">岩美酒库</a>
<button class="thm" id="thm" aria-label="切换主题">
<svg viewBox="0 0 24 24"><path d="M20.38 3.46 16 2a4 4 0 0 1-8 0L3.62 3.46a2 2 0 0 0-1.34 2.23l.58 3.47a1 1 0 0 0 .99.84H6v10c0 1.1.9 2 2 2h8a2 2 0 0 0 2-2V10h2.15a1 1 0 0 0 .99-.84l.58-3.47a2 2 0 0 0-1.34-2.23z"/></svg>
<span id="thmName">经典蓝</span>
<svg class="cv" viewBox="0 0 24 24"><path d="m6 9 6 6 6-6"/></svg>
</button>
<div class="thm-menu" id="thmMenu" hidden>
<button data-t="a"><span class="ck"></span>A · 经典蓝</button>
<button data-t="b"><span class="ck"></span>B · 琥珀</button>
<button data-t="c"><span class="ck"></span>C · 酒窖</button>
</div>
</header>
{{if .Found}}
<div class="hero">
<div class="frame">
@@ -234,14 +267,27 @@
</div>
<script>
(function(){
var order=['a','b','c'],root=document.documentElement,btn=document.getElementById('thm');
if(!btn)return;
btn.addEventListener('click',function(){
var cur=root.getAttribute('data-theme')||'a',
next=order[(order.indexOf(cur)+1)%order.length];
if(next==='a')root.removeAttribute('data-theme');else root.setAttribute('data-theme',next);
try{localStorage.setItem('jiu-pub-theme',next);}catch(e){}
});
var NAMES={a:'经典蓝',b:'琥珀',c:'酒窖'},root=document.documentElement,
btn=document.getElementById('thm'),menu=document.getElementById('thmMenu'),
label=document.getElementById('thmName');
if(!btn||!menu)return;
var opts=[].slice.call(menu.children);
function cur(){return root.getAttribute('data-theme')||'a';}
function paint(){
label.textContent=NAMES[cur()];
opts.forEach(function(b){var on=b.getAttribute('data-t')===cur();
b.className=on?'on':'';b.querySelector('.ck').textContent=on?'✓':'';});
}
btn.addEventListener('click',function(e){e.stopPropagation();menu.hidden=!menu.hidden;});
opts.forEach(function(b){b.addEventListener('click',function(e){
e.stopPropagation();
var t=b.getAttribute('data-t');
if(t==='a')root.removeAttribute('data-theme');else root.setAttribute('data-theme',t);
try{localStorage.setItem('jiu-pub-theme',t);}catch(err){}
paint();menu.hidden=true;
});});
document.addEventListener('click',function(){menu.hidden=true;});
paint();
})();
</script>
{{if .Images}}
@@ -34,7 +34,9 @@
--glow1:rgba(124,31,44,.05); --glow2:rgba(181,134,47,.04);
}
*{box-sizing:border-box;margin:0;padding:0;}
html{background:var(--bg);height:100%;}
body{
min-height:100%;
background-color:var(--bg);
background-image:
radial-gradient(circle at 12% 0%, var(--glow1), transparent 38%),
@@ -42,9 +44,11 @@
color:var(--text);
font:var(--fs-title)/1.7 var(--font);
-webkit-font-smoothing:antialiased;
-webkit-tap-highlight-color:transparent;
transition:background-color .25s,color .25s;
}
.page{max-width:560px;margin:0 auto;padding:0 16px 40px;}
/* 自适应满屏:页眉贴顶、页脚贴底、中间信息弹性填充;内容超屏时自然滚动 */
.page{max-width:560px;margin:0 auto;padding:0 16px 24px;min-height:100vh;min-height:100dvh;display:flex;flex-direction:column;}
a{color:var(--primary);text-decoration:none;}
.mast{
@@ -53,11 +57,29 @@
border-bottom:1px solid var(--border);position:relative;
}
.mast a{color:var(--primary-dark);font-weight:700;letter-spacing:.3em;}
/* 主题选择器:与 App ThemePickerPill 同构(衬衫图标 + 主题名 + ▾ + 下拉单选) */
.thm{
position:absolute;right:0;top:50%;transform:translateY(-58%);width:30px;height:30px;
position:absolute;right:0;top:50%;transform:translateY(-58%);
display:flex;align-items:center;gap:6px;height:30px;padding:0 11px;
border-radius:var(--r-pill);border:1px solid var(--border);background:var(--surface);
color:var(--muted);font-size:14px;line-height:1;cursor:pointer;
color:var(--text);font-size:var(--fs-sm);font-family:var(--font);cursor:pointer;letter-spacing:0;
}
.thm svg{width:15px;height:15px;stroke:var(--muted);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;}
.thm svg.cv{width:13px;height:13px;}
.thm-menu{
position:absolute;right:0;top:calc(100% + 6px);z-index:50;min-width:136px;padding:4px;
background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);
box-shadow:0 4px 14px var(--shadow);
}
.thm-menu[hidden]{display:none;}
.thm-menu button{
display:flex;align-items:center;gap:4px;width:100%;height:36px;padding:0 10px;
border:none;background:none;color:var(--text);font-size:var(--fs-body);
font-family:var(--font);cursor:pointer;border-radius:4px;text-align:left;letter-spacing:0;text-indent:0;
}
.thm-menu button:hover{background:var(--brand50);}
.thm-menu button.on{color:var(--primary);font-weight:600;}
.thm-menu .ck{width:16px;color:var(--primary);font-weight:700;flex:none;}
/* 店铺题名 */
.shop{text-align:center;padding:24px 0 4px;animation:rise .5s ease both;}
@@ -110,7 +132,7 @@
.empty h2{font-size:17px;margin-bottom:8px;color:var(--heading);}
.empty p{color:var(--muted);font-size:var(--fs-body);}
.foot{margin-top:30px;text-align:center;color:var(--muted);font-size:var(--fs-sm);line-height:2;}
.foot{margin-top:auto;padding-top:30px;text-align:center;color:var(--muted);font-size:var(--fs-sm);line-height:2;}
.foot-rule{display:flex;align-items:center;gap:12px;margin-bottom:8px;color:var(--border);}
.foot-rule::before,.foot-rule::after{content:"";height:1px;background:var(--border);flex:1;}
.foot a{color:var(--muted);}
@@ -131,7 +153,18 @@
</head>
<body>
<div class="page">
<header class="mast"><a href="https://jiu.51yanmei.com">岩美酒库</a><button class="thm" id="thm" aria-label="切换主题"></button></header>
<header class="mast"><a href="https://jiu.51yanmei.com">岩美酒库</a>
<button class="thm" id="thm" aria-label="切换主题">
<svg viewBox="0 0 24 24"><path d="M20.38 3.46 16 2a4 4 0 0 1-8 0L3.62 3.46a2 2 0 0 0-1.34 2.23l.58 3.47a1 1 0 0 0 .99.84H6v10c0 1.1.9 2 2 2h8a2 2 0 0 0 2-2V10h2.15a1 1 0 0 0 .99-.84l.58-3.47a2 2 0 0 0-1.34-2.23z"/></svg>
<span id="thmName">经典蓝</span>
<svg class="cv" viewBox="0 0 24 24"><path d="m6 9 6 6 6-6"/></svg>
</button>
<div class="thm-menu" id="thmMenu" hidden>
<button data-t="a"><span class="ck"></span>A · 经典蓝</button>
<button data-t="b"><span class="ck"></span>B · 琥珀</button>
<button data-t="c"><span class="ck"></span>C · 酒窖</button>
</div>
</header>
{{if .Found}}
<div class="shop">
{{if .LogoURL}}<img src="{{.LogoURL}}" alt="{{.ShopName}}" decoding="async">{{end}}
@@ -184,14 +217,27 @@
</div>
<script>
(function(){
var order=['a','b','c'],root=document.documentElement,btn=document.getElementById('thm');
if(!btn)return;
btn.addEventListener('click',function(){
var cur=root.getAttribute('data-theme')||'a',
next=order[(order.indexOf(cur)+1)%order.length];
if(next==='a')root.removeAttribute('data-theme');else root.setAttribute('data-theme',next);
try{localStorage.setItem('jiu-pub-theme',next);}catch(e){}
});
var NAMES={a:'经典蓝',b:'琥珀',c:'酒窖'},root=document.documentElement,
btn=document.getElementById('thm'),menu=document.getElementById('thmMenu'),
label=document.getElementById('thmName');
if(!btn||!menu)return;
var opts=[].slice.call(menu.children);
function cur(){return root.getAttribute('data-theme')||'a';}
function paint(){
label.textContent=NAMES[cur()];
opts.forEach(function(b){var on=b.getAttribute('data-t')===cur();
b.className=on?'on':'';b.querySelector('.ck').textContent=on?'✓':'';});
}
btn.addEventListener('click',function(e){e.stopPropagation();menu.hidden=!menu.hidden;});
opts.forEach(function(b){b.addEventListener('click',function(e){
e.stopPropagation();
var t=b.getAttribute('data-t');
if(t==='a')root.removeAttribute('data-theme');else root.setAttribute('data-theme',t);
try{localStorage.setItem('jiu-pub-theme',t);}catch(err){}
paint();menu.hidden=true;
});});
document.addEventListener('click',function(){menu.hidden=true;});
paint();
})();
</script>
</body>