Show recent item patch notes under the shop detail panel.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
voson
2026-07-31 10:18:17 +08:00
co-authored by Cursor
parent 961574037e
commit 1e44c0eb9b
6 changed files with 89 additions and 9 deletions
+59
View File
@@ -3590,6 +3590,9 @@ function renderItemDetail() {
render();
},
});
const patchPanel = buildItemPatchChangesPanel(meta.key);
if (patchPanel) root.appendChild(patchPanel);
}
// Stat-icon labels for patch hero_notes (icon field). Attr values map to the
@@ -3772,6 +3775,62 @@ function buildPatchChangesPanel(heroKey) {
return wrap;
}
/** Match shop/item key against a patch items or neutral_items entry via lookup. */
function patchItemEntryForKey(entries, itemKey, lookup) {
if (!itemKey || !entries?.length) return null;
const itemsLookup = (lookup && lookup.items) || {};
for (const entry of entries) {
if (!entry || entry.is_general_note || entry.ability_id === -1) continue;
const meta = itemsLookup[String(entry.ability_id)];
if (meta && meta.key === itemKey) return entry;
}
return null;
}
/** Recent patch notes for one item (shop detail). Null when none in window. */
function buildItemPatchChangesPanel(itemKey) {
const patches = state.data.patches || [];
const details = state.data.patch_details || {};
const lookup = state.data.patch_lookup || { items: {}, abilities: {}, heroes: {} };
if (!itemKey || !patches.length) return null;
const blocks = [];
for (const p of patches) {
const det = details[p.version];
if (!det) continue;
const entry =
patchItemEntryForKey(det.items, itemKey, lookup) ||
patchItemEntryForKey(det.neutral_items, itemKey, lookup);
if (!entry) continue;
const notesHtml = renderNotesList(entry.ability_notes);
if (!notesHtml) continue;
const patchDate =
formatAbsoluteTime(p.date || p.timestamp, { dateOnly: true }) ||
p.date ||
"";
blocks.push(
`<div class="patch-change-version">` +
`<div class="patch-change-ver">${escapeHtml(p.version)}` +
`<span class="patch-change-date">${escapeHtml(patchDate)}</span></div>` +
notesHtml +
`</div>`
);
}
if (!blocks.length) return null;
const section = document.createElement("div");
section.className = "item-detail-patches";
const label = document.createElement("div");
label.className = "craft-label";
label.textContent = "改动";
section.appendChild(label);
const wrap = document.createElement("div");
wrap.className = "patch-changes item-patch-changes";
wrap.innerHTML = blocks.join("");
section.appendChild(wrap);
return section;
}
function ensureDefaultPatch() {
const patches = state.data?.patches || [];
if (!patches.length) return;
+1 -1
View File
@@ -1,5 +1,5 @@
/* Local defaults; production export overwrites via export_relations_site.py. */
var SITE_VERSION = "0.6.14";
var SITE_VERSION = "0.6.15";
var SITE_ORIGIN = "";
var ABILITY_VIDEO_BASE = "";
var STATIC_ASSET_BASE = "";
+5 -5
View File
@@ -43,8 +43,8 @@
}
</script>
<link rel="icon" href="/ui-icon/dota2_logo.png" type="image/png" />
<link rel="stylesheet" href="/style.css?v=0.6.14" />
<script src="/mobile-gate.js?v=0.6.14"></script>
<link rel="stylesheet" href="/style.css?v=0.6.15" />
<script src="/mobile-gate.js?v=0.6.15"></script>
</head>
<body>
<h1 class="sr-only">DOTA2 上分帝</h1>
@@ -240,8 +240,8 @@
</div>
<footer class="heroes-site-foot" id="heroes-site-foot" aria-hidden="true"></footer>
<script src="/config.js?v=0.6.14"></script>
<script src="/router.js?v=0.6.14"></script>
<script src="/app.js?v=0.6.14"></script>
<script src="/config.js?v=0.6.15"></script>
<script src="/router.js?v=0.6.15"></script>
<script src="/app.js?v=0.6.15"></script>
</body>
</html>
+17 -2
View File
@@ -2639,16 +2639,31 @@ body:has(#items-view:not(.hidden)) {
flex: 1 1 auto;
}
.item-detail-recipe,
.item-detail-upgrades {
.item-detail-upgrades,
.item-detail-patches {
margin-top: 4px;
padding-top: 12px;
border-top: 1px solid var(--line);
}
.item-detail-recipe .craft-label,
.item-detail-upgrades .craft-label {
.item-detail-upgrades .craft-label,
.item-detail-patches .craft-label {
display: block;
margin: 0 0 8px;
}
.item-detail-box .item-patch-changes {
max-width: 100%;
margin: 0;
padding: 0;
gap: 12px;
}
.item-detail-box .patch-change-ver {
font-size: var(--fs-body-sm);
}
.item-detail-box .patch-notes {
font-size: var(--fs-label);
line-height: 1.45;
}
.shop-col-headers {
width: 100%;
display: grid;