feat(creator-studio): icon toolbar with block tools, drop author strip
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
7bdf7cf018
commit
7c33482be7
19 files changed
+600
-241
No files matched your search
@@ -7,18 +7,18 @@
|
||||
* @package Jio
|
||||
*/
|
||||
|
||||
import { createRoot, useCallback, useEffect, useMemo, useRef, useState } from '@wordpress/element';
|
||||
import { createRoot, useCallback, useEffect, useRef, useState } from '@wordpress/element';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
|
||||
import { apiPost } from './services/api';
|
||||
import { PublishDrawer } from './panels/publish-drawer';
|
||||
import { EditorToolbar } from './components/editor-toolbar';
|
||||
import { PublishSettings } from './components/publish-settings';
|
||||
import { AuthorRow } from './components/author-row';
|
||||
import { SaveState, type SaveStateValue } from './components/save-state';
|
||||
import { useAutosave } from './hooks/use-autosave';
|
||||
import { useLocalRecovery } from './hooks/use-local-recovery';
|
||||
import { normalizePayForRequest } from './utils/pay';
|
||||
import { codeBlockMarkup, dividerMarkup, footnoteMarkup, listMarkup, mathMarkup, tableMarkup, tocMarkup } from './utils/block-markup';
|
||||
import './styles/studio.scss';
|
||||
|
||||
const bootstrap: Record<string, any> = window['jioCreatorStudio'] || {};
|
||||
@@ -184,8 +184,6 @@ function Studio(): JSX.Element {
|
||||
setFormatValue(['h1', 'h2', 'h3', 'blockquote'].includes(name) ? name : 'p');
|
||||
}, []);
|
||||
|
||||
const charCount = useMemo(() => Array.from(plainText(draft.content)).length, [draft.content]);
|
||||
|
||||
const buildPayload = useCallback((extra: Record<string, any> = {}) => {
|
||||
const current = draftRef.current;
|
||||
return {
|
||||
@@ -510,7 +508,31 @@ function Studio(): JSX.Element {
|
||||
}
|
||||
}, [focusEditor]);
|
||||
|
||||
const openMedia = useCallback((type: 'image' | 'video') => {
|
||||
const insertBlock = useCallback((kind: string) => {
|
||||
const editor = focusEditor();
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
const markup: Record<string, string> = {
|
||||
list: listMarkup(false),
|
||||
toc: tocMarkup(),
|
||||
divider: dividerMarkup(),
|
||||
code: codeBlockMarkup(),
|
||||
footnote: footnoteMarkup(),
|
||||
math: mathMarkup(),
|
||||
table: tableMarkup(),
|
||||
};
|
||||
const html = markup[kind];
|
||||
if (!html) {
|
||||
return;
|
||||
}
|
||||
editor.insertContent(html);
|
||||
editor.nodeChanged();
|
||||
updateContent(editor.getContent());
|
||||
updateHistoryAvailability(editor);
|
||||
}, [focusEditor]);
|
||||
|
||||
const openMedia = useCallback((type: 'image' | 'video' | 'file') => {
|
||||
const editor = editorRef.current;
|
||||
const media = (window as any).JioSubmitMedia;
|
||||
if (!editor || !media || typeof media.open !== 'function') {
|
||||
@@ -535,6 +557,10 @@ function Studio(): JSX.Element {
|
||||
const fullAttribute = fullUrl ? ` data-full-url="${escapeAttribute(fullUrl)}"` : '';
|
||||
return `<p><img src="${escapeAttribute(url)}"${idAttribute} alt="${escapeAttribute(String(item.name || item.title || ''))}"${fullAttribute}></p>`;
|
||||
}
|
||||
if (type === 'file') {
|
||||
const name = String(item.filename || item.name || url.split('/').pop() || '');
|
||||
return `<p><a class="jio-file-link" href="${escapeAttribute(url)}"${idAttribute}><i class="fa fas fa-paperclip" aria-hidden="true"></i> ${escapeAttribute(name)}</a></p>`;
|
||||
}
|
||||
return `<div contenteditable="false" data-video-url="${escapeAttribute(url)}" data-video-name="${escapeAttribute(String(item.filename || item.name || url))}"${idAttribute} class="new-dplayer post-dplayer dplayer"></div><p></p>`;
|
||||
}).join('');
|
||||
if (markup) {
|
||||
@@ -572,8 +598,8 @@ function Studio(): JSX.Element {
|
||||
|
||||
<EditorToolbar
|
||||
ready={editorReady}
|
||||
formatValue={formatValue}
|
||||
onFormatChange={setFormatValue}
|
||||
formatValue={formatValue}
|
||||
onFormatChange={setFormatValue}
|
||||
canUndo={historyAvailability.canUndo}
|
||||
canRedo={historyAvailability.canRedo}
|
||||
capabilities={capabilities}
|
||||
@@ -581,6 +607,7 @@ function Studio(): JSX.Element {
|
||||
onRememberSelection={rememberSelection}
|
||||
onOpenLink={openLink}
|
||||
onOpenMedia={openMedia}
|
||||
onInsertBlock={insertBlock}
|
||||
/>
|
||||
<div className="jio-creator__bar-actions jio-creator__toolbar-extension" data-toolbar-extension aria-label={__('工具扩展区', 'jio')}>
|
||||
<SaveState value={saveState} />
|
||||
@@ -618,8 +645,6 @@ function Studio(): JSX.Element {
|
||||
)}
|
||||
|
||||
<main className="jio-creator__canvas">
|
||||
<AuthorRow author={bootstrap.author || {}} />
|
||||
|
||||
<label className="jio-creator__title">
|
||||
<span className="screen-reader-text">{__('文章标题', 'jio')}</span>
|
||||
<textarea
|
||||
@@ -651,11 +676,6 @@ function Studio(): JSX.Element {
|
||||
onScheduleChange={(enabled, at) => patchDraft({ schedule: { enabled, at } })}
|
||||
/>
|
||||
|
||||
<footer className="jio-creator__footer">
|
||||
<span>{__('字数', 'jio')}:{charCount}</span>
|
||||
<span>{__('约', 'jio')} {Math.max(1, Math.round(charCount / 400))} {__('分钟阅读', 'jio')}</span>
|
||||
</footer>
|
||||
|
||||
{drawerOpen && (
|
||||
<PublishDrawer
|
||||
draft={draft}
|
||||
|
||||
Reference in new issue
Block a user