feat(topics): restore topic taxonomy workflow
This commit is contained in:
1 parent
f3dd1ec3b1
commit
a254cbd3e9
59 files changed
+771
-192
No files matched your search
@@ -60,6 +60,15 @@ export const pageDisplaySection = {
|
||||
canonicalDomain: 'page_display',
|
||||
section: 'tag',
|
||||
}),
|
||||
schemaPage({
|
||||
key: 'page-display-topics',
|
||||
name: 'PageDisplayTopics',
|
||||
label: '专题页面',
|
||||
route: '/page-display/topics',
|
||||
title: '专题页面',
|
||||
canonicalDomain: 'page_display',
|
||||
section: 'topics',
|
||||
}),
|
||||
schemaPage({
|
||||
key: 'page-display-user-home',
|
||||
name: 'PageDisplayUserHome',
|
||||
|
||||
@@ -63,12 +63,13 @@ export const searchSchema = {
|
||||
{ key: 'search_custom_key_s', label: '自定义匹配范围', type: 'switch', default: true, help: '启用后可配置搜索匹配字段范围' },
|
||||
{ key: 'search_custom_key', label: '匹配字段', type: 'checkbox', default: ['title', 'content', 'excerpt', 'category', 'post_tag'], dependsOn: { key: 'search_custom_key_s', value: true }, options: [
|
||||
{ label: '标题', value: 'title' }, { label: '内容', value: 'content' }, { label: '简介', value: 'excerpt' },
|
||||
{ label: '分类', value: 'category' }, { label: '标签', value: 'post_tag' },
|
||||
{ label: '分类', value: 'category' }, { label: '标签', value: 'post_tag' }, { label: '专题', value: 'topics' },
|
||||
{ label: '评论', value: 'coment' }, { label: '作者昵称', value: 'user' },
|
||||
] },
|
||||
{ key: 'search_facets', label: '搜索筛选', type: 'fieldset', sanitizeType: 'array', default: {}, dependsOn: { key: 'search_ms_s', value: false }, help: '搜索结果中显示的筛选列表;启用 Meilisearch 后由搜索引擎生成关联筛选。', fields: [
|
||||
{ key: 'category', label: '[文章] 分类', type: 'taxonomy_select', taxonomy: 'category', multiple: true, default: [] },
|
||||
{ key: 'post_tag', label: '[文章] 标签', type: 'taxonomy_select', taxonomy: 'post_tag', multiple: true, default: [] },
|
||||
{ key: 'topics', label: '[文章] 专题', type: 'taxonomy_select', taxonomy: 'topics', multiple: true, default: [] },
|
||||
] },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@ export const filterSchema = {
|
||||
key: 'filter_intro',
|
||||
type: 'content',
|
||||
ui_only: true,
|
||||
content: '<p class="jio-hint"><b>文章高级筛选功能:</b>通过此功能可实现更加复杂、精细化的内容筛选<br/>添加筛选类型和内容值之后,编写文章时候,可以进行选择,且在前台也可以实现精准筛选<br/>例如影视网站:[类型]有[剧情/喜剧/悬疑/惊悚/犯罪],[地区]有[大陆/美国/日韩/港台/印度],[年份]有[2022/2021/2020/10年代/00年代]等<br/><span class="jio-warn">注意事项:添加类型key时候,只能使用英文加下划线,不能有空格,且尽量复杂一点(不能为tag,category等系统已存在的类型),避免与其他mate_key重复!类型名称不能为分类、标签等系统已存在的类型</span></p>',
|
||||
content: '<p class="jio-hint"><b>文章高级筛选功能:</b>通过此功能可实现更加复杂、精细化的内容筛选<br/>添加筛选类型和内容值之后,编写文章时候,可以进行选择,且在前台也可以实现精准筛选<br/>例如影视网站:[类型]有[剧情/喜剧/悬疑/惊悚/犯罪],[地区]有[大陆/美国/日韩/港台/印度],[年份]有[2022/2021/2020/10年代/00年代]等<br/><span class="jio-warn">注意事项:添加类型key时候,只能使用英文加下划线,不能有空格,且尽量复杂一点(不能为tag,category,topics等系统已存在的类型),避免与其他mate_key重复!类型名称不能为分类、专题、标签等系统已存在的类型</span></p>',
|
||||
},
|
||||
{
|
||||
key: 'custom_filter_show',
|
||||
@@ -28,6 +28,7 @@ export const filterSchema = {
|
||||
options: [
|
||||
{ label: '分类页面显示', value: 'cat' },
|
||||
{ label: '标签页面显示', value: 'tag' },
|
||||
{ label: '专题页面显示', value: 'topics' },
|
||||
],
|
||||
description: '勾选后将会在对应页面默认显示全部筛选,您可以在下方为单独的分类添加自定义筛选',
|
||||
},
|
||||
@@ -87,6 +88,18 @@ export const filterSchema = {
|
||||
{ key: 'dropdown', label: '下拉列表', type: 'switch', default: false, description: '用下拉框显示更多内容' },
|
||||
],
|
||||
},
|
||||
{ key: 'topics_s', label: '专题筛选', type: 'switch', default: false, description: '在所选分类页显示的专题筛选列表' },
|
||||
{
|
||||
key: 'topics_lists',
|
||||
label: ' ',
|
||||
type: 'fieldset',
|
||||
default: { lists: [], dropdown: false },
|
||||
dependsOn: { key: 'topics_s', value: true },
|
||||
fields: [
|
||||
{ key: 'lists', label: '按钮列表', type: 'async_select', source: 'topics', multiple: true, sortable: true, default: [] },
|
||||
{ key: 'dropdown', label: '下拉列表', type: 'switch', default: false },
|
||||
],
|
||||
},
|
||||
{ key: 'orderby_s', label: '排序方式', type: 'switch', default: true, description: '在所选分类页显示排序方式按钮' },
|
||||
{
|
||||
key: 'orderby_lists',
|
||||
|
||||
@@ -13,11 +13,12 @@ export const listSchema = {
|
||||
post_list_author: true,
|
||||
post_list_time: true,
|
||||
list_meta_show: 'like',
|
||||
list_badge_show: ['pay', 'cat', 'tag'],
|
||||
list_badge_show: ['pay', 'tag', 'topics', 'cat'],
|
||||
list_show_type: 'separate',
|
||||
list_type: 'thumb',
|
||||
list_card_home: false,
|
||||
list_card_tag: false,
|
||||
list_card_topics: false,
|
||||
list_card_author: false,
|
||||
list_card_cat: [],
|
||||
list_list_option: { style: 'null', img_position: 'left', scale: 70 },
|
||||
@@ -39,7 +40,7 @@ export const listSchema = {
|
||||
{ label: '发布时间', value: 'date' }, { label: '更新时间', value: 'modified' },
|
||||
] },
|
||||
{ key: 'sticky_s', label: '显示置顶文章', type: 'checkbox', default: ['home', 'cat'], options: [
|
||||
{ label: '首页', value: 'home' }, { label: '分类页', value: 'cat' }, { label: '标签页', value: 'tag' },
|
||||
{ label: '首页', value: 'home' }, { label: '分类页', value: 'cat' }, { label: '标签页', value: 'tag' }, { label: '专题页', value: 'topics' },
|
||||
] },
|
||||
],
|
||||
},
|
||||
@@ -52,8 +53,8 @@ export const listSchema = {
|
||||
{ key: 'list_meta_show', label: '列表小部件(移动端优先)', type: 'radio', default: 'like', options: [
|
||||
{ label: '阅读量', value: 'view' }, { label: '点赞数', value: 'like' }, { label: '评论', value: 'comm' },
|
||||
] },
|
||||
{ key: 'list_badge_show', label: '显示列表标签', type: 'checkbox', default: ['pay', 'cat', 'tag'], options: [
|
||||
{ label: '付费信息', value: 'pay' }, { label: '分类', value: 'cat' }, { label: '标签', value: 'tag' },
|
||||
{ key: 'list_badge_show', label: '显示列表标签', type: 'checkbox', default: ['pay', 'tag', 'topics', 'cat'], options: [
|
||||
{ label: '付费信息', value: 'pay' }, { label: '分类', value: 'cat' }, { label: '专题', value: 'topics' }, { label: '标签', value: 'tag' },
|
||||
] },
|
||||
],
|
||||
},
|
||||
@@ -70,8 +71,9 @@ export const listSchema = {
|
||||
], help: '文字、自动图文和多图模式仅在开启侧栏的页面有效。' },
|
||||
{ key: 'list_card_home', label: '首页列表卡片模式', type: 'switch', default: false, dependsOn: { key: 'list_type', not: true, value: 'card' } },
|
||||
{ key: 'list_card_tag', label: '标签页列表卡片模式', type: 'switch', default: false, dependsOn: { key: 'list_type', not: true, value: 'card' } },
|
||||
{ key: 'list_card_topics', label: '专题页列表卡片模式', type: 'switch', default: false, dependsOn: { key: 'list_type', not: true, value: 'card' } },
|
||||
{ key: 'list_card_author', label: '用户页列表卡片模式', type: 'switch', default: false, dependsOn: { key: 'list_type', not: true, value: 'card' } },
|
||||
{ key: 'list_card_cat', label: '分类页自定义卡片模式', type: 'taxonomy_select', taxonomy: 'category', multiple: true, default: [], dependsOn: { key: 'list_type', not: true, value: 'card' } },
|
||||
{ key: 'list_card_cat', label: '分类、专题页自定义卡片模式', type: 'taxonomy_select', taxonomy: 'category,topics', multiple: true, default: [], dependsOn: { key: 'list_type', not: true, value: 'card' } },
|
||||
{ key: 'list_list_option', label: '列表模式 UI 配置', type: 'fieldset', default: { style: 'null', img_position: 'left', scale: 70 }, fields: [
|
||||
{ key: 'style', label: '列表样式', type: 'radio', default: 'null', options: [
|
||||
{ label: '默认', value: 'null' }, { label: '样式 2', value: 'style2' },
|
||||
|
||||
@@ -7,6 +7,8 @@ export const submitSchema = {
|
||||
post_article_s: true,
|
||||
post_article_btn_txte: '发布文章',
|
||||
post_article_cat: [],
|
||||
post_article_topics_s: false,
|
||||
post_article_topics: [],
|
||||
post_article_custom_filter_s: true,
|
||||
post_article_tag: true,
|
||||
post_article_user: 1,
|
||||
@@ -34,6 +36,8 @@ export const submitSchema = {
|
||||
},
|
||||
{ key: 'post_article_btn_txte', label: '按钮文字', type: 'input', default: '发布文章', dependsOn: { key: 'post_article_s', value: true }, description: '投稿按钮的显示的文字,推荐4个字更加协调' },
|
||||
{ key: 'post_article_cat', label: '投稿允许选择的分类', type: 'taxonomy_select', taxonomy: 'category', multiple: true, default: [], placeholder: '输入关键词以搜索分类', dependsOn: { key: 'post_article_s', value: true }, description: '投稿允许选择的分类,为空则允许选择全部分类,所选分类下如果有子分类则会自动显示,如果选择了上级分类,则不要再选该分类下的子分类。注意:请确保所选分类包含子分类总数不要超过50个,否则可能会引起页面崩溃' },
|
||||
{ key: 'post_article_topics_s', label: '允许选择专题', type: 'switch', default: false, dependsOn: { key: 'post_article_s', value: true } },
|
||||
{ key: 'post_article_topics', label: '投稿允许选择的专题', type: 'taxonomy_select', taxonomy: 'topics', multiple: true, default: [], dependsOn: { all: [{ key: 'post_article_s', value: true }, { key: 'post_article_topics_s', value: true }] } },
|
||||
{ key: 'post_article_custom_filter_s', label: '允许选择高级筛选', type: 'switch', default: true, dependsOn: { key: 'post_article_s', value: true } },
|
||||
{
|
||||
key: 'submit_filter_notice',
|
||||
|
||||
@@ -19,9 +19,10 @@ type Props = {
|
||||
options: CategoryOption[];
|
||||
value: number[];
|
||||
onChange: (ids: number[]) => void;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
export function CategorySelect({ options, value, onChange }: Props) {
|
||||
export function CategorySelect({ options, value, onChange, label = __('分类', 'jio') }: Props) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [query, setQuery] = useState('');
|
||||
const { triggerRef, panelRef, position } = useAnchoredPanel<HTMLDivElement>({
|
||||
@@ -71,16 +72,16 @@ export function CategorySelect({ options, value, onChange }: Props) {
|
||||
<input
|
||||
type="search"
|
||||
value={query}
|
||||
placeholder={__('搜索分类', 'jio')}
|
||||
aria-label={__('搜索分类', 'jio')}
|
||||
placeholder={sprintf(__('搜索%s', 'jio'), label)}
|
||||
aria-label={sprintf(__('搜索%s', 'jio'), label)}
|
||||
// 打开即可输入:分类列表通常很长,键盘操作比翻找更快。
|
||||
autoFocus
|
||||
onChange={(event) => setQuery(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="jio-creator-picker__list" aria-label={__('分类', 'jio')}>
|
||||
<div className="jio-creator-picker__list" aria-label={label}>
|
||||
{filtered.length === 0 && (
|
||||
<p className="jio-creator-picker__empty">{__('没有匹配的分类', 'jio')}</p>
|
||||
<p className="jio-creator-picker__empty">{sprintf(__('没有匹配的%s', 'jio'), label)}</p>
|
||||
)}
|
||||
{filtered.map((option) => {
|
||||
const active = selected.has(option.id);
|
||||
@@ -133,7 +134,7 @@ export function CategorySelect({ options, value, onChange }: Props) {
|
||||
>
|
||||
<span className="jio-creator-select__tokens">
|
||||
{chosen.length === 0 ? (
|
||||
<span className="jio-creator-select__placeholder">{__('选择分类(可多选)', 'jio')}</span>
|
||||
<span className="jio-creator-select__placeholder">{sprintf(__('选择%s(可多选)', 'jio'), label)}</span>
|
||||
) : (
|
||||
chosen.map((option) => (
|
||||
<span key={option.id} className="jio-creator-select__token">
|
||||
@@ -143,7 +144,7 @@ export function CategorySelect({ options, value, onChange }: Props) {
|
||||
<button
|
||||
type="button"
|
||||
className="jio-creator-select__token-x"
|
||||
aria-label={sprintf(__('移除分类 %s', 'jio'), option.name)}
|
||||
aria-label={sprintf(__('移除%s %s', 'jio'), label, option.name)}
|
||||
onClick={(event) => {
|
||||
// 令牌上的叉号只移除这一项,不要顺带展开面板。
|
||||
event.stopPropagation();
|
||||
|
||||
@@ -19,6 +19,7 @@ type Featured = { type: string; data: Record<string, any>; mediaId?: number };
|
||||
|
||||
export type TaxonomyDef = {
|
||||
categories: CategoryOption[];
|
||||
topics: { enabled: boolean; items: CategoryOption[] };
|
||||
/** 标签是否开放;开放时附带站点已有标签,用于输入建议。 */
|
||||
tags: { enabled: boolean; suggestions: string[] };
|
||||
customDefs: Array<{ key: string; name: string; values: Array<{ key: string; name: string }> }>;
|
||||
@@ -34,12 +35,14 @@ type Props = {
|
||||
canPay: boolean;
|
||||
taxonomy: TaxonomyDef;
|
||||
categories: number[];
|
||||
topics: number[];
|
||||
tags: string[];
|
||||
custom: Record<string, string[]>;
|
||||
onFeaturedChange: (featured: Featured) => void;
|
||||
onScheduleChange: (enabled: boolean, at: string) => void;
|
||||
onPayEnabledChange: (enabled: boolean) => void;
|
||||
onCategoriesChange: (categories: number[]) => void;
|
||||
onTopicsChange: (topics: number[]) => void;
|
||||
onTagsChange: (tags: string[]) => void;
|
||||
onCustomChange: (custom: Record<string, string[]>) => void;
|
||||
/** 打开发布抽屉并直接定位到付费配置。 */
|
||||
@@ -69,12 +72,14 @@ export function PublishSettings({
|
||||
canPay,
|
||||
taxonomy,
|
||||
categories,
|
||||
topics,
|
||||
tags,
|
||||
custom,
|
||||
onFeaturedChange,
|
||||
onScheduleChange,
|
||||
onPayEnabledChange,
|
||||
onCategoriesChange,
|
||||
onTopicsChange,
|
||||
onTagsChange,
|
||||
onCustomChange,
|
||||
onOpenPaySettings,
|
||||
@@ -141,6 +146,13 @@ export function PublishSettings({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{taxonomy.topics.enabled && taxonomy.topics.items.length > 0 && (
|
||||
<div className="jio-creator__setting-row jio-creator__setting-row--stack">
|
||||
<div className="jio-creator__setting-copy"><span className="jio-creator__setting-label">{__('专题', 'jio')}</span></div>
|
||||
<CategorySelect options={taxonomy.topics.items} value={topics} onChange={onTopicsChange} label={__('专题', 'jio')} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{taxonomy.tags.enabled && (
|
||||
<div className="jio-creator__setting-row jio-creator__setting-row--stack">
|
||||
<div className="jio-creator__setting-copy">
|
||||
|
||||
@@ -57,6 +57,7 @@ export type Draft = {
|
||||
content: string;
|
||||
schedule: Schedule;
|
||||
categories: number[];
|
||||
topics: number[];
|
||||
tags: string[];
|
||||
custom: Record<string, string[]>;
|
||||
featured: Featured;
|
||||
@@ -66,6 +67,7 @@ export type Draft = {
|
||||
export function initialDraft(bootstrap: Record<string, any>): Draft {
|
||||
const pay = bootstrap.pay || {};
|
||||
const selected = (bootstrap.categories && bootstrap.categories.selected) || [];
|
||||
const selectedTopics = (bootstrap.topics && bootstrap.topics.selected) || [];
|
||||
const tags = (bootstrap.tags && bootstrap.tags.items) || [];
|
||||
return {
|
||||
postId: Number(bootstrap.sourceId || 0),
|
||||
@@ -75,6 +77,7 @@ export function initialDraft(bootstrap: Record<string, any>): Draft {
|
||||
content: String(bootstrap.content || ''),
|
||||
schedule: { enabled: false, at: '' },
|
||||
categories: selected.map(Number),
|
||||
topics: selectedTopics.map(Number),
|
||||
tags: tags.slice(),
|
||||
custom: bootstrap.custom || {},
|
||||
featured: bootstrap.featured || { type: '', data: {} },
|
||||
|
||||
@@ -207,6 +207,7 @@ function Studio(): JSX.Element {
|
||||
title: current.title,
|
||||
content: current.content,
|
||||
categories: current.categories,
|
||||
topics: current.topics,
|
||||
tags: current.tags,
|
||||
custom: current.custom,
|
||||
featured: current.featured,
|
||||
@@ -859,6 +860,10 @@ function Studio(): JSX.Element {
|
||||
canPay={!!capabilities.canPay}
|
||||
taxonomy={{
|
||||
categories: (bootstrap.categories && bootstrap.categories.items) || [],
|
||||
topics: {
|
||||
enabled: !!bootstrap.topics?.enabled,
|
||||
items: (bootstrap.topics && bootstrap.topics.items) || [],
|
||||
},
|
||||
tags: {
|
||||
enabled: !!bootstrap.tags?.enabled,
|
||||
suggestions: (bootstrap.tags && bootstrap.tags.suggestions) || [],
|
||||
@@ -866,12 +871,14 @@ function Studio(): JSX.Element {
|
||||
customDefs: bootstrap.customDefs || [],
|
||||
}}
|
||||
categories={draft.categories}
|
||||
topics={draft.topics}
|
||||
tags={draft.tags}
|
||||
custom={draft.custom}
|
||||
onFeaturedChange={(featured) => patchDraft({ featured })}
|
||||
onScheduleChange={(enabled, at) => patchDraft({ schedule: { enabled, at } })}
|
||||
onPayEnabledChange={(enabled) => patchDraft({ pay: { ...draftRef.current.pay, enabled } })}
|
||||
onCategoriesChange={(categories) => patchDraft({ categories })}
|
||||
onTopicsChange={(topics) => patchDraft({ topics })}
|
||||
onTagsChange={(tags) => patchDraft({ tags })}
|
||||
onCustomChange={(custom) => patchDraft({ custom })}
|
||||
onOpenPaySettings={() => setDrawerOpen(true)}
|
||||
|
||||
Reference in new issue
Block a user