Files
wordpress-theme-aksrt/tests/widget-system/user-card-runtime-harness.php
T
kate522 9cb5e7bea3 feat(frontend): unify avatar shape, move VIP icon to badge row
Make --radius-avatar the single source of truth for frontend user avatar shape. A new primitive in components-ext.css (img.avatar / avatar-mini / avatar-md / avatar-lg / .avatar-img img) forces a circle on every avatar image, which covers the bare avatar-mini in the ban and report modals, the classless img inside the VIP modal's .avatar-img, and the post-card meta avatar that previously depended on post-card.css being enqueued. The user center header frame, the public user home hero and the friends page avatar switch to the same token because route CSS loads after the public bundle and would otherwise override the primitive.

The VIP icon no longer rides the avatar corner. The user card widget, the after-article author card and the sign-in modal stop opting into aksrt_get_avatar_box()'s corner badge, and the icon renders first in the badge/level row instead, since aksrt_get_user_name already orders name -> VIP -> auth -> medal -> level. The sign-in modal appends it after the display name and keeps the legacy precedence where a ban badge takes the VIP slot. The user card widget name row now shrinks its display name so the extra icon cannot overflow a narrow sidebar.

Verified with the new frontend-avatar-shape-contract test plus post-visual, user-card-runtime, circular-button-icon-margin, user-features and page-display contracts, and php -l on every changed PHP file. The public bundle was rebuilt with tools/build-public-assets.mjs.
2026-10-10 13:53:07 +08:00

182 lines
6.9 KiB
PHP

