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
@@ -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