[CMS-VISUAL] D1-D10 后端: 新组件数据槽(banner 扩 topic/event 位 5 列 + cms_person 新表+CRUD+防跨站)+ 6 区块类型校验与装配(空数据整块不渲染 R-44)+ 骨架新组件 fragment/内置 22 图标集/共享动效 JS(reveal+count-up R-42)+ searchStyle 搜索浮层(D-10,含坑④条件包裹修复)+ 三保留主题 4 新参数
This commit is contained in:
@@ -31,10 +31,19 @@
|
||||
th:src="${url.upload(site.config['logo'])}" th:alt="${site.name}">
|
||||
<a class="cg-site-name" th:href="${url.home()}" th:text="${site.name}">站点名称</a>
|
||||
</div>
|
||||
<form class="cg-site-search" th:action="${url.search('', null)}" method="get" role="search">
|
||||
<!-- D-10(docs/20):searchStyle=overlay 换全屏搜索浮层;none 隐藏;inline/缺省保留原表单。
|
||||
坑④:th:replace 优先级(100)先于 th:if(300)——条件必须放外层 th:block,replace 放子元素 -->
|
||||
<th:block th:if="${themeParams != null and themeParams['searchStyle'] == 'overlay'}">
|
||||
<th:block th:replace="~{'themes/common/fragments/search' :: overlay(${url})}" />
|
||||
</th:block>
|
||||
<th:block th:if="${themeParams == null or themeParams['searchStyle'] == null or themeParams['searchStyle'] == 'inline'}">
|
||||
<form class="cg-site-search"
|
||||
|
||||
th:action="${url.search('', null)}" method="get" role="search">
|
||||
<input type="text" name="q" placeholder="站内搜索" aria-label="站内搜索">
|
||||
<button type="submit">搜索</button>
|
||||
</form>
|
||||
</th:block>
|
||||
</div>
|
||||
|
||||
<nav class="cg-nav" aria-label="栏目导航">
|
||||
|
||||
@@ -8,19 +8,152 @@
|
||||
"screenshot": "assets/screenshot.png",
|
||||
"bannerSize": "1920x560",
|
||||
"params": [
|
||||
{ "key": "primary", "cssVar": "--cg-primary", "label": "主色", "type": "color", "default": "#0e8a5f" },
|
||||
{ "key": "primaryDark", "cssVar": "--cg-primary-dark", "label": "主色加深", "type": "color", "default": "#0a6244" },
|
||||
{ "key": "accent", "cssVar": "--cg-accent", "label": "强调色", "type": "color", "default": "#ff7a1a" },
|
||||
{ "key": "text", "cssVar": "--cg-text", "label": "正文文字色", "type": "color", "default": "#2b2f33" },
|
||||
{ "key": "textLight", "cssVar": "--cg-text-light", "label": "次要文字色", "type": "color", "default": "#7a8288" },
|
||||
{ "key": "bg", "cssVar": "--cg-bg", "label": "页面底色", "type": "color", "default": "#f4f7f5" },
|
||||
{ "key": "cardBg", "cssVar": "--cg-card-bg", "label": "卡片底色", "type": "color", "default": "#ffffff" },
|
||||
{ "key": "border", "cssVar": "--cg-border", "label": "边框色", "type": "color", "default": "#e3e8e4" },
|
||||
{ "key": "galleryCols", "label": "展厅每行列数", "type": "select", "default": "4",
|
||||
{
|
||||
"key": "primary",
|
||||
"cssVar": "--cg-primary",
|
||||
"label": "主色",
|
||||
"type": "color",
|
||||
"default": "#0e8a5f"
|
||||
},
|
||||
{
|
||||
"key": "primaryDark",
|
||||
"cssVar": "--cg-primary-dark",
|
||||
"label": "主色加深",
|
||||
"type": "color",
|
||||
"default": "#0a6244"
|
||||
},
|
||||
{
|
||||
"key": "accent",
|
||||
"cssVar": "--cg-accent",
|
||||
"label": "强调色",
|
||||
"type": "color",
|
||||
"default": "#ff7a1a"
|
||||
},
|
||||
{
|
||||
"key": "text",
|
||||
"cssVar": "--cg-text",
|
||||
"label": "正文文字色",
|
||||
"type": "color",
|
||||
"default": "#2b2f33"
|
||||
},
|
||||
{
|
||||
"key": "textLight",
|
||||
"cssVar": "--cg-text-light",
|
||||
"label": "次要文字色",
|
||||
"type": "color",
|
||||
"default": "#7a8288"
|
||||
},
|
||||
{
|
||||
"key": "bg",
|
||||
"cssVar": "--cg-bg",
|
||||
"label": "页面底色",
|
||||
"type": "color",
|
||||
"default": "#f4f7f5"
|
||||
},
|
||||
{
|
||||
"key": "cardBg",
|
||||
"cssVar": "--cg-card-bg",
|
||||
"label": "卡片底色",
|
||||
"type": "color",
|
||||
"default": "#ffffff"
|
||||
},
|
||||
{
|
||||
"key": "border",
|
||||
"cssVar": "--cg-border",
|
||||
"label": "边框色",
|
||||
"type": "color",
|
||||
"default": "#e3e8e4"
|
||||
},
|
||||
{
|
||||
"key": "galleryCols",
|
||||
"label": "展厅每行列数",
|
||||
"type": "select",
|
||||
"default": "4",
|
||||
"options": [
|
||||
{ "value": "3", "label": "3 列" },
|
||||
{ "value": "4", "label": "4 列" },
|
||||
{ "value": "5", "label": "5 列" }
|
||||
{
|
||||
"value": "3",
|
||||
"label": "3 列"
|
||||
},
|
||||
{
|
||||
"value": "4",
|
||||
"label": "4 列"
|
||||
},
|
||||
{
|
||||
"value": "5",
|
||||
"label": "5 列"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "animation",
|
||||
"label": "首页动效",
|
||||
"type": "select",
|
||||
"default": "on",
|
||||
"options": [
|
||||
{
|
||||
"value": "on",
|
||||
"label": "开启(滚动入场 + 数字计数)"
|
||||
},
|
||||
{
|
||||
"value": "off",
|
||||
"label": "关闭(静态呈现)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "titleStyle",
|
||||
"label": "栏目标题语言",
|
||||
"type": "select",
|
||||
"default": "cn",
|
||||
"options": [
|
||||
{
|
||||
"value": "cn",
|
||||
"label": "仅中文"
|
||||
},
|
||||
{
|
||||
"value": "bilingual",
|
||||
"label": "中英双语(大中文 + 斜体英文副题)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "iconShape",
|
||||
"label": "图标形状语言",
|
||||
"type": "select",
|
||||
"default": "circle",
|
||||
"options": [
|
||||
{
|
||||
"value": "circle",
|
||||
"label": "圆形徽章"
|
||||
},
|
||||
{
|
||||
"value": "hexagon",
|
||||
"label": "六边形"
|
||||
},
|
||||
{
|
||||
"value": "square",
|
||||
"label": "圆角方形"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "searchStyle",
|
||||
"label": "门户搜索样式",
|
||||
"type": "select",
|
||||
"default": "inline",
|
||||
"options": [
|
||||
{
|
||||
"value": "none",
|
||||
"label": "不显示搜索"
|
||||
},
|
||||
{
|
||||
"value": "inline",
|
||||
"label": "通栏搜索条(banner 下方白色大搜索条)"
|
||||
},
|
||||
{
|
||||
"value": "overlay",
|
||||
"label": "全屏搜索浮层(右上放大镜唤起)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -94,6 +94,84 @@ main > .plb-anchor > .plb-ticker{grid-column:1 / -1}
|
||||
main > .plb-anchor > .plb-newshot{grid-column:1 / -1}
|
||||
main > .plb-anchor > .plb-section{grid-column:1 / -1}
|
||||
main > .plb-anchor > .plb-notice-bar{grid-column:1 / -1}
|
||||
|
||||
/* ===== docs/20 D 组件库骨架样式(跟随主题变量;campus-glow 等可自持精细版覆盖) ===== */
|
||||
/* D-4 双语标题:themeParams.titleStyle=bilingual 时副题斜体展示(默认 cn 不展示由渲染端守卫) */
|
||||
.plb-sub{font-style:italic}
|
||||
/* D-1 数字计数带 */
|
||||
.plb-stats-row{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
|
||||
.plb-stats-row li{text-align:center;padding:14px 8px}
|
||||
.plb-num{display:block;font-size:34px;font-weight:700;line-height:1.1;color:var(--plb-primary);font-variant-numeric:tabular-nums}
|
||||
.plb-unit{font-size:14px;font-weight:600;margin-left:2px}
|
||||
.plb-stats-label{display:block;margin-top:6px;color:var(--plb-muted);font-size:13px}
|
||||
/* D-2 图标宫格(quick_links 升级):形状由主题 iconShape 参数控制(circle/hexagon/square) */
|
||||
.plb-quick-grid{grid-template-columns:repeat(6,1fr)}
|
||||
.plb-qitem{display:flex;flex-direction:column;align-items:center;gap:8px;padding:14px 8px;text-decoration:none;background:var(--plb-page-bg);border:1px solid var(--plb-border);border-radius:var(--plb-radius);transition:transform .2s,border-color .2s}
|
||||
.plb-qitem:hover{transform:translateY(-3px);border-color:var(--plb-primary)}
|
||||
.plb-qicon{display:inline-flex;align-items:center;justify-content:center;width:52px;height:52px;color:#fff;background:linear-gradient(135deg,var(--plb-primary),var(--plb-primary, #2d8cf0));border-radius:50%}
|
||||
.plb-qicon svg{width:26px;height:26px}
|
||||
.plb-shape-square .plb-qicon{border-radius:10px}
|
||||
.plb-shape-hexagon .plb-qicon{clip-path:polygon(50% 0,93% 25%,93% 75%,50% 100%,7% 75%,7% 25%);border-radius:0}
|
||||
.plb-qfall{font-size:22px;font-weight:700;line-height:1}
|
||||
.plb-qname{font-size:14px;color:var(--plb-text)}
|
||||
/* D-3 专题大卡 */
|
||||
.plb-topics{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px}
|
||||
.plb-topic{position:relative;display:block;border-radius:var(--plb-radius);overflow:hidden;text-decoration:none;min-height:220px;box-shadow:0 6px 20px rgba(15,34,66,.12)}
|
||||
.plb-topic img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .35s}
|
||||
.plb-topic:hover img{transform:scale(1.04)}
|
||||
.plb-topic-body{position:absolute;left:0;right:0;bottom:0;padding:40px 16px 14px;background:linear-gradient(180deg,transparent,rgba(0,0,0,.72));color:#fff}
|
||||
.plb-topic-t{display:block;font-size:17px;font-weight:600}
|
||||
.plb-topic-d{display:block;margin-top:4px;font-size:13px;opacity:.85;line-height:1.5}
|
||||
.plb-topic-cta{display:inline-block;margin-top:10px;font-size:13px;border:1px solid rgba(255,255,255,.7);border-radius:16px;padding:3px 14px;color:#fff !important;text-decoration:none}
|
||||
.plb-topic-cta:hover{background:rgba(255,255,255,.15)}
|
||||
/* D-5 视频/VR 校园 */
|
||||
.plb-video{position:relative;display:block;border-radius:var(--plb-radius);overflow:hidden;box-shadow:0 8px 26px rgba(15,34,66,.16)}
|
||||
.plb-video img{width:100%;height:340px;object-fit:cover;display:block}
|
||||
.plb-video-play{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}
|
||||
.plb-video-play::before{content:"";position:absolute;width:74px;height:74px;border-radius:50%;background:rgba(0,0,0,.45);backdrop-filter:blur(2px)}
|
||||
.plb-video-play::after{content:"";position:absolute;width:0;height:0;border-style:solid;border-width:14px 0 14px 24px;border-color:transparent transparent transparent #fff;margin-left:6px}
|
||||
/* D-6 学术活动(大日期块横带) */
|
||||
.plb-events{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px}
|
||||
.plb-event{display:flex;gap:14px;align-items:center;padding:14px 16px;background:var(--plb-card-bg);border:1px solid var(--plb-border);border-radius:var(--plb-radius);text-decoration:none}
|
||||
.plb-event-date{flex:none;width:64px;text-align:center;color:var(--plb-primary)}
|
||||
.plb-event-date b{display:block;font-size:30px;line-height:1;font-weight:700}
|
||||
.plb-event-date i{display:block;font-style:normal;font-size:11px;color:var(--plb-muted);margin-top:3px}
|
||||
.plb-event-t{display:block;color:var(--plb-text);font-size:15px;font-weight:600;line-height:1.4}
|
||||
.plb-event-loc{display:block;color:var(--plb-muted);font-size:12px;margin-top:3px}
|
||||
.plb-event:hover .plb-event-t{color:var(--plb-primary)}
|
||||
/* D-7 名师风采 */
|
||||
.plb-people{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:16px}
|
||||
.plb-person{display:flex;flex-direction:column;align-items:center;text-align:center;padding:20px 12px;background:var(--plb-card-bg);border:1px solid var(--plb-border);border-radius:var(--plb-radius)}
|
||||
.plb-person-avatar{width:84px;height:84px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,var(--plb-primary),#8fb8f0);color:#fff;font-size:32px;font-weight:700}
|
||||
.plb-person-avatar img{width:100%;height:100%;object-fit:cover}
|
||||
.plb-person-name{margin-top:12px;font-size:16px;font-weight:600;color:var(--plb-text)}
|
||||
.plb-person-title{margin-top:2px;font-size:12px;color:var(--plb-primary)}
|
||||
.plb-person-bio{margin-top:8px;font-size:13px;color:var(--plb-muted);line-height:1.6}
|
||||
/* D-8 campus_wall 瀑布流(columns 流式,块高天然错落) */
|
||||
.plb-gallery-grid.masonry{display:block;columns:4;column-gap:14px}
|
||||
.plb-gallery-grid.masonry li{break-inside:avoid;margin-bottom:14px}
|
||||
.plb-gallery-grid.masonry img{height:auto}
|
||||
/* D-9 徽章带 */
|
||||
.plb-badges{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;justify-content:center;gap:28px}
|
||||
.plb-badge-item{display:flex;flex-direction:column;align-items:center;text-align:center;max-width:130px}
|
||||
.plb-badge-item img{width:72px;height:72px;object-fit:contain}
|
||||
.plb-badge-label{margin-top:8px;font-size:14px;font-weight:600;color:var(--plb-text)}
|
||||
.plb-badge-desc{margin-top:2px;font-size:12px;color:var(--plb-muted)}
|
||||
/* D-8/D-42 骨架共享入场动效(R-42:所有主题自动生效,主题参数 animation=off 关闭) */
|
||||
.plb-anim{opacity:0;transform:translateY(24px);transition:opacity .6s ease,transform .6s ease}
|
||||
.plb-anim.plb-in{opacity:1;transform:none}
|
||||
@media (prefers-reduced-motion: reduce){.plb-anim{opacity:1;transform:none;transition:none}}
|
||||
main > .plb-anchor > .plb-stats-band{grid-column:1 / -1}
|
||||
main > .plb-anchor > .plb-section{grid-column:1 / -1}
|
||||
@media (max-width:768px){
|
||||
.plb-stats-row{grid-template-columns:repeat(2,1fr)}
|
||||
.plb-topics{grid-template-columns:1fr}
|
||||
.plb-video img{height:210px}
|
||||
.plb-gallery-grid.masonry{columns:2}
|
||||
.plb-quick-grid{grid-template-columns:repeat(3,1fr)}
|
||||
.plb-people{grid-template-columns:repeat(2,1fr)}
|
||||
.plb-badges{gap:16px}
|
||||
}
|
||||
@media (max-width:768px){
|
||||
.plb-grid2{columns:1}
|
||||
.plb-imagewall{grid-template-columns:repeat(2,1fr)}
|
||||
@@ -124,6 +202,13 @@ main > .plb-anchor > .plb-notice-bar{grid-column:1 / -1}
|
||||
<th:block th:case="'links'"><th:block th:replace="~{'themes/common/fragments/home-blocks' :: plbLinks(${block})}" /></th:block>
|
||||
<th:block th:case="'quick_links'"><th:block th:replace="~{'themes/common/fragments/home-blocks' :: plbQuickLinks(${block})}" /></th:block>
|
||||
<th:block th:case="'notice_bar'"><th:block th:replace="~{'themes/common/fragments/home-blocks' :: plbNoticeBar(${block})}" /></th:block>
|
||||
<!-- docs/20 D-1~D-9 新组件(骨架兜底渲染;A 档主题可自持精细版覆盖) -->
|
||||
<th:block th:case="'stats_band'"><th:block th:replace="~{'themes/common/fragments/home-blocks' :: plbStatsBand(${block})}" /></th:block>
|
||||
<th:block th:case="'featured_topics'"><th:block th:replace="~{'themes/common/fragments/home-blocks' :: plbFeaturedTopics(${block})}" /></th:block>
|
||||
<th:block th:case="'video_tour'"><th:block th:replace="~{'themes/common/fragments/home-blocks' :: plbVideoTour(${block})}" /></th:block>
|
||||
<th:block th:case="'events'"><th:block th:replace="~{'themes/common/fragments/home-blocks' :: plbEvents(${block})}" /></th:block>
|
||||
<th:block th:case="'people'"><th:block th:replace="~{'themes/common/fragments/home-blocks' :: plbPeople(${block})}" /></th:block>
|
||||
<th:block th:case="'badges'"><th:block th:replace="~{'themes/common/fragments/home-blocks' :: plbBadges(${block})}" /></th:block>
|
||||
<th:block th:case="*"><th:block th:replace="~{'themes/common/fragments/home-blocks' :: plbCard(${block})}" /></th:block>
|
||||
</th:block>
|
||||
</th:block>
|
||||
@@ -132,7 +217,8 @@ main > .plb-anchor > .plb-notice-bar{grid-column:1 / -1}
|
||||
<div class="plb-head" th:fragment="head(block)">
|
||||
<div>
|
||||
<h2 th:text="${block.title}">区块标题</h2>
|
||||
<p class="plb-sub" th:if="${!#strings.isEmpty(block['subtitle'])}" th:text="${block['subtitle']}">副题</p>
|
||||
<!-- D-4(docs/20):中英双语副题;themeParams.titleStyle=cn 时隐藏(主题级开关) -->
|
||||
<p class="plb-sub" th:if="${!#strings.isEmpty(block['subtitle']) and (themeParams == null or themeParams['titleStyle'] == null or themeParams['titleStyle'] != 'cn')}" th:text="${block['subtitle']}">副题</p>
|
||||
</div>
|
||||
<a class="plb-more" th:if="${!#strings.isEmpty(block['moreUrl'])}" th:href="${block['moreUrl']}">更多 ></a>
|
||||
</div>
|
||||
@@ -272,7 +358,8 @@ main > .plb-anchor > .plb-notice-bar{grid-column:1 / -1}
|
||||
<h2 th:text="${block.title}">线上展厅</h2>
|
||||
<p class="plb-sub" th:if="${!#strings.isEmpty(block.subtitle)}" th:text="${block.subtitle}">Online Exhibition Hall</p>
|
||||
</div>
|
||||
<ul class="plb-gallery-grid">
|
||||
<!-- D-8(docs/20):layout=masonry 时瀑布流(columns 错落) -->
|
||||
<ul class="plb-gallery-grid" th:classappend="${block['layout'] == 'masonry' ? 'masonry' : ''}">
|
||||
<li th:each="g : ${block.items}">
|
||||
<a th:href="${g.linkUrl}" th:title="${g.title}">
|
||||
<img th:src="${g.imageUrl}" th:alt="${g.title}">
|
||||
@@ -306,9 +393,20 @@ main > .plb-anchor > .plb-notice-bar{grid-column:1 / -1}
|
||||
<div class="plb-container">
|
||||
<div class="plb-card">
|
||||
<div th:replace="~{'themes/common/fragments/home-blocks' :: head(${block})}"></div>
|
||||
<ul class="plb-quick-grid" th:if="${!#lists.isEmpty(block['quickLinks'])}">
|
||||
<!-- D-2(docs/20):图标宫格——内置 SVG 图标集,未选图标降级首字徽章;形状随主题 iconShape 参数 -->
|
||||
<ul class="plb-quick-grid" th:with="shapeCls=${themeParams != null and themeParams['iconShape'] != null ? 'plb-shape-' + themeParams['iconShape'] : 'plb-shape-circle'}"
|
||||
th:if="${!#lists.isEmpty(block['quickLinks'])}">
|
||||
<li th:each="l : ${block['quickLinks']}">
|
||||
<a class="plb-quick-link" th:href="${l.url}" th:text="${l.name}">入口名</a>
|
||||
<a class="plb-qitem" th:classappend="${shapeCls}" th:href="${l.url}">
|
||||
<span class="plb-qicon">
|
||||
<th:block th:if="${!#strings.isEmpty(l['icon'])}">
|
||||
<th:block th:replace="~{'themes/common/fragments/home-blocks' :: icon(${l['icon']})}" />
|
||||
</th:block>
|
||||
<span class="plb-qfall" th:unless="${!#strings.isEmpty(l['icon'])}"
|
||||
th:text="${#strings.length(l.name) > 0 ? #strings.substring(l.name, 0, 1) : ''}">首</span>
|
||||
</span>
|
||||
<span class="plb-qname" th:text="${l.name}">入口名</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- 空态守卫必须包在 th:block 外层(坑①:th:replace 优先级 100 先于 th:if 300 求值) -->
|
||||
@@ -378,3 +476,239 @@ main > .plb-anchor > .plb-notice-bar{grid-column:1 / -1}
|
||||
})();
|
||||
</script>
|
||||
</th:block>
|
||||
|
||||
<!--
|
||||
===== docs/20 D-1~D-9 新组件骨架 fragment(追加于文件尾部) =====
|
||||
契约键:stats_band.stats / featured_topics.items[{title,description,imageUrl,linkUrl,ctaText,ctaUrl}] /
|
||||
video_tour.{cover,videoUrl} / events.items[{title,linkUrl,eventDate,location}] /
|
||||
people.items[{name,title,bio,avatar}] / badges.items[{label,desc,image}]。
|
||||
空数据由渲染端直接不产出区块(R-44),此处守卫为双保险。
|
||||
-->
|
||||
|
||||
<!-- D-1 数字计数带:count-up 动画由共享动效脚本驱动(data-plb-countup) -->
|
||||
<section class="plb-section plb-stats-band" th:fragment="plbStatsBand(block)" aria-label="数字计数">
|
||||
<div class="plb-container">
|
||||
<div th:replace="~{'themes/common/fragments/home-blocks' :: head(${block})}"></div>
|
||||
<ul class="plb-stats-row" th:if="${!#lists.isEmpty(block['stats'])}">
|
||||
<li th:each="st : ${block['stats']}">
|
||||
<span class="plb-num">
|
||||
<span class="plb-count" th:attr="data-plb-countup=${st['value']}" th:text="${st['value']}">3.2</span><span
|
||||
class="plb-unit" th:if="${!#strings.isEmpty(st['unit'])}" th:text="${st['unit']}">万</span>
|
||||
</span>
|
||||
<span class="plb-stats-label" th:text="${st['label']}">在校生</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- D-3 专题大卡:大图 + 标题 + 描述 + CTA 按钮(数据 = 轮播管理「专题大卡」位)。
|
||||
整卡主链接 = linkUrl;CTA 按钮 = ctaUrl(无 ctaUrl 时回落 linkUrl),span+data-href 由脚本转 a 语义防止嵌套 a -->
|
||||
<section class="plb-section" th:fragment="plbFeaturedTopics(block)" aria-label="专题推荐" th:if="${!#lists.isEmpty(block.items)}">
|
||||
<div class="plb-container">
|
||||
<div th:replace="~{'themes/common/fragments/home-blocks' :: head(${block})}"></div>
|
||||
<div class="plb-topics">
|
||||
<a class="plb-topic" th:each="t : ${block.items}" th:href="${!#strings.isEmpty(t['ctaUrl']) ? t['ctaUrl'] : t['linkUrl']}">
|
||||
<img th:src="${t['imageUrl']}" th:alt="${t['title']}">
|
||||
<span class="plb-topic-body">
|
||||
<span class="plb-topic-t" th:text="${t['title']}">专题标题</span>
|
||||
<span class="plb-topic-d" th:if="${!#strings.isEmpty(t['description'])}" th:text="${t['description']}">专题描述</span>
|
||||
<span class="plb-topic-cta" th:if="${!#strings.isEmpty(t['ctaText'])}" th:text="${t['ctaText']}">进入专题</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- D-5 视频/VR 校园:封面大图 + 播放按钮(点击开新窗跳视频/VR 地址) -->
|
||||
<section class="plb-section" th:fragment="plbVideoTour(block)" aria-label="云端校园">
|
||||
<div class="plb-container">
|
||||
<div th:replace="~{'themes/common/fragments/home-blocks' :: head(${block})}"></div>
|
||||
<a class="plb-video" th:href="${block['videoUrl']}" target="_blank" rel="noopener">
|
||||
<img th:src="${block['cover']}" th:alt="${block['title']}">
|
||||
<span class="plb-video-play"></span>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- D-6 学术日历/活动:大日期块(日 / 年月两段)+ 活动名 + 地点(数据 = 轮播管理「学术活动」位) -->
|
||||
<section class="plb-section" th:fragment="plbEvents(block)" aria-label="学术活动" th:if="${!#lists.isEmpty(block.items)}">
|
||||
<div class="plb-container">
|
||||
<div th:replace="~{'themes/common/fragments/home-blocks' :: head(${block})}"></div>
|
||||
<ul class="plb-events">
|
||||
<li th:each="e : ${block.items}">
|
||||
<a class="plb-event" th:href="${e['linkUrl']}">
|
||||
<span class="plb-event-date" th:if="${e['eventDate'] != null}">
|
||||
<b th:text="${#temporals.format(e['eventDate'], 'dd')}">28</b>
|
||||
<i th:text="${#temporals.format(e['eventDate'], 'yyyy-MM')}">2026-09</i>
|
||||
</span>
|
||||
<span class="plb-event-date" th:unless="${e['eventDate'] != null}">
|
||||
<b>·</b><i>待定</i>
|
||||
</span>
|
||||
<span>
|
||||
<span class="plb-event-t" th:text="${e['title']}">活动名称</span>
|
||||
<span class="plb-event-loc" th:if="${!#strings.isEmpty(e['location'])}" th:text="${e['location']}">活动地点</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- D-7 名师风采:圆头像(无头像首字徽章)+ 姓名 + 头衔 + 简介(数据 = 人物管理) -->
|
||||
<section class="plb-section" th:fragment="plbPeople(block)" aria-label="名师风采" th:if="${!#lists.isEmpty(block.items)}">
|
||||
<div class="plb-container">
|
||||
<div th:replace="~{'themes/common/fragments/home-blocks' :: head(${block})}"></div>
|
||||
<ul class="plb-people">
|
||||
<li class="plb-person" th:each="pp : ${block.items}">
|
||||
<span class="plb-person-avatar">
|
||||
<img th:if="${!#strings.isEmpty(pp['avatar'])}" th:src="${url.upload(pp['avatar'])}" th:alt="${pp['name']}">
|
||||
<span th:unless="${!#strings.isEmpty(pp['avatar'])}"
|
||||
th:text="${#strings.length(pp['name']) > 0 ? #strings.substring(pp['name'], 0, 1) : ''}">师</span>
|
||||
</span>
|
||||
<span class="plb-person-name" th:text="${pp['name']}">姓名</span>
|
||||
<span class="plb-person-title" th:if="${!#strings.isEmpty(pp['title'])}" th:text="${pp['title']}">头衔</span>
|
||||
<span class="plb-person-bio" th:if="${!#strings.isEmpty(pp['bio'])}" th:text="${pp['bio']}">一句话简介</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- D-9 排名/学科评估徽章带 -->
|
||||
<section class="plb-section" th:fragment="plbBadges(block)" aria-label="实力声誉" th:if="${!#lists.isEmpty(block.items)}">
|
||||
<div class="plb-container">
|
||||
<div th:replace="~{'themes/common/fragments/home-blocks' :: head(${block})}"></div>
|
||||
<ul class="plb-badges">
|
||||
<li class="plb-badge-item" th:each="bd : ${block.items}">
|
||||
<img th:src="${url.upload(bd['image'])}" th:alt="${bd['label']}">
|
||||
<span class="plb-badge-label" th:text="${bd['label']}">软科排名</span>
|
||||
<span class="plb-badge-desc" th:if="${!#strings.isEmpty(bd['desc'])}" th:text="${bd['desc']}">前 100 强</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!--
|
||||
D-2 内置通用 SVG 图标集(docs/20 §3.3 定案 2:平台内置约 20 个,不引外部 CDN)。
|
||||
24x24 线条风格,stroke=currentColor;管理端图标选择器同 key 对应(front IconGrid)。
|
||||
SpEL 对 Map 缺失键访问会抛错——l['icon'] 的 Map 取值安全(缺键返回 null),不用的 g 分支整组不渲染。
|
||||
-->
|
||||
<svg th:fragment="icon(name)" class="plb-svg-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<!-- 招生(学士帽) -->
|
||||
<g th:if="${name == 'zhaosheng'}"><path d="M3 9.5 12 4.5 21 9.5 12 14.5 3 9.5z"/><path d="M7 12v4.5c0 1 2.2 2 5 2s5-1 5-2V12"/><path d="M21 9.5V15"/></g>
|
||||
<!-- 就业(公文包) -->
|
||||
<g th:if="${name == 'jiuye'}"><rect x="3.5" y="8" width="17" height="11.5" rx="2"/><path d="M9 8V6.2C9 5.5 9.6 5 10.3 5h3.4c.7 0 1.3.5 1.3 1.2V8"/><path d="M3.5 12.5h17"/></g>
|
||||
<!-- 图书馆(书) -->
|
||||
<g th:if="${name == 'tushuguan'}"><path d="M4 19.5 4.9 6.5 11 5v15"/><path d="M11 20h9V8l-7.9-1.5"/><path d="M4 19.5h7"/><path d="M14.5 11.5h3M14.5 15h3"/></g>
|
||||
<!-- 办事大厅(对话) -->
|
||||
<g th:if="${name == 'banshi'}"><path d="M4 5.5h16v10H9.5L5 19.2V15.5H4z"/></g>
|
||||
<!-- 信息公开(眼睛) -->
|
||||
<g th:if="${name == 'xinxi'}"><path d="M2.5 12C5 7.5 8.3 5.5 12 5.5S19 7.5 21.5 12C19 16.5 15.7 18.5 12 18.5S5 16.5 2.5 12z"/><circle cx="12" cy="12" r="3"/></g>
|
||||
<!-- 校友(人群) -->
|
||||
<g th:if="${name == 'xiaoyou'}"><circle cx="9" cy="8.5" r="3"/><path d="M3.5 19c0-3 2.5-5 5.5-5s5.5 2 5.5 5"/><circle cx="17" cy="9.5" r="2.2"/><path d="M16 14.2c2.6.3 4.5 2.1 4.5 4.8"/></g>
|
||||
<!-- 邮箱 -->
|
||||
<g th:if="${name == 'youjian'}"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3.5 7 8.5 6 8.5-6"/></g>
|
||||
<!-- 电话 -->
|
||||
<g th:if="${name == 'dianhua'}"><path d="M5 4h3.5l1.7 4.3-2.3 1.8a12.5 12.5 0 0 0 5.9 5.9l1.8-2.3L20 15.4V19a1.5 1.5 0 0 1-1.6 1.5C10 20 4 14 3.5 5.6A1.5 1.5 0 0 1 5 4z"/></g>
|
||||
<!-- 地图(定位) -->
|
||||
<g th:if="${name == 'ditu'}"><path d="M12 21.5c4.2-5 6.8-8 6.8-11.5a6.8 6.8 0 1 0-13.6 0c0 3.5 2.6 6.5 6.8 11.5z"/><circle cx="12" cy="9.7" r="2.4"/></g>
|
||||
<!-- 新闻 -->
|
||||
<g th:if="${name == 'xinwen'}"><rect x="3" y="5" width="18" height="14" rx="1.5"/><path d="M6.5 9h6M6.5 12.5h6M6.5 16h6"/><rect x="15.5" y="9" width="3" height="7.5" rx=".5"/></g>
|
||||
<!-- 日历 -->
|
||||
<g th:if="${name == 'rili'}"><rect x="3.5" y="5" width="17" height="15.5" rx="2"/><path d="M3.5 10h17M8 3v4M16 3v4"/></g>
|
||||
<!-- 视频 -->
|
||||
<g th:if="${name == 'shipin'}"><circle cx="12" cy="12" r="8.5"/><path d="M10 8.5 16 12l-6 3.5z"/></g>
|
||||
<!-- 微信 -->
|
||||
<g th:if="${name == 'weixin'}"><path d="M9.5 5.5C6 5.5 3 7.8 3 10.7c0 1.6.9 3 2.3 4L5 17l2.6-1.3c.6.2 1.3.3 1.9.3"/><path d="M21.5 14.8c0-2.4-2.3-4.3-5.1-4.3s-5.1 1.9-5.1 4.3 2.3 4.3 5.1 4.3c.6 0 1.2-.1 1.7-.3L20.5 20l-.5-1.7c.9-.8 1.5-2.1 1.5-3.5z"/></g>
|
||||
<!-- 微博 -->
|
||||
<g th:if="${name == 'weibo'}"><path d="M10.5 19.5c-3.5 0-6.5-2-6.5-4.7 0-2.9 3.3-5.6 6.8-5.6 3 0 6.5 1.6 6.5 4.2 0 2.3-1.9 4.3-4.4 4.3-1.8 0-3.6-.8-3.6-2 0-.8.7-1.5 1.7-1.5.9 0 1.5.5 1.5 1.1 0 .4-.3.7-.7.8"/><path d="M15.5 4.5c2.9 0 5 1.8 5.2 4.3"/><path d="M15.8 7.2c1.5 0 2.7.9 2.8 2.3"/></g>
|
||||
<!-- 抖音(音符) -->
|
||||
<g th:if="${name == 'douyin'}"><circle cx="8" cy="17.5" r="3"/><path d="M11 17.5V4.5l7 2v3.2l-4.6-1.3"/></g>
|
||||
<!-- B站 -->
|
||||
<g th:if="${name == 'bilibili'}"><rect x="3" y="6.5" width="18" height="12.5" rx="3"/><path d="M7 4l2.2 2.4M17 4l-2.2 2.4"/><path d="M9.2 10.5v4M14.8 10.5v4"/></g>
|
||||
<!-- 链接 -->
|
||||
<g th:if="${name == 'lianjie'}"><path d="m9.5 14.5 5-5"/><path d="m8 12-3 3a4 4 0 0 0 5.7 5.7l3-3"/><path d="m16 12 3-3a4 4 0 0 0-5.7-5.7l-3 3"/></g>
|
||||
<!-- 档案 -->
|
||||
<g th:if="${name == 'dangan'}"><path d="M6 3.5h8.5L18 7v13.5H6z"/><path d="M14 3.5V7h4"/><path d="M9 11h6M9 14.5h6M9 18h3.5"/></g>
|
||||
<!-- 校历/校史(建筑) -->
|
||||
<g th:if="${name == 'xiaoli'}"><path d="M4 21V10l8-6.2L20 10v11"/><path d="M10 21v-6h4v6"/><path d="M4 21h16"/><path d="M9.5 10.5h5"/></g>
|
||||
<!-- 体育(奖杯) -->
|
||||
<g th:if="${name == 'tiyu'}"><path d="M8 4.5h8v5a4 4 0 0 1-8 0z"/><path d="M8 5.5H5v1.6A3.4 3.4 0 0 0 8.4 10M16 5.5h3v1.6A3.4 3.4 0 0 1 15.6 10"/><path d="M12 13.5v3M8.5 20h7M9.8 20c0-1.7.9-3.5 2.2-3.5s2.2 1.8 2.2 3.5"/></g>
|
||||
<!-- 艺术(调色板) -->
|
||||
<g th:if="${name == 'yishu'}"><path d="M12 3a9 9 0 0 0 0 18c1.4 0 2-.8 2-1.7 0-1.5-1.6-1.9-1.6-3.1 0-1 .8-1.7 2-1.7h1.8A4.8 4.8 0 0 0 21 9.7C21 5.9 17 3 12 3z"/><circle cx="7.8" cy="10.5" r=".9"/><circle cx="12" cy="7.6" r=".9"/><circle cx="16.2" cy="10" r=".9"/></g>
|
||||
<!-- 实验(烧瓶) -->
|
||||
<g th:if="${name == 'shiyan'}"><path d="M10 3.5h4M11 3.5v6l-4.6 8.2A2 2 0 0 0 8.2 20.5h7.6a2 2 0 0 0 1.8-2.8L13 9.5v-6"/><path d="M8.5 14.5h7"/></g>
|
||||
</svg>
|
||||
|
||||
<!--
|
||||
D-8 配套 · 骨架共享动效脚本(R-42):滚动入场(fade-in-up + stagger)+ 数字计数 count-up。
|
||||
一处实现全局生效(D-8 决策),主题经 theme.json 参数 animation=off 关闭(由引用方 th:if 守卫);
|
||||
尊重 prefers-reduced-motion。观察目标 = main 的区块级直接子元素(.plb-anchor 子节点或 main 直属区块根)。
|
||||
-->
|
||||
<th:block th:fragment="motionScript">
|
||||
<script>
|
||||
(function () {
|
||||
if (window.__cmsMotionBound) { return; }
|
||||
window.__cmsMotionBound = true;
|
||||
var reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
if (reduced) { return; }
|
||||
function targets() {
|
||||
var main = document.querySelector('main');
|
||||
if (!main) { return []; }
|
||||
var out = [];
|
||||
Array.prototype.forEach.call(main.children, function (n) {
|
||||
if (n.classList && n.classList.contains('plb-anchor')) {
|
||||
Array.prototype.forEach.call(n.children, function (c) { out.push(c); });
|
||||
} else if (n.tagName === 'SECTION' || (n.tagName === 'DIV' && n.getAttribute('role') === 'note')) {
|
||||
out.push(n);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
var els = targets();
|
||||
els.forEach(function (el, i) {
|
||||
el.classList.add('plb-anim');
|
||||
el.style.transitionDelay = Math.min(i * 80, 400) + 'ms';
|
||||
});
|
||||
if (!('IntersectionObserver' in window)) {
|
||||
els.forEach(function (el) { el.classList.add('plb-in'); });
|
||||
} else {
|
||||
var io = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (en) {
|
||||
if (en.isIntersecting) {
|
||||
en.target.classList.add('plb-in');
|
||||
io.unobserve(en.target);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.12 });
|
||||
els.forEach(function (el) { io.observe(el); });
|
||||
}
|
||||
document.querySelectorAll('[data-plb-countup]').forEach(function (node) {
|
||||
var raw = (node.textContent || '').trim();
|
||||
var m = raw.match(/^([^0-9]*)([0-9,]+(?:\.[0-9]+)?)(.*)$/);
|
||||
if (!m) { return; }
|
||||
var prefix = m[1], numText = m[2].replace(/,/g, ''), suffix = m[3];
|
||||
var target = parseFloat(numText);
|
||||
if (isNaN(target)) { return; }
|
||||
var decimals = (numText.split('.')[1] || '').length;
|
||||
var t0 = null, dur = 1200;
|
||||
function step(ts) {
|
||||
if (!t0) { t0 = ts; }
|
||||
var p = Math.min((ts - t0) / dur, 1);
|
||||
var eased = 1 - Math.pow(1 - p, 3);
|
||||
node.textContent = prefix + (target * eased).toFixed(decimals) + suffix;
|
||||
if (p < 1) { requestAnimationFrame(step); }
|
||||
}
|
||||
var cio = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (en) {
|
||||
if (en.isIntersecting) {
|
||||
cio.disconnect();
|
||||
requestAnimationFrame(step);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.4 });
|
||||
cio.observe(node);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</th:block>
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<!--
|
||||
D-10(docs/20)搜索浮层 · 通用 fragment:theme.json 参数 searchStyle 控制门户搜索形态——
|
||||
· inline(缺省)= 保留主题 header 自有内联搜索表单(现状外观,零变化)
|
||||
· none = 不渲染任何搜索入口
|
||||
· overlay = 隐藏内联表单,渲染右上「放大镜」按钮 + 全屏搜索浮层(本文件实现)
|
||||
引用方式:主题 header.html 在其内联搜索表单位置——
|
||||
<th:block th:if="${themeParams != null and themeParams['searchStyle'] == 'overlay'}"
|
||||
th:replace="~{'themes/common/fragments/search' :: overlay(${url})}" />
|
||||
<form class="…" th:unless="${themeParams != null and themeParams['searchStyle'] == 'overlay'}" …>(inline/缺省保留原表单)
|
||||
样式/脚本自持(不引外部依赖);颜色跟随主题变量缺省蓝。
|
||||
-->
|
||||
<th:block th:fragment="overlay(url)">
|
||||
<div class="plb-search-widget">
|
||||
<button type="button" class="plb-search-toggle" aria-label="打开站内搜索" aria-expanded="false">
|
||||
<svg viewBox="0 0 24 24" width="19" height="19" focusable="false" aria-hidden="true">
|
||||
<path d="M10.5 3a7.5 7.5 0 015.9 12.1l4.3 4.3-1.4 1.4-4.3-4.3A7.5 7.5 0 1110.5 3zm0 2a5.5 5.5 0 100 11 5.5 5.5 0 000-11z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
<span>搜索</span>
|
||||
</button>
|
||||
<div class="plb-search-layer" role="dialog" aria-modal="true" aria-label="站内搜索">
|
||||
<button type="button" class="plb-search-close" aria-label="关闭搜索">✕</button>
|
||||
<form class="plb-search-form" th:action="${url.search('', null)}" method="get" role="search">
|
||||
<input type="text" name="q" placeholder="输入关键词,搜索本站内容…" aria-label="站内搜索" autocomplete="off">
|
||||
<button type="submit">搜 索</button>
|
||||
</form>
|
||||
<p class="plb-search-tip">按 ESC 或点击空白处关闭</p>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.plb-search-widget{position:relative}
|
||||
.plb-search-toggle{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border, #e5e6eb);
|
||||
background:transparent;color:inherit;border-radius:18px;padding:5px 14px;font-size:13px;cursor:pointer;
|
||||
transition:border-color .2s,color .2s}
|
||||
.plb-search-toggle:hover{border-color:var(--primary, #2d8cf0);color:var(--primary, #2d8cf0)}
|
||||
.plb-search-layer{position:fixed;inset:0;z-index:9999;display:none;align-items:center;justify-content:center;
|
||||
flex-direction:column;background:rgba(10,20,40,.82);backdrop-filter:blur(6px)}
|
||||
.plb-search-widget.open .plb-search-layer{display:flex}
|
||||
.plb-search-close{position:absolute;top:26px;right:32px;background:none;border:0;color:#fff;font-size:22px;
|
||||
cursor:pointer;opacity:.8;padding:6px}
|
||||
.plb-search-close:hover{opacity:1}
|
||||
.plb-search-form{display:flex;width:min(640px,86vw);border-radius:8px;overflow:hidden;box-shadow:0 18px 60px rgba(0,0,0,.35)}
|
||||
.plb-search-form input{flex:1;border:0;padding:16px 18px;font-size:16px;outline:none;min-width:0}
|
||||
.plb-search-form button{border:0;padding:0 26px;font-size:15px;cursor:pointer;
|
||||
background:var(--primary, #2d8cf0);color:#fff}
|
||||
.plb-search-form button:hover{filter:brightness(1.08)}
|
||||
.plb-search-tip{margin-top:16px;color:rgba(255,255,255,.55);font-size:12px;letter-spacing:.05em}
|
||||
</style>
|
||||
<script>
|
||||
(function () {
|
||||
var widget = document.currentScript && document.currentScript.previousElementSibling;
|
||||
while (widget && !(widget.classList && widget.classList.contains('plb-search-widget'))) {
|
||||
widget = widget && widget.previousElementSibling;
|
||||
}
|
||||
if (!widget || widget.__plbSearchBound) { return; }
|
||||
widget.__plbSearchBound = true;
|
||||
var toggle = widget.querySelector('.plb-search-toggle');
|
||||
var layer = widget.querySelector('.plb-search-layer');
|
||||
var input = widget.querySelector('.plb-search-form input');
|
||||
function open() {
|
||||
widget.classList.add('open');
|
||||
toggle.setAttribute('aria-expanded', 'true');
|
||||
if (input) { setTimeout(function () { input.focus(); }, 50); }
|
||||
}
|
||||
function close() {
|
||||
widget.classList.remove('open');
|
||||
toggle.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
toggle.addEventListener('click', open);
|
||||
widget.querySelector('.plb-search-close').addEventListener('click', close);
|
||||
layer.addEventListener('click', function (e) { if (e.target === layer) { close(); } });
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') { close(); }
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</th:block>
|
||||
@@ -34,10 +34,19 @@
|
||||
th:src="${url.upload(site.config['logo'])}" th:alt="${site.name}">
|
||||
<a class="site-name" th:href="${url.home()}" th:text="${site.name}">站点名称</a>
|
||||
</div>
|
||||
<form class="site-search" th:action="${url.search('', null)}" method="get" role="search">
|
||||
<!-- D-10(docs/20):searchStyle=overlay 换全屏搜索浮层;none 隐藏;inline/缺省保留原表单。
|
||||
坑④:th:replace 优先级(100)先于 th:if(300)——条件必须放外层 th:block,replace 放子元素 -->
|
||||
<th:block th:if="${themeParams != null and themeParams['searchStyle'] == 'overlay'}">
|
||||
<th:block th:replace="~{'themes/common/fragments/search' :: overlay(${url})}" />
|
||||
</th:block>
|
||||
<th:block th:if="${themeParams == null or themeParams['searchStyle'] == null or themeParams['searchStyle'] == 'inline'}">
|
||||
<form class="site-search"
|
||||
|
||||
th:action="${url.search('', null)}" method="get" role="search">
|
||||
<input type="text" name="q" placeholder="站内搜索" aria-label="站内搜索">
|
||||
<button type="submit">搜索</button>
|
||||
</form>
|
||||
</th:block>
|
||||
</div>
|
||||
|
||||
<!-- 栏目导航:外链栏目直接外跳;其余进栏目页(方案 §8.1) -->
|
||||
|
||||
@@ -8,12 +8,126 @@
|
||||
"screenshot": "assets/screenshot.png",
|
||||
"bannerSize": "1920x560",
|
||||
"params": [
|
||||
{ "key": "primary", "cssVar": "--primary", "label": "主色", "type": "color", "default": "#1a5cb0" },
|
||||
{ "key": "primaryDark", "cssVar": "--primary-dark", "label": "主色加深", "type": "color", "default": "#12447f" },
|
||||
{ "key": "text", "cssVar": "--text", "label": "正文文字色", "type": "color", "default": "#333333" },
|
||||
{ "key": "textLight", "cssVar": "--text-light", "label": "次要文字色", "type": "color", "default": "#777777" },
|
||||
{ "key": "bg", "cssVar": "--bg", "label": "页面底色", "type": "color", "default": "#f5f6f8" },
|
||||
{ "key": "cardBg", "cssVar": "--card-bg", "label": "卡片底色", "type": "color", "default": "#ffffff" },
|
||||
{ "key": "border", "cssVar": "--border", "label": "边框色", "type": "color", "default": "#e5e6eb" }
|
||||
{
|
||||
"key": "primary",
|
||||
"cssVar": "--primary",
|
||||
"label": "主色",
|
||||
"type": "color",
|
||||
"default": "#1a5cb0"
|
||||
},
|
||||
{
|
||||
"key": "primaryDark",
|
||||
"cssVar": "--primary-dark",
|
||||
"label": "主色加深",
|
||||
"type": "color",
|
||||
"default": "#12447f"
|
||||
},
|
||||
{
|
||||
"key": "text",
|
||||
"cssVar": "--text",
|
||||
"label": "正文文字色",
|
||||
"type": "color",
|
||||
"default": "#333333"
|
||||
},
|
||||
{
|
||||
"key": "textLight",
|
||||
"cssVar": "--text-light",
|
||||
"label": "次要文字色",
|
||||
"type": "color",
|
||||
"default": "#777777"
|
||||
},
|
||||
{
|
||||
"key": "bg",
|
||||
"cssVar": "--bg",
|
||||
"label": "页面底色",
|
||||
"type": "color",
|
||||
"default": "#f5f6f8"
|
||||
},
|
||||
{
|
||||
"key": "cardBg",
|
||||
"cssVar": "--card-bg",
|
||||
"label": "卡片底色",
|
||||
"type": "color",
|
||||
"default": "#ffffff"
|
||||
},
|
||||
{
|
||||
"key": "border",
|
||||
"cssVar": "--border",
|
||||
"label": "边框色",
|
||||
"type": "color",
|
||||
"default": "#e5e6eb"
|
||||
},
|
||||
{
|
||||
"key": "animation",
|
||||
"label": "首页动效",
|
||||
"type": "select",
|
||||
"default": "on",
|
||||
"options": [
|
||||
{
|
||||
"value": "on",
|
||||
"label": "开启(滚动入场 + 数字计数)"
|
||||
},
|
||||
{
|
||||
"value": "off",
|
||||
"label": "关闭(静态呈现)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "titleStyle",
|
||||
"label": "栏目标题语言",
|
||||
"type": "select",
|
||||
"default": "cn",
|
||||
"options": [
|
||||
{
|
||||
"value": "cn",
|
||||
"label": "仅中文"
|
||||
},
|
||||
{
|
||||
"value": "bilingual",
|
||||
"label": "中英双语(大中文 + 斜体英文副题)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "iconShape",
|
||||
"label": "图标形状语言",
|
||||
"type": "select",
|
||||
"default": "circle",
|
||||
"options": [
|
||||
{
|
||||
"value": "circle",
|
||||
"label": "圆形徽章"
|
||||
},
|
||||
{
|
||||
"value": "hexagon",
|
||||
"label": "六边形"
|
||||
},
|
||||
{
|
||||
"value": "square",
|
||||
"label": "圆角方形"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "searchStyle",
|
||||
"label": "门户搜索样式",
|
||||
"type": "select",
|
||||
"default": "inline",
|
||||
"options": [
|
||||
{
|
||||
"value": "none",
|
||||
"label": "不显示搜索"
|
||||
},
|
||||
{
|
||||
"value": "inline",
|
||||
"label": "通栏搜索条(banner 下方白色大搜索条)"
|
||||
},
|
||||
{
|
||||
"value": "overlay",
|
||||
"label": "全屏搜索浮层(右上放大镜唤起)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -44,7 +44,15 @@
|
||||
</span>
|
||||
<a class="sp-site-name" th:href="${url.home()}" th:text="${site.name}">站点名称</a>
|
||||
</div>
|
||||
<form class="sp-search" th:action="${url.search('', null)}" method="get" role="search">
|
||||
<!-- D-10(docs/20):searchStyle=overlay 换全屏搜索浮层;none 隐藏;inline/缺省保留原表单。
|
||||
坑④:th:replace 优先级(100)先于 th:if(300)——条件必须放外层 th:block,replace 放子元素 -->
|
||||
<th:block th:if="${themeParams != null and themeParams['searchStyle'] == 'overlay'}">
|
||||
<th:block th:replace="~{'themes/common/fragments/search' :: overlay(${url})}" />
|
||||
</th:block>
|
||||
<th:block th:if="${themeParams == null or themeParams['searchStyle'] == null or themeParams['searchStyle'] == 'inline'}">
|
||||
<form class="sp-search"
|
||||
|
||||
th:action="${url.search('', null)}" method="get" role="search">
|
||||
<input type="text" name="q" placeholder="请输入关键字…" aria-label="站内搜索">
|
||||
<button type="submit" aria-label="搜索">
|
||||
<svg viewBox="0 0 24 24" width="16" height="16" focusable="false" aria-hidden="true">
|
||||
@@ -53,6 +61,7 @@
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
</th:block>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -8,20 +8,163 @@
|
||||
"screenshot": "assets/screenshot.png",
|
||||
"bannerSize": "1920x560",
|
||||
"params": [
|
||||
{ "key": "primary", "cssVar": "--sp-primary", "label": "主色", "type": "color", "default": "#0a5aa8" },
|
||||
{ "key": "primaryDark", "cssVar": "--sp-primary-dark", "label": "主色加深", "type": "color", "default": "#033d70" },
|
||||
{ "key": "primaryLight", "cssVar": "--sp-primary-light","label": "主色提亮", "type": "color", "default": "#1167bb" },
|
||||
{ "key": "navBg", "cssVar": "--sp-nav-bg", "label": "导航条底色", "type": "color", "default": "#ffffff" },
|
||||
{ "key": "footerBg", "cssVar": "--sp-footer-bg", "label": "页脚底色", "type": "color", "default": "#0b4781" },
|
||||
{ "key": "text", "cssVar": "--sp-text", "label": "正文文字色", "type": "color", "default": "#333333" },
|
||||
{ "key": "textLight", "cssVar": "--sp-text-light", "label": "次要文字色", "type": "color", "default": "#777777" },
|
||||
{ "key": "bg", "cssVar": "--sp-bg", "label": "页面底色", "type": "color", "default": "#eff2f6" },
|
||||
{ "key": "cardBg", "cssVar": "--sp-card-bg", "label": "卡片底色", "type": "color", "default": "#ffffff" },
|
||||
{ "key": "border", "cssVar": "--sp-border", "label": "边框色", "type": "color", "default": "#e3e7ee" },
|
||||
{ "key": "headerStyle", "label": "头部样式", "type": "select", "default": "banner",
|
||||
{
|
||||
"key": "primary",
|
||||
"cssVar": "--sp-primary",
|
||||
"label": "主色",
|
||||
"type": "color",
|
||||
"default": "#0a5aa8"
|
||||
},
|
||||
{
|
||||
"key": "primaryDark",
|
||||
"cssVar": "--sp-primary-dark",
|
||||
"label": "主色加深",
|
||||
"type": "color",
|
||||
"default": "#033d70"
|
||||
},
|
||||
{
|
||||
"key": "primaryLight",
|
||||
"cssVar": "--sp-primary-light",
|
||||
"label": "主色提亮",
|
||||
"type": "color",
|
||||
"default": "#1167bb"
|
||||
},
|
||||
{
|
||||
"key": "navBg",
|
||||
"cssVar": "--sp-nav-bg",
|
||||
"label": "导航条底色",
|
||||
"type": "color",
|
||||
"default": "#ffffff"
|
||||
},
|
||||
{
|
||||
"key": "footerBg",
|
||||
"cssVar": "--sp-footer-bg",
|
||||
"label": "页脚底色",
|
||||
"type": "color",
|
||||
"default": "#0b4781"
|
||||
},
|
||||
{
|
||||
"key": "text",
|
||||
"cssVar": "--sp-text",
|
||||
"label": "正文文字色",
|
||||
"type": "color",
|
||||
"default": "#333333"
|
||||
},
|
||||
{
|
||||
"key": "textLight",
|
||||
"cssVar": "--sp-text-light",
|
||||
"label": "次要文字色",
|
||||
"type": "color",
|
||||
"default": "#777777"
|
||||
},
|
||||
{
|
||||
"key": "bg",
|
||||
"cssVar": "--sp-bg",
|
||||
"label": "页面底色",
|
||||
"type": "color",
|
||||
"default": "#eff2f6"
|
||||
},
|
||||
{
|
||||
"key": "cardBg",
|
||||
"cssVar": "--sp-card-bg",
|
||||
"label": "卡片底色",
|
||||
"type": "color",
|
||||
"default": "#ffffff"
|
||||
},
|
||||
{
|
||||
"key": "border",
|
||||
"cssVar": "--sp-border",
|
||||
"label": "边框色",
|
||||
"type": "color",
|
||||
"default": "#e3e7ee"
|
||||
},
|
||||
{
|
||||
"key": "headerStyle",
|
||||
"label": "头部样式",
|
||||
"type": "select",
|
||||
"default": "banner",
|
||||
"options": [
|
||||
{ "value": "banner", "label": "深蓝顶栏+品牌行+白底导航(完整学院派)" },
|
||||
{ "value": "plain", "label": "简洁顶栏(收起深蓝细条、压低品牌行)" }
|
||||
] }
|
||||
{
|
||||
"value": "banner",
|
||||
"label": "深蓝顶栏+品牌行+白底导航(完整学院派)"
|
||||
},
|
||||
{
|
||||
"value": "plain",
|
||||
"label": "简洁顶栏(收起深蓝细条、压低品牌行)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "animation",
|
||||
"label": "首页动效",
|
||||
"type": "select",
|
||||
"default": "on",
|
||||
"options": [
|
||||
{
|
||||
"value": "on",
|
||||
"label": "开启(滚动入场 + 数字计数)"
|
||||
},
|
||||
{
|
||||
"value": "off",
|
||||
"label": "关闭(静态呈现)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "titleStyle",
|
||||
"label": "栏目标题语言",
|
||||
"type": "select",
|
||||
"default": "cn",
|
||||
"options": [
|
||||
{
|
||||
"value": "cn",
|
||||
"label": "仅中文"
|
||||
},
|
||||
{
|
||||
"value": "bilingual",
|
||||
"label": "中英双语(大中文 + 斜体英文副题)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "iconShape",
|
||||
"label": "图标形状语言",
|
||||
"type": "select",
|
||||
"default": "circle",
|
||||
"options": [
|
||||
{
|
||||
"value": "circle",
|
||||
"label": "圆形徽章"
|
||||
},
|
||||
{
|
||||
"value": "hexagon",
|
||||
"label": "六边形"
|
||||
},
|
||||
{
|
||||
"value": "square",
|
||||
"label": "圆角方形"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "searchStyle",
|
||||
"label": "门户搜索样式",
|
||||
"type": "select",
|
||||
"default": "inline",
|
||||
"options": [
|
||||
{
|
||||
"value": "none",
|
||||
"label": "不显示搜索"
|
||||
},
|
||||
{
|
||||
"value": "inline",
|
||||
"label": "通栏搜索条(banner 下方白色大搜索条)"
|
||||
},
|
||||
{
|
||||
"value": "overlay",
|
||||
"label": "全屏搜索浮层(右上放大镜唤起)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user