2023 lines
71 KiB
HTML
2023 lines
71 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>预览 16:08 · 设置</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 is-active" data-profile-tab="account" role="tab" aria-selected="true">用户设置</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" data-profile-tab="security" role="tab" aria-selected="false">防护设置</button>
|
||
</div>
|
||
|
||
|
||
<div class="profile-panel" data-profile-panel="account">
|
||
<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" hidden>
|
||
<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>
|
||
|