<?php
declare(strict_types=1);
namespace AKSRT\Settings {
final class Settings {
public static bool $closed = false;
public static bool $registration = true;
public static function close_sign(): bool {
return self::$closed;
}
public static function registration_enabled(): bool {
return self::$registration;
}
}
}
namespace AKSRT\Auth {
final class OAuth {
public static function get_instance(): self {
return new self();
}
public function get_auth_providers_data(): array {
return [
[
'name' => 'github',
'label' => 'GitHub',
'icon' => '<i class="fa fab fa-github"></i>',
'url' => 'https://example.test/oauth/github',
],
[
'name' => 'clogin_qq',
'label' => 'QQ · 聚合',
'icon' => '<i class="fa fab fa-qq"></i>',
'url' => 'https://example.test/oauth/qq',
],
];
}
}
}
namespace {
if (!defined('ABSPATH')) {
define('ABSPATH', __DIR__);
}
final class WP_User {
public int $ID;
public string $display_name;
public function __construct(int $id, string $display_name) {
$this->ID = $id;
$this->display_name = $display_name;
}
}
final class WP_Post {
public int $ID;
public int $post_author;
public function __construct(int $id, int $post_author) {
$this->ID = $id;
$this->post_author = $post_author;
}
}
$GLOBALS['aksrt_user_card_state'] = [
'current_user_id' => 0,
'post' => null,
];
function __($text, $domain = null): string { unset($domain); return (string) $text; }
function esc_html__($text, $domain = null): string { return esc_html(__($text, $domain)); }
function esc_attr__($text, $domain = null): string { return esc_attr(__($text, $domain)); }
function esc_html($value): string { return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
function esc_attr($value): string { return esc_html($value); }
function esc_url($value): string { return esc_attr((string) $value); }
function sanitize_key($value): string { return preg_replace('/[^a-z0-9_\-]/', '', strtolower((string) $value)) ?? ''; }
function sanitize_html_class($value): string { return preg_replace('/[^A-Za-z0-9_-]/', '', (string) $value) ?? ''; }
function wp_parse_args($args, array $defaults = []): array { return array_merge($defaults, is_array($args) ? $args : []); }
function get_option($name, $default = false) { unset($name); return $default; }
function get_current_user_id(): int { return (int) $GLOBALS['aksrt_user_card_state']['current_user_id']; }
function get_userdata($user_id): ?WP_User {
$user_id = (int) $user_id;
return $user_id > 0 ? new WP_User($user_id, 'User ' . $user_id) : null;
}
function get_post(): ?WP_Post { return $GLOBALS['aksrt_user_card_state']['post']; }
function aksrt_get_user_cover_url(int $user_id): string {
return $user_id > 0 ? 'https://example.test/cover-' . $user_id . '.jpg' : 'https://example.test/default-cover.jpg';
}
function aksrt_get_lazy_thumb(): string { return 'https://example.test/lazy.svg'; }
function aksrt_get_lazy_attr(string $type, string $url, string $class, string $placeholder = ''): string {
return ' class="' . esc_attr($class) . '" data-lazy-type="' . esc_attr($type) . '" src="' . esc_url($placeholder ?: $url) . '" data-src="' . esc_url($url) . '"';
}
function aksrt_get_default_avatar_url(): string { return 'https://example.test/default-avatar.png'; }
function aksrt_get_avatar_html($subject, int $size, array $attrs = []): string {
unset($subject);
return '<img class="' . esc_attr((string) ($attrs['class'] ?? 'avatar')) . '" alt="' . esc_attr((string) ($attrs['alt'] ?? '')) . '" width="' . $size . '" height="' . $size . '">';
}
function aksrt_get_avatar_box($user_id, string $class, bool $link = true, bool $vip = true): string {
$inner = '<span class="' . esc_attr($class) . '"><img class="avatar"></span>';
return $link ? '<a href="https://example.test/user/' . (int) $user_id . '">' . $inner . '</a>' : $inner;
}
function aksrt_get_user_name(array $args): string {
return '<name class="' . esc_attr((string) ($args['class'] ?? '')) . '"><a class="display-name">User ' . (int) ($args['id'] ?? 0) . '</a></name>';
}
function aksrt_get_user_badges(int $user_id): string { return '<span class="badg">' . $user_id . '</span>'; }
function aksrt_get_user_description(int $user_id): string { return 'Description ' . $user_id; }
function aksrt_header_user_checkin_btn(int $user_id, bool $large, string $class): string {
unset($user_id, $large);
return '<button class="' . esc_attr($class) . '">签到</button>';
}
function aksrt_render_user_card_posts(array $args): string {
return '<div data-post-type="' . esc_attr((string) ($args['post_type'] ?? '')) . '" data-post-style="' . esc_attr((string) ($args['post_style'] ?? '')) . '"></div>';
}
function aksrt_get_new_post_url(): string { return 'https://example.test/new-post'; }
function aksrt_get_user_home_url($user_id): string { return 'https://example.test/user/' . (int) $user_id; }
function aksrt_get_user_center_url(): string { return 'https://example.test/user-center'; }
function aksrt_renderer_svg_icon(string $name): string { return '<svg data-icon="' . esc_attr($name) . '"></svg>'; }
require dirname(__DIR__, 2) . '/src/WidgetSystem/Renderers/UserRenderer.php';
function aksrt_render_user_widget_state(string $slug, array $instance): string {
return \AKSRT\WidgetSystem\Renderers\UserRenderer::render($slug, $instance);
}
\AKSRT\Settings\Settings::$closed = false;
\AKSRT\Settings\Settings::$registration = true;
$GLOBALS['aksrt_user_card_state']['current_user_id'] = 0;
$guest = aksrt_render_user_widget_state('user_card', [
'show_img_bg' => true,
'loged_title' => 'HI!请登录',
]);
\AKSRT\Settings\Settings::$registration = false;
$guest_no_registration = aksrt_render_user_widget_state('user_card', [
'show_img_bg' => true,
'loged_title' => 'HI!请登录',
]);
\AKSRT\Settings\Settings::$closed = true;
$closed = aksrt_render_user_widget_state('user_card', []);
\AKSRT\Settings\Settings::$closed = false;
\AKSRT\Settings\Settings::$registration = true;
$GLOBALS['aksrt_user_card_state']['current_user_id'] = 7;
$logged = aksrt_render_user_widget_state('user_card', [
'show_img_bg' => true,
'show_button' => false,
]);
$logged_buttons = aksrt_render_user_widget_state('user_card', [
'show_img_bg' => false,
'button_1_text' => '发布文章',
'button_2_text' => '用户中心',
]);
$GLOBALS['aksrt_user_card_state']['current_user_id'] = 2;
$GLOBALS['aksrt_user_card_state']['post'] = new WP_Post(33, 9);
$author = aksrt_render_user_widget_state('author_card', [
'show_img_bg' => true,
'show_posts' => true,
'post_style' => 'card',
'limit' => 6,
'orderby' => 'date',
'show_button' => true,
]);
echo json_encode([
'guest' => $guest,
'guest_no_registration' => $guest_no_registration,
'closed' => $closed,
'logged' => $logged,
'logged_buttons' => $logged_buttons,
'author' => $author,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}