Refine UI for categories hiden

pull/6116/head
Ryan Wang 2024-06-26 19:25:10 +08:00 committed by guqing
parent 0196315228
commit bc1033611e
11 changed files with 81 additions and 1 deletions

View File

@ -27,6 +27,7 @@ import run.halo.app.extension.GroupVersionKind;
public class Category extends AbstractExtension { public class Category extends AbstractExtension {
public static final String KIND = "Category"; public static final String KIND = "Category";
public static final String LAST_HIDDEN_STATE_ANNO = "content.halo.run/last-hidden-state";
public static final GroupVersionKind GVK = GroupVersionKind.fromExtension(Category.class); public static final GroupVersionKind GVK = GroupVersionKind.fromExtension(Category.class);
@ -79,6 +80,15 @@ public class Category extends AbstractExtension {
* and B will be queried, but C and D will not be queried.</p> * and B will be queried, but C and D will not be queried.</p>
*/ */
private boolean preventParentPostCascadeQuery; private boolean preventParentPostCascadeQuery;
/**
* <p>Whether to hide the category from the category list.</p>
* <p>When set to true, the category including its subcategories and related posts will
* not be displayed in the category list, but it can still be accessed by permalink.</p>
* <p>Limitation: It only takes effect on the theme-side categorized list and it only
* allows to be set to true on the first level(root node) of categories.</p>
*/
private boolean hideFromList;
} }
@JsonIgnore @JsonIgnore

View File

@ -168,6 +168,11 @@ public class Post extends AbstractExtension {
private List<String> contributors; private List<String> contributors;
/**
* see {@link Category.CategorySpec#isHideFromList()}.
*/
private Boolean hideFromList;
private Instant lastModifyTime; private Instant lastModifyTime;
private Long observedVersion; private Long observedVersion;

View File

@ -21,7 +21,7 @@ public class NotEqual extends SimpleQuery {
indexView.acquireReadLock(); indexView.acquireReadLock();
try { try {
NavigableSet<String> equalNames = equalQuery.matches(indexView); NavigableSet<String> equalNames = equalQuery.matches(indexView);
NavigableSet<String> allNames = indexView.getIdsForField(fieldName); NavigableSet<String> allNames = indexView.getAllIds();
allNames.removeAll(equalNames); allNames.removeAll(equalNames);
return allNames; return allNames;
} finally { } finally {

View File

@ -26,10 +26,12 @@ const props = withDefaults(
defineProps<{ defineProps<{
category?: Category; category?: Category;
parentCategory?: Category; parentCategory?: Category;
isChildLevelCategory: boolean;
}>(), }>(),
{ {
category: undefined, category: undefined,
parentCategory: undefined, parentCategory: undefined,
isChildLevelCategory: false,
} }
); );
@ -266,6 +268,22 @@ const { handleGenerateSlug } = useSlugify(
:accepts="['image/*']" :accepts="['image/*']"
validation="length:0,1024" validation="length:0,1024"
></FormKit> ></FormKit>
<FormKit
v-model="formState.spec.hideFromList"
:disabled="isChildLevelCategory"
:label="
$t(
'core.post_category.editing_modal.fields.hide_from_list.label'
)
"
:help="
$t(
'core.post_category.editing_modal.fields.hide_from_list.help'
)
"
type="checkbox"
name="hideFromList"
></FormKit>
<FormKit <FormKit
v-model="formState.spec.preventParentPostCascadeQuery" v-model="formState.spec.preventParentPostCascadeQuery"
:label=" :label="

View File

@ -5,6 +5,7 @@ import type { Category } from "@halo-dev/api-client";
import { coreApiClient } from "@halo-dev/api-client"; import { coreApiClient } from "@halo-dev/api-client";
import { import {
Dialog, Dialog,
IconEyeOff,
IconList, IconList,
Toast, Toast,
VDropdownItem, VDropdownItem,
@ -23,6 +24,8 @@ import CategoryEditingModal from "./CategoryEditingModal.vue";
const { currentUserHasPermission } = usePermission(); const { currentUserHasPermission } = usePermission();
withDefaults(defineProps<{ isChildLevel?: boolean }>(), {});
const categories = defineModel({ const categories = defineModel({
type: Array as PropType<CategoryTree[]>, type: Array as PropType<CategoryTree[]>,
default: [], default: [],
@ -95,6 +98,7 @@ const handleDelete = async (category: CategoryTree) => {
> >
<CategoryEditingModal <CategoryEditingModal
v-if="editingModal" v-if="editingModal"
:is-child-level-category="isChildLevel"
:category="selectedCategory" :category="selectedCategory"
:parent-category="selectedParentCategory" :parent-category="selectedParentCategory"
@close="onEditingModalClose" @close="onEditingModalClose"
@ -134,6 +138,14 @@ const handleDelete = async (category: CategoryTree) => {
/> />
</template> </template>
</VEntityField> </VEntityField>
<VEntityField v-if="category.spec.hideFromList">
<template #description>
<IconEyeOff
v-tooltip="$t('core.post_category.list.fields.hide_from_list')"
class="cursor-pointer text-sm transition-all hover:text-blue-600"
/>
</template>
</VEntityField>
<VEntityField v-if="category.spec.preventParentPostCascadeQuery"> <VEntityField v-if="category.spec.preventParentPostCascadeQuery">
<template #description> <template #description>
<GridiconsLinkBreak <GridiconsLinkBreak
@ -185,6 +197,7 @@ const handleDelete = async (category: CategoryTree) => {
</VEntity> </VEntity>
<CategoryListItem <CategoryListItem
v-model="category.spec.children" v-model="category.spec.children"
is-child-level
class="pl-10 transition-all duration-300" class="pl-10 transition-all duration-300"
@change="onChange" @change="onChange"
/> />

View File

@ -44,6 +44,12 @@ export interface CategorySpec {
* @memberof CategorySpec * @memberof CategorySpec
*/ */
'displayName': string; 'displayName': string;
/**
*
* @type {boolean}
* @memberof CategorySpec
*/
'hideFromList'?: boolean;
/** /**
* *
* @type {string} * @type {string}

View File

@ -47,6 +47,12 @@ export interface PostStatus {
* @memberof PostStatus * @memberof PostStatus
*/ */
'excerpt'?: string; 'excerpt'?: string;
/**
*
* @type {boolean}
* @memberof PostStatus
*/
'hideFromList'?: boolean;
/** /**
* *
* @type {boolean} * @type {boolean}

View File

@ -47,6 +47,12 @@ export interface SinglePageStatus {
* @memberof SinglePageStatus * @memberof SinglePageStatus
*/ */
'excerpt'?: string; 'excerpt'?: string;
/**
*
* @type {boolean}
* @memberof SinglePageStatus
*/
'hideFromList'?: boolean;
/** /**
* *
* @type {boolean} * @type {boolean}

View File

@ -416,11 +416,19 @@ core:
help: >- help: >-
Customize the rendering template of posts in the current category, Customize the rendering template of posts in the current category,
which requires support from the theme which requires support from the theme
hide_from_list:
label: Hide from list
help: >-
After turning on this option, this category and its subcategories,
as well as its posts, will not be displayed in the front-end list.
You need to actively visit the category archive page. This feature
is only effective for the first-level directory.
list: list:
fields: fields:
prevent_parent_post_cascade_query: >- prevent_parent_post_cascade_query: >-
Prevent parent category from including this category and its Prevent parent category from including this category and its
subcategories in cascade post queries subcategories in cascade post queries
hide_from_list: This category is hidden, This category and its subcategories, as well as its posts, will not be displayed in the front-end list. You need to actively visit the category archive page
page: page:
title: Pages title: Pages
actions: actions:

View File

@ -406,9 +406,13 @@ core:
post_template: post_template:
label: 自定义文章模板 label: 自定义文章模板
help: 自定义当前分类下文章的渲染模版,需要主题提供支持 help: 自定义当前分类下文章的渲染模版,需要主题提供支持
hide_from_list:
label: 在列表中隐藏
help: 开启此选项后,此分类和其下子分类,以及其下文章将不会显示在前台的列表中,需要主动访问分类归档页面,此功能仅对第一级目录生效
list: list:
fields: fields:
prevent_parent_post_cascade_query: 阻止父级分类在级联文章查询中包含此分类及其子分类 prevent_parent_post_cascade_query: 阻止父级分类在级联文章查询中包含此分类及其子分类
hide_from_list: 已隐藏,此分类和其下子分类,以及其下文章将不会显示在前台的列表中
page: page:
title: 页面 title: 页面
actions: actions:

View File

@ -386,9 +386,13 @@ core:
post_template: post_template:
label: 自定義文章模板 label: 自定義文章模板
help: 自定義當前分類下文章的渲染模板,需要主題提供支持 help: 自定義當前分類下文章的渲染模板,需要主題提供支持
hide_from_list:
label: 在列表中隱藏
help: 開啟此選項後,此分類和其下子分類,以及其下文章將不會顯示在前臺的列表中,需要主動訪問分類歸檔頁面,此功能僅對第一級目錄生效
list: list:
fields: fields:
prevent_parent_post_cascade_query: 阻止父級分類在級聯文章查詢中包含此分類及其子分類 prevent_parent_post_cascade_query: 阻止父級分類在級聯文章查詢中包含此分類及其子分類
hide_from_list: 已隱藏,此分類和其下子分類,以及其下文章將不會顯示在前臺的列表中,需要主動訪問分類歸檔頁面
page: page:
title: 頁面 title: 頁面
actions: actions: