fix(frontend): align top navigation with reference theme

This commit is contained in:
kate522 committed 2026-10-29 18:10:00 +08:00
1 parent 1c501ff713
commit 9b27508a5b
12 files changed
+234 -607

No files matched your search

@@ -169,7 +169,8 @@ 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 \.navbar-but > \.hover-show\s*\{[^}]*display:\s*inline-block;/s)
assert.match(headerMenuButtons, /class="hover-show inline-block"/)
assert.doesNotMatch(headerCss, /\.navbar-top \.navbar-but > \.hover-show/)
assert.doesNotMatch(headerCss, /\.navbar-cta|\.navbar-vip-hover/)
assert.match(legacyMainCss, /\.navbar-top \.navbar-right \.sub-menu\s*\{[^}]*right:\s*0;/s)
})
@@ -350,20 +351,19 @@ 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, /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, /\$fold \. \('3' === \$layout \? \$right_but \. \$button : \$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-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;/)
// Bootstrap's base .navbar-form rule keeps margin-top: 8px at >=768px (the
// override only zeroes the horizontal margins), so every right-cluster group
// starts 8px below the top of .navbar-collapse. A 34px cross-size therefore
// puts each group's midline on the navbar's 25px line, where the 50px menu row
// and the logo already sit. A 50px min-height double-counts that 8px: the
// group's content drops 8px below the line and the navbar grows from 50px to
// 58px, which also breaks the body.nav-fixed offset.
assert.doesNotMatch(headerCss, /\.navbar-top \.aksrt-navbar-account\s*\{[^}]*min-height/s)
assert.match(headerCss, /\.navbar-top \.navbar-form\.flex\.ac\s*\{[^}]*min-height:\s*34px;/s)
assert.match(headerNavbar, /<ul class="list-inline splitters relative">/)
assert.doesNotMatch(headerNavbar, /aksrt-navbar-account|aksrt-nav-avatar/)
assert.match(headerNavbar, /class="navbar-avatar"/)
assert.match(legacyMainCss, /\.navbar-avatar\s*\{[^}]*margin-top:\s*3px;[^}]*width:\s*29px;[^}]*height:\s*29px;/s)
assert.match(headerNavbar, /aksrt_get_translate_language_btn\('ml10 pull-right'\)/)
assert.match(headerNavbar, /<a data-toggle-class data-target="\.nav\.navbar-nav" href="javascript:;" class="but"/)
assert.match(headerNavbar, /<svg class="icon" viewBox="50 0 924 924"/)
assert.match(headerNavbar, /<svg class="icon" aria-hidden="true"><use xlink:href="#icon-search"/)
assert.doesNotMatch(headerCss, /\.aksrt-navbar-account|\.aksrt-nav-avatar|navbar-form\.flex\.ac\s*\{[^}]*min-height/)
assert.match(headerCss, /\.navbar-top \.aksrt-nav-icon\s*\{[^}]*display:\s*inline-block;[^}]*padding:\s*6px 12px;[^}]*font-size:\s*14px;[^}]*line-height:\s*1\.42857143;[^}]*border:\s*1px solid transparent;[^}]*border-radius:\s*4px;/s)
// 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.
// Descendant, not child: the VIP chip lives inside the hover-show wrapper.
@@ -371,15 +371,14 @@ test('desktop header actions share one row without generic button masks', () =>
assert.doesNotMatch(headerCss, /\.navbar-cta|\.navbar-vip-hover/)
// 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)
assert.doesNotMatch(headerCss, /\.aksrt-navbar-actions|\.aksrt-navbar-account|\.aksrt-nav-avatar/)
})
test('mobile search stays inside the scroll-hiding top header', () => {
test('mobile search follows the reference center and left header placements', () => {
assert.match(headerNavbar, /class="navbar-toggle main-search-btn"/)
assert.doesNotMatch(headerNavbar, /mobile_layout/)
assert.doesNotMatch(headerMobile, /main-search-btn|\$m_layout|aksrt_navbar_header/)
assert.match(headerNavbar, /mobile_layout/)
assert.match(headerNavbar, /'center' === \(\$ctx\['mobile_layout'\] \?\? 'center'\)/)
assert.match(headerMobile, /main-search-btn|toggle-radius/)
assert.match(headerMobile, /aksrt_nav_mobile_content\(\$ctx\)/)
assert.doesNotMatch(headerRender, /'fixed'\s*=>/)
assert.doesNotMatch(legacyMainCss, /\.mobile-navbar \.navbar-(?:header|brand)/)
@@ -394,14 +393,12 @@ test('mobile search stays inside the scroll-hiding top header', () => {
assert.match(legacyMainCss, /\.scroll-down\.nav-fixed \.header\.scroll-down-hide\s*\{[^}]*transform:\s*translate3d\(0, -105%, 0\);/s)
})
test('search dropdown clears the fixed header and closes from the panel lower-right', () => {
assert.match(headerCss, /\.navbar-search\s*\{[^}]*z-index:\s*1001;[^}]*transform:\s*translate3d\(0, -24px, 0\);[^}]*transition:\s*transform \.24s ease, opacity \.18s ease, visibility 0s linear \.24s;/s)
assert.match(headerCss, /\.navbar-search\.show\s*\{[^}]*opacity:\s*1;[^}]*transform:\s*translate3d\(0, 0, 0\);/s)
assert.doesNotMatch(headerCss, /\.navbar-search\s*\{[^}]*height:\s*100%/s)
assert.doesNotMatch(headerCss, /\.navbar-search > \.container\s*\{[^}]*overflow-y:\s*auto/s)
test('search panel retains the reference main.css surface and close spacing', () => {
assert.match(legacyMainCss, /\.navbar-search\s*\{[^}]*visibility:\s*hidden;[^}]*transform:\s*translateY\(-101%\);[^}]*padding:\s*10px 30px;[^}]*padding-top:\s*80px;[^}]*transition:\s*all 0\.5s;/s)
assert.match(legacyMainCss, /\.navbar-search\.show\s*\{[^}]*visibility:\s*unset;[^}]*transform:\s*translateY\(0\);/s)
assert.doesNotMatch(headerCss, /\.navbar-search(?:\.show)?\s*\{[^}]*transform:/s)
assert.match(headerCss, /\.navbar-search \.line-form-input:focus,[\s\S]*?\.navbar-search \.line-form-input:focus-visible\s*\{[^}]*outline:\s*0;[^}]*box-shadow:\s*none;/s)
assert.match(headerCss, /\.navbar-search \.search-close-box\s*\{[^}]*display:\s*flex;[^}]*justify-content:\s*flex-end;[^}]*margin:\s*16px auto 0;/s)
assert.doesNotMatch(headerCss, /\.navbar-search \.search-close-box\s*\{[^}]*position:\s*fixed/s)
assert.match(headerSearch, /class="mb20 search-close-box"/)
assert.ok(headerSearch.indexOf('echo $remote') < headerSearch.indexOf('search-close-box'))
})