fix(frontend): align post thumbnail display with reference
This commit is contained in:
1 parent
542daca457
commit
4cdde50695
11 files changed
+201
-104
No files matched your search
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const { spawnSync } = require('node:child_process');
|
||||
const test = require('node:test');
|
||||
const root = path.resolve(__dirname, '../..');
|
||||
const result = spawnSync(process.env.PHP_BINARY || 'php', [path.join(__dirname, 'post-thumbnail-render-harness.php')], { cwd: root, encoding: 'utf8' });
|
||||
assert.equal(result.status, 0, result.stderr || result.stdout);
|
||||
const rendered = JSON.parse(result.stdout);
|
||||
|
||||
test('configured thumbnail ratios override body defaults for both list and card covers', () => {
|
||||
const main = fs.readFileSync(path.join(root, 'assets/css/main.css'), 'utf8');
|
||||
assert.match(main, /^body\s*\{[^}]*--posts-card-scale:\s*70%;[^}]*--posts-list-scale:\s*70%;/s);
|
||||
for (const [scenario, list, card] of [['defaults', 70, 70], ['custom', 100, 56], ['bounds', 50, 200]]) {
|
||||
const html = rendered.styles[scenario];
|
||||
const body = html.match(/<style id="aksrt-theme-color">body\{([^}]+)\}/)[1];
|
||||
assert.match(body, new RegExp(`--posts-list-scale:${list}%;`));
|
||||
assert.match(body, new RegExp(`--posts-card-scale:${card}%;`));
|
||||
const rootVariables = html.match(/<style id="aksrt-runtime-vars">:root\{([^}]+)\}/)[1];
|
||||
assert.doesNotMatch(rootVariables, /--posts-(list|card)-scale/);
|
||||
assert.equal((html.match(/--posts-list-scale:/g) || []).length, 1);
|
||||
assert.equal((html.match(/--posts-card-scale:/g) || []).length, 1);
|
||||
}
|
||||
});
|
||||
|
||||
test('featured attachments use the configured image size and missing attachments fall through in reference order', () => {
|
||||
assert.equal(rendered.featured.primary, 'https://example.test/featured-large.jpg');
|
||||
assert.equal(rendered.external.primary, 'https://example.test/external.jpg');
|
||||
assert.equal(rendered.content.primary, 'https://example.test/content.jpg');
|
||||
assert.equal(rendered.spare.primary, 'https://example.test/spare.jpg');
|
||||
assert.equal(rendered.featured.has_real, true);
|
||||
assert.equal(rendered.external.has_real, true);
|
||||
assert.equal(rendered.content.has_real, true);
|
||||
assert.equal(rendered.spare.has_real, false);
|
||||
assert.deepEqual(rendered.slides, ['https://example.test/featured-medium.jpg']);
|
||||
});
|
||||
|
||||
test('cover and contain images preserve the reference image and gradient wrappers', () => {
|
||||
assert.match(rendered.cover, /^<div class="item-thumbnail"><a[^>]+><img class="fit-cover radius8"/);
|
||||
assert.doesNotMatch(rendered.cover, /contain|gradient-bg/);
|
||||
assert.match(rendered.contain, /^<div class="item-thumbnail contain gradient-bg" data-opacity="0\.2">/);
|
||||
assert.match(rendered.contain, /src="https:\/\/example\.test\/featured-large\.jpg"/);
|
||||
});
|
||||
|
||||
test('one featured slide stays static and multiple slides retain every image with the reference interval', () => {
|
||||
assert.match(rendered.single, /new-swiper item-thumbnail swiper-container-initialized/);
|
||||
assert.doesNotMatch(rendered.single, /swiper-pagination|swiper-button/);
|
||||
assert.match(rendered.single, /class="lazyload radius8 swiper-lazy"/);
|
||||
assert.match(rendered.single, /data-src="https:\/\/example.test\/slide.jpg"/);
|
||||
assert.equal((rendered.multiple.match(/class="swiper-slide gradient-bg"/g) || []).length, 12);
|
||||
assert.match(rendered.multiple, /data-interval="4000"/);
|
||||
assert.match(rendered.multiple, /class="swiper-pagination kaoyou"/);
|
||||
assert.doesNotMatch(rendered.multiple, /swiper-container-initialized/);
|
||||
});
|
||||
|
||||
test('video thumbnails have one runtime player owner and retain the featured image before playback', () => {
|
||||
assert.match(rendered.video, /class="video-thumb-box" video-url="https:\/\/example.test\/movie.mp4" data-volume="none"/);
|
||||
assert.match(rendered.video, /class="img-thumb"><img[^>]+featured-large.jpg/);
|
||||
assert.match(rendered.video, /<div class="video-thumb"><\/div>/);
|
||||
assert.doesNotMatch(rendered.video, /<video\b|data-post-thumb-video|class="dplayer/);
|
||||
assert.doesNotMatch(fs.readFileSync(path.join(root, 'assets/js/core/misc.js'), 'utf8'), /initPostThumbMedia|data-post-thumb-video/);
|
||||
assert.doesNotMatch(fs.readFileSync(path.join(root, 'assets/css/frontend/post-card.css'), 'utf8'), /\.posts-item\.thumb-dplayer-playing|\.dplayer\.dplayer-thumb\s*\{/);
|
||||
assert.match(fs.readFileSync(path.join(root, 'assets/js/runtime/main.js'), 'utf8'), /thumb_dplayer\(_wid > 640[^\n]+video-thumb-box/);
|
||||
});
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/** Render thumbnail settings and image markup without a WordPress installation. */
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace AKSRT\Settings {
|
||||
final class Settings {
|
||||
public static array $values = [];
|
||||
public static function get_all(): array { return self::$values; }
|
||||
public static function get_post_list_style_settings(): array { return PostDisplay::get_post_list_style_settings(); }
|
||||
public static function logo_url(): string { return ''; }
|
||||
public static function logo_dark_url(): string { return ''; }
|
||||
public static function favicon_url(): string { return ''; }
|
||||
public static function theme_color(): string { return '#f04494'; }
|
||||
public static function dark_theme_color(): string { return '#abcdef'; }
|
||||
public static function main_radius(): int { return 8; }
|
||||
public static function container_max_width(): int { return 1200; }
|
||||
public static function font_family(): string { return 'system'; }
|
||||
public static function font_family_custom(): string { return ''; }
|
||||
public static function logo_width(): int { return 150; }
|
||||
public static function get_sidebar_config(): array { return ['width' => 311]; }
|
||||
public static function get_header_theme_config(): array { return []; }
|
||||
public static function background_css(string $key): string { return ''; }
|
||||
}
|
||||
}
|
||||
|
||||
namespace AKSRT\Core {
|
||||
final class PostMetaBox {
|
||||
public static array $meta = [];
|
||||
public static function get_meta_value(int $id, string $key, $default = '') { return self::$meta[$key] ?? $default; }
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
define('ABSPATH', dirname(__DIR__, 2) . DIRECTORY_SEPARATOR);
|
||||
set_error_handler(static function (int $severity, string $message, string $file, int $line): bool {
|
||||
if (!(error_reporting() & $severity)) return false;
|
||||
throw new \ErrorException($message, 0, $severity, $file, $line);
|
||||
});
|
||||
function __($text, $domain = ''): string { return (string) $text; }
|
||||
function esc_html($text): string { return htmlspecialchars((string) $text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
|
||||
function esc_attr($text): string { return esc_html($text); }
|
||||
function esc_url($url): string { return esc_attr($url); }
|
||||
function esc_url_raw($url): string { return (string) $url; }
|
||||
function sanitize_key($value): string { return preg_replace('/[^a-z0-9_-]/', '', strtolower((string) $value)); }
|
||||
function wp_kses_post($html): string { return (string) $html; }
|
||||
function strip_shortcodes($content): string { return (string) $content; }
|
||||
function wp_strip_all_tags($content): string { return strip_tags((string) $content); }
|
||||
function get_post_thumbnail_id($id): int { return $GLOBALS['featured_id']; }
|
||||
function attachment_url_to_postid($url): int { return 0; }
|
||||
function wp_get_attachment_image_url($id, $size) {
|
||||
return $id === 42 ? 'https://example.test/featured-' . $size . '.jpg' : false;
|
||||
}
|
||||
function get_post_field($field, $id, $context = ''): string { return $GLOBALS['post_content']; }
|
||||
function get_the_category($id): array { return []; }
|
||||
function get_post_format($id = null) { return false; }
|
||||
function aksrt_get_lazy_thumb($size = ''): string { return 'https://example.test/placeholder.svg'; }
|
||||
function aksrt_is_lazy($key): bool { return $key === 'lazy_sider'; }
|
||||
function aksrt_get_lazy_attr($key, $src, $class = ''): string {
|
||||
if (aksrt_is_lazy($key)) {
|
||||
return ' class="lazyload ' . esc_attr($class) . '" src="' . aksrt_get_lazy_thumb() . '" data-src="' . esc_url($src) . '"';
|
||||
}
|
||||
return ' class="' . esc_attr($class) . '" src="' . esc_url($src) . '"';
|
||||
}
|
||||
|
||||
require ABSPATH . 'src/Settings/PostDisplay.php';
|
||||
require ABSPATH . 'src/Frontend/InlineStyleBuilder.php';
|
||||
require ABSPATH . 'inc/helpers/posts-renderer/config.php';
|
||||
require ABSPATH . 'inc/helpers/posts-renderer/post-data.php';
|
||||
|
||||
$styles = [];
|
||||
foreach (['defaults' => [], 'custom' => ['list_list_option' => ['scale' => 100], 'list_card_option' => ['scale' => 56]], 'bounds' => ['list_list_option' => ['scale' => 1], 'list_card_option' => ['scale' => 900]]] as $name => $values) {
|
||||
\AKSRT\Settings\Settings::$values = $values;
|
||||
ob_start();
|
||||
(new \AKSRT\Frontend\InlineStyleBuilder())->output();
|
||||
$styles[$name] = (string) ob_get_clean();
|
||||
}
|
||||
|
||||
$GLOBALS['featured_id'] = 42;
|
||||
$GLOBALS['post_content'] = '<p><img src="https://example.test/content.jpg"></p>';
|
||||
\AKSRT\Core\PostMetaBox::$meta = ['thumbnail_url' => 'https://example.test/external.jpg'];
|
||||
$cfg = ['thumb' => ['thumb_postfirstimg_size' => 'large', 'thumb_postfirstimg_s' => true, 'spare_thumbnail' => ['https://example.test/spare.jpg']]];
|
||||
$featured = aksrt_renderer_resolve_images(1, $cfg);
|
||||
$GLOBALS['featured_id'] = 999;
|
||||
$external = aksrt_renderer_resolve_images(1, $cfg);
|
||||
\AKSRT\Core\PostMetaBox::$meta = [];
|
||||
$content = aksrt_renderer_resolve_images(1, $cfg);
|
||||
$GLOBALS['post_content'] = '';
|
||||
$spare = aksrt_renderer_resolve_images(1, $cfg);
|
||||
\AKSRT\Core\PostMetaBox::$meta = ['featured_slide' => '999,42'];
|
||||
$slides = aksrt_renderer_curated_images(1, 'medium');
|
||||
|
||||
$data = [
|
||||
'post_id' => 1, 'primary' => $featured['primary'], 'has_real' => true,
|
||||
'permalink' => 'https://example.test/post/', 'title' => 'Featured image',
|
||||
'video_url' => '', 'slides' => [], 'gallery_count' => 0,
|
||||
];
|
||||
$cover = aksrt_renderer_thumb($data, ['thumb' => ['list_thumb_fit' => '']]);
|
||||
$contain = aksrt_renderer_thumb($data, ['thumb' => ['list_thumb_fit' => 'contain']]);
|
||||
$data['is_slide'] = true;
|
||||
$data['slides'] = ['https://example.test/slide.jpg'];
|
||||
$single = aksrt_renderer_thumb($data, ['thumb' => []]);
|
||||
\AKSRT\Core\PostMetaBox::$meta = ['featured_slide' => implode(',', array_fill(0, 12, '42'))];
|
||||
$data['slides'] = aksrt_renderer_curated_images(1, 'large');
|
||||
$multiple = aksrt_renderer_thumb($data, ['thumb' => ['list_thumb_fit' => 'contain']]);
|
||||
$data['video_url'] = 'https://example.test/movie.mp4';
|
||||
$video = aksrt_renderer_thumb($data, ['thumb' => ['list_thumb_video_s' => true, 'list_thumb_video_mute_s' => true]]);
|
||||
|
||||
echo json_encode(compact('styles', 'featured', 'external', 'content', 'spare', 'slides', 'cover', 'contain', 'single', 'multiple', 'video'), JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
@@ -165,7 +165,9 @@ test('list, card, media, badge and Mini DOM follow dedicated legacy structures',
|
||||
assert.match(data, /relative aksrt-slider.*new-swiper item-thumbnail/s);
|
||||
assert.match(data, /swiper-slide.*gradient-bg.*data-opacity="0\.2"/s);
|
||||
assert.match(data, /\$fit = \$is_contain && !\$has_slides \? ' contain gradient-bg' : ''/);
|
||||
assert.match(data, /video-thumb-box.*data-post-thumb-video/s);
|
||||
assert.match(data, /video-thumb-box.*video-url=/s);
|
||||
assert.match(data, /<div class="video-thumb"><\/div>/);
|
||||
assert.doesNotMatch(data, /data-post-thumb-video/);
|
||||
assert.match(data, /class="thumb-items/);
|
||||
assert.match(data, /empty\(\$cfg\['is_category'\]\).*in_array\('cat'/s);
|
||||
assert.match(data, /empty\(\$cfg\['is_tag'\]\).*in_array\('tag'/s);
|
||||
@@ -372,10 +374,10 @@ test('AJAX pagination can recover, caps auto loading and rehydrates appended med
|
||||
assert.match(homepage, /aksrt_render_pagination\(\$query,[\s\S]*?'query_context'\s*=>\s*\$contract\['query_context'\]/);
|
||||
assert.doesNotMatch(homepage, /href="javascript:;" class="ajax-next aksrt-load-more-btn"/);
|
||||
assert.match(ajaxList, /if \(link\.closest\("\[data-aksrt-pagination\], \.aksrt-comment-pagination"\)\) return;/);
|
||||
assert.match(media, /thumb-dplayer-playing/);
|
||||
assert.match(read('assets/js/runtime/main.js'), /thumb_dplayer\(_wid > 640/);
|
||||
assert.doesNotMatch(media, /new Swiper|data-post-thumb-slider/);
|
||||
assert.match(read('assets/js/runtime/main.min.js'), /new-swiper/);
|
||||
assert.match(media, /data-post-thumb-video/);
|
||||
assert.doesNotMatch(media, /data-post-thumb-video|initPostThumbMedia/);
|
||||
assert.match(media, /window\.Grade\(container/);
|
||||
assert.match(media, /linear-gradient\(135deg/);
|
||||
assert.match(media, /aksrtGradientState/);
|
||||
|
||||
Reference in new issue
Block a user