Merge pull request 'Worktree nav zibll 1to1' (#256) from worktree-nav-zibll-1to1 into main

Reviewed-on: CYL/wordpress-theme-aksrt#256
This commit is contained in:
2026-07-22 12:27:29 +08:00
38 changed files with 1123 additions and 2014 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

@@ -3,6 +3,14 @@
* Each key corresponds to a sub-page under the "页面&显示" section.
*/
/** Theme asset base for layout previews (admin SPA). */
function themeAsset(path) {
const base = (typeof window !== 'undefined' && window.aksrtAdminData && window.aksrtAdminData.themeUri)
? String(window.aksrtAdminData.themeUri).replace(/\/$/, '')
: ''
return base ? `${base}/${path.replace(/^\//, '')}` : path
}
/** Homepage sort options — keep in sync with AKSRT_Settings_Home_Cms::homepage_allowed_sorts() */
const sortOptions = [
{ label: '最近更新', value: 'modified' },
@@ -37,6 +45,7 @@ export const pageDisplaySchemas = {
header_nav_pay_vip: true,
header_nav_user_pay_vip: true,
header_newposts_types: ['post'],
header_user_newposts_btn: 'post',
header_user_newposts_text: '发布内容',
mobile_header_layout: 'center',
mobile_navbar_align: 'left',
@@ -78,23 +87,23 @@ export const pageDisplaySchemas = {
{
key: 'header_layout',
label: '电脑端布局',
type: 'radio',
default: '2',
type: 'image_select',
default: '1',
options: [
{ label: '布局 1(经典)', value: '1' },
{ label: '布局 2(内联搜索)', value: '2' },
{ label: '布局 3(紧凑)', value: '3' },
{ label: '布局 1(经典)', value: '1', image: themeAsset('assets/images/header-layout/header_layout_1.png') },
{ label: '布局 2(内联搜索)', value: '2', image: themeAsset('assets/images/header-layout/header_layout_2.png') },
{ label: '布局 3(紧凑)', value: '3', image: themeAsset('assets/images/header-layout/header_layout_3.png') },
],
help: '不同布局切换导航 DOM 结构',
help: '不同布局切换导航 DOM 结构(与 zibll image_select 一致)',
},
{
key: 'mobile_header_layout',
label: '移动端布局',
type: 'radio',
type: 'image_select',
default: 'center',
options: [
{ label: '居中(含搜索按钮)', value: 'center' },
{ label: '靠左', value: 'left' },
{ label: '居中(含搜索按钮)', value: 'center', image: themeAsset('assets/images/header-layout/mobile_header_layout_center.png') },
{ label: '靠左', value: 'left', image: themeAsset('assets/images/header-layout/mobile_header_layout_left.png') },
],
},
{
@@ -124,6 +133,11 @@ export const pageDisplaySchemas = {
{ label: '帖子', value: 'topic' },
{ label: '商品', value: 'product' },
], dependsOn: { key: 'header_newposts_enabled', value: true }, help: '未开启的模块不会显示' },
{ key: 'header_user_newposts_btn', label: '用户卡发布类型', type: 'select', default: 'post', options: [
{ label: '文章', value: 'post' },
{ label: '帖子', value: 'topic' },
{ label: '商品', value: 'product' },
] },
{ key: 'header_user_newposts_text', label: '用户卡发布文案', type: 'input', default: '发布内容' },
{ key: 'header_nav_pay_vip', label: '导航栏开通会员按钮', type: 'switch', default: true, help: '顶部导航显示开通会员' },
{ key: 'header_nav_user_pay_vip', label: '用户框开通会员按钮', type: 'switch', default: true },
+2 -5
View File
@@ -2,10 +2,7 @@
@import url("nav/zib-navbar-core.css");
@import url("nav/zib-mobile-navbar.css");
@import url("nav/zib-senior-submenu.css");
@import url("nav/dark-mode-submenu.css");
@import url("nav/dark-mode-mega-menu.css");
@import url("nav/zib-utilities.css");
@import url("nav/header-menu-buttons.css");
@import url("nav/header-userbox.css");
@import url("nav/menu-item-icon.css");
@import url("nav/menu-item-badge.css");
@import url("nav/hover-effects.css");
@import url("nav/dark-mode-submenu.css");
-577
View File
@@ -1,577 +0,0 @@
/* Zibll body.nav-fixed: hard 88px reserve (main.css), not bare --nav-height.
* Nav bar itself is ~60px; extra space matches zibll chrome/shadow gap.
* --nav-fixed-reserve is shared with the hero pull-up so they cancel exactly
* (zibll: body padding-top 88px + .slide-header { margin-top: -90px }). */
body.nav-fixed {
--nav-fixed-reserve: 88px;
padding-top: var(--nav-fixed-reserve);
}
@media (max-width: 768px) {
body.nav-fixed {
--nav-fixed-reserve: 72px;
padding-top: var(--nav-fixed-reserve);
}
}
@media (max-width: 640px) {
body.nav-fixed {
--nav-fixed-reserve: 60px;
padding-top: var(--nav-fixed-reserve);
}
}
/* Fixed nav without hero overlay: take header out of flow.
body.nav-fixed already reserves space via padding-top. */
body.nav-fixed .header:not(.show-slide) {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%;
z-index: 1000;
}
/* Nav lives inside the fixed header — don't keep sticky (double offset). */
body.nav-fixed .header:not(.show-slide) .site-nav,
body.nav-fixed .header:not(.show-slide) .navbar.navbar-top {
position: relative;
top: auto;
}
/*
* Non-home pages have no hero under the fixed header. Keep the first content
* (breadcrumb / article) clearly below the bar even if a fluid widget zone is
* empty or a child uses negative margin.
*/
body.nav-fixed:not(:has(.header.show-slide)) .fluid-widget-wrap:first-of-type:empty + main.container,
body.nav-fixed:not(:has(.header.show-slide)) main.container:first-of-type {
scroll-margin-top: calc(var(--nav-fixed-reserve, 88px) + 8px);
}
/* Hero sits under transparent fixed/absolute header.
* MUST cancel the full --nav-fixed-reserve (88/72/60), not just --nav-height (60).
* Using only -60px against 88px padding left a ~28px blank strip above the hero. */
body.nav-fixed .header-slider-container,
body.nav-fixed .header-components-container,
body.nav-fixed .header-components.slide-header {
margin-top: calc(var(--nav-fixed-reserve, 88px) * -1) !important;
position: relative;
z-index: 1;
}
/* ============================================================
* AKSRT Navigation — Zibll-aligned
*
* - 高度 60px (--nav-height)
* - 毛玻璃 blur-bg(saturate(5) blur(20px))
* - 透明叠 slider → 滚动后恢复实底
* - 滚动隐藏(scroll-down-hide 等价)
* ============================================================ */
.site-nav {
position: sticky;
top: 0;
z-index: 1000;
min-height: var(--nav-height, 60px);
background-color: var(--blur-bg);
border-bottom: 1px solid rgba(255, 255, 255, 0.45);
backdrop-filter: saturate(5) blur(20px);
-webkit-backdrop-filter: saturate(5) blur(20px);
transition: background-color 0.25s ease,
border-color 0.25s ease,
color 0.25s ease,
box-shadow 0.25s ease,
transform 0.3s ease; /* 滚动隐藏过渡 */
}
/* 滚动隐藏头部 — 对齐 zibll .scroll-down.nav-fixed .header.scroll-down-hide */
.site-nav.is-hidden {
transform: translateY(-105%);
}
.site-nav--static {
position: relative;
}
.site-nav--transparent {
background: transparent; /* 对齐 zibll .header.show-slide: 透明覆盖在 slider 上 */
border-bottom-color: transparent;
}
.site-nav--transparent:not(.is-scrolled) {
--header-color: #fff; /* 对齐 zibll --header-color:#fff */
color: #fff;
}
.site-nav--transparent:not(.is-scrolled) a {
color: inherit;
}
.site-nav--transparent.is-scrolled {
background: var(--blur-bg); /* 滚动后恢复毛玻璃背景 */
border-bottom-color: var(--color-line-soft);
}
.site-nav--blur {
background: var(--blur-bg);
backdrop-filter: saturate(5) blur(20px);
-webkit-backdrop-filter: saturate(5) blur(20px);
border-bottom-color: transparent;
}
html.dark .site-nav--transparent:not(.is-scrolled),
html.dark .site-nav--blur:not(.is-scrolled),
body.dark-theme .site-nav--transparent:not(.is-scrolled),
body.dark-theme .site-nav--blur:not(.is-scrolled) {
background: transparent;
border-bottom-color: transparent;
}
html.dark .site-nav--transparent.is-scrolled,
html.dark .site-nav--blur.is-scrolled,
body.dark-theme .site-nav--transparent.is-scrolled,
body.dark-theme .site-nav--blur.is-scrolled {
background: var(--blur-bg);
border-bottom-color: var(--color-line-soft);
}
/* 滚动后追加阴影 — 对齐 zibll .body-scroll .header */
.site-nav.is-scrolled {
box-shadow: 0 4px 10px var(--main-shadow, var(--shadow-sm));
}
/* WordPress Admin Bar 已全局禁用,无需偏移规则 */
/* ============================================================
* Inner / Row layout
* ============================================================ */
.site-nav__inner {
max-width: var(--nav-max-width, var(--container));
margin: 0 auto;
padding: 0 16px;
display: flex;
flex-direction: column;
gap: 0;
}
.site-nav__row {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 12px;
width: 100%;
min-height: var(--nav-height, 60px);
}
/* ============================================================
* Brand
* ============================================================ */
.site-brand {
display: inline-flex;
align-items: center;
gap: 10px;
min-width: 0;
max-width: min(48vw, 360px);
padding: 7px 10px;
color: var(--color-ink);
font-size: 17px;
font-weight: 700;
letter-spacing: -0.01em;
flex-shrink: 0;
text-decoration: none;
}
.site-brand:hover {
color: var(--color-ink);
text-decoration: none;
}
.site-brand--has-logo {
gap: 0;
}
.site-brand__logo {
width: 36px;
height: 36px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 800;
font-size: 13px;
color: var(--color-on-primary, #fff);
background: linear-gradient(135deg, var(--color-primary), var(--color-primary-active, var(--color-primary-dark)));
letter-spacing: 0.02em;
overflow: hidden;
}
.site-brand__media {
display: block;
flex: 0 1 auto;
max-width: 100%;
padding: 0 30px;
line-height: 0;
box-sizing: border-box;
background: transparent !important;
border: 0;
border-radius: 0;
box-shadow: none;
filter: none !important;
opacity: 1;
}
.site-brand__img {
display: block;
height: 36px;
width: auto;
max-width: 100%;
object-fit: contain;
object-position: left center;
background: transparent !important;
border-radius: 0;
box-shadow: none;
filter: none !important;
mix-blend-mode: normal !important;
opacity: 1;
transform: none !important;
}
.site-brand__name {
font-weight: 700;
letter-spacing: -0.01em;
white-space: nowrap;
}
/* Light/dark logo: single adaptive img (white-src/dark-src via theme.js) */
.navbar-logo > img,
.navbar-logo .site-brand__logo-img,
.site-brand .site-brand__logo-img,
.site-brand__logo-img,
.site-brand .navbar-logo img {
height: 36px !important;
width: auto !important;
max-width: min(180px, 40vw) !important;
max-height: 36px !important;
padding: 0 !important;
object-fit: contain !important;
display: inline-block;
vertical-align: middle;
}
/* Legacy dual-img classes (if any remain elsewhere) */
.site-brand__logo-img--dark {
display: none;
}
html.dark .site-brand__logo-img--light,
[data-theme="dark"] .site-brand__logo-img--light,
body.dark-theme .site-brand__logo-img--light {
display: none;
}
html.dark .site-brand__logo-img--dark,
[data-theme="dark"] .site-brand__logo-img--dark,
body.dark-theme .site-brand__logo-img--dark {
display: inline-block;
}
/* ============================================================
* Desktop menu
* ============================================================ */
ul.nav-desktop {
display: none;
list-style: none;
margin: 0;
padding: 0;
align-items: center;
flex: 1 1 auto;
min-width: 0;
}
.nav-desktop--fallback {
display: none;
align-items: center;
flex: 1 1 auto;
min-width: 0;
}
ul.nav-desktop a,
.nav-desktop--fallback a {
color: var(--color-ink-3);
font-size: 14px;
font-weight: 500;
padding: 0 12px; /* 对齐 zibll:仅水平 padding,垂直居中靠 flex 行高 */
border-radius: 4px;
transition: color var(--dur-fast, 0.15s) var(--ease),
background var(--dur-fast, 0.15s) var(--ease);
}
/* Hover — 对齐 zibll: 仅变色,无背景 */
ul.nav-desktop a:hover,
.nav-desktop--fallback a:hover {
color: var(--color-primary);
background: transparent;
}
/* Active page — 对齐 zibll: 仅变色(指示器走下方胶囊条) */
ul.nav-desktop .current-menu-item > a,
ul.nav-desktop .current_page_item > a {
color: var(--color-primary);
background: transparent;
}
/* ============================================================
* Desktop submenu (dropdown)
* ============================================================ */
ul.nav-desktop .menu-item {
position: relative;
}
/* 顶部 hover/current 胶囊指示器 — 对齐 zibll .navbar-nav>li:before
(5px 高、底部 15px 圆角,从 header 顶缘垂下)。
stretch 链(row→ul→li)让 li 充满 60px 行高,::before top:0 即锚定 header 顶部;
::before 为 absolute 不进入 flex 流,不挤压链接。 */
ul.nav-desktop {
align-self: stretch;
}
ul.nav-desktop > .menu-item {
align-self: stretch;
display: flex;
align-items: center;
}
ul.nav-desktop > .menu-item::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 5px;
background: var(--focus-color, var(--color-primary));
border-radius: 0 0 15px 15px;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
}
ul.nav-desktop > .menu-item:hover::before,
ul.nav-desktop > .current-menu-item::before,
ul.nav-desktop > .current_page_item::before {
opacity: 1;
}
ul.nav-desktop .sub-menu {
position: absolute;
top: 100%;
left: 0;
z-index: 998; /* 保留较高 z-index(zibll 用 99,AKSRT 栈更深,避免被覆盖) */
min-width: 140px;
list-style: none;
margin: 8px 0 0;
padding: 8px 6px;
background: var(--main-bg-color, #fff);
border: none;
border-radius: var(--main-radius, var(--radius, 8px));
box-shadow: var(--shadow-lg);
opacity: 0;
visibility: hidden;
transform: translateY(6px);
transition: opacity 0.4s ease, transform 0.4s ease, visibility 0.4s ease;
}
ul.nav-desktop .menu-item:hover > .sub-menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
ul.nav-desktop .sub-menu .menu-item > a {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 15px;
font-size: 14px;
border-radius: 4px;
white-space: nowrap;
}
ul.nav-desktop .sub-menu .menu-item > a:hover {
background: var(--color-primary-soft, rgba(240, 68, 148, 0.08));
color: var(--color-primary);
}
/* Nested submenus fly out to the right — 对齐 zibll top:-10px,去 margin-left */
ul.nav-desktop .sub-menu .sub-menu {
top: -10px;
left: 100%;
margin: 0;
}
/* ============================================================
* Zibll .header.show-slide — transparent gradient over hero
* ============================================================ */
.header.show-slide {
--header-bg: linear-gradient(0, rgba(0, 0, 0, 0) 5%, rgba(0, 0, 0, 0.1) 80%);
--header-color: #fff;
-webkit-backdrop-filter: unset;
backdrop-filter: unset;
}
body.nav-fixed .header.show-slide {
position: absolute !important;
top: 0;
left: 0;
right: 0;
width: 100%;
z-index: 30;
background: transparent !important;
box-shadow: none !important;
border: 0 !important;
}
/* Nav inside absolute header must not use sticky (avoids double offset) */
body.nav-fixed .header.show-slide .site-nav,
body.nav-fixed .header.show-slide .navbar.navbar-top {
position: relative !important;
top: auto !important;
background: var(--header-bg, transparent) !important;
border-bottom-color: transparent !important;
box-shadow: none !important;
color: var(--header-color, #fff);
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
.header.show-slide .navbar.navbar-top,
.header.show-slide .site-nav {
background: var(--header-bg, transparent);
border-bottom-color: transparent;
box-shadow: none;
color: var(--header-color, #fff);
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
.header.show-slide .site-nav:not(.is-scrolled) a,
.header.show-slide .site-nav:not(.is-scrolled) .icon-btn,
.header.show-slide .site-nav:not(.is-scrolled) .site-brand__name {
color: #fff;
}
.header.show-slide .site-nav.is-scrolled,
.site-nav.is-scrolled {
background: var(--blur-bg);
color: var(--header-color, var(--color-ink-2));
border-bottom-color: rgba(255, 255, 255, 0.45);
backdrop-filter: saturate(5) blur(20px);
-webkit-backdrop-filter: saturate(5) blur(20px);
box-shadow: 0 4px 10px var(--main-shadow, rgba(116, 116, 116, 0.08));
}
.navbar.navbar-top {
margin: 0;
border-radius: 0 !important;
font-size: 15px;
}
.container-header,
.container-footer {
max-width: calc(var(--mian-max-width, var(--container, 1200px)) + 180px);
margin-left: auto;
margin-right: auto;
width: 100%;
padding-left: 15px;
padding-right: 15px;
}
.navbar-top .navbar-brand {
padding: 7px 10px;
}
.navbar-logo > img,
.navbar-logo .site-brand__logo-img,
.site-brand .site-brand__logo-img,
.site-brand__logo-img {
height: 36px !important;
width: auto !important;
max-width: min(180px, 40vw) !important;
max-height: 36px !important;
padding: 0 !important;
object-fit: contain !important;
}
.navbar-top .navbar-nav,
.navbar-top ul.nav-desktop {
margin-left: 20px;
margin-right: 20px;
display: flex;
align-items: center;
gap: 0;
list-style: none;
padding: 0;
}
.navbar-top .navbar-nav > li > a,
.navbar-top ul.nav-desktop > li > a {
padding-left: 10px;
padding-right: 10px;
border-radius: 4px;
display: inline-flex !important;
align-items: center;
min-height: 36px;
font-size: 15px;
}
.navbar-top .site-nav__row {
display: flex;
align-items: center;
width: 100%;
min-height: var(--nav-height, 60px);
}
.navbar-top .nav-actions {
margin-left: auto;
display: flex;
align-items: center;
gap: 8px;
overflow: visible;
position: relative;
z-index: 25;
}
.scroll-down.nav-fixed .header.scroll-down-hide,
body.scroll-down.nav-fixed .header.scroll-down-hide {
transform: translate3d(0, -105%, 0);
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
/* Layout-1 style: keep search as icon; hide expanded desktop form */
@media (min-width: 992px) {
.navbar-top .nav-searchbox--desktop {
display: none !important;
}
}
/* Transparent white controls on gradient hero */
.header.show-slide .site-nav:not(.is-scrolled) .btn-outline {
color: #fff;
border-color: rgba(255, 255, 255, 0.55);
background: transparent;
}
.header.show-slide .site-nav:not(.is-scrolled) .btn-outline:hover {
color: #fff;
border-color: #fff;
background: rgba(255, 255, 255, 0.12);
}
.header.show-slide .site-nav:not(.is-scrolled) .nav-user__guest-avatar,
.header.show-slide .site-nav:not(.is-scrolled) .icon-btn {
color: #fff;
}
-128
View File
@@ -1,128 +0,0 @@
/* Cards submenu */
.aksrt-nav__cards {
display: grid;
gap: 12px;
padding: 8px;
}
.aksrt-nav__card {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 12px;
border-radius: 6px;
text-decoration: none;
color: inherit;
transition: background 0.15s;
}
.aksrt-nav__card:hover {
background: var(--color-primary-soft, rgba(240, 68, 148, 0.06));
}
.aksrt-nav__card-icon {
width: 36px;
height: 36px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
background: var(--color-primary-soft, #e6f4ff);
color: var(--color-primary);
font-size: 16px;
flex-shrink: 0;
}
.aksrt-nav__card-text {
flex: 1;
min-width: 0;
}
.aksrt-nav__card-title {
font-size: 13px;
font-weight: 600;
color: var(--color-ink);
margin: 0;
}
.aksrt-nav__card-desc {
font-size: 11px;
color: var(--color-ink-4);
margin: 2px 0 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ============================================================
* 导航溢出「更多」下拉
* ============================================================ */
.aksrt-nav-more {
position: relative;
}
.aksrt-nav-more__btn {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 6px 12px;
border: none;
background: none;
color: var(--color-ink-2);
font-size: 14px;
font-weight: 500;
cursor: pointer;
border-radius: var(--radius, 8px);
transition: background 0.15s, color 0.15s;
}
.aksrt-nav-more__btn:hover {
background: var(--color-primary-soft, rgba(240, 68, 148, 0.08));
color: var(--color-primary);
}
.aksrt-nav-more__dropdown {
display: none;
position: absolute;
top: 100%;
right: 0;
min-width: 160px;
padding: 6px 0;
background: var(--surface-1, #fff);
border: 1px solid var(--color-line, rgba(50, 50, 50, 0.06));
border-radius: var(--radius, 8px);
box-shadow: var(--shadow-lg, 0 0 10px rgba(116, 116, 116, 0.12));
z-index: var(--z-dropdown, 100);
list-style: none;
margin: 4px 0 0;
}
.aksrt-nav-more__dropdown.is-open {
display: block;
}
.aksrt-nav-more__dropdown li {
display: block;
}
.aksrt-nav-more__dropdown li a,
.aksrt-nav-more__dropdown li button {
display: block;
width: 100%;
padding: 8px 16px;
border: none;
background: none;
color: var(--color-ink-2);
font-size: 14px;
text-align: left;
text-decoration: none;
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.aksrt-nav-more__dropdown li a:hover,
.aksrt-nav-more__dropdown li button:hover {
background: var(--color-primary-soft, rgba(240, 68, 148, 0.08));
color: var(--color-primary);
}
@@ -1,12 +0,0 @@
/* Dark mode Mega Menu */
html.dark ul.nav-desktop .mega-menu-item > .mega-menu__panel,
body.dark-theme ul.nav-desktop .mega-menu-item > .mega-menu__panel {
background: var(--surface-page);
border-color: var(--color-line, #2d2d3f);
}
html.dark .mega-menu__panel > .menu-item:hover,
body.dark-theme .mega-menu__panel > .menu-item:hover {
background: var(--surface-2);
}
-35
View File
@@ -1,35 +0,0 @@
/* Hover effects */
.aksrt-nav__item--hover-underline > a::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 2px;
background: var(--color-primary);
transition: width 0.2s ease, left 0.2s ease;
border-radius: 1px;
}
.aksrt-nav__item--hover-underline:hover > a::after {
width: 60%;
left: 20%;
}
.aksrt-nav__item--hover-background > a {
transition: background-color 0.2s;
border-radius: 4px;
}
.aksrt-nav__item--hover-background:hover > a {
background-color: var(--color-primary-soft, rgba(240, 68, 148, 0.08));
}
.aksrt-nav__item--hover-color > a {
transition: color 0.2s;
}
.aksrt-nav__item--hover-color:hover > a {
color: var(--color-primary);
}
-28
View File
@@ -1,28 +0,0 @@
/* Mega submenu */
.aksrt-nav__mega {
position: absolute;
top: 100%;
left: 0;
z-index: 1001;
background: var(--surface-1);
border: 1px solid var(--color-line);
border-radius: var(--radius);
box-shadow: var(--shadow-lg);
padding: 16px;
opacity: 0;
visibility: hidden;
transform: translateY(8px);
transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
}
.aksrt-nav__item:hover > .aksrt-nav__mega {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.aksrt-nav__mega--columns {
display: grid;
gap: 16px;
}
@@ -1,41 +0,0 @@
/* Menu item badge */
.aksrt-nav__badge {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 600;
line-height: 1;
padding: 2px 5px;
border-radius: 3px;
margin-left: 4px;
white-space: nowrap;
vertical-align: middle;
transform: translateY(-1px);
}
.aksrt-nav__badge--new {
color: #fff;
background: var(--color-error);
}
.aksrt-nav__badge--hot {
color: #fff;
background: var(--color-warning);
}
.aksrt-nav__badge--info {
color: #fff;
background: var(--color-info);
}
.aksrt-nav__badge--success {
color: #fff;
background: var(--color-success);
}
.aksrt-nav__badge--vip {
color: #fff;
background: linear-gradient(135deg, var(--color-warning), var(--color-error));
}
@@ -1,20 +0,0 @@
/* Menu item icon */
.aksrt-nav__icon {
font-size: 0.85em;
width: 1.2em;
text-align: center;
margin-right: 4px;
opacity: 0.7;
transition: opacity 0.2s;
}
.aksrt-nav__item--has-icon > a {
display: inline-flex;
align-items: center;
gap: 4px;
}
.aksrt-nav__item--has-icon:hover .aksrt-nav__icon {
opacity: 1;
}
@@ -1,18 +0,0 @@
/* Mobile theme toggle in drawer */
.nav-drawer__theme-toggle {
padding: 0 20px 16px;
}
.nav-drawer__theme-toggle .theme-toggle-mobile {
width: 100%;
min-height: 44px;
justify-content: center;
gap: 8px;
display: flex;
align-items: center;
}
/* ============================================================
* Menu Decoration — Icons, Badges, Hover Effects
* ============================================================ */
-814
View File
@@ -1,814 +0,0 @@
/* Mobile toggle */
.nav-toggle {
display: flex;
}
@media (max-width: 991px) {
.site-brand {
max-width: min(46vw, 311px);
}
.site-brand__media {
padding: 0 8px;
}
.nav-publish-btn {
display: none;
}
}
/* Desktop search icon: hide on mobile (use drawer search instead) */
@media (max-width: 767px) {
.site-brand {
max-width: min(62vw, 260px);
padding: 7px 0;
}
.site-brand__media {
padding: 0;
}
#search-toggle {
display: none;
}
/* Search panel only makes sense alongside the desktop search icon */
.nav-search-panel {
display: none !important;
}
}
@media (min-width: 768px) {
ul.nav-desktop,
.nav-desktop--fallback {
display: flex;
}
.nav-auth {
display: flex;
}
.nav-auth-dropdown {
display: flex;
}
.nav-toggle {
display: none;
}
}
/* ============================================================
* Header Layout Variants (desktop ≥768px)
* Layout 1: Standard — brand left, nav flex-1, actions right
* Layout 2: Centered — brand left, nav centered with flex, actions right
* Layout 3: Compact — brand left, nav pushed right, actions right
* ============================================================ */
@media (min-width: 768px) {
/* Layout 2: center the nav between brand and actions */
body.header-layout-2 .nav-desktop {
flex: 1;
justify-content: center;
}
body.header-layout-2 .nav-actions {
flex-shrink: 0;
}
/* Layout 3: push nav to the right side */
body.header-layout-3 .site-nav__row {
justify-content: flex-start;
}
body.header-layout-3 .nav-desktop {
flex: 1;
justify-content: flex-end;
margin-left: 24px;
}
body.header-layout-3 .nav-actions {
margin-left: 8px;
}
}
.nav-mobile-strip {
display: none;
width: calc(100% + 8px);
margin: 0 -4px;
padding: 0 0 12px;
}
.nav-mobile-strip__menu,
.nav-mobile-strip__menu ul {
display: flex;
align-items: center;
gap: 8px;
overflow-x: auto;
margin: 0;
padding: 0;
list-style: none;
scrollbar-width: none;
-ms-overflow-style: none;
}
.nav-mobile-strip__menu::-webkit-scrollbar,
.nav-mobile-strip__menu ul::-webkit-scrollbar {
display: none;
}
.nav-mobile-strip__menu a {
display: inline-flex;
align-items: center;
min-height: 34px;
padding: 0 12px;
border-radius: var(--radius-pill, 999px);
background: var(--surface-2);
color: var(--color-ink-2);
white-space: nowrap;
text-decoration: none;
font-size: 0.875rem;
font-weight: 500;
}
.nav-mobile-strip__menu .current-menu-item > a,
.nav-mobile-strip__menu .current_page_item > a {
background: var(--color-primary);
color: var(--color-on-primary, #fff);
}
@media (max-width: 767px) {
.nav-mobile-strip {
display: block;
}
}
/* ============================================================
* User avatar + dropdown
* ============================================================ */
.nav-user {
position: relative;
}
.nav-user__toggle {
width: 36px;
height: 36px;
border-radius: var(--radius-avatar);
padding: 0;
border: none; /* 对齐 zibll:头像无边框 */
cursor: pointer;
/* Allow unread corner badge to paint outside the avatar circle. */
overflow: visible;
background: var(--surface-2);
transition: box-shadow var(--dur-fast, 0.15s) var(--ease);
}
.nav-user__toggle:hover {
box-shadow: 0 0 0 2px var(--color-primary-soft);
}
.nav-user__toggle img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
border-radius: inherit;
}
.user-dropdown {
position: absolute;
top: calc(100% + 8px);
right: 0;
width: 260px;
max-width: calc(100vw - 32px);
padding: 12px 0;
background: var(--surface-1);
border: 1px solid var(--color-line);
border-radius: var(--radius-lg, 8px);
box-shadow: var(--shadow-lg);
z-index: 1100;
opacity: 0;
visibility: hidden;
transform: translateY(-6px);
transition: opacity 0.2s, transform 0.2s, visibility 0.2s;
}
.user-dropdown.is-open {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.user-dropdown__profile {
display: flex;
align-items: center;
gap: 12px;
padding: 8px 16px 14px;
}
.user-dropdown__profile img {
width: 44px;
height: 44px;
border-radius: var(--radius-avatar);
object-fit: cover;
flex-shrink: 0;
}
.user-dropdown__name {
font-weight: 700;
font-size: 0.9375rem;
color: var(--color-ink);
}
.user-dropdown__email {
font-size: 0.75rem;
color: var(--color-ink-4);
word-break: break-all;
margin-top: 2px;
}
.user-dropdown__sep {
height: 1px;
background: var(--color-line);
margin: 6px 0;
}
.user-dropdown a,
.user-dropdown button {
display: flex;
align-items: center;
gap: 10px;
width: 100%;
padding: 0 16px;
height: 44px;
border: none;
background: none;
font-size: 0.875rem;
color: var(--color-ink);
text-align: left;
cursor: pointer;
transition: background var(--dur-fast, 0.15s) var(--ease),
color var(--dur-fast, 0.15s) var(--ease);
}
.user-dropdown a:hover,
.user-dropdown button:hover {
background: var(--surface-3);
color: var(--color-primary-active);
}
/* dropdown 项内的 SVG 图标 */
.user-dropdown__item svg {
width: 16px;
height: 16px;
flex-shrink: 0;
opacity: 0.85;
}
.user-dropdown__item span:first-of-type:not(.user-dropdown__pill) {
flex: 1;
min-width: 0;
}
/* 未读消息数 badge */
.user-dropdown__badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 18px;
height: 18px;
padding: 0 5px;
margin-left: auto;
font-size: 11px;
font-weight: 600;
color: #fff;
background: var(--color-error, #ef4444);
border-radius: 9px;
line-height: 1;
}
.user-dropdown__credits {
display: flex;
align-items: center;
gap: 10px;
padding: 0 16px;
height: 44px;
font-size: 0.875rem;
color: var(--color-ink-2);
}
.user-dropdown__credits i {
color: var(--color-warning);
flex-shrink: 0;
}
.user-dropdown__credits-label {
flex: 1;
}
.user-dropdown__credits-value {
font-weight: 600;
color: var(--color-primary);
}
.user-dropdown__logout {
color: var(--color-error) !important;
}
.user-dropdown__logout svg {
color: var(--color-error);
}
.user-dropdown__logout:hover {
background: rgba(239, 68, 68, 0.08) !important;
color: var(--color-error) !important;
}
.user-dropdown .badge-dot {
margin-left: auto;
min-width: 8px;
height: 8px;
border-radius: var(--radius-pill);
background: var(--color-error);
}
/* ============================================================
* Search panel
* ============================================================ */
.nav-search-panel {
display: none;
padding: 12px 0 16px;
border-top: 1px solid var(--color-line);
}
.nav-search-panel.is-open {
display: block;
}
.nav-searchbox {
margin: 0;
}
.nav-searchbox__field {
display: flex;
align-items: center;
gap: 10px;
min-height: 42px;
padding: 0 6px 0 14px;
border: 1px solid var(--color-line);
border-radius: var(--radius-pill, 999px);
background: var(--surface-3);
box-sizing: border-box;
transition: border-color var(--dur-fast, 0.15s) var(--ease), box-shadow var(--dur-fast, 0.15s) var(--ease), background var(--dur-fast, 0.15s) var(--ease);
}
.nav-searchbox__icon {
order: 1;
flex: 0 0 16px;
width: 16px;
height: 16px;
color: var(--color-ink-4);
pointer-events: none;
}
.nav-searchbox__input {
order: 2;
flex: 1;
min-width: 0;
width: auto;
height: 40px;
padding: 0;
border: 0;
background: transparent;
color: var(--color-ink);
font-size: 0.9rem;
line-height: 1.2;
box-sizing: border-box;
}
.nav-searchbox__input:focus {
outline: none;
}
.nav-searchbox__input::placeholder {
color: var(--color-ink-4);
}
.nav-searchbox__submit {
order: 3;
flex: 0 0 auto;
height: 30px;
min-width: 64px;
padding: 0 14px;
border: 0;
border-radius: var(--radius-pill, 999px);
background: var(--color-primary);
color: #fff;
font-size: 0.8125rem;
font-weight: 600;
line-height: 1;
white-space: nowrap;
cursor: pointer;
}
.nav-searchbox__field:focus-within {
border-color: var(--color-primary);
box-shadow: 0 0 0 3px var(--color-primary-soft);
background: var(--surface-1);
}
.nav-searchbox__submit:hover {
background: var(--color-primary-active);
}
/* ============================================================
* Mobile drawer / mobile header
* ============================================================ */
.mobile-header.nav-drawer-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1200;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s;
}
.mobile-header.nav-drawer-backdrop.is-open {
opacity: 1;
visibility: visible;
}
.mobile-header.nav-drawer {
position: fixed;
top: 0;
right: 0;
width: min(100vw, 360px);
height: 100vh;
max-height: 100dvh;
background: var(--surface-page);
z-index: 1210;
box-shadow: var(--shadow-drawer);
transform: translateX(100%);
transition: transform 0.32s var(--ease-out, ease);
display: flex;
flex-direction: column;
overflow: auto;
pointer-events: none;
visibility: hidden;
}
.mobile-header.nav-drawer.is-open {
transform: translateX(0);
pointer-events: auto;
visibility: visible;
}
.mobile-navbar {
display: flex;
flex-direction: column;
min-height: 100%;
}
.mobile-navbar .navbar-brand {
max-width: calc(100% - 52px);
padding: 7px 0;
}
.mobile-navbar .navbar-logo {
padding: 0;
}
.nav-drawer-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1200;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s;
}
.nav-drawer-backdrop.is-open {
opacity: 1;
visibility: visible;
}
.nav-drawer {
position: fixed;
top: 0;
right: 0;
width: min(100vw, 360px);
height: 100vh;
max-height: 100dvh;
background: var(--surface-page);
z-index: 1210;
box-shadow: var(--shadow-drawer);
transform: translateX(100%);
transition: transform 0.32s var(--ease-out, ease);
display: flex;
flex-direction: column;
overflow: auto;
pointer-events: none;
visibility: hidden;
}
.nav-drawer.is-open {
transform: translateX(0);
pointer-events: auto;
visibility: visible;
}
.nav-drawer__head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 16px 20px;
border-bottom: 1px solid var(--color-line);
font-weight: 700;
font-size: 1rem;
}
.site-brand--drawer {
max-width: calc(100% - 52px);
padding: 7px 0;
}
.site-brand--drawer .site-brand__media {
padding: 0;
}
.nav-drawer__search {
padding: 16px 20px 0;
}
.nav-drawer__search .nav-searchbox__field {
min-height: 40px;
}
.nav-drawer__search .nav-searchbox__input {
height: 38px;
}
.nav-drawer__search .nav-searchbox__submit {
height: 28px;
min-width: 58px;
padding: 0 12px;
font-size: 0.75rem;
}
.nav-searchbox__meta {
display: grid;
gap: 10px;
margin-top: 12px;
}
.nav-searchbox__types {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.nav-searchbox__type {
display: inline-flex;
align-items: center;
min-height: 32px;
padding: 0 12px;
border: 1px solid var(--color-line);
border-radius: var(--radius-pill, 999px);
background: var(--surface-2);
color: var(--color-ink-3);
font-size: 0.8125rem;
font-weight: 600;
cursor: pointer;
}
.nav-searchbox__type.is-active {
border-color: var(--color-primary);
background: var(--color-primary-soft);
color: var(--color-primary);
}
.nav-searchbox__category-wrap {
position: relative;
}
.nav-searchbox__category {
appearance: none;
width: 100%;
min-height: 36px;
padding: 0 34px 0 12px;
border: 1px solid var(--color-line);
border-radius: var(--radius-pill, 999px);
background: var(--surface-2);
color: var(--color-ink);
font: 500 0.875rem/1 var(--font-ui);
}
.nav-searchbox__category-wrap::after {
content: '';
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid var(--color-ink-3);
pointer-events: none;
}
.nav-searchbox__category:disabled {
opacity: 0.56;
cursor: not-allowed;
}
.nav-drawer__menu {
flex: 1;
padding: 16px 20px 32px;
}
.nav-drawer__menu a {
display: block;
padding: 14px 0;
font-size: 1rem;
font-weight: 500;
color: var(--color-ink);
border-bottom: 1px solid var(--color-line-soft);
}
.nav-drawer__menu a:hover {
color: var(--color-primary-active);
}
.nav-drawer__menu ul {
list-style: none;
margin: 0;
padding: 0;
}
.nav-drawer__auth {
padding: 20px;
display: flex;
flex-direction: column;
gap: 12px;
border-top: 1px solid var(--color-line);
}
.nav-drawer__auth .btn-outline,
.nav-drawer__auth .btn-primary {
width: 100%;
height: 44px;
}
.nav-drawer__publish {
padding: 0 20px 20px;
}
.nav-drawer__publish .btn-primary {
width: 100%;
min-height: 44px;
justify-content: center;
gap: 8px;
}
/* ============================================================
* Header user box (Zibll-like sub-user-box grid)
* ============================================================ */
.nav-user__toggle {
position: relative;
}
.nav-user__dot {
position: absolute;
top: -1px;
right: -1px;
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--color-error, #ef4444);
border: 2px solid var(--surface-1, #fff);
box-sizing: content-box;
pointer-events: none;
z-index: 2;
}
.nav-user__guest-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
background: var(--surface-2);
color: var(--color-ink-3);
}
.user-dropdown {
width: 300px;
padding: 14px 12px 12px;
}
.user-dropdown__profile.user-info {
position: relative;
padding-right: 42px;
}
.user-dropdown__meta {
min-width: 0;
flex: 1;
}
.user-dropdown__name {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
}
/* Beat generic `.user-dropdown a { width:100%; height:44px }` sizing. */
.user-dropdown a.user-dropdown__msg,
.user-dropdown__msg {
position: absolute;
top: 8px;
right: 8px;
width: 34px !important;
height: 34px !important;
min-width: 34px;
max-width: 34px;
border-radius: 50%;
display: inline-flex !important;
align-items: center;
justify-content: center;
gap: 0 !important;
padding: 0 !important;
background: var(--surface-2);
color: var(--color-ink-3);
box-sizing: border-box;
}
.user-dropdown a.user-dropdown__msg:hover,
.user-dropdown__msg:hover {
background: var(--surface-3);
color: var(--color-primary);
}
.user-dropdown__msg .user-dropdown__badge {
position: absolute;
top: -4px;
right: -4px;
margin: 0;
}
.user-dropdown__guest-title {
padding: 4px 8px 12px;
text-align: center;
font-weight: 700;
color: var(--color-ink);
}
.user-dropdown__actions {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px 4px;
padding: 4px 2px 2px;
}
.user-dropdown__actions--admin {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.user-dropdown__action {
display: flex !important;
flex-direction: column;
align-items: center;
justify-content: flex-start;
gap: 6px !important;
width: auto !important;
height: auto !important;
min-height: 0;
padding: 6px 4px !important;
text-align: center !important;
font-size: 12px !important;
line-height: 1.25;
color: var(--color-ink-3) !important;
background: transparent !important;
}
.user-dropdown__action:hover {
background: transparent !important;
color: var(--color-primary) !important;
}
.user-dropdown__action-icon {
width: 40px;
height: 40px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 15px;
color: #fff;
}
.user-dropdown__action-icon.is-blue { background: linear-gradient(135deg, #60a5fa, #3b82f6); }
.user-dropdown__action-icon.is-purple { background: linear-gradient(135deg, #a78bfa, #8b5cf6); }
.user-dropdown__action-icon.is-green { background: linear-gradient(135deg, #34d399, #10b981); }
.user-dropdown__action-icon.is-red { background: linear-gradient(135deg, #f87171, #ef4444); }
.user-dropdown__action-icon.is-yellow { background: linear-gradient(135deg, #fbbf24, #f59e0b); color: #1f2937; }
.user-dropdown__action.is-danger {
color: var(--color-error, #ef4444) !important;
}
.user-dropdown__credits {
margin-top: 2px;
border-radius: 12px;
background: var(--surface-2);
margin-left: 4px;
margin-right: 4px;
width: auto;
}
@@ -1,10 +0,0 @@
/* ===== nav_fixed mobile fallback ===== */
/* On mobile, static nav should remain sticky so the hamburger toggle stays accessible */
@media (max-width: 767px) {
.has-static-nav .site-nav--static {
position: sticky;
top: 0;
z-index: 1000;
}
}
@@ -1,109 +0,0 @@
/* Responsive Mega Menu */
@media (max-width: 767px) {
ul.nav-desktop .mega-menu-item > .mega-menu__panel {
position: static;
transform: none;
width: 100%;
max-width: none;
margin: 0;
box-shadow: none;
}
.mega-menu__columns-2,
.mega-menu__columns-3,
.mega-menu__columns-4,
.mega-menu__columns-5 {
grid-template-columns: 1fr;
}
}
/* ============================================================
* Right actions (icons + auth)
* ============================================================ */
.nav-actions {
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
margin-left: auto;
overflow: visible;
position: relative;
z-index: 25;
}
.nav-settings-link,
.nav-publish-btn {
flex-shrink: 0;
}
.nav-settings-link svg {
width: 18px;
height: 18px;
}
.nav-publish-btn {
display: inline-flex;
align-items: center;
gap: 8px;
height: 36px;
padding: 0 14px;
font-size: 0.875rem;
font-weight: 600;
}
.nav-publish-btn i {
font-size: 0.8125rem;
}
.theme-toggle.is-animating svg {
transform: rotate(360deg);
}
/* ============================================================
* Auth buttons (in nav, when logged out)
* ============================================================ */
.nav-auth {
display: none;
align-items: center;
gap: 8px;
}
/* btn-outline / btn-primary 复用 core/buttons.css 的定义,
* 这里仅做导航专用调整(高度对齐、字体) */
.nav-auth .btn-outline,
.nav-auth .btn-primary {
height: 36px;
font-size: 0.875rem;
padding: 0 16px;
}
/* Auth dropdown variant (layouts 1/3) — icon trigger + panel */
.nav-auth-dropdown {
position: relative;
display: none;
align-items: center;
}
.nav-auth-dropdown__trigger {
width: 36px;
height: 36px;
}
.nav-auth-dropdown__trigger svg {
width: 20px;
height: 20px;
}
.nav-auth-dropdown__panel {
display: none;
position: absolute;
top: calc(100% + 8px);
right: 0;
min-width: 180px;
z-index: 1100;
}
.nav-auth-dropdown.is-open .nav-auth-dropdown__panel {
display: block;
}
+164
View File
@@ -0,0 +1,164 @@
/* Utilities for zibll header chrome */
.css-icon.i-menu {
position: relative;
display: inline-block;
width: 1.15em;
height: 1em;
vertical-align: -0.1em;
}
.css-icon.i-menu > i,
.css-icon.i-menu::before,
.css-icon.i-menu::after {
content: "";
position: absolute;
left: 0;
right: 0;
height: 2px;
background: currentColor;
border-radius: 1px;
transition: 0.25s;
}
.css-icon.i-menu > i { top: 50%; margin-top: -1px; }
.css-icon.i-menu::before { top: 0; }
.css-icon.i-menu::after { bottom: 0; }
.list-inline { padding-left: 0; list-style: none; margin: 0; }
.list-inline > li { display: inline-block; vertical-align: middle; }
.list-inline.splitters > li + li { margin-left: 6px; }
.navbar-top .flex.ac { display: flex; align-items: center; }
.navbar-top .flex.jsb { display: flex; justify-content: space-between; }
.navbar-top .flex.jsa { display: flex; justify-content: space-around; }
.navbar-top .flex.jc { display: flex; justify-content: center; }
.mb6 { margin-bottom: 6px; }
.mb10 { margin-bottom: 10px; }
.mb20 { margin-bottom: 20px; }
.mt6 { margin-top: 6px; }
.mt10 { margin-top: 10px; }
.ml6 { margin-left: 6px; }
.ml10 { margin-left: 10px; }
.em09 { font-size: 0.9em; }
.em12 { font-size: 1.2em; }
.muted-2-color { opacity: 0.7; }
.muted-3-color { opacity: 0.55; }
.text-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.padding-10 { padding: 10px; }
.relative { position: relative; }
.inline-block { display: inline-block; }
.hide { display: none !important; }
.pull-right { float: right; }
.null { background: none; border: 0; padding: 0; color: inherit; }
.abs-right { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); }
/* Mid breakpoint fold trigger (zibll ~991) */
@media (max-width: 991px) {
.navbar-top .show-nav-but { display: block !important; }
.navbar-top .nav.navbar-nav:not(.show) {
display: none;
}
.navbar-top .nav.navbar-nav.show {
display: block;
position: absolute;
left: 0; right: 0;
top: 100%;
background: var(--main-bg-color, #fff);
z-index: 1001;
padding: 10px;
box-shadow: 0 8px 20px rgba(0,0,0,.08);
}
}
/* Language dropdown */
.language-dropdown { position: relative; }
.language-dropdown .dropdown-menu,
.language-dropdown .hover-show-con {
min-width: 140px;
right: 0;
left: auto;
padding: 8px 0;
}
.language-dropdown .translate-button { display: flex; align-items: center; padding: 6px 14px; }
.language-dropdown .translate-button.active { color: var(--focus-color); }
/* Layout2 inline search focus panel */
.navbar-collapse .search-input {
min-width: 160px;
max-width: 240px;
height: 34px;
border-radius: 20px;
border: 0;
padding: 0 36px 0 14px;
}
.navbar-form.navbar-left.hover-show { margin: 0 8px; }
.navbar-form .form-group.relative { position: relative; }
.navbar-form .abs-right { right: 10px; }
/* Mobile drawer body scroll lock */
body.mobile-navbar-show { overflow: hidden; }
/* Ensure container-header flex row */
.container-header {
display: flex;
align-items: center;
flex-wrap: nowrap;
max-width: var(--nav-max-width, 100%);
margin: 0 auto;
width: 100%;
}
.navbar-collapse {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
flex-wrap: nowrap;
}
.navbar-header { display: flex; align-items: center; flex-shrink: 0; }
.navbar-top .navbar-toggle { display: none; background: none; border: 0; color: inherit; }
@media (max-width: 767px) {
.navbar-top .navbar-toggle { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; }
.navbar-collapse { display: none; }
}
/* Senior submenu full width under fixed header */
.navbar-top .sub-menu.senior-submenu {
position: fixed;
left: 0; right: 0;
top: 59px;
width: 100%;
min-width: 100%;
padding: 20px 0;
border-radius: 0;
z-index: 998;
}
.navbar-inline-search-panel {
position: absolute;
left: 0;
top: calc(100% + 8px);
min-width: 280px;
max-width: 360px;
padding: 12px;
background: var(--main-bg-color, #fff);
border-radius: var(--main-radius, 8px);
box-shadow: 0 8px 24px rgba(0,0,0,.12);
z-index: 1002;
display: none;
}
.navbar-form .form-group:hover .navbar-inline-search-panel,
.navbar-form .form-group:focus-within .navbar-inline-search-panel,
.navbar-inline-search-panel.is-open {
display: block;
visibility: visible;
}
.navbar-inline-search-suggest__item {
display: flex;
flex-direction: column;
padding: 6px 4px;
color: inherit;
text-decoration: none;
}
.navbar-inline-search-suggest__item:hover { color: var(--focus-color); }
.navbar-inline-search-hots .but { margin: 0 4px 4px 0; }
.aksrt-sme-field { display: block; margin: 4px 0; }
.aksrt-sme-field span { display: block; font-size: 12px; color: #646970; }
.aksrt-sme-card, .aksrt-sme-col { border: 1px solid #dcdcde; padding: 8px; margin: 8px 0; border-radius: 4px; }
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

+243
View File
@@ -0,0 +1,243 @@
/**
* Nav menu senior submenu visual editors (graphic cards / multi-column).
* Enhances WP Appearance → Menus fields for aksrt_menu_options JSON.
*
* @package AKSRT
*/
(function ($) {
'use strict';
function parseJSON(raw, fallback) {
try {
var data = JSON.parse(raw || '');
return data && typeof data === 'object' ? data : fallback;
} catch (e) {
return fallback;
}
}
function graphicTemplate() {
return {
arrangement: '',
size: 'md',
img_scale: 100,
items: [{ img: '', title: '', badge: '', badge_class: 'jb-red', link: { url: '', text: '', target: '' } }],
};
}
function multiTemplate() {
return {
columns: [
{
title: '',
icon: '',
img_icon: '',
link: { url: '', text: '', target: '' },
items: [{ title: '', icon: '', img_icon: '', link: { url: '', text: '', target: '' } }],
},
],
};
}
function field(name, label, value, type) {
type = type || 'text';
return (
'<label class="aksrt-sme-field"><span>' +
label +
'</span><input type="' +
type +
'" data-name="' +
name +
'" value="' +
String(value || '').replace(/"/g, '&quot;') +
'" class="widefat"></label>'
);
}
function renderGraphicUI($wrap, data) {
var html = '<div class="aksrt-sme-toolbar">';
html += '<button type="button" class="button aksrt-sme-add-card">添加卡片</button>';
html += '</div><div class="aksrt-sme-cards">';
(data.items || []).forEach(function (item, i) {
html += '<div class="aksrt-sme-card" data-index="' + i + '">';
html += '<div class="aksrt-sme-card-head"><strong>卡片 #' + (i + 1) + '</strong>';
html += ' <button type="button" class="button-link-delete aksrt-sme-del-card">删除</button></div>';
html += field('img', '图片 URL', item.img || '');
html += field('title', '标题', item.title || '');
html += field('badge', '徽章', item.badge || '');
html += field('badge_class', '徽章 class', item.badge_class || '');
html += field('link.url', '链接', (item.link && item.link.url) || '');
html += '</div>';
});
html += '</div>';
html += field('size', '尺寸 sm/md/lg/xs', data.size || 'md');
html += field('img_scale', '图片比例%', data.img_scale || 100, 'number');
$wrap.html(html);
}
function renderMultiUI($wrap, data) {
var html = '<div class="aksrt-sme-toolbar">';
html += '<button type="button" class="button aksrt-sme-add-col">添加栏目</button>';
html += '</div><div class="aksrt-sme-cols">';
(data.columns || []).forEach(function (col, i) {
html += '<div class="aksrt-sme-col" data-index="' + i + '">';
html += '<div class="aksrt-sme-card-head"><strong>栏目 #' + (i + 1) + '</strong>';
html += ' <button type="button" class="button-link-delete aksrt-sme-del-col">删除栏目</button></div>';
html += field('title', '栏目标题', col.title || '');
html += field('icon', '图标 class', col.icon || '');
html += field('link.url', '栏目链接', (col.link && col.link.url) || '');
html += '<div class="aksrt-sme-items">';
(col.items || []).forEach(function (item, j) {
html += '<div class="aksrt-sme-item" data-j="' + j + '">';
html += field('items.' + j + '.title', '链接标题', item.title || '');
html += field('items.' + j + '.link.url', '链接 URL', (item.link && item.link.url) || '');
html += field('items.' + j + '.icon', '图标', item.icon || '');
html += '</div>';
});
html += '<button type="button" class="button aksrt-sme-add-item">添加链接</button>';
html += '</div></div>';
});
html += '</div>';
$wrap.html(html);
}
function readGraphic($wrap) {
var data = graphicTemplate();
data.size = $wrap.find('[data-name="size"]').val() || 'md';
data.img_scale = parseInt($wrap.find('[data-name="img_scale"]').val(), 10) || 100;
data.items = [];
$wrap.find('.aksrt-sme-card').each(function () {
var $c = $(this);
data.items.push({
img: $c.find('[data-name="img"]').val() || '',
title: $c.find('[data-name="title"]').val() || '',
badge: $c.find('[data-name="badge"]').val() || '',
badge_class: $c.find('[data-name="badge_class"]').val() || '',
link: { url: $c.find('[data-name="link.url"]').val() || '', text: '', target: '' },
});
});
return data;
}
function readMulti($wrap) {
var data = { columns: [] };
$wrap.find('.aksrt-sme-col').each(function () {
var $col = $(this);
var col = {
title: $col.find('[data-name="title"]').first().val() || '',
icon: $col.find('[data-name="icon"]').first().val() || '',
img_icon: '',
link: { url: $col.find('[data-name="link.url"]').first().val() || '', text: '', target: '' },
items: [],
};
$col.find('.aksrt-sme-item').each(function () {
var $it = $(this);
col.items.push({
title: $it.find('input[data-name$=".title"]').val() || '',
icon: $it.find('input[data-name$=".icon"]').val() || '',
img_icon: '',
link: { url: $it.find('input[data-name$=".link.url"]').val() || '', text: '', target: '' },
});
});
data.columns.push(col);
});
return data;
}
function enhanceItem($item) {
if ($item.data('aksrtSme')) return;
$item.data('aksrtSme', 1);
var $graphicTa = $item.find('textarea[name*="[graphic_card_opts_json]"]');
var $multiTa = $item.find('textarea[name*="[multi_column_links_opts_json]"]');
var $type = $item.find('select[name*="[submenu_type]"]');
if (!$graphicTa.length && !$multiTa.length) return;
var $ui = $('<div class="aksrt-sme-ui" style="margin:8px 0;padding:10px;border:1px solid #dcdcde;background:#fff;border-radius:4px;"></div>');
$graphicTa.closest('p').before($ui);
function sync() {
var type = $type.val();
if (type === 'graphic_card') {
$graphicTa.closest('p').hide();
$multiTa.closest('p').hide();
var g = parseJSON($graphicTa.val(), graphicTemplate());
renderGraphicUI($ui, g);
$ui.show();
} else if (type === 'multi_column_links') {
$graphicTa.closest('p').hide();
$multiTa.closest('p').hide();
var m = parseJSON($multiTa.val(), multiTemplate());
renderMultiUI($ui, m);
$ui.show();
} else {
$ui.hide().empty();
$graphicTa.closest('p').show();
$multiTa.closest('p').show();
}
}
$type.on('change', sync);
$ui.on('click', '.aksrt-sme-add-card', function (e) {
e.preventDefault();
var g = readGraphic($ui);
g.items.push({ img: '', title: '', badge: '', badge_class: 'jb-red', link: { url: '', text: '', target: '' } });
renderGraphicUI($ui, g);
});
$ui.on('click', '.aksrt-sme-del-card', function (e) {
e.preventDefault();
$(this).closest('.aksrt-sme-card').remove();
});
$ui.on('click', '.aksrt-sme-add-col', function (e) {
e.preventDefault();
var m = readMulti($ui);
m.columns.push({
title: '',
icon: '',
img_icon: '',
link: { url: '', text: '', target: '' },
items: [{ title: '', icon: '', img_icon: '', link: { url: '', text: '', target: '' } }],
});
renderMultiUI($ui, m);
});
$ui.on('click', '.aksrt-sme-del-col', function (e) {
e.preventDefault();
$(this).closest('.aksrt-sme-col').remove();
});
$ui.on('click', '.aksrt-sme-add-item', function (e) {
e.preventDefault();
var $col = $(this).closest('.aksrt-sme-col');
var m = readMulti($ui);
var idx = $col.index();
if (m.columns[idx]) {
m.columns[idx].items.push({ title: '', icon: '', img_icon: '', link: { url: '', text: '', target: '' } });
}
renderMultiUI($ui, m);
});
// Before save, write UI → textarea
$('#update-nav-menu').on('submit.aksrtSme', function () {
var type = $type.val();
if (type === 'graphic_card') {
$graphicTa.val(JSON.stringify(readGraphic($ui), null, 2));
} else if (type === 'multi_column_links') {
$multiTa.val(JSON.stringify(readMulti($ui), null, 2));
}
});
// Hide raw JSON by default; toggle available via double-click title
$graphicTa.closest('p').find('label').attr('title', '双击显示原始 JSON');
sync();
}
function boot() {
$('#menu-to-edit .menu-item').each(function () {
enhanceItem($(this));
});
}
$(boot);
$(document).on('menu-item-added', function () {
setTimeout(boot, 50);
});
})(jQuery);
+51 -24
View File
@@ -1,13 +1,15 @@
/**
* AKSRT nav chrome — zibll contract (body.mobile-navbar-show, folding, chevron).
* Drawer open/close is handled by aksrt-runtime [data-toggle-class].
* AKSRT nav chrome — zibll contract (folding, chevron, language, drawer a11y).
* Drawer open/close via aksrt-runtime [data-toggle-class] → body.mobile-navbar-show.
*/
(function () {
"use strict";
function appendChevrons() {
document.querySelectorAll(".navbar-top li.menu-item-has-children > a").forEach(function (a) {
if (a.querySelector(".fa-angle-down")) return;
var foldTimer = null;
function appendChevrons(root) {
(root || document).querySelectorAll(".navbar-top li.menu-item-has-children > a").forEach(function (a) {
if (a.querySelector(".fa-angle-down, .fas.fa-angle-down")) return;
var i = document.createElement("i");
i.className = "fa fa-angle-down ml6";
i.setAttribute("aria-hidden", "true");
@@ -15,18 +17,30 @@
});
}
function clearFolding() {
var more = document.querySelector(".navbar-nav > li.aksrt-nav-more");
if (!more) return;
var sub = more.querySelector(".sub-menu");
var nav = more.parentNode;
if (sub && nav) {
while (sub.firstChild) {
nav.insertBefore(sub.firstChild, more);
}
}
more.remove();
}
function navFolding() {
var collapse = document.querySelector(".navbar-collapse");
var nav = document.querySelector(".navbar-nav");
if (!collapse || !nav) return;
if (window.innerWidth <= 996) return;
clearFolding();
if (window.innerWidth <= 996) return;
var header = document.querySelector(".header");
if (header && header.offsetHeight <= 81) return;
// Already folded?
if (nav.querySelector("li.aksrt-nav-more")) return;
var surplus = collapse.clientWidth;
Array.prototype.forEach.call(collapse.children, function (child) {
if (!child.classList.contains("navbar-nav")) {
@@ -40,9 +54,7 @@
var foldItems = [];
Array.prototype.forEach.call(nav.children, function (li) {
navsWidth += li.offsetWidth || 0;
if (navsWidth > surplus) {
foldItems.push(li);
}
if (navsWidth > surplus) foldItems.push(li);
});
if (!foldItems.length) return;
@@ -51,14 +63,33 @@
more.innerHTML =
'<a href="javascript:void(0);"><i class="fas fa-bars" aria-hidden="true"></i></a><ul class="sub-menu"></ul>';
var sub = more.querySelector(".sub-menu");
foldItems.forEach(function (li) {
sub.appendChild(li);
});
foldItems.forEach(function (li) { sub.appendChild(li); });
nav.appendChild(more);
appendChevrons(more);
}
function scheduleFold() {
if (foldTimer) clearTimeout(foldTimer);
foldTimer = setTimeout(function () {
try { navFolding(); } catch (e) {}
}, 80);
}
function bindLanguage() {
document.addEventListener("click", function (e) {
var btn = e.target && e.target.closest ? e.target.closest(".translate-button[data-language]") : null;
if (!btn) return;
e.preventDefault();
var lang = btn.getAttribute("data-language");
if (!lang) return;
try { localStorage.setItem("aksrt_lang", lang); } catch (err) {}
var url = new URL(window.location.href);
url.searchParams.set("lang", lang);
window.location.href = url.toString();
});
}
function bindDrawerA11y() {
// Esc closes mobile nav via body class.
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && document.body.classList.contains("mobile-navbar-show")) {
document.body.classList.remove("mobile-navbar-show");
@@ -68,18 +99,14 @@
function init() {
appendChevrons();
try {
navFolding();
} catch (err) {
// ignore fold failures
}
scheduleFold();
bindLanguage();
bindDrawerA11y();
window.addEventListener("resize", scheduleFold, { passive: true });
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === "function") {
window.AksrtFrontend.register("aksrt-nav-chrome", function () {
init();
});
window.AksrtFrontend.register("aksrt-nav-chrome", function () { init(); });
} else if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
+140
View File
@@ -0,0 +1,140 @@
/**
* Enhance layout-2 inline search with AJAX suggestions (aksrt_search_suggestions).
* Extends existing panel search without dual systems.
*/
(function () {
"use strict";
function initInlineSearchSuggest() {
var form = document.querySelector('form[data-aksrt-search-form="inline"]');
if (!form || !window.aksrtData || !aksrtData.ajaxUrl) return;
var input = form.querySelector(".search-input");
var group = form.querySelector(".form-group.relative, .form-group");
if (!input || !group) return;
var panel = group.querySelector(".navbar-inline-search-panel");
if (!panel) {
panel = document.createElement("div");
panel.className = "dropdown-menu hover-show-con navbar-inline-search-panel";
group.appendChild(panel);
}
var timer = null;
var searchConfig = (window.aksrtData && aksrtData.search) || {};
var suggestionsEnabled = searchConfig.suggestionsEnabled !== false;
function typeValue() {
var t = form.querySelector('input[name="aksrt_search_type"]');
return (t && t.value) || searchConfig.defaultType || "post";
}
function renderItems(items) {
var html = "";
if (items && items.length) {
html += '<div class="muted-2-color em09 mb6">' + (searchConfig.suggestTitle || "搜索建议") + "</div>";
html += '<div class="navbar-inline-search-suggest">';
items.forEach(function (it) {
html +=
'<a class="navbar-inline-search-suggest__item" href="' +
(it.url || "#") +
'"><span class="title">' +
(it.title || "") +
'</span>' +
(it.meta ? '<span class="meta muted-2-color em09">' + it.meta + "</span>" : "") +
"</a>";
});
html += "</div>";
}
// Keep hot keywords block if present as static sibling content was replaced —
// re-append hots from data attribute if we stored them.
var hots = form.getAttribute("data-hots");
if (hots) {
try {
var arr = JSON.parse(hots);
if (arr && arr.length) {
html += '<div class="muted-2-color em09 mb6 mt10">热门搜索</div><div class="navbar-inline-search-hots">';
arr.forEach(function (kw) {
html +=
'<a class="but jb-sm" href="' +
(window.location.origin || "") +
"/?s=" +
encodeURIComponent(kw) +
'">' +
kw +
"</a> ";
});
html += "</div>";
}
} catch (e) {}
}
panel.innerHTML = html || panel.innerHTML;
panel.classList.add("is-open");
panel.style.display = "block";
panel.style.visibility = "visible";
}
// Persist hot keywords for re-render after suggestions
var hotLinks = panel.querySelectorAll(".navbar-inline-search-hots a");
if (hotLinks.length) {
var kws = [];
hotLinks.forEach(function (a) {
kws.push((a.textContent || "").trim());
});
form.setAttribute("data-hots", JSON.stringify(kws));
}
function request(q) {
if (!suggestionsEnabled || q.length < 2) {
// restore hots-only
if (form.getAttribute("data-hots")) {
renderItems([]);
}
return;
}
var xhr = new XMLHttpRequest();
xhr.open("POST", aksrtData.ajaxUrl, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
xhr.onload = function () {
if (xhr.status < 200 || xhr.status >= 300) return;
try {
var json = JSON.parse(xhr.responseText);
if (json.success && json.data && json.data.items) {
renderItems(json.data.items);
}
} catch (e) {}
};
xhr.send(
"action=aksrt_search_suggestions&nonce=" +
encodeURIComponent(aksrtData.nonce) +
"&q=" +
encodeURIComponent(q) +
"&type=" +
encodeURIComponent(typeValue())
);
}
input.addEventListener("input", function () {
var q = (input.value || "").trim();
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
request(q);
}, 180);
});
input.addEventListener("focus", function () {
panel.style.display = "block";
panel.style.visibility = "visible";
});
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === "function") {
window.AksrtFrontend.register("aksrt-inline-search-suggest", function () {
initInlineSearchSuggest();
});
} else if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initInlineSearchSuggest);
} else {
initInlineSearchSuggest();
}
})();
+127 -155
View File
@@ -1,9 +1,7 @@
/**
* AKSRT Section Navs — Article TOC / Scrollspy
* AKSRT Section Navs — zibll section_navs parity (posts-nav-lists + scrollspy).
*
* Auto-generates a table of contents from h1~h4 headings within
* [data-nav] content areas. Scrollspy highlights the current section.
* Collapsible sub-items when the TOC is tall.
* Builds TOC from [data-nav] h1–h4 into .posts-nav-box / .posts-nav-lists.
*
* @package AKSRT
*/
@@ -12,164 +10,138 @@
var HEADING_SEL = 'h1, h2, h3, h4';
var MIN_HEADINGS = 2;
var SCROLL_OFFSET = 105;
var MAX_HEIGHT_COLLAPSE = 380;
var NAVBOX = '.posts-nav-box';
var NAV_CLASS = 'posts-nav-lists';
function initSectionNavs() {
var navContainer = document.querySelector('[data-nav]');
if (!navContainer) return;
function isExcluded(el) {
return el.classList.contains('item-heading') || !!el.closest('.no-nav');
}
// Single-post TOC is owned by page-template.js (.posts-nav-box .toc-list).
// Do not invent a second .aksrt-section-nav tree on article singles.
if (document.querySelector('.posts-nav-box .toc-list, .posts-nav-box.toc-widget')) {
function ensureId(el, index) {
if (!el.id) {
el.id = 'section-nav-' + index;
}
return el.id;
}
function buildLists(root) {
var headings = root.querySelectorAll(HEADING_SEL);
var html = '';
var count = 0;
headings.forEach(function (h, i) {
if (isExcluded(h)) return;
var id = ensureId(h, i);
var tag = h.tagName.toUpperCase();
var text = (h.textContent || '').trim();
if (!text) return;
html += '<li class="n-' + tag + '"><a href="#' + id + '">' + text + '</a></li>';
count++;
});
return count >= MIN_HEADINGS ? html : '';
}
function fillBoxes(listsHtml) {
document.querySelectorAll(NAVBOX).forEach(function (box) {
var existing = box.querySelector('.' + NAV_CLASS);
if (existing) {
existing.innerHTML = listsHtml;
return;
}
var title = box.getAttribute('data-title') || '';
var titleHtml = title
? '<div class="box-body notop"><div class="title-theme">' + title + '</div></div>'
: '';
box.insertAdjacentHTML(
'beforeend',
titleHtml +
'<div class="zib-widget"><div class="' +
NAV_CLASS +
' scroll-y mini-scrollbar list-unstyled">' +
listsHtml +
'</div></div>'
);
});
}
function smoothTo(hash) {
var el = document.querySelector(hash);
if (!el) return;
var offset = 0;
var header = document.querySelector('.header');
if (document.body.classList.contains('nav-fixed') && header) {
offset = header.offsetHeight + 12;
}
var top = el.getBoundingClientRect().top + window.pageYOffset - offset;
window.scrollTo({ top: top, behavior: 'smooth' });
}
function bindClicks() {
document.addEventListener('click', function (e) {
var a = e.target && e.target.closest ? e.target.closest('.' + NAV_CLASS + ' a[href^="#"]') : null;
if (!a) return;
var href = a.getAttribute('href');
if (!href || href.length < 2) return;
e.preventDefault();
history.replaceState(null, '', href);
smoothTo(href);
});
}
function scrollspy() {
var links = document.querySelectorAll('.' + NAV_CLASS + ' a[href^="#"]');
if (!links.length) return;
var map = [];
links.forEach(function (a) {
var id = a.getAttribute('href').slice(1);
var el = document.getElementById(id);
if (el) map.push({ el: el, a: a, li: a.parentElement });
});
function update() {
var y = window.scrollY + 110;
var current = null;
for (var i = 0; i < map.length; i++) {
if (map[i].el.offsetTop <= y) current = map[i];
}
map.forEach(function (m) {
if (m.li) m.li.classList.toggle('active', m === current);
});
}
window.addEventListener('scroll', update, { passive: true });
update();
}
function autoHash() {
if (window.location.hash) {
setTimeout(function () {
smoothTo(window.location.hash);
}, 40);
}
}
function init() {
if (document.querySelector('.posts-nav-box .toc-list, .posts-nav-box.toc-widget .toc-list')) {
return;
}
var headings = navContainer.querySelectorAll(HEADING_SEL);
if (headings.length < MIN_HEADINGS) return;
var tocContainer = document.querySelector('.posts-nav-lists, .aksrt-section-nav');
if (!tocContainer) {
// Docs / page-navs only: create a dedicated container. Never inject into single sidebars.
if (document.body.classList.contains('single') || document.body.classList.contains('single-post')) {
return;
}
tocContainer = document.createElement('nav');
tocContainer.className = 'aksrt-section-nav';
tocContainer.setAttribute('aria-label', '文章目录');
var sidebar = document.querySelector('.content-layout__aside, .sidebar, .widget-area');
if (sidebar) {
sidebar.insertBefore(tocContainer, sidebar.firstChild);
} else if (navContainer.parentNode) {
navContainer.parentNode.insertBefore(tocContainer, navContainer);
} else {
return;
}
var root = document.querySelector('[data-nav], .article-content, .entry-content, main.article');
if (!root) return;
var listsHtml = buildLists(root);
if (!listsHtml) return;
if (!document.querySelector(NAVBOX) && !document.querySelector('.' + NAV_CLASS)) {
return;
}
fillBoxes(listsHtml);
bindClicks();
scrollspy();
autoHash();
}
var list = document.createElement('ul');
list.className = 'aksrt-section-nav__list';
var items = [];
headings.forEach(function (heading, i) {
if (!heading.id) {
heading.id = 'section-nav-' + i;
}
var level = parseInt(heading.tagName.charAt(1), 10);
var li = document.createElement('li');
li.className = 'aksrt-section-nav__item aksrt-section-nav__item--h' + level;
var link = document.createElement('a');
link.href = '#' + heading.id;
link.textContent = heading.textContent.trim();
link.className = 'aksrt-section-nav__link';
link.addEventListener('click', function (e) {
e.preventDefault();
smoothScrollTo(heading);
// Expand collapsed panels containing the target
var panel = heading.closest('[data-collapse], .collapse');
if (panel) {
panel.classList.add('show', 'is-open');
var readMore = panel.previousElementSibling;
if (readMore && readMore.classList.contains('read-more-open')) readMore.click();
}
});
li.appendChild(link);
list.appendChild(li);
items.push({ el: heading, link: link, li: li, level: level });
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-section-navs', function () {
init();
});
tocContainer.innerHTML = '';
tocContainer.appendChild(list);
// Collapse sub-items if TOC is tall
if (tocContainer.scrollHeight > MAX_HEIGHT_COLLAPSE) {
collapseSubItems(list, items);
}
// Scrollspy
var ticking = false;
function onScroll() {
if (ticking) return;
ticking = true;
requestAnimationFrame(function () {
ticking = false;
var scrollTop = window.pageYOffset + SCROLL_OFFSET;
var activeIdx = 0;
for (var i = items.length - 1; i >= 0; i--) {
if (items[i].el.offsetTop <= scrollTop) {
activeIdx = i;
break;
}
}
items.forEach(function (item, idx) {
item.link.classList.toggle('is-active', idx === activeIdx);
});
});
}
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
// URL hash auto-scroll
if (window.location.hash) {
var target = document.querySelector(window.location.hash);
if (target) setTimeout(function () { smoothScrollTo(target); }, 100);
}
}
function smoothScrollTo(el) {
if (window.aksrt && aksrt.scrollTopTo) {
aksrt.scrollTopTo(el);
} else {
var top = el.getBoundingClientRect().top + window.pageYOffset - SCROLL_OFFSET;
window.scrollTo({ top: Math.max(0, top), behavior: 'smooth' });
}
}
function collapseSubItems(list, items) {
var parentStack = [];
items.forEach(function (item) {
while (parentStack.length && parentStack[parentStack.length - 1].level >= item.level) {
parentStack.pop();
}
if (item.level >= 3 && parentStack.length) {
item.li.classList.add('yc');
// Add collapse toggle to parent if not already there
var parentLi = parentStack[parentStack.length - 1].li;
if (!parentLi.querySelector('.nav-toggle-collapse')) {
var toggle = document.createElement('span');
toggle.className = 'nav-toggle-collapse';
toggle.innerHTML = '<i class="fas fa-chevron-right"></i>';
toggle.addEventListener('click', function (e) {
e.stopPropagation();
toggle.classList.toggle('fa-rotate-90');
var next = parentLi.nextElementSibling;
while (next && next.classList.contains('yc')) {
next.classList.toggle('yc-open');
next = next.nextElementSibling;
}
});
parentLi.appendChild(toggle);
}
}
parentStack.push(item);
});
}
if (window.AksrtFrontend) {
AksrtFrontend.register('aksrt-section-navs', function () { initSectionNavs(); });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSectionNavs);
} else if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
initSectionNavs();
init();
}
})();
+53
View File
@@ -147,3 +147,56 @@ function aksrt_render_language_switcher(string $style = 'dropdown'): string {
return $html;
}
/**
* Header language dropdown (zibll zib_get_translate_language_btn).
* Uses SPA i18n_available_langs when i18n enabled and position includes header.
*
* @param string $class Extra classes.
*/
function aksrt_get_translate_language_btn(string $class = ''): string {
if (!class_exists('\AKSRT\Settings\Settings')) {
return '';
}
$cfg = \AKSRT\Settings\Settings::get_i18n_config();
if (empty($cfg['enabled'])) {
return '';
}
$pos = (string) ($cfg['switcherPosition'] ?? 'footer');
if (!in_array($pos, ['header', 'both'], true)) {
return '';
}
$raw = (string) ($cfg['availableLangs'] ?? '');
$buttons = [];
foreach (preg_split('/
|␍|
/', $raw) as $line) {
$line = trim($line);
if ($line === '' || strpos($line, '|') === false) {
continue;
}
[$code, $label] = array_map('trim', explode('|', $line, 2));
if ($code === '' || $label === '') {
continue;
}
$buttons[] = ['language' => $code, 'text' => $label];
}
if (!$buttons) {
return '';
}
$buttons_html = '';
foreach ($buttons as $button) {
$buttons_html .= '<li><a href="javascript:;" class="translate-button translate-ignore flex ac" data-language="'
. esc_attr($button['language']) . '">' . esc_html($button['text']) . '</a></li>';
}
$is_mobile = wp_is_mobile();
$dropdown = '<ul class="dropdown-menu hover-show-con">' . $buttons_html . '</ul>';
$hover = !$is_mobile ? ' hover-show' : '';
$toggle = !$is_mobile ? '' : ' data-toggle="dropdown"';
return '<div class="dropdown language-dropdown ' . esc_attr($class) . $hover . '">'
. '<a href="javascript:;" class="toggle-radius"' . $toggle . ' title="' . esc_attr__('切换语言', 'aksrt') . '">'
. '<i class="fas fa-language" aria-hidden="true"></i></a>' . $dropdown . '</div>';
}
@@ -80,6 +80,9 @@ if (!function_exists('aksrt_nav_mobile_content')) :
$top_btns .= '<a href="javascript:;" class="toggle-radius main-search-btn" data-toggle-class data-target=".navbar-search" aria-label="'
. esc_attr__('打开搜索', 'aksrt') . '"><i class="fas fa-search" aria-hidden="true"></i></a>';
}
if (function_exists('aksrt_get_translate_language_btn')) {
$top_btns .= aksrt_get_translate_language_btn('pull-right');
}
if ($top_btns !== '') {
echo '<div class="flex ac pull-right" style="margin-right: -3px;">' . $top_btns . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
@@ -116,6 +119,10 @@ if (!function_exists('aksrt_nav_mobile_content')) :
}
echo $menu; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
if (is_singular('post')) {
echo '<div class="posts-nav-box" data-title="' . esc_attr__('文章目录', 'aksrt') . '"></div>';
}
// User box at bottom of drawer.
if (!empty($ctx['user_menu'])) {
echo aksrt_header_user_box_html($ctx); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+34 -5
View File
@@ -104,6 +104,7 @@ if (!function_exists('aksrt_get_menu_search')) :
$type = (string) ($state['type'] ?? 'post');
$cat_enabled = !empty($state['category_enabled']);
$cat_id = (int) ($state['category_id'] ?? 0);
$hots = is_array($ctx['search_hot_keywords'] ?? null) ? $ctx['search_hot_keywords'] : [];
echo '<form method="get" class="navbar-form navbar-left hover-show" action="' . esc_url(home_url('/')) . '" role="search" data-aksrt-search-form="inline">';
echo '<div class="form-group relative dropdown">';
@@ -112,9 +113,22 @@ if (!function_exists('aksrt_get_menu_search')) :
echo '<input type="hidden" name="aksrt_category" value="' . esc_attr((string) $cat_id) . '">';
}
echo '<input type="text" class="form-control search-input focus-show" name="s" value="'
. esc_attr(get_search_query()) . '" placeholder="' . esc_attr($placeholder) . '">';
. esc_attr(get_search_query()) . '" placeholder="' . esc_attr($placeholder) . '" autocomplete="off">';
echo '<div class="abs-right muted-3-color"><button type="submit" class="null" aria-label="'
. esc_attr__('搜索', 'aksrt') . '"><i class="fas fa-search" aria-hidden="true"></i></button></div>';
if ($hots) {
echo '<div class="dropdown-menu hover-show-con navbar-inline-search-panel">';
echo '<div class="muted-2-color em09 mb6">' . esc_html__('热门搜索', 'aksrt') . '</div>';
echo '<div class="navbar-inline-search-hots">';
foreach ($hots as $kw) {
$kw = trim((string) $kw);
if ($kw === '') {
continue;
}
echo '<a class="but jb-sm" href="' . esc_url(home_url('/?s=' . rawurlencode($kw))) . '">' . esc_html($kw) . '</a> ';
}
echo '</div></div>';
}
echo '</div></form>';
}
endif;
@@ -179,13 +193,25 @@ if (!function_exists('aksrt_header_user_box_html')) :
}
if (!empty($ctx['can_publish'])) {
$pub_text = class_exists('\AKSRT\Settings\Settings')
? (string) (\AKSRT\Settings\Settings::get_all()['header_user_newposts_text'] ?? '')
: '';
$all = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_all() : [];
$pub_text = (string) ($all['header_user_newposts_text'] ?? '');
if ($pub_text === '') {
$pub_text = __('发布内容', 'aksrt');
}
$href .= '<a rel="nofollow" href="' . esc_url((string) $ctx['publish_url']) . '">';
$pub_type = sanitize_key((string) ($all['header_user_newposts_btn'] ?? 'post'));
$pub_url = (string) $ctx['publish_url'];
if ($pub_type === 'topic' && function_exists('aksrt_get_forum_compose_url')) {
$u = aksrt_get_forum_compose_url();
if ($u) { $pub_url = $u; }
} elseif ($pub_type === 'product') {
if (function_exists('aksrt_get_product_edit_url')) {
$u = (string) aksrt_get_product_edit_url();
if ($u !== '') { $pub_url = $u; }
} else {
$pub_url = admin_url('post-new.php?post_type=aksrt_product');
}
}
$href .= '<a rel="nofollow" href="' . esc_url($pub_url) . '">';
$href .= '<div class="badg mb6 toggle-radius c-green"><i class="fas fa-pen" aria-hidden="true"></i></div>';
$href .= '<div class="c-green">' . esc_html($pub_text) . '</div></a>';
}
@@ -284,6 +310,9 @@ if (!function_exists('aksrt_menu_button')) :
$radius_but .= '<i class="fas fa-sun theme-icon-sun" aria-hidden="true" style="display:none"></i>';
$radius_but .= '</a>';
}
if (function_exists('aksrt_get_translate_language_btn')) {
$radius_but .= aksrt_get_translate_language_btn('ml10 pull-right');
}
if ($radius_but !== '') {
$button .= '<div class="navbar-form navbar-right flex ac">' . $radius_but . '</div>';
}
+1
View File
@@ -132,6 +132,7 @@ class Admin {
'siteUrl' => home_url('/'),
'adminUrl' => admin_url('/'),
'themeVersion' => wp_get_theme()->get('Version') ?: '3.4.0-dev',
'themeUri' => defined('AKSRT_URI') ? AKSRT_URI : get_template_directory_uri(),
'buildOk' => $missing_chunks === [],
]);
+170 -13
View File
@@ -1,6 +1,6 @@
<?php
/**
* Native WP nav-menu item options (aksrt_menu_options).
* Native WP nav-menu item options (aksrt_menu_options) with senior submenu JSON.
*
* @package AKSRT
*/
@@ -14,6 +14,24 @@ class NavMenuOptions {
public static function init(): void {
add_action('wp_nav_menu_item_custom_fields', [self::class, 'render_fields'], 10, 2);
add_action('wp_update_nav_menu_item', [self::class, 'save'], 10, 2);
add_action('admin_enqueue_scripts', [self::class, 'enqueue_admin']);
}
public static function enqueue_admin(string $hook): void {
if ($hook !== 'nav-menus.php') {
return;
}
$path = get_template_directory() . '/assets/js/admin-nav-menu-senior.js';
if (!file_exists($path)) {
return;
}
wp_enqueue_script(
'aksrt-admin-nav-menu-senior',
get_template_directory_uri() . '/assets/js/admin-nav-menu-senior.js',
['jquery'],
(string) filemtime($path),
true
);
}
/**
@@ -29,6 +47,12 @@ class NavMenuOptions {
$badge_class = (string) ($opts['badge_class'] ?? '');
$submenu_s = !empty($opts['submenu_s']);
$submenu_type = (string) ($opts['submenu_type'] ?? '');
$graphic_json = !empty($opts['graphic_card_opts'])
? wp_json_encode($opts['graphic_card_opts'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
: self::sample_graphic_json();
$multi_json = !empty($opts['multi_column_links_opts'])
? wp_json_encode($opts['multi_column_links_opts'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
: self::sample_multi_json();
?>
<p class="field-aksrt-icon description description-wide">
<label for="edit-menu-item-aksrt-icon-<?php echo esc_attr((string) $item_id); ?>">
@@ -57,7 +81,7 @@ class NavMenuOptions {
<p class="field-aksrt-submenu description description-wide">
<label>
<input type="checkbox" name="aksrt_menu_options[<?php echo esc_attr((string) $item_id); ?>][submenu_s]" value="1" <?php checked($submenu_s); ?>>
<?php esc_html_e('启用高级子菜单(一级菜单)', 'aksrt'); ?>
<?php esc_html_e('启用高级子菜单(仅一级菜单)', 'aksrt'); ?>
</label>
</p>
<p class="field-aksrt-submenu-type description description-wide">
@@ -71,8 +95,19 @@ class NavMenuOptions {
</select>
</label>
</p>
<p class="description description-wide">
<?php esc_html_e('高级子菜单内容(graphic_card_opts / multi_column_links_opts)可在后续可视化编辑;也可通过 meta 写入 JSON。', 'aksrt'); ?>
<p class="field-aksrt-graphic description description-wide">
<label for="edit-menu-item-aksrt-graphic-<?php echo esc_attr((string) $item_id); ?>">
<?php esc_html_e('图文卡片 JSON(type=graphic_card)', 'aksrt'); ?><br>
<textarea rows="8" class="widefat code" id="edit-menu-item-aksrt-graphic-<?php echo esc_attr((string) $item_id); ?>"
name="aksrt_menu_options[<?php echo esc_attr((string) $item_id); ?>][graphic_card_opts_json]"><?php echo esc_textarea((string) $graphic_json); ?></textarea>
</label>
</p>
<p class="field-aksrt-multi description description-wide">
<label for="edit-menu-item-aksrt-multi-<?php echo esc_attr((string) $item_id); ?>">
<?php esc_html_e('多列链接 JSON(type=multi_column_links)', 'aksrt'); ?><br>
<textarea rows="8" class="widefat code" id="edit-menu-item-aksrt-multi-<?php echo esc_attr((string) $item_id); ?>"
name="aksrt_menu_options[<?php echo esc_attr((string) $item_id); ?>][multi_column_links_opts_json]"><?php echo esc_textarea((string) $multi_json); ?></textarea>
</label>
</p>
<?php
}
@@ -83,15 +118,12 @@ class NavMenuOptions {
*/
public static function save($menu_id, $menu_item_db_id): void {
$menu_item_db_id = (int) $menu_item_db_id;
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- WP core nav-menu form nonce.
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if (empty($_POST['aksrt_menu_options'][ $menu_item_db_id ]) || !is_array($_POST['aksrt_menu_options'][ $menu_item_db_id ])) {
// If fields absent, leave existing meta (WP may not resubmit all fields in bulk edits).
return;
}
// phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$raw = wp_unslash($_POST['aksrt_menu_options'][ $menu_item_db_id ]);
$existing = get_post_meta($menu_item_db_id, 'aksrt_menu_options', true);
$existing = is_array($existing) ? $existing : [];
$clean = [
'icon' => sanitize_text_field((string) ($raw['icon'] ?? '')),
@@ -100,13 +132,138 @@ class NavMenuOptions {
'submenu_s' => !empty($raw['submenu_s']),
'submenu_type' => sanitize_key((string) ($raw['submenu_type'] ?? '')),
];
// Preserve complex opts not edited by this form.
if (!empty($existing['graphic_card_opts'])) {
$clean['graphic_card_opts'] = $existing['graphic_card_opts'];
$graphic = self::decode_json_field((string) ($raw['graphic_card_opts_json'] ?? ''));
if (is_array($graphic)) {
$clean['graphic_card_opts'] = self::sanitize_graphic_opts($graphic);
}
if (!empty($existing['multi_column_links_opts'])) {
$clean['multi_column_links_opts'] = $existing['multi_column_links_opts'];
$multi = self::decode_json_field((string) ($raw['multi_column_links_opts_json'] ?? ''));
if (is_array($multi)) {
$clean['multi_column_links_opts'] = self::sanitize_multi_opts($multi);
}
update_post_meta($menu_item_db_id, 'aksrt_menu_options', $clean);
}
/**
* @return array<string,mixed>|null
*/
private static function decode_json_field(string $json): ?array {
$json = trim($json);
if ($json === '') {
return null;
}
$data = json_decode($json, true);
return is_array($data) ? $data : null;
}
/**
* @param array<string,mixed> $opts
* @return array<string,mixed>
*/
private static function sanitize_graphic_opts(array $opts): array {
$items_in = is_array($opts['items'] ?? null) ? $opts['items'] : [];
$items = [];
foreach ($items_in as $item) {
if (!is_array($item)) {
continue;
}
$items[] = [
'img' => esc_url_raw((string) ($item['img'] ?? '')),
'title' => sanitize_text_field((string) ($item['title'] ?? '')),
'badge' => sanitize_text_field((string) ($item['badge'] ?? '')),
'badge_class' => sanitize_html_class((string) ($item['badge_class'] ?? '')),
'link' => [
'url' => esc_url_raw((string) ($item['link']['url'] ?? '')),
'text' => sanitize_text_field((string) ($item['link']['text'] ?? '')),
'target' => sanitize_text_field((string) ($item['link']['target'] ?? '')),
],
];
}
return [
'arrangement' => sanitize_key((string) ($opts['arrangement'] ?? '')),
'align' => sanitize_key((string) ($opts['align'] ?? '')),
'size' => sanitize_key((string) ($opts['size'] ?? '')),
'img_scale' => max(0, min(200, (int) ($opts['img_scale'] ?? 100))),
'items' => $items,
];
}
/**
* @param array<string,mixed> $opts
* @return array<string,mixed>
*/
private static function sanitize_multi_opts(array $opts): array {
$columns_in = is_array($opts['columns'] ?? null) ? $opts['columns'] : [];
$columns = [];
foreach ($columns_in as $col) {
if (!is_array($col)) {
continue;
}
$items = [];
if (!empty($col['items']) && is_array($col['items'])) {
foreach ($col['items'] as $item) {
if (!is_array($item)) {
continue;
}
$items[] = [
'title' => sanitize_text_field((string) ($item['title'] ?? '')),
'icon' => sanitize_text_field((string) ($item['icon'] ?? '')),
'img_icon' => esc_url_raw((string) ($item['img_icon'] ?? '')),
'link' => [
'url' => esc_url_raw((string) ($item['link']['url'] ?? '')),
'text' => sanitize_text_field((string) ($item['link']['text'] ?? '')),
'target' => sanitize_text_field((string) ($item['link']['target'] ?? '')),
],
];
}
}
$columns[] = [
'title' => sanitize_text_field((string) ($col['title'] ?? '')),
'icon' => sanitize_text_field((string) ($col['icon'] ?? '')),
'img_icon' => esc_url_raw((string) ($col['img_icon'] ?? '')),
'link' => [
'url' => esc_url_raw((string) ($col['link']['url'] ?? '')),
'text' => sanitize_text_field((string) ($col['link']['text'] ?? '')),
'target' => sanitize_text_field((string) ($col['link']['target'] ?? '')),
],
'items' => $items,
];
}
return ['columns' => $columns];
}
private static function sample_graphic_json(): string {
$sample = [
'arrangement' => '',
'size' => 'md',
'img_scale' => 100,
'items' => [
[
'img' => '',
'title' => '卡片标题',
'badge' => '',
'badge_class' => 'jb-red',
'link' => ['url' => home_url('/'), 'text' => '', 'target' => ''],
],
],
];
return (string) wp_json_encode($sample, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
private static function sample_multi_json(): string {
$sample = [
'columns' => [
[
'title' => '栏目一',
'icon' => 'fas fa-folder',
'link' => ['url' => '', 'text' => '', 'target' => ''],
'items' => [
['title' => '链接 A', 'icon' => '', 'link' => ['url' => home_url('/'), 'text' => '', 'target' => '']],
],
],
],
];
return (string) wp_json_encode($sample, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
}
+27 -9
View File
@@ -31,15 +31,8 @@ class SchemaPageDisplay {
['key' => 'header_scroll_down_hide', 'label' => '下滑隐藏导航栏', 'type' => 'switch', 'default' => true],
]],
['key' => 'layout-type', 'title' => '布局类型', 'fields' => [
['key' => 'header_layout', 'label' => '桌面端布局', 'type' => 'radio', 'default' => '1', 'options' => [
['label' => '布局 1(经典)', 'value' => '1'],
['label' => '布局 2(内联搜索)', 'value' => '2'],
['label' => '布局 3(紧凑)', 'value' => '3'],
]],
['key' => 'mobile_header_layout', 'label' => '移动端布局', 'type' => 'radio', 'default' => 'center', 'options' => [
['label' => '居中(含搜索按钮)', 'value' => 'center'],
['label' => '靠左', 'value' => 'left'],
]],
['key' => 'header_layout', 'label' => '桌面端布局', 'type' => 'image_select', 'default' => '1', 'options' => self::header_layout_options()],
['key' => 'mobile_header_layout', 'label' => '移动端布局', 'type' => 'image_select', 'default' => 'center', 'options' => self::mobile_header_layout_options()],
['key' => 'mobile_navbar_align', 'label' => '移动端菜单方向', 'type' => 'radio', 'default' => 'left', 'options' => [
['label' => '顶部(关闭手势)', 'value' => 'top'],
['label' => '左侧滑出', 'value' => 'left'],
@@ -64,6 +57,11 @@ class SchemaPageDisplay {
['label' => '帖子', 'value' => 'topic'],
['label' => '商品', 'value' => 'product'],
]],
['key' => 'header_user_newposts_btn', 'label' => '用户卡发布类型', 'type' => 'select', 'default' => 'post', 'options' => [
['label' => '文章', 'value' => 'post'],
['label' => '帖子', 'value' => 'topic'],
['label' => '商品', 'value' => 'product'],
]],
['key' => 'header_user_newposts_text', 'label' => '用户卡发布文案', 'type' => 'input', 'default' => '发布内容'],
]],
['key' => 'color', 'title' => '颜色设置', 'fields' => [
@@ -527,4 +525,24 @@ class SchemaPageDisplay {
],
];
}
/** @return list<array{label:string,value:string,image:string}> */
private static function header_layout_options(): array {
$base = defined('AKSRT_URI') ? trailingslashit(AKSRT_URI) . 'assets/images/header-layout/' : '';
return [
['label' => '布局 1(经典)', 'value' => '1', 'image' => $base . 'header_layout_1.png'],
['label' => '布局 2(内联搜索)', 'value' => '2', 'image' => $base . 'header_layout_2.png'],
['label' => '布局 3(紧凑)', 'value' => '3', 'image' => $base . 'header_layout_3.png'],
];
}
/** @return list<array{label:string,value:string,image:string}> */
private static function mobile_header_layout_options(): array {
$base = defined('AKSRT_URI') ? trailingslashit(AKSRT_URI) . 'assets/images/header-layout/' : '';
return [
['label' => '居中(含搜索按钮)', 'value' => 'center', 'image' => $base . 'mobile_header_layout_center.png'],
['label' => '靠左', 'value' => 'left', 'image' => $base . 'mobile_header_layout_left.png'],
];
}
}
+24 -1
View File
@@ -161,7 +161,19 @@ trait ScriptsPart1b {
);
}
$hmb_js = get_template_directory() . '/assets/js/header-newadd.js';
$inline_search_js = get_template_directory() . '/assets/js/header-inline-search.js';
if (file_exists($inline_search_js)) {
wp_enqueue_script(
'aksrt-header-inline-search',
$base_uri . '/assets/js/header-inline-search.js',
[],
(string) filemtime($inline_search_js),
true
);
}
$hmb_js = get_template_directory() . '/assets/js/header-newadd.js';
if (file_exists($hmb_js)) {
wp_enqueue_script(
'aksrt-header-newadd',
@@ -475,6 +487,17 @@ trait ScriptsPart1b {
// 文章导航页(zibll postsnavs.php)
if (is_page_template('templates/pages/page-posts-navs.php')) {
$page_navs_js = get_template_directory() . '/assets/js/page-navs.js';
if (file_exists($page_navs_js)) {
wp_enqueue_script(
'aksrt-page-navs',
$base_uri . '/assets/js/page-navs.js',
[],
(string) filemtime($page_navs_js),
true
);
}
$pn_css = get_template_directory() . '/assets/css/routes/posts-navs.css';
if (file_exists($pn_css)) {
wp_enqueue_style(
+21 -1
View File
@@ -105,8 +105,28 @@ class InlineStyleBuilder {
echo '--focus-color:' . esc_attr($dark_primary) . ';';
}
echo '}</style>' . "\n";
// Zibll header_theme_custom → --header-bg / --header-color on .header.
if (class_exists('\AKSRT\Settings\Settings')) {
$ht = \AKSRT\Settings\Settings::get_header_theme_config();
if (!empty($ht['custom'])) {
$h_bg = $ht['bg_custom'] !== '' ? $ht['bg_custom'] : ($ht['bg'] ?? '');
$h_fg = $ht['color_custom'] ?? '';
if ($h_bg !== '' || $h_fg !== '') {
echo '<style id="aksrt-header-theme">.header{';
if ($h_bg !== '') {
echo '--header-bg:' . esc_attr($h_bg) . ';background:' . esc_attr($h_bg) . ';';
}
if ($h_fg !== '') {
echo '--header-color:' . esc_attr($h_fg) . ';color:' . esc_attr($h_fg) . ';';
}
echo '}</style>' . "\n";
}
}
}
if (class_exists('\AKSRT\Settings\Settings') && !empty(\AKSRT\Settings\Settings::get_value('close_backdrop', false))) {
echo '<style id="aksrt-no-backdrop">.aksrt-header,.header-inner,.site-header,.mobile-nav-overlay,.modal-backdrop,.aksrt-drawer-overlay,.aksrt-float-btn,.sidebar-inner{backdrop-filter:none!important;-webkit-backdrop-filter:none!important;background-color:var(--bg-card,#fff)!important}</style>' . "\n";
echo '<style id="aksrt-no-backdrop">.aksrt-header,.header-inner,.site-header,.header,.mobile-nav-overlay,.modal-backdrop,.aksrt-drawer-overlay,.aksrt-float-btn,.sidebar-inner{backdrop-filter:none!important;-webkit-backdrop-filter:none!important;background-color:var(--bg-card,#fff)!important}</style>' . "\n";
}
echo '<style id="aksrt-runtime-components">'
. '.aksrt-search-hot-keywords{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:12px;font-family:var(--font-ui);}'
+35
View File
@@ -0,0 +1,35 @@
# Top nav zibll 1:1 acceptance checklist
Branch: `worktree-nav-zibll-1to1`
## Desktop
- [ ] Layout 1: logo | menu | publish/VIP | theme(+lang) | user | search icon
- [ ] Layout 2: logo | menu | inline search(+hot/suggest) | CTAs | user (no search icon)
- [ ] Layout 3: logo | CTAs/user | menu right cluster
- [ ] Fixed `body.nav-fixed` 88px reserve; hero show-slide pull-up
- [ ] Scroll-down hide / scroll-up show
- [ ] Submenu hover + chevron; overflow folding "更多"
- [ ] Publish single vs multi; VIP hover cards gated by switches
- [ ] User box density + user-card publish type URL
- [ ] Header theme colors when custom enabled
- [ ] Language dropdown when i18n enabled + position header/both
## Mobile
- [ ] center/left header; drawer left/right/top
- [ ] `body.mobile-navbar-show` open/close + fixed-body + swipe
- [ ] mobile menus depth 2 + user box + widgets
- [ ] posts-nav-box TOC on single posts
## Admin
- [ ] SPA image_select previews for layouts
- [ ] newposts types multi + VIP switches persist
- [ ] Appearance → Menus: icon/badge/senior visual editor saves meta
- [ ] `cd assets/admin && npm run build` after schema changes
## Page/section navs
- [ ] section-navs builds `.posts-nav-lists` on `[data-nav]` pages
- [ ] page-navs enqueued on posts-navs template
## Deploy notes
- Admin `build/` is gitignored — run build on deploy host.
- PR: open from branch `worktree-nav-zibll-1to1` against main on Gitea.
+1
View File
@@ -0,0 +1 @@
PASS all nav zibll source contracts