fix(layout): align color scheme, content width and fonts with reference theme
- Color scheme: zibll field order/labels, theme_skin_custom overrides palette, hex palette swatches, dark_theme_skin_custom, light/dark background images, close_backdrop via body.fps-accelerat, theme_main_radius drives --main-radius - Emit --theme-color / --focus-shadow-color / --focus-color-opacity* vars - Drop border_radius, primary_color readers and legacy value maps - Content max width: free 1200-2200 number field; fix font family/custom stack Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6da08d9d4f
commit
74021d26bb
8 files changed
+319
-221
No files matched your search
@@ -1,3 +1,52 @@
|
||||
const bgDefault = {
|
||||
color: '',
|
||||
image: '',
|
||||
position: 'center top',
|
||||
repeat: 'no-repeat',
|
||||
attachment: 'fixed',
|
||||
size: '100%',
|
||||
origin: '',
|
||||
}
|
||||
|
||||
const opts = (pairs) => pairs.map(([value, label]) => ({ label, value }))
|
||||
|
||||
// 与 Settings ThemeSearch::background_css() 的白名单一致。
|
||||
const bgField = (key, label, help) => ({
|
||||
key,
|
||||
label,
|
||||
type: 'fieldset',
|
||||
default: { ...bgDefault },
|
||||
help,
|
||||
fields: [
|
||||
{ key: 'color', label: '背景颜色', type: 'color', default: '' },
|
||||
{ key: 'image', label: '背景图片', type: 'media', default: '' },
|
||||
{ key: 'position', label: '背景位置', type: 'select', default: 'center top', options: opts([
|
||||
['', '默认'], ['left top', '左上'], ['left center', '左中'], ['left bottom', '左下'],
|
||||
['center top', '中上'], ['center center', '居中'], ['center bottom', '中下'],
|
||||
['right top', '右上'], ['right center', '右中'], ['right bottom', '右下'],
|
||||
]) },
|
||||
{ key: 'repeat', label: '背景重复', type: 'select', default: 'no-repeat', options: opts([
|
||||
['', '默认'], ['repeat', '重复'], ['no-repeat', '不重复'], ['repeat-x', '水平重复'], ['repeat-y', '垂直重复'],
|
||||
]) },
|
||||
{ key: 'attachment', label: '背景附着', type: 'select', default: 'fixed', options: opts([
|
||||
['', '默认'], ['scroll', '滚动'], ['fixed', '固定'],
|
||||
]) },
|
||||
{ key: 'size', label: '背景尺寸', type: 'select', default: '100%', options: opts([
|
||||
['', '默认'], ['100%', '100%'], ['cover', '覆盖 (cover)'], ['contain', '包含 (contain)'], ['auto', '自动 (auto)'],
|
||||
]) },
|
||||
{ key: 'origin', label: '背景原点', type: 'select', default: '', options: opts([
|
||||
['', '默认'], ['padding-box', 'Padding Box'], ['border-box', 'Border Box'], ['content-box', 'Content Box'],
|
||||
]) },
|
||||
],
|
||||
})
|
||||
|
||||
// palette 的 label 即色块背景色;ff1856 的色块沿用参考主题的 #fd2760。
|
||||
const SKIN_PALETTE = [
|
||||
['ff1856', '#fd2760'], ['f04494', '#f04494'], ['ae53f3', '#ae53f3'], ['627bf5', '#627bf5'],
|
||||
['00a2e3', '#00a2e3'], ['16b597', '#16b597'], ['36af18', '#36af18'], ['8fb107', '#8fb107'],
|
||||
['b18c07', '#b18c07'], ['e06711', '#e06711'], ['f74735', '#f74735'],
|
||||
].map(([value, label]) => ({ label, value }))
|
||||
|
||||
export const layoutSchema = {
|
||||
key: 'global.layout',
|
||||
title: '显示 & 布局',
|
||||
@@ -6,10 +55,12 @@ export const layoutSchema = {
|
||||
defaults: {
|
||||
theme_mode: 'time-auto',
|
||||
theme_mode_button: ['pc_nav', 'm_menu'],
|
||||
primary_color: '#1890ff',
|
||||
theme_img_bg: { ...bgDefault },
|
||||
dark_theme_img_bg: { ...bgDefault },
|
||||
theme_skin_custom: '',
|
||||
theme_skin: 'f04494',
|
||||
dark_primary_color: '',
|
||||
border_radius: 8,
|
||||
dark_theme_skin_custom: '',
|
||||
close_backdrop: false,
|
||||
theme_main_radius: 12,
|
||||
container_max_width: 1200,
|
||||
sidebar_enabled: true,
|
||||
@@ -22,6 +73,7 @@ export const layoutSchema = {
|
||||
sidebar_page_enabled: true,
|
||||
sidebar_search_enabled: true,
|
||||
font_family: 'system',
|
||||
font_family_custom: '',
|
||||
qj_loading: false,
|
||||
qj_dh_xs: 'no1',
|
||||
},
|
||||
@@ -61,50 +113,41 @@ export const layoutSchema = {
|
||||
fields: [
|
||||
{
|
||||
key: 'theme_mode',
|
||||
label: '默认主题模式',
|
||||
label: '主题模式',
|
||||
type: 'radio',
|
||||
default: 'time-auto',
|
||||
options: [
|
||||
{ label: '浅色', value: 'white-theme' },
|
||||
{ label: '深色', value: 'dark-theme' },
|
||||
{ label: '跟随系统', value: 'time-auto' },
|
||||
{ label: '日间亮色主题', value: 'white-theme' },
|
||||
{ label: '夜间深色主题', value: 'dark-theme' },
|
||||
{ label: '早晚8点自动切换', value: 'time-auto' },
|
||||
],
|
||||
help: '此处设置为默认风格,实际显示风格以用户设置优先。如需固定风格,则关闭还需下方主题切换按钮',
|
||||
},
|
||||
{
|
||||
key: 'theme_mode_button',
|
||||
label: '主题切换按钮位置',
|
||||
label: '主题切换按钮',
|
||||
type: 'checkbox',
|
||||
default: ['pc_nav', 'm_menu'],
|
||||
options: [
|
||||
{ label: 'PC 顶部导航', value: 'pc_nav' },
|
||||
{ label: '移动端菜单', value: 'm_menu' },
|
||||
{ label: 'PC端顶部导航', value: 'pc_nav' },
|
||||
{ label: '移动端弹出菜单', value: 'm_menu' },
|
||||
],
|
||||
help: '控制主题切换按钮在哪些位置显示',
|
||||
help: '如果关闭此功能,则前端不会显示切换按钮',
|
||||
},
|
||||
{ key: 'primary_color', label: '主题色', type: 'color', default: '#f04494', help: '按钮、链接和强调元素的主色调' },
|
||||
bgField('theme_img_bg', '全局背景图', '注意:要达到良好的效果需要图片与参数配合,同时需注意颜色搭配!配合不好容易降低显示美感'),
|
||||
bgField('dark_theme_img_bg', '夜间模式背景图', '如未设置夜间模式背景图,则夜间模式也显示上方背景图'),
|
||||
{ key: 'theme_skin_custom', label: '全局主题色', type: 'color', default: '', help: '默认主题高亮颜色。如需选择下方预置颜色,请先清空上方颜色' },
|
||||
{
|
||||
key: 'theme_skin',
|
||||
label: '预设主题色',
|
||||
label: ' ',
|
||||
type: 'palette',
|
||||
default: 'f04494',
|
||||
options: [
|
||||
{ label: '玫红', value: 'ff1856' },
|
||||
{ label: '粉色', value: 'f04494' },
|
||||
{ label: '紫色', value: 'ae53f3' },
|
||||
{ label: '靛蓝', value: '627bf5' },
|
||||
{ label: '天蓝', value: '00a2e3' },
|
||||
{ label: '青绿', value: '16b597' },
|
||||
{ label: '翠绿', value: '36af18' },
|
||||
{ label: '黄绿', value: '8fb107' },
|
||||
{ label: '棕金', value: 'b18c07' },
|
||||
{ label: '橘橙', value: 'e06711' },
|
||||
{ label: '朱红', value: 'f74735' },
|
||||
],
|
||||
help: '选择预设主题色,将覆盖上方自定义主题色',
|
||||
dependsOn: { key: 'theme_skin_custom', operator: 'empty' },
|
||||
options: SKIN_PALETTE,
|
||||
},
|
||||
{ key: 'dark_primary_color', label: '暗色模式主题色', type: 'color', default: '', help: '暗色模式下独立的主题色,留空则跟随浅色模式' },
|
||||
{ key: 'border_radius', label: '全局圆角 (px)', type: 'slider', min: 0, max: 20, step: 1, default: 8 },
|
||||
{ key: 'theme_main_radius', label: '卡片圆角 (px)', type: 'number', min: 0, max: 30, default: 12, help: '独立卡片圆角,留空则使用全局圆角 +4' },
|
||||
{ key: 'dark_theme_skin_custom', label: '夜间模式主题色', type: 'color', default: '', help: '在此可单独设置夜间模式的高亮色,清空此处则使用上方默认高亮色' },
|
||||
{ key: 'close_backdrop', label: '全局关闭背景高斯模糊', type: 'switch', default: false, help: '在支持的浏览器上部分UI(例如导航栏)会显示背景高斯模糊的特效,但此功能比较消耗浏览器性能。同时系统会自动检测用户浏览器性能情况,如果性能较差,将自动关闭此特效,以提供更流畅的体验' },
|
||||
{ key: 'theme_main_radius', label: '卡片圆角', type: 'spinner', default: 12, min: 0, max: 30, step: 1, unit: 'PX', description: '页面卡片的圆角尺寸' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -112,16 +155,7 @@ export const layoutSchema = {
|
||||
title: '布局设置',
|
||||
icon: 'fa fas fa-columns',
|
||||
fields: [
|
||||
{ key: 'container_max_width', label: '内容最大宽度 (px)', type: 'select', default: 1200, options: [
|
||||
{ label: '1200px', value: 1200 },
|
||||
{ label: '1320px', value: 1320 },
|
||||
{ label: '1440px', value: 1440 },
|
||||
{ label: '1600px', value: 1600 },
|
||||
{ label: '1800px', value: 1800 },
|
||||
{ label: '2000px', value: 2000 },
|
||||
{ label: '2200px', value: 2200 },
|
||||
{ label: '全宽', value: 0 },
|
||||
]},
|
||||
{ key: 'container_max_width', label: '内容最大宽度', type: 'number', default: 1200, min: 1200, max: 2200, step: 50, unit: 'PX', help: '页面布局的最大宽度,可设置 1200–2200PX。宽度过大会造成显示不协调,非特殊需求请勿调整。' },
|
||||
{ key: 'sidebar_enabled', label: '开启侧边栏', type: 'switch', default: true },
|
||||
{ key: 'sidebar_position', label: '侧边栏位置', type: 'radio', default: 'right', dependsOn: { key: 'sidebar_enabled', value: true }, options: [
|
||||
{ label: '左侧', value: 'left' },
|
||||
@@ -153,7 +187,8 @@ export const layoutSchema = {
|
||||
{ label: '思源黑体', value: 'noto-sans-sc' },
|
||||
{ label: '思源宋体', value: 'noto-serif-sc' },
|
||||
{ label: '自定义', value: 'custom' },
|
||||
]},
|
||||
], help: '思源字体不会远程加载,访客设备未安装时回退到系统字体。' },
|
||||
{ key: 'font_family_custom', label: '自定义字体', type: 'input', default: '', placeholder: '例如:"LXGW WenKai", "PingFang SC", sans-serif', dependsOn: { key: 'font_family', value: 'custom' }, help: 'CSS font-family 字体栈,多个字体用英文逗号分隔;留空使用系统字体。' },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -101,38 +101,26 @@ class GlobalSchema {
|
||||
'option_key' => 'aksrt_settings',
|
||||
'groups' => [
|
||||
['key' => 'color', 'title' => '色彩方案', 'fields' => [
|
||||
['key' => 'theme_mode', 'label' => '默认主题模式', 'type' => 'radio', 'default' => 'time-auto', 'options' => [
|
||||
['label' => '浅色', 'value' => 'white-theme'],
|
||||
['label' => '深色', 'value' => 'dark-theme'],
|
||||
['label' => '跟随系统', 'value' => 'time-auto'],
|
||||
['key' => 'theme_mode', 'label' => '主题模式', 'type' => 'radio', 'default' => 'time-auto', 'help' => '此处设置为默认风格,实际显示风格以用户设置优先。如需固定风格,则关闭还需下方主题切换按钮', 'options' => [
|
||||
['label' => '日间亮色主题', 'value' => 'white-theme'],
|
||||
['label' => '夜间深色主题', 'value' => 'dark-theme'],
|
||||
['label' => '早晚8点自动切换', 'value' => 'time-auto'],
|
||||
]],
|
||||
['key' => 'theme_mode_button', 'label' => '主题切换按钮位置', 'type' => 'checkbox', 'default' => ['pc_nav', 'm_menu'], 'options' => [
|
||||
['label' => 'PC 顶部导航', 'value' => 'pc_nav'],
|
||||
['label' => '移动端菜单', 'value' => 'm_menu'],
|
||||
['key' => 'theme_mode_button', 'label' => '主题切换按钮', 'type' => 'checkbox', 'default' => ['pc_nav', 'm_menu'], 'help' => '如果关闭此功能,则前端不会显示切换按钮', 'options' => [
|
||||
['label' => 'PC端顶部导航', 'value' => 'pc_nav'],
|
||||
['label' => '移动端弹出菜单', 'value' => 'm_menu'],
|
||||
]],
|
||||
['key' => 'theme_skin', 'label' => '预设主题色', 'type' => 'palette', 'default' => 'f04494', 'options' => [
|
||||
['label' => '玫红', 'value' => 'ff1856'],
|
||||
['label' => '粉色', 'value' => 'f04494'],
|
||||
['label' => '紫色', 'value' => 'ae53f3'],
|
||||
['label' => '靛蓝', 'value' => '627bf5'],
|
||||
['label' => '天蓝', 'value' => '00a2e3'],
|
||||
['label' => '青绿', 'value' => '16b597'],
|
||||
['label' => '翠绿', 'value' => '36af18'],
|
||||
['label' => '黄绿', 'value' => '8fb107'],
|
||||
['label' => '棕金', 'value' => 'b18c07'],
|
||||
['label' => '橘橙', 'value' => 'e06711'],
|
||||
['label' => '朱红', 'value' => 'f74735'],
|
||||
]],
|
||||
['key' => 'primary_color', 'label' => '自定义主题色', 'type' => 'color', 'default' => '#f04494'],
|
||||
['key' => 'dark_primary_color', 'label' => '暗色模式主题色', 'type' => 'color', 'default' => '#f04494'],
|
||||
['key' => 'border_radius', 'label' => '全局圆角', 'type' => 'slider', 'default' => 8, 'min' => 0, 'max' => 20],
|
||||
['key' => 'theme_main_radius', 'label' => '卡片圆角 (px)', 'type' => 'number', 'default' => 12, 'min' => 0, 'max' => 30, 'help' => '独立卡片圆角,不填则使用全局圆角 +4'],
|
||||
['key' => 'close_backdrop', 'label' => '关闭毛玻璃效果', 'type' => 'switch', 'default' => false],
|
||||
self::background_field('theme_img_bg', '全局背景图', '注意:要达到良好的效果需要图片与参数配合,同时需注意颜色搭配!配合不好容易降低显示美感'),
|
||||
self::background_field('dark_theme_img_bg', '夜间模式背景图', '如未设置夜间模式背景图,则夜间模式也显示上方背景图'),
|
||||
['key' => 'theme_skin_custom', 'label' => '全局主题色', 'type' => 'color', 'default' => '', 'help' => '默认主题高亮颜色。如需选择下方预置颜色,请先清空上方颜色'],
|
||||
['key' => 'theme_skin', 'label' => ' ', 'type' => 'palette', 'default' => 'f04494', 'dependsOn' => ['key' => 'theme_skin_custom', 'operator' => 'empty'], 'options' => self::skin_palette()],
|
||||
['key' => 'dark_theme_skin_custom', 'label' => '夜间模式主题色', 'type' => 'color', 'default' => '', 'help' => '在此可单独设置夜间模式的高亮色,清空此处则使用上方默认高亮色'],
|
||||
['key' => 'close_backdrop', 'label' => '全局关闭背景高斯模糊', 'type' => 'switch', 'default' => false, 'help' => '在支持的浏览器上部分UI(例如导航栏)会显示背景高斯模糊的特效,但此功能比较消耗浏览器性能。同时系统会自动检测用户浏览器性能情况,如果性能较差,将自动关闭此特效,以提供更流畅的体验'],
|
||||
['key' => 'theme_main_radius', 'label' => '卡片圆角', 'type' => 'spinner', 'default' => 12, 'min' => 0, 'max' => 30, 'step' => 1, 'unit' => 'PX', 'description' => '页面卡片的圆角尺寸'],
|
||||
]],
|
||||
['key' => 'layout', 'title' => '布局设置', 'fields' => [
|
||||
// 0(全宽)与 1200–2200 与设置页下拉选项、Settings::container_max_width() 归一化区间一致;
|
||||
// 上限低于 UI 可选项会让后台保存被校验拒绝,页面宽度卡在旧值。
|
||||
['key' => 'container_max_width', 'label' => '内容最大宽度', 'type' => 'number', 'default' => 1200, 'min' => 0, 'max' => 2200],
|
||||
// 1200–2200 与 Settings::container_max_width() 归一化区间一致。
|
||||
['key' => 'container_max_width', 'label' => '内容最大宽度', 'type' => 'number', 'default' => 1200, 'min' => 1200, 'max' => 2200, 'step' => 50, 'unit' => 'PX'],
|
||||
['key' => 'sidebar_enabled', 'label' => '开启侧边栏', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'sidebar_position', 'label' => '侧边栏位置', 'type' => 'radio', 'default' => 'right', 'options' => [
|
||||
['label' => '左侧', 'value' => 'left'],
|
||||
@@ -153,6 +141,7 @@ class GlobalSchema {
|
||||
['label' => '思源宋体', 'value' => 'noto-serif-sc'],
|
||||
['label' => '自定义', 'value' => 'custom'],
|
||||
]],
|
||||
['key' => 'font_family_custom', 'label' => '自定义字体', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'font_family', 'value' => 'custom']],
|
||||
]],
|
||||
['key' => 'performance', 'title' => '性能优化', 'fields' => [
|
||||
['key' => 'qj_loading', 'label' => '全站加载动画', 'type' => 'switch', 'default' => false],
|
||||
@@ -458,4 +447,57 @@ class GlobalSchema {
|
||||
],
|
||||
];
|
||||
}
|
||||
/** 与 assets/admin/src/schema/sections/global/layout.js 的 skinPalette 保持一致;label 即色块颜色。 */
|
||||
private static function skin_palette(): array {
|
||||
$map = [
|
||||
'ff1856' => '#fd2760', 'f04494' => '#f04494', 'ae53f3' => '#ae53f3', '627bf5' => '#627bf5',
|
||||
'00a2e3' => '#00a2e3', '16b597' => '#16b597', '36af18' => '#36af18', '8fb107' => '#8fb107',
|
||||
'b18c07' => '#b18c07', 'e06711' => '#e06711', 'f74735' => '#f74735',
|
||||
];
|
||||
$options = [];
|
||||
foreach ($map as $value => $label) {
|
||||
$options[] = ['label' => $label, 'value' => (string) $value];
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/** 背景图配置(对齐参考主题 background 字段:颜色/图片/位置/重复/附着/尺寸/原点)。 */
|
||||
private static function background_field(string $key, string $label, string $help): array {
|
||||
$opts = static function (array $map): array {
|
||||
$out = [['label' => '默认', 'value' => '']];
|
||||
foreach ($map as $value => $text) {
|
||||
$out[] = ['label' => $text, 'value' => $value];
|
||||
}
|
||||
return $out;
|
||||
};
|
||||
return [
|
||||
'key' => $key, 'label' => $label, 'type' => 'fieldset', 'help' => $help,
|
||||
// 子键与 layout.js bgField 及 ThemeSearch::background_css() 白名单一致。
|
||||
'default' => [
|
||||
'color' => '', 'image' => '', 'position' => 'center top',
|
||||
'repeat' => 'no-repeat', 'attachment' => 'fixed', 'size' => '100%', 'origin' => '',
|
||||
],
|
||||
'fields' => [
|
||||
['key' => 'color', 'label' => '背景颜色', 'type' => 'color', 'default' => ''],
|
||||
['key' => 'image', 'label' => '背景图片', 'type' => 'media', 'default' => ''],
|
||||
['key' => 'position', 'label' => '背景位置', 'type' => 'select', 'default' => 'center top', 'options' => $opts([
|
||||
'left top' => '左上', 'left center' => '左中', 'left bottom' => '左下',
|
||||
'center top' => '中上', 'center center' => '居中', 'center bottom' => '中下',
|
||||
'right top' => '右上', 'right center' => '右中', 'right bottom' => '右下',
|
||||
])],
|
||||
['key' => 'repeat', 'label' => '背景重复', 'type' => 'select', 'default' => 'no-repeat', 'options' => $opts([
|
||||
'repeat' => '重复', 'no-repeat' => '不重复', 'repeat-x' => '水平重复', 'repeat-y' => '垂直重复',
|
||||
])],
|
||||
['key' => 'attachment', 'label' => '背景附着', 'type' => 'select', 'default' => 'fixed', 'options' => $opts([
|
||||
'scroll' => '滚动', 'fixed' => '固定',
|
||||
])],
|
||||
['key' => 'size', 'label' => '背景尺寸', 'type' => 'select', 'default' => '100%', 'options' => $opts([
|
||||
'100%' => '100%', 'cover' => '覆盖 (cover)', 'contain' => '包含 (contain)', 'auto' => '自动 (auto)',
|
||||
])],
|
||||
['key' => 'origin', 'label' => '背景原点', 'type' => 'select', 'default' => '', 'options' => $opts([
|
||||
'padding-box' => 'Padding Box', 'border-box' => 'Border Box', 'content-box' => 'Content Box',
|
||||
])],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -112,6 +112,11 @@ trait ScriptsPart2 {
|
||||
$classes[] = 'auth-page';
|
||||
}
|
||||
|
||||
// 对齐参考主题 close_backdrop:fps-accelerat 由 main.css 统一关闭 backdrop-filter。
|
||||
if (class_exists('\AKSRT\Settings\Settings') && \AKSRT\Settings\Settings::close_backdrop()) {
|
||||
$classes[] = 'fps-accelerat';
|
||||
}
|
||||
|
||||
// legacy site-layout-1/2/3 (no sidebar / right / left).
|
||||
if (function_exists('aksrt_body_layout_classes')) {
|
||||
foreach (aksrt_body_layout_classes() as $layout_class) {
|
||||
|
||||
@@ -13,28 +13,18 @@ class InlineStyleBuilder {
|
||||
$logo_url = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::logo_url() : (string) aksrt_get_setting('logo_url', '');
|
||||
$dark_logo_url = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::logo_dark_url() : (string) aksrt_get_setting('site_logo_dark', '');
|
||||
$favicon = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::favicon_url() : (string) aksrt_get_setting('favicon_url', '');
|
||||
$primary_color = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::resolved_primary_color() : '#f04494';
|
||||
$dark_primary = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::dark_primary_color() : '#f04494';
|
||||
$border_radius = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::border_radius() : 8;
|
||||
$card_radius = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::card_radius() : ($border_radius + 4);
|
||||
$primary_color = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::theme_color() : '#f04494';
|
||||
$dark_primary = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::dark_theme_color() : '';
|
||||
$main_radius = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::main_radius() : 12;
|
||||
$container_max = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::container_max_width() : 1200;
|
||||
$font_family = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::font_family() : 'system';
|
||||
$logo_width = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::logo_width() : 150;
|
||||
$sidebar_cfg = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_sidebar_config() : ['width' => 311, 'enabled' => true, 'position' => 'right'];
|
||||
|
||||
$content_width = $container_max === 0 ? '100%' : $container_max . 'px';
|
||||
$container_wide = $container_max === 0 ? '100%' : max(1280, $container_max + 160) . 'px';
|
||||
$radius_sm = max(0, $border_radius - 2);
|
||||
$radius_lg = $border_radius + 4;
|
||||
$radius_xl = $border_radius + 10;
|
||||
$rgb = $this->hex_to_rgb($primary_color);
|
||||
$primary_hover = $this->adjust_hex_color($primary_color, -0.12);
|
||||
$primary_active = $this->adjust_hex_color($primary_color, -0.22);
|
||||
$font_stacks = $this->resolve_font_stacks($font_family);
|
||||
|
||||
$dark_rgb = $this->hex_to_rgb($dark_primary);
|
||||
$dark_hover = $this->adjust_hex_color($dark_primary, -0.12);
|
||||
$dark_active = $this->adjust_hex_color($dark_primary, -0.22);
|
||||
$content_width = $container_max . 'px';
|
||||
$container_wide = max(1280, $container_max + 160) . 'px';
|
||||
$font_custom = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::font_family_custom() : '';
|
||||
$font_stacks = $this->resolve_font_stacks($font_family, $font_custom);
|
||||
|
||||
// legacy hard-codes 311px dual-column math; keep runtime width aligned to that
|
||||
// baseline when settings still hold the old 300 default (or empty).
|
||||
@@ -49,22 +39,7 @@ class InlineStyleBuilder {
|
||||
'--container-wide' => $container_wide,
|
||||
'--mian-max-width' => $content_width, // legacy typo token
|
||||
'--sidebar-width' => $sidebar_width . 'px',
|
||||
'--color-primary' => $primary_color,
|
||||
'--color-primary-hover' => $primary_hover,
|
||||
'--color-primary-active' => $primary_active,
|
||||
'--color-primary-soft' => sprintf('rgba(%d, %d, %d, 0.12)', $rgb[0], $rgb[1], $rgb[2]),
|
||||
'--color-primary-softer' => sprintf('rgba(%d, %d, %d, 0.06)', $rgb[0], $rgb[1], $rgb[2]),
|
||||
'--color-primary-rgb' => implode(', ', $rgb),
|
||||
'--focus-color' => $primary_color,
|
||||
'--radius-sm' => $radius_sm . 'px',
|
||||
'--radius' => $border_radius . 'px',
|
||||
'--radius-card' => $card_radius . 'px',
|
||||
// legacy --main-radius tracks the base radius (8), not the larger card radius.
|
||||
'--main-radius' => $border_radius . 'px',
|
||||
'--radius-btn' => $border_radius . 'px',
|
||||
'--radius-code' => $border_radius . 'px',
|
||||
'--radius-lg' => $radius_lg . 'px',
|
||||
'--radius-xl' => $radius_xl . 'px',
|
||||
'--radius-card' => $main_radius . 'px',
|
||||
'--shadow-md' => '0 8px 24px rgba(20, 28, 48, 0.10)',
|
||||
'--main-shadow' => 'rgba(116, 116, 116, 0.08)',
|
||||
'--font-body' => $font_stacks['body'],
|
||||
@@ -79,7 +54,9 @@ class InlineStyleBuilder {
|
||||
|
||||
echo '<style id="aksrt-runtime-vars">:root{';
|
||||
foreach ($layout_vars as $name => $value) {
|
||||
echo esc_html($name) . ':' . esc_attr($value) . ';';
|
||||
// esc_attr() would turn font-stack quotes into literal " inside <style>,
|
||||
// invalidating font-family; strip only characters that can break out of a declaration.
|
||||
echo esc_html($name) . ':' . $this->css_value((string) $value) . ';';
|
||||
}
|
||||
if ($logo_url) {
|
||||
echo '--aksrt-logo-url:"' . esc_url($logo_url) . '";';
|
||||
@@ -90,18 +67,26 @@ class InlineStyleBuilder {
|
||||
if ($favicon) {
|
||||
echo '--aksrt-favicon:"' . esc_url($favicon) . '";';
|
||||
}
|
||||
if ($dark_primary !== $primary_color) {
|
||||
echo '}html.dark{';
|
||||
echo '--color-primary:' . esc_attr($dark_primary) . ';';
|
||||
echo '--color-primary-hover:' . esc_attr($dark_hover) . ';';
|
||||
echo '--color-primary-active:' . esc_attr($dark_active) . ';';
|
||||
echo '--color-primary-soft:' . sprintf('rgba(%d,%d,%d,0.12)', $dark_rgb[0], $dark_rgb[1], $dark_rgb[2]) . ';';
|
||||
echo '--color-primary-softer:' . sprintf('rgba(%d,%d,%d,0.06)', $dark_rgb[0], $dark_rgb[1], $dark_rgb[2]) . ';';
|
||||
echo '--color-primary-rgb:' . esc_attr(implode(', ', $dark_rgb)) . ';';
|
||||
echo '--focus-color:' . esc_attr($dark_primary) . ';';
|
||||
}
|
||||
echo '}</style>' . "\n";
|
||||
|
||||
// 对齐参考主题 zib_head_css():主题色变量与 --main-radius 挂在 body(main.css 的定义层级),
|
||||
// 夜间主题色仅在单独设置时覆盖 body.dark-theme。
|
||||
echo '<style id="aksrt-theme-color">body{' . $this->theme_color_vars($primary_color) . '--main-radius:' . (int) $main_radius . 'px;}';
|
||||
if ($dark_primary !== '') {
|
||||
echo 'html.dark body,body.dark-theme{' . $this->theme_color_vars($dark_primary) . '}';
|
||||
}
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$bg_css = \AKSRT\Settings\Settings::background_css('theme_img_bg');
|
||||
$dark_bg_css = \AKSRT\Settings\Settings::background_css('dark_theme_img_bg');
|
||||
if ($bg_css !== '') {
|
||||
echo 'body{' . $bg_css . '}';
|
||||
}
|
||||
if ($dark_bg_css !== '') {
|
||||
echo 'html.dark body,body.dark-theme{' . $dark_bg_css . '}';
|
||||
}
|
||||
}
|
||||
echo '</style>' . "\n";
|
||||
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$list_settings = \AKSRT\Settings\Settings::get_post_list_style_settings();
|
||||
$mobile_meta = sanitize_key((string) ($list_settings['list_meta_show'] ?? 'like'));
|
||||
@@ -130,9 +115,6 @@ class InlineStyleBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists('\AKSRT\Settings\Settings') && !empty(\AKSRT\Settings\Settings::get_value('close_backdrop', false))) {
|
||||
echo '<style id="aksrt-no-backdrop">.aksrt-header,.header-inner,.site-header,.header,.mobile-nav-overlay,.modal-backdrop,.aksrt-drawer-overlay,.sidebar-inner{backdrop-filter:none!important;-webkit-backdrop-filter:none!important;background-color:var(--bg-card,#fff)!important}</style>' . "\n";
|
||||
}
|
||||
echo '<style id="aksrt-runtime-components">'
|
||||
. '.aksrt-search-hot-keywords{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:12px;font-family:var(--font-ui);}'
|
||||
. '.aksrt-search-hot-keywords__label{font-size:12px;color:var(--color-ink-3);}'
|
||||
@@ -143,27 +125,56 @@ class InlineStyleBuilder {
|
||||
. '</style>' . "\n";
|
||||
}
|
||||
|
||||
private function resolve_font_stacks(string $family): array {
|
||||
private function resolve_font_stacks(string $family, string $custom = ''): array {
|
||||
// Same system stack as tokens.css; "system" must not swap in a serif face.
|
||||
$system = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif';
|
||||
switch ($family) {
|
||||
case 'noto-sans-sc':
|
||||
return [
|
||||
'body' => '"Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif',
|
||||
'display' => '"Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif',
|
||||
'ui' => 'Inter, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif',
|
||||
];
|
||||
$stack = '"Noto Sans SC", "Source Han Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif';
|
||||
break;
|
||||
case 'noto-serif-sc':
|
||||
return [
|
||||
'body' => '"Noto Serif SC", Georgia, "Songti SC", serif',
|
||||
'display' => '"Noto Serif SC", Georgia, "Songti SC", serif',
|
||||
'ui' => 'Inter, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif',
|
||||
];
|
||||
$stack = '"Noto Serif SC", "Source Han Serif SC", "Songti SC", "STSong", SimSun, serif';
|
||||
break;
|
||||
case 'custom':
|
||||
$stack = $custom !== '' ? $custom . ', ' . $system : $system;
|
||||
break;
|
||||
default:
|
||||
return [
|
||||
'body' => '"Source Serif 4", "Noto Serif SC", Georgia, "Songti SC", "STSong", serif',
|
||||
'display' => '"Source Serif 4", "Noto Serif SC", Georgia, "Songti SC", "STSong", serif',
|
||||
'ui' => 'Inter, Manrope, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',
|
||||
];
|
||||
$stack = $system;
|
||||
}
|
||||
return ['body' => $stack, 'display' => $stack, 'ui' => $stack];
|
||||
}
|
||||
|
||||
/** 参考主题色变量族(--theme-color / --focus-* 透明度)+ AKSRT --color-primary* 族;$hex 已由 Settings 校验。 */
|
||||
private function theme_color_vars(string $hex): string {
|
||||
$rgb = $this->hex_to_rgb($hex);
|
||||
$rgba = static function (float $alpha) use ($rgb): string {
|
||||
return sprintf('rgba(%d,%d,%d,%s)', $rgb[0], $rgb[1], $rgb[2], $alpha);
|
||||
};
|
||||
$vars = [
|
||||
'--theme-color' => $hex,
|
||||
'--focus-color' => $hex,
|
||||
'--focus-shadow-color' => $rgba(0.4),
|
||||
'--focus-color-opacity1' => $rgba(0.1),
|
||||
'--focus-color-opacity05' => $rgba(0.05),
|
||||
'--focus-color-opacity3' => $rgba(0.3),
|
||||
'--focus-color-opacity6' => $rgba(0.6),
|
||||
'--color-primary' => $hex,
|
||||
'--color-primary-hover' => $this->adjust_hex_color($hex, -0.12),
|
||||
'--color-primary-active' => $this->adjust_hex_color($hex, -0.22),
|
||||
'--color-primary-soft' => $rgba(0.12),
|
||||
'--color-primary-softer' => $rgba(0.06),
|
||||
'--color-primary-rgb' => implode(', ', $rgb),
|
||||
];
|
||||
$css = '';
|
||||
foreach ($vars as $name => $value) {
|
||||
$css .= $name . ':' . $this->css_value($value) . ';';
|
||||
}
|
||||
return $css;
|
||||
}
|
||||
|
||||
/** CSS-context escape for custom property values inside a <style> block. */
|
||||
private function css_value(string $value): string {
|
||||
return trim((string) preg_replace('/[<>{};\\\\]/', '', $value));
|
||||
}
|
||||
|
||||
private function hex_to_rgb(string $hex): array {
|
||||
|
||||
@@ -156,13 +156,15 @@ trait DisplayPageGroups {
|
||||
'site_favicon' => self::favicon_url(),
|
||||
'theme_mode' => self::theme_mode(),
|
||||
'theme_mode_button' => self::get_theme_mode_button_positions(),
|
||||
'primary_color' => self::primary_color(),
|
||||
'border_radius' => self::border_radius(),
|
||||
'theme_main_radius' => self::card_radius(),
|
||||
'theme_color' => self::theme_color(),
|
||||
'dark_theme_color' => self::dark_theme_color(),
|
||||
'theme_main_radius' => self::main_radius(),
|
||||
'close_backdrop' => self::close_backdrop(),
|
||||
'qj_loading' => self::is_qj_loading_enabled(),
|
||||
'qj_dh_xs' => self::get_qj_loading_style(),
|
||||
'container_max_width' => self::container_max_width(),
|
||||
'font_family' => self::font_family(),
|
||||
'font_family_custom' => self::font_family_custom(),
|
||||
'search_type' => !isset($s['search_type']) || !empty($s['search_type']),
|
||||
'search_type_in' => sanitize_key((string) ($s['search_type_in'] ?? 'post')),
|
||||
'search_placeholder' => self::search_placeholder(),
|
||||
|
||||
+22
-22
@@ -413,23 +413,16 @@ class Settings {
|
||||
|
||||
|
||||
|
||||
/** 获取主题色 */
|
||||
public static function primary_color(): string {
|
||||
return ThemeSearch::primary_color();
|
||||
/** 全局主题色(theme_skin_custom 优先,否则 theme_skin 预置色) */
|
||||
public static function theme_color(): string {
|
||||
return ThemeSearch::theme_color();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取主题皮肤预设 hex(解析 palette 选项为 #hex 格式) */
|
||||
public static function theme_skin(): string {
|
||||
return ThemeSearch::theme_skin();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取暗色模式独立主题色 */
|
||||
public static function dark_primary_color(): string {
|
||||
return ThemeSearch::dark_primary_color();
|
||||
/** 夜间模式主题色;未设置返回空串 */
|
||||
public static function dark_theme_color(): string {
|
||||
return ThemeSearch::dark_theme_color();
|
||||
}
|
||||
|
||||
|
||||
@@ -441,23 +434,23 @@ class Settings {
|
||||
|
||||
|
||||
|
||||
/** 获取最终生效的主题色(skin 优先于 custom primary_color) */
|
||||
public static function resolved_primary_color(): string {
|
||||
return ThemeSearch::resolved_primary_color();
|
||||
/** 卡片圆角 theme_main_radius */
|
||||
public static function main_radius(): int {
|
||||
return ThemeSearch::main_radius();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取全局圆角 */
|
||||
public static function border_radius(): int {
|
||||
return ThemeSearch::border_radius();
|
||||
/** 全局关闭背景高斯模糊 */
|
||||
public static function close_backdrop(): bool {
|
||||
return ThemeSearch::close_backdrop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取卡片圆角值(独立设置优先,否则 border_radius + 4) */
|
||||
public static function card_radius(): int {
|
||||
return ThemeSearch::card_radius();
|
||||
/** 背景图 CSS 声明(theme_img_bg / dark_theme_img_bg) */
|
||||
public static function background_css(string $key): string {
|
||||
return ThemeSearch::background_css($key);
|
||||
}
|
||||
|
||||
|
||||
@@ -490,6 +483,13 @@ class Settings {
|
||||
|
||||
|
||||
|
||||
/** 获取自定义字体栈(仅 font_family = custom 时生效) */
|
||||
public static function font_family_custom(): string {
|
||||
return ThemeSearch::font_family_custom();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取代码高亮配置
|
||||
*
|
||||
|
||||
@@ -345,10 +345,6 @@ class ThemeSearch {
|
||||
|
||||
public static function theme_mode(): string {
|
||||
$mode = sanitize_key((string) Settings::get_value('theme_mode', 'time-auto'));
|
||||
$map = ['light' => 'white-theme', 'dark' => 'dark-theme', 'auto' => 'time-auto'];
|
||||
if (isset($map[$mode])) {
|
||||
return $map[$mode];
|
||||
}
|
||||
$valid = ['white-theme', 'dark-theme', 'time-auto'];
|
||||
return in_array($mode, $valid, true) ? $mode : 'time-auto';
|
||||
}
|
||||
@@ -392,68 +388,71 @@ class ThemeSearch {
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function primary_color(): string {
|
||||
$color = trim((string) Settings::get_value('primary_color', '#f04494'));
|
||||
return preg_match('/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/', $color) ? $color : '#f04494';
|
||||
private const HEX_PATTERN = '/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/';
|
||||
|
||||
/** 全局主题色:theme_skin_custom 优先,清空时使用 theme_skin 预置色(对齐参考主题 zib_head_css)。 */
|
||||
public static function theme_color(): string {
|
||||
$custom = trim((string) Settings::get_value('theme_skin_custom', ''));
|
||||
if (preg_match(self::HEX_PATTERN, $custom)) {
|
||||
return $custom;
|
||||
}
|
||||
$skin = ltrim(trim((string) Settings::get_value('theme_skin', 'f04494')), '#');
|
||||
return preg_match('/^[0-9a-fA-F]{6}$/', $skin) ? '#' . $skin : '#f04494';
|
||||
}
|
||||
|
||||
public static function theme_skin(): string {
|
||||
$skin = trim((string) Settings::get_value('theme_skin', 'f04494'));
|
||||
$skin = ltrim($skin, '#');
|
||||
if (preg_match('/^[0-9a-fA-F]{6}$/', $skin)) {
|
||||
return '#' . $skin;
|
||||
}
|
||||
$legacy_map = [
|
||||
'pink' => '#f04494',
|
||||
'blue' => '#627bf5',
|
||||
'green' => '#36af18',
|
||||
'purple' => '#ae53f3',
|
||||
'custom' => '',
|
||||
];
|
||||
if (isset($legacy_map[$skin])) {
|
||||
return $legacy_map[$skin] !== '' ? $legacy_map[$skin] : self::primary_color();
|
||||
}
|
||||
return self::primary_color();
|
||||
}
|
||||
|
||||
public static function dark_primary_color(): string {
|
||||
$color = trim((string) Settings::get_value('dark_primary_color', ''));
|
||||
if (preg_match('/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/', $color)) {
|
||||
return $color;
|
||||
}
|
||||
return self::primary_color();
|
||||
/** 夜间模式主题色;未设置返回空串,夜间沿用全局主题色。 */
|
||||
public static function dark_theme_color(): string {
|
||||
$color = trim((string) Settings::get_value('dark_theme_skin_custom', ''));
|
||||
return preg_match(self::HEX_PATTERN, $color) ? $color : '';
|
||||
}
|
||||
|
||||
public static function get_theme_mode_button_positions(): array {
|
||||
$raw = Settings::get_value('theme_mode_button', ['pc_nav', 'm_menu']);
|
||||
if (is_array($raw)) {
|
||||
return array_values(array_filter(array_map('sanitize_text_field', $raw)));
|
||||
}
|
||||
if (is_bool($raw)) {
|
||||
return $raw ? ['pc_nav', 'm_menu'] : [];
|
||||
}
|
||||
$str = trim((string) $raw);
|
||||
if ($str === '' || $str === '0') return [];
|
||||
$items = preg_split('/[,|]+/', $str) ?: [];
|
||||
return array_values(array_filter(array_map('sanitize_text_field', $items)));
|
||||
return array_values(array_intersect(array_map('sanitize_key', (array) $raw), ['pc_nav', 'm_menu']));
|
||||
}
|
||||
|
||||
public static function resolved_primary_color(): string {
|
||||
$skin = self::theme_skin();
|
||||
return $skin !== '' ? $skin : self::primary_color();
|
||||
/** 卡片圆角 theme_main_radius(0–30,默认 12)→ --main-radius。 */
|
||||
public static function main_radius(): int {
|
||||
return max(0, min(30, (int) Settings::get_value('theme_main_radius', 12)));
|
||||
}
|
||||
|
||||
public static function border_radius(): int {
|
||||
$radius = (int) Settings::get_value('border_radius', 8);
|
||||
return max(0, min(20, $radius));
|
||||
public static function close_backdrop(): bool {
|
||||
return !empty(Settings::get_value('close_backdrop', false));
|
||||
}
|
||||
|
||||
public static function card_radius(): int {
|
||||
$main = Settings::get_value('theme_main_radius', null);
|
||||
if ($main !== null && $main !== '') {
|
||||
return max(0, min(30, (int) $main));
|
||||
/**
|
||||
* 背景图 CSS 声明(不含选择器);无颜色且无图片时返回空串。
|
||||
* 子键白名单与 GlobalSchema::background_field() / layout.js bgField 一致。
|
||||
*/
|
||||
public static function background_css(string $key): string {
|
||||
$bg = Settings::get_value($key, []);
|
||||
if (!is_array($bg)) {
|
||||
return '';
|
||||
}
|
||||
return self::border_radius() + 4;
|
||||
$color = trim((string) ($bg['color'] ?? ''));
|
||||
$color = preg_match(self::HEX_PATTERN, $color) ? $color : '';
|
||||
$image = esc_url_raw(trim((string) ($bg['image'] ?? '')));
|
||||
if ($color === '' && $image === '') {
|
||||
return '';
|
||||
}
|
||||
$allowed = [
|
||||
'position' => ['left top', 'left center', 'left bottom', 'center top', 'center center', 'center bottom', 'right top', 'right center', 'right bottom'],
|
||||
'repeat' => ['repeat', 'no-repeat', 'repeat-x', 'repeat-y'],
|
||||
'attachment' => ['scroll', 'fixed'],
|
||||
'size' => ['100%', 'cover', 'contain', 'auto'],
|
||||
'origin' => ['padding-box', 'border-box', 'content-box'],
|
||||
];
|
||||
$css = $color !== '' ? 'background-color:' . $color . ';' : '';
|
||||
if ($image !== '') {
|
||||
$css .= 'background-image:url("' . str_replace(['"', '\\', "\n", "\r"], '', $image) . '");';
|
||||
foreach ($allowed as $prop => $values) {
|
||||
$value = (string) ($bg[$prop] ?? '');
|
||||
if (in_array($value, $values, true)) {
|
||||
$css .= 'background-' . $prop . ':' . $value . ';';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $css;
|
||||
}
|
||||
|
||||
public static function is_qj_loading_enabled(): bool {
|
||||
@@ -470,9 +469,6 @@ class ThemeSearch {
|
||||
|
||||
public static function container_max_width(): int {
|
||||
$width = (int) Settings::get_value('container_max_width', 1200);
|
||||
if ($width === 0) {
|
||||
return 0;
|
||||
}
|
||||
return max(1200, min(2200, $width));
|
||||
}
|
||||
|
||||
@@ -481,6 +477,13 @@ class ThemeSearch {
|
||||
return in_array($family, ['system', 'noto-sans-sc', 'noto-serif-sc', 'custom'], true) ? $family : 'system';
|
||||
}
|
||||
|
||||
/** 自定义 font-family 字体栈,只保留字体名、引号、逗号等安全字符。 */
|
||||
public static function font_family_custom(): string {
|
||||
$stack = (string) Settings::get_value('font_family_custom', '');
|
||||
$stack = preg_replace('/[^\p{L}\p{N}\s,"\'\-_.]/u', '', $stack);
|
||||
return trim((string) preg_replace('/\s+/', ' ', (string) $stack), " ,");
|
||||
}
|
||||
|
||||
public static function get_code_highlight_config(): array {
|
||||
$s = Settings::get_all();
|
||||
|
||||
|
||||
@@ -865,14 +865,14 @@ test('content max width is one contract from admin option to runtime var', () =>
|
||||
const themeSearch = read('src/Settings/ThemeSearch.php');
|
||||
const builder = read('src/Frontend/InlineStyleBuilder.php');
|
||||
|
||||
// Every width the settings UI offers must pass REST validation, or the save is
|
||||
// rejected and the rendered width silently keeps the previous value.
|
||||
const pxOptions = [...layoutSchema.matchAll(/value: (\d+) \}/g)].map((match) => Number(match[1]));
|
||||
assert.ok(pxOptions.includes(1200));
|
||||
assert.ok(pxOptions.includes(2200));
|
||||
const schemaMax = Number(globalSchema.match(/'container_max_width'[\s\S]*?'max' => (\d+)/)[1]);
|
||||
assert.equal(schemaMax, Math.max(...pxOptions));
|
||||
assert.match(globalSchema.match(/'container_max_width'[^\n]*/)[0], /'min' => 0/);
|
||||
// Free number input (zibll layout_max_width parity): UI range, REST validation
|
||||
// and runtime clamp must agree, or saves are rejected / silently clamped.
|
||||
const vueField = layoutSchema.match(/key: 'container_max_width'[^\n]*/)[0];
|
||||
assert.match(vueField, /type: 'number'/);
|
||||
assert.match(vueField, /min: 1200, max: 2200, step: 50/);
|
||||
const phpField = globalSchema.match(/'container_max_width'[^\n]*/)[0];
|
||||
assert.match(phpField, /'type' => 'number'/);
|
||||
assert.match(phpField, /'min' => 1200, 'max' => 2200, 'step' => 50/);
|
||||
|
||||
assert.match(themeSearch, /max\(1200, min\(2200, \$width\)\)/);
|
||||
assert.match(builder, /'--container'\s*=> \$content_width/);
|
||||
|
||||
Reference in new issue
Block a user