fix(header): 1:1 zibll overlay icon cards for top multifunc component

Rebuild header-slider card DOM/CSS against zib_header_slide + zib_icon_cover_card so shared/individual backgrounds, flex gutters, and badge icons match the reference theme.
This commit is contained in:
kate522 committed 2026-07-24 10:30:22 +08:00
1 parent bbdeeafc80
commit e35011f2c0
7 files changed
+384 -463

No files matched your search

@@ -12,292 +12,149 @@ body.dark-theme .header-components-search__input {
} }
/* ============================================================ /* ============================================================
* Layer 3: 图标卡片(模仿 zibll — 骑在 hero 底部边界线上) * Layer 3: Icon cards — 1:1 zibll header-slider-card
* * DOM: .header-slider-card.container > (.zib-widget.padding-10|div)
* 关键技术:卡片在 DOM 中位于轮播之后, * > .flex.jse.flex-row.gutters-5.flex-col-sm-2
* 使用 margin-top: -40px 向上拉,使其骑在 hero 底部边界线上 * > (.flex1|.relative-h) > [.main-color >] .icon-cover-card.flex.ac.(zib-widget|padding-10)
* ============================================================ */ * ============================================================ */
.header-slider-card,
.header-components-card { .header-components-card {
position: relative; position: relative;
z-index: 1;
margin-top: -40px; margin-top: -40px;
z-index: 1;
} }
.header-components-card__container { .header-slider-card .zib-widget,
max-width: var(--container, 1280px); .header-components-card .zib-widget {
margin: 0 auto; margin-bottom: 0;
padding: 0 16px;
} }
/* 卡片行:flex 水平排列 */ /* Individual card surface = .zib-widget (from card-primitives); shared mode uses outer .zib-widget.padding-10 */
.header-components-card__row { .header-slider-card .icon-cover-card.zib-widget,
display: flex; .header-components-card .icon-cover-card.zib-widget {
gap: 10px; margin-bottom: 0;
padding-top: 4px; /* 为 hover 上浮留出空间 */
} }
/* 每个卡片项等宽 */ /* zibll filter-blur glass on card surfaces + search form */
.header-components-card__item { .filter-blur .header-slider-search .line-form,
flex: 1; .filter-blur .header-components-search .line-form,
min-width: 0; .filter-blur .header-slider-card .zib-widget,
.filter-blur .header-components-card .zib-widget {
-webkit-backdrop-filter: saturate(5) blur(20px);
backdrop-filter: saturate(5) blur(20px);
} }
/* 共享背景模式:一个大卡片包裹 */ .filter-blur .header-slider-card .zib-widget,
.header-components-card__wrap--shared { .filter-blur .header-components-card .zib-widget {
background: var(--surface-page); background: var(--blur-bg, rgba(255, 255, 255, 0.75));
border-radius: 8px;
padding: 10px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
border: 1px solid var(--color-line);
} }
/* 独立背景模式:每个卡片有自己的背景 */ .theme-dark .filter-blur .header-slider-card .zib-widget,
.header-components-card__item-bg { html.dark .filter-blur .header-slider-card .zib-widget,
background: var(--surface-page); body.dark-theme .filter-blur .header-slider-card .zib-widget,
border-radius: 8px; .theme-dark .filter-blur .header-components-card .zib-widget,
padding: 12px 14px; html.dark .filter-blur .header-components-card .zib-widget,
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); body.dark-theme .filter-blur .header-components-card .zib-widget {
border: 1px solid var(--color-line); background: var(--blur-bg, rgba(30, 30, 30, 0.75));
height: 100%;
transition: transform 0.2s ease, box-shadow 0.2s ease;
} }
.header-components-card__item-bg:hover { /* Device-split blur (AKSRT extension of zibll filter-blur) */
transform: none;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
/* 毛玻璃效果 */
.filter-blur .header-components-card__wrap--shared,
.filter-blur .header-components-card__item-bg {
background: rgba(255, 255, 255, 0.75);
backdrop-filter: saturate(3) blur(20px);
-webkit-backdrop-filter: saturate(3) blur(20px);
border-color: rgba(255, 255, 255, 0.3);
}
.theme-dark .filter-blur .header-components-card__wrap--shared,
html.dark .filter-blur .header-components-card__wrap--shared,
body.dark-theme .filter-blur .header-components-card__wrap--shared,
.theme-dark .filter-blur .header-components-card__item-bg,
html.dark .filter-blur .header-components-card__item-bg,
body.dark-theme .filter-blur .header-components-card__item-bg {
background: rgba(30, 30, 30, 0.75);
border-color: rgba(255, 255, 255, 0.1);
}
/* ============================================================
* 单个图标卡片样式(模仿 zibll icon-cover-card)
* 结构:左侧圆形图标 + 右侧标题/描述
* ============================================================ */
.icon-cover-card {
display: flex;
align-items: center;
gap: 10px;
padding: 8px;
border-radius: 6px;
text-decoration: none;
color: var(--color-ink);
transition: background 0.15s ease;
}
a.icon-cover-card:hover {
background: var(--surface-3);
text-decoration: none;
color: var(--color-ink);
}
/* 图标容器 — 圆形 */
.icon-cover-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
min-width: 40px;
border-radius: 50%;
font-size: 18px;
flex-shrink: 0;
}
/* 方形图标 */
.icon-cover-icon.radius4 {
border-radius: 6px;
}
/* 图标颜色类(模仿 zibll 的调色板) */
.icon-cover-icon.c-blue {
background: rgba(66, 133, 244, 0.12);
color: #4285f4;
}
.icon-cover-icon.c-yellow {
background: rgba(251, 188, 4, 0.12);
color: #fbbc04;
}
.icon-cover-icon.c-green {
background: rgba(52, 168, 83, 0.12);
color: #34a853;
}
.icon-cover-icon.c-red {
background: rgba(234, 67, 53, 0.12);
color: #ea4335;
}
.icon-cover-icon.c-orange {
background: rgba(255, 152, 0, 0.12);
color: #ff9800;
}
.icon-cover-icon.c-cyan {
background: rgba(0, 188, 212, 0.12);
color: #00bcd4;
}
.icon-cover-icon.c-pink {
background: rgba(233, 30, 99, 0.12);
color: #e91e63;
}
/* 渐变图标背景 */
.icon-cover-icon.jb-cyan {
background: linear-gradient(135deg, #4facfe, #00f2fe);
color: #fff;
}
.icon-cover-icon.jb-green {
background: linear-gradient(135deg, #43e97b, #38f9d7);
color: #fff;
}
.icon-cover-icon.jb-orange {
background: linear-gradient(135deg, #fa709a, #fee140);
color: #fff;
}
/* 文字区 */
.icon-cover-desc {
flex: 1;
min-width: 0;
overflow: hidden;
}
.icon-cover-title {
font-size: 13px;
font-weight: 600;
line-height: 1.3;
color: var(--color-ink);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.icon-cover-subtitle {
font-size: 11px;
color: var(--color-ink-4);
margin-top: 2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.3;
}
/* ============================================================
* 响应式
* ============================================================ */
@media (max-width: 767px) {
.header-components-card {
margin-top: -35px;
}
.header-components-card__row {
flex-wrap: wrap;
gap: 6px;
}
/* 移动端 2 列 */
.header-components-card__item {
flex: 0 0 calc(50% - 3px);
}
.header-components-card__item-bg {
padding: 10px;
}
.header-components-card__wrap--shared {
padding: 6px;
}
.icon-cover-card {
gap: 6px;
padding: 6px;
}
.icon-cover-icon {
width: 32px;
height: 32px;
min-width: 32px;
font-size: 14px;
}
.icon-cover-title {
font-size: 12px;
}
.icon-cover-subtitle {
display: none;
}
}
@media (max-width: 480px) {
.icon-cover-card {
gap: 4px;
padding: 2px;
}
.icon-cover-icon {
width: 28px;
height: 28px;
min-width: 28px;
font-size: 12px;
}
}
/* ============================================================
* Container-level blur: PC/Mobile split (colors only; no top offsets)
* ============================================================ */
@media (min-width: 768px) { @media (min-width: 768px) {
.has-blur-pc .header-components-card__wrap--shared, .has-blur-pc .header-slider-card .zib-widget,
.has-blur-pc .header-components-card__item-bg { .has-blur-pc .header-components-card .zib-widget {
background: rgba(255, 255, 255, 0.75); -webkit-backdrop-filter: saturate(5) blur(20px);
backdrop-filter: saturate(3) blur(20px); backdrop-filter: saturate(5) blur(20px);
-webkit-backdrop-filter: saturate(3) blur(20px); background: var(--blur-bg, rgba(255, 255, 255, 0.75));
border-color: rgba(255, 255, 255, 0.3);
} }
.has-blur-pc .header-components-search .line-form, .has-blur-pc .header-components-search .line-form,
.has-blur-pc .header-slider-search .line-form { .has-blur-pc .header-slider-search .line-form {
background: rgba(255, 255, 255, 0.75); background: rgba(255, 255, 255, 0.75);
} }
.theme-dark .has-blur-pc .header-components-card__wrap--shared, .theme-dark .has-blur-pc .header-slider-card .zib-widget,
html.dark .has-blur-pc .header-components-card__wrap--shared, html.dark .has-blur-pc .header-slider-card .zib-widget,
.theme-dark .has-blur-pc .header-components-card__item-bg, .theme-dark .has-blur-pc .header-components-card .zib-widget,
html.dark .has-blur-pc .header-components-card__item-bg { html.dark .has-blur-pc .header-components-card .zib-widget {
background: rgba(30, 30, 30, 0.75); background: var(--blur-bg, rgba(30, 30, 30, 0.75));
border-color: rgba(255, 255, 255, 0.1);
} }
} }
@media (max-width: 767px) { @media (max-width: 767px) {
.has-blur-mobile .header-components-card__wrap--shared, .has-blur-mobile .header-slider-card .zib-widget,
.has-blur-mobile .header-components-card__item-bg { .has-blur-mobile .header-components-card .zib-widget {
background: rgba(255, 255, 255, 0.75); -webkit-backdrop-filter: saturate(5) blur(20px);
backdrop-filter: saturate(3) blur(20px); backdrop-filter: saturate(5) blur(20px);
-webkit-backdrop-filter: saturate(3) blur(20px); background: var(--blur-bg, rgba(255, 255, 255, 0.75));
border-color: rgba(255, 255, 255, 0.3);
} }
.has-blur-mobile .header-components-search .line-form, .has-blur-mobile .header-components-search .line-form,
.has-blur-mobile .header-slider-search .line-form { .has-blur-mobile .header-slider-search .line-form {
background: rgba(255, 255, 255, 0.75); background: rgba(255, 255, 255, 0.75);
} }
.theme-dark .has-blur-mobile .header-components-card__wrap--shared, .theme-dark .has-blur-mobile .header-slider-card .zib-widget,
html.dark .has-blur-mobile .header-components-card__wrap--shared, html.dark .has-blur-mobile .header-slider-card .zib-widget,
.theme-dark .has-blur-mobile .header-components-card__item-bg, .theme-dark .has-blur-mobile .header-components-card .zib-widget,
html.dark .has-blur-mobile .header-components-card__item-bg { html.dark .has-blur-mobile .header-components-card .zib-widget {
background: rgba(30, 30, 30, 0.75); background: var(--blur-bg, rgba(30, 30, 30, 0.75));
border-color: rgba(255, 255, 255, 0.1); }
.header-slider-card .icon-cover-card.zib-widget,
.header-components-card .icon-cover-card.zib-widget {
padding: 10px;
}
.header-slider-card .icon-cover-card.padding-10,
.header-components-card .icon-cover-card.padding-10 {
padding: 2px;
}
.header-slider-card,
.header-components-card {
margin-top: -35px;
} }
} }
/* icon-cover-card itself is a flex row — do NOT re-skin as a bordered box here.
* Surface comes from .zib-widget / .padding-10; icon badge from .badg.cir + c-*/jb-*. */
.header-slider-card .icon-cover-card,
.header-components-card .icon-cover-card {
display: flex;
align-items: center;
gap: 0;
/* padding comes from .zib-widget or .padding-10 class on the same node */
}
.header-slider-card a.main-color,
.header-components-card a.main-color {
color: inherit;
text-decoration: none;
display: block;
}
.header-slider-card a.main-color:hover,
.header-components-card a.main-color:hover {
color: inherit;
text-decoration: none;
}
/* Let .badg.cir + color modifiers drive icon look; only size/image tweaks here */
.header-slider-card .icon-cover-icon.badg.cir,
.header-components-card .icon-cover-icon.badg.cir {
display: inline-flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
}
.header-slider-card .icon-cover-icon img,
.header-components-card .icon-cover-icon img {
width: 70%;
height: 70%;
object-fit: contain;
}
.header-slider-card .icon-cover-desc,
.header-components-card .icon-cover-desc {
min-width: 0;
overflow: hidden;
}
.header-slider-card .icon-cover-desc .font-bold,
.header-components-card .icon-cover-desc .font-bold {
font-weight: bold;
}
@@ -100,48 +100,16 @@
margin-top: -35px; margin-top: -35px;
} }
.header-components-card__container {
padding: 0 10px; .header-slider-card .icon-cover-card.zib-widget,
.header-components-card .icon-cover-card.zib-widget {
padding: 10px;
}
.header-slider-card .icon-cover-card.padding-10,
.header-components-card .icon-cover-card.padding-10 {
padding: 2px;
} }
.header-components-card__row {
flex-wrap: wrap;
gap: 6px;
}
.header-components-card__item {
flex: 0 0 calc(50% - 3px);
}
.header-components-card__item-bg {
padding: 8px 10px;
}
.header-components-card__wrap--shared {
padding: 6px;
}
.icon-cover-card {
gap: 6px;
padding: 4px;
min-height: 52px;
border-radius: 6px;
}
.icon-cover-icon {
width: 30px;
height: 30px;
min-width: 30px;
font-size: 14px;
}
.icon-cover-title {
font-size: 12px;
}
.icon-cover-subtitle {
display: none;
}
/* zibll ~640px: slide-header text padding 52px */ /* zibll ~640px: slide-header text padding 52px */
.header-components.slide-header .slide-text, .header-components.slide-header .slide-text,
+9 -18
View File
@@ -1862,31 +1862,21 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0; gap: 0;
padding: 12px; /* Surface: .zib-widget / .padding-10 on same node (zibll). Do not re-box. */
border-radius: 8px;
background: var(--surface-1, #fff);
border: 1px solid var(--color-line, #e5e7eb);
transition: box-shadow .2s ease, transform .2s ease;
} }
a.main-color > .icon-cover-card:hover, a.main-color > .icon-cover-card:hover {
.icon-cover-card:hover { opacity: 0.92;
box-shadow: 0 6px 18px rgba(0,0,0,.06);
transform: translateY(-1px);
} }
/* Icon badge uses .badg.cir (+ c-* / jb-*); only ensure flex centering. */
.icon-cover-icon.badg.cir { .icon-cover-icon.badg.cir {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 2.4em;
height: 2.4em;
min-width: 2.4em;
border-radius: 50%;
background: rgba(59, 130, 246, 0.12);
color: #2563eb;
flex-shrink: 0; flex-shrink: 0;
} }
.icon-cover-icon.radius4 { .icon-cover-icon.radius4,
border-radius: 10px !important; .icon-cover-icon.badg.cir.radius4 {
border-radius: 4px !important;
} }
.icon-cover-icon img { .icon-cover-icon img {
width: 70%; width: 70%;
@@ -1895,9 +1885,10 @@ a.main-color > .icon-cover-card:hover,
} }
.icon-cover-desc { .icon-cover-desc {
min-width: 0; min-width: 0;
overflow: hidden;
} }
.icon-cover-desc .font-bold { .icon-cover-desc .font-bold {
font-weight: 700; font-weight: bold;
} }
/* Buttons wrap (zibll flex hh) */ /* Buttons wrap (zibll flex hh) */
+23
View File
@@ -25,6 +25,29 @@
.flex1 { flex: 1 1 auto; min-width: 0; } .flex1 { flex: 1 1 auto; min-width: 0; }
.flex.column { flex-direction: column; } .flex.column { flex-direction: column; }
.flex.wrap { flex-wrap: wrap; } .flex.wrap { flex-wrap: wrap; }
.flex.flex-row,
.flex-row { flex-direction: row; }
.flex.jse,
.jse { justify-content: space-evenly; }
.flex.jsa,
.jsa { justify-content: space-around; }
/* Nested flex1 (zibll .flex .flex1) — allow both direct and descendant */
.flex > .flex1,
.flex .flex1 { flex: 1; overflow: hidden; min-width: 0; }
.relative-h { position: relative; height: 100%; }
.padding-10 { padding: 10px; }
.font-bold { font-weight: bold; }
.mt6 { margin-top: 6px; }
.gutters-5 { margin: -5px; }
.gutters-5 > * { padding: 5px; }
@media (max-width: 767px) {
.flex.flex-row.flex-col-sm-2 {
flex-wrap: wrap;
}
.flex.flex-row.flex-col-sm-2 > * {
flex-basis: 50%;
}
}
.clearfix::before, .clearfix::before,
.clearfix::after { .clearfix::after {
+153 -91
View File
@@ -135,103 +135,165 @@ if (!function_exists('aksrt_icon_cover_card')) :
* @param bool $echo * @param bool $echo
*/ */
function aksrt_icon_cover_card(array $args = [], bool $echo = false): string { function aksrt_icon_cover_card(array $args = [], bool $echo = false): string {
$defaults = [ $defaults = [
'class' => 'zib-widget', 'class' => 'zib-widget',
'icon' => '', 'icon' => '',
'icon_size' => 25, 'icon_size' => 25,
'customize_icon' => '', 'customize_icon' => '',
'icon_image' => '', 'custom_icon' => '',
'link' => [ 'icon_image' => '',
'url' => '', 'link' => [
'target' => '', 'url' => '',
], 'target' => '',
'icon_radius' => false, ],
'icon_color' => '', // Flat keys used by header_components_icon_cards admin schema.
'icon_custom_color' => '', 'url' => '',
'icon_class' => '', 'target' => '',
'title' => '', 'icon_radius' => false,
'desc' => '', 'icon_color' => '',
]; 'icon_custom_color' => '',
$args = wp_parse_args($args, $defaults); 'icon_class' => '',
'title' => '',
'desc' => '',
];
$args = wp_parse_args($args, $defaults);
$icon_fa = sanitize_text_field((string) $args['icon']); // Normalize link: accept nested link[] or flat url/target (SPA schema).
$icon_img = esc_url_raw(trim((string) ($args['icon_image'] !== '' ? $args['icon_image'] : ''))); $link = $args['link'];
$custom_html = ''; if (is_string($link)) {
if ($icon_img === '' && is_string($args['customize_icon']) && str_contains((string) $args['customize_icon'], '<')) { $link = ['url' => $link, 'target' => (string) $args['target']];
$custom_html = wp_kses((string) $args['customize_icon'], [ }
'i' => ['class' => true, 'aria-hidden' => true], if (!is_array($link)) {
'img' => ['src' => true, 'alt' => true, 'class' => true, 'loading' => true], $link = ['url' => '', 'target' => ''];
'span'=> ['class' => true], }
]); if (trim((string) ($link['url'] ?? '')) === '' && trim((string) $args['url']) !== '') {
} elseif ($icon_img === '' && is_string($args['customize_icon']) && filter_var((string) $args['customize_icon'], FILTER_VALIDATE_URL)) { $link['url'] = (string) $args['url'];
$icon_img = esc_url_raw((string) $args['customize_icon']); }
} if (trim((string) ($link['target'] ?? '')) === '' && trim((string) $args['target']) !== '') {
if ($icon_fa === '' && $icon_img === '' && $custom_html === '') { $link['target'] = (string) $args['target'];
return '';
}
$link = $args['link'];
if (is_string($link)) {
$link = ['url' => $link, 'target' => ''];
}
if (!is_array($link)) {
$link = ['url' => '', 'target' => ''];
}
$url = esc_url(trim((string) ($link['url'] ?? '')));
$target = sanitize_text_field((string) ($link['target'] ?? ''));
$tgt = $target !== '' ? ' target="' . esc_attr($target) . '" rel="noopener noreferrer"' : '';
$icon_class = trim('icon-cover-icon badg cir ' . sanitize_html_class((string) $args['icon_class']) . ' ' . sanitize_html_class((string) $args['icon_color']));
if (!empty($args['icon_radius'])) {
$icon_class .= ' radius4';
}
$icon_size = max(14, min(64, (int) $args['icon_size']));
$style = 'font-size:' . $icon_size . 'px;';
$custom_color = sanitize_hex_color((string) $args['icon_custom_color']);
if ($custom_color) {
$style .= 'color:' . $custom_color . ';';
}
if ($custom_html !== '') {
$icon_inner = $custom_html;
} elseif ($icon_img !== '') {
$icon_inner = '<img src="' . esc_url($icon_img) . '" alt="" loading="lazy" />';
} else {
if ($icon_fa !== '' && !str_contains($icon_fa, 'fa-') && !str_contains($icon_fa, ' ')) {
$icon_fa = 'fa fa-' . $icon_fa;
} }
$icon_inner = '<i class="' . esc_attr($icon_fa) . ' em09" aria-hidden="true"></i>';
}
$icon = '<div class="' . esc_attr(trim($icon_class)) . '" style="' . esc_attr($style) . '">' . $icon_inner . '</div>';
$title = trim((string) $args['title']); $icon_fa = trim((string) $args['icon']);
$desc = trim((string) $args['desc']); // custom_icon (SPA) + customize_icon (zibll) + icon_image URL.
$text = ''; $custom_src = (string) ($args['custom_icon'] !== '' ? $args['custom_icon'] : $args['customize_icon']);
if ($title !== '') { $icon_img = esc_url_raw(trim((string) ($args['icon_image'] !== '' ? $args['icon_image'] : '')));
$text .= '<div class="em12 text-ellipsis font-bold">' . esc_html($title) . '</div>'; $custom_html = '';
} if ($icon_img === '' && $custom_src !== '' && str_contains($custom_src, '<')) {
if ($desc !== '') { $custom_html = wp_kses($custom_src, [
$text .= '<div class="muted-color mt6 text-ellipsis">' . esc_html($desc) . '</div>'; 'i' => ['class' => true, 'aria-hidden' => true],
} 'img' => ['src' => true, 'alt' => true, 'class' => true, 'loading' => true, 'width' => true, 'height' => true],
'span' => ['class' => true],
'svg' => ['class' => true, 'viewbox' => true, 'viewBox' => true, 'width' => true, 'height' => true, 'fill' => true, 'xmlns' => true, 'aria-hidden' => true],
'path' => ['d' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true],
'use' => ['href' => true, 'xlink:href' => true],
]);
} elseif ($icon_img === '' && $custom_src !== '' && filter_var($custom_src, FILTER_VALIDATE_URL)) {
$icon_img = esc_url_raw($custom_src);
}
if ($icon_fa === '' && $icon_img === '' && $custom_html === '') {
return '';
}
$html = ''; $url = esc_url(trim((string) ($link['url'] ?? '')));
if ($url !== '') { $target = sanitize_text_field((string) ($link['target'] ?? ''));
$html .= '<a class="main-color" href="' . esc_url($url) . '"' . $tgt . '>'; // zibll only adds target= when non-empty; keep same for 1:1.
} $tgt = ($target !== '' && $target !== '_self') ? ' target="' . esc_attr($target) . '"' : '';
$html .= '<div class="icon-cover-card flex ac ' . esc_attr((string) $args['class']) . '">';
$html .= $icon;
$html .= $text !== '' ? '<div class="icon-cover-desc ml10 flex1 px12-sm">' . $text . '</div>' : '';
$html .= '</div>';
if ($url !== '') {
$html .= '</a>';
}
if ($echo) { // zibll: class = "icon-cover-icon badg cir" + optional icon_class (may include radius4 / c-* / jb-*).
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped // Do NOT sanitize_html_class on the whole string — it collapses multi-token classes.
return ''; $icon_class_extra = trim(preg_replace('/\s+/', ' ', (string) $args['icon_class']));
$icon_class = 'icon-cover-icon badg cir';
if ($icon_class_extra !== '') {
$tokens = preg_split('/\s+/', $icon_class_extra) ?: [];
$safe = [];
foreach ($tokens as $tok) {
$tok = preg_replace('/[^a-zA-Z0-9_-]/', '', $tok);
if ($tok !== '') {
$safe[] = $tok;
}
}
if ($safe) {
$icon_class .= ' ' . implode(' ', $safe);
}
}
if (!empty($args['icon_radius']) && !str_contains($icon_class, 'radius4')) {
$icon_class .= ' radius4';
}
$icon_color = trim((string) $args['icon_color']);
if ($icon_color !== '' && !str_contains($icon_class, $icon_color)) {
$icon_class .= ' ' . preg_replace('/[^a-zA-Z0-9_-]/', '', $icon_color);
}
$icon_size = max(14, min(64, (int) $args['icon_size']));
// zibll always sets font-size on the icon badge.
$style = 'font-size: ' . $icon_size . 'px;';
$custom_color = sanitize_hex_color((string) $args['icon_custom_color']);
if ($custom_color) {
$style .= 'color:' . $custom_color . ';';
}
if ($custom_html !== '') {
$icon_inner = $custom_html;
} elseif ($icon_img !== '') {
$icon_inner = '<img src="' . esc_url($icon_img) . '" alt="" loading="lazy" />';
} else {
// zibll: zib_get_cfs_icon($args['icon'], 'em09') — keep FA class + em09.
if ($icon_fa !== '' && !str_contains($icon_fa, 'fa-') && !str_contains($icon_fa, ' ') && !str_starts_with($icon_fa, 'zibsvg-')) {
$icon_fa = 'fa fa-' . $icon_fa;
}
if (str_contains($icon_fa, '<')) {
$icon_inner = wp_kses($icon_fa, [
'i' => ['class' => true, 'aria-hidden' => true],
'svg' => ['class' => true, 'viewbox' => true, 'viewBox' => true, 'width' => true, 'height' => true, 'fill' => true, 'xmlns' => true, 'aria-hidden' => true],
'path' => ['d' => true, 'fill' => true],
'use' => ['href' => true, 'xlink:href' => true],
]);
} else {
$icon_inner = '<i class="' . esc_attr($icon_fa) . ' em09" aria-hidden="true"></i>';
}
}
$icon = '<div class="' . esc_attr(trim($icon_class)) . '" style="' . esc_attr($style) . '">' . $icon_inner . '</div>';
// zibll allows HTML in title/desc (admin stores badges etc.).
$title = (string) $args['title'];
$desc = (string) $args['desc'];
$allow = [
'badge' => ['class' => true],
'span' => ['class' => true],
'i' => ['class' => true, 'aria-hidden' => true],
'em' => ['class' => true],
'strong' => ['class' => true],
'b' => [],
'small' => ['class' => true],
'br' => [],
];
$text = '';
if (trim(wp_strip_all_tags($title)) !== '' || str_contains($title, '<')) {
$text .= '<div class="em12 text-ellipsis font-bold"> ' . wp_kses($title, $allow) . '</div>';
}
if (trim(wp_strip_all_tags($desc)) !== '' || str_contains($desc, '<')) {
$text .= '<div class="muted-color mt6 text-ellipsis"> ' . wp_kses($desc, $allow) . '</div>';
}
$html = '';
if ($url !== '') {
// zibll: <a class="main-color" [target] href="...">
$html .= '<a class="main-color" ' . ($tgt !== '' ? ltrim($tgt) . ' ' : '') . 'href="' . esc_url($url) . '">';
}
$html .= '<div class="icon-cover-card flex ac ' . esc_attr((string) $args['class']) . '">';
$html .= $icon;
$html .= $text !== '' ? '<div class="icon-cover-desc ml10 flex1 px12-sm"> ' . $text . '</div>' : '';
$html .= '</div>';
if ($url !== '') {
$html .= '</a>';
}
if ($echo) {
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
return '';
}
return $html;
} }
return $html;
}
endif; endif;
if (!function_exists('aksrt_obs_animate_attrs')) : if (!function_exists('aksrt_obs_animate_attrs')) :
+34 -33
View File
@@ -495,45 +495,46 @@ if (!function_exists('aksrt_render_icon_cover_card')):
* @return string HTML * @return string HTML
*/ */
function aksrt_render_icon_cover_card(array $card): string { function aksrt_render_icon_cover_card(array $card): string {
$icon = $card['icon'] ?? 'fas fa-star'; // Prefer canonical zibll-aligned renderer.
$custom_icon = $card['custom_icon'] ?? ''; if (function_exists('aksrt_icon_cover_card')) {
$icon_class = $card['icon_class'] ?? 'c-blue'; return aksrt_icon_cover_card($card);
$icon_shape = ($card['icon_shape'] ?? 'circle') === 'square' ? 'radius4' : ''; }
$title = $card['title'] ?? '';
$desc = $card['desc'] ?? '';
$url = $card['url'] ?? '';
$target = ($card['target'] ?? '_self') === '_blank' ? ' target="_blank" rel="noopener"' : '';
// 图标 HTML $icon = $card['icon'] ?? 'fas fa-star';
$icon_html = $custom_icon $custom_icon = $card['custom_icon'] ?? ($card['customize_icon'] ?? '');
? $custom_icon $icon_class = trim((string) ($card['icon_class'] ?? 'c-blue'));
: '<i class="' . esc_attr($icon) . '"></i>'; if (($card['icon_shape'] ?? '') === 'square' && !str_contains($icon_class, 'radius4')) {
$icon_class .= ' radius4';
}
$title = $card['title'] ?? '';
$desc = $card['desc'] ?? '';
$url = $card['url'] ?? ($card['link']['url'] ?? '');
$target = $card['target'] ?? ($card['link']['target'] ?? '');
$tgt = ($target !== '' && $target !== '_self') ? ' target="' . esc_attr((string) $target) . '"' : '';
// 图标容器 $icon_html = $custom_icon !== ''
$icon_container = '<div class="icon-cover-icon ' . esc_attr($icon_class) . ' ' . esc_attr($icon_shape) . '">' . $icon_html . '</div>'; ? wp_kses_post((string) $custom_icon)
: '<i class="' . esc_attr((string) $icon) . ' em09" aria-hidden="true"></i>';
// 文字区 $icon_container = '<div class="icon-cover-icon badg cir ' . esc_attr($icon_class) . '" style="font-size: 25px;">' . $icon_html . '</div>';
$text_html = '<div class="icon-cover-desc">';
if ($title) {
$text_html .= '<div class="icon-cover-title">' . wp_kses_post($title) . '</div>';
}
if ($desc) {
$text_html .= '<div class="icon-cover-subtitle">' . wp_kses_post($desc) . '</div>';
}
$text_html .= '</div>';
// 卡片内容 $text_html = '<div class="icon-cover-desc ml10 flex1 px12-sm">';
$card_inner = $icon_container . $text_html; if ($title !== '') {
$text_html .= '<div class="em12 text-ellipsis font-bold"> ' . wp_kses_post((string) $title) . '</div>';
}
if ($desc !== '') {
$text_html .= '<div class="muted-color mt6 text-ellipsis"> ' . wp_kses_post((string) $desc) . '</div>';
}
$text_html .= '</div>';
// 包裹标签 $card_inner = $icon_container . $text_html;
if ($url) { $cls = 'icon-cover-card flex ac ' . esc_attr((string) ($card['class'] ?? 'zib-widget'));
$html = '<a href="' . esc_url($url) . '" class="icon-cover-card"' . $target . '>' . $card_inner . '</a>';
} else {
$html = '<div class="icon-cover-card">' . $card_inner . '</div>';
}
return $html; if ($url !== '') {
} return '<a class="main-color" ' . ($tgt !== '' ? ltrim($tgt) . ' ' : '') . 'href="' . esc_url((string) $url) . '"><div class="' . $cls . '">' . $card_inner . '</div></a>';
}
return '<div class="' . $cls . '">' . $card_inner . '</div>';
}
endif; endif;
// ============================================================ // ============================================================
+44 -25
View File
@@ -152,33 +152,52 @@ $render_icon_cards = static function () use ($show_cards, $icon_cards, $card_bg_
if (!$show_cards || empty($icon_cards)) { if (!$show_cards || empty($icon_cards)) {
return; return;
} }
/**
* Overlay icon cards — 1:1 zibll zib_header_slide() card module.
*
* show_widget_bg (shared) → outer .zib-widget.padding-10 + each card class=padding-10 in .relative-h
* individual (default) → outer empty div + each card class=zib-widget in .flex1
* Row: .flex.jse.flex-row.gutters-5.flex-col-sm-2
*/
$show_widget_bg = ($card_bg_mode === 'shared');
$icon_radius4 = ($card_icon_shape === 'square');
$slider_card_html = '';
foreach ($icon_cards as $raw) {
if (!is_array($raw)) {
continue;
}
$card = $raw;
$card['class'] = $show_widget_bg ? 'padding-10' : 'zib-widget';
$extra = trim((string) ($card['icon_class'] ?? ''));
if ($icon_radius4 && !str_contains($extra, 'radius4')) {
$extra = trim($extra . ' radius4');
}
$card['icon_class'] = $extra;
unset($card['icon_shape']);
$wrap_class = $show_widget_bg ? 'relative-h' : 'flex1';
$inner = function_exists('aksrt_icon_cover_card')
? aksrt_icon_cover_card($card)
: (function_exists('aksrt_render_icon_cover_card') ? aksrt_render_icon_cover_card($card) : '');
if ($inner === '') {
continue;
}
$slider_card_html .= '<div class="' . esc_attr($wrap_class) . '">' . $inner . '</div>';
}
if ($slider_card_html === '') {
return;
}
?> ?>
<div class="header-slider-card header-components-card container"> <div class="header-slider-card header-components-card container">
<div class="header-components-card__container container"> <?php if ($show_widget_bg) : ?>
<?php if ($card_bg_mode === 'shared') : ?> <div class="zib-widget padding-10">
<div class="header-components-card__wrap header-components-card__wrap--shared"> <?php else : ?>
<div class="header-components-card__row"> <div class="">
<?php foreach ($icon_cards as $card) : ?> <?php endif; ?>
<?php $card['icon_shape'] = $card_icon_shape; ?> <div class="flex jse flex-row gutters-5 flex-col-sm-2">
<div class="header-components-card__item"> <?php echo $slider_card_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<?php echo aksrt_render_icon_cover_card($card); ?> </div>
</div> </div>
<?php endforeach; ?>
</div>
</div>
<?php else : ?>
<div class="header-components-card__row">
<?php foreach ($icon_cards as $card) : ?>
<?php $card['icon_shape'] = $card_icon_shape; ?>
<div class="header-components-card__item">
<div class="header-components-card__item-bg">
<?php echo aksrt_render_icon_cover_card($card); ?>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div> </div>
<?php <?php
}; };