Files
tamabox/templates/question/list.html
T
2026-10-19 11:08:30 +08:00

324 lines
16 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.
{{template "base/header" .}}
<!-- 头像直连 R2:crossorigin 让 favicon 也以 CORS 模式请求,确保浏览器缓存的响应都带 ACAO;
?v=2 击穿历史上被「无 ACAO 响应」污染的缓存条目(R2 对无 Origin 请求的响应无 Vary,可缓存 31 天) -->
<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">
<style>
/* 封面高度(原内联 style,改到类里便于和遮罩一起维护) */
.tb-profile-cover { min-height: 260px; }
/* 投票列表:与探索页"全部投票"一致的列表行样式 */
.profile-votes-list { display: grid; gap: 0; }
.profile-vote-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
min-width: 0;
padding: 14px 16px;
border-bottom: 1px solid var(--tb-border);
text-decoration: none;
}
.profile-vote-item:first-child { border-top: 1px solid var(--tb-border); }
.profile-vote-item:hover { background: var(--tb-surface-hover); text-decoration: none; }
.profile-vote-content { min-width: 0; }
.profile-vote-title {
display: block;
overflow: hidden;
color: var(--tb-text);
font-size: 0.98rem;
font-weight: 600;
line-height: 1.45;
text-overflow: ellipsis;
white-space: nowrap;
}
.profile-vote-meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 7px;
margin-top: 8px;
}
.profile-vote-meta .uk-label { font-size: 0.72rem; line-height: 1.6; }
.profile-vote-action {
flex: 0 0 auto;
color: var(--tb-primary);
font-size: 0.82rem;
white-space: nowrap;
}
html[data-theme="dark"] .profile-vote-item { border-color: var(--tb-border); }
html[data-theme="dark"] .profile-vote-title { color: var(--tb-text); }
html[data-theme="dark"] .profile-vote-item:hover { background: rgba(78, 168, 245, 0.10); }
/* 个人主页 Tab:与探索页一致的胶囊切换样式 */
/* 个人主页 Tab:全宽等分,置于主体顶部,作为一级导航(移动端整行可点) */
.profile-tabs {
display: flex;
gap: 4px;
padding: 4px;
margin-top: 20px;
margin-bottom: 18px;
border: 1px solid var(--tb-border);
border-radius: 9px;
background: var(--tb-surface-2);
}
.profile-tab {
flex: 1;
border: 0;
border-radius: 6px;
padding: 9px 15px;
background: transparent;
color: var(--tb-text-muted);
cursor: pointer;
font-size: 0.9rem;
transition: background 0.2s ease, color 0.2s ease;
}
.profile-tab:hover { color: var(--tb-primary); }
.profile-tab.is-active {
background: var(--tb-surface);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10);
color: var(--tb-primary);
font-weight: 600;
}
/* 功能关闭时置灰禁用的 Tab(如投票功能关闭) */
.profile-tab.is-disabled,
.profile-tab:disabled {
cursor: not-allowed;
color: var(--tb-text-muted);
opacity: 0.7;
}
.profile-tab.is-disabled:hover { color: var(--tb-text-muted); }
.profile-panel[hidden] { display: none !important; }
html[data-theme="dark"] .profile-tabs {
border-color: var(--tb-border);
background: var(--tb-surface-2);
}
html[data-theme="dark"] .profile-tab { color: var(--tb-text-muted); }
html[data-theme="dark"] .profile-tab.is-active { background: var(--tb-surface); color: var(--tb-primary); }
html[data-theme="dark"] .profile-tab.is-disabled { color: var(--tb-text-muted); opacity: 0.55; }
</style>
<div class="uk-card uk-card-default uk-text-center">
<div class="tb-profile-cover uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light{{ if .PageUser.Background }} tb-cover{{ end }}" 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}}";
// 封面上的文字颜色由箱主自选,深浅不定:按用户名颜色的亮度决定遮罩方向
// (深字上面压浅色遮罩、浅字上面压深色遮罩),保证任何配色都能读。
// 无背景图时页面没有 .tb-cover,这里什么都不做,保持原样。
(function () {
var cover = document.querySelector('.tb-cover');
var el = document.getElementById('usernamecolor');
if (!cover || !el) return;
var m = window.getComputedStyle(el).color.match(/\d+/g);
if (!m || m.length < 3) return;
var lum = (0.299 * m[0] + 0.587 * m[1] + 0.114 * m[2]) / 255;
if (lum > 0.62) cover.classList.add('tb-cover-dark');
})();
</script>
<div>
<div class="uk-card uk-card-default uk-card-small uk-card-body">
{{ if .CanAsk }}
<!-- jQuery 已改为按需加载:defer 按文档顺序先于 easy.qrcode 执行,保证就绪 -->
<script defer src="https://cdnjs.snrat.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script defer src='https://r2.337845818.best/tamabox/cdn/js/remake/easy.qrcode.min.js' type="text/javascript" charset="utf-8"></script>
<center><div id="boxqrimg"></div></center>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
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">{{t .LangCode "ask.scan" .PageUser.Name}}<br>{{ if .RegisterOnlyAsk }}{{t .LangCode "ask.registerOnly"}}{{ else }}{{t .LangCode "ask.anonymous"}}{{ end }}</p>
<div class="uk-text-center uk-margin-small-top">
<a id="share-btn" href="/_/{{ .PageUser.Domain }}/share-card" download class="uk-button uk-button-default uk-button-small">
📤 {{t .LangCode "ask.share"}}
</a>
</div>
<div id="share-loading-overlay" style="display:none; position: fixed; top:0; left:0; width:100%; height:100%; background: rgba(255,255,255,0.85); z-index:9999;">
<div style="display:flex; flex-direction:column; align-items:center; justify-content:center; height:100%;">
<div uk-spinner="ratio: 2" class="uk-margin-bottom"></div>
<p class="uk-text-large uk-text-muted">{{t .LangCode "ask.generating"}}</p>
</div>
</div>
<script>
(function() {
var btn = document.getElementById('share-btn');
var overlay = document.getElementById('share-loading-overlay');
if (!btn || !overlay) return;
btn.addEventListener('click', function(e) {
e.preventDefault();
overlay.style.display = 'block';
btn.style.pointerEvents = 'none';
fetch(btn.href)
.then(function(response) {
if (!response.ok) throw new Error('{{t .LangCode "ask.networkError"}}');
return response.blob();
})
.then(function(blob) {
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = '{{t .LangCode "ask.shareFilename"}}';
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 100);
})
.catch(function(err) {
alert('{{t .LangCode "ask.genFailed"}}');
console.error(err);
})
.finally(function() {
overlay.style.display = 'none';
btn.style.pointerEvents = 'auto';
});
});
})();
</script>
{{ end }}
{{template "base/alert" .}}
<!-- 提问 / 投票 切换:默认显示提问,支持 ?tab=votes 直达(服务端初始态)与 #votes hash 覆盖 -->
<div class="profile-tabs" role="tablist">
<button type="button" class="profile-tab{{ if eq .ActiveProfileTab "questions" }} is-active{{ end }}" data-profile-tab="questions" role="tab" aria-selected="{{ if eq .ActiveProfileTab "questions" }}true{{ else }}false{{ end }}">{{t .LangCode "explore.questionsTab"}}</button>
{{ if .VoteEnabled }}
<button type="button" class="profile-tab{{ if eq .ActiveProfileTab "votes" }} is-active{{ end }}" data-profile-tab="votes" role="tab" aria-selected="{{ if eq .ActiveProfileTab "votes" }}true{{ else }}false{{ end }}">{{t .LangCode "explore.votesTab"}}</button>
{{ else }}
<!-- 投票功能关闭:保留 Tab 展示但置灰禁用,hover 提示原因 -->
<button type="button" class="profile-tab is-disabled" disabled aria-disabled="true" uk-tooltip="{{ .VoteClosedMessage }}">{{t .LangCode "explore.votesTab"}} <span uk-icon="icon: lock; ratio: 0.8"></span></button>
{{ end }}
</div>
<div class="profile-panel" data-profile-panel="questions"{{ if eq .ActiveProfileTab "votes" }} hidden{{ end }}>
{{template "question/new-question-template" .}}
{{ 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 class="profile-panel" data-profile-panel="votes"{{ if ne .ActiveProfileTab "votes" }} hidden{{ end }}>
{{ if .PageVotes }}
<!-- 匿名投票板块:箱主"进行中"的公开投票(列表行样式,与探索页"全部投票"一致) -->
<div class="profile-votes-list">
{{ range .PageVotes }}
<a href="/vote/{{ .LinkToken }}" class="profile-vote-item">
<div class="profile-vote-content">
<span class="profile-vote-title" title="{{ .Title }}">{{ .Title }}</span>
<span class="profile-vote-meta">
{{ if eq .Type "single" }}<span class="uk-label uk-label-primary">{{t $.LangCode "vote.typeSingle"}}</span>{{ end }}
{{ if eq .Type "multiple" }}<span class="uk-label uk-label-primary">{{t $.LangCode "vote.typeMultiple"}}</span>{{ end }}
{{ if eq .Type "rating" }}<span class="uk-label uk-label-primary">{{t $.LangCode "vote.typeRating"}}</span>{{ end }}
{{ if eq .Type "rank" }}<span class="uk-label uk-label-primary">{{t $.LangCode "vote.typeRank"}}</span>{{ end }}
{{ if eq .Type "form" }}<span class="uk-label uk-label-primary">{{t $.LangCode "vote.typeForm"}}</span>{{ end }}
<span class="uk-text-meta">{{ .CreatedAt.Format "2006-01-02" }}</span>
</span>
</div>
<span class="profile-vote-action">{{t $.LangCode "vote.page.goVote"}} <span uk-icon="icon: arrow-right; ratio: .8"></span></span>
</a>
{{ end }}
</div>
{{ else }}
<div class="uk-alert uk-alert-primary uk-margin-remove-top">{{t .LangCode "explore.noVotes"}}</div>
{{ end }}
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var tabs = document.querySelectorAll('[data-profile-tab]');
var panels = document.querySelectorAll('[data-profile-panel]');
function showPanel(name) {
tabs.forEach(function(tab) {
var active = tab.dataset.profileTab === name;
tab.classList.toggle('is-active', active);
tab.setAttribute('aria-selected', active ? 'true' : 'false');
});
panels.forEach(function(panel) {
panel.hidden = panel.dataset.profilePanel !== name;
});
if (window.history && window.history.replaceState) {
window.history.replaceState({}, document.title, window.location.pathname + window.location.search + (name === 'votes' ? '#votes' : ''));
}
}
tabs.forEach(function(tab) {
tab.addEventListener('click', function() { showPanel(tab.dataset.profileTab); });
});
// 仅当投票 Tab 可点击(功能开启)时才响应 #votes hash,避免投票关闭时切到空面板
if (window.location.hash === '#votes' && document.querySelector('[data-profile-tab="votes"]')) {
showPanel('votes');
}
});
</script>
{{template "base/footer" .}}