feat(creator-studio): dialog-driven table/math/footnote, theme quote, code language picker

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Opus 5 committed 2026-11-06 23:23:59 +08:00
1 parent 7c33482be7
commit 7885f42cff
14 files changed
+1005 -54

No files matched your search

@@ -7,6 +7,7 @@
* @package Jio
*/
import { useEffect, useRef, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
type Capabilities = Record<string, boolean>;
@@ -23,6 +24,7 @@ type Props = {
onOpenLink: () => void;
onOpenMedia: (type: 'image' | 'video' | 'file') => void;
onInsertBlock: (kind: string) => void;
onInsertQuote: (color: '' | 'qe_wzk_c-red' | 'qe_wzk_lan' | 'qe_wzk_lv') => void;
};
type ToolButtonProps = {
@@ -61,7 +63,34 @@ export function EditorToolbar({
onOpenLink,
onOpenMedia,
onInsertBlock,
onInsertQuote,
}: Props) {
const [quoteOpen, setQuoteOpen] = useState(false);
const quoteRef = useRef<HTMLDivElement | null>(null);
// 点击别处或按 Esc 收起引用样式菜单。
useEffect(() => {
if (!quoteOpen) {
return undefined;
}
const onPointerDown = (event: PointerEvent) => {
if (!quoteRef.current?.contains(event.target as Node)) {
setQuoteOpen(false);
}
};
const onKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
setQuoteOpen(false);
}
};
document.addEventListener('pointerdown', onPointerDown);
document.addEventListener('keydown', onKeyDown);
return () => {
document.removeEventListener('pointerdown', onPointerDown);
document.removeEventListener('keydown', onKeyDown);
};
}, [quoteOpen]);
return (
<div
className="jio-creator__toolbar-tools"
@@ -112,7 +141,33 @@ export function EditorToolbar({
<div className="jio-creator__toolbar-group" role="group" aria-label={__('段落块', 'jio')}>
<ToolButton label={__('列表', 'jio')} icon="fa fas fa-list-ul" ready={ready} onClick={() => onInsertBlock('list')} />
<ToolButton label={__('目录', 'jio')} icon="fa fas fa-list-ol" ready={ready} onClick={() => onInsertBlock('toc')} />
<ToolButton label={__('引用', 'jio')} icon="fa fas fa-quote-left" ready={ready} onClick={() => onCommand('format', 'blockquote')} />
<div className="jio-creator__quote" ref={quoteRef}>
<ToolButton label={__('引用', 'jio')} icon="fa fas fa-quote-left" ready={ready} onClick={() => setQuoteOpen((open) => !open)} />
{quoteOpen && (
<div className="jio-creator__quote-menu" role="menu" aria-label={__('引用样式', 'jio')}>
{[
{ key: '' as const, label: __('灰色引用', 'jio'), className: '' },
{ key: 'qe_wzk_c-red' as const, label: __('红色引用', 'jio'), className: 'is-red' },
{ key: 'qe_wzk_lan' as const, label: __('蓝色引用', 'jio'), className: 'is-blue' },
{ key: 'qe_wzk_lv' as const, label: __('绿色引用', 'jio'), className: 'is-green' },
].map((option) => (
<button
key={option.key || 'default'}
type="button"
role="menuitem"
className={`jio-creator__quote-option ${option.className}`.trim()}
onClick={() => {
setQuoteOpen(false);
onInsertQuote(option.key);
}}
>
<span className="jio-creator__quote-swatch" aria-hidden="true" />
{option.label}
</button>
))}
</div>
)}
</div>
<ToolButton label={__('分割线', 'jio')} icon="fa fas fa-minus" ready={ready} onClick={() => onInsertBlock('divider')} />
<ToolButton label={__('代码块', 'jio')} icon="fa fas fa-code" ready={ready} onClick={() => onInsertBlock('code')} />
<ToolButton label={__('注释', 'jio')} icon="fa fas fa-comment-dots" ready={ready} onClick={() => onInsertBlock('footnote')} />