Files
tamabox/outputs/preview-profile-light.html
T
2026-10-19 15:23:11 +08:00

2023 lines
71 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">
<title>预览 15:15 · 设置</title>
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
<script>
(function () {
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
})();
</script>
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
<link rel="stylesheet" href="/static/css/base.css?v="/>
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/waline/2.15.8/waline.js"></script>
<script src="/recaptcha/api.js" async defer></script>
<script>function onSubmit() {document.getElementById('form').submit();}</script>
<meta property="og:site_name" content="狼的提问箱 | 匿名提问箱" />
<meta property="og:type" content="website" />
<meta property="og:title" content="狼的提问箱 | 匿名提问箱" />
<meta property="og:url" content="" />
<meta property="og:description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。" />
<meta itemprop="image" content="https://r2.337845818.best/tamabox/tamabox_low.png"/>
<meta name="msapplication-TileImage" content="https://r2.337845818.best/tamabox/tamabox_low.png"/>
<link rel="shortcut icon" href="https://r2.337845818.best/tamabox/tamabox_low.png" />
<link rel="apple-touch-icon" href="https://r2.337845818.best/tamabox/tamabox_low.png"/>
<link rel="icon" sizes="192x192" href="https://r2.337845818.best/tamabox/tamabox_low.png">
<meta name="twitter:image:src" content="https://r2.337845818.best/tamabox/tamabox_low.png" />
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
<script>
window.addEventListener("load", function () {
var s = document.createElement("script");
s.src = "https://mami.shiroko.one/tamami.js";
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
document.body.appendChild(s);
});
</script>
</head>
<body>
<script>
window.tbRenderQR = function (el, getOptions) {
if (!el || typeof QRCode === 'undefined') return;
var opts = getOptions();
function remoteOf(o, key) {
var v = o[key];
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
}
var good = window._tbQrGood || (window._tbQrGood = {});
var bad = window._tbQrBad || (window._tbQrBad = {});
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
var layers = [
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
} },
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
} }
];
var needProbe = false;
for (var i = 0; i < layers.length; i++) {
layers[i].st = layerState(layers[i].url);
if (layers[i].st === null) needProbe = true;
}
function paint(states) {
var o = {};
for (var k in opts) o[k] = opts[k];
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
el.innerHTML = '';
new QRCode(el, o);
}
var initStates = [];
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
paint(initStates);
if (!needProbe) return;
var pending = 0, cross = opts.crossOrigin || 'anonymous';
layers.forEach(function (L) {
if (L.st !== null) return;
pending++;
var im = new Image();
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
if (cross) im.crossOrigin = cross;
im.src = L.url;
});
function onDone() {
if (--pending > 0) return;
var finalStates = [];
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
var changed = false;
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
if (changed) paint(finalStates);
}
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
};
</script>
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
<div class="uk-navbar-center">
<div class="uk-navbar-center-left">
<div>
<ul class="uk-navbar-nav">
<li><a href="/explore">探索</a></li>
<li><a href="/_/tester">我的</a></li>
</ul>
</div>
</div>
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>的提问箱</a>
<div class="uk-navbar-center-right">
<div>
<ul class="uk-navbar-nav">
<li><a href="/user/questions">提问</a></li>
</ul>
<ul class="uk-navbar-nav">
<li><a href="/user/profile">设置</a></li>
</ul>
<ul class="uk-navbar-nav tb-nav-utils">
<li>
<a href="#" aria-label="语言" title="语言"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/><path d="M3.2 9h17.6M3.2 15h17.6"/><ellipse cx="12" cy="12" rx="4" ry="9"/></svg></a>
<div class="uk-navbar-dropdown" uk-drop="mode: click; pos: bottom-right">
<ul class="uk-nav uk-navbar-dropdown-nav">
<li class="uk-active">
<a href="/i18n/zh-CN?to=%3Cnil%3E">简体中文</a>
</li>
</ul>
</div>
</li>
</ul>
<ul class="uk-navbar-nav tb-nav-utils">
<li>
<a href="#" id="theme-toggle" title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
</a>
</li>
</ul>
</div>
</div>
</div>
</nav>
<script>
document.addEventListener("DOMContentLoaded", function() {
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦‍⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕‍🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
const placeholder = document.querySelector('.emoji-placeholder');
if (placeholder) {
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
}
});
</script>
<div id="tb-mobile-utils">
<select id="mobile-lang-select" class="uk-select uk-form-small" aria-label="语言">
<option value="zh-CN" selected>简体中文</option>
</select>
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
</button>
</div>
<script>
(function() {
var THEME_COOKIE = 'theme';
function getTheme() {
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
return m ? m[1] : '';
}
function applyTheme(theme) {
if (theme === 'dark') {
document.documentElement.setAttribute('data-theme', 'dark');
} else {
document.documentElement.removeAttribute('data-theme');
}
}
function toggleTheme() {
var next = getTheme() === 'dark' ? 'light' : 'dark';
applyTheme(next);
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
}
document.addEventListener('DOMContentLoaded', function() {
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
buttons.forEach(function(btn) {
btn.addEventListener('click', function(e) {
e.preventDefault();
toggleTheme();
});
});
var langSel = document.getElementById('mobile-lang-select');
if (langSel) {
langSel.addEventListener('change', function() {
if (!this.value) return;
var to = window.location.pathname + window.location.search;
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
});
}
});
})();
</script>
<div class="uk-container uk-container-xsmall">
<script src="https://cdnjs.cloudflare.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>
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/lib/pickr/1.10.1/nano.min.css"/>
<script src="https://r2.337845818.best/tamabox/cdn/lib/pickr/1.10.1/pickr.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.min.js"></script>
<style>
.range-input-group {
display: flex;
align-items: center;
gap: 10px;
}
.range-input-group input[type="range"] {
flex: 1;
}
.range-input-group input[type="number"] {
width: 70px;
}
.range-input-group .range-value {
min-width: 40px;
text-align: right;
}
.color-picker {
display: inline-block;
vertical-align: middle;
}
.preview-card {
background: #fff;
padding: 20px;
border: 1px solid var(--tb-border);
border-radius: 8px;
text-align: center;
}
.preview-card .qrcode-wrapper {
width: 100%;
max-width: 220px;
margin: 0 auto;
}
.theme-btn {
margin: 2px;
font-size: 0.8rem;
}
.social-item {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.social-item label.checkbox-label {
margin: 0;
white-space: nowrap;
}
.social-item input[type="text"] {
flex: 1;
}
.social-item input[type="text"]:invalid {
border-color: #f0506e;
}
@media (max-width: 640px) {
.preview-card {
margin-top: 20px;
}
}
.profile-tabs {
display: flex;
gap: 4px;
padding: 4px;
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 8px;
background: transparent;
color: var(--tb-text-muted);
cursor: pointer;
font-size: 0.9rem;
white-space: nowrap;
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;
}
.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); }
.feat-card {
display: flex;
flex-direction: column;
gap: 12px;
padding: 16px;
border: 1px solid var(--tb-border);
border-radius: 8px;
background: #fff;
}
.feat-card-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.feat-card-head h3 { font-size: 1.05rem; }
.feat-status {
flex: 0 0 auto;
font-size: 0.72rem;
line-height: 1.6;
padding: 0 8px;
border-radius: 2px;
}
.feat-status.is-open { background: #32d296; color: #fff; }
.feat-status.is-closed { background: #f0506e; color: #fff; }
.feat-hint {
display: block;
font-size: 0.78rem;
line-height: 1.5;
color: var(--tb-text-muted);
}
.feat-field { display: block; }
.feat-field > label > span {
display: block;
margin-bottom: 4px;
font-size: 0.875rem;
}
.feat-field-label {
display: block;
margin-bottom: 4px;
font-size: 0.875rem;
}
.feat-modes {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 4px;
}
.is-hidden { display: none !important; }
.feat-field input[type="datetime-local"],
.feat-field input[type="number"] { width: 100%; }
.feat-schedule { display: flex; flex-direction: column; gap: 8px; }
.feat-schedule-days {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.feat-day {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 3px 8px;
border: 1px solid var(--tb-border);
border-radius: 999px;
font-size: 0.78rem;
color: var(--tb-text-secondary);
cursor: pointer;
user-select: none;
}
.feat-day input { margin: 0; }
.feat-day.is-on {
border-color: var(--tb-primary);
background: rgba(30, 135, 240, 0.08);
color: var(--tb-primary);
}
.feat-schedule-times {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.feat-schedule-times label {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.82rem;
color: var(--tb-text-secondary);
}
.feat-schedule-times input[type="time"] {
width: 130px;
padding: 4px 8px;
border: 1px solid var(--tb-border);
border-radius: 4px;
}
html[data-theme="dark"] .feat-day {
border-color: var(--tb-border);
color: var(--tb-text-muted);
}
html[data-theme="dark"] .feat-day.is-on {
border-color: var(--tb-primary);
background: rgba(30, 135, 240, 0.14);
color: var(--tb-primary);
}
html[data-theme="dark"] .feat-schedule-times input[type="time"] {
border-color: var(--tb-border);
background: var(--tb-surface);
color: var(--tb-text);
}
.feat-quota-line {
font-size: 0.82rem;
color: var(--tb-text-secondary);
text-align: center;
}
.feat-actions {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 8px;
align-items: center;
margin-top: auto;
}
.feat-actions form { margin: 0; }
html[data-theme="dark"] .feat-card {
border-color: var(--tb-border);
background: var(--tb-surface);
}
html[data-theme="dark"] .feat-card-head h3 { color: var(--tb-text); }
html[data-theme="dark"] .feat-hint,
html[data-theme="dark"] .feat-quota-line { color: var(--tb-text-muted); }
.chat-zone .feat-card {
padding: 0;
border: 0;
background: transparent;
}
.chat-zone hr { margin: 14px 0; }
.chat-zone .uk-legend {
font-size: 1.05rem;
margin: 0 0 10px;
}
.tb-tag-box {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
padding: 6px 8px;
border: 1px solid var(--tb-border);
border-radius: 4px;
background: #fff;
cursor: text;
}
.tb-tag-box:focus-within { border-color: var(--tb-primary); }
.tb-tag-chip {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 2px 8px;
border-radius: 3px;
background: var(--tb-primary);
color: #fff;
font-size: 0.875rem;
line-height: 1.8;
}
.tb-tag-chip button {
padding: 0;
border: 0;
background: transparent;
color: inherit;
font-size: 1rem;
line-height: 1;
cursor: pointer;
opacity: 0.75;
}
.tb-tag-chip button:hover { opacity: 1; }
.tb-tag-entry {
flex: 1;
min-width: 120px;
border: 0;
outline: 0;
background: transparent;
color: inherit;
font-size: 0.875rem;
}
.tb-tag-meta {
display: flex;
justify-content: space-between;
gap: 8px;
margin-top: 4px;
font-size: 0.75rem;
color: var(--tb-text-muted);
}
.tb-tag-error { color: #f0506e; }
html[data-theme="dark"] .tb-tag-box {
border-color: var(--tb-border);
background: var(--tb-surface);
color: var(--tb-text);
}
html[data-theme="dark"] .tb-tag-entry { color: var(--tb-text); }
html[data-theme="dark"] .tb-tag-meta { color: var(--tb-text-muted); }
.tb-pcard {
background: var(--tb-surface);
border: 1px solid var(--tb-border);
border-radius: 10px;
padding: 13px 14px 8px;
margin-bottom: 12px;
}
.tb-pcard-title {
margin: 0 0 10px;
font-size: 1.02rem;
font-weight: 600;
}
.profile-panel .uk-margin { margin-bottom: 12px; }
.tb-pcard-title .tb-pcard-extra {
float: right;
font-size: 0.76rem;
font-weight: 400;
color: var(--tb-text-muted);
line-height: 1.6;
}
.tb-media-row {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: flex-start;
gap: 14px 32px;
}
.tb-media-item {
flex: 0 0 280px;
max-width: 100%;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.tb-media-frame {
display: block;
flex: none;
border: 1px solid var(--tb-border);
background: #f7f7f7;
overflow: hidden;
}
.tb-media-frame.tb-frame-avatar {
width: 150px;
height: 150px;
border-radius: 50%;
}
.tb-media-frame.tb-frame-bg {
width: 267px;
max-width: 100%;
aspect-ratio: 16 / 9;
border-radius: 8px;
}
.tb-media-frame img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.tb-ratio-tag {
display: inline-block;
margin: 8px 0 0;
font-size: 0.72rem;
line-height: 1;
color: var(--tb-text-secondary);
background: #f4f4f4;
border: 1px solid var(--tb-border);
border-radius: 999px;
padding: 4px 9px;
}
.tb-file-hint {
display: block;
font-size: 0.78rem;
line-height: 1.5;
color: var(--tb-text-muted);
margin-top: 6px;
}
.tb-media-actions { margin-top: 10px; }
.tb-media-actions .uk-button { min-width: 150px; }
.tb-card-save,
.tb-media-save {
margin-top: 6px;
text-align: center;
}
.tb-account-actions { margin-top: 0; }
.tb-account-pair {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 10px 14px;
padding: 8px 0;
}
.tb-account-pair form { margin: 0; }
.tb-account-note {
display: block;
margin: 0 0 10px;
text-align: center;
font-size: 0.78rem;
line-height: 1.6;
color: var(--tb-text-muted);
}
.tb-account-note:last-child { margin-bottom: 0; }
.tb-crop-stage {
max-width: 100%;
text-align: center;
}
.tb-crop-stage img {
display: inline-block;
max-width: 100%;
max-height: 58vh;
}
#media-crop-modal .uk-modal-dialog { width: 640px; }
.tb-crop-hint { margin-top: 12px; }
html[data-theme="dark"] .tb-pcard-title { color: var(--tb-text); }
html[data-theme="dark"] .tb-pcard-extra,
html[data-theme="dark"] .tb-file-hint { color: var(--tb-text-muted); }
html[data-theme="dark"] .tb-media-frame {
border-color: var(--tb-border);
background: var(--tb-surface-2);
}
html[data-theme="dark"] .tb-ratio-tag {
color: var(--tb-text-muted);
border-color: var(--tb-border);
background: var(--tb-surface-2);
}
html[data-theme="dark"] .tb-account-note { color: var(--tb-text-muted); }
html[data-theme="dark"] .tb-pcard .uk-accordion-title {
color: var(--tb-text);
}
html[data-theme="dark"] .tb-pcard .uk-accordion-title:hover {
color: var(--tb-primary);
}
@media (max-width: 640px) {
.tb-pcard { padding: 13px 12px 8px; }
.tb-media-row { gap: 14px; }
.tb-media-item { flex-basis: 100%; width: auto; max-width: none; }
.tb-media-frame.tb-frame-avatar { width: 120px; height: 120px; }
.tb-media-frame.tb-frame-bg { width: 100%; max-width: none; }
.tb-media-actions .uk-button,
.tb-media-save .uk-button,
.tb-card-save .uk-button { width: 100%; }
}
</style>
<div id="media-crop-modal" uk-modal>
<div class="uk-modal-dialog">
<button class="uk-modal-close-default" type="button" uk-close></button>
<div class="uk-modal-header">
<h2 class="uk-modal-title">裁剪图片</h2>
</div>
<div class="uk-modal-body">
<div class="tb-crop-stage">
<img id="media-crop-image" alt="">
</div>
<p class="uk-text-meta tb-crop-hint" id="media-crop-hint"></p>
</div>
<div class="uk-modal-footer uk-text-right">
<button type="button" class="uk-button uk-button-default uk-modal-close">取消</button>
<button type="button" class="uk-button uk-button-primary" id="media-crop-confirm">确认裁剪</button>
</div>
</div>
</div>
<div class="profile-tabs" role="tablist">
<button type="button" class="profile-tab" data-profile-tab="account" role="tab" aria-selected="false">用户设置</button>
<button type="button" class="profile-tab" data-profile-tab="question" role="tab" aria-selected="false">提问</button>
<button type="button" class="profile-tab" data-profile-tab="chat" role="tab" aria-selected="false">私聊</button>
<button type="button" class="profile-tab" data-profile-tab="vote" role="tab" aria-selected="false">投票</button>
<button type="button" class="profile-tab is-active" data-profile-tab="security" role="tab" aria-selected="true">防护设置</button>
</div>
<div class="profile-panel" data-profile-panel="account" hidden>
<form id="profile-form" method="post" enctype="multipart/form-data" action="/user/profile/update">
<input type="hidden" name="_csrf" value="x">
<section class="tb-pcard">
<h3 class="tb-pcard-title">基础资料</h3>
<div class="uk-margin">
<label class="uk-form-label">电子邮箱</label>
<input class="uk-input" type="text" disabled value="[email protected]">
</div>
<div class="uk-margin">
<label class="uk-form-label">昵称</label>
<input name="name" class="uk-input" type="text" value="测试箱主">
</div>
<div class="uk-margin">
<label class="uk-form-label">昵称颜色</label>
<div class="color-picker" data-default="#000"></div>
<input type="hidden" name="usernamecolor" value="#000">
</div>
<div class="uk-margin">
<label class="uk-form-label">提问箱介绍</label>
<input name="intro" class="uk-input" type="text" value="">
</div>
<div class="uk-margin">
<label class="uk-form-label">提问箱介绍颜色</label>
<div class="color-picker" data-default="#666"></div>
<input type="hidden" name="introcolor" value="#666">
</div>
<div class="uk-margin">
<label class="uk-form-label">界面语言</label>
<select name="language" class="uk-select">
<option value="zh-CN" selected>简体中文</option>
</select>
<span class="uk-text-small uk-text-muted">选择访客访问你的提问箱时显示的语言(后台页面跟随此设置)</span>
</div>
<div class="uk-margin">
<label class="uk-form-label">新提问通知</label>
<label>
<input name="notify_email" class="uk-checkbox" type="checkbox"
checked>
<span class="uk-text-small"> 邮件</span>
</label>
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">保存基础资料</button>
</div>
</section>
<section class="tb-pcard">
<h3 class="tb-pcard-title">头像与背景</h3>
<div class="tb-media-row">
<div class="tb-media-item">
<span class="tb-media-frame tb-frame-avatar">
<img id="avatar-prev" alt="" src="">
</span>
<span class="tb-ratio-tag">1:1</span>
<div class="tb-media-actions">
<input type="file" name="avatar" id="avatar-input" accept="image/*" class="uk-hidden">
<button type="button" class="uk-button uk-button-default uk-button-small" data-pick-image="avatar">更换头像</button>
</div>
<span class="tb-file-hint">裁剪框已锁定为 1:1 正方形</span>
</div>
<div class="tb-media-item">
<span class="tb-media-frame tb-frame-bg">
<img id="bg-prev" alt="">
</span>
<span class="tb-ratio-tag">16:9</span>
<div class="tb-media-actions">
<input type="file" name="background" id="background-input" accept="image/*" class="uk-hidden">
<button type="button" class="uk-button uk-button-default uk-button-small" data-pick-image="background">更换背景</button>
</div>
<span class="tb-file-hint">裁剪框已锁定为 16:9 宽屏</span>
</div>
</div>
<div class="tb-media-save">
<button type="submit" class="uk-button uk-button-primary">保存头像与背景</button>
</div>
</section>
<section class="tb-pcard">
<ul class="uk-accordion" uk-accordion="multiple: true">
<li class="uk-open">
<a class="uk-accordion-title" href="#">二维码样式</a>
<div class="uk-accordion-content">
<div class="uk-grid" uk-grid>
<div class="uk-width-2-3@m uk-width-1-1">
<div class="uk-margin">
<label class="uk-form-label">二维码背景色(亮色部分)</label>
<div class="color-picker" data-default="#000"></div>
<input type="hidden" name="qrcodecolor" value="#000">
</div>
<div class="uk-margin">
<label class="uk-form-label">二维码探测图形颜色(边角方形)</label>
<div class="color-picker" data-default="#000"></div>
<input type="hidden" name="qrcodepdpcolor" value="#000">
</div>
<div class="uk-margin">
<label class="uk-form-label">二维码前景色</label>
<div class="uk-margin-small">
<label>
<input type="checkbox" id="use-custom-fg" name="use_custom_qr_color"
>
启用自定义前景色(否则自动匹配)
</label>
</div>
<div class="color-picker" data-default="#fff"></div>
<input type="hidden" name="qrcodebackcolor" value="#fff">
<span class="uk-text-small uk-text-muted">仅在启用时生效,否则颜色由系统自动生成</span>
</div>
<div class="uk-margin">
<label class="uk-form-label">二维码点大小 (←小 大→)</label>
<div class="range-input-group">
<input name="dotscale" class="uk-range" type="range" step="0.01" min="0" max="1" value="0.35">
<span class="range-value" id="dotscale-val">0.35</span>
<input class="uk-input uk-form-width-xsmall" type="number" step="0.01" min="0" max="1" id="dotscale-num" value="0.35">
</div>
</div>
<div class="uk-margin">
<label class="uk-form-label">二维码背景透明度 (←不透明 很透明→)</label>
<div class="range-input-group">
<input name="backgroundimagealpha" class="uk-range" type="range" step="0.01" min="0" max="1" value="0.8">
<span class="range-value" id="bgalpha-val">0.8</span>
<input class="uk-input uk-form-width-xsmall" type="number" step="0.01" min="0" max="1" id="bgalpha-num" value="0.8">
</div>
</div>
<div class="uk-margin">
<label class="uk-form-label">二维码背景图</label>
<div uk-form-custom="target: true">
<input type="file" name="backgroundimage" accept="image/*" id="backgroundimage-file">
<input class="uk-input uk-form-width-large" type="text" placeholder="上传二维码背景(颜色过深的背景会导致二维码无法识别)" disabled>
</div>
<span class="uk-text-small uk-text-muted">选择图片后预览将即时更新</span>
</div>
</div>
<div class="uk-width-1-3@m uk-width-1-1">
<div class="preview-card">
<h4 class="uk-text-center">实时预览</h4>
<div class="qrcode-wrapper" id="qrcode-preview"></div>
<hr class="uk-margin-small">
<div class="uk-text-small">
<strong>预设主题</strong>
<div class="uk-flex uk-flex-wrap uk-flex-center">
<button type="button" class="uk-button uk-button-default uk-button-small theme-btn" data-theme="default">默认</button>
<button type="button" class="uk-button uk-button-default uk-button-small theme-btn" data-theme="dark">暗夜</button>
<button type="button" class="uk-button uk-button-default uk-button-small theme-btn" data-theme="ocean">海洋</button>
<button type="button" class="uk-button uk-button-default uk-button-small theme-btn" data-theme="sunset">日落</button>
</div>
</div>
<div class="uk-margin-small-top">
<button type="button" id="reset-qr-defaults" class="uk-button uk-button-default uk-button-small uk-width-1-1">🔄 恢复默认值</button>
</div>
<p class="uk-text-meta uk-margin-small-top">调整仅用于预览,最终效果点击「保存修改」后生效</p>
</div>
</div>
</div>
</div>
</li>
</ul>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">保存二维码样式</button>
</div>
</section>
<section class="tb-pcard">
<ul class="uk-accordion" uk-accordion="multiple: true">
<li class="uk-open">
<a class="uk-accordion-title" href="#">社交信息设置</a>
<div class="uk-accordion-content">
<span class="uk-text-muted">勾选后填写主页地址(无需 https://),未勾选的项将不会在前台显示。</span>
<div class="uk-margin social-item">
<label class="checkbox-label">
<input type="checkbox" class="social-enable" data-target="acfunlink"> 启用 AcFun
</label>
<input name="acfunlink" class="uk-input social-input" type="text" placeholder="acfun.cn/xxx" value="">
</div>
<div class="uk-margin social-item">
<label class="checkbox-label">
<input type="checkbox" class="social-enable" data-target="bililink"> 启用 Bilibili
</label>
<input name="bililink" class="uk-input social-input" type="text" placeholder="bilibili.com/xxx" value="">
</div>
<div class="uk-margin social-item">
<label class="checkbox-label">
<input type="checkbox" class="social-enable" data-target="weibolink"> 启用 微博
</label>
<input name="weibolink" class="uk-input social-input" type="text" placeholder="weibo.com/xxx" value="">
</div>
<div class="uk-margin social-item">
<label class="checkbox-label">
<input type="checkbox" class="social-enable" data-target="xiaohongshulink"> 启用 小红书
</label>
<input name="xiaohongshulink" class="uk-input social-input" type="text" placeholder="xiaohongshu.com/xxx" value="">
</div>
<div class="uk-margin social-item">
<label class="checkbox-label">
<input type="checkbox" class="social-enable" data-target="bloglink"> 启用 个人博客
</label>
<input name="bloglink" class="uk-input social-input" type="text" placeholder="example.com" value="">
</div>
</div>
</li>
</ul>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">保存社交链接</button>
</div>
</section>
<section class="tb-pcard">
<h3 class="tb-pcard-title">修改密码</h3>
<div class="uk-margin">
<label class="uk-form-label">旧密码</label>
<input name="old_password" class="uk-input" type="password" placeholder="修改密码使用,留空则不修改" autocomplete="current-password">
</div>
<div class="uk-margin">
<label class="uk-form-label">新密码</label>
<input name="new_password" class="uk-input" type="password" placeholder="6-64 位,留空则不修改" autocomplete="new-password">
</div>
<p class="uk-text-small uk-text-muted">保存后当前会话立即失效,需使用新密码重新登录</p>
<hr class="uk-margin-small">
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">确认修改密码</button>
</div>
</section>
</form>
<section class="tb-pcard">
<h3 class="tb-pcard-title">标签设置</h3>
<form method="post" action="/user/tags/update">
<input type="hidden" name="_csrf" value="x">
<div class="uk-margin">
<label class="uk-form-label">标签(最多5个,每个最多5字,回车或逗号分隔)</label>
<input name="tags" class="uk-input" type="text" value="杂谈" placeholder="例如:动漫,音乐,游戏"
data-tb-tag-input
data-tb-max="5" data-tb-max-len="5"
data-tb-msg-too-many="标签不能超过 5 个"
data-tb-msg-too-long="每个标签不能超过 5 个字符:%s"
data-tb-msg-duplicate="已存在,已忽略"
data-tb-msg-hint="输入后按回车或逗号添加">
</div>
<div class="uk-margin">
<label>
<input name="show_in_home" class="uk-checkbox" type="checkbox" >
<span class="uk-text-small"> 在首页展示我的标签(允许其他用户通过标签搜索到我)</span>
</label>
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">更新标签</button>
</div>
</form>
</section>
<section class="tb-pcard">
<h3 class="tb-pcard-title">账号设置</h3>
<div class="tb-account-actions">
<div class="tb-account-pair">
<form action="/user/profile/export" method="post" target="_blank" data-tb-skip-submit-feedback="1">
<input type="hidden" name="_csrf" value="x">
<button class="uk-button uk-button-default">导出数据</button>
</form>
<form action="/user/profile/export-json" method="post" target="_blank" data-tb-skip-submit-feedback="1">
<input type="hidden" name="_csrf" value="x">
<button class="uk-button uk-button-default">导出JSON</button>
</form>
</div>
<span class="tb-account-note">您可以导出您在 狼的提问箱 | 匿名提问箱 中的所有个人数据,包括你的基本信息、收到的问题以及回答。 包含提问、回答、追问与私聊记录,可完整备份或迁移。</span>
<div class="tb-account-pair">
<form method="post" action="/user/logout">
<input type="hidden" name="_csrf" value="x">
<button type="submit" class="uk-button uk-button-danger">退出登录</button>
</form>
<a class="uk-button uk-button-danger" href="/user/profile/deactivate">停用我的账号</a>
</div>
<span class="tb-account-note">您随时可以选择停用您的账号。停用后,您的账号将无法登录,您的提问箱页面以及提问将无法访问,其他人也无法再给您发送新的提问。<b>该操作无法撤销!请谨慎操作!</b></span>
</div>
</section>
<section class="tb-pcard">
<h3 class="tb-pcard-title">主题外观</h3>
<form method="post" action="/user/profile/theme">
<input type="hidden" name="_csrf" value="x">
<p class="tb-theme-hint">仅对提问箱页面生效,站内其它页面保持默认外观。</p>
<div class="tb-theme-grid">
<label class="tb-theme-opt">
<input class="uk-radio" type="radio" name="theme" value="">
<span class="tb-theme-swatch" style="background: linear-gradient(135deg, var(--tb-surface-2) 0 55%, var(--tb-border) 55% 100%)"></span>
<span class="tb-theme-name">跟随站点默认</span>
</label>
<label class="tb-theme-opt">
<input class="uk-radio" type="radio" name="theme" value="default">
<span class="tb-theme-swatch"></span>
<span class="tb-theme-name">基础外观</span>
</label>
<label class="tb-theme-opt">
<input class="uk-radio" type="radio" name="theme" value="sakura" checked>
<span class="tb-theme-swatch" style="background: ZgotmplZ"></span>
<span class="tb-theme-name">樱花</span>
</label>
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">保存主题</button>
</div>
</form>
</section>
</div>
<div class="profile-panel" data-profile-panel="question" hidden>
</div>
<div class="profile-panel" data-profile-panel="chat" hidden>
<section class="tb-pcard chat-zone">
<hr>
<form method="post" action="/user/profile/update-chat-settings">
<input type="hidden" name="_csrf" value="x">
<legend class="uk-legend">私聊设置</legend>
<div class="uk-margin">
<label class="uk-form-label">私聊消息条数上限</label>
<input name="chat_max_messages" class="uk-input uk-width-small" type="number" min="1" max="200" value="20">
</div>
<div class="uk-margin">
<label class="uk-form-label">单用户每日私信条数上限</label>
<input name="chat_daily_limit" class="uk-input uk-width-small" type="number" min="0" max="999" value="0">
<span class="uk-text-muted uk-text-small">0 表示不限制</span>
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">更新私聊设置</button>
</div>
</form>
</section>
</div>
<div class="profile-panel" data-profile-panel="vote" hidden>
</div>
<div class="profile-panel" data-profile-panel="security">
<section class="tb-pcard">
<div class="uk-margin">
<form method="post" action="/user/harassment/update?tab=security">
<input type="hidden" name="_csrf" value="x">
<legend class="uk-legend">防骚扰设置</legend>
<div class="uk-margin">
<label class="uk-form-label">提问限制</label><br>
<label>
<input name="register_only" class="uk-checkbox" type="checkbox"
>
<span class="uk-text-small"> 仅允许注册用户向我提问</span>
</label>
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">更新防骚扰设置</button>
</div>
</form>
</div>
<hr>
<div class="uk-margin">
<form method="post" action="/user/blockwords/update?tab=security">
<input type="hidden" name="_csrf" value="x">
<legend class="uk-legend">全局屏蔽词</legend>
<div class="uk-margin">
<p class="uk-text-meta uk-text-small">屏蔽词对提问、私聊(对方发给你的消息)与投票提交内容生效;三个设置页同步显示同一份设置,任意一处修改即时生效。</p>
<label class="uk-form-label">屏蔽词设置(回车或逗号分隔,最多支持 10 个屏蔽词,每个屏蔽词最大长度为 10)</label>
<input name="block_words" class="uk-input" type="text" value="广告,spam"
data-tb-tag-input
data-tb-max="10" data-tb-max-len="10"
data-tb-msg-too-many="屏蔽词不能超过 10 个"
data-tb-msg-too-long="屏蔽词长度不能超过 10 个字符:%s"
data-tb-msg-duplicate="已存在,已忽略"
data-tb-msg-hint="输入后按回车或逗号添加">
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">保存屏蔽词</button>
</div>
</form>
</div>
<div class="uk-margin" data-page-node-id="0VziNJMvvostIMmOJAfJ5g">
<form method="post" action="/user/moderation-strictness/update?tab=security" data-page-node-id="ko4Nj1yDJIUUpsEoILiYAb">
<input type="hidden" name="_csrf" value="x">
<legend class="uk-legend" data-page-node-id="2usTgd9N8PHPO95MFzvct7">审核严格度</legend>
<p class="uk-text-meta uk-text-small" data-page-node-id="GF3aXisM5hvonHBGY2m69p">对提问、投票、私聊三类内容同时生效。这里调节的是「审核命中之后是否拦截」,不影响屏蔽词——屏蔽词始终直接拒绝。</p>
<p class="uk-text-meta uk-text-small" data-page-node-id="AoSpxE29Qnz8tgDhTEX8SU">底线拦截(所有档位强制生效,不可关闭):涉政、暴恐、色情,以及审核服务自定义词库的命中。</p>
<table class="uk-table uk-table-small uk-table-divider" data-page-node-id="NHmbNbedxyS9p1zF1xh04X">
<thead data-page-node-id="E11Y0hvt2TJsKSaJncgwgf">
<tr data-page-node-id="aMFSpdotgCq0r6J2L8rCdq">
<th class="uk-table-shrink" style="white-space: nowrap;" data-page-node-id="2jACHZBk0oxOkr47BNuZ0v">档位</th>
<th class="uk-table-expand" data-page-node-id="2Zo97ZXwvrdRT5Y7SGGDbC">拦截范围</th>
</tr>
</thead>
<tbody data-page-node-id="j0rtD87L017rNi73VtGNZI">
<tr data-page-node-id="z3H6fvsm60FhSmhmHt9lUf">
<td class="uk-table-shrink" style="white-space: nowrap;" data-page-node-id="fy0gR7lZnunOcjwbZdm363">畅所欲言</td>
<td class="uk-table-expand" data-page-node-id="7Z1Up9Su7AUn5Trl69aG6h">仅拦截底线内容,其余一律放行(误伤最少)。</td>
</tr>
<tr data-page-node-id="HAeGyGZcyJoKAsHwzGbLc0">
<td class="uk-table-shrink" style="white-space: nowrap;" data-page-node-id="vW3L2l6uS8eueDU9BTFpfV">正常水平</td>
<td class="uk-table-expand" data-page-node-id="luI6WgZHZuZ7imRc7Zfy0s">底线内容,以及置信度不低于 90% 的辱骂、违禁内容。</td>
</tr>
<tr data-page-node-id="wARdw1jBaCI6hH31TZPIjC">
<td class="uk-table-shrink" style="white-space: nowrap;" data-page-node-id="0MTeu5eoZ1GRO8q4f7Skaw">不听坏话</td>
<td class="uk-table-expand" data-page-node-id="7ZvrruLq1FQ9FOyDsmjA9C">底线内容,以及辱骂、违禁、垃圾信息、广告、灌水、无意义、不良场景内容(不限置信度);同时采信审核服务给出的整体拦截建议。最严格档,拦截面不小于升级前。</td>
</tr>
</tbody>
</table>
<div class="uk-margin" data-page-node-id="c3SODOKZkDUTm0moKYnNJz">
<label class="uk-form-label" style="display: block;" data-page-node-id="IBc6LpxtWpQxECLCOcNzlZ">审核严格度</label>
<div class="uk-margin-small-top" data-page-node-id="HIWMgKH7FXZ9BYygBQ23A8">
<select name="strictness" class="uk-select uk-width-medium" style="max-width: 100%;" data-page-node-id="43cBp9IvsqBOUUpcIqISNq">
<option value="lax" data-page-node-id="XLfr3E5HDhGCCe27M9DQQX">
畅所欲言
</option>
<option value="standard" selected data-page-node-id="bucHVmBTgVGR93Hhja4Dl9">
正常水平
</option>
<option value="strict" data-page-node-id="kbcP6ka4VLHBgNqUrQL3jV">
不听坏话
</option>
</select>
</div>
<div class="uk-margin-small-top" data-page-node-id="x0HenJ4S8MklMYn0KwF3nP">
<span class="uk-text-muted uk-text-small" data-page-node-id="wjCCL3LYk3jbKWgng8IQQS">未设置时跟随站点默认档位。</span>
</div>
</div>
<div class="tb-card-save" data-page-node-id="vmD40ecSRAGLrWqlz5F2c5">
<button type="submit" class="uk-button uk-button-primary" data-page-node-id="r04SFvzxXIgjRvgG0xaQIw">保存审核严格度</button>
</div>
</form>
</div>
<hr>
<div class="uk-margin">
<form method="post" action="/user/profile/update-page-password?tab=security">
<input type="hidden" name="_csrf" value="x">
<legend class="uk-legend">页面访问密码</legend>
<div class="uk-margin">
<label class="uk-form-label">设置访问密码(留空则关闭)</label>
<input name="password" class="uk-input" type="password" placeholder="输入页面访问密码">
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">更新页面密码</button>
</div>
</form>
</div>
<hr>
<div class="uk-margin">
<form method="post" action="/user/profile/update-ask-password?tab=security">
<input type="hidden" name="_csrf" value="x">
<legend class="uk-legend">提问密码</legend>
<div class="uk-margin">
<label class="uk-form-label">设置提问密码(留空则关闭)</label>
<input name="password" class="uk-input" type="password" placeholder="输入提问密码">
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">更新提问密码</button>
</div>
</form>
</div>
</section>
</div>
<script>
(function() {
function initSocialCheckboxes() {
document.querySelectorAll('.social-item').forEach(function(item) {
var checkbox = item.querySelector('.social-enable');
var input = item.querySelector('.social-input');
if (!checkbox || !input) return;
var currentVal = input.value.trim();
if (currentVal === 'none' || currentVal === '') {
checkbox.checked = false;
input.value = 'none';
input.disabled = true;
input.removeAttribute('required');
} else {
checkbox.checked = true;
input.disabled = false;
input.setAttribute('required', 'required');
}
checkbox.addEventListener('change', function() {
if (checkbox.checked) {
input.disabled = false;
if (input.value === 'none') input.value = '';
input.setAttribute('required', 'required');
input.focus();
} else {
input.value = 'none';
input.disabled = true;
input.removeAttribute('required');
input.setCustomValidity('');
}
});
input.addEventListener('input', function() {
if (input.validity.customError) {
input.setCustomValidity('');
}
});
});
}
var profileForm = document.getElementById('profile-form');
profileForm.addEventListener('submit', function(e) {
var valid = true;
document.querySelectorAll('.social-item').forEach(function(item) {
var checkbox = item.querySelector('.social-enable');
var input = item.querySelector('.social-input');
if (checkbox.checked && input.value.trim() === '') {
input.setCustomValidity('请填写链接或取消勾选');
valid = false;
} else {
input.setCustomValidity('');
}
});
if (!valid) {
e.preventDefault();
profileForm.reportValidity();
} else {
document.querySelectorAll('.social-item').forEach(function(item) {
var checkbox = item.querySelector('.social-enable');
var input = item.querySelector('.social-input');
if (!checkbox.checked) {
input.value = 'none';
}
});
}
});
initSocialCheckboxes();
function debounce(func, wait) {
var timeout;
return function() {
var context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() { func.apply(context, args); }, wait);
};
}
document.querySelectorAll('.color-picker').forEach(function(el) {
var hiddenInput = el.nextElementSibling;
if (!hiddenInput || hiddenInput.type !== 'hidden') return;
var pickr = Pickr.create({
el: el,
theme: 'nano',
default: hiddenInput.value || '#000000',
defaultRepresentation: 'HEX',
components: {
preview: true,
opacity: false,
hue: true,
interaction: {
hex: true,
input: true,
clear: true,
save: true
}
}
});
pickr.on('save', function(color) {
var hex = color.toHEXA().toString();
hiddenInput.value = hex;
hiddenInput.dispatchEvent(new Event('input'));
});
});
function bindRangeNumber(range, num, span) {
if (!range || !num) return;
var update = function() {
num.value = range.value;
if (span) span.textContent = parseFloat(range.value).toFixed(2);
debouncedUpdatePreview();
};
range.addEventListener('input', update);
num.addEventListener('change', function() {
var val = parseFloat(num.value);
if (isNaN(val)) return;
range.value = val;
if (span) span.textContent = val.toFixed(2);
debouncedUpdatePreview();
});
if (span) span.textContent = parseFloat(range.value).toFixed(2);
}
var dotScaleRange = document.querySelector('input[name="dotscale"]');
var dotScaleNum = document.getElementById('dotscale-num');
var dotScaleSpan = document.getElementById('dotscale-val');
var bgAlphaRange = document.querySelector('input[name="backgroundimagealpha"]');
var bgAlphaNum = document.getElementById('bgalpha-num');
var bgAlphaSpan = document.getElementById('bgalpha-val');
bindRangeNumber(dotScaleRange, dotScaleNum, dotScaleSpan);
bindRangeNumber(bgAlphaRange, bgAlphaNum, bgAlphaSpan);
var bgImageFile = document.getElementById('backgroundimage-file');
window._bgImageDataURL = null;
if (bgImageFile) {
bgImageFile.addEventListener('change', function(e) {
var file = e.target.files[0];
if (!file) return;
var reader = new FileReader();
reader.onload = function(ev) {
window._bgImageDataURL = ev.target.result;
debouncedUpdatePreview();
};
reader.readAsDataURL(file);
});
}
var boxURL = window.location.origin + '/_/' + 'tester';
var previewEl = document.getElementById('qrcode-preview');
var useCustomFg = document.getElementById('use-custom-fg');
updatePreview();
function getInputVal(name, fallback) {
var input = document.querySelector('input[name="' + name + '"]');
var v = input ? (input.value || '').trim() : '';
return v || (fallback || '#000000');
}
function updatePreview() {
var useFg = useCustomFg.checked;
var containerWidth = previewEl.clientWidth || 220;
var size = Math.min(containerWidth, 220);
var dotScaleVal = parseFloat(dotScaleRange.value) || 0.4;
var bgAlphaVal = parseFloat(bgAlphaRange.value) || 0.8;
var options = {
text: boxURL,
width: size,
height: size,
colorDark: useFg ? getInputVal('qrcodebackcolor', '#000000') : '#000000',
colorLight: getInputVal('qrcodecolor', '#FFFFFF'),
dotScale: dotScaleVal,
dotScaleTiming: dotScaleVal,
dotScaleA: dotScaleVal,
correctLevel: QRCode.CorrectLevel.H,
logo: (function () {
var a = "" || "";
return a ? (a.indexOf("http") === 0 ? a + "?v=2" : a) : undefined;
})(),
logoWidth: Math.floor(size * 0.25),
logoHeight: Math.floor(size * 0.25),
logoBackgroundTransparent: true,
crossOrigin: 'anonymous',
backgroundImage: window._bgImageDataURL || ("" ? "" : undefined),
backgroundImageAlpha: bgAlphaVal,
autoColor: false,
PO: getInputVal('qrcodepdpcolor', '#000000'),
PI: getInputVal('qrcodepdpcolor', '#000000'),
AO: '',
AI: '',
timing: getInputVal('qrcodepdpcolor', '#000000')
};
window.tbRenderQR(previewEl, function () { return options; });
}
var debouncedUpdatePreview = debounce(updatePreview, 150);
window.__tbRefreshAccountPreview = debouncedUpdatePreview;
var colorInputs = document.querySelectorAll('input[type="hidden"][name="qrcodebackcolor"], input[type="hidden"][name="qrcodecolor"], input[type="hidden"][name="qrcodepdpcolor"]');
colorInputs.forEach(function(input) {
input.addEventListener('input', debouncedUpdatePreview);
});
useCustomFg.addEventListener('change', debouncedUpdatePreview);
window.addEventListener('resize', debouncedUpdatePreview);
document.addEventListener('shown', function(e) {
if (e.target && e.target.closest && e.target.closest('.uk-accordion')) {
debouncedUpdatePreview();
}
});
updatePreview();
var themes = {
'default': {
qrcodecolor: '#FFFFFF',
qrcodebackcolor: '#000000',
qrcodepdpcolor: '#000000',
dotscale: 0.35,
bgalpha: 0.8
},
'dark': {
qrcodecolor: '#1a1a1a',
qrcodebackcolor: '#FFFFFF',
qrcodepdpcolor: '#FFFFFF',
dotscale: 0.5,
bgalpha: 0.9
},
'ocean': {
qrcodecolor: '#E0F7FA',
qrcodebackcolor: '#006064',
qrcodepdpcolor: '#004D40',
dotscale: 0.4,
bgalpha: 0.7
},
'sunset': {
qrcodecolor: '#FFF3E0',
qrcodebackcolor: '#BF360C',
qrcodepdpcolor: '#870000',
dotscale: 0.45,
bgalpha: 0.75
}
};
function applyTheme(theme) {
var t = themes[theme];
if (!t) return;
document.querySelector('input[name="qrcodecolor"]').value = t.qrcodecolor;
document.querySelector('input[name="qrcodebackcolor"]').value = t.qrcodebackcolor;
document.querySelector('input[name="qrcodepdpcolor"]').value = t.qrcodepdpcolor;
dotScaleRange.value = t.dotscale;
dotScaleNum.value = t.dotscale;
dotScaleSpan.textContent = parseFloat(t.dotscale).toFixed(2);
bgAlphaRange.value = t.bgalpha;
bgAlphaNum.value = t.bgalpha;
bgAlphaSpan.textContent = parseFloat(t.bgalpha).toFixed(2);
document.querySelector('input[name="qrcodecolor"]').dispatchEvent(new Event('input'));
document.querySelector('input[name="qrcodebackcolor"]').dispatchEvent(new Event('input'));
document.querySelector('input[name="qrcodepdpcolor"]').dispatchEvent(new Event('input'));
debouncedUpdatePreview();
}
document.querySelectorAll('.theme-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
applyTheme(this.getAttribute('data-theme'));
});
});
document.getElementById('reset-qr-defaults').addEventListener('click', function() {
applyTheme('default');
useCustomFg.checked = false;
debouncedUpdatePreview();
});
})();
</script>
<script>
document.addEventListener('DOMContentLoaded', function() {
var tabs = document.querySelectorAll('[data-profile-tab]');
var panels = document.querySelectorAll('[data-profile-panel]');
function showPanel(name, pushToURL) {
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 (name === 'account' && window.__tbRefreshAccountPreview) {
window.__tbRefreshAccountPreview();
}
if (pushToURL && window.history && window.history.replaceState) {
window.history.replaceState({}, document.title, '/user/profile?tab=' + name);
}
}
tabs.forEach(function(tab) {
tab.addEventListener('click', function() { showPanel(tab.dataset.profileTab, true); });
});
var hash = (window.location.hash || '').replace('#', '');
if (hash && document.querySelector('[data-profile-tab="' + hash + '"]')) {
showPanel(hash, false);
}
});
</script>
<script>
(function () {
function parseList(value) {
return String(value || '').split(/[,,]/).map(function (s) {
return s.trim();
}).filter(function (s) { return s !== ''; });
}
function initTagInput(input) {
var max = parseInt(input.getAttribute('data-tb-max'), 10);
var maxLen = parseInt(input.getAttribute('data-tb-max-len'), 10);
if (!max || max < 1) { max = 10; }
if (!maxLen || maxLen < 1) { maxLen = 10; }
var msgTooMany = input.getAttribute('data-tb-msg-too-many') || '';
var msgTooLong = input.getAttribute('data-tb-msg-too-long') || '';
var msgDuplicate = input.getAttribute('data-tb-msg-duplicate') || '';
var hint = input.getAttribute('data-tb-msg-hint') || '';
var items = parseList(input.value);
var box = document.createElement('div');
box.className = 'tb-tag-box';
var entry = document.createElement('input');
entry.type = 'text';
entry.className = 'tb-tag-entry';
box.appendChild(entry);
var meta = document.createElement('div');
meta.className = 'tb-tag-meta';
var count = document.createElement('span');
var error = document.createElement('span');
error.className = 'tb-tag-error';
meta.appendChild(count);
meta.appendChild(error);
var wrap = document.createElement('div');
wrap.appendChild(box);
wrap.appendChild(meta);
input.style.display = 'none';
if (input.parentNode) { input.parentNode.insertBefore(wrap, input.nextSibling); }
function sync() { input.value = items.join(','); }
function showError(msg) { error.textContent = msg || ''; }
function commit(raw) {
var v = String(raw || '').trim().replace(/[,,]/g, '');
if (v === '') { return; }
if (items.length >= max) { showError(msgTooMany); return; }
if (Array.from(v).length > maxLen) { showError(msgTooLong.replace('%s', v)); return; }
if (items.indexOf(v) >= 0) { showError(msgDuplicate); return; }
showError('');
items.push(v);
render();
}
function render() {
Array.prototype.slice.call(box.childNodes).forEach(function (node) {
if (node !== entry) { box.removeChild(node); }
});
items.forEach(function (text, i) {
var chip = document.createElement('span');
chip.className = 'tb-tag-chip';
chip.appendChild(document.createTextNode(text));
var del = document.createElement('button');
del.type = 'button';
del.textContent = '×';
del.title = text;
del.addEventListener('click', function () {
items.splice(i, 1);
showError('');
render();
});
chip.appendChild(del);
box.insertBefore(chip, entry);
});
entry.disabled = items.length >= max;
entry.placeholder = entry.disabled ? '' : hint;
count.textContent = items.length + ' / ' + max;
sync();
}
box.addEventListener('click', function (e) {
if (e.target === box) { entry.focus(); }
});
entry.addEventListener('input', function () {
if (entry.value.indexOf(',') >= 0 || entry.value.indexOf(',') >= 0) {
commit(entry.value);
entry.value = '';
}
});
entry.addEventListener('keydown', function (e) {
if (e.key === 'Enter') {
e.preventDefault();
commit(entry.value);
entry.value = '';
} else if (e.key === 'Backspace' && entry.value === '' && items.length > 0) {
items.pop();
showError('');
render();
}
});
entry.addEventListener('blur', function () {
if (entry.value.trim() !== '') {
commit(entry.value);
entry.value = '';
}
});
if (input.form) {
input.form.addEventListener('submit', function () {
commit(entry.value);
entry.value = '';
sync();
});
}
render();
}
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('[data-tb-tag-input]').forEach(initTagInput);
});
})();
</script>
<script data-cfasync="false">
(function () {
var MSG_AVATAR_TOO_LARGE = '头像文件太大,最大支持 2MB';
var MSG_BG_TOO_LARGE = '背景图文件太大,最大支持 2MB';
var MSG_NO_CROPPER = '图片裁剪组件加载失败,请刷新页面后重试';
var HINT_AVATAR = '裁剪框已锁定为 1:1 正方形';
var HINT_BG = '裁剪框已锁定为 16:9 宽屏';
var MAX_FILE = 2 * 1024 * 1024;
var media = {
avatar: {
input: document.getElementById('avatar-input'),
prev: document.getElementById('avatar-prev'),
ratio: 1,
hint: HINT_AVATAR,
maxSizeMsg: MSG_AVATAR_TOO_LARGE,
canvas: { maxWidth: 512 },
fileType: 'image/png', fileExt: 'png', quality: null
},
background: {
input: document.getElementById('background-input'),
prev: document.getElementById('bg-prev'),
ratio: 16 / 9,
hint: HINT_BG,
maxSizeMsg: MSG_BG_TOO_LARGE,
canvas: { maxWidth: 1920 },
fileType: 'image/jpeg', fileExt: 'jpg', quality: 0.92
}
};
var modalEl = document.getElementById('media-crop-modal');
var stageImg = document.getElementById('media-crop-image');
var hintEl = document.getElementById('media-crop-hint');
var confirmBtn = document.getElementById('media-crop-confirm');
var cropper = null;
var pendingKey = null;
var pendingURL = null;
var appliedURL = {};
var modalObj = null;
function notify(msg) {
if (window.UIkit) { UIkit.modal.alert(msg); } else { window.alert(msg); }
}
function whenReady(cb) {
if (window.UIkit && window.Cropper) { cb(); return; }
var waited = 0;
var timer = setInterval(function () {
waited += 100;
if (window.UIkit && window.Cropper) {
clearInterval(timer);
cb();
} else if (waited >= 3000) {
clearInterval(timer);
notify(MSG_NO_CROPPER);
}
}, 100);
}
function revoke(store, key) {
if (store[key]) { URL.revokeObjectURL(store[key]); store[key] = null; }
}
function startCrop(key) {
var cfg = media[key];
if (!cfg) return;
var file = cfg.input && cfg.input.files && cfg.input.files[0];
if (!file) return;
if (file.size > MAX_FILE) { notify(cfg.maxSizeMsg); cfg.input.value = ''; return; }
whenReady(function () {
var f = cfg.input.files && cfg.input.files[0];
if (!f) return;
if (f.size > MAX_FILE) { notify(cfg.maxSizeMsg); cfg.input.value = ''; return; }
if (!modalObj) { modalObj = UIkit.modal(modalEl); }
revoke(appliedURL, key);
pendingKey = key;
if (pendingURL) { URL.revokeObjectURL(pendingURL); pendingURL = null; }
pendingURL = URL.createObjectURL(f);
hintEl.textContent = cfg.hint;
stageImg.onload = function () { initCropper(); };
stageImg.src = pendingURL;
modalObj.show();
});
}
function initCropper() {
if (cropper) { cropper.destroy(); cropper = null; }
if (!pendingKey) return;
var cfg = media[pendingKey];
var box = stageImg.parentElement;
cropper = new Cropper(stageImg, {
viewMode: 1,
dragMode: 'move',
aspectRatio: cfg.ratio,
autoCropArea: 1,
responsive: true,
background: false,
rotatable: true,
zoomable: true,
wheelZoomRatio: 0.08
});
}
modalEl.addEventListener('hidden', function () {
if (cropper) { cropper.destroy(); cropper = null; }
if (pendingURL) { URL.revokeObjectURL(pendingURL); pendingURL = null; }
stageImg.removeAttribute('src');
pendingKey = null;
});
confirmBtn.addEventListener('click', function () {
if (!cropper || !pendingKey || !modalObj) return;
var cfg = media[pendingKey];
var canvas = cropper.getCroppedCanvas(cfg.canvas);
if (!canvas) return;
canvas.toBlob(function (blob) {
if (!blob) return;
var dt = new DataTransfer();
dt.items.add(new File([blob], 'cropped-' + pendingKey + '.' + cfg.fileExt, { type: cfg.fileType }));
cfg.input.files = dt.files;
appliedURL[pendingKey] = URL.createObjectURL(blob);
if (cfg.prev) { cfg.prev.src = appliedURL[pendingKey]; cfg.prev.style.display = 'block'; }
modalObj.hide();
}, cfg.fileType, cfg.quality || undefined);
});
document.querySelectorAll('[data-pick-image]').forEach(function (btn) {
btn.addEventListener('click', function () {
var key = btn.getAttribute('data-pick-image');
var input = media[key] && media[key].input;
if (input) input.click();
});
});
Object.keys(media).forEach(function (key) {
var input = media[key].input;
if (!input) return;
input.addEventListener('change', function () { startCrop(key); });
});
})();
</script>
<p class=" uk-text-right uk-text-muted uk-text-small">
<br>
<a href="/rules">社区规则</a> |
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">找站长</a>
<br>
<a href="https://share.shiroko.one" target="_blank">盘</a>
| <a href="https://blog.shiroko.one" target="_blank">公告板</a>
| <a href="https://chat.shiroko.one" target="_blank">聊天室</a>
| <a href="https://status.shiroko.one" target="_blank">监控板</a>
| <a href="https://shiroko.one" target="_blank">导航页</a>
<br>Powered by NekoBox |
<br>提问箱已成功存活:<span id="box_runtime"></span>
</p>
<script>
(function () {
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
function tick() {
var el = document.getElementById("box_runtime");
if (!el) return;
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
var t = [0, 0, 0, 0, 0];
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
if (s > 0) { t[4] = s; }
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
}
tick();
setInterval(tick, 1000);
})();
</script>
<br>
</div>
<script>
var SUBMIT_I18N = {
submitting: '提交中...',
uploading: '上传中...'
};
function tbResetSubmitButtons() {
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
b.disabled = false;
b.removeAttribute('data-tb-submitting');
var orig = b.getAttribute('data-tb-restore');
if (orig !== null) {
b.innerHTML = orig;
b.removeAttribute('data-tb-restore');
}
});
}
document.addEventListener('submit', function(e) {
var form = e.target;
if (!form || form.tagName !== 'FORM') return;
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
form.removeAttribute('data-tb-skip-submit-feedback');
return;
}
if (form.getAttribute('target') === '_blank') return;
var trigger = e.submitter || form.querySelector('button[type="submit"]');
var hasFile = false;
form.querySelectorAll('input[type="file"]').forEach(function(f) {
if (f.files && f.files.length > 0) hasFile = true;
});
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
if (trigger && trigger.tagName === 'BUTTON') {
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
}
form.querySelectorAll('button').forEach(function(b) {
b.disabled = true;
b.setAttribute('data-tb-submitting', '1');
});
});
window.addEventListener('pageshow', tbResetSubmitButtons);
</script>
</body>
</html>