From 74021d26bb118215eda0c98ee9dda2dd51717ddb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 28 Oct 2026 19:36:11 +0800 Subject: [PATCH] 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 --- .../src/schema/sections/global/layout.js | 117 +++++++++------ src/Admin/Schema/GlobalSchema.php | 98 +++++++++---- src/Core/ScriptsPart2.php | 5 + src/Frontend/InlineStyleBuilder.php | 137 ++++++++++-------- src/Settings/DisplayPageGroups.php | 8 +- src/Settings/Settings.php | 44 +++--- src/Settings/ThemeSearch.php | 115 ++++++++------- .../post-visual-contract.test.cjs | 16 +- 8 files changed, 319 insertions(+), 221 deletions(-) diff --git a/assets/admin/src/schema/sections/global/layout.js b/assets/admin/src/schema/sections/global/layout.js index 2a35fa0e..6be77a22 100644 --- a/assets/admin/src/schema/sections/global/layout.js +++ b/assets/admin/src/schema/sections/global/layout.js @@ -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 字体栈,多个字体用英文逗号分隔;留空使用系统字体。' }, ], }, ], diff --git a/src/Admin/Schema/GlobalSchema.php b/src/Admin/Schema/GlobalSchema.php index b2912999..cc1fa3cf 100644 --- a/src/Admin/Schema/GlobalSchema.php +++ b/src/Admin/Schema/GlobalSchema.php @@ -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', + ])], + ], + ]; + } } diff --git a/src/Core/ScriptsPart2.php b/src/Core/ScriptsPart2.php index 60ad71a1..dee1a085 100644 --- a/src/Core/ScriptsPart2.php +++ b/src/Core/ScriptsPart2.php @@ -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) { diff --git a/src/Frontend/InlineStyleBuilder.php b/src/Frontend/InlineStyleBuilder.php index b968f406..4e67c934 100644 --- a/src/Frontend/InlineStyleBuilder.php +++ b/src/Frontend/InlineStyleBuilder.php @@ -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 '' . "\n"; + // 对齐参考主题 zib_head_css():主题色变量与 --main-radius 挂在 body(main.css 的定义层级), + // 夜间主题色仅在单独设置时覆盖 body.dark-theme。 + echo '' . "\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 '' . "\n"; - } echo '' . "\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