Fix env config tabs with CSS radio labels, no JS required
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -73,32 +73,8 @@
|
|||||||
return document.querySelector(".env-config-page");
|
return document.querySelector(".env-config-page");
|
||||||
}
|
}
|
||||||
|
|
||||||
let envTabsDelegateReady = false;
|
|
||||||
|
|
||||||
function bindEnvTabs() {
|
function bindEnvTabs() {
|
||||||
if (envTabsDelegateReady) return;
|
/* Tab 切换由 CSS radio+label 实现 */
|
||||||
envTabsDelegateReady = true;
|
|
||||||
document.addEventListener("click", (e) => {
|
|
||||||
const btn = e.target.closest(".env-tab-btn");
|
|
||||||
if (!btn) return;
|
|
||||||
const root = btn.closest(".env-config-page");
|
|
||||||
if (!root) return;
|
|
||||||
const hostPane = root.closest(".embed-tab-pane");
|
|
||||||
if (hostPane && !hostPane.classList.contains("is-active-pane")) return;
|
|
||||||
const idx = btn.getAttribute("data-env-tab");
|
|
||||||
if (idx == null) return;
|
|
||||||
e.preventDefault();
|
|
||||||
root.querySelectorAll(".env-tab-btn").forEach((b) => {
|
|
||||||
const on = b.getAttribute("data-env-tab") === idx;
|
|
||||||
b.classList.toggle("is-active", on);
|
|
||||||
b.setAttribute("aria-selected", on ? "true" : "false");
|
|
||||||
});
|
|
||||||
root.querySelectorAll(".env-panel").forEach((p) => {
|
|
||||||
const on = p.getAttribute("data-env-panel") === idx;
|
|
||||||
p.classList.toggle("is-active", on);
|
|
||||||
p.hidden = !on;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadDisplayPrefsForm(force) {
|
async function loadDisplayPrefsForm(force) {
|
||||||
@@ -221,6 +197,15 @@
|
|||||||
body.className = "env-config-body card";
|
body.className = "env-config-body card";
|
||||||
body.id = "env-config-body";
|
body.id = "env-config-body";
|
||||||
body.setAttribute("data-env-ssr", "1");
|
body.setAttribute("data-env-ssr", "1");
|
||||||
|
groups.forEach((_group, idx) => {
|
||||||
|
const radio = document.createElement("input");
|
||||||
|
radio.type = "radio";
|
||||||
|
radio.name = "env-section";
|
||||||
|
radio.id = "env-sec-" + idx;
|
||||||
|
radio.className = "env-tab-radio";
|
||||||
|
if (idx === 0) radio.checked = true;
|
||||||
|
body.appendChild(radio);
|
||||||
|
});
|
||||||
const tabBar = document.createElement("div");
|
const tabBar = document.createElement("div");
|
||||||
tabBar.className = "env-config-tabs";
|
tabBar.className = "env-config-tabs";
|
||||||
tabBar.setAttribute("role", "tablist");
|
tabBar.setAttribute("role", "tablist");
|
||||||
@@ -228,19 +213,15 @@
|
|||||||
panelsWrap.className = "env-config-panels";
|
panelsWrap.className = "env-config-panels";
|
||||||
panelsWrap.id = "env-config-grid";
|
panelsWrap.id = "env-config-grid";
|
||||||
groups.forEach((group, idx) => {
|
groups.forEach((group, idx) => {
|
||||||
const tab = document.createElement("button");
|
const label = document.createElement("label");
|
||||||
tab.type = "button";
|
label.className = "env-tab-btn";
|
||||||
tab.className = "env-tab-btn" + (idx === 0 ? " is-active" : "");
|
label.htmlFor = "env-sec-" + idx;
|
||||||
tab.setAttribute("role", "tab");
|
label.setAttribute("role", "tab");
|
||||||
tab.dataset.envTab = String(idx);
|
label.textContent = group.title || "其他";
|
||||||
tab.setAttribute("aria-selected", idx === 0 ? "true" : "false");
|
tabBar.appendChild(label);
|
||||||
tab.textContent = group.title || "其他";
|
|
||||||
tabBar.appendChild(tab);
|
|
||||||
const panel = document.createElement("section");
|
const panel = document.createElement("section");
|
||||||
panel.className = "env-panel" + (idx === 0 ? " is-active" : "");
|
panel.className = "env-panel env-panel--" + idx;
|
||||||
panel.setAttribute("role", "tabpanel");
|
panel.setAttribute("role", "tabpanel");
|
||||||
panel.dataset.envPanel = String(idx);
|
|
||||||
if (idx !== 0) panel.hidden = true;
|
|
||||||
if (group.has_restart) {
|
if (group.has_restart) {
|
||||||
const hint = document.createElement("p");
|
const hint = document.createElement("p");
|
||||||
hint.className = "env-panel-hint";
|
hint.className = "env-panel-hint";
|
||||||
@@ -262,7 +243,6 @@
|
|||||||
const root = envConfigRoot();
|
const root = envConfigRoot();
|
||||||
const body = root && root.querySelector("#env-config-body");
|
const body = root && root.querySelector("#env-config-body");
|
||||||
if (!force && body && body.getAttribute("data-env-ssr") === "1" && body.querySelector("[data-env-key]")) {
|
if (!force && body && body.getAttribute("data-env-ssr") === "1" && body.querySelector("[data-env-key]")) {
|
||||||
bindEnvTabs();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return loadEnvConfigIn(root);
|
return loadEnvConfigIn(root);
|
||||||
@@ -283,7 +263,6 @@
|
|||||||
const data = await fetchJson("/api/settings/env");
|
const data = await fetchJson("/api/settings/env");
|
||||||
envSchemaGroups = data.groups || [];
|
envSchemaGroups = data.groups || [];
|
||||||
loading.replaceWith(renderEnvConfigBody(envSchemaGroups));
|
loading.replaceWith(renderEnvConfigBody(envSchemaGroups));
|
||||||
bindEnvTabs();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
loading.innerHTML = '<span class="err">' + (e.message || "加载失败") + "</span>";
|
loading.innerHTML = '<span class="err">' + (e.message || "加载失败") + "</span>";
|
||||||
}
|
}
|
||||||
@@ -379,7 +358,6 @@
|
|||||||
bindEvents();
|
bindEvents();
|
||||||
loadDisplayPrefsForm(false);
|
loadDisplayPrefsForm(false);
|
||||||
loadEnvConfig(false);
|
loadEnvConfig(false);
|
||||||
bindEnvTabs();
|
|
||||||
if (global.__INSTANCE_DISPLAY__) applyDisplayToNav(global.__INSTANCE_DISPLAY__);
|
if (global.__INSTANCE_DISPLAY__) applyDisplayToNav(global.__INSTANCE_DISPLAY__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2225,6 +2225,19 @@ html[data-theme="light"] .journal-detail-img-thumb {
|
|||||||
.env-config-body {
|
.env-config-body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-tab-radio {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-config-tabs {
|
.env-config-tabs {
|
||||||
@@ -2239,6 +2252,7 @@ html[data-theme="light"] .journal-detail-img-thumb {
|
|||||||
|
|
||||||
.env-tab-btn {
|
.env-tab-btn {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
display: inline-block;
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--muted, #8892b0);
|
color: var(--muted, #8892b0);
|
||||||
@@ -2249,18 +2263,49 @@ html[data-theme="light"] .journal-detail-img-thumb {
|
|||||||
margin-bottom: -1px;
|
margin-bottom: -1px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
transition: color 0.15s, border-color 0.15s;
|
transition: color 0.15s, border-color 0.15s;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-tab-btn:hover {
|
.env-tab-btn:hover {
|
||||||
color: #c5cae0;
|
color: #c5cae0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-tab-btn.is-active {
|
.env-config-panels .env-panel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#env-sec-0:checked ~ .env-config-tabs label[for="env-sec-0"],
|
||||||
|
#env-sec-1:checked ~ .env-config-tabs label[for="env-sec-1"],
|
||||||
|
#env-sec-2:checked ~ .env-config-tabs label[for="env-sec-2"],
|
||||||
|
#env-sec-3:checked ~ .env-config-tabs label[for="env-sec-3"],
|
||||||
|
#env-sec-4:checked ~ .env-config-tabs label[for="env-sec-4"],
|
||||||
|
#env-sec-5:checked ~ .env-config-tabs label[for="env-sec-5"],
|
||||||
|
#env-sec-6:checked ~ .env-config-tabs label[for="env-sec-6"],
|
||||||
|
#env-sec-7:checked ~ .env-config-tabs label[for="env-sec-7"],
|
||||||
|
#env-sec-8:checked ~ .env-config-tabs label[for="env-sec-8"],
|
||||||
|
#env-sec-9:checked ~ .env-config-tabs label[for="env-sec-9"],
|
||||||
|
#env-sec-10:checked ~ .env-config-tabs label[for="env-sec-10"],
|
||||||
|
#env-sec-11:checked ~ .env-config-tabs label[for="env-sec-11"] {
|
||||||
color: #e8ecff;
|
color: #e8ecff;
|
||||||
border-bottom-color: var(--accent, #7c6cf0);
|
border-bottom-color: var(--accent, #7c6cf0);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#env-sec-0:checked ~ .env-config-panels .env-panel--0,
|
||||||
|
#env-sec-1:checked ~ .env-config-panels .env-panel--1,
|
||||||
|
#env-sec-2:checked ~ .env-config-panels .env-panel--2,
|
||||||
|
#env-sec-3:checked ~ .env-config-panels .env-panel--3,
|
||||||
|
#env-sec-4:checked ~ .env-config-panels .env-panel--4,
|
||||||
|
#env-sec-5:checked ~ .env-config-panels .env-panel--5,
|
||||||
|
#env-sec-6:checked ~ .env-config-panels .env-panel--6,
|
||||||
|
#env-sec-7:checked ~ .env-config-panels .env-panel--7,
|
||||||
|
#env-sec-8:checked ~ .env-config-panels .env-panel--8,
|
||||||
|
#env-sec-9:checked ~ .env-config-panels .env-panel--9,
|
||||||
|
#env-sec-10:checked ~ .env-config-panels .env-panel--10,
|
||||||
|
#env-sec-11:checked ~ .env-config-panels .env-panel--11 {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.env-config-panels {
|
.env-config-panels {
|
||||||
padding: 14px 16px 16px;
|
padding: 14px 16px 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
|
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
|
||||||
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
|
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
|
||||||
<link rel="stylesheet" href="/static/instance_page.css?v=4">
|
<link rel="stylesheet" href="/static/instance_page.css?v=4">
|
||||||
<link rel="stylesheet" href="/static/instance_theme.css?v=73">
|
<link rel="stylesheet" href="/static/instance_theme.css?v=74">
|
||||||
<script src="/static/account_risk_badge.js?v=4"></script>
|
<script src="/static/account_risk_badge.js?v=4"></script>
|
||||||
<meta name="theme-color" content="#0b0d14">
|
<meta name="theme-color" content="#0b0d14">
|
||||||
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
||||||
@@ -103,7 +103,7 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj
|
|||||||
<script>
|
<script>
|
||||||
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
|
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/instance_settings_prefs.js?v=8"></script>
|
<script src="/static/instance_settings_prefs.js?v=9"></script>
|
||||||
<script src="/static/instance_live.js?v=4"></script>
|
<script src="/static/instance_live.js?v=4"></script>
|
||||||
<script src="/static/instance_embed.js?v=20"></script>
|
<script src="/static/instance_embed.js?v=20"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{# env配置:Tab 分类 + 双列表单,顶部统一保存 #}
|
{# env配置:CSS Tab(无需 JS)+ 双列表单 #}
|
||||||
<div class="env-config-page">
|
<div class="env-config-page">
|
||||||
<div class="env-config-head card">
|
<div class="env-config-head card">
|
||||||
<div class="env-config-head-row">
|
<div class="env-config-head-row">
|
||||||
@@ -17,14 +17,17 @@
|
|||||||
|
|
||||||
{% if env_config_groups %}
|
{% if env_config_groups %}
|
||||||
<div class="env-config-body card" data-env-ssr="1" id="env-config-body">
|
<div class="env-config-body card" data-env-ssr="1" id="env-config-body">
|
||||||
|
{% for group in env_config_groups %}
|
||||||
|
<input type="radio" name="env-section" id="env-sec-{{ loop.index0 }}" class="env-tab-radio"{% if loop.first %} checked{% endif %}>
|
||||||
|
{% endfor %}
|
||||||
<div class="env-config-tabs" role="tablist" aria-label="配置分类">
|
<div class="env-config-tabs" role="tablist" aria-label="配置分类">
|
||||||
{% for group in env_config_groups %}
|
{% for group in env_config_groups %}
|
||||||
<button type="button" class="env-tab-btn{% if loop.first %} is-active{% endif %}" role="tab" data-env-tab="{{ loop.index0 }}" aria-selected="{{ 'true' if loop.first else 'false' }}">{{ group.title }}</button>
|
<label for="env-sec-{{ loop.index0 }}" class="env-tab-btn" role="tab">{{ group.title }}</label>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="env-config-panels" id="env-config-grid">
|
<div class="env-config-panels" id="env-config-grid">
|
||||||
{% for group in env_config_groups %}
|
{% for group in env_config_groups %}
|
||||||
<section class="env-panel{% if loop.first %} is-active{% endif %}" role="tabpanel" data-env-panel="{{ loop.index0 }}"{% if not loop.first %} hidden{% endif %}>
|
<section class="env-panel env-panel--{{ loop.index0 }}" role="tabpanel">
|
||||||
{% if group.has_restart %}
|
{% if group.has_restart %}
|
||||||
<p class="env-panel-hint">本组含需重启项,修改后请点「保存并重启」。</p>
|
<p class="env-panel-hint">本组含需重启项,修改后请点「保存并重启」。</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<link rel="manifest" href="/static/icons/manifest.webmanifest">
|
<link rel="manifest" href="/static/icons/manifest.webmanifest">
|
||||||
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
||||||
<link rel="stylesheet" href="/static/instance_page.css?v=1">
|
<link rel="stylesheet" href="/static/instance_page.css?v=1">
|
||||||
<link rel="stylesheet" href="/static/instance_theme.css?v=73">
|
<link rel="stylesheet" href="/static/instance_theme.css?v=74">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body
|
<body
|
||||||
@@ -2038,6 +2038,6 @@ setInterval(refreshPriceSnapshotConditional, {{ price_refresh_seconds * 1000 }})
|
|||||||
<script>
|
<script>
|
||||||
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
|
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/instance_settings_prefs.js?v=8"></script>
|
<script src="/static/instance_settings_prefs.js?v=9"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user