diff --git a/assets/css/frontend/medal.css b/assets/css/frontend/medal.css index 465021db..60f2760e 100644 --- a/assets/css/frontend/medal.css +++ b/assets/css/frontend/medal.css @@ -7,7 +7,63 @@ * 加载条件与 user-badges.js 一致(badge surface 页面)。 * ============================================================ */ -/* ---------- 分类分组(zibll .medal-cat-box / .medal-cat-name) ---------- */ +/* ---------- 顶部资料卡入口(zibll user-medal-info parity) ---------- */ +.aksrt-medal-entry { + display: inline-flex; + align-items: center; + gap: 4px; + min-width: 0; + margin: 2px 8px 2px 0; + padding: 2px 0; + border: 0; + background: transparent; + color: var(--muted-2-color, var(--color-ink-4)); + font: inherit; + font-size: 12px; + line-height: 1.4; + cursor: pointer; + white-space: nowrap; + transition: color .15s ease, opacity .15s ease; +} +.aksrt-medal-entry:hover, +.aksrt-medal-entry:focus-visible { + color: var(--focus-color); + opacity: 1; +} +.aksrt-medal-entry:focus-visible { + outline: 2px solid var(--focus-color); + outline-offset: 2px; + border-radius: var(--mini-radius, 6px); +} +.aksrt-medal-entry__icons { + display: inline-flex; + align-items: center; + flex: none; + min-width: 0; +} +.aksrt-medal-entry__icon { + width: auto; + height: 1.45em; + max-width: 2.2em; + margin: 0 1px; + object-fit: contain; + vertical-align: middle; +} +.aksrt-medal-entry__icon + .aksrt-medal-entry__icon { margin-left: -1px; } +.aksrt-medal-entry__fallback { + display: inline-flex; + align-items: center; + justify-content: center; + width: 1.6em; + height: 1.6em; + color: var(--focus-color); + background: var(--focus-color-opacity1); + border-radius: 50%; +} +.aksrt-medal-entry__count { margin-left: 2px; } +.aksrt-medal-entry__arrow { margin-left: 1px; font-size: .9em; } + + .medal-cat-box { position: relative; text-align: center; diff --git a/assets/css/frontend/widget-batch5.css b/assets/css/frontend/widget-batch5.css index f320be8e..9e5995e3 100644 --- a/assets/css/frontend/widget-batch5.css +++ b/assets/css/frontend/widget-batch5.css @@ -738,8 +738,7 @@ } .aksrt-author-card__badge img { border-radius: 50%; } -/* 徽章远程弹窗样式已迁至 assets/css/frontend/medal.css(zibll medal 风格)。 */ -.aksrt-author-hero__badges { margin-top: 8px; } +/* 徽章入口与弹窗样式统一由 assets/css/frontend/medal.css 提供。 */ /* Forum tab topics (batch6) */ .aksrt-ftab__nav { diff --git a/inc/helpers/aksrt-identity.php b/inc/helpers/aksrt-identity.php index 6dde7567..eac33cd5 100644 --- a/inc/helpers/aksrt-identity.php +++ b/inc/helpers/aksrt-identity.php @@ -234,6 +234,63 @@ if (!function_exists('aksrt_get_user_name')) { } } +if (!function_exists('aksrt_render_user_medal_entry')) { + /** + * Render the compact Zibll-style badge overview entry. + * + * The configured limit controls preview icons only; the count remains + * the complete owned badge count returned by the privacy-aware DTO. + * + * @param int $user_id + * @param string $context user-center|user-home + * @param bool $can_wear Whether the viewer may initially wear a badge. + */ + function aksrt_render_user_medal_entry(int $user_id, string $context = 'user-home', bool $can_wear = false): string { + if ($user_id <= 0 || !class_exists('AKSRT\\User\\Badges') || !class_exists('AKSRT\\Settings\\Settings')) { + return ''; + } + + $settings = \AKSRT\Settings\Settings::get_user_identity_settings(); + $medal = is_array($settings['medal'] ?? null) ? $settings['medal'] : []; + if (empty($medal['enabled']) || ($context === 'user-home' && empty($medal['public_display']))) { + return ''; + } + + $data = \AKSRT\User\Badges::list_for_user($user_id); + if (empty($data['enabled']) || ($context === 'user-home' && empty($data['public_display']))) { + return ''; + } + + $limit = max(1, min(8, (int) ($medal['limit'] ?? 3))); + $icons = []; + foreach ((array) ($data['categories'] ?? []) as $category) { + foreach ((array) ($category['items'] ?? []) as $item) { + if (empty($item['owned'])) { + continue; + } + $icon_url = esc_url((string) ($item['icon_url'] ?? '')); + if ($icon_url === '') { + continue; + } + $label = sanitize_text_field((string) ($item['label'] ?? __('徽章', 'aksrt'))); + $icons[] = '' . esc_attr($label) . ''; + if (count($icons) >= $limit) { + break 2; + } + } + } + + $count = max(0, (int) ($data['count'] ?? 0)); + $label = $count > 0 ? sprintf(_n('%d枚徽章', '%d枚徽章', $count, 'aksrt'), $count) : __('获取徽章', 'aksrt'); + $icons_html = implode('', $icons); + if ($icons_html === '') { + $icons_html = ''; + } + $classes = 'aksrt-medal-entry aksrt-medal-entry--' . sanitize_html_class($context); + return ''; + } +} + if (!function_exists('aksrt_user_has_visible_badges')) { /** * Whether a user owns at least one badge that exists in the current catalog. diff --git a/inc/helpers/user-center-renderers/profile-header.php b/inc/helpers/user-center-renderers/profile-header.php index 1570b3b1..607a85ca 100644 --- a/inc/helpers/user-center-renderers/profile-header.php +++ b/inc/helpers/user-center-renderers/profile-header.php @@ -41,6 +41,9 @@ extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_
+ + + user_login); ?> @@ -61,12 +64,6 @@ extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_
- - - - diff --git a/src/User/Badges.php b/src/User/Badges.php index 7a46df70..d037cec2 100644 --- a/src/User/Badges.php +++ b/src/User/Badges.php @@ -168,7 +168,7 @@ class Badges { return false; } $settings = \AKSRT\Settings\Settings::get_user_identity_settings(); - return !empty($settings['badge']['enabled']); + return !empty($settings['medal']['enabled']); } public static function public_display(): bool { @@ -176,7 +176,7 @@ class Badges { return false; } $settings = \AKSRT\Settings\Settings::get_user_identity_settings(); - return !empty($settings['badge']['enabled']) && !empty($settings['badge']['public_display']); + return !empty($settings['medal']['enabled']) && !empty($settings['medal']['public_display']); } /** @@ -190,7 +190,20 @@ class Badges { return self::$dictionary_cache = []; } $settings = \AKSRT\Settings\Settings::get_user_identity_settings(); - $dict = is_array($settings['badge']['dictionary'] ?? null) ? $settings['badge']['dictionary'] : []; + $medal = is_array($settings['medal'] ?? null) ? $settings['medal'] : []; + $dict = []; + foreach ((array) ($medal['items_by_slug'] ?? []) as $item) { + if (!is_array($item)) { + continue; + } + $dict[] = [ + 'slug' => sanitize_key((string) ($item['slug'] ?? '')), + 'label' => (string) ($item['name'] ?? $item['slug'] ?? ''), + 'tone' => 'neutral', + 'desc' => (string) ($item['desc'] ?? ''), + 'icon_url' => (string) ($item['icon'] ?? ''), + ]; + } $out = []; foreach ($dict as $item) { $slug = sanitize_key((string) ($item['slug'] ?? '')); diff --git a/src/User/Home.php b/src/User/Home.php index 891e5601..4578d551 100644 --- a/src/User/Home.php +++ b/src/User/Home.php @@ -161,8 +161,8 @@ class Home { } } - if (!empty($settings['badge']['enabled']) && !empty($settings['badge']['public_display'])) { - $limit = max(1, (int) ($settings['badge']['limit'] ?? 3)); + if (!empty($settings['medal']['enabled']) && !empty($settings['medal']['public_display'])) { + $limit = max(1, (int) ($settings['medal']['limit'] ?? 3)); if (class_exists('AKSRT\\User\\Badges')) { $list = Badges::list_for_user($user_id); $badge_count = 0; diff --git a/templates/parts/user/author-hero.php b/templates/parts/user/author-hero.php index 0cafcc76..a532b9e4 100644 --- a/templates/parts/user/author-hero.php +++ b/templates/parts/user/author-hero.php @@ -100,25 +100,21 @@ $pm_url = ($pm_enabled && $messages_url !== '') - -
- -
- - - +
+
- + description) : ?>

description); ?>