From 4f67512dba8dd022e756b6b2b6d3551a387ac27d Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 4 Jul 2026 16:25:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E9=BD=90=E5=86=85=E5=AE=B9=E4=B8=BB?= =?UTF-8?q?=E7=BA=BF=E9=A1=B5=E9=AA=A8=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- archive.php | 41 +++-- assets/css/frontend/layout.css | 76 ++++++++- assets/css/frontend/pagination.css | 11 ++ assets/css/routes/search.css | 14 +- assets/js/core/archive.js | 66 ++++---- assets/js/core/pagination.js | 74 ++++----- category.php | 56 ++++--- inc/helpers/aksrt-frontend-tags.php | 42 +++-- inc/helpers/aksrt-template-tags.php | 6 +- search.php | 230 ++++++++++++++-------------- single.php | 12 +- tag.php | 56 ++++--- 12 files changed, 420 insertions(+), 264 deletions(-) diff --git a/archive.php b/archive.php index b3e4f13a..12ea2423 100644 --- a/archive.php +++ b/archive.php @@ -63,27 +63,34 @@ if (is_author()) { } ?> -
+
+
+ - + - - - 'archive', 'render_config' => $render_config]); ?> - -
-

-
- +
+ + 'content-stream__list'])); ?> + + +
+

+
+ +
+
diff --git a/assets/css/frontend/layout.css b/assets/css/frontend/layout.css index 8b0530e9..5fe4a7a1 100644 --- a/assets/css/frontend/layout.css +++ b/assets/css/frontend/layout.css @@ -1,11 +1,34 @@ /* ========== 面包屑 — 对齐 zibll .breadcrumb ========== */ +.breadcrumbs-wrap { + margin-bottom: 18px; +} + .breadcrumbs { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0; + margin: 0; + padding: 0; + list-style: none; font-size: 13px; color: var(--muted-2-color, #999); - margin-bottom: 12px; opacity: 0.8; } +.breadcrumbs__item { + display: inline-flex; + align-items: center; + min-width: 0; +} + +.breadcrumbs__item a, +.breadcrumbs__item span { + display: inline-flex; + align-items: center; + gap: 6px; +} + .breadcrumbs a { color: var(--muted-2-color, #999); } @@ -23,6 +46,10 @@ .breadcrumbs { font-size: 12px; } + + .breadcrumbs-wrap { + margin-bottom: 14px; + } } /* 封面内面包屑 */ @@ -33,6 +60,14 @@ } /* ========== 主布局 ========== */ +.content-main { + width: 100%; +} + +.content-main--single { + max-width: 100%; +} + .content-shell { width: 100%; margin: 0 auto; @@ -348,6 +383,45 @@ margin-top: 10px; } + +.content-stream { + display: grid; + gap: 20px; +} + +.content-main--archive, +.content-main--tag, +.content-main--category, +.content-main--search, +.content-main--single { + display: grid; + gap: 20px; +} + +.content-stream__list { + width: 100%; +} + +.content-stream__footer { + margin-top: 4px; +} + +.content-stream__footer > .content-stream__footer-nav, +.archive__ajax-wrap > .content-stream__footer-nav { + margin-top: 0; +} + +.content-stream__empty { + padding: 28px 24px; + border-radius: var(--radius-lg); + background: var(--surface-1); + border: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.08)); +} + +.article-shell { + overflow: hidden; +} + /* AJAX 筛选加载状态 */ .archive__ajax-wrap { position: relative; diff --git a/assets/css/frontend/pagination.css b/assets/css/frontend/pagination.css index e13a1072..a673d6e5 100644 --- a/assets/css/frontend/pagination.css +++ b/assets/css/frontend/pagination.css @@ -1,4 +1,15 @@ /* ========== 分页 — 对齐 zibll pagination ========== */ +.content-stream__footer-nav { + width: 100%; +} + +.content-stream__footer-nav.aksrt-pagination, +.content-stream__footer-nav.aksrt-pagination-ajax, +.content-stream__footer .aksrt-pagination, +.content-stream__footer .aksrt-pagination-ajax { + margin: 0; +} + .pagination, .aksrt-pagination, .navigation.pagination .nav-links, diff --git a/assets/css/routes/search.css b/assets/css/routes/search.css index ea6d136a..d346d830 100644 --- a/assets/css/routes/search.css +++ b/assets/css/routes/search.css @@ -129,11 +129,21 @@ align-items: center; justify-content: space-between; gap: 16px; - margin-bottom: 24px; - padding-bottom: 12px; + margin-bottom: 0; + padding-bottom: 14px; border-bottom: 1px solid var(--color-line); } +.search-page-filters { + display: grid; + gap: 14px; + margin: 0; + padding: 16px 18px; + border: 1px solid var(--color-line); + border-radius: var(--radius-lg); + background: var(--surface-2); +} + .search-page-toolbar__count { color: var(--color-ink-3); } diff --git a/assets/js/core/archive.js b/assets/js/core/archive.js index f4415a21..3a7fda75 100644 --- a/assets/js/core/archive.js +++ b/assets/js/core/archive.js @@ -4,17 +4,19 @@ (function () { "use strict"; - function initArchiveFilter() { - var bar = document.querySelector(".archive-filter-bar--ajax[data-ajax-archive]"); + function initArchiveFilter(root) { + var scope = root || document; + var bar = scope.querySelector(".archive-filter-bar--ajax[data-ajax-archive]"); if (!bar) return; var archiveType = bar.dataset.ajaxArchive || "category"; var termId = parseInt(bar.dataset.termId, 10) || 0; - var wrap = document.querySelector("[data-ajax-wrap]"); + var wrap = scope.querySelector("[data-ajax-wrap]"); if (!wrap) return; var loading = wrap.querySelector(".archive__ajax-loading"); var REST_BASE = "/wp-json/aksrt/v1/archive/posts"; + var emptyText = archiveType === "tag" ? "该标签下暂无文章" : "该分类下暂无文章"; var state = { filter_cat: "", @@ -24,14 +26,12 @@ cf: {} }; - // Read initial state from active chips var activeCat = bar.querySelector("[data-filter-cat].is-active"); if (activeCat) state.filter_cat = activeCat.dataset.filterCat || ""; var activeTag = bar.querySelector("[data-filter-tag].is-active"); if (activeTag) state.filter_tag = activeTag.dataset.filterTag || ""; var activeSort = bar.querySelector("[data-filter-sort].is-active"); if (activeSort) state.sort = activeSort.dataset.filterSort || "latest"; - // custom_filter: read initial cf state from active chips bar.querySelectorAll("[data-filter-cf].is-active").forEach(function (el) { var dimKey = el.dataset.filterCf || ""; var dimVal = el.dataset.filterCfVal || ""; @@ -50,11 +50,13 @@ params.set("sort", s ? s.orderby : "date"); params.set("order", s ? s.order : "DESC"); params.set("page", String(state.page)); - // custom_filter: pass active dimensions as JSON var cfActive = {}; var hasCf = false; for (var cfK in state.cf) { - if (state.cf[cfK]) { cfActive[cfK] = state.cf[cfK]; hasCf = true; } + if (state.cf[cfK]) { + cfActive[cfK] = state.cf[cfK]; + hasCf = true; + } } if (hasCf) params.set("custom_filters", JSON.stringify(cfActive)); return REST_BASE + "?" + params.toString(); @@ -70,7 +72,6 @@ bar.querySelectorAll("[data-filter-sort]").forEach(function (el) { el.classList.toggle("is-active", (el.dataset.filterSort || "latest") === state.sort); }); - // custom_filter: update cf chip active state bar.querySelectorAll("[data-filter-cf]").forEach(function (el) { var dimKey = el.dataset.filterCf || ""; var dimVal = el.dataset.filterCfVal || ""; @@ -89,6 +90,13 @@ wrap.classList.remove("is-loading"); } + function rebuildEmptyState() { + var noResults = document.createElement("div"); + noResults.className = "no-results content-stream__empty"; + noResults.innerHTML = "

" + emptyText + "

"; + wrap.appendChild(noResults); + } + function fetchPosts(pushState) { showLoading(); fetch(buildUrl(), { @@ -103,7 +111,6 @@ .then(function (data) { hideLoading(); if (data.html !== undefined) { - // Keep the loading element, replace the rest var children = Array.from(wrap.children); children.forEach(function (child) { if (child !== loading) wrap.removeChild(child); @@ -113,13 +120,9 @@ temp.innerHTML = data.html; while (temp.firstChild) wrap.appendChild(temp.firstChild); } else { - var noResults = document.createElement("div"); - noResults.className = "no-results"; - noResults.innerHTML = "

暂无文章

"; - wrap.appendChild(noResults); + rebuildEmptyState(); } - // Re-init rehydratable modules for new content - if (window.AksrtFrontend) AksrtFrontend.rehydrate(wrap, 'ajax'); + if (window.AksrtFrontend) AksrtFrontend.rehydrate(wrap, "ajax"); } if (pushState !== false) { var url = new URL(window.location.href); @@ -128,18 +131,21 @@ url.searchParams.delete("paged"); url.searchParams.delete("aksrt_filter_cat"); url.searchParams.delete("aksrt_filter_tag"); - // custom_filter: clean cf params url.searchParams.forEach(function (v, k) { if (k.indexOf("aksrt_cf_") === 0) url.searchParams.delete(k); }); if (state.filter_cat) url.searchParams.set("aksrt_filter_cat", state.filter_cat); if (state.filter_tag) url.searchParams.set("aksrt_filter_tag", state.filter_tag); - // custom_filter: set cf URL params for (var cfK2 in state.cf) { if (state.cf[cfK2]) url.searchParams.set("aksrt_cf_" + cfK2, state.cf[cfK2]); } - if (state.sort === "oldest") { url.searchParams.set("orderby", "date"); url.searchParams.set("order", "asc"); } - else if (state.sort === "popular") { url.searchParams.set("orderby", "comment_count"); url.searchParams.set("order", "desc"); } + if (state.sort === "oldest") { + url.searchParams.set("orderby", "date"); + url.searchParams.set("order", "asc"); + } else if (state.sort === "popular") { + url.searchParams.set("orderby", "comment_count"); + url.searchParams.set("order", "desc"); + } if (state.page > 1) url.searchParams.set("paged", String(state.page)); history.pushState({ aksrtArchive: true, state: Object.assign({}, state) }, "", url.toString()); } @@ -157,17 +163,25 @@ var changed = false; if (chip.dataset.filterCat !== undefined) { var newCat = chip.dataset.filterCat; - if (newCat !== state.filter_cat) { state.filter_cat = newCat; changed = true; } + if (newCat !== state.filter_cat) { + state.filter_cat = newCat; + changed = true; + } } if (chip.dataset.filterTag !== undefined) { var newTag = chip.dataset.filterTag; - if (newTag !== state.filter_tag) { state.filter_tag = newTag; changed = true; } + if (newTag !== state.filter_tag) { + state.filter_tag = newTag; + changed = true; + } } if (chip.dataset.filterSort !== undefined) { var newSort = chip.dataset.filterSort || "latest"; - if (newSort !== state.sort) { state.sort = newSort; changed = true; } + if (newSort !== state.sort) { + state.sort = newSort; + changed = true; + } } - // custom_filter: handle cf chip clicks if (chip.dataset.filterCf !== undefined) { var cfKey = chip.dataset.filterCf; var cfVal = chip.dataset.filterCfVal || ""; @@ -184,7 +198,6 @@ } }); - // Pagination within AJAX wrap wrap.addEventListener("click", function (e) { var pageLink = e.target.closest(".pagination a, .nav-links a, a.page-numbers"); if (!pageLink || !wrap.contains(pageLink)) return; @@ -199,7 +212,6 @@ } }); - // Handle browser back/forward window.addEventListener("popstate", function (e) { if (e.state && e.state.aksrtArchive) { state = Object.assign(state, e.state.state); @@ -209,5 +221,7 @@ }); } - window.AksrtFrontend.register("aksrt-archive-filter", function () { initArchiveFilter(); }); + window.AksrtFrontend.register("aksrt-archive-filter", function (root) { + initArchiveFilter(root); + }); })(); diff --git a/assets/js/core/pagination.js b/assets/js/core/pagination.js index 59eb0ef5..431c090a 100644 --- a/assets/js/core/pagination.js +++ b/assets/js/core/pagination.js @@ -25,8 +25,13 @@ var loading = false; var loadMoreBtn = container.querySelector(".aksrt-load-more-btn, .ajax-next"); var indicator = container.querySelector(".aksrt-loading-indicator"); - // 目标容器:文章列表取 .post-grid,评论取 .comment-list var target = container.previousElementSibling; + if (target && target.classList && target.classList.contains("content-stream__footer")) { + target = target.previousElementSibling; + } + if (!target && container.parentElement) { + target = container.parentElement.querySelector(".post-grid, .comment-list, .content-stream__list"); + } function showSkeleton() { if (!target) return; @@ -96,10 +101,8 @@ nextPage++; container.dataset.nextPage = String(nextPage); - // 重新初始化懒加载(新加载的图片) if (typeof initLazyLoad === "function") initLazyLoad(); - // 如果没有更多页 if (nextPage > maxPages || !res.data.has_more) { if (loadMoreBtn) { loadMoreBtn.textContent = nomoreText; @@ -124,7 +127,6 @@ }); } - // 加载更多按钮点击 if (loadMoreBtn) { loadMoreBtn.addEventListener("click", function(e) { e.preventDefault(); @@ -154,55 +156,48 @@ }); } - // 无限滚动:IntersectionObserver if (mode === "infinite" && "IntersectionObserver" in window) { - // Comment containers respect commentIasAuto; if disabled, fall back to click-to-load if (isComment && window.aksrtData && aksrtData.commentIasAuto === false) { - // Skip IntersectionObserver — load_more button already present } else { - var sentinel = document.createElement("div"); - sentinel.className = "aksrt-scroll-sentinel"; - container.appendChild(sentinel); - var lazyloadAction = container.dataset.lazyloadAction || ""; - var iasMax = isComment - ? ((window.aksrtData && typeof aksrtData.commentIasMax !== "undefined") ? parseInt(aksrtData.commentIasMax, 10) : 0) - : ((window.aksrtData && typeof aksrtData.iasMax !== "undefined") ? parseInt(aksrtData.iasMax, 10) : 0); - var initialPage = nextPage - 1; // page at init time - var observer = new IntersectionObserver( - function (entries) { - if (entries[0].isIntersecting && !loading) { - // iasMax = 0 means unlimited, otherwise limit additional pages - if (iasMax > 0 && (nextPage - initialPage) >= iasMax) { - // Reached ias max, show nomore and disconnect - observer.disconnect(); - if (loadMoreBtn) { - loadMoreBtn.textContent = nomoreText; - loadMoreBtn.classList.add("ajax-nomore"); - loadMoreBtn.style.pointerEvents = "none"; + var sentinel = document.createElement("div"); + sentinel.className = "aksrt-scroll-sentinel"; + container.appendChild(sentinel); + var lazyloadAction = container.dataset.lazyloadAction || ""; + var iasMax = isComment + ? ((window.aksrtData && typeof aksrtData.commentIasMax !== "undefined") ? parseInt(aksrtData.commentIasMax, 10) : 0) + : ((window.aksrtData && typeof aksrtData.iasMax !== "undefined") ? parseInt(aksrtData.iasMax, 10) : 0); + var initialPage = nextPage - 1; + var observer = new IntersectionObserver( + function (entries) { + if (entries[0].isIntersecting && !loading) { + if (iasMax > 0 && (nextPage - initialPage) >= iasMax) { + observer.disconnect(); + if (loadMoreBtn) { + loadMoreBtn.textContent = nomoreText; + loadMoreBtn.classList.add("ajax-nomore"); + loadMoreBtn.style.pointerEvents = "none"; + } + return; } - return; + loadNextPage(); } - loadNextPage(); - } - }, - { rootMargin: "400px" } - ); - if (lazyloadAction === "ias") { - container.classList.add("ias-pending"); - } - observer.observe(sentinel); + }, + { rootMargin: "400px" } + ); + if (lazyloadAction === "ias") { + container.classList.add("ias-pending"); + } + observer.observe(sentinel); } } }); } - /* ====== 图片懒加载 ====== */ function initLazyLoad(root) { var scope = root || document; var lazyImages = scope.querySelectorAll("img.aksrt-lazy"); if (!lazyImages.length) return; - // 不支持 IntersectionObserver 时直接加载所有图片 if (!("IntersectionObserver" in window)) { lazyImages.forEach(function (img) { var src = img.dataset.src; @@ -230,13 +225,11 @@ return; } - // 创建新图片预加载 var tempImg = new Image(); tempImg.onload = function () { img.src = src; img.classList.remove("aksrt-lazy"); img.classList.add("aksrt-loaded"); - // 移除骨架 var skeleton = img.previousElementSibling; if (skeleton && skeleton.classList.contains("aksrt-skeleton")) { skeleton.remove(); @@ -245,7 +238,6 @@ tempImg.onerror = function () { img.classList.remove("aksrt-lazy"); img.classList.add("aksrt-error"); - // 移除骨架 var skeleton = img.previousElementSibling; if (skeleton && skeleton.classList.contains("aksrt-skeleton")) { skeleton.remove(); diff --git a/category.php b/category.php index 6926a455..07b5ece5 100644 --- a/category.php +++ b/category.php @@ -142,26 +142,34 @@ if ($ajax_filter && !empty($filter_settings['cat_show_tag'])) { - - - +
+ - -
data-ajax-archive="category" data-term-id="term_id; ?>"> + + + + + +
data-ajax-archive="category" data-term-id="term_id; ?>" data-query-context="archive" data-render-mode="" data-card-style="">
@@ -226,13 +234,15 @@ if ($ajax_filter && !empty($filter_settings['cat_show_tag'])) {
-
data-ajax-wrap> +
data-ajax-wrap data-query-context="archive"> - - 'archive', 'render_config' => $render_config]); ?> + 'content-stream__list'])); ?> + -
+

