support wrapped recharge reward slots

This commit is contained in:
zhx 2026-05-26 21:02:42 +08:00
parent f888682c13
commit 196438b02c

View File

@ -765,6 +765,13 @@
var LEVEL_GAP = 814;
var LEVEL_PANEL_HEIGHT = 618;
var LEVEL_BOTTOM_PADDING = 57;
var REWARD_COLUMNS = 3;
var REWARD_ROW_GAP = 330;
var REWARD_FRAME_LEFTS = {
1: [420],
2: [269, 571],
3: [118, 420, 722],
};
var query = buildPageQueryParams();
var countdownTimer = null;
var countdownEndsAt = 0;
@ -1024,22 +1031,68 @@
});
}
function setCanvasHeight(levelCount) {
var count = Math.max(0, Number(levelCount) || 0);
var height = count > 0
? LEVEL_PANEL_TOP + ((count - 1) * LEVEL_GAP) + LEVEL_PANEL_HEIGHT + LEVEL_BOTTOM_PADDING
function layoutPanel(panel, panelHeight) {
if (!panel) return;
panel.style.height = panelHeight + "px";
var middleHeight = Math.max(0, panelHeight - 382);
var middles = Array.prototype.slice.call(panel.querySelectorAll(".panel-middle"));
var middle = middles[0];
if (middle) {
middle.classList.remove("is-hidden");
middle.style.top = "191px";
middle.style.height = middleHeight + "px";
}
middles.slice(1).forEach(function (node) {
node.classList.add("is-hidden");
});
var bottom = panel.querySelector(".panel-edge.bottom");
if (bottom) bottom.style.top = (panelHeight - 191) + "px";
}
function rewardRowCount(level) {
var rewardCount = levelRewards(level).length;
return Math.max(1, Math.ceil(rewardCount / REWARD_COLUMNS));
}
function rewardExtraHeight(rowCount) {
return Math.max(0, Number(rowCount || 1) - 1) * REWARD_ROW_GAP;
}
function buildLevelLayouts(levels) {
var offset = 0;
return levels.map(function (level) {
var rowCount = rewardRowCount(level);
var layout = {
offset: offset,
rowCount: rowCount,
panelHeight: LEVEL_PANEL_HEIGHT + rewardExtraHeight(rowCount),
};
offset += LEVEL_GAP + rewardExtraHeight(rowCount);
return layout;
});
}
function setCanvasHeight(layouts) {
var count = Array.isArray(layouts) ? layouts.length : 0;
var last = count > 0 ? layouts[count - 1] : null;
var height = last
? LEVEL_PANEL_TOP + last.offset + last.panelHeight + LEVEL_BOTTOM_PADDING
: LEVEL_BASE_HEIGHT;
document.documentElement.style.setProperty("--canvas-height", height + "px");
}
function layoutLevelSection(section, index) {
function layoutLevelSection(section, index, layout) {
if (!section) return;
var offset = index * LEVEL_GAP;
var offset = layout ? layout.offset : index * LEVEL_GAP;
var panelHeight = layout ? layout.panelHeight : LEVEL_PANEL_HEIGHT;
var rowCount = layout ? layout.rowCount : 1;
section.setAttribute("data-level-section", String(index));
section.setAttribute("data-level-offset", String(offset));
section.setAttribute("data-level-row-count", String(rowCount));
section.setAttribute("aria-label", "Recharge level " + (index + 1));
var panel = firstLevelPanel(section);
setTop(panel, LEVEL_PANEL_TOP + offset);
if (panel) panel.style.height = LEVEL_PANEL_HEIGHT + "px";
layoutPanel(panel, panelHeight);
setTop(section.querySelector(".section-badge"), LEVEL_BADGE_TOP + offset);
setTop(section.querySelector("[data-level-title]"), LEVEL_TITLE_TOP + offset);
Array.prototype.slice.call(section.querySelectorAll("[data-level-frame]")).forEach(function (node) {
@ -1053,8 +1106,9 @@
});
}
function ensureLevelSections(levelCount) {
var targetCount = Math.max(0, Number(levelCount) || 0);
function ensureLevelSections(levels) {
var targetCount = Array.isArray(levels) ? levels.length : Math.max(0, Number(levels) || 0);
var layouts = Array.isArray(levels) ? buildLevelLayouts(levels) : [];
var sections = Array.prototype.slice.call(document.querySelectorAll("[data-level-section]"));
var template = sections[0];
if (!template) return [];
@ -1064,14 +1118,71 @@
sections.push(next);
}
sections.forEach(function (section, index) {
layoutLevelSection(section, index);
layoutLevelSection(section, index, layouts[index]);
section.classList.toggle("is-hidden", index >= targetCount);
});
setCanvasHeight(targetCount);
setCanvasHeight(layouts);
els.sections = sections;
return sections;
}
function ensureRewardSlots(section, rewardCount) {
var targetCount = Math.max(0, Number(rewardCount) || 0);
var frames = Array.prototype.slice.call(section.querySelectorAll("[data-level-frame]"));
var images = Array.prototype.slice.call(section.querySelectorAll("[data-reward-image]"));
var prices = Array.prototype.slice.call(section.querySelectorAll(".reward-price"));
var frameTemplate = frames[0];
var imageTemplate = images[0];
var priceTemplate = prices[0];
while (frames.length < targetCount && frameTemplate) {
var frame = frameTemplate.cloneNode(true);
frame.setAttribute("data-level-frame", String(frames.length));
section.appendChild(frame);
frames.push(frame);
}
while (images.length < targetCount && imageTemplate) {
var image = imageTemplate.cloneNode(true);
image.setAttribute("data-reward-image", String(images.length));
section.appendChild(image);
images.push(image);
}
while (prices.length < targetCount && priceTemplate) {
var price = priceTemplate.cloneNode(true);
var label = price.querySelector("[data-reward-label]");
if (label) label.setAttribute("data-reward-label", String(prices.length));
section.appendChild(price);
prices.push(price);
}
}
function rewardFrameLeft(rowSize, slotIndex) {
var positions = REWARD_FRAME_LEFTS[Math.max(1, Math.min(REWARD_COLUMNS, rowSize))] || REWARD_FRAME_LEFTS[3];
return positions[Math.max(0, Math.min(slotIndex, positions.length - 1))];
}
function positionRewardNodes(section, index, totalRewards, nodes) {
var offset = Number(section.getAttribute("data-level-offset") || 0);
var rowIndex = Math.floor(index / REWARD_COLUMNS);
var rowStart = rowIndex * REWARD_COLUMNS;
var rowSize = Math.min(REWARD_COLUMNS, totalRewards - rowStart);
var slotIndex = index - rowStart;
var frameLeft = rewardFrameLeft(rowSize, slotIndex);
var rowOffset = rowIndex * REWARD_ROW_GAP;
if (nodes.frame) {
nodes.frame.style.left = frameLeft + "px";
setTop(nodes.frame, LEVEL_FRAME_TOP + offset + rowOffset);
}
if (nodes.image) {
nodes.image.style.left = (frameLeft + 20) + "px";
setTop(nodes.image, LEVEL_ICON_TOP + offset + rowOffset);
}
if (nodes.price) {
nodes.price.style.left = (frameLeft - 22) + "px";
setTop(nodes.price, LEVEL_PRICE_TOP + offset + rowOffset);
}
}
function renderLevel(section, level) {
if (!section) return;
if (!level) {
@ -1082,6 +1193,7 @@
var title = section.querySelector("[data-level-title]");
if (title) title.textContent = "Recharge $" + formatAmountCents(centsValue(level));
var rewards = levelRewards(level);
ensureRewardSlots(section, rewards.length);
var images = Array.prototype.slice.call(section.querySelectorAll("[data-reward-image]"));
var labels = Array.prototype.slice.call(section.querySelectorAll("[data-reward-label]"));
var frames = Array.prototype.slice.call(section.querySelectorAll("[data-level-frame]"));
@ -1093,6 +1205,11 @@
if (node) node.classList.toggle("is-hidden", !reward);
});
if (!reward) continue;
positionRewardNodes(section, i, rewards.length, {
frame: frames[i],
image: images[i],
price: prices[i],
});
setImage(images[i], reward.cover, DEFAULT_REWARD_ICON);
if (labels[i]) labels[i].textContent = rewardLabel(reward);
}
@ -1111,7 +1228,7 @@
startCountdown(body.countdownMillis);
var levels = normalizeLevels(body.levelConfigs);
if (Array.isArray(body.levelConfigs)) {
ensureLevelSections(levels.length).forEach(function (section, index) {
ensureLevelSections(levels).forEach(function (section, index) {
renderLevel(section, levels[index]);
});
}