v0.10.6 首页 H3 标题条 1:1(heading typography 支持 + resolveGlobals 支持非 hex 全局色 + section 双份 padding 修复;Poppins 与原站一致回退系统字体)

This commit is contained in:
BigCode
2026-11-01 00:39:50 +08:00
parent 5b83e71ad9
commit 37b71ff230
5 changed files with 70 additions and 10 deletions
+48 -7
View File
@@ -72,6 +72,37 @@ function collapseBoxValues(v: string): string {
return v;
}
/** # 函数 解析 Typography 组合样式(typography_typography=custom 时的 typography_* 字段)
* 覆盖 font-family/size/weight/line-height/letter-spacing/word-spacing/text-transform/
* font-style/text-decoration(凡 settings 中有定义的值写入内联样式),
* 供 heading / text-editor / image-box 等按原站 kit 逐字重渲染。
* 参数 settings 元素 settings;prefix 通常为 "typography"
* 返回值 CSSProperties(无 custom 时为空对象)
*/
function typographyCss(settings: Record<string, unknown>, prefix = "typography"): CSSProperties {
const style: CSSProperties = {};
if (s(settings[`${prefix}_typography`]) !== "custom") return style;
const fam = s(settings[`${prefix}_font_family`]);
if (fam) style.fontFamily = `"${fam}", sans-serif`;
const size = sizeCss(settings[`${prefix}_font_size`]);
if (size) style.fontSize = size;
const weight = s(settings[`${prefix}_font_weight`]);
if (weight) style.fontWeight = weight as CSSProperties["fontWeight"];
const lh = sizeCss(settings[`${prefix}_line_height`]);
if (lh) style.lineHeight = lh;
const ls = sizeCss(settings[`${prefix}_letter_spacing`]);
if (ls) style.letterSpacing = ls;
const ws = sizeCss(settings[`${prefix}_word_spacing`]);
if (ws) style.wordSpacing = ws;
const tt = s(settings[`${prefix}_text_transform`]);
if (tt) style.textTransform = tt as CSSProperties["textTransform"];
const fs = s(settings[`${prefix}_font_style`]);
if (fs) style.fontStyle = fs as CSSProperties["fontStyle"];
const td = s(settings[`${prefix}_text_decoration`]);
if (td) style.textDecoration = td as CSSProperties["textDecoration"];
return style;
}
/** # 函数 解析 padding(Elementor 可能是对象/字符串/数组) */
function paddingCss(v: unknown): string | undefined {
if (!v) return undefined;
@@ -132,9 +163,9 @@ function resolveGlobals<T>(settings: T): T {
return settings;
}
/** # 函数 单值全局色引用解析 */
/** # 函数 单值全局色引用解析(键名含非十六进制 id:text/primary/accent 等) */
function resolveGlobalsStr(v: string): string {
const m = /^globals\/colors\?id=([0-9a-f]+)$/.exec(v.trim());
const m = /^globals\/colors\?id=([\w-]+)$/.exec(v.trim());
if (m) return ELEMENTOR_GLOBAL_COLORS[m[1]!] ?? v;
return v;
}
@@ -160,8 +191,7 @@ function sectionBgStyle(settings: Record<string, unknown>): CSSProperties {
} else if (s(settings.background_color)) {
style.backgroundColor = s(settings.background_color);
}
const pad = paddingCss(settings.padding);
if (pad) style.padding = pad;
// padding 由调用方(SectionNode 写到内容容器 / ColumnNode 写到列)负责,不在此叠加避免双份
return style;
}
@@ -436,13 +466,19 @@ function WidgetNodeInner({ el }: { el: ElElement }) {
/** # 组件 heading widget:标题级别/颜色/对齐 */
function HeadingWidget({ settings }: { settings: Record<string, unknown> }) {
// 标签合法域同原站 Utils::validate_html_tag(h1..h6 / div / span / p);默认 h2
const size = s(settings.header_size) || "h2";
const Tag = (["h1", "h2", "h3", "h4", "h5", "h6"].includes(size) ? size : "h2") as "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
const Tag = (["h1", "h2", "h3", "h4", "h5", "h6", "div", "span", "p"].includes(size) ? size : "h2") as "h2";
const style: CSSProperties = {};
if (s(settings.title_color)) style.color = s(settings.title_color);
const align = s(settings.align);
if (align) style.textAlign = align as CSSProperties["textAlign"];
return <Tag className="mb-[18px]" style={style} dangerouslySetInnerHTML={{ __html: s(settings.title) }} />;
Object.assign(style, typographyCss(settings));
// widget 自带内边距(Elementor 高级项 _padding)
const pad = paddingCss(settings._padding);
if (pad) style.padding = pad;
// 通用 margin 不设(实测原站 heading widget margin 0,间距全部来自原站 settings)
return <Tag style={style} dangerouslySetInnerHTML={{ __html: s(settings.title) }} />;
}
/** # 组件 text-editor widget:富文本 HTML */
@@ -451,7 +487,12 @@ function TextEditorWidget({ settings }: { settings: Record<string, unknown> }) {
if (!html) return null;
// 文本颜色可能来自全局色(如蓝底白字副标题),style 方式应用
const color = s(settings.text_color);
return <div className="mb-[18px]" style={color ? { color } : undefined} dangerouslySetInnerHTML={{ __html: html }} />;
const style: CSSProperties = {};
if (color) style.color = color;
Object.assign(style, typographyCss(settings));
const pad = paddingCss(settings._padding);
if (pad) style.padding = pad;
return <div className="mb-[18px]" style={Object.keys(style).length ? style : undefined} dangerouslySetInnerHTML={{ __html: html }} />;
}
/** # 组件 image widget */
+16
View File
@@ -37,6 +37,22 @@ const SETTING_KEYS = new Set([
"color_a",
"color_b",
"header_size",
// 组件自带盒间距与列 margin(heading/text-editor 的 _padding;内层列 margin)
"_padding",
"margin",
// Typography 组合字段(typography_typography=custom 时逐键采用)
"typography_typography",
"typography_font_family",
"typography_font_size",
"typography_font_size_tablet",
"typography_font_size_mobile",
"typography_font_weight",
"typography_line_height",
"typography_letter_spacing",
"typography_word_spacing",
"typography_text_transform",
"typography_font_style",
"typography_text_decoration",
// 列结构
"_column_size",
"_inline_size",
+4 -1
View File
@@ -28,5 +28,8 @@ function RootDocument() {
);
}
/** # 成员变量 根路由实例 **/
/** # 成员变量 根路由实例
* (取证:原站 head 无 Poppins css link、无 woff2 请求,Poppins 仅作 CSS 声明,
* 实际渲染走系统 fallback;本地同样不加载字体文件,保持两边一致回退。)
**/
export const Route = createRootRoute({ component: RootDocument, loader });