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:
1 parent
2c7262770b
commit
d07cffe99e
10 files changed
+272
-39
No files matched your search
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 本地视觉预览页:加载 WordPress 官方 dist 脚本 + Creator Studio 构建产物,
|
||||
* 用一份模拟的 bootstrap 数据渲染工作台,便于在不登录的情况下截图核对视觉。
|
||||
* 仅用于本机视觉验收,不进入主题运行时。
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const [srcArg, outArg] = process.argv.slice(2);
|
||||
const src = srcArg || '/tmp/studio-preview.html';
|
||||
const out = outArg || 'C:/Users/Xing/Desktop/WP-Date/data/wordpress/jio-preview.html';
|
||||
|
||||
let html = fs.readFileSync(src, 'utf8');
|
||||
|
||||
const mockBootstrap = {
|
||||
sourceId: 0,
|
||||
versionId: 0,
|
||||
versionRev: 0,
|
||||
status: '',
|
||||
reviewNote: '',
|
||||
title: '',
|
||||
excerpt: '',
|
||||
content:
|
||||
'<!-- wp:paragraph --><p>这是正文的第一段。微信公众号式的编辑体验强调沉浸感:大面积留白、克制的工具栏、只在需要时才出现的设置面板。</p><!-- /wp:paragraph -->',
|
||||
permalink: '',
|
||||
isPublished: false,
|
||||
categories: {
|
||||
items: [
|
||||
{ id: 1, name: '未分类' },
|
||||
{ id: 4, name: '分类一' },
|
||||
{ id: 5, name: '分类二' },
|
||||
],
|
||||
selected: [1],
|
||||
},
|
||||
tags: { items: ['写作', '产品'], enabled: true },
|
||||
custom: {},
|
||||
customDefs: [],
|
||||
featured: { type: '', data: {}, canImage: true, canSlide: false, canVideo: false },
|
||||
pay: {
|
||||
enabled: false,
|
||||
canPay: true,
|
||||
canDownload: true,
|
||||
payModo: 'cash',
|
||||
price: '0.00',
|
||||
points: 0,
|
||||
vip1Price: '0.00',
|
||||
vip2Price: '0.00',
|
||||
payLimit: 0,
|
||||
downloads: [],
|
||||
freeAllowed: true,
|
||||
priceMin: 0,
|
||||
priceMax: 0,
|
||||
pointsMin: 0,
|
||||
pointsMax: 0,
|
||||
privateStorage: false,
|
||||
},
|
||||
capabilities: {
|
||||
canUploadImage: true,
|
||||
canUploadVideo: true,
|
||||
canUploadFile: true,
|
||||
canEmbed: true,
|
||||
canHide: true,
|
||||
canPay: true,
|
||||
canPayDownload: true,
|
||||
canPublishNow: true,
|
||||
canEdit: true,
|
||||
isLoggedIn: true,
|
||||
},
|
||||
limits: { titleMin: 5, titleMax: 30, titlePlaceholder: '请输入标题', contentPlaceholder: '开始写作…' },
|
||||
privateUploads: [],
|
||||
privateStorage: false,
|
||||
media: { maxBytes: 5242880, batch: 6 },
|
||||
rest: { root: 'https://localhost/wp-json/', nonce: 'preview' },
|
||||
urls: { submit: '#', newPost: '#', center: '#' },
|
||||
captcha: { enabled: false },
|
||||
creator: {
|
||||
saveUrl: '#',
|
||||
submitUrl: '#',
|
||||
previewUrl: '#',
|
||||
privateUrl: '#',
|
||||
bootstrapUrl: '#',
|
||||
},
|
||||
blocks: { mediaUploadUrl: '#', mediaListUrl: '#' },
|
||||
nonce: 'preview',
|
||||
};
|
||||
|
||||
// 换成模拟数据。WP 的 wp_add_inline_script 会在结尾追加 sourceURL 注释,
|
||||
// 所以只匹配到 JSON 的结束分号,保留其后的注释。
|
||||
const before = html.length;
|
||||
html = html.replace(
|
||||
/window\.jioCreatorStudio = \{[\s\S]*?\};\n/,
|
||||
`window.jioCreatorStudio = ${JSON.stringify(mockBootstrap)};\n`
|
||||
);
|
||||
if (html.length === before) {
|
||||
console.error('WARN: bootstrap 替换未生效');
|
||||
}
|
||||
|
||||
// 追加一个 banner 说明这是预览
|
||||
html = html.replace(
|
||||
'</body>',
|
||||
`<div style="position:fixed;left:0;right:0;bottom:0;z-index:99999;padding:6px 12px;background:#1d5f52;color:#fff;font:12px/1.6 system-ui;text-align:center">视觉预览(模拟数据)· 非真实登录会话</div></body>`
|
||||
);
|
||||
|
||||
fs.writeFileSync(out, html, 'utf8');
|
||||
console.log('written ' + out + ' bytes=' + html.length);
|
||||
console.log('has studio script: ' + /jio-creator-studio-js/.test(html));
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 截图:打开预览页并保存桌面 / 移动端截图,同时把配色、字体与布局尺寸打印出来。
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const puppeteer = require('puppeteer-core');
|
||||
|
||||
const CANDIDATES = [
|
||||
process.env.JIO_BROWSER,
|
||||
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
||||
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
||||
'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
|
||||
'C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe',
|
||||
].filter(Boolean);
|
||||
const BROWSER = CANDIDATES.find((p) => fs.existsSync(p));
|
||||
|
||||
const URL = process.argv[2] || 'https://localhost/jio-preview.html';
|
||||
const PREFIX = process.argv[3] || 'C:/Users/Xing/Desktop/WP-Date/data/wordpress/shot';
|
||||
|
||||
(async () => {
|
||||
if (!BROWSER) {
|
||||
console.error('no browser');
|
||||
process.exit(1);
|
||||
}
|
||||
const browser = await puppeteer.launch({
|
||||
executablePath: BROWSER,
|
||||
headless: 'new',
|
||||
ignoreHTTPSErrors: true,
|
||||
args: ['--disable-gpu', '--no-sandbox'],
|
||||
});
|
||||
|
||||
for (const [name, viewport] of [
|
||||
['desktop', { width: 1440, height: 1000 }],
|
||||
['mobile', { width: 390, height: 844, isMobile: true, hasTouch: true }],
|
||||
]) {
|
||||
const page = await browser.newPage();
|
||||
await page.setViewport(viewport);
|
||||
await page.goto(URL, { waitUntil: 'networkidle2', timeout: 60000 });
|
||||
await new Promise((r) => setTimeout(r, 2000));
|
||||
await page.screenshot({ path: `${PREFIX}-${name}.png` });
|
||||
|
||||
const metrics = await page.evaluate(() => {
|
||||
const pick = (sel) => {
|
||||
const el = document.querySelector(sel);
|
||||
if (!el) return null;
|
||||
const cs = getComputedStyle(el);
|
||||
const r = el.getBoundingClientRect();
|
||||
return {
|
||||
text: (el.textContent || '').trim().slice(0, 40),
|
||||
font: `${cs.fontSize}/${cs.lineHeight} ${cs.fontFamily.split(',')[0]}`,
|
||||
weight: cs.fontWeight,
|
||||
color: cs.color,
|
||||
bg: cs.backgroundColor,
|
||||
pad: cs.padding,
|
||||
box: `${Math.round(r.width)}x${Math.round(r.height)}`,
|
||||
};
|
||||
};
|
||||
return {
|
||||
bar: pick('.jio-creator__bar'),
|
||||
title: pick('.jio-creator__title textarea'),
|
||||
excerpt: pick('.jio-creator__excerpt textarea'),
|
||||
canvas: pick('.jio-creator__canvas'),
|
||||
para: pick('.block-editor-block-list__block'),
|
||||
appender: pick('.block-editor-default-block-appender'),
|
||||
primaryBtn: pick('.jio-creator__primary'),
|
||||
ghostBtn: pick('.jio-creator__ghost'),
|
||||
pageBg: getComputedStyle(document.body).backgroundColor,
|
||||
};
|
||||
});
|
||||
console.log(`=== ${name} ===`);
|
||||
console.log(JSON.stringify(metrics, null, 2));
|
||||
await page.close();
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
})();
|
||||
Reference in new issue
Block a user