fix(header): restore reference VIP chip geometry and cluster split
The VIP chip never received the reference .but geometry. Commit f03d72c8
narrowed the legacy selector from a descendant to a child combinator as a
side effect of an unrelated user-popover fix, and the contract test then
pinned the narrowed form. Because the VIP anchor lives inside the
hover-show wrapper rather than being a direct child of .navbar-but, it
fell back to the bare .but defaults: 15px type instead of 0.8em, no
0.4em margin, and no padding override.
Restore the descendant selector so both chips share one geometry:
- .navbar-top .navbar-but .but is byte-identical to the reference again,
giving the VIP chip font-size 0.8em, padding 0.3em 1em !important and
margin 0.4em
- the publish and VIP anchors are plain inline-block .but elements again
(the merged flex container no longer blockifies them)
- ml10 is back on the VIP anchor; .navbar-top .navbar-but .but overrides
it exactly as it does in the reference, so it stays markup parity
without changing the computed margin
The right cluster was also merged into one .aksrt-navbar-actions flex
container with a 10px gap and zero padding, while the reference emits
three floated .navbar-form.navbar-right groups whose 15px padding is what
produces the inter-cluster spacing. Split them again: publish/VIP in
.navbar-but, theme toggle plus language switcher in a flex ac group, and
the account row in its own group. Measured against the reference, the
publish-to-VIP gap was 19.6px instead of 9.6px, and VIP-to-theme-toggle
was 14.8px instead of 34.8px.
The container rules in header-userbox.css are re-anchored onto the
reference structure: .aksrt-navbar-account owns the only remaining flex
context, .toggle-radius and .aksrt-navbar-language are scoped through
.navbar-form, and the hover-show rule targets .navbar-but. Coverage of
those selectors is unchanged, so the theme toggle, language switcher and
message icon keep their current geometry.
The .aksrt-navbar-actions wrapper and its gap are gone; a negative
assertion now guards against reintroducing them.
Verified: node --test across tests/ (603 passing), php -l on the changed
PHP files, and a stubbed render of aksrt_menu_button() for guest,
logged-in and layout 2.
This commit is contained in:
+13
-28
@@ -2714,27 +2714,22 @@ main.container,
|
||||
* shell anchoring plus the account action-row geometry.
|
||||
*/
|
||||
|
||||
/* The desktop action cluster owns one horizontal alignment context. */
|
||||
.navbar-top .aksrt-navbar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-height: 50px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-actions > *,
|
||||
.navbar-top .aksrt-navbar-account,
|
||||
.navbar-top .aksrt-navbar-account > li {
|
||||
/* The reference keeps the right cluster as three floated .navbar-form groups, so
|
||||
* only the account row carries its own alignment context; the button groups
|
||||
* inherit their geometry from .navbar-top .navbar-but .but and .navbar-form. */
|
||||
.navbar-top .aksrt-navbar-account {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
gap: 4px;
|
||||
min-height: 50px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-account > li {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
padding: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
@@ -2747,16 +2742,6 @@ main.container,
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-account {
|
||||
gap: 4px;
|
||||
min-height: 50px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-account.navbar-text {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-nav-icon,
|
||||
.navbar-top .aksrt-nav-avatar {
|
||||
display: inline-flex !important;
|
||||
@@ -2789,13 +2774,13 @@ main.container,
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-actions .toggle-radius {
|
||||
.navbar-top .navbar-form .toggle-radius {
|
||||
flex: 0 0 29px;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-language {
|
||||
.navbar-top .navbar-form .aksrt-navbar-language {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -2803,7 +2788,7 @@ main.container,
|
||||
* absolutely positioned .sub-vip-card takes its normal-flow static position.
|
||||
* The shared action cluster otherwise forces inline-flex on every child, which
|
||||
* would move that static position to the flex container's cross-start. */
|
||||
.navbar-top .aksrt-navbar-actions > .hover-show {
|
||||
.navbar-top .navbar-but > .hover-show {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -7,27 +7,22 @@
|
||||
* shell anchoring plus the account action-row geometry.
|
||||
*/
|
||||
|
||||
/* The desktop action cluster owns one horizontal alignment context. */
|
||||
.navbar-top .aksrt-navbar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-height: 50px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-actions > *,
|
||||
.navbar-top .aksrt-navbar-account,
|
||||
.navbar-top .aksrt-navbar-account > li {
|
||||
/* The reference keeps the right cluster as three floated .navbar-form groups, so
|
||||
* only the account row carries its own alignment context; the button groups
|
||||
* inherit their geometry from .navbar-top .navbar-but .but and .navbar-form. */
|
||||
.navbar-top .aksrt-navbar-account {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
gap: 4px;
|
||||
min-height: 50px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-account > li {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
padding: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
@@ -40,16 +35,6 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-account {
|
||||
gap: 4px;
|
||||
min-height: 50px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-account.navbar-text {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-nav-icon,
|
||||
.navbar-top .aksrt-nav-avatar {
|
||||
display: inline-flex !important;
|
||||
@@ -82,13 +67,13 @@
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-actions .toggle-radius {
|
||||
.navbar-top .navbar-form .toggle-radius {
|
||||
flex: 0 0 29px;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.navbar-top .aksrt-navbar-language {
|
||||
.navbar-top .navbar-form .aksrt-navbar-language {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -96,7 +81,7 @@
|
||||
* absolutely positioned .sub-vip-card takes its normal-flow static position.
|
||||
* The shared action cluster otherwise forces inline-flex on every child, which
|
||||
* would move that static position to the flex container's cross-start. */
|
||||
.navbar-top .aksrt-navbar-actions > .hover-show {
|
||||
.navbar-top .navbar-but > .hover-show {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -6838,7 +6838,7 @@ badge.top,
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.navbar-top .navbar-but > .but {
|
||||
.navbar-top .navbar-but .but {
|
||||
font-size: 0.8em;
|
||||
padding: 0.3em 1em !important;
|
||||
margin: 0.4em;
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -119,7 +119,7 @@ if (!function_exists('aksrt_render_header_menu_buttons')) :
|
||||
}
|
||||
// legacy: span.hover-show wraps button + .sub-menu.sub-vip-card
|
||||
$html .= '<span class="hover-show inline-block">';
|
||||
$html .= '<a class="' . esc_attr($cls) . ' but jb-red radius payvip-icon" href="javascript:;">'
|
||||
$html .= '<a class="' . esc_attr($cls) . ' but jb-red radius payvip-icon ml10" href="javascript:;">'
|
||||
. '<svg class="em12 mr3" aria-hidden="true"><use xlink:href="#icon-vip_1"></use></svg>'
|
||||
. esc_html__('开通会员', 'aksrt') . '</a>' . $hover . '</span>';
|
||||
}
|
||||
|
||||
@@ -303,6 +303,12 @@ if (!function_exists('aksrt_menu_button')) :
|
||||
/**
|
||||
* Right cluster: fold, publish/VIP, theme, user, search (legacy).
|
||||
*
|
||||
* The reference splits the cluster into three floated .navbar-form
|
||||
* groups (publish/VIP, theme + language, account row). Each group
|
||||
* keeps its own .navbar-form padding, which is what produces the
|
||||
* reference inter-cluster spacing, so the groups are emitted
|
||||
* separately instead of being merged into one flex container.
|
||||
*
|
||||
* @param array<string,mixed> $ctx
|
||||
*/
|
||||
function aksrt_menu_button(array $ctx): void {
|
||||
@@ -371,14 +377,24 @@ if (!function_exists('aksrt_menu_button')) :
|
||||
$account = '<ul class="list-inline splitters relative aksrt-navbar-account'
|
||||
. ($user_id <= 0 && '2' === $layout ? ' navbar-text' : '') . '">'
|
||||
. $notification_but . $sign_but . $search_but . '</ul>';
|
||||
$button = '<div class="aksrt-navbar-actions navbar-form navbar-right navbar-but">'
|
||||
. $actions . $utility_buttons . $account . '</div>';
|
||||
|
||||
// Reference cluster split: publish/VIP, theme + language, account row.
|
||||
$button = '';
|
||||
if ($actions !== '') {
|
||||
$button = '<div class="navbar-form navbar-right navbar-but">' . $actions . '</div>';
|
||||
}
|
||||
if ($utility_buttons !== '') {
|
||||
$button .= '<div class="navbar-form navbar-right flex ac">' . $utility_buttons . '</div>';
|
||||
}
|
||||
$right_but = '<div class="navbar-form navbar-right'
|
||||
. ($user_id <= 0 && '2' === $layout ? ' navbar-text' : '') . '">'
|
||||
. $account . '</div>';
|
||||
|
||||
$fold = '<div class="navbar-form navbar-right hide show-nav-but" style="margin-right:-10px;">'
|
||||
. '<a data-toggle-class data-target=".nav.navbar-nav" href="javascript:;" class="aksrt-nav-icon" aria-label="'
|
||||
. esc_attr__('展开菜单', 'aksrt') . '"><svg class="icon" viewBox="0 0 1024 1024" aria-hidden="true"><use xlink:href="#icon-menu_2"></use></svg></a></div>';
|
||||
|
||||
$html = $fold . $button;
|
||||
$html = $fold . $button . $right_but;
|
||||
|
||||
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
@@ -225,8 +225,11 @@ test('the account popover rows match the reference user box structure', () => {
|
||||
assert.match(header, /but block c-yellow is-done/);
|
||||
assert.match(buttonsCss, /\.but\.block\s*\{\s*display:\s*block;\s*\}/);
|
||||
assert.match(buttonsCss, /\.btn-block\s*\{\s*display:\s*block;\s*width:\s*100%;\s*\}/);
|
||||
assert.match(legacyMainCss, /\.navbar-top \.navbar-but > \.but\s*\{[^}]*font-size:\s*0\.8em;[^}]*padding:\s*0\.3em 1em !important;[^}]*margin:\s*0\.4em;/s);
|
||||
assert.doesNotMatch(legacyMainCss, /\.navbar-top \.navbar-but \.but\s*\{/);
|
||||
// The reference selector is a descendant, so the VIP chip inside its hover-show
|
||||
// wrapper receives the same .but geometry (font-size, padding, margin) as the
|
||||
// publish chip instead of falling back to the bare .but defaults.
|
||||
assert.match(legacyMainCss, /\.navbar-top \.navbar-but \.but\s*\{[^}]*font-size:\s*0\.8em;[^}]*padding:\s*0\.3em 1em !important;[^}]*margin:\s*0\.4em;/s);
|
||||
assert.doesNotMatch(legacyMainCss, /\.navbar-top \.navbar-but > \.but\s*\{/);
|
||||
assert.doesNotMatch(header, /but block c-yellow[^"']*btn-block/);
|
||||
assert.match(header, /<div class="mt6 em09" style="padding:2px;">' \. \$checkin \. '<\/div>/);
|
||||
assert.match(header, /data-signin-done-label[\s\S]{0,120}?今日已签到/);
|
||||
|
||||
@@ -142,7 +142,7 @@ test('VIP navigation purchase switches are saved and consumed end to end', () =>
|
||||
test('header VIP hover cards match the legacy markup and style contract', () => {
|
||||
assert.match(headerMenuButtons, /<span class="hover-show inline-block">/)
|
||||
assert.match(headerMenuButtons, /<div class="sub-menu hover-show-con sub-vip-card">/)
|
||||
assert.match(headerMenuButtons, /'<a class="' \. esc_attr\(\$cls\) \. ' but jb-red radius payvip-icon" href="javascript:;">'/)
|
||||
assert.match(headerMenuButtons, /'<a class="' \. esc_attr\(\$cls\) \. ' but jb-red radius payvip-icon ml10" href="javascript:;">'/)
|
||||
assert.match(headerMenuButtons, /<svg class="em12 mr3" aria-hidden="true"><use xlink:href="#icon-vip_1"><\/use><\/svg>'/)
|
||||
assert.match(headerMenuButtons, /'<a rel="nofollow" class="newadd-btns ' \. esc_attr\(\$class\) \. ' btn-newadd"/)
|
||||
assert.equal((headerMenuButtons.match(/Settings::close_sign\(\)/g) || []).length, 2)
|
||||
@@ -167,7 +167,7 @@ test('header VIP hover cards match the legacy markup and style contract', () =>
|
||||
assert.match(legacyMainCss, /\.sub-vip-card \.vip-img\s*\{[^}]*display:\s*none;/s)
|
||||
// The hover wrapper must stay a plain block container so the legacy static
|
||||
// position of .sub-vip-card matches the reference theme.
|
||||
assert.match(headerCss, /\.navbar-top \.aksrt-navbar-actions > \.hover-show\s*\{[^}]*display:\s*inline-block;/s)
|
||||
assert.match(headerCss, /\.navbar-top \.navbar-but > \.hover-show\s*\{[^}]*display:\s*inline-block;/s)
|
||||
assert.doesNotMatch(headerCss, /\.navbar-cta|\.navbar-vip-hover/)
|
||||
assert.match(legacyMainCss, /\.navbar-top \.navbar-right \.sub-menu\s*\{[^}]*right:\s*0;/s)
|
||||
})
|
||||
@@ -346,16 +346,21 @@ test('user profile and author widgets render the reference user-card contract',
|
||||
})
|
||||
|
||||
test('desktop header actions share one row without generic button masks', () => {
|
||||
assert.match(headerNavbar, /aksrt-navbar-actions navbar-form navbar-right/)
|
||||
assert.match(headerNavbar, /navbar-form navbar-right navbar-but/)
|
||||
assert.match(headerNavbar, /navbar-form navbar-right flex ac/)
|
||||
assert.match(headerNavbar, /\$fold \. \$button \. \$right_but/)
|
||||
assert.match(headerNavbar, /class="aksrt-nav-icon nav-search-btn main-search-btn"/)
|
||||
assert.doesNotMatch(headerNavbar, /class="btn nav-search-btn main-search-btn"/)
|
||||
assert.match(headerCss, /\.navbar-top \.aksrt-navbar-actions\s*\{[^}]*display:\s*flex;[^}]*align-items:\s*center;/s)
|
||||
assert.match(headerCss, /\.navbar-top \.aksrt-navbar-account\s*\{[^}]*display:\s*inline-flex;[^}]*align-items:\s*center;/s)
|
||||
assert.match(headerCss, /\.navbar-top \.aksrt-nav-icon,[\s\S]*?background:\s*transparent !important;/)
|
||||
// The publish and VIP chips ride the legacy .but geometry verbatim; nothing in
|
||||
// the header module may restate their padding, margin, radius or icon size.
|
||||
assert.match(legacyMainCss, /\.navbar-top \.navbar-but > \.but\s*\{[^}]*font-size:\s*0\.8em;[^}]*padding:\s*0\.3em 1em !important;[^}]*margin:\s*0\.4em;/s)
|
||||
// Descendant, not child: the VIP chip lives inside the hover-show wrapper.
|
||||
assert.match(legacyMainCss, /\.navbar-top \.navbar-but \.but\s*\{[^}]*font-size:\s*0\.8em;[^}]*padding:\s*0\.3em 1em !important;[^}]*margin:\s*0\.4em;/s)
|
||||
assert.doesNotMatch(headerCss, /\.navbar-cta|\.navbar-vip-hover/)
|
||||
assert.match(headerCss, /\.navbar-top \.aksrt-navbar-actions\s*\{[^}]*gap:\s*10px;/s)
|
||||
// No merged flex container: the three groups keep their own .navbar-form
|
||||
// padding, which is what produces the reference inter-cluster spacing.
|
||||
assert.doesNotMatch(headerCss, /\.aksrt-navbar-actions/)
|
||||
assert.match(headerCss, /\.navbar-top \.aksrt-navbar-account > li\s*\{[^}]*position:\s*relative;/s)
|
||||
assert.match(headerCss, /\.navbar-top \.aksrt-navbar-account > li > \.sub-menu\s*\{[^}]*top:\s*calc\(100% \+ 5px\);[^}]*right:\s*0;/s)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user