fix(single): align slide and video cover heights with image cover

The image-mode cover reserves +50px for the title/breadcrumb overlay
(calc(scale% + 50px)), but the slide cover wrapper was given a bare
inline padding-bottom by aksrt_render_slider, permanently defeating the
.cover-slide rule, and the video cover used a bare video_scale%.

- aksrt_render_slider: add scale_extra so scale mode emits
  calc(ratio% + extra); the single cover passes 50px so all three
  modes share one height formula
- drop the unreachable static slide fallback and function_exists guard
  (the helper is unconditionally loaded by inc/bootstrap.php), the
  always-true cover_url/ep_count conditions, and the dead --scale-ratio
  and inner swiper padding emitted in scale mode
- remove the dead cover CSS cluster with no producer: .single-cover-slide
  (main.css/main.min.css/cover.css), .single-cover-slider family
  (components/base.css), .single-cover-slide-wrap and .single-cover__*
  helpers (cover.css), and initSlideCovers in misc.js
- rebuild public bundles via tools/build-public-assets.mjs
- add single-cover-height-contract test covering the shared formula
  and the dead-code removals
This commit is contained in:
2026-09-05 18:22:37 +08:00
parent 05a6b6fc54
commit 4f2d17f6ee
12 changed files with 133 additions and 418 deletions
@@ -0,0 +1,99 @@
'use strict';
// 文章详情页顶部封面高度契约:单图 / 多图(轮播) / 视频三种模式
// 必须共用同一高度公式 padding-bottom: calc(比例% + 50px)。
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const test = require('node:test');
const root = path.resolve(__dirname, '..', '..');
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
const singleRender = read('inc/helpers/aksrt-single-render.php');
const sliderHelper = read('inc/helpers/aksrt-slider.php');
test('single cover: image mode keeps the calc(scale% + 50px) height', () => {
assert.match(
singleRender,
/single-cover imgbox-container" style="padding-bottom:calc\(<\?php echo esc_attr\(\(string\) \$img_scale\); \?>% \+ 50px\);"/,
'单图封面必须输出 calc(img_scale% + 50px) 内联高度'
);
});
test('single cover: video mode aligns with the image-mode height formula', () => {
assert.match(
singleRender,
/single-cover--video imgbox-container" style="padding-bottom:calc\(<\?php echo esc_attr\(\(string\) \$video_scale\); \?>% \+ 50px\);"/,
'视频封面必须输出 calc(video_scale% + 50px) 内联高度'
);
// 不得回退到裸比例高度。
assert.doesNotMatch(
singleRender,
/padding-bottom:<\?php echo esc_attr\(\(string\) \$video_scale\); \?>%;"/,
'视频封面禁止输出不带 +50px 的裸比例高度'
);
});
test('single cover: slide mode reserves the same +50px via the slider helper', () => {
assert.match(
singleRender,
/'scale_extra'\s*=>\s*'50px'/,
'多图封面必须向 aksrt_render_slider 传入 scale_extra=50px'
);
assert.match(
sliderHelper,
/'scale_extra'\s*=>\s*''/,
'slider helper 需声明 scale_extra 默认参数'
);
// wrapper 的 padding-bottom 必须由比例 + 附加量组合而成。
assert.match(
sliderHelper,
/\$scale_padding = 'calc\(' \. \$scale_padding \. ' \+ ' \. \$scale_extra \. '\)';/,
'scale 模式必须把 scale_extra 合成 calc 表达式'
);
});
test('single cover: the dead static slide fallback is gone', () => {
assert.doesNotMatch(
singleRender,
/function_exists\('aksrt_render_slider'\)/,
'aksrt_render_slider 由 bootstrap 无条件加载,不得保留 function_exists 双路判断'
);
assert.doesNotMatch(
singleRender,
/single-cover--slide imgbox-container" style="padding-bottom/,
'多图封面只允许经由 slider helper 输出,禁止保留静态 fallback 分支'
);
});
test('slider scale mode: inner swiper carries no dead inline height styles', () => {
assert.doesNotMatch(
sliderHelper,
/--scale-ratio/,
'--scale-ratio 无任何 CSS 消费方,禁止输出'
);
const scaleMode = sliderHelper.split("if ($args['scale_height']) {")[1] || '';
assert.ok(scaleMode.includes("position:absolute;inset:0;width:100%;height:100%;"));
});
test('dead cover css is removed from every stylesheet surface', () => {
for (const file of [
'assets/css/frontend/single-post/cover.css',
'assets/css/main.css',
'assets/css/main.min.css',
'assets/css/build/public.css',
'assets/css/build/public.min.css',
'assets/css/frontend/enhancements/components/base.css',
]) {
const css = read(file);
assert.doesNotMatch(css, /\.single-cover-slide[,{ ]/, `${file} 不得再包含死的 .single-cover-slide 规则`);
assert.doesNotMatch(css, /\.single-cover-slider\b/, `${file} 不得再包含死的 .single-cover-slider 规则`);
}
assert.doesNotMatch(
read('assets/js/core/misc.js'),
/initSlideCovers/,
'misc.js 的 initSlideCovers(无标记生产方)已删除'
);
});