diff --git a/inc/helpers/aksrt-frontend-tags.php b/inc/helpers/aksrt-frontend-tags.php index 0ec1676d..10247222 100644 --- a/inc/helpers/aksrt-frontend-tags.php +++ b/inc/helpers/aksrt-frontend-tags.php @@ -303,34 +303,52 @@ if (!function_exists('aksrt_breadcrumbs')) : } $items = []; - $items[] = '
  • ' . esc_html($home_text) . '
  • '; + $items[] = ''; if (is_category()) { - $items[] = '
  • ' . esc_html(single_cat_title('', false)) . '
  • '; + $term = get_queried_object(); + if ($term instanceof WP_Term) { + $ancestors = array_reverse(get_ancestors($term->term_id, 'category')); + foreach ($ancestors as $ancestor_id) { + $ancestor = get_term($ancestor_id, 'category'); + if ($ancestor instanceof WP_Term && !is_wp_error($ancestor)) { + $items[] = ''; + } + } + $items[] = ''; + } } elseif (is_tag()) { - $items[] = '
  • ' . esc_html(single_tag_title('', false)) . '
  • '; + $items[] = ''; } elseif (is_author()) { - $items[] = '
  • ' . esc_html(get_the_author()) . '
  • '; + $items[] = ''; } elseif (is_search()) { - $items[] = '
  • ' . esc_html__('搜索', 'aksrt') . '
  • '; + $search_query = trim((string) get_search_query()); + $items[] = ''; } elseif (function_exists('aksrt_is_resource_archive') && aksrt_is_resource_archive()) { - $items[] = '
  • ' . esc_html__('资源', 'aksrt') . '
  • '; + $items[] = ''; } elseif (is_singular('post')) { $cats = get_the_category(); if (!empty($cats)) { $category = $cats[0]; - $items[] = '
  • ' . esc_html($category->name) . '
  • '; + $ancestors = array_reverse(get_ancestors($category->term_id, 'category')); + foreach ($ancestors as $ancestor_id) { + $ancestor = get_term($ancestor_id, 'category'); + if ($ancestor instanceof WP_Term && !is_wp_error($ancestor)) { + $items[] = ''; + } + } + $items[] = ''; } - $items[] = '
  • ' . esc_html(get_the_title()) . '
  • '; + $items[] = ''; } elseif (is_page()) { - $items[] = '
  • ' . esc_html(get_the_title()) . '
  • '; + $items[] = ''; } elseif (is_archive()) { - $items[] = '
  • ' . esc_html(get_the_archive_title()) . '
  • '; + $items[] = ''; } else { - $items[] = '
  • ' . esc_html(get_the_title()) . '
  • '; + $items[] = ''; } - echo ''; + echo ''; } endif; diff --git a/inc/helpers/aksrt-template-tags.php b/inc/helpers/aksrt-template-tags.php index 8bc143bc..e95c7303 100644 --- a/inc/helpers/aksrt-template-tags.php +++ b/inc/helpers/aksrt-template-tags.php @@ -1014,7 +1014,7 @@ if (!function_exists('aksrt_render_pagination')) { return; } - echo '