From 2f7e6355a1b389ec2a8bd1c9fbfe186515be795c Mon Sep 17 00:00:00 2001 From: dekun Date: Sat, 18 Jul 2026 17:41:04 +0800 Subject: [PATCH] Add section badges to strategy TOC/headings and fill cards to viewport height. Co-authored-by: Cursor --- manual_trading_hub/static/app.css | 139 +++++++++++++++++++++----- manual_trading_hub/static/index.html | 4 +- manual_trading_hub/static/strategy.js | 39 ++++++-- 3 files changed, 150 insertions(+), 32 deletions(-) diff --git a/manual_trading_hub/static/app.css b/manual_trading_hub/static/app.css index 6250f9b..a52505b 100644 --- a/manual_trading_hub/static/app.css +++ b/manual_trading_hub/static/app.css @@ -9704,26 +9704,39 @@ body:not(.hub-phone) #page-calculator .calc-layout[data-calc-tab="roll"] [data-c color: var(--text); } .strategy-doc-panel { - padding: 18px 20px 20px; - min-width: 0; -} -.strategy-blog-layout { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(200px, 260px); - gap: 18px; - align-items: start; -} -.strategy-blog-main { + padding: 16px 18px 18px; min-width: 0; display: flex; flex-direction: column; + height: calc(100dvh - 168px); + min-height: 420px; + max-height: calc(100dvh - 140px); +} +.strategy-blog-layout { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(220px, 280px); + gap: 16px; + align-items: stretch; + flex: 1 1 auto; + min-height: 0; +} +.strategy-blog-main { + min-width: 0; + min-height: 0; + display: flex; + flex-direction: column; + height: 100%; } .strategy-toc-card { padding: 14px 12px 16px; position: sticky; - top: 72px; - max-height: calc(100vh - 96px); + top: 0; + align-self: stretch; + height: 100%; + max-height: none; overflow: auto; + display: flex; + flex-direction: column; } .strategy-toc-title { margin: 0 0 12px; @@ -9736,17 +9749,20 @@ body:not(.hub-phone) #page-calculator .calc-layout[data-calc-tab="roll"] [data-c .strategy-toc-nav { display: flex; flex-direction: column; - gap: 2px; + gap: 4px; border-left: 2px solid var(--border-soft); padding-left: 2px; + flex: 1 1 auto; + min-height: 0; } .strategy-toc-item { - display: flex; - align-items: flex-start; + display: grid; + grid-template-columns: auto auto minmax(0, 1fr); + align-items: start; gap: 8px; width: 100%; text-align: left; - padding: 7px 10px; + padding: 8px 10px; border: none; border-radius: 0 8px 8px 0; background: transparent; @@ -9774,9 +9790,34 @@ body:not(.hub-phone) #page-calculator .calc-layout[data-calc-tab="roll"] [data-c } .strategy-toc-num { flex: 0 0 auto; - min-width: 1.6em; - opacity: 0.85; + min-width: 1.7em; + height: 1.7em; + padding: 0 5px; + border-radius: 999px; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.72rem; + font-weight: 700; font-variant-numeric: tabular-nums; + color: var(--accent); + background: rgba(0, 212, 255, 0.12); + border: 1px solid rgba(0, 212, 255, 0.35); +} +.strategy-toc-tag { + flex: 0 0 auto; + padding: 1px 6px; + border-radius: 4px; + font-size: 0.68rem; + line-height: 1.4; + color: var(--muted); + background: var(--inset-surface, rgba(0, 0, 0, 0.28)); + border: 1px solid var(--border-soft); + white-space: nowrap; +} +.strategy-toc-item.is-active .strategy-toc-tag { + color: var(--accent); + border-color: rgba(0, 212, 255, 0.35); } .strategy-toc-text { flex: 1 1 auto; @@ -9822,7 +9863,7 @@ body:not(.hub-phone) #page-calculator .calc-layout[data-calc-tab="roll"] [data-c .strategy-doc-body { flex: 1 1 auto; min-height: 0; - max-height: min(70vh, 820px); + max-height: none; font-size: 0.88rem; line-height: 1.55; color: var(--text); @@ -9832,6 +9873,10 @@ body:not(.hub-phone) #page-calculator .calc-layout[data-calc-tab="roll"] [data-c scrollbar-gutter: stable; } .strategy-doc-body h2 { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 8px; font-size: 1.05rem; margin: 1.1em 0 0.55em; color: var(--text); @@ -9840,6 +9885,43 @@ body:not(.hub-phone) #page-calculator .calc-layout[data-calc-tab="roll"] [data-c .strategy-doc-body h2:first-child { margin-top: 0; } +.strategy-sec-mark { + display: inline-flex; + align-items: center; + gap: 6px; + margin-right: 2px; +} +.strategy-sec-num { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 1.7em; + height: 1.7em; + padding: 0 6px; + border-radius: 999px; + font-size: 0.72rem; + font-weight: 700; + font-variant-numeric: tabular-nums; + color: #041018; + background: var(--accent); +} +.strategy-sec-tag { + display: inline-flex; + align-items: center; + padding: 2px 7px; + border-radius: 4px; + font-size: 0.68rem; + font-weight: 600; + letter-spacing: 0.02em; + color: var(--accent); + background: rgba(0, 212, 255, 0.1); + border: 1px solid rgba(0, 212, 255, 0.35); +} +.strategy-checklist-card { + height: calc(100dvh - 168px); + min-height: 420px; + max-height: calc(100dvh - 140px); +} .strategy-doc-body h3 { font-size: 0.94rem; margin: 1em 0 0.4em; @@ -9876,8 +9958,9 @@ body:not(.hub-phone) #page-calculator .calc-layout[data-calc-tab="roll"] [data-c color: var(--muted); } .strategy-checklist-body { - flex: 0 0 auto; - overflow: visible; + flex: 1 1 auto; + min-height: 0; + overflow: auto; padding: 2px 10px 2px 4px; } .strategy-checklist-body ul { @@ -9925,20 +10008,28 @@ body:not(.hub-phone) #page-calculator .calc-layout[data-calc-tab="roll"] [data-c .strategy-layout { grid-template-columns: 1fr; } + .strategy-doc-panel, + .strategy-checklist-card { + height: auto; + max-height: none; + min-height: 0; + } .strategy-blog-layout { grid-template-columns: 1fr; } .strategy-toc-card { position: static; - max-height: none; + height: auto; + max-height: min(36vh, 280px); order: -1; } .strategy-doc-card, .strategy-checklist-card { align-self: stretch; } - .strategy-doc-body { - max-height: min(60vh, 640px); + .strategy-doc-body, + .strategy-checklist-body { + max-height: min(58vh, 560px); } } diff --git a/manual_trading_hub/static/index.html b/manual_trading_hub/static/index.html index 770a4e4..3435d90 100644 --- a/manual_trading_hub/static/index.html +++ b/manual_trading_hub/static/index.html @@ -15,7 +15,7 @@ - + @@ -1385,7 +1385,7 @@ - + diff --git a/manual_trading_hub/static/strategy.js b/manual_trading_hub/static/strategy.js index eb672c6..d042c10 100644 --- a/manual_trading_hub/static/strategy.js +++ b/manual_trading_hub/static/strategy.js @@ -1,5 +1,5 @@ /** - * 策略说明:策略正文(博客目录 h2+h3) + 执行清单 Tab. + * 策略说明:策略正文(目录 h2 + 章节标识) + 执行清单 Tab. */ (function () { const page = document.getElementById("page-strategy"); @@ -126,6 +126,22 @@ heads.forEach((h) => scrollSpyObs.observe(h)); } + function sectionTag(title) { + const t = String(title || ""); + if (/账户|定位/.test(t)) return "账户"; + if (/开仓类型|开仓|入场|反转|顺势|波段|假破|结构/.test(t)) return "入场"; + if (/周期/.test(t)) return "周期"; + if (/方向/.test(t)) return "方向"; + if (/纪律|出场|笔数|节奏/.test(t)) return "纪律"; + if (/持仓|离场|强平/.test(t)) return "离场"; + if (/资金|杠杆|计仓/.test(t)) return "仓位"; + if (/系统|字段|对接/.test(t)) return "系统"; + if (/修订|记录/.test(t)) return "版本"; + if (/边界|关系|行情状态/.test(t)) return "边界"; + if (/选择|如何/.test(t)) return "选择"; + return "章节"; + } + function buildDocToc() { if (!docBody || !docToc) return; const heads = Array.from(docBody.querySelectorAll("h2")); @@ -136,8 +152,10 @@ const used = {}; const items = []; heads.forEach((el, idx) => { - const num = String(idx + 1); - let base = "st-" + num + "-" + slugify(el.textContent); + const num = String(idx + 1).padStart(2, "0"); + const text = (el.textContent || "").trim(); + const tag = sectionTag(text); + let base = "st-" + num + "-" + slugify(text); if (!base || base === "st-" + num + "-") base = "st-" + num; let id = base; let n = 2; @@ -147,9 +165,17 @@ } used[id] = true; el.id = id; - items.push({ num, id, text: (el.textContent || "").trim() }); + if (!el.querySelector(".strategy-sec-mark")) { + const mark = document.createElement("span"); + mark.className = "strategy-sec-mark"; + mark.setAttribute("aria-hidden", "true"); + mark.innerHTML = + `${esc(num)}` + + `${esc(tag)}`; + el.insertBefore(mark, el.firstChild); + } + items.push({ num, id, text, tag }); }); - // 正文内 h3 仍保留锚点,便于日后扩展,但不进目录 Array.from(docBody.querySelectorAll("h3")).forEach((el, idx) => { if (el.id) return; let base = "st-h3-" + (idx + 1) + "-" + slugify(el.textContent); @@ -165,8 +191,9 @@ docToc.innerHTML = items .map( (it) => - `` + + `` + `${esc(it.num)}` + + `${esc(it.tag)}` + `${esc(it.text)}` ) .join("");