1) 防重复点击原来漏了最主要的一条路径
footer 的全局 submit 监听会禁用按钮,但**程序化 form.submit() 不触发 submit 事件** ——
走 reCAPTCHA / Turnstile 的流程是在回调里调 form.submit() 的,而默认配置
captcha_type = recaptcha,也就是主提问流一直没有防重复。登录、注册、找回密码、
投票、注销账号同样走这个回调。
→ 把「切提交中状态」抽成 tbBeginSubmit(form, trigger) 挂到 window,
验证码回调先调它再 submit。7 个 data-callback="onSubmit" 的模板全部受益。
顺带加了 data-tb-restore 的重复覆盖保护,避免 bfcache 复位后按钮卡在转圈。
2) waline.js / waline.css 从全站改按页加载
只有 home.html 与 item.html 用评论区,但此前挂在 header 里 —— 登录、后台、投票、
私聊每页都下载解析 waline.js(2.15 未压缩约 200KB)。实测 /login 已无引用。
3) 图片懒加载:explore 列表头像与题目配图加 loading="lazy"(首屏推荐位不加,避免影响 LCP)。
4) 移动端底栏:body 只预留固定 56px,而底栏 padding 含 safe-area-inset-bottom。
带 Home Indicator 的 iPhone 上 inset 约 34px、底栏实际约 88px,最后约 32px
(页脚备案、存活计时)被压在栏下,滚到底也看不到。改成 calc(56px + env(...))。
5) 硬编码中文接字典(en/ja 用户此前直接看到中文):
history-template 的「查看回答 / 加载更多 / 加载中... / 无更多留言」、
单题页「@xxx 以前回答过的问题」(字典里本来就有 ask.history)、
投票页「(最多 N 项)」改为带参数的整句(原先前半走字典、后半手写中文)。
新增 4 个 key × 4 语言。
实测:箱主语言设为 en 后箱主页显示 View answer ×2 / Load more / No more posts,中文零残留。
106 lines
5.9 KiB
HTML
106 lines
5.9 KiB
HTML
{{template "base/header" .}}
|
||
<!--<link rel="stylesheet" href="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/uikit/3.3.3/css/uikit.min.css">-->
|
||
<!-- 头像直连 R2:crossorigin 让 favicon 也以 CORS 模式请求,确保浏览器缓存的响应都带 ACAO;
|
||
?v=2 击穿历史上被「无 ACAO 响应」污染的缓存条目 -->
|
||
<link rel="shortcut icon"
|
||
href="{{.PageUser.Avatar}}?v=2" crossorigin="anonymous"/>
|
||
<link rel="apple-touch-icon"
|
||
href="{{.PageUser.Avatar}}?v=2" crossorigin="anonymous"/>
|
||
<link rel="icon" sizes="192x192"
|
||
href="{{.PageUser.Avatar}}?v=2" crossorigin="anonymous">
|
||
<div class="uk-card uk-card-default uk-text-center">
|
||
<div class="uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light" style="min-height: 260px;" data-src="{{ .PageUser.Background }}" uk-img>
|
||
<div class="uk-card-body">
|
||
<img class="uk-border-circle uk-box-shadow-large" src="{{ if .PageUser.Avatar }}{{ .PageUser.Avatar }}?v=2{{ else }}{{ .DefaultAvatar }}{{ end }}" crossorigin="anonymous" style="width: 100px; height: 100px; max-width: 100%; max-height: 100%;">
|
||
<h3 id="usernamecolor">{{ .PageUser.Name }}</h3>
|
||
<p id="introcolor">{{ .PageUser.Intro }}</p>
|
||
<div class="icon-container">
|
||
{{ if and .PageUser.Acfunlink (ne .PageUser.Acfunlink "none") }}
|
||
<a href="https://{{.PageUser.Acfunlink}}" target="_blank">
|
||
<img src="https://r2.337845818.best/tamabox/icon/social/ailicili.png" alt="acfunlink" class="icon">
|
||
</a>
|
||
{{ end }}
|
||
{{ if and .PageUser.Bililink (ne .PageUser.Bililink "none") }}
|
||
<a href="https://{{.PageUser.Bililink}}" target="_blank">
|
||
<img src="https://r2.337845818.best/tamabox/icon/social/bili.png" alt="bililink" class="icon">
|
||
</a>
|
||
{{ end }}
|
||
{{ if and .PageUser.Weibolink (ne .PageUser.Weibolink "none") }}
|
||
<a href="https://{{.PageUser.Weibolink}}" target="_blank">
|
||
<img src="https://r2.337845818.best/tamabox/icon/social/weibo.png" alt="weibolink" class="icon">
|
||
</a>
|
||
{{ end }}
|
||
{{ if and .PageUser.Xiaohongshulink (ne .PageUser.Xiaohongshulink "none") }}
|
||
<a href="https://{{.PageUser.Xiaohongshulink}}" target="_blank">
|
||
<img src="https://r2.337845818.best/tamabox/icon/social/xiaohongshu.png" alt="xiaohongshulink" class="icon">
|
||
</a>
|
||
{{ end }}
|
||
{{ if and .PageUser.Bloglink (ne .PageUser.Bloglink "none") }}
|
||
<a href="https://{{.PageUser.Bloglink}}" target="_blank">
|
||
<img src="https://r2.337845818.best/tamabox/icon/social/blog.png" alt="bloglink" class="icon">
|
||
</a>
|
||
{{ end }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
document.getElementById("usernamecolor").style.color = {{.PageUser.Usernamecolor}};
|
||
document.getElementById("introcolor").style.color = {{.PageUser.Introcolor}};
|
||
</script>
|
||
<div>
|
||
<div class="uk-card uk-card-default uk-card-small uk-card-body">
|
||
{{ if .CanAsk }}
|
||
<!-- jQuery 按需加载(同步,保证下方内联二维码初始化就绪) -->
|
||
<script src="https://cdnjs.snrat.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||
<script src='https://r2.337845818.best/tamabox/cdn/js/remake/easy.qrcode.min.js' type="text/javascript" charset="utf-8"></script>
|
||
<div class="uk-text-center"><div id="boxqrimg"></div></div>
|
||
<script type="text/javascript">
|
||
var options = {
|
||
text: window.location.href,
|
||
width: 200,
|
||
height: 200,
|
||
// 与 Profile 编辑器保持一致:仅当启用自定义前景色时,才把 Qrcodebackcolor 作为前景色;
|
||
// 否则强制黑色 #000000,避免未勾选却显示自定义前景色、与 Profile 预览不一致。
|
||
colorDark: ({{.PageUser.UseCustomQRColor}} ? "{{.PageUser.Qrcodebackcolor}}" : "#000000") || "#000000",
|
||
colorLight: "{{.PageUser.Qrcodecolor}}" || "#FFFFFF",
|
||
dotScale: parseFloat("{{.PageUser.Dotscale}}") || 0.4,
|
||
dotScaleTiming: parseFloat("{{.PageUser.Dotscale}}") || 0.4,
|
||
dotScaleA: parseFloat("{{.PageUser.Dotscale}}") || 0.4,
|
||
correctLevel: QRCode.CorrectLevel.H,
|
||
logo: (function () {
|
||
// ?v=2:击穿曾被无 ACAO 响应污染的浏览器缓存条目;仅对 http(s) 绝对地址追加
|
||
var a = "{{.PageUser.Avatar}}" || "{{.DefaultAvatar}}";
|
||
return a ? (a.indexOf("http") === 0 ? a + "?v=2" : a) : undefined;
|
||
})(),
|
||
logoWidth: 60,
|
||
logoHeight: 60,
|
||
logoBackgroundTransparent: true,
|
||
// 直连 R2 等跨域图片须以 CORS 模式加载,canvas 才不被污染、可正常导出
|
||
crossOrigin: 'anonymous',
|
||
backgroundImage: ("{{.PageUser.BackgroundImage}}" ? "{{.PageUser.BackgroundImage}}" : undefined),
|
||
backgroundImageAlpha: parseFloat("{{.PageUser.Backgroundimagealpha}}") || 0.8,
|
||
autoColor: false,
|
||
PO: "{{.PageUser.Qrcodepdpcolor}}" || "#000000",
|
||
PI: "{{.PageUser.Qrcodepdpcolor}}" || "#000000",
|
||
AO: '',
|
||
AI: '',
|
||
timing: "{{.PageUser.Qrcodepdpcolor}}" || "#000000"
|
||
};
|
||
// 降级渲染:头像(logo)/ 背景图加载慢/失败时先出基础码,探针成功后再升级带 logo 版
|
||
window.tbRenderQR(document.getElementById("boxqrimg"), function () { return options; });
|
||
</script>
|
||
|
||
<p class="uk-text-center uk-text-small">扫码向@{{ .PageUser.Name }}提问<br>{{ if .RegisterOnlyAsk }}{{t .LangCode "ask.registerOnly"}}{{ else }}{{t .LangCode "ask.anonymous"}}{{ end }}</p>
|
||
{{ end }}
|
||
{{template "base/alert" .}}
|
||
{{template "question/new-question-template" .}}
|
||
|
||
<hr class="uk-divider-icon">
|
||
{{ if ne (len .PageQuestions) 0 }}
|
||
<p class="uk-text-left uk-text-muted uk-text-small">{{t .LangCode "ask.history" .PageUser.Name}} ({{ .AnsweredCount }})</p>
|
||
{{ template "question/history-template" . }}
|
||
{{ end }}
|
||
</div>
|
||
</div>
|
||
{{template "base/footer" .}} |