fix(admin): stop cropping the layout preview images in image_select

AksImageSelectField pinned every preview to a 60x60 box with
object-fit:cover, but these are wide layout strips: header layouts are
597x57 (10.47:1), the footer template is 800x190 (4.21:1) and the slide
align set is 200x101. A 10:1 strip inside a square crop keeps ~6% of its
width, so the layout it is supposed to illustrate is unrecognisable.

Constrain the width instead and let the height follow, which is what the
reference theme's CSF image_select does (max-width:100%; height:auto).
Each field now declares the width that suits its images, and an option
may still override it: header 200, footer 240, slide align 160, mobile
header 120.

Only presentation changed. No image files and no stored values moved,
so existing settings are unaffected.
This commit is contained in:
kate522 committed 2026-11-01 12:18:14 +08:00
1 parent 4740078135
commit df12f51199
4 files changed
+32 -16

No files matched your search

@@ -329,6 +329,7 @@
:model-value="modelValue"
:options="normalizedOptions"
:disabled="schema.disabled"
:preview-width="schema.previewWidth"
@update:model-value="emit('update:modelValue', $event)"
/>
@@ -11,8 +11,8 @@
:disabled="disabled"
@click="emit('update:modelValue', opt.value)"
>
<img v-if="opt.image" :src="opt.image" :alt="opt.label" class="aksrt-image-select__img" />
<span v-else class="aksrt-image-select__placeholder">
<img v-if="opt.image" :src="opt.image" :alt="opt.label" class="aksrt-image-select__img" :style="imgStyle(opt)" />
<span v-else class="aksrt-image-select__placeholder" :style="imgStyle(opt)">
<FaIcon :icon="opt.icon || 'fa fas fa-image'" :size="20" />
</span>
<span class="aksrt-image-select__label">{{ opt.label }}</span>
@@ -24,12 +24,21 @@
/** image_select:带预览图的单选。 */
import FaIcon from './FaIcon.vue'
defineProps({
const props = defineProps({
modelValue: { default: null },
options: { type: Array, default: () => [] },
disabled: { type: Boolean, default: false },
// Preview width in px. Layout strips (header/footer) are very wide and only
// need enough width to be legible; near-square previews want more room.
previewWidth: { type: [Number, String], default: 140 },
})
const emit = defineEmits(['update:modelValue'])
// An option may override the group width via its own `width`.
function imgStyle(opt) {
const width = opt && opt.width ? opt.width : props.previewWidth
return { '--aksrt-image-select-max': typeof width === 'number' ? `${width}px` : width }
}
</script>
<style scoped>
@@ -69,17 +78,23 @@ const emit = defineEmits(['update:modelValue'])
}
.aksrt-image-select__img {
width: 60px;
height: 60px;
object-fit: cover;
display: block;
/* Preview images are wide layout strips (header 597x57, footer 800x190, slide
align 200x101), so let them keep their own aspect ratio inside the card.
A fixed square box with object-fit:cover crops the layout to an
unrecognisable sliver — the width is capped instead and the height follows. */
width: 100%;
max-width: var(--aksrt-image-select-max, 140px);
height: auto;
border-radius: 4px;
background: var(--aksrt-color-canvas);
}
.aksrt-image-select__placeholder {
display: flex;
align-items: center;
justify-content: center;
width: 60px;
width: var(--aksrt-image-select-max, 140px);
height: 60px;
border-radius: 4px;
background: var(--aksrt-color-canvas);
+4 -4
View File
@@ -45,8 +45,8 @@ class SchemaPageDisplay {
self::field('header_theme_bg_custom', '导航栏:背景色', 'color', '', ['dependsOn' => self::enabled('header_theme_custom'), 'description' => '如需选择预置颜色,请先清空此颜色。']),
self::field('header_theme_bg', '', 'palette', '', ['dependsOn' => ['all' => [self::enabled('header_theme_custom'), ['key' => 'header_theme_bg_custom', 'operator' => 'empty']]], 'options' => self::solid_palette()]),
self::field('header_theme_color_custom', '导航栏:前景色', 'color', '', ['dependsOn' => self::enabled('header_theme_custom'), 'description' => '请注意背景色和前景色的搭配,以免文字看不清。']),
self::field('header_layout', '电脑端导航布局', 'image_select', '1', ['options' => self::header_layout_options()]),
self::field('mobile_header_layout', '移动端导航布局', 'image_select', 'center', ['options' => self::mobile_header_layout_options()]),
self::field('header_layout', '电脑端导航布局', 'image_select', '1', ['previewWidth' => 200, 'options' => self::header_layout_options()]),
self::field('mobile_header_layout', '移动端导航布局', 'image_select', 'center', ['previewWidth' => 120, 'options' => self::mobile_header_layout_options()]),
self::field('mobile_navbar_align', '移动端菜单弹出方向', 'radio', 'left', ['inline' => true, 'options' => self::options(['top' => '顶部', 'left' => '左边', 'right' => '右边'])]),
self::field('nav_fixed', '导航浮动', 'switcher', true, ['description' => '导航栏一直固定在顶部。']),
self::field('nav_scroll_down_hide', '页面向下滚动时隐藏', 'switcher', true, ['dependsOn' => self::enabled('nav_fixed'), 'description' => '下滚动隐藏,上滚动显示。']),
@@ -80,7 +80,7 @@ class SchemaPageDisplay {
self::field('footer_theme_bg_custom', '底部页脚:背景色', 'color', '', ['dependsOn' => self::enabled('footer_theme_custom')]),
self::field('footer_theme_bg', '', 'palette', '', ['dependsOn' => ['all' => [self::enabled('footer_theme_custom'), ['key' => 'footer_theme_bg_custom', 'operator' => 'empty']]], 'options' => self::solid_palette()]),
self::field('footer_theme_color_custom', '底部页脚:前景色', 'color', '', ['dependsOn' => self::enabled('footer_theme_custom')]),
self::field('fcode_template', '页脚布局模板选择', 'image_select', 'template_1', ['options' => [['label' => '模板一', 'value' => 'template_1', 'image' => self::asset('assets/images/footer/fcode_template_1.png')]]]),
self::field('fcode_template', '页脚布局模板选择', 'image_select', 'template_1', ['previewWidth' => 240, 'options' => [['label' => '模板一', 'value' => 'template_1', 'image' => self::asset('assets/images/footer/fcode_template_1.png')]]]),
self::field('footer_t1_m_s', '版块一移动端显示', 'switcher', false),
self::field('footer_t1_img', '日间模式图片', 'upload', $img . 'logo.png'),
self::field('footer_t1_img_dark', '夜间模式图片', 'upload', $img . 'logo_dark.png'),
@@ -168,7 +168,7 @@ class SchemaPageDisplay {
return [
self::field('background', '图片背景', 'upload', ''), self::field('background_video', '视频背景', 'upload', '', ['media_type' => 'video']), self::field('hide', '显示规则', 'radio', '', ['options' => self::options(['' => '全部显示', 'pc' => 'PC端不显示', 'm' => '移动端不显示'])]), self::field('link', '跳转链接', 'link', []),
self::field('image_layer', '叠加图层', 'group', [], ['button_title' => '添加图层', 'fields' => [self::field('image', '图层图片', 'upload', ''), self::field('free_size', '自由尺寸', 'switcher', false), self::field('align', '图层对齐', 'radio', 'center', ['dependsOn' => ['all' => [self::not_empty('image'), self::enabled('free_size')]], 'options' => self::options(['left' => '靠左显示', 'center' => '居中显示', 'right' => '靠右显示'])]), self::field('parallax', '视差滚动', 'number', 0, ['dependsOn' => self::not_empty('image'), 'min' => -200, 'max' => 200, 'step' => 5]), self::field('parallax_scale', '视差缩放', 'number', 100, ['dependsOn' => self::not_empty('image'), 'min' => 1, 'max' => 200, 'step' => 5]), self::field('parallax_opacity', '视差透明', 'number', 100, ['dependsOn' => ['all' => [self::not_empty('image'), self::not_empty('parallax')]], 'min' => 1, 'max' => 100, 'step' => 5])]]),
self::field('text', '叠加文案', 'accordion', ['title' => '', 'desc' => '', 'text_align' => 'left-bottom', 'text_size_pc' => 30, 'text_size_m' => 20, 'parallax' => 40], ['fields' => [self::field('title', '幻灯片标题', 'textarea', '', ['sanitize_type' => 'html']), self::field('desc', '幻灯片简介', 'textarea', '', ['dependsOn' => self::not_empty('title'), 'sanitize_type' => 'html']), self::field('text_align', '显示位置', 'image_select', 'left-bottom', ['dependsOn' => self::not_empty('title'), 'options' => self::text_align_options()]), self::field('text_size_pc', 'PC端字体大小', 'number', 30, ['dependsOn' => self::not_empty('title'), 'min' => 12, 'max' => 50, 'step' => 1]), self::field('text_size_m', '移动端字体大小', 'number', 20, ['dependsOn' => self::not_empty('title'), 'min' => 12, 'max' => 50, 'step' => 1]), self::field('parallax', '文案视差滚动', 'number', 40, ['dependsOn' => self::not_empty('title'), 'min' => -200, 'max' => 200, 'step' => 10])]]),
self::field('text', '叠加文案', 'accordion', ['title' => '', 'desc' => '', 'text_align' => 'left-bottom', 'text_size_pc' => 30, 'text_size_m' => 20, 'parallax' => 40], ['fields' => [self::field('title', '幻灯片标题', 'textarea', '', ['sanitize_type' => 'html']), self::field('desc', '幻灯片简介', 'textarea', '', ['dependsOn' => self::not_empty('title'), 'sanitize_type' => 'html']), self::field('text_align', '显示位置', 'image_select', 'left-bottom', ['dependsOn' => self::not_empty('title'), 'previewWidth' => 160, 'options' => self::text_align_options()]), self::field('text_size_pc', 'PC端字体大小', 'number', 30, ['dependsOn' => self::not_empty('title'), 'min' => 12, 'max' => 50, 'step' => 1]), self::field('text_size_m', '移动端字体大小', 'number', 20, ['dependsOn' => self::not_empty('title'), 'min' => 12, 'max' => 50, 'step' => 1]), self::field('parallax', '文案视差滚动', 'number', 40, ['dependsOn' => self::not_empty('title'), 'min' => -200, 'max' => 200, 'step' => 10])]]),
];
}
+5 -5
View File
@@ -1,5 +1,5 @@
{
"generated_at": "2026-11-01T03:45:46+00:00",
"generated_at": "2026-11-01T04:11:06+00:00",
"errors": [],
"warnings": [
"customPage tools-update section 'tools/update' not in PHP schema (ok if pure operational page)",
@@ -258,7 +258,7 @@
"entry": true,
"missing_chunks": [],
"chunks": [
"SchemaPage.BM05qq7c.js",
"SchemaPage.YNr16Fc9.js",
"vendor-vue.CibbKclz.js",
"FaIcon.DB-L86Cm.js",
"useCollapsibleItems.B7EjDmsr.js",
@@ -276,8 +276,8 @@
"FloatingButtonsSettings.DYWR59AW.js",
"PageHeader.UHsfBDVL.js",
"FooterTabbarSettings.D8ujMgd9.js",
"PostPageSettings.Bhei4Dk4.js",
"CommentSettings.Ct-HES9S.js",
"PostPageSettings.D8BXJ07f.js",
"CommentSettings.1Il-GVqw.js",
"PermissionsCapabilities.DXXFzINq.js",
"CmsCredits.DESOnIkP.js",
"ThemeInfoPage.D5AogccB.js",
@@ -287,7 +287,7 @@
"UsersLevel.B-jXEukF.js",
"UsersBadge.DVCEC3QE.js",
"UsersWechatTemplate.DHoNsqm_.js",
"UsersTicket.DcwmQE5D.js",
"UsersTicket.D5BTFq6U.js",
"ToolsImportExport.C-XhCKwl.js",
"ToolsHealth.DNZ1YaWo.js",
"ToolsUpdate.38p6GYou.js"