v0.4.1: OSS skill videos, site version footer, and mail contact.

Host ability demos on Aliyun OSS instead of Pages bundles; add patches-page version label and top-right mailto link; improve spirit bear portrait export.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
voson
2026-07-27 20:26:30 +08:00
co-authored by Cursor
parent adb8f303c2
commit 124bdbb7c7
11 changed files with 289 additions and 22 deletions
+34 -3
View File
@@ -1,4 +1,30 @@
/* global fetch, document */
/* global fetch, document, ABILITY_VIDEO_BASE, SITE_VERSION */
/** OSS / CDN base for ability demos; empty => same-origin `/ability-video/...`. */
function abilityVideoBase() {
const raw =
typeof ABILITY_VIDEO_BASE === "string" ? ABILITY_VIDEO_BASE.trim() : "";
return raw.replace(/\/+$/, "");
}
function abilityVideoUrl(heroKey, abilityKey) {
const rel = `/ability-video/${heroKey}/${abilityKey}.webm`;
const base = abilityVideoBase();
return base ? `${base}${rel}` : rel;
}
function siteVersionLabel() {
const v = typeof SITE_VERSION === "string" ? SITE_VERSION.trim() : "";
return v ? `v${v}` : "";
}
function renderPatchesSiteVersion() {
const el = $("#patches-site-version");
if (!el) return;
const label = siteVersionLabel();
el.textContent = label;
el.setAttribute("aria-hidden", label ? "false" : "true");
}
const state = {
data: null,
@@ -724,15 +750,17 @@ function mountSkillInspect(root, skillEnt, heroKey) {
// Official-page layout: demo clip on the left, name/desc column on the right.
const body = document.createElement("div");
body.className = "skill-info-body";
// Official demo clip (assets/ability_videos); hidden when not cached locally.
// Official demo clip: local `/ability-video/...` (serve_relations) or OSS base
// from config.js (static export / Pages). Hidden when the file is missing.
if (heroKey && skillEnt.ability_key) {
const video = document.createElement("video");
video.className = "skill-info-video";
video.src = `/ability-video/${heroKey}/${skillEnt.ability_key}.webm`;
video.src = abilityVideoUrl(heroKey, skillEnt.ability_key);
video.muted = true;
video.loop = true;
video.autoplay = true;
video.playsInline = true;
video.crossOrigin = "anonymous";
video.addEventListener("error", () => video.remove());
body.appendChild(video);
}
@@ -1723,6 +1751,7 @@ function renderPatches() {
if (select) select.innerHTML = "";
if (verEl) verEl.textContent = "";
root.innerHTML = '<div class="patches-empty">暂无版本数据,请运行 python fetch_patches.py</div>';
renderPatchesSiteVersion();
return;
}
@@ -1753,6 +1782,7 @@ function renderPatches() {
const det = details[state.selectedPatch];
if (!det) {
root.innerHTML = '<div class="patches-empty">该版本详情暂未抓取,请重跑 python fetch_patches.py</div>';
renderPatchesSiteVersion();
return;
}
@@ -1785,6 +1815,7 @@ function renderPatches() {
.map((h) => renderHeroEntry(h, lookup))
.join("");
renderPatchSection(root, "英雄改动", heroesHtml);
renderPatchesSiteVersion();
}
function escapeHtml(s) {