fix(creator-studio): 沉浸式布局与公众号式写作体验

首轮实机体验暴露的问题:

- 投稿页仍在渲染主题头部的 all_top_fluid 挂件区、页脚与浮动入口,
  与工作台顶栏重复。header.php / footer.php 新增 jio_render_header、
  jio_render_footer、jio_render_fluid_widgets 过滤器,工作台模式下全部关闭
- 区块 Inspector 被写在 BlockList 之后,作为正文流的一部分渲染出
  一个巨大的「未选择区块」白框;移除内联 Inspector(区块设置改由
  行内工具栏的区块菜单提供)
- 中文正文被 wordcount 的 'words' 口径算成「字数:1」;改用
  characters_excluding_spaces,与前台 TinyMCE 字数一致
- 行宽 820px、标题 34px 偏松散;收窄到 720px / 27px,正文 16px/1.85,
  段落间距与选区描边收敛,行内工具栏改为深色圆角悬浮条

新增本地视觉验收脚本(不参与运行时):
- scripts/preview.cjs:用模拟 bootstrap 生成离线预览页
- scripts/shoot.cjs:桌面/移动端截图与控制台错误采集

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Opus 5 committed 2026-11-06 15:49:57 +08:00
1 parent 2c7262770b
commit d07cffe99e
10 files changed
+272 -39

No files matched your search

+10 -7
View File
@@ -12,7 +12,7 @@ import { createRoot, useCallback, useEffect, useMemo, useRef, useState } from '@
import { parse, serialize } from '@wordpress/blocks';
import { registerCoreBlocks } from '@wordpress/block-library';
import { useSelect } from '@wordpress/data';
import { BlockEditorProvider, BlockList, BlockTools, BlockInspector } from '@wordpress/block-editor';
import { BlockEditorProvider, BlockList, BlockTools } from '@wordpress/block-editor';
import { count as countWords } from '@wordpress/wordcount';
import { __ } from '@wordpress/i18n';
@@ -133,7 +133,13 @@ function Studio(): JSX.Element {
}, []);
const serialized = useMemo(() => serialize(blocks), [blocks]);
const words = useMemo(() => countWords(serialized.replace(/<[^>]*>/g, ' '), 'words', {}), [serialized]);
// 中文没有空格分词,wordcount 的 'words' 会把整段算成 1。
// 'characters_excluding_spaces' 才是中文场景该用的口径(与前台 TinyMCE 字数一致)。
const charCount = useMemo(() => {
const text = serialized.replace(/<[^>]*>/g, ' ');
return countWords(text, 'characters_excluding_spaces', {});
}, [serialized]);
const buildPayload = useCallback(
(extra: Record<string, any> = {}) => ({
@@ -400,16 +406,13 @@ function Studio(): JSX.Element {
<BlockTools>
<BlockList />
</BlockTools>
<aside className="jio-creator__inspector" aria-label={__('区块设置', 'jio')}>
<BlockInspector />
</aside>
</BlockEditorProvider>
</div>
<footer className="jio-creator__footer">
<span>{__('字数', 'jio')}:{words}</span>
<span>{__('字数', 'jio')}:{charCount}</span>
<span>
{__('约', 'jio')} {Math.max(1, Math.round(words / 400))} {__('分钟阅读', 'jio')}
{__('约', 'jio')} {Math.max(1, Math.round(charCount / 400))} {__('分钟阅读', 'jio')}
</span>
</footer>
</main>
+63 -26
View File
@@ -218,26 +218,28 @@ $warn: #b4573f;
}
.jio-creator__canvas {
width: min(820px, 100%);
/* 公众号式阅读宽度:正文行宽控制在约 40 个汉字,留白优先。 */
width: min(720px, 100%);
margin: 0 auto;
padding: clamp(24px, 5vw, 56px) clamp(16px, 4vw, 40px) 120px;
padding: clamp(20px, 4vw, 44px) clamp(20px, 5vw, 52px) 140px;
}
.jio-creator__title {
display: block;
margin-bottom: 8px;
margin-bottom: 6px;
textarea {
width: 100%;
min-height: 56px;
min-height: 50px;
padding: 0;
border: 0;
background: transparent;
color: var(--jc-ink);
font-family: "Songti SC", "Noto Serif SC", "Source Han Serif SC", serif;
font-size: clamp(26px, 3.4vw, 34px);
font-weight: 600;
line-height: 1.35;
font-size: clamp(23px, 2.6vw, 27px);
font-weight: 500;
letter-spacing: 0.01em;
line-height: 1.4;
resize: none;
&:focus {
@@ -252,29 +254,28 @@ $warn: #b4573f;
.jio-creator__excerpt {
display: block;
margin-bottom: 28px;
margin-bottom: 22px;
> span {
display: block;
margin-bottom: 6px;
color: var(--jc-ink-soft);
margin-bottom: 4px;
color: #9aa8a2;
font-size: 12px;
letter-spacing: 0.02em;
}
textarea {
width: 100%;
padding: 8px 0;
padding: 6px 0;
border: 0;
border-bottom: 1px solid var(--jc-line);
background: transparent;
color: var(--jc-ink-soft);
font-family: inherit;
font-size: 15px;
font-size: 14px;
line-height: 1.7;
resize: none;
&:focus {
border-color: var(--jc-accent);
outline: 0;
}
}
@@ -282,10 +283,13 @@ $warn: #b4573f;
.jio-creator__editor {
position: relative;
/* 行内浮动工具栏相对书写区定位,而不是相对整个页面。 */
min-height: 40vh;
.block-editor-writing-flow {
font-size: 17px;
font-size: 16px;
line-height: 1.85;
letter-spacing: 0.01em;
}
.block-editor-default-block-appender textarea.block-editor-default-block-appender__content {
@@ -293,28 +297,61 @@ $warn: #b4573f;
}
.block-editor-block-list__layout {
padding-bottom: 80px;
padding-bottom: 40px;
}
.wp-block {
max-width: none;
}
}
.jio-creator__inspector {
margin-top: 24px;
.block-editor-block-inspector {
border-top: 1px solid var(--jc-line);
padding-top: 16px;
/* 段落之间留出公众号式的呼吸感,标题上方多留一档。 */
.block-editor-block-list__block {
margin-top: 0;
margin-bottom: 1.1em;
}
.block-editor-block-inspector:empty {
display: none;
.block-editor-block-list__block[data-type='core/heading'] {
margin-top: 1.6em;
}
.components-panel__body {
/* 选中时的虚线框收敛成低对比描边,贴近公众号的“轻选中”。 */
.block-editor-block-list__block.is-selected::after,
.block-editor-block-list__block.is-hovered::after {
box-shadow: 0 0 0 1.5px rgba(38, 118, 101, 0.35);
border-radius: 3px;
}
/* 行内工具栏:圆角悬浮条,深色底更接近公众号的选中工具条。 */
.block-editor-block-contextual-toolbar {
margin-left: 0;
}
.block-editor-block-contextual-toolbar .block-editor-block-toolbar {
border: 0;
border-radius: 8px;
background: #2b3733;
box-shadow: 0 6px 20px rgba(20, 32, 28, 0.22);
.components-toolbar-group,
.components-toolbar {
border: 0;
}
.components-button {
color: rgba(255, 255, 255, 0.86);
&:hover:not(:disabled),
&:focus:not(:disabled) {
background: rgba(255, 255, 255, 0.12);
color: #fff;
}
&.is-pressed,
&[aria-pressed='true'] {
background: rgba(255, 255, 255, 0.2);
color: #fff;
}
}
}
}