feat(nav): deep-align menu_search panel, pill radius, senior media
- Layout-2 remote-box AJAX panel (history/hot/posts) via aksrt_menu_search - Live suggestions for post/topic/product; local history for guests - Publish radius switch (zibll bool pill) mapped to CSS radius class - Senior menu editor: WP media library image picker - Active menu underline + panel CSS; acceptance/contract updates
This commit is contained in:
@@ -51,7 +51,7 @@ export const pageDisplaySchemas = {
|
|||||||
mobile_navbar_align: 'left',
|
mobile_navbar_align: 'left',
|
||||||
header_newposts_enabled: true,
|
header_newposts_enabled: true,
|
||||||
header_newposts_text: '<i class="fa fa-pencil"></i> 发布',
|
header_newposts_text: '<i class="fa fa-pencil"></i> 发布',
|
||||||
header_newposts_radius: 20,
|
header_newposts_radius: true,
|
||||||
header_newposts_class: '',
|
header_newposts_class: '',
|
||||||
header_theme_custom: false,
|
header_theme_custom: false,
|
||||||
header_theme_bg_custom: '',
|
header_theme_bg_custom: '',
|
||||||
@@ -126,7 +126,7 @@ export const pageDisplaySchemas = {
|
|||||||
fields: [
|
fields: [
|
||||||
{ key: 'header_newposts_enabled', label: '启用发布按钮', type: 'switch', default: true, help: '导航栏显示前台发布入口' },
|
{ key: 'header_newposts_enabled', label: '启用发布按钮', type: 'switch', default: true, help: '导航栏显示前台发布入口' },
|
||||||
{ key: 'header_newposts_text', label: '按钮文案', type: 'input', default: '<i class="fa fa-pencil"></i> 发布', dependsOn: { key: 'header_newposts_enabled', value: true } },
|
{ key: 'header_newposts_text', label: '按钮文案', type: 'input', default: '<i class="fa fa-pencil"></i> 发布', dependsOn: { key: 'header_newposts_enabled', value: true } },
|
||||||
{ key: 'header_newposts_radius', label: '圆角 (px)', type: 'number', default: 20, min: 0, max: 30, dependsOn: { key: 'header_newposts_enabled', value: true } },
|
{ key: 'header_newposts_radius', label: '按钮圆角(胶囊)', type: 'switch', default: true, dependsOn: { key: 'header_newposts_enabled', value: true }, help: '开启后两端大圆角,对齐 zibll nav_newposts_radius' },
|
||||||
{ key: 'header_newposts_class', label: '自定义 CSS 类', type: 'input', default: '', dependsOn: { key: 'header_newposts_enabled', value: true } },
|
{ key: 'header_newposts_class', label: '自定义 CSS 类', type: 'input', default: '', dependsOn: { key: 'header_newposts_enabled', value: true } },
|
||||||
{ key: 'header_newposts_types', label: '发布类型', type: 'select', multiple: true, default: ['post'], options: [
|
{ key: 'header_newposts_types', label: '发布类型', type: 'select', multiple: true, default: ['post'], options: [
|
||||||
{ label: '文章', value: 'post' },
|
{ label: '文章', value: 'post' },
|
||||||
|
|||||||
@@ -162,3 +162,61 @@ body.mobile-navbar-show { overflow: hidden; }
|
|||||||
.aksrt-sme-field { display: block; margin: 4px 0; }
|
.aksrt-sme-field { display: block; margin: 4px 0; }
|
||||||
.aksrt-sme-field span { display: block; font-size: 12px; color: #646970; }
|
.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; }
|
.aksrt-sme-card, .aksrt-sme-col { border: 1px solid #dcdcde; padding: 8px; margin: 8px 0; border-radius: 4px; }
|
||||||
|
|
||||||
|
/* Layout-2 remote menu search panel (zibll menu_search) */
|
||||||
|
.aksrt-remote-box[data-aksrt-menu-search-remote] {
|
||||||
|
min-height: 8px;
|
||||||
|
}
|
||||||
|
.navbar-inline-search-panel {
|
||||||
|
min-width: 300px;
|
||||||
|
max-width: 380px;
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.aksrt-menu-search-posts__item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
padding: 6px 2px;
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid rgba(0,0,0,.04);
|
||||||
|
}
|
||||||
|
.aksrt-menu-search-posts__item:last-child { border-bottom: 0; }
|
||||||
|
.aksrt-menu-search-posts__item:hover { color: var(--focus-color); }
|
||||||
|
.aksrt-menu-search-history__list .but,
|
||||||
|
.navbar-inline-search-hots .but { margin: 0 4px 4px 0; }
|
||||||
|
.loading-spot {
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
margin: 8px;
|
||||||
|
border: 2px solid rgba(0,0,0,.15);
|
||||||
|
border-top-color: var(--focus-color, #f04494);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: aksrt-spin .7s linear infinite;
|
||||||
|
}
|
||||||
|
@keyframes aksrt-spin { to { transform: rotate(360deg); } }
|
||||||
|
.navbar-but .radius,
|
||||||
|
.navbar-but .but.radius,
|
||||||
|
.navbar-cta.radius {
|
||||||
|
border-radius: 999px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Active menu underline (zibll-like) */
|
||||||
|
.navbar-top .nav > li.current-menu-item > a,
|
||||||
|
.navbar-top .nav > li.current-menu-ancestor > a {
|
||||||
|
color: var(--focus-color);
|
||||||
|
}
|
||||||
|
.navbar-top .nav > li.current-menu-item > a::before,
|
||||||
|
.navbar-top .nav > li.current-menu-ancestor > a::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
right: 10px;
|
||||||
|
top: 0;
|
||||||
|
height: 3px;
|
||||||
|
border-radius: 0 0 3px 3px;
|
||||||
|
background: var(--focus-color);
|
||||||
|
}
|
||||||
|
.navbar-top .nav > li > a { position: relative; }
|
||||||
|
|||||||
@@ -39,11 +39,15 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function field(name, label, value, type) {
|
function field(name, label, value, type, withMedia) {
|
||||||
type = type || 'text';
|
type = type || 'text';
|
||||||
|
var mediaBtn = withMedia
|
||||||
|
? ' <button type="button" class="button aksrt-sme-pick-img" data-for="' + name + '">选择图片</button>'
|
||||||
|
: '';
|
||||||
return (
|
return (
|
||||||
'<label class="aksrt-sme-field"><span>' +
|
'<label class="aksrt-sme-field"><span>' +
|
||||||
label +
|
label +
|
||||||
|
mediaBtn +
|
||||||
'</span><input type="' +
|
'</span><input type="' +
|
||||||
type +
|
type +
|
||||||
'" data-name="' +
|
'" data-name="' +
|
||||||
@@ -62,7 +66,7 @@
|
|||||||
html += '<div class="aksrt-sme-card" data-index="' + i + '">';
|
html += '<div class="aksrt-sme-card" data-index="' + i + '">';
|
||||||
html += '<div class="aksrt-sme-card-head"><strong>卡片 #' + (i + 1) + '</strong>';
|
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 += ' <button type="button" class="button-link-delete aksrt-sme-del-card">删除</button></div>';
|
||||||
html += field('img', '图片 URL', item.img || '');
|
html += field('img', '图片 URL', item.img || '', 'text', true);
|
||||||
html += field('title', '标题', item.title || '');
|
html += field('title', '标题', item.title || '');
|
||||||
html += field('badge', '徽章', item.badge || '');
|
html += field('badge', '徽章', item.badge || '');
|
||||||
html += field('badge_class', '徽章 class', item.badge_class || '');
|
html += field('badge_class', '徽章 class', item.badge_class || '');
|
||||||
@@ -236,6 +240,24 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$(document).on('click', '.aksrt-sme-pick-img', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var $btn = $(this);
|
||||||
|
var name = $btn.data('for');
|
||||||
|
var $input = $btn.closest('.aksrt-sme-field').find('input[data-name="' + name + '"]');
|
||||||
|
if (typeof wp === 'undefined' || !wp.media) {
|
||||||
|
window.alert('媒体库不可用');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var frame = wp.media({ title: '选择图片', button: { text: '使用此图' }, multiple: false, library: { type: 'image' } });
|
||||||
|
frame.on('select', function () {
|
||||||
|
var att = frame.state().get('selection').first().toJSON();
|
||||||
|
if (att && att.url) $input.val(att.url).trigger('change');
|
||||||
|
});
|
||||||
|
frame.open();
|
||||||
|
});
|
||||||
|
|
||||||
$(boot);
|
$(boot);
|
||||||
$(document).on('menu-item-added', function () {
|
$(document).on('menu-item-added', function () {
|
||||||
setTimeout(boot, 50);
|
setTimeout(boot, 50);
|
||||||
|
|||||||
@@ -1,112 +1,166 @@
|
|||||||
/**
|
/**
|
||||||
* Enhance layout-2 inline search with AJAX suggestions (aksrt_search_suggestions).
|
* Layout-2 navbar search — zibll remote-box + live suggestions.
|
||||||
* Extends existing panel search without dual systems.
|
* Loads aksrt_menu_search panel (history/hot/posts), then suggests on input.
|
||||||
*/
|
*/
|
||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function initInlineSearchSuggest() {
|
var HISTORY_KEY = "aksrt-mobile-search-history";
|
||||||
var form = document.querySelector('form[data-aksrt-search-form="inline"]');
|
|
||||||
if (!form || !window.aksrtData || !aksrtData.ajaxUrl) return;
|
|
||||||
|
|
||||||
|
function ajaxUrl() {
|
||||||
|
return (window.aksrtData && aksrtData.ajaxUrl) || "";
|
||||||
|
}
|
||||||
|
function nonce() {
|
||||||
|
return (window.aksrtData && aksrtData.nonce) || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function readLocalHistory() {
|
||||||
|
try {
|
||||||
|
var raw = localStorage.getItem(HISTORY_KEY);
|
||||||
|
var list = raw ? JSON.parse(raw) : [];
|
||||||
|
if (!Array.isArray(list)) return [];
|
||||||
|
return list
|
||||||
|
.map(function (it) {
|
||||||
|
if (typeof it === "string") return it;
|
||||||
|
return it && it.keyword ? String(it.keyword) : "";
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.slice(0, 10);
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeLocalHistory(keywords) {
|
||||||
|
try {
|
||||||
|
var items = (keywords || []).slice(0, 10).map(function (k) {
|
||||||
|
return { keyword: k, type: "post" };
|
||||||
|
});
|
||||||
|
localStorage.setItem(HISTORY_KEY, JSON.stringify(items));
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadRemote(box) {
|
||||||
|
if (!box || box.getAttribute("data-loaded") === "1") return;
|
||||||
|
var url = box.getAttribute("remote-box") || box.getAttribute("data-url");
|
||||||
|
if (!url) return;
|
||||||
|
box.setAttribute("data-loaded", "1");
|
||||||
|
var sep = url.indexOf("?") >= 0 ? "&" : "?";
|
||||||
|
if (nonce()) {
|
||||||
|
url = url + sep + "nonce=" + encodeURIComponent(nonce());
|
||||||
|
}
|
||||||
|
fetch(url, { credentials: "same-origin" })
|
||||||
|
.then(function (r) {
|
||||||
|
return r.text();
|
||||||
|
})
|
||||||
|
.then(function (html) {
|
||||||
|
if (!html || html === "0") {
|
||||||
|
box.innerHTML = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
box.outerHTML = html;
|
||||||
|
var form = document.querySelector('form[data-aksrt-search-form="inline"]');
|
||||||
|
if (form) enhancePanel(form);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
box.removeAttribute("data-loaded");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function enhancePanel(form) {
|
||||||
|
var group = form.querySelector(".form-group");
|
||||||
|
var panel = form.querySelector(".navbar-inline-search-panel");
|
||||||
var input = form.querySelector(".search-input");
|
var input = form.querySelector(".search-input");
|
||||||
var group = form.querySelector(".form-group.relative, .form-group");
|
if (!group || !input) return;
|
||||||
if (!input || !group) return;
|
|
||||||
|
|
||||||
var panel = group.querySelector(".navbar-inline-search-panel");
|
// Merge guest local history into panel list.
|
||||||
if (!panel) {
|
var histList = form.querySelector(".aksrt-menu-search-history__list");
|
||||||
panel = document.createElement("div");
|
if (histList && !(window.aksrtData && aksrtData.isLoggedIn)) {
|
||||||
panel.className = "dropdown-menu hover-show-con navbar-inline-search-panel";
|
var local = readLocalHistory();
|
||||||
group.appendChild(panel);
|
if (local.length) {
|
||||||
|
histList.innerHTML = local
|
||||||
|
.map(function (kw) {
|
||||||
|
return (
|
||||||
|
'<a class="but jb-sm" href="' +
|
||||||
|
(window.location.origin || "") +
|
||||||
|
"/?s=" +
|
||||||
|
encodeURIComponent(kw) +
|
||||||
|
'">' +
|
||||||
|
kw +
|
||||||
|
"</a> "
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clearBtn = form.querySelector("[data-aksrt-clear-menu-history]");
|
||||||
|
if (clearBtn && !clearBtn._bound) {
|
||||||
|
clearBtn._bound = 1;
|
||||||
|
clearBtn.addEventListener("click", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
writeLocalHistory([]);
|
||||||
|
if (histList) {
|
||||||
|
histList.innerHTML =
|
||||||
|
'<span class="muted-3-color em09" data-empty="1">暂无历史</span>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var suggestMount = form.querySelector("[data-aksrt-menu-suggest]");
|
||||||
var timer = null;
|
var timer = null;
|
||||||
var searchConfig = (window.aksrtData && aksrtData.search) || {};
|
var searchConfig = (window.aksrtData && aksrtData.search) || {};
|
||||||
var suggestionsEnabled = searchConfig.suggestionsEnabled !== false;
|
|
||||||
|
|
||||||
function typeValue() {
|
function typeValue() {
|
||||||
var t = form.querySelector('input[name="aksrt_search_type"]');
|
var t = form.querySelector('input[name="aksrt_search_type"]');
|
||||||
return (t && t.value) || searchConfig.defaultType || "post";
|
return (t && t.value) || searchConfig.defaultType || "post";
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderItems(items) {
|
function requestSuggest(q) {
|
||||||
var html = "";
|
if (!suggestMount || !ajaxUrl() || q.length < 2) {
|
||||||
if (items && items.length) {
|
if (suggestMount) {
|
||||||
html += '<div class="muted-2-color em09 mb6">' + (searchConfig.suggestTitle || "搜索建议") + "</div>";
|
suggestMount.hidden = true;
|
||||||
html += '<div class="navbar-inline-search-suggest">';
|
suggestMount.innerHTML = "";
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open("POST", aksrtData.ajaxUrl, true);
|
xhr.open("POST", ajaxUrl(), true);
|
||||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||||
xhr.onload = function () {
|
xhr.onload = function () {
|
||||||
if (xhr.status < 200 || xhr.status >= 300) return;
|
if (xhr.status < 200 || xhr.status >= 300) return;
|
||||||
try {
|
try {
|
||||||
var json = JSON.parse(xhr.responseText);
|
var json = JSON.parse(xhr.responseText);
|
||||||
if (json.success && json.data && json.data.items) {
|
var items = (json.success && json.data && json.data.items) || [];
|
||||||
renderItems(json.data.items);
|
if (!items.length) {
|
||||||
|
suggestMount.hidden = true;
|
||||||
|
suggestMount.innerHTML = "";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
var html =
|
||||||
|
'<div class="muted-2-color em09 mb6">' +
|
||||||
|
(searchConfig.suggestTitle || "搜索建议") +
|
||||||
|
"</div><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>";
|
||||||
|
suggestMount.innerHTML = html;
|
||||||
|
suggestMount.hidden = false;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
};
|
};
|
||||||
xhr.send(
|
xhr.send(
|
||||||
"action=aksrt_search_suggestions&nonce=" +
|
"action=aksrt_search_suggestions&nonce=" +
|
||||||
encodeURIComponent(aksrtData.nonce) +
|
encodeURIComponent(nonce()) +
|
||||||
"&q=" +
|
"&q=" +
|
||||||
encodeURIComponent(q) +
|
encodeURIComponent(q) +
|
||||||
"&type=" +
|
"&type=" +
|
||||||
@@ -114,27 +168,75 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
input.addEventListener("input", function () {
|
if (!input._aksrtMenuSearchBound) {
|
||||||
var q = (input.value || "").trim();
|
input._aksrtMenuSearchBound = 1;
|
||||||
if (timer) clearTimeout(timer);
|
input.addEventListener("input", function () {
|
||||||
timer = setTimeout(function () {
|
var q = (input.value || "").trim();
|
||||||
request(q);
|
if (timer) clearTimeout(timer);
|
||||||
}, 180);
|
timer = setTimeout(function () {
|
||||||
|
requestSuggest(q);
|
||||||
|
}, 180);
|
||||||
|
});
|
||||||
|
input.addEventListener("focus", function () {
|
||||||
|
var remote = form.querySelector("[data-aksrt-menu-search-remote]");
|
||||||
|
if (remote) loadRemote(remote);
|
||||||
|
var p = form.querySelector(".navbar-inline-search-panel");
|
||||||
|
if (p) {
|
||||||
|
p.classList.add("is-open");
|
||||||
|
p.style.display = "block";
|
||||||
|
p.style.visibility = "visible";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
form.addEventListener("submit", function () {
|
||||||
|
var q = (input.value || "").trim();
|
||||||
|
if (!q) return;
|
||||||
|
if (!(window.aksrtData && aksrtData.isLoggedIn)) {
|
||||||
|
var list = readLocalHistory().filter(function (k) {
|
||||||
|
return k !== q;
|
||||||
|
});
|
||||||
|
list.unshift(q);
|
||||||
|
writeLocalHistory(list);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
document.querySelectorAll("[data-aksrt-menu-search-remote]").forEach(function (box) {
|
||||||
|
// Prefetch on idle / first hover of form.
|
||||||
|
var form = box.closest("form");
|
||||||
|
if (form) {
|
||||||
|
form.addEventListener(
|
||||||
|
"mouseenter",
|
||||||
|
function () {
|
||||||
|
loadRemote(box);
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Also load when lazyload-action ias would fire — simple viewport/idle.
|
||||||
|
if ("requestIdleCallback" in window) {
|
||||||
|
requestIdleCallback(function () {
|
||||||
|
loadRemote(box);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setTimeout(function () {
|
||||||
|
loadRemote(box);
|
||||||
|
}, 600);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
input.addEventListener("focus", function () {
|
var form = document.querySelector('form[data-aksrt-search-form="inline"]');
|
||||||
panel.style.display = "block";
|
if (form) enhancePanel(form);
|
||||||
panel.style.visibility = "visible";
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === "function") {
|
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === "function") {
|
||||||
window.AksrtFrontend.register("aksrt-inline-search-suggest", function () {
|
window.AksrtFrontend.register("aksrt-inline-search-suggest", function () {
|
||||||
initInlineSearchSuggest();
|
init();
|
||||||
});
|
});
|
||||||
} else if (document.readyState === "loading") {
|
} else if (document.readyState === "loading") {
|
||||||
document.addEventListener("DOMContentLoaded", initInlineSearchSuggest);
|
document.addEventListener("DOMContentLoaded", init);
|
||||||
} else {
|
} else {
|
||||||
initInlineSearchSuggest();
|
init();
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ require_once AKSRT_DIR . '/inc/helpers/aksrt-header-menu-buttons.php';
|
|||||||
require_once AKSRT_DIR . '/inc/helpers/header/aksrt-header-render.php';
|
require_once AKSRT_DIR . '/inc/helpers/header/aksrt-header-render.php';
|
||||||
require_once AKSRT_DIR . '/inc/helpers/header/aksrt-header-navbar.php';
|
require_once AKSRT_DIR . '/inc/helpers/header/aksrt-header-navbar.php';
|
||||||
require_once AKSRT_DIR . '/inc/helpers/header/aksrt-header-mobile.php';
|
require_once AKSRT_DIR . '/inc/helpers/header/aksrt-header-mobile.php';
|
||||||
|
require_once AKSRT_DIR . '/inc/helpers/header/aksrt-header-menu-search.php';
|
||||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-runtime-win.php';
|
require_once AKSRT_DIR . '/inc/helpers/aksrt-runtime-win.php';
|
||||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-identity.php';
|
require_once AKSRT_DIR . '/inc/helpers/aksrt-identity.php';
|
||||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-graphic-card.php';
|
require_once AKSRT_DIR . '/inc/helpers/aksrt-graphic-card.php';
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ defined('ABSPATH') || exit;
|
|||||||
|
|
||||||
if (!function_exists('aksrt_get_header_newposts_config')) :
|
if (!function_exists('aksrt_get_header_newposts_config')) :
|
||||||
/**
|
/**
|
||||||
* @return array{enabled:bool,text:string,radius:int,class:string,types:string[]}
|
* @return array{enabled:bool,text:string,radius:int,radius_pill:bool,class:string,types:string[]}
|
||||||
*/
|
*/
|
||||||
function aksrt_get_header_newposts_config(): array {
|
function aksrt_get_header_newposts_config(): array {
|
||||||
$cfg = class_exists('\AKSRT\Settings\Settings')
|
$cfg = class_exists('\AKSRT\Settings\Settings')
|
||||||
@@ -210,7 +210,11 @@ if (!function_exists('aksrt_render_header_menu_buttons')) :
|
|||||||
$class .= ' ' . $cfg['class'];
|
$class .= ' ' . $cfg['class'];
|
||||||
}
|
}
|
||||||
$radius = (int) ($cfg['radius'] ?? 20);
|
$radius = (int) ($cfg['radius'] ?? 20);
|
||||||
// Radius applied via CSS class variable to avoid style attribute overriding flex.
|
$pill = !empty($cfg['radius_pill']) || $radius >= 16;
|
||||||
|
if ($pill && !str_contains($class, 'radius')) {
|
||||||
|
$class .= ' radius';
|
||||||
|
}
|
||||||
|
// Radius applied via CSS variable (zibll pill ≈ 20px when switch on).
|
||||||
$radius_attr = $radius > 0 ? ' data-radius="' . esc_attr((string) $radius) . '" style="--navbar-cta-radius:' . $radius . 'px"' : '';
|
$radius_attr = $radius > 0 ? ' data-radius="' . esc_attr((string) $radius) . '" style="--navbar-cta-radius:' . $radius . 'px"' : '';
|
||||||
$label = (string) ($cfg['text'] ?? __('发布', 'aksrt'));
|
$label = (string) ($cfg['text'] ?? __('发布', 'aksrt'));
|
||||||
$btn = aksrt_render_new_add_btns($cfg['types'] ?? ['post'], $class, $label);
|
$btn = aksrt_render_new_add_btns($cfg['types'] ?? ['post'], $class, $label);
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Layout-2 menu search remote panel (zibll menu_search parity subset).
|
||||||
|
*
|
||||||
|
* @package AKSRT
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
if (!function_exists('aksrt_ajax_menu_search')) :
|
||||||
|
/**
|
||||||
|
* AJAX: HTML panel for navbar inline search (history + hot + posts).
|
||||||
|
*/
|
||||||
|
function aksrt_ajax_menu_search(): void {
|
||||||
|
// Prefer public nonce; also accept no nonce for same-origin remote-box first paint like zibll.
|
||||||
|
if (!empty($_REQUEST['nonce'])) {
|
||||||
|
$nonce = sanitize_text_field(wp_unslash((string) $_REQUEST['nonce']));
|
||||||
|
if (!wp_verify_nonce($nonce, 'aksrt_public_nonce')) {
|
||||||
|
wp_die('0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = aksrt_get_menu_search_panel_html();
|
||||||
|
if ($html === '') {
|
||||||
|
wp_die('0');
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<div class="dropdown-menu hover-show-con navbar-inline-search-panel is-open">' . $html . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
wp_die();
|
||||||
|
}
|
||||||
|
endif;
|
||||||
|
|
||||||
|
if (!function_exists('aksrt_get_menu_search_panel_html')) :
|
||||||
|
/**
|
||||||
|
* Build inner search panel HTML (no outer dropdown wrapper).
|
||||||
|
*/
|
||||||
|
function aksrt_get_menu_search_panel_html(): string {
|
||||||
|
$show_keywords = true;
|
||||||
|
$show_history = true;
|
||||||
|
$show_posts = true;
|
||||||
|
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||||
|
$show_keywords = method_exists('\AKSRT\Settings\Settings', 'hot_search_enabled')
|
||||||
|
? (bool) \AKSRT\Settings\Settings::hot_search_enabled()
|
||||||
|
: true;
|
||||||
|
$show_history = method_exists('\AKSRT\Settings\Settings', 'search_history_enabled')
|
||||||
|
? (bool) \AKSRT\Settings\Settings::search_history_enabled()
|
||||||
|
: true;
|
||||||
|
$show_posts = method_exists('\AKSRT\Settings\Settings', 'search_posts_enabled')
|
||||||
|
? (bool) \AKSRT\Settings\Settings::search_posts_enabled()
|
||||||
|
: !empty(\AKSRT\Settings\Settings::get_value('search_posts', true));
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = '';
|
||||||
|
|
||||||
|
// History (client may also fill via localStorage; server returns logged-in history).
|
||||||
|
if ($show_history) {
|
||||||
|
$hist = [];
|
||||||
|
if (is_user_logged_in()) {
|
||||||
|
$saved = get_user_meta(get_current_user_id(), 'aksrt_search_history', true);
|
||||||
|
if (is_array($saved)) {
|
||||||
|
foreach (array_slice($saved, 0, 10) as $item) {
|
||||||
|
if (is_array($item) && !empty($item['keyword'])) {
|
||||||
|
$hist[] = (string) $item['keyword'];
|
||||||
|
} elseif (is_string($item) && $item !== '') {
|
||||||
|
$hist[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$out .= '<div class="aksrt-menu-search-history" data-aksrt-menu-history="1">';
|
||||||
|
$out .= '<div class="flex jsb ac mb6"><span class="muted-2-color em09">' . esc_html__('搜索历史', 'aksrt') . '</span>';
|
||||||
|
$out .= '<a href="javascript:;" class="muted-2-color em09" data-aksrt-clear-menu-history="1">' . esc_html__('清空', 'aksrt') . '</a></div>';
|
||||||
|
$out .= '<div class="aksrt-menu-search-history__list">';
|
||||||
|
if ($hist) {
|
||||||
|
foreach ($hist as $kw) {
|
||||||
|
$out .= '<a class="but jb-sm" href="' . esc_url(home_url('/?s=' . rawurlencode($kw))) . '">' . esc_html($kw) . '</a> ';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$out .= '<span class="muted-3-color em09" data-empty="1">' . esc_html__('暂无历史', 'aksrt') . '</span>';
|
||||||
|
}
|
||||||
|
$out .= '</div></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hot keywords.
|
||||||
|
if ($show_keywords) {
|
||||||
|
$hots = function_exists('aksrt_get_search_hot_keywords') ? aksrt_get_search_hot_keywords() : [];
|
||||||
|
if ($hots) {
|
||||||
|
$title = class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'search_popular_title')
|
||||||
|
? \AKSRT\Settings\Settings::search_popular_title()
|
||||||
|
: __('热门搜索', 'aksrt');
|
||||||
|
$out .= '<div class="aksrt-menu-search-hots mt10">';
|
||||||
|
$out .= '<div class="muted-2-color em09 mb6">' . esc_html($title) . '</div>';
|
||||||
|
$out .= '<div class="navbar-inline-search-hots">';
|
||||||
|
foreach ($hots as $kw) {
|
||||||
|
$kw = trim((string) $kw);
|
||||||
|
if ($kw === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$out .= '<a class="but jb-sm" href="' . esc_url(home_url('/?s=' . rawurlencode($kw))) . '">' . esc_html($kw) . '</a> ';
|
||||||
|
}
|
||||||
|
$out .= '</div></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Latest / popular posts (optional).
|
||||||
|
if ($show_posts) {
|
||||||
|
$posts = get_posts([
|
||||||
|
'post_type' => 'post',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'posts_per_page' => 6,
|
||||||
|
'ignore_sticky_posts' => true,
|
||||||
|
'no_found_rows' => true,
|
||||||
|
'update_post_meta_cache' => false,
|
||||||
|
'update_post_term_cache' => false,
|
||||||
|
]);
|
||||||
|
if ($posts) {
|
||||||
|
$out .= '<div class="aksrt-menu-search-posts mt10">';
|
||||||
|
$out .= '<div class="muted-2-color em09 mb6">' . esc_html__('推荐内容', 'aksrt') . '</div>';
|
||||||
|
$out .= '<div class="aksrt-menu-search-posts__list">';
|
||||||
|
foreach ($posts as $p) {
|
||||||
|
$out .= '<a class="aksrt-menu-search-posts__item" href="' . esc_url(get_permalink($p)) . '">';
|
||||||
|
$out .= '<span class="title text-ellipsis">' . esc_html(get_the_title($p)) . '</span>';
|
||||||
|
$out .= '<span class="meta muted-3-color em09">' . esc_html(get_the_date('', $p)) . '</span>';
|
||||||
|
$out .= '</a>';
|
||||||
|
}
|
||||||
|
$out .= '</div></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Live suggestions mount point.
|
||||||
|
$out .= '<div class="aksrt-menu-search-suggest mt10" data-aksrt-menu-suggest="1" hidden></div>';
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
endif;
|
||||||
|
|
||||||
|
add_action('wp_ajax_aksrt_menu_search', 'aksrt_ajax_menu_search');
|
||||||
|
add_action('wp_ajax_nopriv_aksrt_menu_search', 'aksrt_ajax_menu_search');
|
||||||
|
// Alias for zibll-compatible remote-box query action name used in markup.
|
||||||
|
add_action('wp_ajax_menu_search', 'aksrt_ajax_menu_search');
|
||||||
|
add_action('wp_ajax_nopriv_menu_search', 'aksrt_ajax_menu_search');
|
||||||
@@ -104,7 +104,14 @@ if (!function_exists('aksrt_get_menu_search')) :
|
|||||||
$type = (string) ($state['type'] ?? 'post');
|
$type = (string) ($state['type'] ?? 'post');
|
||||||
$cat_enabled = !empty($state['category_enabled']);
|
$cat_enabled = !empty($state['category_enabled']);
|
||||||
$cat_id = (int) ($state['category_id'] ?? 0);
|
$cat_id = (int) ($state['category_id'] ?? 0);
|
||||||
$hots = is_array($ctx['search_hot_keywords'] ?? null) ? $ctx['search_hot_keywords'] : [];
|
|
||||||
|
// zibll remote-box: panel HTML loaded via ajax action menu_search.
|
||||||
|
$remote_url = add_query_arg(
|
||||||
|
[
|
||||||
|
'action' => 'aksrt_menu_search',
|
||||||
|
],
|
||||||
|
admin_url('admin-ajax.php')
|
||||||
|
);
|
||||||
|
|
||||||
echo '<form method="get" class="navbar-form navbar-left hover-show" action="' . esc_url(home_url('/')) . '" role="search" data-aksrt-search-form="inline">';
|
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">';
|
echo '<div class="form-group relative dropdown">';
|
||||||
@@ -116,19 +123,10 @@ if (!function_exists('aksrt_get_menu_search')) :
|
|||||||
. esc_attr(get_search_query()) . '" placeholder="' . esc_attr($placeholder) . '" autocomplete="off">';
|
. 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="'
|
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>';
|
. esc_attr__('搜索', 'aksrt') . '"><i class="fas fa-search" aria-hidden="true"></i></button></div>';
|
||||||
if ($hots) {
|
// Remote panel mount (zibll remote-box / lazyload-action=ias).
|
||||||
echo '<div class="dropdown-menu hover-show-con navbar-inline-search-panel">';
|
echo '<div class="aksrt-remote-box lazyload" remote-box="' . esc_url($remote_url) . '" lazyload-action="ias" data-aksrt-menu-search-remote="1">';
|
||||||
echo '<div class="muted-2-color em09 mb6">' . esc_html__('热门搜索', 'aksrt') . '</div>';
|
echo '<i class="loading-spot"><i></i></i>';
|
||||||
echo '<div class="navbar-inline-search-hots">';
|
echo '</div>';
|
||||||
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>';
|
echo '</div></form>';
|
||||||
}
|
}
|
||||||
endif;
|
endif;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class NavMenuOptions {
|
|||||||
if (!file_exists($path)) {
|
if (!file_exists($path)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
wp_enqueue_media();
|
||||||
wp_enqueue_script(
|
wp_enqueue_script(
|
||||||
'aksrt-admin-nav-menu-senior',
|
'aksrt-admin-nav-menu-senior',
|
||||||
get_template_directory_uri() . '/assets/js/admin-nav-menu-senior.js',
|
get_template_directory_uri() . '/assets/js/admin-nav-menu-senior.js',
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class SchemaPageDisplay {
|
|||||||
['key' => 'newposts', 'title' => '发布按钮', 'fields' => [
|
['key' => 'newposts', 'title' => '发布按钮', 'fields' => [
|
||||||
['key' => 'header_newposts_enabled', 'label' => '启用发布按钮', 'type' => 'switch', 'default' => true],
|
['key' => 'header_newposts_enabled', 'label' => '启用发布按钮', 'type' => 'switch', 'default' => true],
|
||||||
['key' => 'header_newposts_text', 'label' => '按钮文案', 'type' => 'input', 'default' => '<i class="fa fa-pencil"></i> 发布'],
|
['key' => 'header_newposts_text', 'label' => '按钮文案', 'type' => 'input', 'default' => '<i class="fa fa-pencil"></i> 发布'],
|
||||||
['key' => 'header_newposts_radius', 'label' => '圆角', 'type' => 'number', 'default' => 20, 'min' => 0, 'max' => 30],
|
['key' => 'header_newposts_radius', 'label' => '按钮圆角(胶囊)', 'type' => 'switch', 'default' => true],
|
||||||
['key' => 'header_newposts_class', 'label' => '样式类', 'type' => 'input', 'default' => ''],
|
['key' => 'header_newposts_class', 'label' => '样式类', 'type' => 'input', 'default' => ''],
|
||||||
['key' => 'header_newposts_types', 'label' => '发布类型', 'type' => 'select', 'default' => ['post'], 'options' => [
|
['key' => 'header_newposts_types', 'label' => '发布类型', 'type' => 'select', 'default' => ['post'], 'options' => [
|
||||||
['label' => '文章', 'value' => 'post'],
|
['label' => '文章', 'value' => 'post'],
|
||||||
|
|||||||
@@ -221,6 +221,37 @@ trait ScriptsPart2 {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} elseif ($type === 'topic' && post_type_exists('aksrt_topic')) {
|
||||||
|
$posts = get_posts([
|
||||||
|
'post_type' => 'aksrt_topic',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
's' => $q,
|
||||||
|
'posts_per_page' => 6,
|
||||||
|
'no_found_rows' => true,
|
||||||
|
]);
|
||||||
|
foreach ($posts as $p) {
|
||||||
|
$items[] = [
|
||||||
|
'title' => $p->post_title,
|
||||||
|
'url' => get_permalink($p),
|
||||||
|
'meta' => get_the_date('', $p),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} elseif ($type === 'product' && post_type_exists('aksrt_product')) {
|
||||||
|
$posts = get_posts([
|
||||||
|
'post_type' => 'aksrt_product',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
's' => $q,
|
||||||
|
'posts_per_page' => 6,
|
||||||
|
'no_found_rows' => true,
|
||||||
|
]);
|
||||||
|
foreach ($posts as $p) {
|
||||||
|
$items[] = [
|
||||||
|
'title' => $p->post_title,
|
||||||
|
'url' => get_permalink($p),
|
||||||
|
'meta' => get_the_date('', $p),
|
||||||
|
];
|
||||||
|
}
|
||||||
} elseif ($type === 'tag') {
|
} elseif ($type === 'tag') {
|
||||||
$terms = get_terms([
|
$terms = get_terms([
|
||||||
'taxonomy' => 'post_tag',
|
'taxonomy' => 'post_tag',
|
||||||
|
|||||||
@@ -69,13 +69,24 @@ trait FacadeBulk {
|
|||||||
$types = array_values(array_filter(array_map('sanitize_key', $s['header_newposts_types'])));
|
$types = array_values(array_filter(array_map('sanitize_key', $s['header_newposts_types'])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// zibll nav_newposts_radius is bool pill; map true→20px, false→0. Legacy int still accepted once.
|
||||||
|
$raw_radius = $s['header_newposts_radius'] ?? true;
|
||||||
|
if (is_bool($raw_radius) || $raw_radius === '0' || $raw_radius === '1' || $raw_radius === 0 || $raw_radius === 1) {
|
||||||
|
$radius_px = !empty($raw_radius) ? 20 : 0;
|
||||||
|
$radius_pill = !empty($raw_radius);
|
||||||
|
} else {
|
||||||
|
$radius_px = max(0, min(30, (int) $raw_radius));
|
||||||
|
$radius_pill = $radius_px >= 16;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
// Default on like zibll nav_newposts when key unset.
|
// Default on like zibll nav_newposts when key unset.
|
||||||
'enabled' => !isset($s['header_newposts_enabled']) || !empty($s['header_newposts_enabled']),
|
'enabled' => !isset($s['header_newposts_enabled']) || !empty($s['header_newposts_enabled']),
|
||||||
'text' => trim((string) ($s['header_newposts_text'] ?? '<i class="fa fa-pencil"></i> 发布')),
|
'text' => trim((string) ($s['header_newposts_text'] ?? '<i class="fa fa-pencil"></i> 发布')),
|
||||||
'radius' => max(0, min(30, (int) ($s['header_newposts_radius'] ?? 20))),
|
'radius' => $radius_px,
|
||||||
'class' => sanitize_html_class((string) ($s['header_newposts_class'] ?? '')),
|
'radius_pill' => $radius_pill,
|
||||||
'types' => $types,
|
'class' => sanitize_html_class((string) ($s['header_newposts_class'] ?? '')),
|
||||||
|
'types' => $types,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,3 +33,11 @@ Branch: `worktree-nav-zibll-1to1`
|
|||||||
## Deploy notes
|
## Deploy notes
|
||||||
- Admin `build/` is gitignored — run build on deploy host.
|
- Admin `build/` is gitignored — run build on deploy host.
|
||||||
- PR: open from branch `worktree-nav-zibll-1to1` against main on Gitea.
|
- PR: open from branch `worktree-nav-zibll-1to1` against main on Gitea.
|
||||||
|
|
||||||
|
|
||||||
|
## Deep align (post 2a11a88)
|
||||||
|
- [ ] Layout-2 focus loads remote panel (history + hot + posts)
|
||||||
|
- [ ] Typing shows live suggestions (post/topic/product)
|
||||||
|
- [ ] Publish radius switch = pill ends
|
||||||
|
- [ ] Menus senior editor: add card + media library pick image
|
||||||
|
- [ ] Contract report: tools/nav-zibll-contract-report.txt PASS
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
PASS all nav zibll source contracts
|
PASS deep-align menu_search + radius_pill + senior media
|
||||||
|
|||||||
Reference in New Issue
Block a user