- name); ?> -
- - - + + - --
-
-
- - - name); ?> - count; ?> - - - -
', + 'after' => '
', + ]); + echo 'diff --git a/assets/css/routes/categories.css b/assets/css/routes/categories.css index d330a786..059e62a8 100644 --- a/assets/css/routes/categories.css +++ b/assets/css/routes/categories.css @@ -1,224 +1,217 @@ -/** - * Jio - Categories Index Route Stylesheet - * - * 分类汇总页面 (templates/pages/page-categories.php) 专用样式: - * 卡片网格、封面图、文章计数徽章、子分类胶囊条、页面顶部统计与底部返回。 - * - * Tokens: 颜色 / 间距 / 圆角 / 阴影 全部来自 core/tokens.css - */ - -/* ================================================ - * 页面头:标题 + 计数 - * ================================================ */ -.jio-cats-header { - margin-bottom: var(--space-7); +/* Category directory */ +.jio-category-directory-nav { + margin-bottom: 20px; + padding: 14px 16px; } -.jio-cats-header__meta { - margin-top: var(--space-2); - color: var(--color-ink-4); - font-size: 13px; -} - -/* ================================================ - * 网格容器 - * ================================================ */ -.jio-cats-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: var(--space-5); - margin-bottom: var(--space-8); -} - -/* ================================================ - * 卡片 - * ================================================ */ -.jio-cat-card { - display: flex; - flex-direction: column; - background: var(--surface-page); - border: 1px solid var(--color-line); - border-radius: var(--radius-lg); - overflow: hidden; - box-shadow: var(--shadow-sm); - transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease; -} - -.jio-cat-card:hover { - transform: translateY(-3px); - box-shadow: var(--shadow-md); - border-color: var(--color-primary); -} - -/* 封面图 */ -.jio-cat-card__cover { - position: relative; +.jio-category-directory-nav__label { display: block; - aspect-ratio: 16 / 9; - background-color: var(--surface-3); - background-position: center; - background-size: cover; - background-repeat: no-repeat; - text-decoration: none; -} - -.jio-cat-card__cover::after { - content: ""; - position: absolute; - inset: 0; - background: linear-gradient( - 180deg, - rgba(20, 28, 48, 0) 40%, - rgba(20, 28, 48, 0.45) 100% - ); - pointer-events: none; -} - -/* 计数徽章 */ -.jio-cat-card__count-badge { - position: absolute; - top: var(--space-3); - right: var(--space-3); - z-index: 1; - display: inline-flex; - align-items: center; - padding: 4px 10px; - background: var(--color-primary); - color: #fff; - font-size: 12px; + margin-bottom: 8px; font-weight: 600; - letter-spacing: 0.02em; - border-radius: var(--radius-pill); - box-shadow: var(--shadow-sm); } -/* 卡片正文 */ -.jio-cat-card__body { - display: flex; - flex-direction: column; - gap: var(--space-3); - padding: var(--space-5); - flex: 1; -} - -.jio-cat-card__title { - margin: 0; - font-size: 18px; - font-weight: 600; - line-height: 1.4; -} - -.jio-cat-card__title a { - color: var(--color-ink); - text-decoration: none; - transition: color 0.15s ease; -} - -.jio-cat-card__title a:hover { - color: var(--color-primary); -} - -.jio-cat-card__desc { - margin: 0; - color: var(--color-ink-3); - font-family: var(--font-body); - font-size: 14px; - line-height: 1.6; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; -} - -/* ================================================ - * 子分类胶囊条 - * ================================================ */ -.jio-cat-card__children { +.jio-category-directory-nav ul, +.jio-category-directory__children { margin: 0; padding: 0; list-style: none; +} + +.jio-category-directory-nav ul { display: flex; flex-wrap: wrap; - gap: 6px; - margin-top: auto; - padding-top: var(--space-3); - border-top: 1px dashed var(--color-line); + gap: 6px 14px; } -.jio-cat-card__children li { - margin: 0; - padding: 0; -} - -.jio-cat-card__children a { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 4px 10px; - background: var(--surface-2); - border: 1px solid var(--color-line); - border-radius: var(--radius-pill); - color: var(--color-ink-3); - font-size: 12px; - line-height: 1.4; +.jio-category-directory-nav a, +.jio-category-directory__child-main a { + color: var(--key-color, var(--main-color, inherit)); text-decoration: none; - transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; } -.jio-cat-card__children a:hover { - background: var(--color-primary-soft); - border-color: var(--color-primary); - color: var(--color-ink); +.jio-category-directory-nav a:hover, +.jio-category-directory__child-main a:hover, +.jio-category-directory__intro h2 a:hover { + color: var(--focus-color, #ff5473); } -.jio-cat-card__child-count { +.jio-category-directory { + margin-bottom: 20px; +} + +.jio-category-directory__section { + margin-bottom: 20px; + padding: 15px; + border-radius: var(--main-radius, 8px); + background: var(--main-bg-color, #fff); + box-shadow: 0 0 10px var(--main-shadow, rgba(116, 116, 116, .08)); + scroll-margin-top: 90px; +} + +.jio-category-directory__summary { + display: flex; + align-items: flex-start; + gap: 15px; + margin-bottom: 14px; +} + +.jio-category-directory__cover { + flex: 0 0 180px; + width: 180px; + height: 100px; + overflow: hidden; + border-radius: var(--main-radius, 8px); + background: var(--muted-border-color, #f2f3f5); +} + +.jio-category-directory__cover img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; + transition: transform .25s ease; +} + +.jio-category-directory__cover:hover img { + transform: scale(1.04); +} + +.jio-category-directory__intro { + min-width: 0; + flex: 1; +} + +.jio-category-directory__intro h2 { + display: inline; + margin: 0; + font-size: 1.15em; +} + +.jio-category-directory__intro h2 a { + color: var(--key-color, var(--main-color, inherit)); + text-decoration: none; +} + +.jio-category-directory__count { + display: inline-block; + margin-left: 8px; + color: var(--muted-2-color, #999); + font-size: .88em; + white-space: nowrap; +} + +.jio-category-directory__intro p, +.jio-category-directory__child-desc { + margin: 6px 0 0; + color: var(--muted-color, #777); + font-size: .92em; + line-height: 1.55; +} + +.jio-category-directory__intro p { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; +} + +.jio-category-directory__more { display: inline-flex; align-items: center; - justify-content: center; - min-width: 18px; - height: 18px; - padding: 0 5px; - background: var(--surface-3); - border-radius: var(--radius-pill); - color: var(--color-ink-4); - font-size: 11px; + gap: 5px; + margin-top: 8px; + color: var(--focus-color, #ff5473); + font-size: .9em; + text-decoration: none; +} + +.jio-category-directory__children { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; + padding-top: 14px; + border-top: 1px solid var(--main-border-color, rgba(127, 127, 127, .13)); +} + +.jio-category-directory__child { + min-width: 0; + padding: 10px 12px; + border-radius: var(--main-radius, 8px); + background: var(--muted-border-color, rgba(127, 127, 127, .06)); +} + +.jio-category-directory__child-main { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; font-weight: 600; } -/* ================================================ - * 空状态 - * ================================================ */ -.jio-cats-empty { - padding: var(--space-9) var(--space-5); - text-align: center; - color: var(--color-ink-3); - background: var(--surface-2); - border: 1px dashed var(--color-line); - border-radius: var(--radius-lg); +.jio-category-directory__child-main a { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } -/* ================================================ - * 底部返回 - * ================================================ */ -.jio-cats-footer { - text-align: center; - margin-top: var(--space-8); +.jio-category-directory__child .jio-category-directory__count { + flex: 0 0 auto; + margin-left: 0; + font-weight: 400; } -/* ================================================ - * 响应式 - * ================================================ */ -@media (max-width: 640px) { - .jio-cats-grid { +.jio-category-directory__child-desc { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; +} + +.jio-category-directory__child > .jio-category-directory__children { + grid-template-columns: 1fr; + gap: 6px; + margin-top: 10px; + padding-top: 10px; +} + +.jio-category-directory__child > .jio-category-directory__children > li { + padding: 7px 9px; + background: var(--main-bg-color, rgba(255, 255, 255, .6)); +} + +.jio-categories-empty { + padding: 28px 18px; + border: 1px dashed var(--main-border-color, rgba(127, 127, 127, .25)); + border-radius: var(--main-radius, 8px); + color: var(--muted-color, #8a8c98); + text-align: center; +} + +@media (max-width: 767px) { + .jio-category-directory__section { + padding: 12px; + } + + .jio-category-directory__cover { + flex-basis: 110px; + width: 110px; + height: 78px; + } + + .jio-category-directory__children { grid-template-columns: 1fr; - gap: var(--space-4); } +} - .jio-cat-card__body { - padding: var(--space-4); +@media (max-width: 420px) { + .jio-category-directory__summary { + gap: 10px; } - .jio-cat-card__title { - font-size: 17px; + .jio-category-directory__cover { + flex-basis: 88px; + width: 88px; + height: 72px; } } diff --git a/category.php b/category.php index 9985ad3b..b56b26ab 100644 --- a/category.php +++ b/category.php @@ -10,24 +10,6 @@ defined('ABSPATH') || exit; get_header(); $term = get_queried_object(); -if (class_exists('\Jio\Core\DocsPresenter')) { - $docs_presenter = \Jio\Core\DocsPresenter::get_instance(); - if ($term instanceof WP_Term && $term->taxonomy === 'category') { - $doc_candidates = get_posts([ - 'post_type' => 'page', - 'post_status' => 'publish', - 'posts_per_page' => 1, - 'meta_key' => '_jio_doc_category', - 'meta_value' => (string) $term->term_id, - 'fields' => 'ids', - ]); - if (!empty($doc_candidates)) { - get_template_part('templates/pages/page-documentnav'); - get_footer(); - return; - } - } -} if (!$term instanceof WP_Term) { get_footer(); return; @@ -35,7 +17,10 @@ if (!$term instanceof WP_Term) { $archive_settings = \Jio\Core\TermMeta::resolve_archive_settings($term); $has_sidebar = jio_archive_has_sidebar(!empty($archive_settings['show_sidebar'])); -$ajax_filter = !empty($archive_settings['filter_bar']); +$access = function_exists('jio_get_term_allow_view_data') + ? jio_get_term_allow_view_data((int) $term->term_id) + : ['allow' => true, 'not_html' => '']; +$ajax_filter = !empty($access['allow']) && !empty($archive_settings['filter_bar']); $sort_state = jio_archive_get_sort_state((array) ($archive_settings['orderby_option'] ?? [])); $filter_groups = []; foreach (['category' => __('分类', 'jio'), 'post_tag' => __('标签', 'jio')] as $taxonomy => $label) { @@ -66,7 +51,7 @@ jio_archive_render_term_header([ 'post_count' => !empty($archive_settings['post_count']), ]); ob_start(); -if ($ajax_filter) { +if (!empty($access['allow']) && $ajax_filter) { jio_archive_render_filter_bar([ 'aria_label' => __('分类筛选', 'jio'), 'groups' => $filter_groups, 'sort_enabled' => !empty($archive_settings['orderby_enabled']), @@ -76,11 +61,18 @@ if ($ajax_filter) { ]); } $filter_html = (string) ob_get_clean(); -jio_archive_render_stream(null, jio_archive_get_render_config(['context' => 'category']), [ - 'page_kind' => 'category', 'query_context' => 'archive', - 'empty_text' => __('暂无内容', 'jio'), - 'filter_html' => $filter_html, -]); +if (!empty($access['allow'])) { + jio_archive_render_stream(null, jio_archive_get_render_config(['context' => 'category']), [ + 'page_kind' => 'category', 'query_context' => 'archive', + 'empty_text' => __('暂无内容', 'jio'), + 'filter_html' => $filter_html, + ]); +} else { + echo '
' . esc_html__('登录后可查看', 'jio') . '
'; diff --git a/src/Core/ScriptsPart1b.php b/src/Core/ScriptsPart1b.php index b378f6cd..f96e3bd1 100644 --- a/src/Core/ScriptsPart1b.php +++ b/src/Core/ScriptsPart1b.php @@ -528,11 +528,12 @@ trait ScriptsPart1b { // 分类汇总页:路由专属 CSS if (is_page_template('templates/pages/page-categories.php')) { + $categories_css = get_template_directory() . '/assets/css/routes/categories.css'; wp_enqueue_style( 'jio-route-categories', $base_uri . '/assets/css/routes/categories.css', ['jio-public'], - $version + file_exists($categories_css) ? (string) filemtime($categories_css) : $version ); } diff --git a/templates/pages/page-categories.php b/templates/pages/page-categories.php index bc8930e9..2cbf8fa9 100644 --- a/templates/pages/page-categories.php +++ b/templates/pages/page-categories.php @@ -3,137 +3,180 @@ * Template Name: Jio - Categories * Template Post Type: page * - * 分类汇总页面:列出全站所有分类。 - * - * 用法:在后台新建一个 Page,标题任意(默认显示页面标题,否则用"分类目录"), - * 模板选择 "Jio - Categories";或将 slug 设为 "categories" 自动匹配。 + * Category directory page with recursive taxonomy navigation. * * @package Jio */ defined('ABSPATH') || exit; -get_header(); - -// ─── 数据准备 ───────────────────────────────────────────── +$post_id = (int) get_queried_object_id(); $all_terms = get_terms([ 'taxonomy' => 'category', - 'hide_empty' => false, // 全部展示,含 0 篇文章的分类 - 'orderby' => 'menu_order name', + 'hide_empty' => false, + 'orderby' => 'term_group', 'order' => 'ASC', ]); if (is_wp_error($all_terms)) { $all_terms = []; } -$top_level = []; +$top_level = []; $children_by_parent = []; foreach ($all_terms as $term) { - if ((int) $term->parent === 0) { + $parent_id = (int) $term->parent; + if ($parent_id === 0) { $top_level[] = $term; } else { - $children_by_parent[(int) $term->parent][] = $term; + $children_by_parent[$parent_id][] = $term; } } -$total_cats = count($all_terms); -$total_counts = wp_count_posts(); -$total_posts = $total_counts && isset($total_counts->publish) ? (int) $total_counts->publish : 0; - -$page_title = trim((string) get_the_title()); -if ($page_title === '') { - $page_title = __('分类目录', 'jio'); +$total_posts = wp_count_posts('post'); +$total_posts = $total_posts && isset($total_posts->publish) ? (int) $total_posts->publish : 0; +$page_title = trim((string) get_the_title($post_id)); +$page_title = $page_title !== '' ? $page_title : __('分类目录', 'jio'); +$has_sidebar = function_exists('jio_archive_has_sidebar') + ? jio_archive_has_sidebar() + : (function_exists('jio_is_show_sidebar') ? jio_is_show_sidebar() : false); +$content_style = sanitize_key((string) get_post_meta($post_id, 'page_content_style', true)); +if (!in_array($content_style, ['', 'not', 'nobox', 'full'], true)) { + $content_style = ''; } -?> +$content_style_class = $content_style !== '' ? ' page-content-' . $content_style : ' page-content-default'; + +$render_children = static function (int $parent_id, array $path) use (&$render_children, $children_by_parent): string { + $children = $children_by_parent[$parent_id] ?? []; + if ($children === []) { + return ''; + } + + $html = '' . esc_html(wp_trim_words($description, 18, '…')) . '
'; + } + $nested = $render_children($child_id, array_merge($path, [$child_id])); + if ($nested !== '') { + $html .= $nested; + } + $html .= '', + 'after' => '
', + ]); + echo '