diff --git a/src/main/resources/templates/themes/agri-forest/README.md b/src/main/resources/templates/themes/agri-forest/README.md new file mode 100644 index 0000000..0813669 --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/README.md @@ -0,0 +1,58 @@ +# agri-forest · 农林绿 + +云海 CMS 皮肤包。fork 自 `default`(数据契约、模板 th:* 绑定与 default 完全一致),视觉层按农林院校门户语言全部重写,设计语言参考信阳农林学院官网(仅学语言,不复制实现)。 + +## 风格定位 + +- **气质词**:庄重、质朴、农林学府。 +- **配色**:墨绿 `#1C6E19` 主导(通栏导航/日期方块/页脚主底),加深端 `#14510F`(页脚/标题条),提亮端 `#3FA43A`(当前导航项/hover),麦穗金 `#C8A45C` 只做装饰线与角标(栏目标题下划线、导航当前项下杠、日期方块 hover 金线、置顶角标)。 +- **结构**:白色页头(左校徽+校名,右工具行:今日日期 + 校园直通车下拉 + 站内搜索)→ 墨绿通栏主导航(白字,当前栏目提亮绿底+金下杠,导航下方与 banner 无缝)→ 通栏轮播(左下墨绿标题条带金边)→ 首页区块 → 墨绿多列页脚(更深底条)。 +- **工艺**:小圆角 4px;间距刻度 4/8/12/16/24/32/48;字号阶梯 12/13/14/15/16/18/20/24/28/32;hover 过渡 0.2s ease;正文行高 1.75;无渐变堆砌、无粉紫、无玻璃拟态;图标一律内联 SVG。 + +## 参数取值建议(theme.json,13 项) + +| key | cssVar | 默认 | 建议 | +| --- | --- | --- | --- | +| primary | `--af-primary` | `#1C6E19` | 主色。换季校庆可微调为 `#1F7A1B`,勿低于 `#14510F` 明度(导航白字对比) | +| primaryDark | `--af-primary-dark` | `#14510F` | 页脚主底/轮播标题条。与 primary 保持同色相 1~2 档差 | +| primaryLight | `--af-primary-light` | `#3FA43A` | 当前导航项/hover。需要更醒目可用 `#4DB548`,过亮会刺眼 | +| accent | `--af-accent` | `#C8A45C` | 麦穗金装饰线/角标。庄重场合可降饱和为 `#B8934A` | +| navBg | `--af-nav-bg` | `#1C6E19` | 主导航底色。默认与 primary 一致;要"导航深一档"配 `#14510F` | +| footerBg | `--af-footer-bg` | `#14510F` | 页脚主底;底条固定更深一档(`--af-primary-deep`,非参数) | +| text / textLight | `--af-text` / `--af-text-light` | `#2A3327` / `#6C7A67` | 正文/次要文字,偏绿灰 | +| bg | `--af-bg` | `#F5F8F3` | 页面底色,带一点绿调的暖白 | +| cardBg | `--af-card-bg` | `#FFFFFF` | 卡片底,建议保持纯白 | +| border | `--af-border` | `#DDE8DA` | 边框/分隔线,绿灰调 | +| linkGreen | `--af-link` | `#277428` | 正文链接绿,介于主色深浅之间 | +| listLayout | —(select) | `date` | 列表页形态:`date`=46px 日期方块行(农林官网典型);`plain`=通栏行式(日期右置),信息密度更高 | + +微调优先级:站点 `theme_params`(本表参数)→ 站点 `custom_css` → 本包 main.css(契约 §6)。 + +## 首页九段形态表(fragments/home-blocks.html) + +站点配 `home_layout` 时首页正文由本包 fragment 渲染(换肤必须连正文一起换): + +| fragment | 触发 | 形态 | +| --- | --- | --- | +| `news_grid` | article_list + homeStyle=news_grid | 三图焦点(横排 3 封面卡)+ 双列要闻行式列表;支持站点背景带(news_bg_image,画在卡片之下) | +| `media_focus` | article_list + homeStyle=media_focus | 学术动态:双列密行 + 墨绿来源徽标 | +| `compact` | article_list + homeStyle=compact | 通知公告:46px 墨绿日期方块(日大号+年月小号),行 hover 出金线 | +| `image_wall` | article_list + homeStyle=image_wall | 四列图片墙(仅有封面条目),悬浮标题 | +| `card` | article_list 其他/未设 | 默认卡:头条图文(有封面则图文)+ 行式列表 | +| `ticker` | type=ticker | 要闻速递横条:墨绿底、金色分隔、单行不塌列 | +| `gallery` | type=gallery | 校园映像:居中标题+副题+四列图墙+悬浮标题 | +| `links` | type=links | 专题网站:4 列缩略卡(绿标题条+金下杠+圆徽),分组拉平 | +| `empty` | 各形态 items 为空 | 空态「栏目暂无内容」(守卫包在外层 th:block,th:replace 优先级 100 先于 th:if 300) | + +未知类型回落 `themes/common` 通用骨架;`:root` 已把 `--af-*` 别名到契约变量(`--primary/--text/--card-bg/--border/--bg/--radius`),兜底骨架与 themeVarsCss 换色可穿透。 + +## 纪律要点 + +- URL 一律 `url.*` 生成,无硬编码绝对地址;非转义输出仅契约七处白名单。 +- 中文防塌列:`.af-ticker-list{min-width:0;white-space:nowrap}`、`.af-ticker-item{flex:none;text-overflow:ellipsis}`、`.af-block-item-title{min-width:0;overflow:hidden;text-overflow:ellipsis}`。 +- 网格一律 `minmax(0,1fr)`;≤768px 单列、导航横滚、子菜单静态平铺。 +- 背景带层序:`.af-sec-bg` z-index:0,其后 `.af-block` z-index:1。 + +## 截图说明 + +`assets/screenshot.png` 为按本皮肤设计语言绘制的门户结构示意图(非浏览器实拍)。管理端选择器如需实拍图,起服后截首页替换即可(记入遗留项)。 diff --git a/src/main/resources/templates/themes/agri-forest/assets/css/main.css b/src/main/resources/templates/themes/agri-forest/assets/css/main.css new file mode 100644 index 0000000..71a30a6 --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/assets/css/main.css @@ -0,0 +1,1555 @@ +/* ===================================================================== + agri-forest · 农林绿(基座 default,设计语言参考信阳农林学院官网) + 设计语言:白色页头(校徽+校名 / 右工具行)+ 墨绿通栏主导航(当前项 primaryLight 底) + + 通栏轮播(左下墨绿标题条)+ 三图焦点新闻 + 带图标栏目标题(麦穗金装饰线) + + 46px 日期方块通知列表 + 学术来源徽标 + 专题缩略卡 + 校园映像四列图墙 + + 墨绿多列页脚(更深底条) + 色彩令牌全部走 CSS 变量,theme.json color 参数经 :root 覆盖真实生效。 + 工艺约定:间距 4/8/12/16/24/32/48 · 字号 12/13/14/15/16/18/20/24/28/32 + · hover 过渡 0.2s ease · 小圆角 4px · 正文行高 1.75 · 禁渐变堆砌/粉紫/玻璃拟态 + ===================================================================== */ + +/* 1. 设计令牌(与 theme.json params 一一对应,禁止出现未消费的声明) */ +:root { + --af-primary: #1C6E19; /* 主色:墨绿,主导航/标题/强调 */ + --af-primary-dark: #14510F; /* 主色加深:页脚主底/hover 深端/标题条 */ + --af-primary-light: #3FA43A; /* 主色提亮:当前导航项/hover 链接 */ + --af-accent: #C8A45C; /* 麦穗金:栏目标题装饰线/角标/日期方块 hover 金线 */ + --af-nav-bg: #1C6E19; /* 主导航条底色(墨绿通栏) */ + --af-footer-bg: #14510F; /* 页脚主底 */ + --af-text: #2A3327; /* 正文 */ + --af-text-light: #6C7A67; /* 次要文字 */ + --af-bg: #F5F8F3; /* 页面底色 */ + --af-card-bg: #FFFFFF; /* 卡片底 */ + --af-border: #DDE8DA; /* 边框/分隔线 */ + --af-link: #277428; /* 链接绿 */ + + /* —— 派生令牌(非参数,供组件消费)—— */ + --af-primary-deep: #0E3D0B; /* 页脚底条(比页脚主底更深一档) */ + --af-tint: #EAF3E8; /* 浅绿面(行 hover/侧栏激活/占位面) */ + --af-tint-strong: #DCEBDA; /* 浅绿面加深(分隔带/表头) */ + --af-accent-soft: #F7F0DF; /* 金浅底(徽标浅衬) */ + --af-on-dark: #FFFFFF; /* 深底主文字 */ + --af-on-dark-soft: rgba(255,255,255,.78); + --af-on-dark-faint: rgba(255,255,255,.55); + --af-shadow-color: rgba(20,81,15,.10); + --af-shadow-sm: 0 1px 4px var(--af-shadow-color); + --af-shadow-md: 0 6px 18px rgba(20,81,15,.13); + --af-shadow-lg: 0 14px 32px rgba(20,81,15,.18); + --af-scrim: rgba(14,61,11,.55); /* 轮播标题条投影端 */ + + /* —— 字号阶梯(12/13/14/15/16/18/20/24/28/32)—— */ + --af-fs-12: 12px; + --af-fs-13: 13px; + --af-fs-14: 14px; + --af-fs-15: 15px; + --af-fs-16: 16px; + --af-fs-18: 18px; + --af-fs-20: 20px; + --af-fs-24: 24px; + --af-fs-28: 28px; + --af-fs-32: 32px; + + /* —— 间距刻度(4/8/12/16/24/32/48)—— */ + --af-sp-1: 4px; + --af-sp-2: 8px; + --af-sp-3: 12px; + --af-sp-4: 16px; + --af-sp-6: 24px; + --af-sp-8: 32px; + --af-sp-12: 48px; + + /* —— 圆角 / 过渡 / 层级 / 栅格 —— */ + --af-radius: 4px; + --af-speed: .2s ease; + --af-z-dropdown: 110; + --af-max-width: 1200px; + --af-gutter: 24px; + --af-font: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Helvetica Neue", Arial, sans-serif; + + /* 皮肤契约别名:common 兜底骨架与 themeVarsCss 换色只认契约变量(--primary/--text/--…), + 不别名过去,换肤就只换了页头页脚、首页区块仍是骨架内置色。 */ + --primary: var(--af-primary); + --primary-dark: var(--af-primary-dark); + --primary-light: var(--af-primary-light); + --text: var(--af-text); + --text-light: var(--af-text-light); + --bg: var(--af-bg); + --card-bg: var(--af-card-bg); + --border: var(--af-border); + --radius: var(--af-radius); +} + +/* 2. Reset 与基础 */ +* { box-sizing: border-box; } +html { -webkit-text-size-adjust: 100%; } +body { + margin: 0; + font-family: var(--af-font); + font-size: var(--af-fs-14); + line-height: 1.75; + color: var(--af-text); + background: var(--af-bg); + word-break: break-word; +} +h1, h2, h3, h4, h5, h6 { margin: 0; line-height: 1.35; color: var(--af-text); } +p { margin: 0 0 var(--af-sp-3); } +ul, ol { margin: 0; padding: 0; list-style: none; } +a { color: var(--af-link); text-decoration: none; transition: color var(--af-speed); } +a:hover { color: var(--af-primary-light); } +a:focus-visible, +button:focus-visible, +input:focus-visible { outline: 2px solid var(--af-primary-light) outline-offset: 2px } +img { max-width: 100%; height: auto; display: block; border: 0; } +button { font-family: inherit; } +time { color: var(--af-text-light); font-size: var(--af-fs-13); } +::selection { background: var(--af-tint-strong); color: var(--af-primary-dark); } + +/* 跳过链接(无障碍) */ +.af-skip-link { + position: absolute; + left: -9999px; + top: 0; + z-index: 200; + background: var(--af-primary); + color: var(--af-on-dark); + padding: var(--af-sp-2) var(--af-sp-4); + border-radius: 0 0 var(--af-radius) 0; +} +.af-skip-link:focus { left: 0; color: var(--af-on-dark); } + +/* 3. 白色页头:左校徽+校名 / 右工具行(日期 + 校园直通车 + 搜索) */ +.af-header { background: var(--af-card-bg); } +.af-head { border-bottom: 1px solid var(--af-border); } +.af-head-inner { + max-width: var(--af-max-width); + margin: 0 auto; + padding: var(--af-sp-4) var(--af-gutter); + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--af-sp-6); +} +.af-brand { display: flex; align-items: center; gap: var(--af-sp-3); min-width: 0; } +.af-logo { height: 60px; width: auto; flex: none; } +.af-sitename { + font-size: var(--af-fs-28); + font-weight: 700; + color: var(--af-primary-dark); + letter-spacing: 2px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.af-sitename:hover { color: var(--af-primary); } + +/* 工具行 */ +.af-head-side { display: flex; align-items: center; gap: var(--af-sp-4); flex: none; } +.af-date { color: var(--af-text-light); font-size: var(--af-fs-13); white-space: nowrap; } + +/* 校园直通车(专业院系)下拉:悬停/聚焦展开 */ +.af-colleges { position: relative; } +.af-colleges-toggle { + display: inline-flex; + align-items: center; + gap: var(--af-sp-1); + padding: var(--af-sp-1) var(--af-sp-2); + border: 1px solid var(--af-border); + border-radius: var(--af-radius); + cursor: pointer; + color: var(--af-text-light); + font-size: var(--af-fs-13); + white-space: nowrap; + transition: color var(--af-speed), border-color var(--af-speed); +} +.af-colleges-toggle:hover { color: var(--af-primary); border-color: var(--af-primary-light); } +.af-colleges-arrow { font-style: normal; font-size: 11px; transition: transform var(--af-speed); } +.af-colleges:hover .af-colleges-arrow { transform: rotate(180deg); } +.af-colleges-menu { + display: none; + position: absolute; + top: 100%; + right: 0; + min-width: 200px; + max-height: 420px; + overflow-y: auto; + padding: var(--af-sp-1) 0; + background: var(--af-card-bg); + border: 1px solid var(--af-border); + border-top: 3px solid var(--af-accent); + border-radius: 0 0 var(--af-radius) var(--af-radius); + box-shadow: var(--af-shadow-md); + z-index: var(--af-z-dropdown); +} +.af-colleges:hover .af-colleges-menu, +.af-colleges:focus-within .af-colleges-menu { display: block; } +.af-colleges-menu li a { + display: block; + padding: var(--af-sp-2) var(--af-sp-4); + color: var(--af-text); + white-space: nowrap; + font-size: var(--af-fs-14); +} +.af-colleges-menu li a:hover { background: var(--af-tint); color: var(--af-primary); } +.af-colleges-menu li.active a { color: var(--af-primary); font-weight: 600; } + +/* 站内搜索(工具行右端) */ +.af-search { display: flex; flex: none; } +.af-search input { + border: 1px solid var(--af-border); + border-right: none; + border-radius: var(--af-radius) 0 0 var(--af-radius); + padding: var(--af-sp-1) var(--af-sp-3); + width: 200px; + font-size: var(--af-fs-13); + font-family: inherit; + color: var(--af-text); + background: var(--af-card-bg); + outline: none; + transition: border-color var(--af-speed), box-shadow var(--af-speed); +} +.af-search input::placeholder { color: var(--af-text-light); } +.af-search input:focus { border-color: var(--af-primary); box-shadow: 0 0 0 3px var(--af-tint-strong); } +.af-search button { + border: none; + background: var(--af-primary); + color: var(--af-on-dark); + padding: var(--af-sp-1) var(--af-sp-4); + font-size: var(--af-fs-13); + border-radius: 0 var(--af-radius) var(--af-radius) 0; + cursor: pointer; + transition: background var(--af-speed); +} +.af-search button:hover { background: var(--af-primary-dark); } + +/* 4. 墨绿通栏主导航:白字,当前栏目 primaryLight 底;导航下方不留缝 */ +.af-nav { background: var(--af-nav-bg); box-shadow: var(--af-shadow-sm); } +.af-nav ul { + max-width: var(--af-max-width); + margin: 0 auto; + padding: 0 var(--af-gutter); + list-style: none; + display: flex; + flex-wrap: wrap; +} +.af-nav > ul > li { position: relative; } +.af-nav li a { + display: block; + padding: var(--af-sp-3) var(--af-sp-6); + color: var(--af-on-dark); + font-size: var(--af-fs-16); + position: relative; + transition: background var(--af-speed); +} +.af-nav li a:hover, +.af-nav li.active > a { background: var(--af-primary-light); color: var(--af-on-dark); } + +/* 麦穗金下杠:当前项/悬停项底部金线 */ +.af-nav li a::after { + content: ""; + position: absolute; + left: var(--af-sp-6); + right: var(--af-sp-6); + bottom: 0; + height: 3px; + background: var(--af-accent); + transform: scaleX(0); + transition: transform var(--af-speed); +} +.af-nav li.active > a::after, +.af-nav li:hover > a::after { transform: scaleX(1); } + +/* 二级下拉:白底面板 + 金顶线 */ +.af-nav li.has-sub > a .af-caret { + font-style: normal; + font-size: 11px; + margin-left: var(--af-sp-1); + opacity: .8; +} +.af-nav ul.af-sub-nav { + display: none; + position: absolute; + top: 100%; + left: 0; + min-width: 176px; + padding: var(--af-sp-1) 0; + background: var(--af-card-bg); + border: 1px solid var(--af-border); + border-top: 3px solid var(--af-accent); + border-radius: 0 0 var(--af-radius) var(--af-radius); + box-shadow: var(--af-shadow-md); + z-index: var(--af-z-dropdown); +} +.af-nav li:hover > ul.af-sub-nav, +.af-nav li:focus-within > ul.af-sub-nav { display: block; } +.af-nav .af-sub-nav li a { + padding: var(--af-sp-2) var(--af-sp-4); + color: var(--af-text); + white-space: nowrap; + background: none; + font-size: var(--af-fs-14); +} +.af-nav .af-sub-nav li a::after { display: none; } +.af-nav .af-sub-nav li a:hover { background: var(--af-tint); color: var(--af-primary); } +.af-nav .af-sub-nav li.active a { color: var(--af-primary); font-weight: 600; } + +/* 5. 首页轮播(通栏 1920×560):干净切图 + 左下墨绿标题条 */ +.af-banner { position: relative; overflow: hidden; background: var(--af-primary-deep); } +.af-banner-slides { position: relative; aspect-ratio: 1920 / 560; max-height: 560px; } +.af-banner-slide { display: none; position: absolute; inset: 0; } +.af-banner-slide.active { display: block; } +.af-banner-slide img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} +.af-banner-title { + position: absolute; + left: max(var(--af-gutter), calc((100% - var(--af-max-width)) / 2 + var(--af-gutter))); + bottom: var(--af-sp-6); + max-width: min(72%, 680px); + padding: var(--af-sp-3) var(--af-sp-6); + background: var(--af-primary-dark); + border-left: 4px solid var(--af-accent); + border-radius: 0 var(--af-radius) var(--af-radius) 0; + box-shadow: var(--af-shadow-md); + color: var(--af-on-dark); + font-size: var(--af-fs-20); + font-weight: 600; + line-height: 1.5; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.af-banner-dots { + position: absolute; + bottom: var(--af-sp-4); + right: max(var(--af-gutter), calc((100% - var(--af-max-width)) / 2 + var(--af-gutter))); + display: flex; + gap: var(--af-sp-2); + z-index: 20; +} +.af-banner-dots button { + width: 10px; + height: 10px; + padding: 0; + border: none; + border-radius: 999px; + background: var(--af-on-dark-faint); + cursor: pointer; + transition: width .2s ease, background .2s ease; +} +.af-banner-dots button.active { width: 28px; background: var(--af-accent); } +.af-banner-arrow { + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 44px; + height: 44px; + border: none; + border-radius: 50%; + background: var(--af-scrim); + color: var(--af-on-dark); + font-size: 22px; + line-height: 1; + cursor: pointer; + opacity: .55; + transition: opacity var(--af-speed), background var(--af-speed); + z-index: 20; + display: flex; + align-items: center; + justify-content: center; + padding: 0; +} +.af-banner-arrow:hover { opacity: 1; background: var(--af-primary); } +.af-banner-arrow.prev { left: max(var(--af-gutter), calc((100% - var(--af-max-width)) / 2)); } +.af-banner-arrow.next { right: max(var(--af-gutter), calc((100% - var(--af-max-width)) / 2)); } + +/* 6. 容器 / 分节 / 背景带层序 */ +.af-home, .af-page { display: block; } +.af-container { max-width: var(--af-max-width) margin: 0 auto padding: 0 var(--af-gutter) } +.af-section { margin: var(--af-sp-12) 0; } +.af-section:first-of-type { margin-top: var(--af-sp-8); } + +/* 新闻背景带:绝对定位层必须压 z-index:0,其后第一个卡片抬到 z-index:1(否则带图糊在卡片正面) */ +.af-sec-bg { + position: absolute; + inset: 0; + z-index: 0; + background-color: var(--af-tint); + background-size: cover; + background-position: center; +} +.af-sec-bg + .af-block { position: relative; z-index: 1; } +.af-section--news { position: relative; padding: var(--af-sp-8) 0; margin: var(--af-sp-8) 0; } + +/* 7. 区块卡与栏目标题(内联 SVG 小图标 + 麦穗金装饰线 + 右侧「更多」) */ +.af-block { + background: var(--af-card-bg); + border: 1px solid var(--af-border); + border-radius: var(--af-radius); + box-shadow: var(--af-shadow-sm); + padding: var(--af-sp-6); + transition: box-shadow var(--af-speed); +} +.af-block:hover { box-shadow: var(--af-shadow-md); } +.af-block-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--af-sp-4); + margin-bottom: var(--af-sp-4); +} +.af-block-title { + display: inline-flex; + align-items: center; + gap: var(--af-sp-2); + padding-bottom: var(--af-sp-2); + border-bottom: 3px solid var(--af-accent); /* 麦穗金装饰线 */ +} +.af-block-title h2 { + font-size: var(--af-fs-20); + font-weight: 700; + color: var(--af-text); + letter-spacing: 1px; + white-space: nowrap; +} +.af-block-icon { + flex: none; + width: 28px; + height: 28px; + border-radius: var(--af-radius); + background: var(--af-primary); + color: var(--af-on-dark); + display: inline-flex; + align-items: center; + justify-content: center; +} +.af-more { + flex: none; + font-size: var(--af-fs-13); + color: var(--af-text-light); + white-space: nowrap; + transition: color var(--af-speed); +} +.af-more:hover { color: var(--af-link); } +.af-section-title { + font-size: var(--af-fs-18); + position: relative; + padding-left: var(--af-sp-3); + margin: 0 0 var(--af-sp-3); +} +.af-section-title::before { + content: ""; + position: absolute; + left: 0; + top: 4px; + bottom: 4px; + width: 4px; + border-radius: 2px; + background: var(--af-primary); +} + +/* 8. 行式列表(要闻/学术/默认卡的公共行)与徽标 */ +.af-block-list { list-style: none; } +.af-block-list--two { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0 var(--af-sp-8); +} +.af-line { + display: flex; + align-items: center; + gap: var(--af-sp-3); + padding: 10px var(--af-sp-2); + margin: 0 calc(-1 * var(--af-sp-2)); + border-bottom: 1px dashed var(--af-border); + border-radius: var(--af-radius); + transition: background var(--af-speed); +} +.af-line:last-child { border-bottom-color: transparent; } +.af-line:hover { background: var(--af-tint); } + +/* 中文防塌列:行标题让出收缩权并超长省略 */ +.af-block-item-title { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: var(--af-fs-15); + color: var(--af-text); + transition: color var(--af-speed); +} +.af-block-item-title:hover { color: var(--af-link); } +.af-item-date { flex: none; color: var(--af-text-light); font-size: var(--af-fs-13); } + +/* 置顶角标:麦穗金 */ +.af-top-badge { + flex: none; + background: var(--af-accent); + color: var(--af-primary-dark); + font-size: var(--af-fs-12); + font-weight: 700; + line-height: 1; + padding: 3px var(--af-sp-2); + border-radius: var(--af-radius); +} + +/* 来源徽标(学术动态):墨绿描边小徽 */ +.af-src { + flex: none; + max-width: 9em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: var(--af-fs-12); + color: var(--af-primary); + background: var(--af-tint); + border: 1px solid var(--af-tint-strong); + border-radius: var(--af-radius); + padding: 1px var(--af-sp-2); + line-height: 1.7; +} + +/* 46px 日期方块(通知公告):日大号 + 年月小号,墨绿底白字,hover 金线 */ +.af-date-chip { + flex: none; + width: 46px; + min-height: 46px; + padding: var(--af-sp-1) 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background: var(--af-primary); + color: var(--af-on-dark); + border-radius: var(--af-radius); + box-shadow: inset 0 -3px 0 transparent; + transition: box-shadow var(--af-speed); +} +.af-date-chip b { font-size: var(--af-fs-18); font-weight: 700; line-height: 1.15; } +.af-date-chip i { font-style: normal; font-size: var(--af-fs-12); line-height: 1.3; opacity: .82; } +.af-line:hover .af-date-chip { box-shadow: inset 0 -3px 0 var(--af-accent); } +.af-notice-list .af-line { padding-top: var(--af-sp-2); padding-bottom: var(--af-sp-2); } + +/* 9. 三图焦点(news_grid 前排 / 首页图片新闻):横排 3 卡 */ +.af-trio { + list-style: none; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: var(--af-sp-4); +} +.af-trio-item > a { display: block; } +.af-trio-cover { + display: block; + position: relative; + aspect-ratio: 4 / 3; + overflow: hidden; + border-radius: var(--af-radius); + background: var(--af-tint); + border: 1px solid var(--af-border); +} +.af-trio-cover img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + transition: transform .2s ease; +} +.af-trio-item:hover .af-trio-cover img { transform: scale(1.04); } + +/* 无封面时的绿面叶纹占位(不造假图) */ +.af-trio-ph { + display: flex; + align-items: center; + justify-content: center; + color: var(--af-primary-light); + background: var(--af-tint); +} +.af-trio-cap { display: block; padding: var(--af-sp-2) var(--af-sp-1) 0; } +.af-trio-title { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: var(--af-fs-15); + font-weight: 600; + color: var(--af-text); + line-height: 1.6; + transition: color var(--af-speed); +} +.af-trio-item:hover .af-trio-title { color: var(--af-link); } +.af-trio-meta { display: flex; align-items: center; gap: var(--af-sp-2); margin-top: var(--af-sp-1); } +.af-news-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--af-sp-6); } + +/* 10. 头条图文(默认卡/回落栏目区块的区块头条) */ +.af-feat, +.af-feat-row { padding-bottom: var(--af-sp-4); border-bottom: 1px solid var(--af-border); } +.af-feat > a, +.af-feat-row > a { display: flex; gap: var(--af-sp-4); align-items: flex-start; } +.af-feat-cover { + flex: none; + display: block; + width: 200px; + aspect-ratio: 16 / 9; + border-radius: var(--af-radius); + overflow: hidden; + background: var(--af-tint); + border: 1px solid var(--af-border); +} +.af-feat-cover img { width: 100%; height: 100%; object-fit: cover; display: block; } +.af-feat-body { min-width: 0; flex: 1; display: flex; flex-direction: column; } +.af-feat-title { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: var(--af-fs-18); + font-weight: 700; + color: var(--af-primary-dark); + line-height: 1.5; + transition: color var(--af-speed); +} +.af-feat > a:hover .af-feat-title, +.af-feat-row > a:hover .af-feat-title { color: var(--af-link); } +.af-feat-summary { + color: var(--af-text-light); + font-size: var(--af-fs-13); + line-height: 1.7; + margin-top: var(--af-sp-2); + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.af-feat-meta { margin-top: auto; padding-top: var(--af-sp-2); display: flex; gap: var(--af-sp-3); align-items: center; } + +/* 11. 四列图片墙(image_wall / 校园映像 gallery):悬浮标题 */ +.af-wall { + list-style: none; + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: var(--af-sp-4); +} +.af-wall-item > a { + display: block; + position: relative; + border-radius: var(--af-radius); + overflow: hidden; + background: var(--af-tint); + border: 1px solid var(--af-border); + box-shadow: var(--af-shadow-sm); + transition: box-shadow var(--af-speed), transform var(--af-speed); +} +.af-wall-item > a:hover { box-shadow: var(--af-shadow-md) transform: translateY(-2px) } +.af-wall-item img { + width: 100%; + aspect-ratio: 3 / 2; + object-fit: cover; + display: block; + transition: transform .2s ease; +} +.af-wall-item > a:hover img { transform: scale(1.05); } +.af-wall-cap { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: var(--af-sp-2) var(--af-sp-3); + background: var(--af-scrim); + color: var(--af-on-dark); + font-size: var(--af-fs-13); + line-height: 1.5; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transform: translateY(100%); + transition: transform .2s ease; +} +.af-wall-item > a:hover .af-wall-cap, +.af-wall-item > a:focus-visible .af-wall-cap { transform: translateY(0); } + +/* 校园映像:居中标题 + 副题 */ +.af-gallery { text-align: left; } +.af-gallery-head { text-align: center; margin-bottom: var(--af-sp-6); } +.af-gallery-title { margin: 0 auto; } +.af-gallery-sub { + margin: var(--af-sp-2) 0 0; + color: var(--af-text-light); + font-size: var(--af-fs-13); + letter-spacing: .18em; +} + +/* 12. 要闻速递横条(ticker):墨绿底 + 金色分隔 */ +.af-ticker { background: var(--af-primary); color: var(--af-on-dark); } +.af-ticker-inner { + display: flex; + align-items: center; + gap: var(--af-sp-4); + padding-top: var(--af-sp-3); + padding-bottom: var(--af-sp-3); +} +.af-ticker-label { + flex: none; + display: inline-flex; + align-items: center; + gap: var(--af-sp-1); + font-size: var(--af-fs-15); + font-weight: 700; + letter-spacing: 2px; + padding-right: var(--af-sp-4); + border-right: 2px solid var(--af-accent); +} + +/* 中文防塌列:速递列表单行可收缩、条目不被压缩 */ +.af-ticker-list { + display: flex; + gap: var(--af-sp-8); + flex: 1; + min-width: 0; + overflow: hidden; + white-space: nowrap; +} +.af-ticker-list li { flex: none; min-width: 0; } +.af-ticker-item { + display: block; + flex: none; + max-width: 300px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--af-on-dark-soft); + font-size: var(--af-fs-14); + transition: color var(--af-speed); +} +.af-ticker-item:hover { color: var(--af-on-dark); } + +/* 13. 专题网站缩略卡(links):4 列卡片,绿标题条 + 金下杠 */ +.af-topic-grid { + list-style: none; + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: var(--af-sp-4); +} +.af-topic > a { + display: flex; + flex-direction: column; + background: var(--af-card-bg); + border: 1px solid var(--af-border); + border-radius: var(--af-radius); + overflow: hidden; + text-align: center; + box-shadow: var(--af-shadow-sm); + transition: box-shadow var(--af-speed), transform var(--af-speed), border-color var(--af-speed); +} +.af-topic > a:hover { + box-shadow: var(--af-shadow-md); + transform: translateY(-2px); + border-color: var(--af-primary-light); +} +.af-topic-bar { + height: 52px; + background: var(--af-primary); + border-bottom: 3px solid var(--af-accent); + display: flex; + align-items: center; + justify-content: center; + color: var(--af-on-dark-soft); +} +.af-topic-glyph { + display: inline-flex; + align-items: center; + justify-content: center; + color: var(--af-primary); + margin: var(--af-sp-4) auto var(--af-sp-2); + width: 44px; + height: 44px; + border-radius: 50%; + background: var(--af-tint); +} +.af-topic-name { + display: block; + padding: 0 var(--af-sp-3) var(--af-sp-4); + font-size: var(--af-fs-14); + color: var(--af-text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + transition: color var(--af-speed); +} +.af-topic > a:hover .af-topic-name { color: var(--af-link); } + +/* 14. 空态(与正常态同等用心,不塌陷) */ +.af-empty { + text-align: center; + padding: var(--af-sp-12) var(--af-sp-4); + color: var(--af-text-light); + font-size: var(--af-fs-15); +} +.af-empty p { margin: 0; } +.af-empty::before { + content: ""; + display: block; + width: 72px; + height: 54px; + margin: 0 auto var(--af-sp-4); + border: 2px solid var(--af-border); + border-radius: var(--af-radius); + background: + linear-gradient(var(--af-tint-strong) 60%, transparent 60%) 12px 10px / 40px 6px no-repeat, + linear-gradient(var(--af-tint-strong) 62%, transparent 62%) 12px 22px / 28px 6px no-repeat, + linear-gradient(var(--af-border) 100%, transparent 100%) 0 38px / 64px 2px no-repeat; +} +.af-empty-hint { font-size: var(--af-fs-13); margin-top: var(--af-sp-1); } + +/* 15. 首页回落:头条推荐(大标题左 + 密行右) */ +.af-headline-body { + display: grid; + grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); + gap: var(--af-sp-8); + align-items: start; +} +.af-headline-lead { padding-bottom: var(--af-sp-2); } +.af-lead-title { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: var(--af-fs-24); + font-weight: 700; + color: var(--af-primary-dark); + line-height: 1.5; + transition: color var(--af-speed); +} +.af-lead-title:hover { color: var(--af-link); } +.af-lead-meta { display: flex; gap: var(--af-sp-3); align-items: center; margin-top: var(--af-sp-2); } + +/* 首页回落:栏目区块两列 */ +.af-blocks { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--af-sp-6); + align-items: start; +} + +/* 16. 列表页 / 单页 / 详情页骨架:左侧栏 + 主卡 */ +.af-page { margin: var(--af-sp-8) auto var(--af-sp-12); } +.af-cols { display: flex; align-items: flex-start; gap: var(--af-sp-6); } +.af-cols .af-page-card { flex: 1; min-width: 0; } + +/* 左侧栏目导航(docs/11) */ +.af-side-nav { + flex: none; + width: 220px; + background: var(--af-card-bg); + border: 1px solid var(--af-border); + border-radius: var(--af-radius); + box-shadow: var(--af-shadow-sm); + overflow: hidden; +} +.af-side-nav-head { + background: var(--af-primary); + border-bottom: 3px solid var(--af-accent); + color: var(--af-on-dark); + font-size: var(--af-fs-18); + font-weight: 700; + text-align: center; + padding: var(--af-sp-3) var(--af-sp-2); + letter-spacing: 2px; +} +.af-side-nav-list { list-style: none; margin: 0; padding: var(--af-sp-1) 0; } +.af-side-nav-item + .af-side-nav-item { border-top: 1px dashed var(--af-border); } +.af-side-nav-item a { + display: block; + position: relative; + padding: var(--af-sp-3) var(--af-sp-4); + color: var(--af-text); + font-size: var(--af-fs-15); + transition: background var(--af-speed), color var(--af-speed); +} +.af-side-nav-item a::before { + content: ""; + position: absolute; + left: 0; + top: 8px; + bottom: 8px; + width: 3px; + border-radius: 0 2px 2px 0; + background: transparent; + transition: background var(--af-speed); +} +.af-side-nav-item a:hover { color: var(--af-primary); background: var(--af-tint); } +.af-side-nav-item.active a { background: var(--af-tint); color: var(--af-primary); font-weight: 600; } +.af-side-nav-item.active a::before { background: var(--af-accent); } + +/* 主卡 */ +.af-page-card { + background: var(--af-card-bg); + border: 1px solid var(--af-border); + border-radius: var(--af-radius); + box-shadow: var(--af-shadow-sm); + padding: var(--af-sp-8) var(--af-sp-6); +} + +/* 面包屑 */ +.af-crumb { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--af-sp-2); + margin-bottom: var(--af-sp-4); + color: var(--af-text-light); + font-size: var(--af-fs-13); +} +.af-crumb a { color: var(--af-text-light); } +.af-crumb a:hover { color: var(--af-link); } +.af-crumb-sep { color: var(--af-border); } +.af-crumb-current { color: var(--af-text); font-weight: 500; } + +/* 页标题:左绿杠 + 金短线 */ +.af-page-title { + position: relative; + font-size: var(--af-fs-24); + font-weight: 700; + padding: 0 0 var(--af-sp-3) var(--af-sp-3); + margin: 0 0 var(--af-sp-6); + border-bottom: 1px solid var(--af-border); +} +.af-page-title::before { + content: ""; + position: absolute; + left: 0; + top: 6px; + bottom: calc(var(--af-sp-3) + 6px); + width: 4px; + border-radius: 2px; + background: var(--af-primary); +} +.af-page-title::after { + content: ""; + position: absolute; + left: 0; + bottom: -2px; + width: 64px; + height: 3px; + background: var(--af-accent); +} + +/* 17. 列表页文章行:图文行 / 日期方块行(plain 形态切通栏行式) */ +.af-article-list { list-style: none; } +.af-article-list > li { padding: var(--af-sp-4) 0 border-bottom: 1px dashed var(--af-border) } +.af-article-list > li:last-child { border-bottom: none; } +.af-article-row { display: flex; gap: var(--af-sp-4); align-items: flex-start; } +.af-item-cover { + flex: none; + display: block; + width: 200px; + aspect-ratio: 16 / 9; + border-radius: var(--af-radius); + overflow: hidden; + background: var(--af-tint); + border: 1px solid var(--af-border); +} +.af-item-cover img { width: 100%; height: 100%; object-fit: cover; display: block; } +.af-item-body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: var(--af-sp-1); } +.af-item-title { font-size: var(--af-fs-18); font-weight: 600; line-height: 1.5; } +.af-item-title a { color: var(--af-text); } +.af-item-title a:hover { color: var(--af-link); } +.af-item-summary { + color: var(--af-text-light); + font-size: var(--af-fs-14); + line-height: 1.75; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.af-item-meta { display: flex; gap: var(--af-sp-3); align-items: center; margin-top: auto; } + +/* 无封面行:46px 日期方块 + 标题(date 形态,默认) */ +.af-article-line { + display: flex; + align-items: center; + gap: var(--af-sp-4); + padding: var(--af-sp-2) var(--af-sp-2); + margin: 0 calc(-1 * var(--af-sp-2)); + border-radius: var(--af-radius); + transition: background var(--af-speed); +} +.af-article-line:hover { background: var(--af-tint); } +.af-line-main { flex: 1; min-width: 0; } +.af-line-main .af-item-summary { margin-top: var(--af-sp-1); font-size: var(--af-fs-13); } +.af-line-side { flex: none; display: flex; align-items: center; gap: var(--af-sp-3); } + +/* plain 形态(themeParams.listLayout=plain):隐藏日期方块,日期右置 */ +.af-page--plainlist .af-article-line .af-date-chip { display: none; } +.af-line-date { display: none; color: var(--af-text-light); font-size: var(--af-fs-13); white-space: nowrap; } +.af-page--plainlist .af-article-line .af-line-date { display: inline; } + +/* 18. 分页 */ +.af-pagination { + display: flex; + gap: var(--af-sp-2); + justify-content: center; + align-items: center; + padding: var(--af-sp-8) 0 var(--af-sp-2); + flex-wrap: wrap; +} +.af-pagination a { + min-width: 36px; + text-align: center; + padding: var(--af-sp-1) var(--af-sp-3); + border: 1px solid var(--af-border); + background: var(--af-card-bg); + border-radius: var(--af-radius); + font-size: var(--af-fs-14); + color: var(--af-text-light); + transition: border-color var(--af-speed), color var(--af-speed), background var(--af-speed); +} +.af-pagination a:hover { + border-color: var(--af-primary); + color: var(--af-link); + background: var(--af-tint); +} +.af-pagination a.active { + background: var(--af-primary); + color: var(--af-on-dark); + border-color: var(--af-primary); + font-weight: 600; +} +.af-pagination a.disabled { opacity: .4; pointer-events: none; } + +/* 19. 详情 / 单页正文 */ +.af-article { display: block; } +.af-article-title { + margin: var(--af-sp-2) 0 var(--af-sp-4); + font-size: var(--af-fs-28); + font-weight: 700; + text-align: center; + line-height: 1.5; +} +.af-article-meta { + display: flex; + gap: var(--af-sp-4); + justify-content: center; + flex-wrap: wrap; + color: var(--af-text-light); + font-size: var(--af-fs-13); + padding: var(--af-sp-2) 0 var(--af-sp-4); + border-bottom: 1px solid var(--af-border); +} +.af-article-content { + line-height: 1.75; + font-size: var(--af-fs-16); + color: var(--af-text); + padding-top: var(--af-sp-6); + word-break: break-word; +} +.af-article-content p { text-indent: 2em; margin: 0 0 var(--af-sp-3); } +.af-article-content p:has(img), .af-article-content figure p { text-indent: 0; text-align: center; } +.af-article-content p > img:only-child { display: inline-block; } +.af-article-content img { height: auto; border-radius: var(--af-radius); } +.af-article-content figure { margin: var(--af-sp-4) auto; text-align: center; text-indent: 0; } +.af-article-content figcaption { font-size: var(--af-fs-13); color: var(--af-text-light); margin-top: var(--af-sp-2); } +.af-article-content h2, .af-article-content h3 { margin: var(--af-sp-6) 0 var(--af-sp-3); } +.af-article-content h2 { font-size: var(--af-fs-20); } +.af-article-content h3 { font-size: var(--af-fs-18); } +.af-article-content ul, .af-article-content ol { margin: 0 0 var(--af-sp-3) 2em; text-indent: 0; list-style: disc; } +.af-article-content ol { list-style: decimal; } +.af-article-content li { margin-bottom: var(--af-sp-1); } +.af-article-content blockquote { + margin: var(--af-sp-4) 0; + padding: var(--af-sp-3) var(--af-sp-4); + border-left: 4px solid var(--af-accent); + background: var(--af-tint); + border-radius: 0 var(--af-radius) var(--af-radius) 0; + color: var(--af-text-light); + text-indent: 0; +} +.af-article-content table { + border-collapse: collapse; + width: 100%; + margin: var(--af-sp-4) 0; + font-size: var(--af-fs-14); +} +.af-article-content table td, .af-article-content table th { border: 1px solid var(--af-border) padding: var(--af-sp-2) var(--af-sp-3) } +.af-article-content table th { background: var(--af-tint); font-weight: 600; } +.af-article-content table tbody tr:nth-child(even) { background: var(--af-tint); } +.af-article-content table tbody tr:hover { background: var(--af-tint-strong); } + +/* 上下篇 */ +.af-sibling { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--af-sp-4); + margin-top: var(--af-sp-8); + padding-top: var(--af-sp-6); + border-top: 1px solid var(--af-border); +} +.af-sibling a { + display: flex; + flex-direction: column; + gap: var(--af-sp-1); + padding: var(--af-sp-3) var(--af-sp-4); + background: var(--af-card-bg); + border: 1px solid var(--af-border); + border-radius: var(--af-radius); + box-shadow: var(--af-shadow-sm); + transition: border-color var(--af-speed), box-shadow var(--af-speed), transform var(--af-speed); +} +.af-sibling a:hover { + border-color: var(--af-primary-light); + box-shadow: var(--af-shadow-md); + transform: translateY(-1px); +} +.af-sibling a.next { text-align: right; } +.af-sibling .sib-label { font-size: var(--af-fs-13); color: var(--af-text-light); } +.af-sibling .sib-title { + font-size: var(--af-fs-14); + color: var(--af-text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.af-sibling a:hover .sib-title { color: var(--af-link); } +.af-sibling .sib-none { + display: flex; + flex-direction: column; + gap: var(--af-sp-1); + padding: var(--af-sp-3) var(--af-sp-4); + background: var(--af-tint); + border: 1px dashed var(--af-border); + border-radius: var(--af-radius); + color: var(--af-text-light); +} +.af-sibling .sib-none.next { text-align: right; } + +/* 20. 服务中心 / 事项指南(事项库 R2,docs/10 §3.4 契约的消费端样式) */ +.af-svc-page, .af-svc-guide { display: block; } + +/* 筛选区:三组 chip(对象/类别/部门),active 态标记当前勾选,URL 由后端预生成 */ +.af-svc-filters { + margin: var(--af-sp-4) 0 var(--af-sp-3); + padding: var(--af-sp-3) var(--af-sp-4); + background: var(--af-tint); + border-radius: var(--af-radius); +} +.af-svc-filter-group { display: flex; align-items: flex-start; gap: var(--af-sp-3); padding: var(--af-sp-2) 0; } +.af-svc-filter-group + .af-svc-filter-group { border-top: 1px dashed var(--af-border); } +.af-svc-filter-label { + flex: none; + width: 4.5em; + padding-top: var(--af-sp-1); + color: var(--af-text-light); + font-size: var(--af-fs-13); + font-weight: 600; +} +.af-svc-filter-options { display: flex; flex-wrap: wrap; gap: var(--af-sp-2); } +.af-svc-chip { + display: inline-flex; + align-items: center; + gap: var(--af-sp-1); + padding: 2px var(--af-sp-3); + background: var(--af-card-bg); + border: 1px solid var(--af-border); + border-radius: 999px; + font-size: var(--af-fs-13); + color: var(--af-text); + transition: border-color var(--af-speed), color var(--af-speed); +} +.af-svc-chip:hover { border-color: var(--af-primary); color: var(--af-link); } +.af-svc-chip em { font-style: normal; color: var(--af-text-light); font-size: var(--af-fs-12); } +.af-svc-chip.active { background: var(--af-primary); border-color: var(--af-primary); color: var(--af-on-dark); } +.af-svc-chip.active em { color: var(--af-on-dark-soft); } + +/* 工具条:关键词搜索 + 清除筛选 */ +.af-svc-toolbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--af-sp-3); + margin-bottom: var(--af-sp-4); +} +.af-svc-search { display: flex; } +.af-svc-search input { + width: 260px; + padding: 7px var(--af-sp-3); + border: 1px solid var(--af-border); + border-right: none; + border-radius: var(--af-radius) 0 0 var(--af-radius); + font-size: var(--af-fs-14); + font-family: inherit; + color: var(--af-text); + outline: none; + transition: border-color var(--af-speed); +} +.af-svc-search input:focus { border-color: var(--af-primary); } +.af-svc-search button { + padding: 7px var(--af-sp-4); + border: none; + border-radius: 0 var(--af-radius) var(--af-radius) 0; + background: var(--af-primary); + color: var(--af-on-dark); + cursor: pointer; + font-size: var(--af-fs-14); + transition: background var(--af-speed); +} +.af-svc-search button:hover { background: var(--af-primary-dark); } +.af-svc-clear { font-size: var(--af-fs-13); color: var(--af-text-light); } +.af-svc-clear:hover { color: var(--af-link); } + +/* 事项列表:卡片行(有封面出图,无封面纯文字,与文章列表同哲学不造占位图) */ +.af-svc-list { list-style: none; } +.af-svc-list li { border-bottom: 1px dashed var(--af-border); } +.af-svc-list li:last-child { border-bottom: none; } +.af-svc-item { display: flex; gap: var(--af-sp-4); padding: var(--af-sp-4) var(--af-sp-2); } +.af-svc-list li:hover { background: var(--af-tint); } +.af-svc-item-cover { + flex: none; + width: 96px; + height: 64px; + border-radius: var(--af-radius); + overflow: hidden; + border: 1px solid var(--af-border); + background: var(--af-tint); +} +.af-svc-item-cover img { width: 100%; height: 100%; object-fit: cover; display: block; } +.af-svc-item-body { display: flex; flex-direction: column; gap: var(--af-sp-1); min-width: 0; } +.af-svc-item-title { display: flex; align-items: center; gap: var(--af-sp-2); flex-wrap: wrap; } +.af-svc-item-name { font-size: var(--af-fs-16); font-weight: 600; color: var(--af-text); } +.af-svc-item:hover .af-svc-item-name { color: var(--af-link); } +.af-svc-tag { + flex: none; + padding: 1px var(--af-sp-2); + border-radius: var(--af-radius); + background: var(--af-tint); + border: 1px solid var(--af-border); + color: var(--af-text-light); + font-size: var(--af-fs-12); + line-height: 1.6; +} +.af-svc-tag.online { background: var(--af-primary); border-color: var(--af-primary); color: var(--af-on-dark); } +.af-svc-item-summary { + color: var(--af-text-light); + font-size: var(--af-fs-14); + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.af-svc-item-meta { display: flex; gap: var(--af-sp-4); color: var(--af-text-light); font-size: var(--af-fs-13); } + +/* 指南页 */ +.af-svc-guide-body { display: block; } +.af-svc-apply { display: flex; align-items: center; gap: var(--af-sp-3); margin: var(--af-sp-4) 0; } +.af-svc-apply-btn { + display: inline-block; + padding: var(--af-sp-2) var(--af-sp-8); + border-radius: var(--af-radius); + background: var(--af-primary); + color: var(--af-on-dark); + font-size: var(--af-fs-16); + font-weight: 600; + transition: background var(--af-speed); +} +.af-svc-apply-btn:hover { background: var(--af-primary-dark); color: var(--af-on-dark); } +.af-svc-apply-hint { color: var(--af-text-light); font-size: var(--af-fs-13); } +.af-svc-summary { + padding: var(--af-sp-3) var(--af-sp-4); + background: var(--af-tint); + border-left: 3px solid var(--af-primary); + border-radius: 0 var(--af-radius) var(--af-radius) 0; + color: var(--af-text-light); +} +.af-svc-info { + width: 100%; + margin: var(--af-sp-4) 0; + border-collapse: collapse; + font-size: var(--af-fs-14); +} +.af-svc-info th, .af-svc-info td { + border: 1px solid var(--af-border); + padding: var(--af-sp-2) var(--af-sp-4); + text-align: left; + vertical-align: top; +} +.af-svc-info th { + width: 7em; + background: var(--af-tint); + color: var(--af-text-light); + font-weight: 600; + white-space: nowrap; +} +.af-svc-section { margin: var(--af-sp-6) 0; } +.af-svc-section h2 { + font-size: var(--af-fs-18); + padding-bottom: var(--af-sp-2); + border-bottom: 2px solid var(--af-primary); + margin-bottom: var(--af-sp-3); +} +.af-svc-attachments ul { list-style: none; } +.af-svc-attachments li { + display: flex; + align-items: center; + gap: var(--af-sp-3); + padding: var(--af-sp-2) 0; + border-bottom: 1px dashed var(--af-border); +} +.af-svc-attachments li:last-child { border-bottom: none; } +.af-svc-attachments a { color: var(--af-link); } +.af-svc-attachments a:hover { text-decoration: underline; } +.af-svc-att-size { color: var(--af-text-light); font-size: var(--af-fs-13); } +.af-svc-links { + display: flex; + gap: var(--af-sp-3); + margin: var(--af-sp-6) 0 0; + padding-top: var(--af-sp-4); + border-top: 1px dashed var(--af-border); +} +.af-svc-links a { + padding: var(--af-sp-1) var(--af-sp-4); + border: 1px solid var(--af-border); + border-radius: var(--af-radius); + font-size: var(--af-fs-13); + color: var(--af-text-light); + transition: border-color var(--af-speed), color var(--af-speed); +} +.af-svc-links a:hover { border-color: var(--af-primary); color: var(--af-link); } + +/* 相关服务侧区 */ +.af-svc-related { margin-top: var(--af-sp-8); } +.af-svc-related-list { list-style: none; margin-top: var(--af-sp-3); } +.af-svc-related-list li { border-bottom: 1px dashed var(--af-border); } +.af-svc-related-list li:last-child { border-bottom: none; } +.af-svc-related-list a { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--af-sp-3); + padding: var(--af-sp-3) var(--af-sp-2); +} +.af-svc-related-list li:hover { background: var(--af-tint); } +.af-svc-related-name { + font-size: var(--af-fs-15); + color: var(--af-text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.af-svc-related-list a:hover .af-svc-related-name { color: var(--af-link); } +.af-svc-related-meta { display: flex; align-items: center; gap: var(--af-sp-2); flex: none; } +.af-svc-related-meta > span:not(.af-svc-tag) { color: var(--af-text-light); font-size: var(--af-fs-13); } + +/* 21. 页脚:墨绿多列(品牌+社媒 / 地址联系 / 二维码)+ 浅绿友链带 + 更深底条 */ +.af-footer { margin-top: var(--af-sp-12); background: var(--af-footer-bg); color: var(--af-on-dark-soft); } +.af-footer-main { padding: var(--af-sp-12) 0 var(--af-sp-8); } +.af-footer-cols { + display: flex; + flex-wrap: wrap; + gap: var(--af-sp-12); + align-items: flex-start; + justify-content: space-between; +} +.af-footer-brand { max-width: 380px; min-width: 240px; } +.af-footer-logo-row { display: flex; align-items: center; gap: var(--af-sp-3); margin-bottom: var(--af-sp-4); } +.af-footer-logo { height: 52px; width: auto; } +.af-footer-site { font-size: var(--af-fs-20); font-weight: 700; color: var(--af-on-dark); letter-spacing: 1px; } + +/* 社媒图标阵列 */ +.af-social { display: flex; gap: var(--af-sp-3); } +.af-social-icon { + width: 36px; + height: 36px; + border: 1px solid var(--af-on-dark-faint); + border-radius: var(--af-radius); + display: inline-flex; + align-items: center; + justify-content: center; + color: var(--af-on-dark-soft); + transition: background var(--af-speed), border-color var(--af-speed), color var(--af-speed); +} +.af-social-icon:hover { background: var(--af-primary-light); border-color: var(--af-primary-light); color: var(--af-on-dark); } + +/* 地址 / 联系 / 版权 / 备案 */ +.af-footer-info { min-width: 260px; font-size: var(--af-fs-13); line-height: 2; } +.af-footer-info p { margin: 0; } +.af-footer-addr { list-style: none; margin: 0 0 var(--af-sp-1); } +.af-footer-addr li { position: relative; padding-left: var(--af-sp-3); } +.af-footer-addr li::before { + content: ""; + position: absolute; + left: 0; + top: 12px; + width: 5px; + height: 5px; + background: var(--af-accent); + border-radius: 1px; +} + +/* 二维码位 */ +.af-footer-qr { display: flex; gap: var(--af-sp-6); } +.af-qr { margin: 0; text-align: center; } +.af-qr img { + width: 96px; + height: 96px; + padding: 6px; + background: var(--af-card-bg); + border-radius: var(--af-radius); + display: block; +} +.af-qr figcaption { margin-top: var(--af-sp-2); font-size: var(--af-fs-12); color: var(--af-on-dark-faint); } + +/* 友链区(浅绿带;无分组的站整段不渲染) */ +.af-footer-links { + background: var(--af-tint); + border-top: 1px solid var(--af-border); + border-bottom: 1px solid var(--af-border); + color: var(--af-text); +} +.af-footer-links-inner { padding: var(--af-sp-4) var(--af-gutter); } +.af-links-group { + display: flex; + flex-wrap: wrap; + gap: var(--af-sp-2) var(--af-sp-4); + align-items: baseline; + font-size: var(--af-fs-13); +} +.af-links-group + .af-links-group { margin-top: var(--af-sp-2); } +.af-group-name { + font-weight: 700; + color: var(--af-primary-dark); + margin-right: var(--af-sp-2); + position: relative; + padding-left: var(--af-sp-3); +} +.af-group-name::before { + content: ""; + position: absolute; + left: 0; + top: 50%; + width: 4px; + height: 4px; + margin-top: -2px; + background: var(--af-accent); + border-radius: 50%; +} +.af-links-row { margin: 0; display: inline; } +.af-links-row a { color: var(--af-text-light); } +.af-links-row a:hover { color: var(--af-link); } + +/* B4 友链 Logo:与名称并排小图(高度 ~20px,垂直居中;过宽截断不撑破页脚) */ +.af-link-logo { + height: 20px; + width: auto; + max-width: 64px; + object-fit: contain; + vertical-align: middle; + margin-right: var(--af-sp-1); + border-radius: 2px; +} + +/* 底条(更深墨绿) */ +.af-footer-bottom { background: var(--af-primary-deep); } +.af-footer-bottom-inner { + padding: var(--af-sp-3) var(--af-gutter); + text-align: center; + font-size: var(--af-fs-13); + color: var(--af-on-dark-faint); +} +.af-footer-bottom-inner p { margin: var(--af-sp-1) 0; } + +/* 22. 响应式(≤1024 两栏收敛;≤768 单列 + 导航折叠) */ +@media (max-width: 1024px) { + .af-headline-body { grid-template-columns: minmax(0, 1fr); } + .af-blocks { grid-template-columns: minmax(0, 1fr); } + .af-cols { flex-direction: column; } + .af-side-nav { width: 100%; } + .af-side-nav-list { display: flex; overflow-x: auto; -webkit-overflow-scrolling: touch; } + .af-side-nav-item { flex: none; } + .af-side-nav-item + .af-side-nav-item { border-top: none; border-left: 1px dashed var(--af-border); } + .af-side-nav-item a { white-space: nowrap; padding: var(--af-sp-3) var(--af-sp-4); } + .af-footer-cols { gap: var(--af-sp-8); } +} + +@media (max-width: 768px) { + :root { --af-gutter: 16px; } + + /* 白色页头折叠:品牌行纵排,工具行换行 */ + .af-head-inner { + flex-direction: column; + align-items: stretch; + gap: var(--af-sp-3); + padding: var(--af-sp-3) var(--af-gutter); + } + .af-sitename { font-size: var(--af-fs-20); } + .af-logo { height: 44px; } + .af-head-side { flex-wrap: wrap; justify-content: space-between; } + .af-search { flex: 1; } + .af-search input { flex: 1; width: auto; } + + /* 主导航:横向滚动 + 子菜单静态平铺(触屏无 hover,不做浮层) */ + .af-nav ul { overflow-x: auto; flex-wrap: nowrap; } + .af-nav li a { padding: var(--af-sp-3) var(--af-sp-4); white-space: nowrap; font-size: var(--af-fs-15); } + .af-nav ul.af-sub-nav { + display: block; + position: static; + border: none; + box-shadow: none; + background: var(--af-primary-dark); + border-radius: 0; + min-width: 0; + padding: 0; + } + .af-nav .af-sub-nav li a { color: var(--af-on-dark-soft); padding: var(--af-sp-2) var(--af-sp-4) var(--af-sp-2) var(--af-sp-8); } + .af-nav .af-sub-nav li a:hover { background: var(--af-primary-deep); color: var(--af-on-dark); } + .af-nav .af-sub-nav li.active a { color: var(--af-on-dark); } + + /* 轮播:4:3 切图,隐藏箭头 */ + .af-banner-slides { aspect-ratio: 4 / 3; max-height: none; } + .af-banner-title { font-size: var(--af-fs-15); padding: var(--af-sp-2) var(--af-sp-3); bottom: var(--af-sp-3); } + .af-banner-arrow { display: none; } + + /* 首页:全部单列 */ + .af-trio { grid-template-columns: minmax(0, 1fr); } + .af-block-list--two { grid-template-columns: minmax(0, 1fr); gap: 0; } + .af-wall { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .af-topic-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .af-section { margin: var(--af-sp-6) 0; } + .af-block, .af-page-card { padding: var(--af-sp-4) var(--af-sp-3); } + .af-feat > a, .af-feat-row > a { flex-direction: column; } + .af-feat-cover { width: 100%; } + + /* 列表页:图文行纵排;日期方块行窄屏保持方块形态 */ + .af-article-row { flex-direction: column; } + .af-item-cover { width: 100%; } + .af-article-line { align-items: flex-start; } + .af-line-side { flex-direction: column; align-items: flex-end; gap: var(--af-sp-1); } + .af-sibling { grid-template-columns: minmax(0, 1fr); } + .af-ticker-item { max-width: 180px; } + .af-footer-cols { flex-direction: column; gap: var(--af-sp-6); } + .af-footer-info { min-width: 0; } + .af-svc-toolbar { flex-direction: column; align-items: stretch; } + .af-svc-search input { width: auto; flex: 1; } + .af-svc-filter-group { flex-direction: column; gap: var(--af-sp-1); } + .af-svc-filter-label { width: auto; padding-top: 0; } + .af-svc-item { flex-direction: column; gap: var(--af-sp-2); } + .af-svc-item-cover { width: 100%; height: 120px; } + .af-svc-info th { width: 5.5em; } + .af-svc-related-list a { flex-direction: column; align-items: flex-start; } +} + +/* 23. 打印样式(公告高频打印场景) */ +@media print { + .af-header, .af-head, .af-nav, .af-banner, .af-footer-links, .af-footer, + .af-sibling, .af-pagination, .af-skip-link, .af-search, .af-colleges, + .af-side-nav, .af-svc-apply, .af-svc-filters, .af-svc-toolbar, .af-svc-related { display: none !important; } + body { background: #ffffff; color: #000000; font-size: 12pt; } + .af-page-card { border: none; box-shadow: none; padding: 0; margin: 0; max-width: 100%; } + .af-article-title { font-size: 20pt; } + .af-article-content { font-size: 11.5pt; line-height: 1.75; } + .af-article-content p { text-indent: 2em; } + a { color: inherit; } +} \ No newline at end of file diff --git a/src/main/resources/templates/themes/agri-forest/assets/favicon.png b/src/main/resources/templates/themes/agri-forest/assets/favicon.png new file mode 100644 index 0000000..822653c Binary files /dev/null and b/src/main/resources/templates/themes/agri-forest/assets/favicon.png differ diff --git a/src/main/resources/templates/themes/agri-forest/assets/js/main.js b/src/main/resources/templates/themes/agri-forest/assets/js/main.js new file mode 100644 index 0000000..d3482ae --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/assets/js/main.js @@ -0,0 +1,87 @@ +/* agri-forest 皮肤包脚本:页头日期 + 首页轮播(自动播放/圆点/箭头/悬停暂停/键盘),无任何外部依赖 */ +(function () { + /* 页头工具行日期(本地时间,YYYY年M月D日 星期X) */ + var dateEl = document.getElementById('siteDate'); + if (dateEl) { + var now = new Date(); + var week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()]; + dateEl.textContent = now.getFullYear() + '年' + (now.getMonth() + 1) + '月' + + now.getDate() + '日 星期' + week; + } + + /* 轮播 */ + var root = document.querySelector('.af-banner'); + var slides = document.querySelectorAll('.af-banner-slide'); + var dots = document.querySelectorAll('.af-banner-dots button'); + var prevBtn = document.querySelector('.af-banner-arrow.prev'); + var nextBtn = document.querySelector('.af-banner-arrow.next'); + if (!slides.length || !root) { + return; + } + var current = 0; + var timer = null; + var INTERVAL = 5000; + + function show(index) { + slides[current].classList.remove('active'); + if (dots[current]) { + dots[current].classList.remove('active'); + } + current = (index + slides.length) % slides.length; + slides[current].classList.add('active'); + if (dots[current]) { + dots[current].classList.add('active'); + } + } + + function start() { + stop(); + if (slides.length > 1) { + timer = window.setInterval(function () { + show(current + 1); + }, INTERVAL); + } + } + + function stop() { + if (timer) { + window.clearInterval(timer); + timer = null; + } + } + + dots.forEach(function (dot, index) { + dot.addEventListener('click', function () { + show(index); + start(); + }); + }); + if (prevBtn) { + prevBtn.addEventListener('click', function () { + show(current - 1); + start(); + }); + } + if (nextBtn) { + nextBtn.addEventListener('click', function () { + show(current + 1); + start(); + }); + } + root.addEventListener('mouseenter', stop); + root.addEventListener('mouseleave', start); + root.addEventListener('focusin', stop); + root.addEventListener('focusout', start); + root.setAttribute('tabindex', '-1'); + root.addEventListener('keydown', function (e) { + if (e.key === 'ArrowLeft') { + show(current - 1); + start(); + } else if (e.key === 'ArrowRight') { + show(current + 1); + start(); + } + }); + + start(); +})(); diff --git a/src/main/resources/templates/themes/agri-forest/assets/screenshot.png b/src/main/resources/templates/themes/agri-forest/assets/screenshot.png new file mode 100644 index 0000000..6dc1772 Binary files /dev/null and b/src/main/resources/templates/themes/agri-forest/assets/screenshot.png differ diff --git a/src/main/resources/templates/themes/agri-forest/detail.html b/src/main/resources/templates/themes/agri-forest/detail.html new file mode 100644 index 0000000..b210470 --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/detail.html @@ -0,0 +1,76 @@ + + + + +
+ +
+
+ + + +
+ + +
+

文章标题

+ + +
正文
+
+ + +
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/agri-forest/fragments/footer.html b/src/main/resources/templates/themes/agri-forest/fragments/footer.html new file mode 100644 index 0000000..27596a2 --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/fragments/footer.html @@ -0,0 +1,92 @@ + + + + + diff --git a/src/main/resources/templates/themes/agri-forest/fragments/head.html b/src/main/resources/templates/themes/agri-forest/fragments/head.html new file mode 100644 index 0000000..7739009 --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/fragments/head.html @@ -0,0 +1,24 @@ + + + + + + + 页面标题 + + + + + + + + + + + + + + + diff --git a/src/main/resources/templates/themes/agri-forest/fragments/header.html b/src/main/resources/templates/themes/agri-forest/fragments/header.html new file mode 100644 index 0000000..34a5721 --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/fragments/header.html @@ -0,0 +1,66 @@ + + + +
+ 跳到主要内容 + + +
+
+ +
+ + 站点名称 +
+ +
+ 加载日期… +
+ + 校园直通车 + + + +
+ +
+
+
+ + + +
+ diff --git a/src/main/resources/templates/themes/agri-forest/fragments/home-blocks.html b/src/main/resources/templates/themes/agri-forest/fragments/home-blocks.html new file mode 100644 index 0000000..612697d --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/fragments/home-blocks.html @@ -0,0 +1,257 @@ + + + + +
+
+
+
+
+ +

学校要闻

+
+ 更多 > +
+ + +
+
+
+
+ + +
+
+
+
+ +

学术动态

+
+ 更多 > +
+ + +
+
+
+
+ + +
+
+
+
+ +

通知公告

+
+ 更多 > +
+ + +
+
+
+
+ + +
+
+
+ +

图片新闻

+
+ 更多 > +
+ + +
+
+
+ + +
+
+
+
+ +

栏目名

+
+ 更多 > +
+ + + +
+
+
+
+ + +
+
+ + + 要闻速递 + + +
+
+ + + + + +
+
+
+ +

专题网站

+
+
+ +
+ + +
+

栏目暂无内容

+

内容发布后将在此展示

+
+ diff --git a/src/main/resources/templates/themes/agri-forest/guide.html b/src/main/resources/templates/themes/agri-forest/guide.html new file mode 100644 index 0000000..aa96960 --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/guide.html @@ -0,0 +1,133 @@ + + + + +
+ + +
+
+ + + +
+

事项服务暂时不可用,请稍后再试

+

事项数据服务暂不可达,稍后刷新即可恢复

+
+ +
+

事项名称

+ + + +
+ 我要办理 + 进入服务大厅在线办理 +
+ +

简介

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事项基本信息
服务对象服务对象
事项类别事项类别
办理地点办理地点
办理时限办理时限
承诺时限承诺时限
咨询电话咨询电话
监督投诉监督投诉电话
+ +
+

办理流程

+
办理流程
+
+
+

所需材料

+
所需材料
+
+
+

注意事项

+
注意事项
+
+ +
+

相关材料下载

+ +
+ + +
+ + +
+
+ + + + + diff --git a/src/main/resources/templates/themes/agri-forest/home.html b/src/main/resources/templates/themes/agri-forest/home.html new file mode 100644 index 0000000..7b54275 --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/home.html @@ -0,0 +1,169 @@ + + + + +
+ +
+ +
+ + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

图片新闻

+
+
+ +
+ + +
+
+
+
+
+ +

头条推荐

+
+
+
+
+ 头条标题 +
+ 置顶 + +
+
+ +
+
+
+
+ + +
+
+
+
+
+ +

栏目名

+
+ 更多 > +
+ +
+

栏目暂无内容

+

内容发布后将在此展示

+
+
+
+
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/agri-forest/list.html b/src/main/resources/templates/themes/agri-forest/list.html new file mode 100644 index 0000000..6f4c7e7 --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/list.html @@ -0,0 +1,111 @@ + + + + +
+ + +
+
+ + + +
+ + + +

栏目名

+

搜索词

+ +
    + +
  • +
    + + + +
    + +

    摘要

    +
    + + 置顶 +
    +
    +
    +
    + + 01 + 2026-01 + +
    + 文章标题 +

    摘要

    +
    +
    + 置顶 + +
    +
    +
  • +
+
+

未找到相关内容

+

栏目暂无内容

+

换个关键词试试

+

内容发布后将在此展示

+
+ + + +
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/agri-forest/service.html b/src/main/resources/templates/themes/agri-forest/service.html new file mode 100644 index 0000000..6d3d3eb --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/service.html @@ -0,0 +1,111 @@ + + + + +
+ + +
+
+ + +

服务中心

+ + +
+

事项服务暂时不可用,请稍后再试

+

事项数据服务暂不可达,稍后刷新即可恢复

+
+ +
+
+ 服务对象 + +
+
+ 事项类别 + +
+
+ 服务部门 + +
+
+ +
+ + 清除筛选 +
+ + +
+

未找到符合条件的服务事项

+

服务中心暂未上架事项

+

换个筛选条件或关键词试试

+

事项发布后将在此展示

+
+ + + +
+
+ + + + + diff --git a/src/main/resources/templates/themes/agri-forest/single.html b/src/main/resources/templates/themes/agri-forest/single.html new file mode 100644 index 0000000..4694399 --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/single.html @@ -0,0 +1,50 @@ + + + + +
+ +
+
+ + + +
+ + +
+

栏目名

+ +
单页内容
+
+

页面暂无内容

+

内容编辑后将在此展示

+
+
+
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/agri-forest/theme.json b/src/main/resources/templates/themes/agri-forest/theme.json new file mode 100644 index 0000000..454845f --- /dev/null +++ b/src/main/resources/templates/themes/agri-forest/theme.json @@ -0,0 +1,30 @@ +{ + "specVersion": 1, + "name": "agri-forest", + "title": "农林绿(agri-forest)", + "version": "1.0.0", + "author": "yunhai", + "description": "墨绿+麦穗金的农林院校风(设计语言参考信阳农林学院官网)。", + "screenshot": "assets/screenshot.png", + "bannerSize": "1920x560", + "params": [ + { "key": "primary", "cssVar": "--af-primary", "label": "主色(墨绿)", "type": "color", "default": "#1C6E19" }, + { "key": "primaryDark", "cssVar": "--af-primary-dark", "label": "主色加深", "type": "color", "default": "#14510F" }, + { "key": "primaryLight", "cssVar": "--af-primary-light","label": "主色提亮", "type": "color", "default": "#3FA43A" }, + { "key": "accent", "cssVar": "--af-accent", "label": "麦穗金", "type": "color", "default": "#C8A45C" }, + { "key": "navBg", "cssVar": "--af-nav-bg", "label": "主导航底色", "type": "color", "default": "#1C6E19" }, + { "key": "footerBg", "cssVar": "--af-footer-bg", "label": "页脚底色", "type": "color", "default": "#14510F" }, + { "key": "text", "cssVar": "--af-text", "label": "正文文字色", "type": "color", "default": "#2A3327" }, + { "key": "textLight", "cssVar": "--af-text-light", "label": "次要文字色", "type": "color", "default": "#6C7A67" }, + { "key": "bg", "cssVar": "--af-bg", "label": "页面底色", "type": "color", "default": "#F5F8F3" }, + { "key": "cardBg", "cssVar": "--af-card-bg", "label": "卡片底色", "type": "color", "default": "#FFFFFF" }, + { "key": "border", "cssVar": "--af-border", "label": "边框色", "type": "color", "default": "#DDE8DA" }, + { "key": "linkGreen", "cssVar": "--af-link", "label": "链接绿", "type": "color", "default": "#277428" }, + { "key": "listLayout", "label": "列表页形态", "type": "select", "default": "date", + "options": [ + { "value": "date", "label": "日期方块" }, + { "value": "plain", "label": "通栏行式" } + ] + } + ] +} diff --git a/src/main/resources/templates/themes/jade-normal/README.md b/src/main/resources/templates/themes/jade-normal/README.md new file mode 100644 index 0000000..a48d41b --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/README.md @@ -0,0 +1,54 @@ +# jade-normal(师大青) + +师范院校风皮肤包:以 `default` 为基座派生,设计语言参考信阳师范大学官网(www.xynu.edu.cn,仅学语言不复制实现)—— +翡翠青主色 + 暖橙点缀,人文师范气质、温润轻盈。 +配了 `home_layout` 的站点,首页正文区块由本主题 `fragments/home-blocks.html` 渲染——派生包不自带区块形态时, +正文会落到 `themes/common` 的通用骨架,换肤就只剩页头页脚(线上事故根因,见《审计验收清单-20260919》)。 + +## 风格定位 + +- 主色翡翠青 `#008D3F` / 加深 `#04682E` / 提亮 `#35B371`,点缀暖橙 `#F18D00`(日期徽标数字、强调角标、"我要办理"按钮)。 +- 页头三段式:深青顶条(日期+专业院系)→ 白色品牌行(校徽+校名居左,服务中心入口+圆角搜索居右)→ + 翡翠青通栏主导航(白字,当前/悬停项 primaryLight 底条,≤768px checkbox 纯 CSS 折叠)。 +- banner 标题用青色底条(非渐变遮罩);列表主打"46px 橙色日期徽标(日大号+年月小号)"语言。 +- 圆角 8/10px、正文行高 1.8、hover 过渡 0.2s ease;无渐变堆砌、无玻璃拟态、无粉紫。 +- 页脚:薄荷友链带 + 翡翠深青 `#04682E` 多列(品牌+社媒图标 / 多校区地址+联系版权备案 / 二维码)+ 深色底条。 +- 全部 12 个颜色参数可在站点 theme_params 微调,另有 1 个 select 布局参数(见下)。 + +## 参数取值建议(theme_params) + +| key | 默认 | 说明 | +| -- | -- | -- | +| `primary` | `#008D3F` | 翡翠青主色(导航/标题/链接) | +| `primaryDark` | `#04682E` | 加深(顶条/页脚/hover) | +| `primaryLight` | `#35B371` | 提亮(当前栏目底条/描边) | +| `accent` | `#F18D00` | 暖橙点缀(日期徽标/角标) | +| `navBg` | `#008D3F` | 主导航条底色(可与主色分离调) | +| `footerBg` | `#04682E` | 页脚主底色 | +| `text` / `textLight` | `#2E3A33` / `#6E7F75` | 正文/次要文字 | +| `bg` / `cardBg` / `border` | `#F4FAF6` / `#FFFFFF` / `#DFEEE5` | 页面底/卡片/边框 | +| `mintBg` | `#E7F6EE` | 薄荷底(背景带/友链区/hover 面) | +| `listLayout` | `badge` | 列表页形态:`badge` 橙色日期徽标行 / `plain` 通栏行式(日期右置) | + +## 首页区块形态(布局模式与回落模式同构) + +| homeStyle | 呈现 | 类名 | +| -- | -- | -- | +| `news_grid` | 校园要闻:左图文头条 + 右橙色日期徽标行 + 四图横排;区块背景可取站点 `news_bg_image` | `jn-split` / `jn-date-badge` / `jn-shots` | +| `compact` | 通知公告:46px「日大号+年月小号」橙色徽标行 | `jn-row-badge` | +| `media_focus` | 学术交流/媒体聚焦:来源徽标 + 双列密行 | `jn-src` / `jn-block-list--two` | +| `image_wall` | 教学科研:四列图片墙,青底标题条,hover 抬图 | `jn-wall` | +| (空/未知) | 整宽区块卡:头条 + 行式列表 | `jn-block--flow` | +| `ticker` | 翡翠青要闻速递横条(单行不换行、超长省略,中文不塌列) | `jn-ticker*` | +| `gallery` | 校园映像四图墙 + 「融媒师大」图标行(微信/微博/抖音/B站走 `social_*` 配置,校报/广播台常驻) | `jn-gallery` / `jn-fusion` | +| `links` | 快捷通道图标宫格(6 列内联 SVG 图标卡,青色描边 hover 青底白字) | `jn-quick` | + +## 契约要点 + +- 结构类前缀 `jn-`,CSS 变量前缀 `--jn-`;`:root` 把 `--jn-*` 别名到皮肤契约变量(`--primary`/`--text`/`--card-bg`/`--border`…), + 使 `themes/common` 兜底骨架也能跟随本皮肤着色。 +- 空态文案「栏目暂无内容」只在 `block.items` 为空时出现;守卫必须写在 `th:block` 外层—— + `th:replace`(优先级 100)先于 `th:if`(300)求值,写在同一标签上等于没写。 +- 页脚消费 docs/12 增强键:`footer_addresses`(经 `site.footerAddressLines` 逐行渲染)、`qr_wechat`/`qr_weibo`、 + `social_wechat`/`social_weibo`/`social_douyin`/`social_bilibili`——均有值才渲染,空站点优雅降级。 +- 回归防线:`ThemeContractIT`(7 条路由);带 home_layout 的站点首页不落通用骨架(本包 home.html 分发到自家 fragment)。 diff --git a/src/main/resources/templates/themes/jade-normal/assets/css/main.css b/src/main/resources/templates/themes/jade-normal/assets/css/main.css new file mode 100644 index 0000000..99cd935 --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/assets/css/main.css @@ -0,0 +1,1949 @@ +/* ===================================================================== + jade-normal · 师大青(基座 default,设计语言参考信阳师范大学官网 xynu.edu.cn) + 设计语言:白色页头(校徽+校名居左/搜索与工具居右) + 翡翠青通栏主导航(白字/当前项 + primaryLight 底条) + 通栏大图 banner(青色底条标题) + 橙色日期徽标列表 + + 快捷通道图标宫格 + 四图横排 + 融媒图标行 + 翡翠深青多列页脚。 + 气质:人文师范、温润轻盈——圆角 8/10px、正文行高 1.8、无渐变堆砌、无玻璃拟态。 + 色彩令牌全部走 CSS 变量(--jn-*),theme.json color 参数经 :root 覆盖真实生效; + 品牌衍生色(悬停/阴影/深底文字)一律由变量或中性黑白透明度派生,不另立色值。 + ===================================================================== */ + +/* --------------------------------------------------------------------- + 1. 设计令牌(与 theme.json params 一一对应,禁止出现未消费的声明) + --------------------------------------------------------------------- */ +:root { + /* —— 品牌色板(theme.json 12 个 color 参数一一对应)—— */ + --jn-primary: #008D3F; /* 主色:翡翠青——导航/标题/链接/强调 */ + --jn-primary-dark: #04682E; /* 主色加深:顶条/页脚/hover 深端 */ + --jn-primary-light: #35B371; /* 主色提亮:当前栏目底条/亮线条/hover 链接 */ + --jn-accent: #F18D00; /* 点缀暖橙:日期徽标/强调数字/角标 */ + --jn-nav-bg: #008D3F; /* 主导航条底色(翡翠青通栏) */ + --jn-footer-bg: #04682E; /* 页脚主底(翡翠深青) */ + --jn-text: #2E3A33; /* 正文(青灰墨) */ + --jn-text-light: #6E7F75; /* 次要文字(青灰) */ + --jn-bg: #F4FAF6; /* 页面底色(薄荷白) */ + --jn-card-bg: #FFFFFF; /* 卡片底 */ + --jn-border: #DFEEE5; /* 边框/分隔线(浅青灰) */ + --jn-mint-bg: #E7F6EE; /* 薄荷底:背景带/友链区/hover 面 */ + + /* —— 深底文字(顶条/导航/页脚;透明度而非新色值,随底色参数自适应)—— */ + --jn-ink: #ffffff; /* 深底主文字 */ + --jn-ink-soft: rgba(255, 255, 255, .78); /* 深底次要文字 */ + --jn-ink-faint: rgba(255, 255, 255, .55); /* 深底弱化文字 */ + --jn-scrim: rgba(0, 0, 0, .45); /* banner 标题投影衬底(中性) */ + + /* —— 阴影(中性墨绿灰,随卡片抬升三档)—— */ + --jn-shadow-sm: 0 1px 4px rgba(23, 46, 36, .08); + --jn-shadow-md: 0 6px 18px rgba(23, 46, 36, .12); + --jn-shadow-lg: 0 14px 32px rgba(23, 46, 36, .16); + + /* —— 圆角(温润人文感:8/10px 两档)—— */ + --jn-radius: 8px; + --jn-radius-lg: 10px; + --jn-pill: 999px; + + /* —— 动效 —— */ + --jn-speed: .2s; /* 统一 hover 过渡 0.2s ease */ + --jn-ease: ease; + + /* —— 字号阶梯(12/13/14/15/16/18/20/24/28/32)—— */ + --jn-fs-12: 12px; + --jn-fs-13: 13px; + --jn-fs-14: 14px; + --jn-fs-15: 15px; + --jn-fs-16: 16px; + --jn-fs-18: 18px; + --jn-fs-20: 20px; + --jn-fs-24: 24px; + --jn-fs-28: 28px; + --jn-fs-32: 32px; + + /* —— 间距系统(4/8/12/16/24/32/48)—— */ + --jn-sp-1: 4px; + --jn-sp-2: 8px; + --jn-sp-3: 12px; + --jn-sp-4: 16px; + --jn-sp-6: 24px; + --jn-sp-8: 32px; + --jn-sp-12: 48px; + + /* —— 栅格 —— */ + --jn-max: 1200px; /* 内容安全宽 */ + --jn-gutter: 24px; /* 页边距 */ + --jn-header-h: 48px; /* 主导航条高(移动端折叠按钮对齐用) */ + + --jn-font: "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", "Helvetica Neue", Arial, sans-serif; + + /* —— 皮肤契约别名:站点配了 home_layout 而本包某形态未覆盖时,回落 + themes/common 兜底骨架只认契约变量(--primary/--text/--card-bg/--border…)。 + 不别名过去,换肤就只换了页头页脚、正文区块仍是骨架内置蓝灰。 —— */ + --primary: var(--jn-primary); + --primary-dark: var(--jn-primary-dark); + --primary-light: var(--jn-primary-light); + --text: var(--jn-text); + --text-light: var(--jn-text-light); + --bg: var(--jn-bg); + --card-bg: var(--jn-card-bg); + --border: var(--jn-border); + --radius: var(--jn-radius); +} + +/* --------------------------------------------------------------------- + 2. Reset 与基础 + --------------------------------------------------------------------- */ +* { box-sizing: border-box; } + +html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; } + +body { + margin: 0; + font-family: var(--jn-font); + font-size: var(--jn-fs-14); + line-height: 1.8; /* 人文师范:正文行高 1.8 */ + color: var(--jn-text); + background: var(--jn-bg); + word-break: break-word; +} + +h1, h2, h3, h4, h5, h6 { margin: 0; line-height: 1.4; color: var(--jn-text); } + +p { margin: 0 0 var(--jn-sp-3); } + +ul, ol { margin: 0; padding: 0; list-style: none; } + +a { color: inherit; text-decoration: none; transition: color var(--jn-speed) var(--jn-ease); } + +img { max-width: 100%; height: auto; display: block; border: 0; } + +button { font-family: inherit; cursor: pointer; } + +input, button, select, textarea { font-size: inherit; color: inherit; } + +time { color: var(--jn-text-light); font-size: var(--jn-fs-13); } + +::selection { background: var(--jn-primary); color: var(--jn-ink); } + +/* 键盘焦点态:全站统一可见(契约 §4 无障碍要求) */ +a:focus-visible, +button:focus-visible, +input:focus-visible, +[tabindex]:focus-visible { + outline: 2px solid var(--jn-primary-light); + outline-offset: 2px; +} + +/* 跳过链接:仅键盘聚焦时可见 */ +.skip-link { + position: absolute; + left: -9999px; + top: 0; + z-index: 300; + background: var(--jn-primary); + color: var(--jn-ink); + padding: var(--jn-sp-2) var(--jn-sp-4); + border-radius: 0 0 var(--jn-radius) 0; +} +.skip-link:focus { left: 0; color: var(--jn-ink); } + +/* --------------------------------------------------------------------- + 3. 页头之一 · 顶条(今日日期 + 专业院系切换,翡翠深青底) + --------------------------------------------------------------------- */ +.jn-topbar { + background: var(--jn-primary-dark); + color: var(--jn-ink-soft); + font-size: var(--jn-fs-13); +} + +.jn-topbar-inner { + max-width: var(--jn-max); + margin: 0 auto; + padding: var(--jn-sp-1) var(--jn-gutter); + min-height: 36px; + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--jn-sp-4); +} + +.jn-topbar-date { white-space: nowrap; letter-spacing: .04em; } + +.jn-topbar-side { display: flex; align-items: center; gap: var(--jn-sp-4); } + +/* 专业院系下拉(无子站整块不渲染;hover/focus-within 展开) */ +.jn-colleges { position: relative; } + +.jn-colleges-toggle { + display: inline-flex; + align-items: center; + gap: var(--jn-sp-1); + padding: var(--jn-sp-1) 0; + color: var(--jn-ink-soft); + font-size: var(--jn-fs-13); + white-space: nowrap; + cursor: pointer; +} +.jn-colleges-toggle:hover { color: var(--jn-ink); } + +.jn-colleges-arrow { + font-style: normal; + font-size: 11px; + transition: transform var(--jn-speed) var(--jn-ease); +} +.jn-colleges:hover .jn-colleges-arrow, +.jn-colleges:focus-within .jn-colleges-arrow { transform: rotate(180deg); } + +.jn-colleges-menu { + display: none; + position: absolute; + top: 100%; + right: 0; + min-width: 208px; + max-height: 420px; + overflow-y: auto; + padding: var(--jn-sp-1) 0; + background: var(--jn-card-bg); + border: 1px solid var(--jn-border); + border-top: 2px solid var(--jn-accent); /* 暖橙角标呼应日期徽标 */ + border-radius: 0 0 var(--jn-radius) var(--jn-radius); + box-shadow: var(--jn-shadow-md); + z-index: 120; +} +.jn-colleges:hover .jn-colleges-menu, +.jn-colleges:focus-within .jn-colleges-menu { display: block; } + +.jn-colleges-menu li a { + display: block; + padding: var(--jn-sp-2) var(--jn-sp-4); + color: var(--jn-text); + font-size: var(--jn-fs-14); + white-space: nowrap; + transition: background var(--jn-speed) var(--jn-ease), color var(--jn-speed) var(--jn-ease); +} +.jn-colleges-menu li a:hover { background: var(--jn-mint-bg); color: var(--jn-primary); } +.jn-colleges-menu li.active a { color: var(--jn-primary); font-weight: 600; } + +/* --------------------------------------------------------------------- + 4. 页头之二 · 品牌行(白色:校徽+校名居左,搜索与工具链接居右) + --------------------------------------------------------------------- */ +.jn-brandbar { + background: var(--jn-card-bg); + border-bottom: 1px solid var(--jn-border); +} + +.jn-brandbar-inner { + max-width: var(--jn-max); + margin: 0 auto; + padding: var(--jn-sp-4) var(--jn-gutter); + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--jn-sp-6); +} + +.jn-brand { display: flex; align-items: center; gap: var(--jn-sp-3); min-width: 0; } + +.jn-brand-badge { + flex: none; + display: inline-flex; + align-items: center; + justify-content: center; + width: 56px; + height: 56px; + border-radius: 50%; + color: var(--jn-primary); +} + +.jn-logo { height: 52px; width: auto; } + +.jn-site-name { + font-size: var(--jn-fs-28); + font-weight: 700; + color: var(--jn-primary-dark); + letter-spacing: 2px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.jn-site-name:hover { color: var(--jn-primary); } + +/* 工具区:服务中心入口 + 站内搜索 */ +.jn-tools { display: flex; align-items: center; gap: var(--jn-sp-4); flex: none; } + +.jn-tool-link { + display: inline-flex; + align-items: center; + gap: var(--jn-sp-1); + padding: var(--jn-sp-1) 0; + font-size: var(--jn-fs-14); + color: var(--jn-text-light); + white-space: nowrap; +} +.jn-tool-link svg { flex: none; } +.jn-tool-link:hover { color: var(--jn-primary); } + +.jn-search { display: flex; align-items: center; } + +.jn-search input { + width: 248px; + padding: var(--jn-sp-2) var(--jn-sp-4); + border: 2px solid var(--jn-primary); + border-right: none; + border-radius: var(--jn-pill) 0 0 var(--jn-pill); + background: var(--jn-card-bg); + color: var(--jn-text); + font-size: var(--jn-fs-14); + outline: none; + transition: border-color var(--jn-speed) var(--jn-ease), box-shadow var(--jn-speed) var(--jn-ease); +} +.jn-search input::placeholder { color: var(--jn-text-light); } +.jn-search input:focus { + border-color: var(--jn-primary-light); + box-shadow: 0 0 0 3px var(--jn-mint-bg); +} + +.jn-search button { + display: inline-flex; + align-items: center; + gap: var(--jn-sp-1); + padding: var(--jn-sp-2) var(--jn-sp-4); + border: none; + border-radius: 0 var(--jn-pill) var(--jn-pill) 0; + background: var(--jn-primary); + color: var(--jn-ink); + font-size: var(--jn-fs-14); + transition: background var(--jn-speed) var(--jn-ease); +} +.jn-search button:hover { background: var(--jn-primary-dark); } + +/* --------------------------------------------------------------------- + 5. 页头之三 · 主导航(翡翠青通栏,白字,当前项 primaryLight 底条) + --------------------------------------------------------------------- */ +.jn-nav { + background: var(--jn-nav-bg); + box-shadow: var(--jn-shadow-sm); + position: relative; + z-index: 110; +} + +.jn-nav > ul { + max-width: var(--jn-max); + margin: 0 auto; + padding: 0 var(--jn-gutter); + display: flex; + flex-wrap: wrap; +} + +.jn-nav > ul > li { position: relative; } + +.jn-nav > ul > li > a { + display: inline-flex; + align-items: center; + gap: var(--jn-sp-1); + padding: 0 var(--jn-sp-6); + height: var(--jn-header-h); + color: var(--jn-ink); + font-size: var(--jn-fs-16); + position: relative; + transition: background var(--jn-speed) var(--jn-ease); +} + +/* 当前栏目 / 悬停:primaryLight 底条(信阳师大导航语言) */ +.jn-nav > ul > li > a::after { + content: ""; + position: absolute; + left: var(--jn-sp-6); + right: var(--jn-sp-6); + bottom: 0; + height: 4px; + border-radius: 4px 4px 0 0; + background: var(--jn-primary-light); + transform: scaleX(0); + transition: transform var(--jn-speed) var(--jn-ease); +} +.jn-nav > ul > li:hover > a { background: var(--jn-primary-dark); } +.jn-nav > ul > li.active > a { font-weight: 600; } +.jn-nav > ul > li.active > a::after, +.jn-nav > ul > li:hover > a::after { transform: scaleX(1); } + +.jn-nav .caret { + font-style: normal; + font-size: 11px; + opacity: .8; + transition: transform var(--jn-speed) var(--jn-ease); +} +.jn-nav > ul > li:hover > a .caret { transform: rotate(180deg); } + +/* 二级下拉:白底面板、青色顶边 */ +.jn-sub { + display: none; + position: absolute; + top: 100%; + left: 0; + min-width: 184px; + padding: var(--jn-sp-1) 0; + background: var(--jn-card-bg); + border: 1px solid var(--jn-border); + border-top: 3px solid var(--jn-primary-light); + border-radius: 0 0 var(--jn-radius) var(--jn-radius); + box-shadow: var(--jn-shadow-md); + z-index: 120; +} +.jn-nav li:hover > .jn-sub, +.jn-nav li:focus-within > .jn-sub { display: block; } + +.jn-sub li a { + display: block; + padding: var(--jn-sp-2) var(--jn-sp-4); + color: var(--jn-text); + font-size: var(--jn-fs-14); + white-space: nowrap; + transition: background var(--jn-speed) var(--jn-ease), color var(--jn-speed) var(--jn-ease), padding-left var(--jn-speed) var(--jn-ease); +} +.jn-sub li a:hover { background: var(--jn-mint-bg); color: var(--jn-primary); padding-left: var(--jn-sp-6); } +.jn-sub li.active a { color: var(--jn-primary); font-weight: 600; } + +/* 移动端导航折叠(纯 CSS:checkbox + label,无 JS) */ +.jn-nav-fold { display: none; } +.jn-nav-btn { + display: none; + align-items: center; + justify-content: center; + gap: var(--jn-sp-2); + width: 100%; + height: var(--jn-header-h); + background: var(--jn-nav-bg); + color: var(--jn-ink); + font-size: var(--jn-fs-16); + cursor: pointer; + user-select: none; +} +.jn-nav-btn::before { content: "☰"; font-size: var(--jn-fs-18); } + +/* --------------------------------------------------------------------- + 6. 首页轮播 banner(通栏大图 1920×560,标题青色底条) + --------------------------------------------------------------------- */ +.jn-banner { + position: relative; + overflow: hidden; + background: var(--jn-primary-dark); +} + +.jn-banner-slides { position: relative; aspect-ratio: 1920 / 560; max-height: 560px; } + +.jn-banner-slide { display: none; position: absolute; inset: 0; } +.jn-banner-slide.active { display: block; } + +.jn-banner-slide img { width: 100%; height: 100%; object-fit: cover; } + +/* 标题:青色底条(非渐变遮罩,呼应信阳师大 banner 语言) */ +.jn-banner-title { + position: absolute; + left: max(var(--jn-gutter), calc((100% - var(--jn-max)) / 2 + var(--jn-gutter))); + bottom: var(--jn-sp-8); + display: inline-block; + max-width: min(72%, 720px); + padding: var(--jn-sp-2) var(--jn-sp-6); + background: var(--jn-primary); + color: var(--jn-ink); + font-size: var(--jn-fs-24); + font-weight: 600; + line-height: 1.5; + border-radius: var(--jn-radius); + box-shadow: var(--jn-shadow-lg); + text-shadow: 0 1px 2px var(--jn-scrim); + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.jn-banner-dots { + position: absolute; + bottom: var(--jn-sp-4); + right: max(var(--jn-gutter), calc((100% - var(--jn-max)) / 2 + var(--jn-gutter))); + display: flex; + gap: var(--jn-sp-2); + z-index: 20; +} +.jn-banner-dots button { + width: 10px; + height: 10px; + padding: 0; + border: none; + border-radius: var(--jn-pill); + background: var(--jn-ink-faint); + transition: width var(--jn-speed) var(--jn-ease), background var(--jn-speed) var(--jn-ease); +} +.jn-banner-dots button.active { width: 30px; background: var(--jn-ink); } + +.jn-banner-arrow { + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 44px; + height: 44px; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + border: none; + border-radius: 50%; + background: var(--jn-scrim); + color: var(--jn-ink); + font-size: 22px; + line-height: 1; + opacity: .6; + transition: opacity var(--jn-speed) var(--jn-ease), background var(--jn-speed) var(--jn-ease); + z-index: 20; +} +.jn-banner-arrow:hover { opacity: 1; background: var(--jn-primary-dark); } +.jn-banner-arrow.prev { left: max(var(--jn-gutter), calc((100% - var(--jn-max)) / 2)); } +.jn-banner-arrow.next { right: max(var(--jn-gutter), calc((100% - var(--jn-max)) / 2)); } + +/* --------------------------------------------------------------------- + 7. 通用容器与区块骨架 + --------------------------------------------------------------------- */ +.jn-container { + max-width: var(--jn-max); + margin: 0 auto; + padding: 0 var(--jn-gutter); +} + +.jn-section { margin: var(--jn-sp-8) 0; } + +/* 区块标题行:青色底条标题 + 右侧「更多」 */ +.jn-block-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: var(--jn-sp-4); + margin-bottom: var(--jn-sp-4); + padding-bottom: var(--jn-sp-3); + border-bottom: 1px solid var(--jn-border); +} + +.jn-block-head h2, +.jn-section-title { + position: relative; + padding: var(--jn-sp-1) 0 var(--jn-sp-1) var(--jn-sp-4); + font-size: var(--jn-fs-24); + font-weight: 700; + color: var(--jn-text); + letter-spacing: .02em; +} +.jn-block-head h2::before, +.jn-section-title::before { + content: ""; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 6px; + height: 70%; + border-radius: var(--jn-pill); + background: var(--jn-primary); +} +.jn-block-head h2::after, +.jn-section-title::after { + content: ""; + position: absolute; + left: 0; + bottom: -13px; + width: 48px; + height: 3px; + border-radius: var(--jn-pill); + background: var(--jn-accent); /* 暖橙短底线:青主橙辅 */ +} + +.jn-more { + display: inline-flex; + align-items: center; + gap: 2px; + font-size: var(--jn-fs-13); + color: var(--jn-primary); + white-space: nowrap; + transition: color var(--jn-speed) var(--jn-ease); +} +.jn-more::after { content: "›"; font-size: var(--jn-fs-15); } +.jn-more:hover { color: var(--jn-accent); } + +/* 区块卡(白底、细边、hover 阴影抬升) */ +.jn-block { + background: var(--jn-card-bg); + border: 1px solid var(--jn-border); + border-radius: var(--jn-radius-lg); + box-shadow: var(--jn-shadow-sm); + padding: var(--jn-sp-6); + transition: box-shadow var(--jn-speed) var(--jn-ease), transform var(--jn-speed) var(--jn-ease); +} +.jn-block:hover { box-shadow: var(--jn-shadow-md); } + +/* 背景带层序(news_bg_image):带压 z-0、卡抬 z-1,缺一不可 */ +.jn-sec-bg { + position: absolute; + inset: 0; + z-index: 0; + background-size: cover; + background-position: center; +} +.jn-sec-bg + .jn-block { + position: relative; + z-index: 1; +} + +/* --------------------------------------------------------------------- + 8. 日期徽标(46px 橙色数字:日大号 + 年月小号) + --------------------------------------------------------------------- */ +.jn-date-badge { + flex: none; + width: 46px; + height: 46px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background: var(--jn-card-bg); + border: 1px solid var(--jn-border); + border-bottom: 2px solid var(--jn-accent); + border-radius: var(--jn-radius); + box-shadow: var(--jn-shadow-sm); + overflow: hidden; +} +.jn-date-badge b { + font-size: var(--jn-fs-18); + font-weight: 700; + line-height: 1.1; + color: var(--jn-accent); /* 橙色数字点缀 */ +} +.jn-date-badge i { + font-style: normal; + font-size: var(--jn-fs-12); + line-height: 1.3; + color: var(--jn-text-light); + letter-spacing: .02em; + transform: scale(.92); +} + +/* 置顶徽标 */ +.jn-top-badge { + flex: none; + padding: 3px var(--jn-sp-2); + border-radius: var(--jn-pill); + background: var(--jn-accent); + color: var(--jn-ink); + font-size: var(--jn-fs-12); + font-weight: 600; + line-height: 1.4; +} + +/* --------------------------------------------------------------------- + 9. 首页 · 回落模式(无 home_layout 时):头条区 + 栏目区块 + --------------------------------------------------------------------- */ +.jn-home { display: block; } + +.jn-headline { + display: grid; + grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); + gap: var(--jn-sp-6); + align-items: stretch; +} + +.jn-headline-card, +.jn-focus-card { display: flex; flex-direction: column; } + +/* 头条推荐列表 */ +.jn-headline-list li { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--jn-sp-3); + padding: var(--jn-sp-3) var(--jn-sp-2); + margin: 0 calc(-1 * var(--jn-sp-2)); + border-bottom: 1px solid var(--jn-border); + border-radius: var(--jn-radius); + transition: background var(--jn-speed) var(--jn-ease); +} +.jn-headline-list li:last-child { border-bottom: none; } +.jn-headline-list li:hover { background: var(--jn-mint-bg); } +.jn-headline-list li a { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: var(--jn-fs-15); +} +.jn-headline-list li a:hover { color: var(--jn-primary); } + +.jn-headline-lead { + display: block; + padding: 0 0 var(--jn-sp-4); + margin: 0; + border-bottom: 1px solid var(--jn-border); + border-radius: 0; +} +.jn-headline-lead:hover { background: none; } +.jn-lead-title { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: var(--jn-fs-24); + font-weight: 700; + line-height: 1.4; + color: var(--jn-primary-dark); + margin-bottom: var(--jn-sp-2); + white-space: normal; +} +.jn-lead-title:hover { color: var(--jn-primary); } +.jn-lead-meta { display: flex; align-items: center; gap: var(--jn-sp-3); } + +/* 图片新闻卡(右列:大图 + 两行小图) */ +.jn-focus-card .jn-focus-lead { display: block; } +.jn-focus-cover { + display: block; + aspect-ratio: 16 / 9; + border-radius: var(--jn-radius); + overflow: hidden; + margin-bottom: var(--jn-sp-3); + background: var(--jn-mint-bg); +} +.jn-focus-cover img { width: 100%; height: 100%; object-fit: cover; } +.jn-focus-title { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: var(--jn-fs-15); + font-weight: 600; + line-height: 1.6; +} +.jn-focus-lead:hover .jn-focus-title { color: var(--jn-primary); } + +.jn-focus-rows { margin-top: var(--jn-sp-3); padding-top: var(--jn-sp-3); border-top: 1px solid var(--jn-border); } +.jn-focus-rows li { border-bottom: 1px solid var(--jn-border); } +.jn-focus-rows li:last-child { border-bottom: none; } +.jn-focus-rows a { display: flex; align-items: center; gap: var(--jn-sp-3); padding: var(--jn-sp-3) 0; } +.jn-row-cover { + flex: none; + width: 92px; + aspect-ratio: 16 / 9; + border-radius: var(--jn-radius); + overflow: hidden; + background: var(--jn-mint-bg); +} +.jn-row-cover img { width: 100%; height: 100%; object-fit: cover; } +.jn-row-title { + flex: 1; + min-width: 0; + font-size: var(--jn-fs-14); + line-height: 1.7; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.jn-focus-rows a:hover .jn-row-title { color: var(--jn-primary); } + +/* 栏目区块网格 */ +.jn-blocks { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--jn-sp-6); +} + +.jn-block-list li.jn-block-item { + display: flex; + align-items: center; + gap: var(--jn-sp-3); + padding: var(--jn-sp-2) var(--jn-sp-2); + margin: 0 calc(-1 * var(--jn-sp-2)); + border-bottom: 1px solid var(--jn-border); + border-radius: var(--jn-radius); + transition: background var(--jn-speed) var(--jn-ease); +} +.jn-block-list li.jn-block-item:last-child { border-bottom: none; } +.jn-block-list li.jn-block-item:hover { background: var(--jn-mint-bg); } + +.jn-block-item-title { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: var(--jn-fs-15); +} +.jn-block-item-title:hover { color: var(--jn-primary); } + +.jn-item-date { flex: none; color: var(--jn-text-light); font-size: var(--jn-fs-13); } + +/* 区块头条(有封面图文 / 无封面纯文摘要) */ +.jn-block-featured { padding-bottom: var(--jn-sp-4); margin-bottom: var(--jn-sp-2); border-bottom: 1px solid var(--jn-border); } +.jn-block-featured > a { display: flex; gap: var(--jn-sp-4); align-items: flex-start; } + +.jn-feat-cover { + flex: none; + display: block; + width: 176px; + aspect-ratio: 16 / 9; + border-radius: var(--jn-radius); + overflow: hidden; + background: var(--jn-mint-bg); +} +.jn-feat-cover img { width: 100%; height: 100%; object-fit: cover; } +.jn-feat-cover--row { width: 100%; margin-bottom: var(--jn-sp-3); } +/* 全宽封面变体:锚点转纵向,否则横向 nowrap 会把正文列压成 0 宽(390px 实测溢出根因) */ +.jn-feat-a--stack { flex-direction: column; align-items: stretch; } + +.jn-feat-body { min-width: 0; flex: 1; display: flex; flex-direction: column; } +.jn-feat-title { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: var(--jn-fs-16); + font-weight: 600; + line-height: 1.6; +} +.jn-feat-summary { + margin-top: var(--jn-sp-2); + color: var(--jn-text-light); + font-size: var(--jn-fs-13); + line-height: 1.7; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.jn-feat-meta { display: flex; align-items: center; gap: var(--jn-sp-3); margin-top: auto; padding-top: var(--jn-sp-2); } +.jn-block-featured a:hover .jn-feat-title { color: var(--jn-primary); } + +/* --------------------------------------------------------------------- + 10. 布局模式 · news_grid(校园要闻:左图文头条 + 右日期徽标行 + 四图横排) + --------------------------------------------------------------------- */ +.jn-news-sec { position: relative; } + +.jn-split { + display: grid; + grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); + gap: var(--jn-sp-6); + align-items: stretch; +} + +.jn-split-side { display: flex; flex-direction: column; min-width: 0; } + +.jn-split-side .jn-block-list { flex: 1; } +.jn-split-side .jn-block-item { padding: var(--jn-sp-3) var(--jn-sp-2); } + +/* 四图横排(教学科研/校园映像形态的紧凑图组) */ +.jn-shots { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: var(--jn-sp-4); + margin-top: var(--jn-sp-6); +} +.jn-shots li { min-width: 0; } +.jn-shot a { display: block; border-radius: var(--jn-radius); overflow: hidden; } +.jn-shot img { + width: 100%; + aspect-ratio: 4 / 3; + object-fit: cover; + border-radius: var(--jn-radius); + background: var(--jn-mint-bg); + transition: transform var(--jn-speed) var(--jn-ease); +} +.jn-shot-cap { + display: block; + margin-top: var(--jn-sp-2); + font-size: var(--jn-fs-13); + color: var(--jn-text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.jn-shot a:hover img { transform: scale(1.04); } +.jn-shot a:hover .jn-shot-cap { color: var(--jn-primary); } + +/* --------------------------------------------------------------------- + 11. 布局模式 · compact(通知公告:橙色日期徽标行)/ media_focus(来源徽标双列) + --------------------------------------------------------------------- */ +.jn-block-list li.jn-row-badge { padding: var(--jn-sp-3) var(--jn-sp-2); } +.jn-row-badge .jn-block-item-title { font-size: var(--jn-fs-15); } + +/* 媒体聚焦:双列密行 */ +.jn-block-list--two { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + column-gap: var(--jn-sp-8); +} +.jn-block-list--two li.jn-block-item { border-bottom: 1px dashed var(--jn-border); } + +/* 来源徽标 */ +.jn-src { + flex: none; + padding: 1px var(--jn-sp-2); + border: 1px solid var(--jn-primary-light); + border-radius: var(--jn-radius); + color: var(--jn-primary); + font-size: var(--jn-fs-12); + line-height: 1.6; + max-width: 8em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* --------------------------------------------------------------------- + 12. 布局模式 · image_wall(四列图片墙) + --------------------------------------------------------------------- */ +.jn-wall { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: var(--jn-sp-4); +} +.jn-wall-item { min-width: 0; } +.jn-wall-item a { + position: relative; + display: block; + border-radius: var(--jn-radius-lg); + overflow: hidden; + box-shadow: var(--jn-shadow-sm); + transition: box-shadow var(--jn-speed) var(--jn-ease), transform var(--jn-speed) var(--jn-ease); +} +.jn-wall-item a:hover { box-shadow: var(--jn-shadow-md); transform: translateY(-3px); } +.jn-wall-item img { + width: 100%; + aspect-ratio: 4 / 3; + object-fit: cover; + background: var(--jn-mint-bg); + transition: transform var(--jn-speed) var(--jn-ease); +} +.jn-wall-item a:hover img { transform: scale(1.05); } +.jn-wall-cap { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: var(--jn-sp-2) var(--jn-sp-3); + background: var(--jn-primary-dark); + color: var(--jn-ink); + font-size: var(--jn-fs-13); + line-height: 1.5; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* --------------------------------------------------------------------- + 13. 布局模式 · ticker(翡翠青要闻速递横条;中文不塌列三件套) + --------------------------------------------------------------------- */ +.jn-ticker { + background: var(--jn-primary); + color: var(--jn-ink); + box-shadow: var(--jn-shadow-sm); +} + +.jn-ticker-inner { + max-width: var(--jn-max); + margin: 0 auto; + padding: var(--jn-sp-2) var(--jn-gutter); + display: flex; + align-items: center; + gap: var(--jn-sp-4); + min-width: 0; +} + +.jn-ticker-label { + flex: none; + display: inline-flex; + align-items: center; + gap: var(--jn-sp-2); + font-size: var(--jn-fs-15); + font-weight: 700; + letter-spacing: .08em; + padding-right: var(--jn-sp-4); + border-right: 1px solid var(--jn-ink-faint); +} +.jn-ticker-label::before { + content: ""; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--jn-accent); +} + +/* flex 项自动最小尺寸=min-content,中文可按字断行 → 不锁 nowrap/不收缩就会塌成一字一列 */ +.jn-ticker-list { + flex: 1; + min-width: 0; + display: flex; + gap: var(--jn-sp-8); + overflow: hidden; + white-space: nowrap; +} +.jn-ticker-list li { flex: none; min-width: 0; } + +.jn-ticker-item { + display: block; + flex: none; + max-width: 280px; + color: var(--jn-ink); + font-size: var(--jn-fs-14); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + opacity: .92; + transition: opacity var(--jn-speed) var(--jn-ease); +} +.jn-ticker-item:hover { opacity: 1; text-decoration: underline; color: var(--jn-ink); } + +/* --------------------------------------------------------------------- + 14. 布局模式 · gallery(校园映像四图 + 融媒师大图标行) + --------------------------------------------------------------------- */ +.jn-gallery { text-align: left; } + +.jn-gallery-sub { + margin: -4px 0 var(--jn-sp-4); + color: var(--jn-text-light); + font-size: var(--jn-fs-13); + letter-spacing: .1em; +} + +/* 融媒体图标行(微信/微博/抖音/B站/校报/广播台,内联 SVG) */ +.jn-fusion { + margin-top: var(--jn-sp-8); + padding: var(--jn-sp-6); + background: var(--jn-mint-bg); + border-radius: var(--jn-radius-lg); +} + +.jn-fusion-label { + display: flex; + align-items: center; + gap: var(--jn-sp-2); + margin-bottom: var(--jn-sp-4); + font-size: var(--jn-fs-16); + font-weight: 600; + color: var(--jn-primary-dark); +} +.jn-fusion-label::before { + content: ""; + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--jn-accent); +} + +.jn-fusion-row { + display: grid; + grid-template-columns: repeat(6, minmax(0, 1fr)); + gap: var(--jn-sp-4); +} + +.jn-fusion-item { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--jn-sp-2); + padding: var(--jn-sp-4) var(--jn-sp-2); + background: var(--jn-card-bg); + border: 1px solid var(--jn-border); + border-radius: var(--jn-radius-lg); + text-align: center; + transition: background var(--jn-speed) var(--jn-ease), border-color var(--jn-speed) var(--jn-ease), + box-shadow var(--jn-speed) var(--jn-ease), transform var(--jn-speed) var(--jn-ease); +} +a.jn-fusion-item:hover { + background: var(--jn-card-bg); + border-color: var(--jn-primary); + box-shadow: var(--jn-shadow-md); + transform: translateY(-3px); +} + +.jn-fusion-ico { + display: inline-flex; + align-items: center; + justify-content: center; + width: 46px; + height: 46px; + border-radius: 50%; + color: var(--jn-primary); + background: var(--jn-mint-bg); + transition: background var(--jn-speed) var(--jn-ease), color var(--jn-speed) var(--jn-ease); +} +a.jn-fusion-item:hover .jn-fusion-ico { + background: var(--jn-primary); + color: var(--jn-ink); +} + +.jn-fusion-name { + font-size: var(--jn-fs-13); + color: var(--jn-text); + white-space: nowrap; +} +a.jn-fusion-item:hover .jn-fusion-name { color: var(--jn-primary); } + +/* --------------------------------------------------------------------- + 15. 布局模式 · links(快捷通道图标宫格:青色描边、hover 青底白字) + --------------------------------------------------------------------- */ +.jn-quick-group { + margin: var(--jn-sp-4) 0 var(--jn-sp-2); + font-size: var(--jn-fs-13); + color: var(--jn-text-light); + letter-spacing: .06em; +} +.jn-quick-group:not(:first-of-type) { margin-top: var(--jn-sp-6); } + +.jn-quick-grid { + display: grid; + grid-template-columns: repeat(6, minmax(0, 1fr)); + gap: var(--jn-sp-4); +} + +.jn-quick-item { min-width: 0; } + +.jn-quick-item a { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--jn-sp-3); + min-height: 108px; + padding: var(--jn-sp-4) var(--jn-sp-2); + background: var(--jn-card-bg); + border: 1px solid var(--jn-primary-light); + border-radius: var(--jn-radius-lg); + text-align: center; + transition: background var(--jn-speed) var(--jn-ease), border-color var(--jn-speed) var(--jn-ease), + box-shadow var(--jn-speed) var(--jn-ease), transform var(--jn-speed) var(--jn-ease); +} + +.jn-quick-ico { + display: inline-flex; + align-items: center; + justify-content: center; + color: var(--jn-primary); /* 青色描边图标 */ + transition: color var(--jn-speed) var(--jn-ease), transform var(--jn-speed) var(--jn-ease); +} + +.jn-quick-name { + font-size: var(--jn-fs-14); + color: var(--jn-text); + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + transition: color var(--jn-speed) var(--jn-ease); +} + +/* hover:青底白字(图标描边同步反白) */ +.jn-quick-item a:hover { + background: var(--jn-primary); + border-color: var(--jn-primary); + box-shadow: var(--jn-shadow-md); + transform: translateY(-3px); +} +.jn-quick-item a:hover .jn-quick-ico { color: var(--jn-ink); transform: scale(1.08); } +.jn-quick-item a:hover .jn-quick-name { color: var(--jn-ink); } + +/* --------------------------------------------------------------------- + 16. 空态(与正常态同等用心:CSS 画一枚「空文件夹」,不造占位图) + --------------------------------------------------------------------- */ +.jn-empty { + padding: var(--jn-sp-12) var(--jn-sp-4); + text-align: center; + color: var(--jn-text-light); + font-size: var(--jn-fs-15); +} +.jn-empty::before { + content: ""; + display: block; + width: 72px; + height: 56px; + margin: 0 auto var(--jn-sp-4); + border: 2px solid var(--jn-border); + border-radius: 0 0 var(--jn-radius) var(--jn-radius); + background: + var(--jn-mint-bg) 14px 26px / 40px 6px no-repeat, + var(--jn-mint-bg) 14px 38px / 26px 6px no-repeat; + box-shadow: inset 0 12px 0 -10px var(--jn-border); +} +.jn-empty .jn-empty-hint { margin-top: var(--jn-sp-1); font-size: var(--jn-fs-13); color: var(--jn-text-light); opacity: .8; } +.jn-empty p { margin: 0; } + +/* --------------------------------------------------------------------- + 17. 列表页 / 搜索页(themeParams.listLayout:badge 日期徽标行 / plain 通栏行式) + --------------------------------------------------------------------- */ +.jn-list-main { margin: var(--jn-sp-8) auto; } + +.jn-page-cols { display: flex; align-items: flex-start; gap: var(--jn-sp-6); } + +/* 左侧栏目导航(docs/11) */ +.jn-side-nav { + flex: none; + width: 224px; + background: var(--jn-card-bg); + border: 1px solid var(--jn-border); + border-radius: var(--jn-radius-lg); + box-shadow: var(--jn-shadow-sm); + overflow: hidden; +} +.jn-side-nav-head { + padding: var(--jn-sp-4) var(--jn-sp-3); + background: var(--jn-primary); + color: var(--jn-ink); + font-size: var(--jn-fs-18); + font-weight: 700; + text-align: center; + letter-spacing: 3px; +} +.jn-side-nav-item + .jn-side-nav-item { border-top: 1px dashed var(--jn-border); } +.jn-side-nav-item a { + display: block; + padding: var(--jn-sp-3) var(--jn-sp-4); + color: var(--jn-text); + font-size: var(--jn-fs-15); + transition: background var(--jn-speed) var(--jn-ease), color var(--jn-speed) var(--jn-ease), + padding-left var(--jn-speed) var(--jn-ease); +} +.jn-side-nav-item a:hover { background: var(--jn-mint-bg); color: var(--jn-primary); padding-left: var(--jn-sp-6); } +.jn-side-nav-item.active a { + background: var(--jn-mint-bg); + border-left: 3px solid var(--jn-accent); + color: var(--jn-primary); + font-weight: 600; + padding-left: calc(var(--jn-sp-4) - 3px); +} + +/* 内容卡 */ +.jn-page-card { + flex: 1; + min-width: 0; + background: var(--jn-card-bg); + border: 1px solid var(--jn-border); + border-radius: var(--jn-radius-lg); + box-shadow: var(--jn-shadow-sm); + padding: var(--jn-sp-8) var(--jn-sp-6); +} + +/* 面包屑 */ +.jn-breadcrumb { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--jn-sp-2); + margin-bottom: var(--jn-sp-4); + color: var(--jn-text-light); + font-size: var(--jn-fs-13); +} +.jn-breadcrumb a { color: var(--jn-text-light); } +.jn-breadcrumb a:hover { color: var(--jn-primary); } +.jn-breadcrumb .crumb-sep { color: var(--jn-border); } +.jn-breadcrumb .current { color: var(--jn-primary-dark); font-weight: 600; } + +.jn-page-title { + position: relative; + margin: 0 0 var(--jn-sp-6); + padding: var(--jn-sp-1) 0 var(--jn-sp-1) var(--jn-sp-4); + font-size: var(--jn-fs-28); + font-weight: 700; + color: var(--jn-text); +} +.jn-page-title::before { + content: ""; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 6px; + height: 70%; + border-radius: var(--jn-pill); + background: var(--jn-primary); +} + +/* 文章列表 */ +.jn-article-list > li { padding: var(--jn-sp-4) 0; border-bottom: 1px solid var(--jn-border); } +.jn-article-list > li:last-child { border-bottom: none; } + +.jn-item { display: flex; gap: var(--jn-sp-4); align-items: flex-start; } + +.jn-item-cover { + flex: none; + width: 176px; + aspect-ratio: 16 / 9; + border-radius: var(--jn-radius); + overflow: hidden; + background: var(--jn-mint-bg); +} +.jn-item-cover img { width: 100%; height: 100%; object-fit: cover; } + +.jn-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--jn-sp-1); } +.jn-item-title { font-size: var(--jn-fs-18); font-weight: 600; line-height: 1.5; } +.jn-item-title a:hover { color: var(--jn-primary); } + +.jn-item-summary { + color: var(--jn-text-light); + font-size: var(--jn-fs-14); + line-height: 1.7; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.jn-item-meta { display: flex; align-items: center; gap: var(--jn-sp-3); margin-top: auto; color: var(--jn-text-light); font-size: var(--jn-fs-13); } + +/* —— 形态一(默认):日期徽标行(无封面条目带 46px 橙徽)—— */ +.jn-list--badge .jn-item--plain { + display: grid; + grid-template-columns: 46px minmax(0, 1fr); + gap: var(--jn-sp-4); + align-items: start; +} +.jn-list--badge .jn-item--plain .jn-item-time { display: none; } /* 时间并入徽标,不重复 */ + +/* —— 形态二:通栏行式(日期右置,themeParams.listLayout=plain)—— */ +.jn-list--plain .jn-date-badge { display: none; } /* 徽标让位 */ +.jn-list--plain .jn-item--plain { display: flex; flex-direction: column; gap: var(--jn-sp-1); } +.jn-list--plain .jn-item--plain .jn-item-title { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: var(--jn-sp-4); +} +.jn-list--plain .jn-item--plain .jn-item-time { flex: none; } +.jn-list--plain .jn-item--plain .jn-item-title > a { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: var(--jn-fs-16); +} + +/* 分页 */ +.jn-pagination { + display: flex; + flex-wrap: wrap; + gap: var(--jn-sp-2); + justify-content: center; + align-items: center; + padding: var(--jn-sp-8) 0 var(--jn-sp-2); +} +.jn-pagination a { + min-width: 36px; + padding: var(--jn-sp-1) var(--jn-sp-3); + border: 1px solid var(--jn-border); + border-radius: var(--jn-radius); + background: var(--jn-card-bg); + color: var(--jn-text-light); + font-size: var(--jn-fs-14); + text-align: center; + transition: border-color var(--jn-speed) var(--jn-ease), color var(--jn-speed) var(--jn-ease), + background var(--jn-speed) var(--jn-ease); +} +.jn-pagination a:hover { border-color: var(--jn-primary); color: var(--jn-primary); background: var(--jn-mint-bg); } +.jn-pagination a.active { background: var(--jn-primary); border-color: var(--jn-primary); color: var(--jn-ink); font-weight: 600; } +.jn-pagination a.disabled { opacity: .4; pointer-events: none; } + +/* --------------------------------------------------------------------- + 18. 详情页 / 单页 + --------------------------------------------------------------------- */ +.jn-detail-main { margin: var(--jn-sp-8) auto; } + +.jn-article-title { + margin: var(--jn-sp-2) 0 var(--jn-sp-4); + font-size: var(--jn-fs-32); + font-weight: 700; + line-height: 1.4; + text-align: center; +} + +.jn-article-meta { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: var(--jn-sp-4); + padding: var(--jn-sp-2) 0 var(--jn-sp-4); + border-bottom: 1px solid var(--jn-border); + color: var(--jn-text-light); + font-size: var(--jn-fs-13); +} + +.jn-article-content { + padding-top: var(--jn-sp-6); + font-size: var(--jn-fs-16); + line-height: 1.9; + color: var(--jn-text); + word-break: break-word; +} +.jn-article-content p { text-indent: 2em; margin: 0 0 var(--jn-sp-3); } +.jn-article-content p:has(img), .jn-article-content figure p { text-indent: 0; text-align: center; } +.jn-article-content p > img:only-child { display: inline-block; } +.jn-article-content img { height: auto; border-radius: var(--jn-radius); } +.jn-article-content figure { margin: var(--jn-sp-4) auto; text-align: center; text-indent: 0; } +.jn-article-content figcaption { margin-top: var(--jn-sp-2); font-size: var(--jn-fs-13); color: var(--jn-text-light); } +.jn-article-content h2, .jn-article-content h3 { margin: var(--jn-sp-6) 0 var(--jn-sp-3); } +.jn-article-content h2 { font-size: var(--jn-fs-20); } +.jn-article-content h3 { font-size: var(--jn-fs-18); } +.jn-article-content ul, .jn-article-content ol { margin: 0 0 var(--jn-sp-3) 2em; text-indent: 0; list-style: disc; } +.jn-article-content ol { list-style: decimal; } +.jn-article-content li { margin-bottom: var(--jn-sp-1); } +.jn-article-content a { color: var(--jn-primary); } +.jn-article-content a:hover { text-decoration: underline; } +.jn-article-content blockquote { + margin: var(--jn-sp-4) 0; + padding: var(--jn-sp-3) var(--jn-sp-4); + border-left: 4px solid var(--jn-accent); + border-radius: 0 var(--jn-radius) var(--jn-radius) 0; + background: var(--jn-mint-bg); + color: var(--jn-text-light); + text-indent: 0; +} +.jn-article-content table { + width: 100%; + margin: var(--jn-sp-4) 0; + border-collapse: collapse; + font-size: var(--jn-fs-14); +} +.jn-article-content table td, +.jn-article-content table th { border: 1px solid var(--jn-border); padding: var(--jn-sp-2) var(--jn-sp-3); } +.jn-article-content table th { background: var(--jn-mint-bg); font-weight: 600; } +.jn-article-content table tbody tr:nth-child(even) { background: var(--jn-mint-bg); } +.jn-article-content table tbody tr:hover { background: var(--jn-border); } + +/* 上下篇 */ +.jn-sibling { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--jn-sp-4); + margin-top: var(--jn-sp-8); + padding-top: var(--jn-sp-6); + border-top: 1px solid var(--jn-border); +} +.jn-sibling a { + display: flex; + flex-direction: column; + gap: var(--jn-sp-1); + padding: var(--jn-sp-3) var(--jn-sp-4); + background: var(--jn-card-bg); + border: 1px solid var(--jn-border); + border-radius: var(--jn-radius-lg); + box-shadow: var(--jn-shadow-sm); + transition: border-color var(--jn-speed) var(--jn-ease), box-shadow var(--jn-speed) var(--jn-ease), + transform var(--jn-speed) var(--jn-ease); +} +.jn-sibling a:hover { border-color: var(--jn-primary); box-shadow: var(--jn-shadow-md); transform: translateY(-2px); } +.jn-sibling a.next { text-align: right; } +.jn-sib-label { font-size: var(--jn-fs-13); color: var(--jn-text-light); } +.jn-sib-title { + font-size: var(--jn-fs-14); + color: var(--jn-text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.jn-sibling a:hover .jn-sib-title { color: var(--jn-primary); } +.jn-sibling .jn-sib-none { + display: flex; + flex-direction: column; + gap: var(--jn-sp-1); + padding: var(--jn-sp-3) var(--jn-sp-4); + background: var(--jn-mint-bg); + border: 1px dashed var(--jn-border); + border-radius: var(--jn-radius-lg); + color: var(--jn-text-light); +} +.jn-sibling .jn-sib-none.next { text-align: right; } + +/* --------------------------------------------------------------------- + 19. 服务中心 / 事项指南(事项库 R2,契约 docs/10 §3.4 消费端样式) + --------------------------------------------------------------------- */ +.jn-svc-page, .jn-svc-guide { display: block; } + +.jn-svc-unavailable { margin-top: var(--jn-sp-4); } + +/* 筛选区:三组 chip */ +.jn-svc-filters { + margin: var(--jn-sp-4) 0 var(--jn-sp-3); + padding: var(--jn-sp-3) var(--jn-sp-4); + background: var(--jn-mint-bg); + border-radius: var(--jn-radius-lg); +} +.jn-svc-filter-group { display: flex; align-items: flex-start; gap: var(--jn-sp-3); padding: var(--jn-sp-2) 0; } +.jn-svc-filter-group + .jn-svc-filter-group { border-top: 1px dashed var(--jn-border); } +.jn-svc-filter-label { + flex: none; + width: 4.5em; + padding-top: var(--jn-sp-1); + color: var(--jn-text-light); + font-size: var(--jn-fs-13); + font-weight: 600; +} +.jn-svc-filter-options { display: flex; flex-wrap: wrap; gap: var(--jn-sp-2); min-width: 0; } + +.jn-svc-chip { + display: inline-flex; + align-items: center; + gap: var(--jn-sp-1); + padding: 2px var(--jn-sp-3); + background: var(--jn-card-bg); + border: 1px solid var(--jn-border); + border-radius: var(--jn-pill); + font-size: var(--jn-fs-13); + color: var(--jn-text); + transition: border-color var(--jn-speed) var(--jn-ease), color var(--jn-speed) var(--jn-ease); +} +.jn-svc-chip:hover { border-color: var(--jn-primary); color: var(--jn-primary); } +.jn-svc-chip em { font-style: normal; color: var(--jn-text-light); font-size: var(--jn-fs-12); } +.jn-svc-chip.active { background: var(--jn-primary); border-color: var(--jn-primary); color: var(--jn-ink); } +.jn-svc-chip.active em { color: var(--jn-ink-soft); } + +/* 工具条 */ +.jn-svc-toolbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--jn-sp-3); + margin-bottom: var(--jn-sp-4); +} +.jn-svc-search { display: flex; } +.jn-svc-search input { + width: 260px; + padding: 7px var(--jn-sp-3); + border: 1px solid var(--jn-border); + border-right: none; + border-radius: var(--jn-radius) 0 0 var(--jn-radius); + font-size: var(--jn-fs-14); + font-family: inherit; + outline: none; +} +.jn-svc-search input:focus { border-color: var(--jn-primary); } +.jn-svc-search button { + padding: 7px var(--jn-sp-4); + border: none; + border-radius: 0 var(--jn-radius) var(--jn-radius) 0; + background: var(--jn-primary); + color: var(--jn-ink); + font-size: var(--jn-fs-14); + transition: background var(--jn-speed) var(--jn-ease); +} +.jn-svc-search button:hover { background: var(--jn-primary-dark); } +.jn-svc-clear { font-size: var(--jn-fs-13); color: var(--jn-text-light); } +.jn-svc-clear:hover { color: var(--jn-primary); } + +/* 事项列表行 */ +.jn-svc-list li { border-bottom: 1px solid var(--jn-border); } +.jn-svc-list li:last-child { border-bottom: none; } +.jn-svc-list li:hover { background: var(--jn-mint-bg); } +.jn-svc-item { display: flex; gap: var(--jn-sp-4); padding: var(--jn-sp-4) var(--jn-sp-2); } +.jn-svc-item-cover { + flex: none; + width: 96px; + height: 64px; + border: 1px solid var(--jn-border); + border-radius: var(--jn-radius); + overflow: hidden; + background: var(--jn-mint-bg); +} +.jn-svc-item-cover img { width: 100%; height: 100%; object-fit: cover; } +.jn-svc-item-body { display: flex; flex-direction: column; gap: var(--jn-sp-1); min-width: 0; } +.jn-svc-item-title { display: flex; align-items: center; gap: var(--jn-sp-2); flex-wrap: wrap; } +.jn-svc-item-name { font-size: var(--jn-fs-16); font-weight: 600; color: var(--jn-text); } +.jn-svc-item:hover .jn-svc-item-name { color: var(--jn-primary); } +.jn-svc-tag { + flex: none; + padding: 1px var(--jn-sp-2); + border: 1px solid var(--jn-border); + border-radius: var(--jn-radius); + background: var(--jn-card-bg); + color: var(--jn-text-light); + font-size: var(--jn-fs-12); + line-height: 1.6; +} +.jn-svc-tag.online { background: var(--jn-primary); border-color: var(--jn-primary); color: var(--jn-ink); } +.jn-svc-item-summary { + color: var(--jn-text-light); + font-size: var(--jn-fs-14); + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.jn-svc-item-meta { display: flex; gap: var(--jn-sp-4); color: var(--jn-text-light); font-size: var(--jn-fs-13); } + +/* 指南页 */ +.jn-svc-guide-body { display: block; } +.jn-svc-apply { display: flex; align-items: center; gap: var(--jn-sp-3); margin: var(--jn-sp-4) 0; } +.jn-svc-apply-btn { + display: inline-block; + padding: var(--jn-sp-2) var(--jn-sp-8); + border-radius: var(--jn-pill); + background: var(--jn-accent); + color: var(--jn-ink); + font-size: var(--jn-fs-16); + font-weight: 600; + transition: background var(--jn-speed) var(--jn-ease), transform var(--jn-speed) var(--jn-ease); +} +.jn-svc-apply-btn:hover { background: var(--jn-primary); color: var(--jn-ink); transform: translateY(-1px); } +.jn-svc-apply-hint { color: var(--jn-text-light); font-size: var(--jn-fs-13); } + +.jn-svc-summary { + padding: var(--jn-sp-3) var(--jn-sp-4); + background: var(--jn-mint-bg); + border-left: 3px solid var(--jn-primary); + border-radius: 0 var(--jn-radius) var(--jn-radius) 0; + color: var(--jn-text-light); +} + +.jn-svc-info { width: 100%; margin: var(--jn-sp-4) 0; border-collapse: collapse; font-size: var(--jn-fs-14); } +.jn-svc-info th, .jn-svc-info td { + border: 1px solid var(--jn-border); + padding: var(--jn-sp-2) var(--jn-sp-4); + text-align: left; + vertical-align: top; +} +.jn-svc-info th { + width: 7em; + background: var(--jn-mint-bg); + color: var(--jn-text-light); + font-weight: 600; + white-space: nowrap; +} + +.jn-svc-section { margin: var(--jn-sp-6) 0; } +.jn-svc-section h2 { + margin-bottom: var(--jn-sp-3); + padding-bottom: var(--jn-sp-2); + border-bottom: 2px solid var(--jn-primary); + font-size: var(--jn-fs-20); +} + +.jn-svc-attachments li { + display: flex; + align-items: center; + gap: var(--jn-sp-3); + padding: var(--jn-sp-2) 0; + border-bottom: 1px dashed var(--jn-border); +} +.jn-svc-attachments li:last-child { border-bottom: none; } +.jn-svc-attachments a { color: var(--jn-primary); } +.jn-svc-attachments a:hover { text-decoration: underline; } +.jn-svc-att-size { color: var(--jn-text-light); font-size: var(--jn-fs-13); } + +.jn-svc-links { + display: flex; + gap: var(--jn-sp-3); + margin: var(--jn-sp-6) 0 0; + padding-top: var(--jn-sp-4); + border-top: 1px dashed var(--jn-border); +} +.jn-svc-links a { + padding: var(--jn-sp-1) var(--jn-sp-4); + border: 1px solid var(--jn-border); + border-radius: var(--jn-pill); + font-size: var(--jn-fs-13); + color: var(--jn-text-light); + transition: border-color var(--jn-speed) var(--jn-ease), color var(--jn-speed) var(--jn-ease); +} +.jn-svc-links a:hover { border-color: var(--jn-primary); color: var(--jn-primary); } + +/* 相关服务侧区 */ +.jn-svc-related { margin-top: var(--jn-sp-8); } +.jn-svc-related-list { margin-top: var(--jn-sp-3); } +.jn-svc-related-list li { border-bottom: 1px solid var(--jn-border); } +.jn-svc-related-list li:last-child { border-bottom: none; } +.jn-svc-related-list a { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--jn-sp-3); + padding: var(--jn-sp-3) var(--jn-sp-2); +} +.jn-svc-related-list li:hover { background: var(--jn-mint-bg); } +.jn-svc-related-name { + font-size: var(--jn-fs-15); + color: var(--jn-text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.jn-svc-related-list a:hover .jn-svc-related-name { color: var(--jn-primary); } +.jn-svc-related-meta { display: flex; align-items: center; gap: var(--jn-sp-2); flex: none; } +.jn-svc-related-meta > span:not(.jn-svc-tag) { color: var(--jn-text-light); font-size: var(--jn-fs-13); } + +/* --------------------------------------------------------------------- + 20. 页脚(薄荷友链带 + 翡翠深青多列主区 + 深色底条) + --------------------------------------------------------------------- */ +/* 友链带(浅薄荷底,无分组整段不渲染) */ +.jn-footer-links { + margin-top: var(--jn-sp-8); + background: var(--jn-mint-bg); + border-top: 1px solid var(--jn-border); +} +.jn-footer-links-inner { + max-width: var(--jn-max); + margin: 0 auto; + padding: var(--jn-sp-4) var(--jn-gutter); + display: flex; + flex-direction: column; + gap: var(--jn-sp-2); +} +.jn-links-group { + display: flex; + flex-wrap: wrap; + gap: var(--jn-sp-2) var(--jn-sp-4); + align-items: baseline; + font-size: var(--jn-fs-13); +} +.jn-group-name { + position: relative; + margin-right: var(--jn-sp-2); + padding-left: var(--jn-sp-3); + color: var(--jn-primary-dark); + font-weight: 600; +} +.jn-group-name::before { + content: ""; + position: absolute; + left: 0; + top: 50%; + width: 5px; + height: 5px; + margin-top: -2.5px; + border-radius: 50%; + background: var(--jn-accent); +} +.jn-links-group a { color: var(--jn-text-light); } +.jn-links-group a:hover { color: var(--jn-primary); } + +/* B4 友链 Logo:与名称并排小图 */ +.link-logo { + height: 20px; + width: auto; + max-width: 64px; + object-fit: contain; + vertical-align: middle; + margin-right: var(--jn-sp-1); + border-radius: 2px; + display: inline-block; +} + +/* 主区:翡翠深青 */ +.jn-footer { background: var(--jn-footer-bg); color: var(--jn-ink-soft); } + +.jn-footer-inner { + max-width: var(--jn-max); + margin: 0 auto; + padding: var(--jn-sp-8) var(--jn-gutter) var(--jn-sp-6); + display: grid; + grid-template-columns: minmax(0, 2fr) minmax(0, 3fr) auto; + gap: var(--jn-sp-8); + align-items: start; +} + +/* 品牌列:校徽 + 站名 + 社媒图标行 */ +.jn-footer-brand { min-width: 0; } +.jn-footer-logo-row { display: flex; align-items: center; gap: var(--jn-sp-3); margin-bottom: var(--jn-sp-4); } +.jn-footer-logo { height: 48px; width: auto; } +.jn-footer-badge { + flex: none; + display: inline-flex; + align-items: center; + justify-content: center; + width: 48px; + height: 48px; + border-radius: 50%; + color: var(--jn-ink); + background: rgba(255, 255, 255, .12); +} +.jn-footer-site { + font-size: var(--jn-fs-20); + font-weight: 600; + color: var(--jn-ink); + letter-spacing: 1px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* 社媒图标(config social_*,有值才渲染;描边圆 hover 反白) */ +.jn-social { display: flex; gap: var(--jn-sp-3); } +.jn-social-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + border: 1px solid var(--jn-ink-faint); + border-radius: 50%; + color: var(--jn-ink-soft); + transition: background var(--jn-speed) var(--jn-ease), color var(--jn-speed) var(--jn-ease), + border-color var(--jn-speed) var(--jn-ease); +} +.jn-social-icon:hover { + background: var(--jn-ink); + border-color: var(--jn-ink); + color: var(--jn-footer-bg); +} + +/* 信息列:多校区地址 + 联系/版权/备案 */ +.jn-footer-info { font-size: var(--jn-fs-13); line-height: 2; min-width: 0; } +.jn-footer-addr { margin: 0 0 var(--jn-sp-2); padding: 0; list-style: none; } +.jn-footer-addr li { display: flex; align-items: baseline; gap: var(--jn-sp-2); color: var(--jn-ink-soft); } +.jn-footer-addr li::before { + content: ""; + flex: none; + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--jn-accent); + transform: translateY(-2px); +} +.jn-footer-line { margin: 0; color: var(--jn-ink-soft); } +.jn-footer-info a { color: var(--jn-ink-soft); } +.jn-footer-info a:hover { color: var(--jn-ink); } + +/* 二维码列(config qr_wechat/qr_weibo,hover 轻抬) */ +.jn-footer-qr { display: flex; gap: var(--jn-sp-4); } +.jn-qr { margin: 0; text-align: center; } +.jn-qr img { + width: 96px; + height: 96px; + padding: var(--jn-sp-1); + background: var(--jn-ink); + border-radius: var(--jn-radius); + object-fit: contain; + transition: transform var(--jn-speed) var(--jn-ease); +} +.jn-qr:hover img { transform: translateY(-3px); } +.jn-qr figcaption { margin-top: var(--jn-sp-2); font-size: var(--jn-fs-12); color: var(--jn-ink-soft); } + +/* 底条(中性黑透明叠深,随 footerBg 参数自适应) */ +.jn-footer-bottom { background: rgba(0, 0, 0, .18); } +.jn-footer-bottom-inner { + max-width: var(--jn-max); + margin: 0 auto; + padding: var(--jn-sp-3) var(--jn-gutter); + text-align: center; + font-size: var(--jn-fs-13); + color: var(--jn-ink-faint); +} +.jn-footer-bottom-inner p { margin: var(--jn-sp-1) 0; } + +/* --------------------------------------------------------------------- + 21. 响应式(≤1024 折中 / ≤768 单列 + 导航折叠) + --------------------------------------------------------------------- */ +@media (max-width: 1024px) { + .jn-headline { grid-template-columns: minmax(0, 1fr); } + .jn-blocks { grid-template-columns: minmax(0, 1fr); } + .jn-split { grid-template-columns: minmax(0, 1fr); } + .jn-block-list--two { grid-template-columns: minmax(0, 1fr); } + .jn-quick-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } + .jn-fusion-row { grid-template-columns: repeat(4, minmax(0, 1fr)); } + .jn-footer-inner { grid-template-columns: minmax(0, 1fr) auto; } + .jn-footer-brand { grid-column: 1 / -1; } +} + +@media (max-width: 768px) { + :root { --jn-gutter: 16px; } + + /* 顶条:居中收敛 */ + .jn-topbar-inner { justify-content: center; } + .jn-topbar-side { display: none; } + + /* 品牌行:纵向堆叠,搜索通栏 */ + .jn-brandbar-inner { flex-direction: column; align-items: stretch; gap: var(--jn-sp-3); padding: var(--jn-sp-3) var(--jn-gutter); } + .jn-brand { justify-content: center; } + .jn-logo { height: 42px; } + .jn-site-name { font-size: var(--jn-fs-20); text-align: center; } + .jn-tools { justify-content: center; } + .jn-search { width: 100%; } + .jn-search input { flex: 1; width: auto; min-width: 0; } + + /* 主导航折叠(checkbox 纯 CSS) */ + .jn-nav-btn { display: flex; } + .jn-nav > ul { + display: none; + flex-direction: column; + padding: 0 var(--jn-gutter) var(--jn-sp-2); + } + .jn-nav-fold:checked ~ ul { display: flex; } /* label 在 ul 前,兄弟选择器展开 */ + .jn-nav > ul > li > a { width: 100%; height: auto; padding: var(--jn-sp-3) var(--jn-sp-4); font-size: var(--jn-fs-15); } + .jn-nav > ul > li > a::after { display: none; } + .jn-nav > ul > li:hover > a { background: var(--jn-primary-dark); } + /* 触屏无 hover:二级静态平铺 */ + .jn-sub { + display: block; + position: static; + min-width: 0; + padding: 0; + background: var(--jn-primary-dark); + border: none; + border-radius: 0; + box-shadow: none; + } + .jn-sub li a { color: var(--jn-ink-soft); padding: var(--jn-sp-2) var(--jn-sp-4) var(--jn-sp-2) var(--jn-sp-8); } + .jn-sub li a:hover { background: rgba(255, 255, 255, .08); color: var(--jn-ink); padding-left: var(--jn-sp-8); } + .jn-sub li.active a { color: var(--jn-ink); } + + /* banner:4:3 竖构图收敛 */ + .jn-banner-slides { aspect-ratio: 4 / 3; max-height: none; } + .jn-banner-title { font-size: var(--jn-fs-16); bottom: var(--jn-sp-6); padding: var(--jn-sp-2) var(--jn-sp-4); } + .jn-banner-arrow { display: none; } + + /* 首页区块单列 */ + .jn-wall, .jn-shots { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .jn-quick-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .jn-fusion-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .jn-block, .jn-page-card { padding: var(--jn-sp-4) var(--jn-sp-3); } + .jn-block-head h2, .jn-section-title { font-size: var(--jn-fs-20); } + + /* 列表/详情:侧栏置顶横滑 */ + .jn-page-cols { flex-direction: column; gap: var(--jn-sp-3); } + .jn-side-nav { width: 100%; } + .jn-side-nav-list { display: flex; overflow-x: auto; -webkit-overflow-scrolling: touch; } + .jn-side-nav-item { flex: none; } + .jn-side-nav-item + .jn-side-nav-item { border-top: none; border-left: 1px dashed var(--jn-border); } + .jn-side-nav-item a { white-space: nowrap; padding: var(--jn-sp-3) var(--jn-sp-4); } + .jn-side-nav-item.active a { border-left: none; border-bottom: 3px solid var(--jn-accent); padding-left: var(--jn-sp-4); } + + .jn-item { flex-direction: column; } + .jn-item-cover { width: 100%; } + .jn-article-title { font-size: var(--jn-fs-24); } + .jn-sibling { grid-template-columns: minmax(0, 1fr); } + + /* 服务中心 */ + .jn-svc-toolbar { flex-direction: column; align-items: stretch; } + .jn-svc-search input { width: auto; flex: 1; min-width: 0; } + .jn-svc-filter-group { flex-direction: column; gap: var(--jn-sp-1); } + .jn-svc-filter-label { width: auto; padding-top: 0; } + .jn-svc-item { flex-direction: column; gap: var(--jn-sp-2); } + .jn-svc-item-cover { width: 100%; height: 120px; } + .jn-svc-info th { width: 5.5em; } + .jn-svc-related-list a { flex-direction: column; align-items: flex-start; } + + /* 页脚单列 */ + .jn-footer-inner { grid-template-columns: minmax(0, 1fr); gap: var(--jn-sp-4); } + .jn-footer-brand { grid-column: auto; } + .jn-footer-logo-row { justify-content: center; } + .jn-footer-qr { justify-content: center; } +} + +/* --------------------------------------------------------------------- + 22. 打印样式(公告高频打印场景:去导航/页脚/交互件,正文降噪) + --------------------------------------------------------------------- */ +@media print { + .jn-topbar, .jn-brandbar, .jn-nav, .jn-banner, + .jn-footer-links, .jn-footer, .jn-sibling, .jn-pagination, + .jn-side-nav, .jn-search, .jn-colleges, .jn-svc-apply, + .jn-svc-filters, .jn-svc-toolbar, .jn-svc-related, .skip-link { display: none !important; } + + body { background: #fff; color: #000; font-size: 12pt; } + .jn-page-card { border: none; box-shadow: none; padding: 0; margin: 0; max-width: 100%; } + .jn-article-title { font-size: 20pt; } + .jn-article-content { font-size: 11.5pt; line-height: 1.8; } + .jn-article-content p { text-indent: 2em; } + .jn-article-content table th { background: #eee !important; } + a { color: inherit; } +} diff --git a/src/main/resources/templates/themes/jade-normal/assets/favicon.png b/src/main/resources/templates/themes/jade-normal/assets/favicon.png new file mode 100644 index 0000000..822653c Binary files /dev/null and b/src/main/resources/templates/themes/jade-normal/assets/favicon.png differ diff --git a/src/main/resources/templates/themes/jade-normal/assets/js/main.js b/src/main/resources/templates/themes/jade-normal/assets/js/main.js new file mode 100644 index 0000000..815d823 --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/assets/js/main.js @@ -0,0 +1,88 @@ +/* jade-normal(师大青)皮肤包脚本:顶条日期 + 首页轮播(自动播放/圆点/箭头/悬停暂停/键盘),无任何外部依赖。 + 选择器与 main.css / home.html 的 jn-* 类名一一对应;导航折叠由 CSS(checkbox + label)承担,无需 JS。 */ +(function () { + /* 顶条日期(本地时间,YYYY年M月D日 星期X) */ + var dateEl = document.getElementById('siteDate'); + if (dateEl) { + var now = new Date(); + var week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()]; + dateEl.textContent = now.getFullYear() + '年' + (now.getMonth() + 1) + '月' + + now.getDate() + '日 星期' + week; + } + + /* 轮播(.jn-banner,见 home.html) */ + var root = document.querySelector('.jn-banner'); + var slides = document.querySelectorAll('.jn-banner-slide'); + var dots = document.querySelectorAll('.jn-banner-dots button'); + var prevBtn = document.querySelector('.jn-banner-arrow.prev'); + var nextBtn = document.querySelector('.jn-banner-arrow.next'); + if (!slides.length || !root) { + return; + } + var current = 0; + var timer = null; + var INTERVAL = 5000; + + function show(index) { + slides[current].classList.remove('active'); + if (dots[current]) { + dots[current].classList.remove('active'); + } + current = (index + slides.length) % slides.length; + slides[current].classList.add('active'); + if (dots[current]) { + dots[current].classList.add('active'); + } + } + + function start() { + stop(); + if (slides.length > 1) { + timer = window.setInterval(function () { + show(current + 1); + }, INTERVAL); + } + } + + function stop() { + if (timer) { + window.clearInterval(timer); + timer = null; + } + } + + dots.forEach(function (dot, index) { + dot.addEventListener('click', function () { + show(index); + start(); + }); + }); + if (prevBtn) { + prevBtn.addEventListener('click', function () { + show(current - 1); + start(); + }); + } + if (nextBtn) { + nextBtn.addEventListener('click', function () { + show(current + 1); + start(); + }); + } + root.addEventListener('mouseenter', stop); + root.addEventListener('mouseleave', start); + root.addEventListener('focusin', stop); + root.addEventListener('focusout', start); + root.setAttribute('tabindex', '-1'); + root.addEventListener('keydown', function (e) { + if (e.key === 'ArrowLeft') { + show(current - 1); + start(); + } else if (e.key === 'ArrowRight') { + show(current + 1); + start(); + } + }); + + start(); +})(); diff --git a/src/main/resources/templates/themes/jade-normal/assets/screenshot.png b/src/main/resources/templates/themes/jade-normal/assets/screenshot.png new file mode 100644 index 0000000..f3991bc Binary files /dev/null and b/src/main/resources/templates/themes/jade-normal/assets/screenshot.png differ diff --git a/src/main/resources/templates/themes/jade-normal/detail.html b/src/main/resources/templates/themes/jade-normal/detail.html new file mode 100644 index 0000000..f27c7a7 --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/detail.html @@ -0,0 +1,76 @@ + + + + +
+ +
+
+ + + +
+ + +
+

文章标题

+ + +
正文
+
+ + +
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/jade-normal/fragments/footer.html b/src/main/resources/templates/themes/jade-normal/fragments/footer.html new file mode 100644 index 0000000..e360e93 --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/fragments/footer.html @@ -0,0 +1,105 @@ + + + + + diff --git a/src/main/resources/templates/themes/jade-normal/fragments/head.html b/src/main/resources/templates/themes/jade-normal/fragments/head.html new file mode 100644 index 0000000..be2097f --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/fragments/head.html @@ -0,0 +1,26 @@ + + + + + + + 页面标题 + + + + + + + + + + + + + + + diff --git a/src/main/resources/templates/themes/jade-normal/fragments/header.html b/src/main/resources/templates/themes/jade-normal/fragments/header.html new file mode 100644 index 0000000..0dd0d83 --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/fragments/header.html @@ -0,0 +1,89 @@ + + + +
+ + + +
+
+ 加载日期… +
+
+ + 专业院系 + + + +
+
+
+
+ + +
+
+
+ + + + 站点名称 +
+
+ + + 服务中心 + + +
+
+
+ + + +
+ diff --git a/src/main/resources/templates/themes/jade-normal/fragments/home-blocks.html b/src/main/resources/templates/themes/jade-normal/fragments/home-blocks.html new file mode 100644 index 0000000..0e17cf2 --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/fragments/home-blocks.html @@ -0,0 +1,316 @@ + + +
+
+
+
+

校园要闻

+ 更多 +
+ + + + +
+
+
+
+ + +
+
+
+

媒体聚焦

+ 更多 +
+ + +
+
+
+
+ + +
+
+
+

通知公告

+ 更多 +
+ + +
+
+
+
+ + +
+
+

图片新闻

+ 更多 +
+ + +
+
+
+ + +
+
+
+

栏目名

+ 更多 +
+ + + +
+
+
+
+ + +
+
+ 要闻速递 + +
+
+ + + + + +
+
+
+

快捷通道

+
+ +

分组

+ +
+
+
+ + +
+

栏目暂无内容

+

内容发布后将在此展示

+
diff --git a/src/main/resources/templates/themes/jade-normal/guide.html b/src/main/resources/templates/themes/jade-normal/guide.html new file mode 100644 index 0000000..c482165 --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/guide.html @@ -0,0 +1,133 @@ + + + + +
+ + +
+
+ + + +
+

事项服务暂时不可用,请稍后再试

+

事项数据服务暂不可达,稍后刷新即可恢复

+
+ +
+

事项名称

+ + + +
+ 我要办理 + 进入服务大厅在线办理 +
+ +

简介

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事项基本信息
服务对象服务对象
事项类别事项类别
办理地点办理地点
办理时限办理时限
承诺时限承诺时限
咨询电话咨询电话
监督投诉监督投诉电话
+ +
+

办理流程

+
办理流程
+
+
+

所需材料

+
所需材料
+
+
+

注意事项

+
注意事项
+
+ +
+

相关材料下载

+ +
+ + +
+ + +
+
+ + + + + diff --git a/src/main/resources/templates/themes/jade-normal/home.html b/src/main/resources/templates/themes/jade-normal/home.html new file mode 100644 index 0000000..b7fdb58 --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/home.html @@ -0,0 +1,147 @@ + + + + +
+ +
+ +
+ + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

头条推荐

+
+ +
+ +
+
+ + +
+
+
+
+

栏目名

+ 更多 +
+ +
+

栏目暂无内容

+

内容发布后将在此展示

+
+
+
+
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/jade-normal/list.html b/src/main/resources/templates/themes/jade-normal/list.html new file mode 100644 index 0000000..57d09d3 --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/list.html @@ -0,0 +1,114 @@ + + + + +
+ + +
+
+ + + +
+ + + +

栏目名

+

搜索词

+ +
    + +
  • +
    + + + +
    + +

    摘要

    +
    + + 置顶 +
    +
    +
    +
    + + + 01 + 2026-01 + +
    +
    + 文章标题 + +
    +

    摘要

    +
    + 置顶 +
    +
    +
    +
  • +
+
+

未找到相关内容

+

栏目暂无内容

+

换个关键词试试

+

内容发布后将在此展示

+
+ + + +
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/jade-normal/service.html b/src/main/resources/templates/themes/jade-normal/service.html new file mode 100644 index 0000000..d766b6d --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/service.html @@ -0,0 +1,111 @@ + + + + +
+ + +
+
+ + +

服务中心

+ + +
+

事项服务暂时不可用,请稍后再试

+

事项数据服务暂不可达,稍后刷新即可恢复

+
+ +
+
+ 服务对象 + +
+
+ 事项类别 + +
+
+ 服务部门 + +
+
+ +
+ + 清除筛选 +
+ + +
+

未找到符合条件的服务事项

+

服务中心暂未上架事项

+

换个筛选条件或关键词试试

+

事项发布后将在此展示

+
+ + + +
+
+ + + + + diff --git a/src/main/resources/templates/themes/jade-normal/single.html b/src/main/resources/templates/themes/jade-normal/single.html new file mode 100644 index 0000000..e63d749 --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/single.html @@ -0,0 +1,50 @@ + + + + +
+ +
+
+ + + +
+ + +
+

栏目名

+ +
单页内容
+
+

页面暂无内容

+

内容编辑后将在此展示

+
+
+
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/jade-normal/theme.json b/src/main/resources/templates/themes/jade-normal/theme.json new file mode 100644 index 0000000..0fcb53e --- /dev/null +++ b/src/main/resources/templates/themes/jade-normal/theme.json @@ -0,0 +1,30 @@ +{ + "specVersion": 1, + "name": "jade-normal", + "title": "师大青(jade-normal)", + "version": "1.0.0", + "author": "yunhai", + "description": "翡翠青+暖橙点缀的师范院校风(设计语言参考信阳师范大学官网)。", + "screenshot": "assets/screenshot.png", + "bannerSize": "1920x560", + "params": [ + { "key": "primary", "cssVar": "--jn-primary", "label": "主色·翡翠青", "type": "color", "default": "#008D3F" }, + { "key": "primaryDark", "cssVar": "--jn-primary-dark", "label": "主色加深", "type": "color", "default": "#04682E" }, + { "key": "primaryLight", "cssVar": "--jn-primary-light","label": "主色提亮", "type": "color", "default": "#35B371" }, + { "key": "accent", "cssVar": "--jn-accent", "label": "点缀橙·日期徽标", "type": "color", "default": "#F18D00" }, + { "key": "navBg", "cssVar": "--jn-nav-bg", "label": "主导航条底色", "type": "color", "default": "#008D3F" }, + { "key": "footerBg", "cssVar": "--jn-footer-bg", "label": "页脚底色", "type": "color", "default": "#04682E" }, + { "key": "text", "cssVar": "--jn-text", "label": "正文文字色", "type": "color", "default": "#2E3A33" }, + { "key": "textLight", "cssVar": "--jn-text-light", "label": "次要文字色", "type": "color", "default": "#6E7F75" }, + { "key": "bg", "cssVar": "--jn-bg", "label": "页面底色", "type": "color", "default": "#F4FAF6" }, + { "key": "cardBg", "cssVar": "--jn-card-bg", "label": "卡片底色", "type": "color", "default": "#FFFFFF" }, + { "key": "border", "cssVar": "--jn-border", "label": "边框色", "type": "color", "default": "#DFEEE5" }, + { "key": "mintBg", "cssVar": "--jn-mint-bg", "label": "薄荷底·背景带", "type": "color", "default": "#E7F6EE" }, + { "key": "listLayout", "label": "列表页形态", "type": "select", "default": "badge", + "options": [ + { "value": "badge", "label": "日期徽标行(橙色日徽)" }, + { "value": "plain", "label": "通栏行式(日期右置)" } + ] + } + ] +} diff --git a/src/main/resources/templates/themes/poly-blue/README.md b/src/main/resources/templates/themes/poly-blue/README.md new file mode 100644 index 0000000..2874693 --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/README.md @@ -0,0 +1,56 @@ +# poly-blue(理工蓝) + +理工院校风皮肤包:以 `default` 为基座派生,配色与首页区块形态按浙江理工大学官网(www.zstu.edu.cn)设计语言重做 +(仅学设计语言,不复制实现)。配了 `home_layout` 的站点,首页正文区块由本主题 `fragments/home-blocks.html` 渲染—— +派生包不自带区块形态时,正文会落到 `themes/common` 的通用骨架,换肤就只剩页头页脚(线上事故根因,见《审计验收清单-20260919》)。 + +## 风格定位 + +- 主色深宝蓝 `#0558a5` + 加深 `#124489` + 提亮 `#258cff` + 活力橙 `#ff7b00`(热词/来源徽标/「更多」与 hover 强调)+ 绿色小标签 `#1c7b46`。 +- 头部为「深宝蓝通栏品牌行(校名 + 受众标签 + 搜索框带热门搜索词)+ 白底吸顶主导航(当前栏目主色下划线)」; + 页脚深宝蓝 `#124489` 多列(品牌+社媒 / 多校区地址 / 二维码位)+ 更深色 `#0b2f5c` 底条。 +- 工艺:全局 radius 6px、间距阶梯 4/8/12/16/24/32/48、字号阶梯 12-36、hover 过渡 0.2s ease、 + 焦点态 outline 2px primaryLight、卡片 hover 阴影抬升;渐变仅 2 处且均为功能性文字遮罩(轮播标题/图片墙标题); + 无玻璃拟态、无粉紫、无大圆角。列表无封面行用 46px 日期方块(日大号 + 年月小号,主色底白字)。 +- `headerStyle` select 参数:`banner`(默认,通栏横幅头图完整形态)/ `plain`(收起受众行与热词、压低品牌行的简洁顶栏)。 + +## 参数取值建议(theme_params,13 个) + +| key | 默认 | 建议 | +| -- | -- | -- | +| `primary` | `#0558a5` | 品牌行/下划线/日期方块主色;改浅不建议超过 `#1a6cc5`,否则白字对比不足 | +| `primaryDark` | `#124489` | 页脚主底;与 footerBg 联动改 | +| `primaryLight` | `#258cff` | hover 链接/焦点描边;与 primary 拉开明度差 | +| `accent` | `#ff7b00` | 活力橙:热词圆点/来源徽标/更多按钮 hover;可换校方第二识别色(如 `#e60012` 红),保持高饱和 | +| `secondary` | `#1c7b46` | 绿色小标签(可在线办理等正向态),建议保持绿系 | +| `navBg` | `#ffffff` | 主导航底色;保持白或极浅色,深色会破坏「白底吸顶」形态 | +| `footerBg` | `#124489` | 页脚主底;底条为固定更深色 `#0b2f5c`(派生令牌) | +| `text` / `textLight` | `#2f3a47` / `#708090` | 正文/次要文字 | +| `bg` | `#f5f8fc` | 页面底色;偏蓝灰的浅底最有「理工」味,可换 `#f7f9fb` 提亮 | +| `cardBg` / `border` | `#ffffff` / `#e2e8f2` | 卡片底/分隔线 | +| `headerStyle` | `banner` | 结构开关:`plain` = 简洁顶栏(受众行/热词隐藏、品牌行压低) | + +## 首页区块形态(布局模式与回落模式同构) + +| homeStyle / type | 呈现 | 类名 | +| -- | -- | -- | +| `news_grid` | 双栏要闻:左 3 份大图文头条卡(16:9 封面 + 标题 + 摘要 + 日期/来源元信息)、右 2 份校园经纬紧凑行(圆点 + 日期右对齐);区块背景可取站点 `news_bg_image` | `pb-split` / `pb-news-*` / `pb-brief-*` | +| `compact` | 通知公告:46px 日期方块(日大号 + 年月小号,主色底白字)+ 标题行 | `pb-notice-item` / `pb-date-chip` | +| `media_focus` | 媒体理工:来源徽标(活力橙小 tag)+ 双列密行 | `pb-media-*` / `pb-src--tag` | +| `image_wall` | 四列图片墙:封面 + 底部渐变遮罩标题,hover 抬图 | `pb-wall` | +| (空/未知) | 整宽区块卡:头条 + 行式列表 | `pb-block--flow` | +| `ticker` | 主蓝要闻速递横条(单行不换行、超长省略,中文不塌列) | `pb-ticker*` | +| `gallery` | 线上展厅:居中双语文区头 + 四列图墙 | `pb-gallery` | +| `links` | 快捷通道:图标宫格卡(主色描边浅底,整卡 hover 反白填色) | `pb-channels` / `pb-channel` | + +## 契约要点 + +- 结构类前缀 `pb-`,CSS 变量前缀 `--pb-`;`:root` 把 `--pb-*` 别名到皮肤契约变量(`--primary`/`--text`/`--card-bg`/`--border`…), + 使 `themes/common` 兜底骨架与站点 `theme_params` 换色能穿透到首页区块。 +- 品牌行受众标签(考生/在校生/教职工/校友)为静态标签位:CMS 暂无受众分组数据源,不造空链接; + 热门搜索词经 `url.search(词, null)` 生成真实搜索链接。 +- 空态文案「栏目暂无内容」只在 `block.items` 为空时出现;守卫必须写在 `th:block` 外层—— + `th:replace`(优先级 100)先于 `th:if`(300)求值,写在同一标签上等于没写。 +- 绝对定位背景带层序:`.pb-sec-bg` z-index:0,其后首个 `.pb-block` z-index:1。 +- 响应式:≤992 收起左侧栏并单列;≤768 品牌行纵排 + 汉堡抽屉 + 二级手风琴;网格一律 `minmax(0,1fr)`(390px 不溢出)。 +- 门禁:`ThemeContractIT`(7 条路由)+ `./verify-theme.sh poly-blue`;受众标签/热词为静态文案属预期,非死链。 diff --git a/src/main/resources/templates/themes/poly-blue/assets/css/main.css b/src/main/resources/templates/themes/poly-blue/assets/css/main.css new file mode 100644 index 0000000..41584cb --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/assets/css/main.css @@ -0,0 +1,1593 @@ +/* ===================================================================== + poly-blue · 理工蓝(基座 default,设计语言参考浙江理工大学官网 zstu.edu.cn) + 设计语言:深宝蓝通栏品牌行(校名/受众/搜索热词)+ 白底吸顶主导航(当前项主色下划线) + + 通栏大图轮播(图上左下角标题渐变遮罩)+ 双栏要闻(左大图头条/右密行) + + 46px 日期方块通知 + 媒体来源徽标(活力橙)+ 快捷通道图标宫格 + + 深宝蓝多列页脚(更深色底条)。 + 工艺约束:全局 radius 6px;间距阶梯 4/8/12/16/24/32/48px;字号阶梯 12/13/14/15/16/18/20/24/28/36; + hover 过渡 0.2s ease;焦点态 outline 2px primaryLight;渐变仅 2 处且均为功能性文字遮罩 + (轮播标题遮罩 / 图片墙标题遮罩);无玻璃拟态、无粉紫、无大圆角。 + 色彩令牌全部走 CSS 变量,theme.json color 参数经 :root 覆盖真实生效。 + ===================================================================== */ + +/* --------------------------------------------------------------------- + 1. 设计令牌(与 theme.json params 一一对应,禁止出现未消费的声明) + --------------------------------------------------------------------- */ +:root { + --pb-primary: #0558a5; /* 主色:深宝蓝,品牌行/下划线/日期方块/强调 */ + --pb-primary-dark: #124489; /* 主色加深:页脚主底/深色端 */ + --pb-primary-light: #258cff; /* 主色提亮:hover 链接/焦点描边/角标 */ + --pb-accent: #ff7b00; /* 活力橙:热词/来源徽标/hover 强调 */ + --pb-secondary: #1c7b46; /* 绿色小标签:可在线办理等正向态 */ + --pb-nav-bg: #ffffff; /* 主导航条底色(白底吸顶) */ + --pb-footer-bg: #124489; /* 页脚主底 */ + --pb-text: #2f3a47; /* 正文 */ + --pb-text-light: #708090; /* 次要文字 */ + --pb-bg: #f5f8fc; /* 页面底色 */ + --pb-card-bg: #ffffff; /* 卡片底 */ + --pb-border: #e2e8f2; /* 边框/分隔线 */ + + /* 派生令牌(固定值,不进 theme.json;均由品牌色系推导,非粉紫) */ + --pb-footer-deep: #0b2f5c; /* 页脚底条更深色 */ + --pb-nav-ink: var(--pb-primary); /* 导航文字色 */ + --pb-ink-on-dark: #ffffff; /* 深底主文字 */ + --pb-ink-on-dark-soft: rgba(255,255,255,.78); + --pb-ink-on-dark-faint: rgba(255,255,255,.56); + --pb-mask: rgba(4,26,54,.78); /* 图上标题遮罩端色 */ + --pb-tint: rgba(5,88,165,.07); /* 主色极浅底(区块头部条/悬停底) */ + --pb-tint-strong: rgba(5,88,165,.14); + --pb-accent-tint: rgba(255,123,0,.10); + --pb-shadow-sm: 0 1px 4px rgba(9,47,88,.08); + --pb-shadow-md: 0 6px 16px rgba(9,47,88,.12); + --pb-shadow-lg: 0 12px 28px rgba(9,47,88,.18); + --pb-radius: 6px; /* 全局唯一主圆角(禁大圆角) */ + --pb-radius-sm: 4px; + --pb-speed: .2s ease; /* 统一 hover 过渡 */ + --pb-font: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Helvetica Neue", Arial, sans-serif; + + /* 间距阶梯(4/8/12/16/24/32/48)与字号阶梯(12/13/14/15/16/18/20/24/28/36) */ + --pb-sp-1: 4px; --pb-sp-2: 8px; --pb-sp-3: 12px; --pb-sp-4: 16px; + --pb-sp-6: 24px; --pb-sp-8: 32px; --pb-sp-12: 48px; + --pb-fz-xs: 12px; --pb-fz-sm: 13px; --pb-fz-md: 14px; --pb-fz-lg: 15px; + --pb-fz-xl: 16px; --pb-fz-2xl: 18px; --pb-fz-3xl: 20px; --pb-fz-4xl: 24px; + --pb-fz-5xl: 28px; --pb-fz-6xl: 36px; + + /* 皮肤契约别名:themes/common 兜底骨架与站点 theme_params 只认契约变量 + (--primary/--text/--text-light/--card-bg/--border/--bg/--radius)。 + 不别名过去,换肤就只换了页头页脚、首页区块仍是骨架内置色。 */ + --primary: var(--pb-primary); + --primary-dark: var(--pb-primary-dark); + --primary-light: var(--pb-primary-light); + --text: var(--pb-text); + --text-light: var(--pb-text-light); + --bg: var(--pb-bg); + --card-bg: var(--pb-card-bg); + --border: var(--pb-border); + --radius: var(--pb-radius); +} + +/* --------------------------------------------------------------------- + 2. Reset 与基础 + --------------------------------------------------------------------- */ +* { margin: 0; padding: 0; box-sizing: border-box; } + +html { -webkit-text-size-adjust: 100%; } + +body { + font-family: var(--pb-font); + font-size: var(--pb-fz-md); + line-height: 1.7; + color: var(--pb-text); + background: var(--pb-bg); + word-break: break-word; +} + +ul, ol { list-style: none; } + +a { color: var(--pb-primary); text-decoration: none; transition: color var(--pb-speed); } +a:hover { color: var(--pb-primary-light); } + +img { max-width: 100%; display: block; border: 0; } + +button { font-family: inherit; cursor: pointer; } + +input, button, select, textarea { font-size: inherit; color: inherit; } + +::selection { background: var(--pb-primary); color: #fff; } + +/* 焦点态可见:键盘聚焦统一 2px 提亮蓝描边 */ +a:focus-visible, +button:focus-visible, +input:focus-visible, +[tabindex]:focus-visible { + outline: 2px solid var(--pb-primary-light); + outline-offset: 2px; +} + +/* 跳转链接:仅键盘聚焦时可见 */ +.skip-link { + position: absolute; + left: -999px; + top: 0; + z-index: 300; + background: var(--pb-primary); + color: #fff; + padding: var(--pb-sp-2) var(--pb-sp-4); + border-radius: 0 0 var(--pb-radius-sm) 0; +} +.skip-link:focus { left: 0; color: #fff; } + +/* --------------------------------------------------------------------- + 3. 布局容器 + --------------------------------------------------------------------- */ +.pb-container { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 var(--pb-sp-4); } + +/* --------------------------------------------------------------------- + 4. 头部:深宝蓝通栏品牌行(校名 + 日期 + 专业院系 + 受众标签 + 搜索/热词) + --------------------------------------------------------------------- */ +.pb-brandbar { background: var(--pb-primary); color: var(--pb-ink-on-dark); } + +.pb-brandbar-inner { + max-width: 1200px; + margin: 0 auto; + padding: var(--pb-sp-4); + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--pb-sp-6); +} + +/* 品牌:校徽徽标 + 校名 */ +.pb-brand { display: flex; align-items: center; gap: var(--pb-sp-3); min-width: 0; } + +.pb-brand-badge { + flex: none; + width: 56px; + height: 56px; + display: flex; + align-items: center; + justify-content: center; + background: rgba(255,255,255,.12); + border: 1px solid rgba(255,255,255,.28); + border-radius: var(--pb-radius); + overflow: hidden; + transition: border-color var(--pb-speed); +} +.pb-brand:hover .pb-brand-badge { border-color: rgba(255,255,255,.6); } + +.pb-logo { width: 100%; height: 100%; object-fit: contain; } + +.pb-brand-badge--plain { color: var(--pb-ink-on-dark); } + +.pb-site-name { + color: var(--pb-ink-on-dark); + font-size: var(--pb-fz-4xl); + font-weight: 700; + letter-spacing: 2px; + line-height: 1.3; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + position: relative; +} +/* 校名下橙色短线:hover 展满(活力橙强调) */ +.pb-site-name::after { + content: ""; + position: absolute; + left: 0; + bottom: -4px; + width: 48px; + height: 3px; + background: var(--pb-accent); + transition: width var(--pb-speed); +} +.pb-site-name:hover { color: var(--pb-ink-on-dark); } +.pb-site-name:hover::after { width: 100%; } + +/* 品牌行右侧:上排(日期/院系/受众)+ 下排(搜索/热词) */ +.pb-brand-side { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: var(--pb-sp-2); } + +.pb-brand-tools { display: flex; align-items: center; gap: var(--pb-sp-3); font-size: var(--pb-fz-sm); color: var(--pb-ink-on-dark-soft); } + +.pb-date { white-space: nowrap; color: var(--pb-ink-on-dark-faint); } + +/* 专业院系下拉(无子站整块不渲染;悬停/键盘焦点展开) */ +.pb-colleges { position: relative; } + +.pb-colleges-toggle { display: inline-flex; align-items: center; gap: var(--pb-sp-1); color: var(--pb-ink-on-dark-soft); cursor: pointer; line-height: 1; } +.pb-colleges-toggle a { color: var(--pb-ink-on-dark-soft); } +.pb-colleges-toggle a:hover { color: var(--pb-ink-on-dark); } + +.pb-colleges-arrow { font-style: normal; font-size: var(--pb-fz-xs); transition: transform var(--pb-speed); } +.pb-colleges:hover .pb-colleges-arrow { transform: rotate(180deg); } + +.pb-colleges-menu { + position: absolute; + top: 100%; + right: 0; + min-width: 180px; + background: var(--pb-card-bg); + border: 1px solid var(--pb-border); + border-radius: var(--pb-radius); + box-shadow: var(--pb-shadow-md); + padding: var(--pb-sp-1) 0; + opacity: 0; + visibility: hidden; + transform: translateY(var(--pb-sp-1)); + transition: opacity var(--pb-speed), transform var(--pb-speed), visibility var(--pb-speed); + z-index: 120; +} +.pb-colleges:hover .pb-colleges-menu, +.pb-colleges:focus-within .pb-colleges-menu { opacity: 1; visibility: visible; transform: translateY(0); } + +.pb-colleges-menu li + li { border-top: 1px solid var(--pb-border); } + +.pb-colleges-menu a { + display: block; + padding: var(--pb-sp-2) var(--pb-sp-4); + color: var(--pb-text); + font-size: var(--pb-fz-sm); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: background var(--pb-speed), color var(--pb-speed), padding-left var(--pb-speed); +} +.pb-colleges-menu a:hover { background: var(--pb-tint); color: var(--pb-primary); padding-left: var(--pb-sp-6); } +.pb-colleges-menu li.active a { + color: var(--pb-primary); + font-weight: 600; + border-left: 3px solid var(--pb-accent); + padding-left: calc(var(--pb-sp-4) - 3px); +} + +/* 受众标签(静态标签位:CMS 暂无受众分组数据源,不造空链接) */ +.pb-audience { display: flex; align-items: center; gap: var(--pb-sp-2); padding-left: var(--pb-sp-3); border-left: 1px solid rgba(255,255,255,.22); } + +.pb-audience-item { color: var(--pb-ink-on-dark-soft); font-size: var(--pb-fz-sm); position: relative; padding: 0 var(--pb-sp-1); } +.pb-audience-item + .pb-audience-item::before { + content: ""; + position: absolute; + left: -5px; + top: 50%; + transform: translateY(-50%); + width: 1px; + height: 10px; + background: rgba(255,255,255,.22); +} + +/* 搜索行:白底圆角搜索框 + 热门搜索词(橙点前缀) */ +.pb-search-row { display: flex; align-items: center; gap: var(--pb-sp-3); } + +.pb-search { + display: flex; + align-items: center; + width: 280px; + background: var(--pb-card-bg); + border-radius: var(--pb-radius); + overflow: hidden; + border: 1px solid transparent; + transition: box-shadow var(--pb-speed), border-color var(--pb-speed); +} +.pb-search:focus-within { border-color: var(--pb-accent); box-shadow: 0 0 0 3px var(--pb-accent-tint); } + +.pb-search input { flex: 1; min-width: 0; border: 0; padding: var(--pb-sp-2) var(--pb-sp-3); font-size: var(--pb-fz-sm); color: var(--pb-text); background: transparent; } +.pb-search input::placeholder { color: var(--pb-text-light); } +.pb-search input:focus { outline: none; } + +.pb-search button { + flex: none; + display: inline-flex; + align-items: center; + gap: var(--pb-sp-1); + border: 0; + background: var(--pb-accent); + color: #fff; + font-size: var(--pb-fz-sm); + padding: var(--pb-sp-2) var(--pb-sp-4); + transition: background var(--pb-speed); +} +.pb-search button:hover { background: #ff9430; } + +.pb-hotwords { display: flex; align-items: center; gap: var(--pb-sp-2); font-size: var(--pb-fz-xs); color: var(--pb-ink-on-dark-faint); white-space: nowrap; } + +.pb-hotwords a { color: var(--pb-ink-on-dark-soft); position: relative; padding-left: var(--pb-sp-2); } +.pb-hotwords a::before { + content: ""; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 4px; + height: 4px; + border-radius: 50%; + background: var(--pb-accent); +} +.pb-hotwords a:hover { color: var(--pb-accent); } + +/* --------------------------------------------------------------------- + 5. 白底吸顶主导航:当前栏目主色下划线高亮;hover 提亮;下拉主色面板 + --------------------------------------------------------------------- */ +.pb-nav { background: var(--pb-nav-bg); border-bottom: 1px solid var(--pb-border); box-shadow: var(--pb-shadow-sm); } + +.pb-nav-inner { max-width: 1200px; margin: 0 auto; padding: 0 var(--pb-sp-4); display: flex; align-items: center; } + +/* 汉堡按钮:≤768 显示 */ +.pb-nav-toggle { + display: none; + flex: none; + width: 40px; + height: 40px; + border: 1px solid var(--pb-border); + border-radius: var(--pb-radius-sm); + background: transparent; + margin: var(--pb-sp-2) 0; +} +.pb-nav-toggle span { display: block; width: 18px; height: 2px; margin: 3px auto; background: var(--pb-primary); border-radius: 1px; transition: transform var(--pb-speed), opacity var(--pb-speed); } + +.pb-nav-list { display: flex; align-items: stretch; flex-wrap: wrap; min-width: 0; } + +.pb-nav-list > li { position: relative; } + +.pb-nav-list > li > a { + display: inline-flex; + align-items: center; + gap: var(--pb-sp-1); + padding: var(--pb-sp-4) var(--pb-sp-3); + color: var(--pb-nav-ink); + font-size: var(--pb-fz-lg); + font-weight: 600; + position: relative; + transition: color var(--pb-speed), background var(--pb-speed); +} +/* 当前栏目:主色下划线(hover 同步生长) */ +.pb-nav-list > li > a::after { + content: ""; + position: absolute; + left: 50%; + bottom: 0; + width: 0; + height: 3px; + background: var(--pb-primary); + transform: translateX(-50%); + transition: width var(--pb-speed); +} +.pb-nav-list > li > a:hover { color: var(--pb-primary-light); background: var(--pb-tint); } +.pb-nav-list > li > a:hover::after, +.pb-nav-list > li.active > a::after { width: 100%; } +.pb-nav-list > li.active > a { color: var(--pb-primary); } + +.pb-caret { font-style: normal; font-size: var(--pb-fz-xs); color: var(--pb-text-light); transition: transform var(--pb-speed); } +.pb-nav-list > li:hover .pb-caret { transform: rotate(180deg); color: var(--pb-primary-light); } + +/* 二级下拉:主色实底面板 + 顶部橙色亮线;悬停/键盘焦点展开 */ +.pb-sub { + position: absolute; + top: 100%; + left: 0; + min-width: 200px; + background: var(--pb-primary); + border-top: 3px solid var(--pb-accent); + border-radius: 0 0 var(--pb-radius) var(--pb-radius); + box-shadow: var(--pb-shadow-md); + padding: var(--pb-sp-1) 0; + opacity: 0; + visibility: hidden; + transform: translateY(var(--pb-sp-1)); + transition: opacity var(--pb-speed), transform var(--pb-speed), visibility var(--pb-speed); + z-index: 110; +} +.pb-nav-list > li:hover > .pb-sub, +.pb-nav-list > li:focus-within > .pb-sub { opacity: 1; visibility: visible; transform: translateY(0); } + +.pb-sub li + li { border-top: 1px solid rgba(255,255,255,.10); } + +.pb-sub a { + display: block; + padding: var(--pb-sp-2) var(--pb-sp-4) var(--pb-sp-2) var(--pb-sp-6); + color: var(--pb-ink-on-dark-soft); + font-size: var(--pb-fz-sm); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + position: relative; +} +.pb-sub a::before { + content: ""; + position: absolute; + left: var(--pb-sp-4); + top: 50%; + transform: translateY(-50%); + width: 4px; + height: 4px; + border-radius: 50%; + background: var(--pb-accent); + opacity: .65; + transition: opacity var(--pb-speed); +} +.pb-sub a:hover { color: var(--pb-ink-on-dark); background: var(--pb-primary-light); } +.pb-sub a:hover::before { opacity: 1; } +.pb-sub li.active > a { color: var(--pb-ink-on-dark); background: var(--pb-primary-light); font-weight: 600; } + +/* 吸顶态(main.js 加 .pb-nav--fixed 并插入等高 .pb-nav-holder 占位) */ +.pb-nav-holder { width: 100%; } + +.pb-nav--fixed { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 200; + box-shadow: var(--pb-shadow-md); + animation: pb-nav-drop var(--pb-speed); +} +@keyframes pb-nav-drop { + from { transform: translateY(-4px); opacity: .6; } + to { transform: translateY(0); opacity: 1; } +} + +/* --------------------------------------------------------------------- + 6. headerStyle=plain 变体(themeParams select,root class 切换): + 收起受众行与热词、压低品牌行高度——简洁顶栏形态 + --------------------------------------------------------------------- */ +.pb-header--plain .pb-brandbar-inner { padding-top: var(--pb-sp-3); padding-bottom: var(--pb-sp-3); } +.pb-header--plain .pb-brand-badge { width: 44px; height: 44px; } +.pb-header--plain .pb-site-name { font-size: var(--pb-fz-3xl); } +.pb-header--plain .pb-audience, +.pb-header--plain .pb-hotwords, +.pb-header--plain .pb-date { display: none; } +.pb-header--plain .pb-brand-side { gap: 0; } +.pb-header--plain .pb-search { width: 220px; } + +/* --------------------------------------------------------------------- + 7. 首页轮播:通栏大图 + 图上左下角标题渐变遮罩(功能性渐变 1/2) + --------------------------------------------------------------------- */ +.pb-banner { position: relative; overflow: hidden; background: var(--pb-primary-dark); } + +.pb-banner-slides { position: relative; aspect-ratio: 1920 / 560; } + +.pb-banner-slide { + position: absolute; + inset: 0; + opacity: 0; + visibility: hidden; + transition: opacity .45s ease, visibility .45s ease; +} +.pb-banner-slide.active { opacity: 1; visibility: visible; position: relative; } + +.pb-banner-slide img { width: 100%; height: 100%; object-fit: cover; } + +/* 图上左下角标题:功能性渐变遮罩保证白字可读(非装饰渐变) */ +.pb-banner-title { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: var(--pb-sp-12) var(--pb-sp-12) var(--pb-sp-6); + background: linear-gradient(to top, var(--pb-mask), rgba(4,26,54,0)); + color: #fff; + font-size: var(--pb-fz-4xl); + font-weight: 700; + letter-spacing: 1px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.pb-banner-slide:hover .pb-banner-title { color: #fff; } + +.pb-banner-arrow { + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 48px; + height: 48px; + border: 0; + border-radius: 50%; + background: rgba(4,26,54,.42); + color: #fff; + font-size: var(--pb-fz-4xl); + line-height: 1; + transition: background var(--pb-speed); + z-index: 5; +} +.pb-banner-arrow:hover { background: var(--pb-primary); } +.pb-banner-arrow.prev { left: var(--pb-sp-6); } +.pb-banner-arrow.next { right: var(--pb-sp-6); } + +.pb-banner-dots { position: absolute; right: var(--pb-sp-6); bottom: var(--pb-sp-4); display: flex; gap: var(--pb-sp-2); z-index: 5; } +.pb-banner-dots button { width: 28px; height: 4px; border: 0; border-radius: 2px; background: rgba(255,255,255,.46); transition: background var(--pb-speed), width var(--pb-speed); } +.pb-banner-dots button:hover { background: rgba(255,255,255,.8); } +.pb-banner-dots button.active { background: var(--pb-accent); width: 40px; } + +/* --------------------------------------------------------------------- + 8. 首页区块公共件:节容器 / 区块卡 / 标题行(色条+底线)/ 更多钩子 + --------------------------------------------------------------------- */ +.pb-home { padding-bottom: var(--pb-sp-12); } + +.pb-section { padding: var(--pb-sp-12) 0 0; position: relative; } + +/* 绝对定位背景带层序:背景 z-index:0,其后首个区块 z-index:1(层序契约) */ +.pb-sec-bg { position: absolute; inset: 0; background-size: cover; background-position: center; background-repeat: no-repeat; opacity: .16; z-index: 0; pointer-events: none; } +.pb-sec-bg + .pb-block { position: relative; z-index: 1; } + +/* 结构钩子(模板结构类:基类/容器/变体标记,仅布局语义) */ +.pb-header { position: relative; } +.pb-block--flow { display: block; width: 100%; } +.pb-footer-brand { min-width: 0; } +.pb-hotwords-label { color: var(--pb-ink-on-dark-faint); } +.pb-svc-guide-body, +.pb-svc-unavailable { min-width: 0; } + +.pb-block { background: var(--pb-card-bg); border: 1px solid var(--pb-border); border-radius: var(--pb-radius); box-shadow: var(--pb-shadow-sm); padding: var(--pb-sp-4) var(--pb-sp-6) var(--pb-sp-6); } + +/* 区块标题行:左侧主色竖条 + 标题,右侧「更多 +」钩子(hover 橙) */ +.pb-block-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--pb-sp-4); + border-bottom: 1px solid var(--pb-border); + padding-bottom: var(--pb-sp-3); + margin-bottom: var(--pb-sp-4); +} + +.pb-block-head h2 { + position: relative; + padding-left: var(--pb-sp-3); + font-size: var(--pb-fz-3xl); + font-weight: 700; + color: var(--pb-text); + line-height: 1.4; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.pb-block-head h2::before { + content: ""; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 4px; + height: 18px; + border-radius: 2px; + background: var(--pb-primary); +} +/* 标题行下橙色短线(活力橙点缀) */ +.pb-block-head h2::after { + content: ""; + position: absolute; + left: 0; + bottom: -13px; + width: 48px; + height: 2px; + background: var(--pb-accent); +} + +.pb-more { + flex: none; + font-size: var(--pb-fz-sm); + color: var(--pb-text-light); + padding: var(--pb-sp-1) var(--pb-sp-2); + border: 1px solid var(--pb-border); + border-radius: var(--pb-radius-sm); + transition: color var(--pb-speed), border-color var(--pb-speed), background var(--pb-speed); +} +.pb-more:hover { color: var(--pb-accent); border-color: var(--pb-accent); background: var(--pb-accent-tint); } + +/* 小徽标:置顶(主色底白字) */ +.pb-top-badge { + flex: none; + display: inline-block; + background: var(--pb-primary); + color: #fff; + font-size: var(--pb-fz-xs); + line-height: 1; + padding: 3px var(--pb-sp-1); + border-radius: var(--pb-radius-sm); +} + +/* 来源徽标:正文态(主色文字 + 极浅底);tag 态(媒体理工:橙系小 tag) */ +.pb-src { + display: inline-block; + font-size: var(--pb-fz-xs); + color: var(--pb-primary); + background: var(--pb-tint-strong); + border-radius: var(--pb-radius-sm); + padding: 2px var(--pb-sp-1); + line-height: 1.5; +} +.pb-src--tag { color: var(--pb-accent); background: var(--pb-accent-tint); border: 1px solid rgba(255,123,0,.28); } + +/* 元信息行(日期/来源/置顶) */ +.pb-news-meta { display: flex; align-items: center; gap: var(--pb-sp-2); font-size: var(--pb-fz-xs); color: var(--pb-text-light); flex-wrap: wrap; } + +/* 中文防塌列契约(回归测试检查项,照 academic-navy 同款规则) */ +.pb-ticker-list { min-width: 0; white-space: nowrap; } +.pb-ticker-item { flex: none; text-overflow: ellipsis; } +.pb-block-item-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; } + +/* 空态 */ +.pb-empty { padding: var(--pb-sp-12) var(--pb-sp-4); text-align: center; color: var(--pb-text-light); background: var(--pb-tint); border: 1px dashed var(--pb-border); border-radius: var(--pb-radius); } +.pb-empty p { font-size: var(--pb-fz-lg); } +.pb-empty-hint { font-size: var(--pb-fz-sm); margin-top: var(--pb-sp-1); } + +/* --------------------------------------------------------------------- + 9. 形态一 news_grid:双栏要闻——左 3 份大图文头条卡 / 右 2 份紧凑密行 + --------------------------------------------------------------------- */ +.pb-split { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: var(--pb-sp-6); align-items: start; } + +/* 左:大图文头条卡(16:9 封面 + 标题 + 摘要 + 日期来源元信息) */ +.pb-news-lead > a { + display: block; + border: 1px solid var(--pb-border); + border-radius: var(--pb-radius); + overflow: hidden; + background: var(--pb-card-bg); + transition: box-shadow var(--pb-speed), transform var(--pb-speed), border-color var(--pb-speed); +} +.pb-news-lead > a:hover { box-shadow: var(--pb-shadow-md); transform: translateY(-2px); border-color: var(--pb-primary-light); } + +.pb-news-cover { display: block; aspect-ratio: 16 / 9; overflow: hidden; background: var(--pb-tint); } +.pb-news-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .3s ease; } +.pb-news-lead > a:hover .pb-news-cover img { transform: scale(1.04); } + +.pb-news-body { display: block; padding: var(--pb-sp-3) var(--pb-sp-4) var(--pb-sp-4); } + +.pb-news-title { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: var(--pb-fz-xl); + font-weight: 700; + color: var(--pb-text); + line-height: 1.5; + margin-bottom: var(--pb-sp-2); + transition: color var(--pb-speed); +} +.pb-news-lead > a:hover .pb-news-title { color: var(--pb-primary); } + +.pb-news-summary { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: var(--pb-fz-sm); + color: var(--pb-text-light); + line-height: 1.8; + margin-bottom: var(--pb-sp-3); +} + +/* 右:校园经纬紧凑列表(圆点前缀 + 日期右对齐) */ +.pb-brief-list { + border: 1px solid var(--pb-border); + border-radius: var(--pb-radius); + background: var(--pb-card-bg); + padding: var(--pb-sp-2) var(--pb-sp-4); +} + +.pb-brief-item { display: flex; align-items: center; gap: var(--pb-sp-2); padding: var(--pb-sp-2) 0; min-width: 0; } +.pb-brief-item + .pb-brief-item { border-top: 1px dashed var(--pb-border); } + +.pb-brief-dot { flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--pb-border); transition: background var(--pb-speed), transform var(--pb-speed); } +.pb-brief-item:hover .pb-brief-dot { background: var(--pb-accent); transform: scale(1.3); } + +.pb-brief-item .pb-block-item-title { flex: 1; font-size: var(--pb-fz-sm); color: var(--pb-text); white-space: nowrap; transition: color var(--pb-speed); } +.pb-brief-item:hover .pb-block-item-title { color: var(--pb-primary-light); } + +.pb-item-date { flex: none; font-size: var(--pb-fz-xs); color: var(--pb-text-light); font-variant-numeric: tabular-nums; } + +/* --------------------------------------------------------------------- + 10. 形态三 compact:通知公告日期方块行(46px「日大号 + 年月小号」,主色底白字) + --------------------------------------------------------------------- */ +.pb-date-chip { + flex: none; + width: 46px; + height: 46px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background: var(--pb-primary); + color: #fff; + border-radius: var(--pb-radius-sm); + line-height: 1.15; + transition: background var(--pb-speed); +} +.pb-date-chip b { font-size: var(--pb-fz-3xl); font-weight: 700; } +.pb-date-chip i { font-style: normal; font-size: var(--pb-fz-xs); opacity: .82; } + +.pb-notice-list li + li { border-top: 1px dashed var(--pb-border); } + +.pb-notice-item { display: flex; align-items: center; gap: var(--pb-sp-3); padding: var(--pb-sp-3) 0; min-width: 0; } +.pb-notice-item:hover .pb-date-chip { background: var(--pb-primary-light); } + +.pb-notice-item .pb-block-item-title { flex: 1; font-size: var(--pb-fz-md); color: var(--pb-text); white-space: nowrap; transition: color var(--pb-speed); } +.pb-notice-item:hover .pb-block-item-title { color: var(--pb-primary-light); } + +/* --------------------------------------------------------------------- + 11. 形态四 media_focus:媒体理工——来源徽标(橙系小 tag)+ 双列密行 + --------------------------------------------------------------------- */ +.pb-media-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--pb-sp-12); } + +.pb-media-item { display: flex; align-items: center; gap: var(--pb-sp-2); padding: var(--pb-sp-2) 0; border-bottom: 1px dashed var(--pb-border); min-width: 0; } + +.pb-media-item .pb-src--tag { flex: none; max-width: 30%; overflow: hidden; white-space: nowrap; } + +.pb-media-item .pb-block-item-title { flex: 1; font-size: var(--pb-fz-sm); color: var(--pb-text); white-space: nowrap; transition: color var(--pb-speed); } +.pb-media-item:hover .pb-block-item-title { color: var(--pb-accent); } + +/* --------------------------------------------------------------------- + 12. 形态五 image_wall / gallery:四列图片墙 + 底部渐变遮罩标题(功能性渐变 2/2) + --------------------------------------------------------------------- */ +.pb-wall { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--pb-sp-4); } + +.pb-wall-item > a { + position: relative; + display: block; + border-radius: var(--pb-radius); + overflow: hidden; + aspect-ratio: 4 / 3; + background: var(--pb-tint); + box-shadow: var(--pb-shadow-sm); + transition: box-shadow var(--pb-speed), transform var(--pb-speed); +} +.pb-wall-item > a:hover { box-shadow: var(--pb-shadow-md); transform: translateY(-3px); } + +.pb-wall-item img { width: 100%; height: 100%; object-fit: cover; transition: transform .3s ease; } +.pb-wall-item > a:hover img { transform: scale(1.05); } + +/* 底部渐变遮罩标题:功能性文字保护(非装饰渐变) */ +.pb-wall-cap { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: var(--pb-sp-8) var(--pb-sp-3) var(--pb-sp-2); + background: linear-gradient(to top, var(--pb-mask), rgba(4,26,54,0)); + color: #fff; + font-size: var(--pb-fz-sm); + line-height: 1.5; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.pb-wall-item > a:hover .pb-wall-cap { color: #fff; } + +/* 线上展厅:居中双语文区头 */ +.pb-gallery { text-align: center; } + +.pb-gallery-head { margin-bottom: var(--pb-sp-4); } + +.pb-gallery-title { justify-content: center; border-bottom: 0; padding-bottom: 0; margin-bottom: var(--pb-sp-1); } +.pb-gallery-title h2::after { left: 50%; transform: translateX(-50%); bottom: -5px; } + +.pb-gallery-sub { font-size: var(--pb-fz-sm); color: var(--pb-text-light); letter-spacing: 2px; } + +.pb-wall--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } + +/* --------------------------------------------------------------------- + 13. 布局模式 ticker:要闻速递横条(主色底白字,单行不换行,中文不塌列) + --------------------------------------------------------------------- */ +.pb-ticker { margin-top: var(--pb-sp-8); background: var(--pb-primary); color: var(--pb-ink-on-dark); } + +.pb-ticker-inner { display: flex; align-items: center; gap: var(--pb-sp-4); padding-top: var(--pb-sp-2); padding-bottom: var(--pb-sp-2); } + +.pb-ticker-label { + flex: none; + position: relative; + font-size: var(--pb-fz-lg); + font-weight: 700; + padding: var(--pb-sp-1) var(--pb-sp-4) var(--pb-sp-1) var(--pb-sp-3); + background: var(--pb-accent); + border-radius: var(--pb-radius-sm); + color: #fff; +} +.pb-ticker-label::before, +.pb-ticker-label::after { + content: ""; + position: absolute; + top: 50%; + width: 5px; + height: 5px; + border-radius: 50%; + background: #fff; + opacity: .85; + transform: translateY(-50%); +} +.pb-ticker-label::before { left: -3px; } +.pb-ticker-label::after { right: -3px; } + +.pb-ticker-list { display: flex; align-items: center; gap: var(--pb-sp-6); overflow: hidden; flex: 1; } +.pb-ticker-list li { min-width: 0; } + +.pb-ticker-item { + flex: none; + display: inline-block; + max-width: 360px; + color: var(--pb-ink-on-dark-soft); + font-size: var(--pb-fz-sm); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.pb-ticker-item:hover { color: var(--pb-ink-on-dark); text-decoration: underline; text-underline-offset: 3px; } + +/* --------------------------------------------------------------------- + 14. 布局模式 links:快捷通道图标宫格(主色描边 hover 填色) + --------------------------------------------------------------------- */ +.pb-channel-group { font-size: var(--pb-fz-sm); font-weight: 600; color: var(--pb-text-light); margin: var(--pb-sp-2) 0; } +.pb-channel-group:first-of-type { margin-top: 0; } + +.pb-channels { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--pb-sp-3); } + +.pb-channel { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--pb-sp-2); + padding: var(--pb-sp-4) var(--pb-sp-2); + border: 1px solid var(--pb-border); + border-radius: var(--pb-radius); + background: var(--pb-card-bg); + transition: border-color var(--pb-speed), background var(--pb-speed), box-shadow var(--pb-speed), transform var(--pb-speed); +} +.pb-channel:hover { border-color: var(--pb-primary); background: var(--pb-primary); color: #fff; box-shadow: var(--pb-shadow-md); transform: translateY(-2px); } + +/* 图标位:主色描边浅底,整卡 hover 反白(描边填色语义) */ +.pb-channel-icon { + width: 52px; + height: 52px; + display: flex; + align-items: center; + justify-content: center; + color: var(--pb-primary); + border: 1px solid var(--pb-primary); + border-radius: var(--pb-radius); + background: var(--pb-tint); + transition: color var(--pb-speed), background var(--pb-speed), border-color var(--pb-speed); +} +.pb-channel:hover .pb-channel-icon { color: var(--pb-primary); background: #fff; border-color: #fff; } + +.pb-channel-name { + font-size: var(--pb-fz-sm); + color: var(--pb-text); + max-width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: color var(--pb-speed); +} +.pb-channel:hover .pb-channel-name { color: #fff; } + +/* --------------------------------------------------------------------- + 15. 回落模式首页(无 home_layout):头条推荐 + 图片新闻双栏 + 栏目区块网格 + --------------------------------------------------------------------- */ +.pb-headline { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: var(--pb-sp-6); align-items: start; } + +.pb-headline-card, +.pb-focus-card { background: var(--pb-card-bg); border: 1px solid var(--pb-border); border-radius: var(--pb-radius); box-shadow: var(--pb-shadow-sm); padding: var(--pb-sp-4) var(--pb-sp-6) var(--pb-sp-6); } + +.pb-headline-list li { display: flex; align-items: center; gap: var(--pb-sp-2); padding: var(--pb-sp-2) 0; min-width: 0; } +.pb-headline-list li + li { border-top: 1px dashed var(--pb-border); } + +.pb-headline-list a { + flex: 1; + min-width: 0; + color: var(--pb-text); + font-size: var(--pb-fz-md); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.pb-headline-list a:hover { color: var(--pb-primary-light); } + +.pb-headline-list time { flex: none; font-size: var(--pb-fz-xs); color: var(--pb-text-light); font-variant-numeric: tabular-nums; } + +.pb-headline-lead { padding-bottom: var(--pb-sp-3); } + +.pb-lead-title { display: block; font-size: var(--pb-fz-xl); font-weight: 700; color: var(--pb-text); line-height: 1.6; } +.pb-lead-title:hover { color: var(--pb-primary); } + +.pb-lead-meta { display: flex; align-items: center; gap: var(--pb-sp-2); margin-top: var(--pb-sp-2); font-size: var(--pb-fz-xs); color: var(--pb-text-light); } + +/* 图片新闻:首条大图 + 缩略行 */ +.pb-focus-lead { + display: block; + border-radius: var(--pb-radius); + overflow: hidden; + position: relative; + aspect-ratio: 16 / 9; + background: var(--pb-tint); + box-shadow: var(--pb-shadow-sm); +} +.pb-focus-lead img { width: 100%; height: 100%; object-fit: cover; } +.pb-focus-lead:hover img { opacity: .92; } + +/* 图片新闻首图封面容器(撑满 16:9 链接位) */ +.pb-focus-cover { display: block; width: 100%; height: 100%; overflow: hidden; } + +/* 图上标题用纯色半透明底带(非渐变,保证全文件渐变恰为 2 处功能性遮罩) */ +.pb-focus-title { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: var(--pb-sp-2) var(--pb-sp-3); + background: var(--pb-mask); + color: #fff; + font-size: var(--pb-fz-lg); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.pb-focus-lead:hover .pb-focus-title { color: #fff; } + +.pb-focus-rows { margin-top: var(--pb-sp-3); display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--pb-sp-1); } + +.pb-focus-rows li + li { border-top: 1px dashed var(--pb-border); } + +.pb-focus-rows a { display: flex; align-items: center; gap: var(--pb-sp-2); padding: var(--pb-sp-2) 0; min-width: 0; } + +.pb-row-cover { flex: none; width: 84px; height: 56px; border-radius: var(--pb-radius-sm); overflow: hidden; background: var(--pb-tint); } +.pb-row-cover img { width: 100%; height: 100%; object-fit: cover; } + +.pb-row-title { + flex: 1; + min-width: 0; + font-size: var(--pb-fz-sm); + color: var(--pb-text); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.pb-focus-rows a:hover .pb-row-title { color: var(--pb-primary-light); } + +/* 栏目区块网格(回落模式) */ +.pb-blocks { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--pb-sp-6); } + +/* 区块内头条(feat):行式图文 */ +.pb-feat { border-bottom: 1px solid var(--pb-border); padding-bottom: var(--pb-sp-3); margin-bottom: var(--pb-sp-2); } + +.pb-feat > a { display: flex; gap: var(--pb-sp-3); min-width: 0; } + +.pb-feat-cover { flex: none; width: 160px; aspect-ratio: 16 / 9; border-radius: var(--pb-radius-sm); overflow: hidden; background: var(--pb-tint); } +.pb-feat-cover img { width: 100%; height: 100%; object-fit: cover; } + +.pb-feat-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--pb-sp-1); } + +.pb-feat-title { + font-size: var(--pb-fz-lg); + font-weight: 700; + color: var(--pb-text); + line-height: 1.5; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.pb-feat > a:hover .pb-feat-title { color: var(--pb-primary); } + +.pb-feat-summary { + font-size: var(--pb-fz-sm); + color: var(--pb-text-light); + line-height: 1.7; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +/* 默认卡行式列表(card 形态) */ +.pb-block-list li + li { border-top: 1px dashed var(--pb-border); } + +.pb-block-item { display: flex; align-items: center; gap: var(--pb-sp-2); padding: var(--pb-sp-2) 0; min-width: 0; } + +.pb-item-tick { flex: none; width: 5px; height: 5px; background: var(--pb-border); transform: rotate(45deg); transition: background var(--pb-speed); } +.pb-block-item:hover .pb-item-tick { background: var(--pb-accent); } + +.pb-block-item .pb-block-item-title { flex: 1; font-size: var(--pb-fz-sm); color: var(--pb-text); white-space: nowrap; transition: color var(--pb-speed); } +.pb-block-item:hover .pb-block-item-title { color: var(--pb-primary-light); } + +.pb-block-item .pb-item-date { font-size: var(--pb-fz-xs); } + +/* --------------------------------------------------------------------- + 16. 列表/详情/单页/搜索:双栏(左侧栏 + 页卡)与页内组件 + --------------------------------------------------------------------- */ +.pb-page { padding: var(--pb-sp-6) 0 var(--pb-sp-12); } + +.pb-cols { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: var(--pb-sp-6); align-items: start; } + +/* 左侧栏目导航(sideNav 为空不渲染,窄屏栅格降级为单列) */ +.pb-side-nav { background: var(--pb-card-bg); border: 1px solid var(--pb-border); border-radius: var(--pb-radius); overflow: hidden; box-shadow: var(--pb-shadow-sm); } + +.pb-side-nav-head { background: var(--pb-primary); color: #fff; font-size: var(--pb-fz-lg); font-weight: 700; padding: var(--pb-sp-3) var(--pb-sp-4); } + +.pb-side-nav-list { padding: var(--pb-sp-2) 0; } + +.pb-side-nav-item a { + display: block; + padding: var(--pb-sp-2) var(--pb-sp-4); + color: var(--pb-text); + font-size: var(--pb-fz-sm); + position: relative; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: background var(--pb-speed), color var(--pb-speed), padding-left var(--pb-speed); +} +.pb-side-nav-item a:hover { background: var(--pb-tint); color: var(--pb-primary); padding-left: var(--pb-sp-6); } +.pb-side-nav-item.active a { + color: var(--pb-primary); + font-weight: 700; + background: var(--pb-tint-strong); + border-left: 3px solid var(--pb-accent); + padding-left: calc(var(--pb-sp-4) - 3px); +} + +/* 页卡 */ +.pb-page-card { background: var(--pb-card-bg); border: 1px solid var(--pb-border); border-radius: var(--pb-radius); box-shadow: var(--pb-shadow-sm); padding: var(--pb-sp-6); min-width: 0; } + +/* 面包屑 */ +.pb-crumb { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--pb-sp-2); + font-size: var(--pb-fz-sm); + color: var(--pb-text-light); + padding-bottom: var(--pb-sp-3); + border-bottom: 1px solid var(--pb-border); + margin-bottom: var(--pb-sp-4); +} +.pb-crumb a { color: var(--pb-text-light); } +.pb-crumb a:hover { color: var(--pb-primary-light); } +.pb-crumb .crumb-parent { color: var(--pb-text-light); } + +.pb-crumb-sep { color: var(--pb-border); } + +.pb-crumb-current { color: var(--pb-primary); font-weight: 600; } + +.pb-page-title { + font-size: var(--pb-fz-3xl); + font-weight: 700; + color: var(--pb-text); + padding-left: var(--pb-sp-3); + border-left: 4px solid var(--pb-primary); + line-height: 1.4; + margin-bottom: var(--pb-sp-6); + word-break: break-word; +} + +/* 文章列表:有封面图文行 / 无封面日期方块行 */ +.pb-article-list > li + li { border-top: 1px solid var(--pb-border); } + +.pb-article-row { display: flex; gap: var(--pb-sp-4); padding: var(--pb-sp-4) 0; min-width: 0; } + +.pb-item-cover { flex: none; width: 200px; aspect-ratio: 16 / 9; border-radius: var(--pb-radius); overflow: hidden; background: var(--pb-tint); } +.pb-item-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .3s ease; } +.pb-article-row:hover .pb-item-cover img { transform: scale(1.04); } + +.pb-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--pb-sp-2); } + +.pb-item-title a { font-size: var(--pb-fz-xl); font-weight: 600; color: var(--pb-text); line-height: 1.6; transition: color var(--pb-speed); } +.pb-item-title a:hover { color: var(--pb-primary-light); } + +.pb-item-summary { + font-size: var(--pb-fz-sm); + color: var(--pb-text-light); + line-height: 1.8; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.pb-item-meta { display: flex; align-items: center; gap: var(--pb-sp-2); font-size: var(--pb-fz-xs); color: var(--pb-text-light); } + +/* 无封面:日期方块行 */ +.pb-article-line { display: flex; align-items: flex-start; gap: var(--pb-sp-3); padding: var(--pb-sp-3) 0; min-width: 0; } +.pb-article-line .pb-date-chip { margin-top: 2px; } + +.pb-line-main { flex: 1; min-width: 0; } + +.pb-line-main .pb-block-item-title { display: block; font-size: var(--pb-fz-md); font-weight: 600; color: var(--pb-text); white-space: nowrap; transition: color var(--pb-speed); } +.pb-article-line:hover .pb-block-item-title { color: var(--pb-primary-light); } +.pb-article-line:hover .pb-date-chip { background: var(--pb-primary-light); } + +.pb-line-main .pb-item-summary { margin-top: var(--pb-sp-1); } + +.pb-line-side { flex: none; padding-top: 2px; } + +/* 分页 */ +.pb-pagination { display: flex; justify-content: center; align-items: center; flex-wrap: wrap; gap: var(--pb-sp-1); margin-top: var(--pb-sp-8); } + +.pb-pagination a { + min-width: 32px; + height: 32px; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0 var(--pb-sp-2); + border: 1px solid var(--pb-border); + border-radius: var(--pb-radius-sm); + color: var(--pb-text); + font-size: var(--pb-fz-sm); + background: var(--pb-card-bg); + transition: color var(--pb-speed), border-color var(--pb-speed), background var(--pb-speed); +} +.pb-pagination a:hover { color: var(--pb-primary); border-color: var(--pb-primary); } +.pb-pagination a.active { background: var(--pb-primary); border-color: var(--pb-primary); color: #fff; font-weight: 600; } +.pb-pagination a.disabled { color: var(--pb-text-light); opacity: .5; pointer-events: none; } + +/* --------------------------------------------------------------------- + 17. 详情页:标题/元信息/正文排版/上下篇 + --------------------------------------------------------------------- */ +.pb-article { min-width: 0; } + +.pb-article-title { + font-size: var(--pb-fz-4xl); + font-weight: 700; + color: var(--pb-text); + line-height: 1.5; + text-align: center; + margin-bottom: var(--pb-sp-4); + word-break: break-word; +} + +.pb-article-meta { + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + gap: var(--pb-sp-3); + padding: var(--pb-sp-3) 0; + border-top: 1px solid var(--pb-border); + border-bottom: 1px solid var(--pb-border); + font-size: var(--pb-fz-xs); + color: var(--pb-text-light); + margin-bottom: var(--pb-sp-6); +} + +/* 富文本正文(jsoup 白名单清洗后直出)排版 */ +.pb-article-content { font-size: var(--pb-fz-lg); line-height: 2; color: var(--pb-text); } +.pb-article-content p { margin: var(--pb-sp-3) 0; } +.pb-article-content h2, +.pb-article-content h3, +.pb-article-content h4 { margin: var(--pb-sp-6) 0 var(--pb-sp-3); color: var(--pb-text); line-height: 1.5; } +.pb-article-content h2 { font-size: var(--pb-fz-3xl); border-left: 4px solid var(--pb-primary); padding-left: var(--pb-sp-2); } +.pb-article-content h3 { font-size: var(--pb-fz-xl); } +.pb-article-content h4 { font-size: var(--pb-fz-lg); } +.pb-article-content img { margin: var(--pb-sp-3) auto; border-radius: var(--pb-radius-sm); } +.pb-article-content a { color: var(--pb-primary); text-decoration: underline; text-underline-offset: 3px; } +.pb-article-content ul, +.pb-article-content ol { margin: var(--pb-sp-3) 0; padding-left: var(--pb-sp-6); } +.pb-article-content ul li { list-style: disc; } +.pb-article-content ol li { list-style: decimal; } +.pb-article-content blockquote { + margin: var(--pb-sp-4) 0; + padding: var(--pb-sp-3) var(--pb-sp-4); + background: var(--pb-tint); + border-left: 4px solid var(--pb-primary-light); + border-radius: 0 var(--pb-radius-sm) var(--pb-radius-sm) 0; + color: var(--pb-text-light); +} +.pb-article-content table { width: 100%; border-collapse: collapse; margin: var(--pb-sp-4) 0; font-size: var(--pb-fz-sm); } +.pb-article-content th, +.pb-article-content td { border: 1px solid var(--pb-border); padding: var(--pb-sp-2) var(--pb-sp-3); text-align: left; } +.pb-article-content th { background: var(--pb-tint); color: var(--pb-text); font-weight: 600; } + +/* 上下篇 */ +.pb-sibling { margin-top: var(--pb-sp-8); padding-top: var(--pb-sp-4); border-top: 1px solid var(--pb-border); display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--pb-sp-4); } + +.pb-sibling a, +.pb-sib-none { + display: flex; + flex-direction: column; + gap: var(--pb-sp-1); + padding: var(--pb-sp-3) var(--pb-sp-4); + border: 1px solid var(--pb-border); + border-radius: var(--pb-radius); + background: var(--pb-card-bg); + transition: border-color var(--pb-speed), box-shadow var(--pb-speed); +} +.pb-sibling a:hover { border-color: var(--pb-primary-light); box-shadow: var(--pb-shadow-sm); } + +.pb-sibling .next { grid-column: 2; text-align: right; } + +.pb-sib-label { font-size: var(--pb-fz-xs); color: var(--pb-primary); font-weight: 600; } + +.pb-sib-title { font-size: var(--pb-fz-sm); color: var(--pb-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.pb-sibling a:hover .pb-sib-title { color: var(--pb-primary-light); } + +.pb-sib-none .pb-sib-title { color: var(--pb-text-light); } + +/* --------------------------------------------------------------------- + 18. 服务中心 / 事项指南(svc 页族) + --------------------------------------------------------------------- */ +.pb-svc-page { min-width: 0; } + +.pb-svc-filters { border: 1px solid var(--pb-border); border-radius: var(--pb-radius); padding: var(--pb-sp-3) var(--pb-sp-4); margin-bottom: var(--pb-sp-4); } + +.pb-svc-filter-group { display: flex; align-items: flex-start; gap: var(--pb-sp-3); padding: var(--pb-sp-2) 0; } +.pb-svc-filter-group + .pb-svc-filter-group { border-top: 1px dashed var(--pb-border); } + +.pb-svc-filter-label { flex: none; font-size: var(--pb-fz-sm); font-weight: 600; color: var(--pb-text); padding-top: var(--pb-sp-1); } + +.pb-svc-filter-options { display: flex; flex-wrap: wrap; gap: var(--pb-sp-2); min-width: 0; } + +.pb-chip { + display: inline-flex; + align-items: center; + gap: var(--pb-sp-1); + padding: 3px var(--pb-sp-2); + border: 1px solid var(--pb-border); + border-radius: var(--pb-radius-sm); + font-size: var(--pb-fz-sm); + color: var(--pb-text); + background: var(--pb-card-bg); + transition: color var(--pb-speed), border-color var(--pb-speed), background var(--pb-speed); +} +.pb-chip em { font-style: normal; font-size: var(--pb-fz-xs); color: var(--pb-text-light); } +.pb-chip:hover { color: var(--pb-primary); border-color: var(--pb-primary); } +.pb-chip.active { background: var(--pb-primary); border-color: var(--pb-primary); color: #fff; } +.pb-chip.active em { color: rgba(255,255,255,.8); } + +.pb-svc-toolbar { display: flex; align-items: center; gap: var(--pb-sp-3); margin-bottom: var(--pb-sp-4); } + +.pb-svc-search { + display: flex; + width: min(420px, 100%); + border: 1px solid var(--pb-border); + border-radius: var(--pb-radius); + overflow: hidden; + transition: border-color var(--pb-speed), box-shadow var(--pb-speed); +} +.pb-svc-search:focus-within { border-color: var(--pb-primary-light); box-shadow: 0 0 0 3px var(--pb-tint-strong); } + +.pb-svc-search input { flex: 1; min-width: 0; border: 0; padding: var(--pb-sp-2) var(--pb-sp-3); font-size: var(--pb-fz-sm); } +.pb-svc-search input:focus { outline: none; } + +.pb-svc-search button { border: 0; background: var(--pb-primary); color: #fff; font-size: var(--pb-fz-sm); padding: var(--pb-sp-2) var(--pb-sp-6); transition: background var(--pb-speed); } +.pb-svc-search button:hover { background: var(--pb-primary-light); } + +.pb-svc-clear { font-size: var(--pb-fz-sm); color: var(--pb-text-light); text-decoration: underline; text-underline-offset: 3px; } +.pb-svc-clear:hover { color: var(--pb-accent); } + +/* 事项卡列表 */ +.pb-svc-list > li + li { border-top: 1px solid var(--pb-border); } + +.pb-svc-item { display: flex; gap: var(--pb-sp-4); padding: var(--pb-sp-4) 0; min-width: 0; } + +.pb-svc-item-cover { flex: none; width: 120px; aspect-ratio: 16 / 9; border-radius: var(--pb-radius-sm); overflow: hidden; background: var(--pb-tint); } +.pb-svc-item-cover img { width: 100%; height: 100%; object-fit: cover; } + +.pb-svc-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--pb-sp-2); } + +.pb-svc-item-title { display: flex; align-items: center; flex-wrap: wrap; gap: var(--pb-sp-2); min-width: 0; } + +.pb-svc-item-name { font-size: var(--pb-fz-lg); font-weight: 600; color: var(--pb-text); transition: color var(--pb-speed); } +.pb-svc-item:hover .pb-svc-item-name { color: var(--pb-primary-light); } + +.pb-tag { flex: none; font-size: var(--pb-fz-xs); color: var(--pb-primary); background: var(--pb-tint-strong); border-radius: var(--pb-radius-sm); padding: 2px var(--pb-sp-1); line-height: 1.5; } +.pb-tag.online { color: var(--pb-secondary); background: rgba(28,123,70,.10); } + +.pb-svc-item-summary { + font-size: var(--pb-fz-sm); + color: var(--pb-text-light); + line-height: 1.7; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.pb-svc-item-meta { display: flex; flex-wrap: wrap; gap: var(--pb-sp-3); font-size: var(--pb-fz-xs); color: var(--pb-text-light); } + +/* 指南页 */ +.pb-svc-guide { min-width: 0; } + +.pb-svc-apply { display: flex; align-items: center; gap: var(--pb-sp-3); margin-bottom: var(--pb-sp-4); } + +.pb-svc-apply-btn { + display: inline-flex; + align-items: center; + background: var(--pb-accent); + color: #fff; + font-size: var(--pb-fz-lg); + font-weight: 600; + padding: var(--pb-sp-2) var(--pb-sp-8); + border-radius: var(--pb-radius); + box-shadow: var(--pb-shadow-sm); + transition: background var(--pb-speed), box-shadow var(--pb-speed), transform var(--pb-speed); +} +.pb-svc-apply-btn:hover { background: #ff9430; color: #fff; box-shadow: var(--pb-shadow-md); transform: translateY(-1px); } + +.pb-svc-apply-hint { font-size: var(--pb-fz-sm); color: var(--pb-text-light); } + +.pb-svc-summary { + padding: var(--pb-sp-3) var(--pb-sp-4); + background: var(--pb-tint); + border-left: 4px solid var(--pb-primary-light); + border-radius: 0 var(--pb-radius-sm) var(--pb-radius-sm) 0; + font-size: var(--pb-fz-sm); + color: var(--pb-text-light); + margin-bottom: var(--pb-sp-4); +} + +.pb-svc-info { width: 100%; border-collapse: collapse; margin: var(--pb-sp-3) 0 var(--pb-sp-6); font-size: var(--pb-fz-sm); } +.pb-svc-info th, +.pb-svc-info td { border: 1px solid var(--pb-border); padding: var(--pb-sp-2) var(--pb-sp-3); text-align: left; vertical-align: top; } +.pb-svc-info th { width: 120px; background: var(--pb-tint); color: var(--pb-text); font-weight: 600; white-space: nowrap; } + +.pb-svc-section { margin-top: var(--pb-sp-6); } +.pb-svc-section h2 { font-size: var(--pb-fz-xl); color: var(--pb-text); padding-left: var(--pb-sp-3); border-left: 4px solid var(--pb-primary); margin-bottom: var(--pb-sp-3); line-height: 1.5; } + +.pb-svc-attachments ul { display: flex; flex-direction: column; gap: var(--pb-sp-2); } + +.pb-svc-attachments a { display: inline-flex; align-items: center; gap: var(--pb-sp-1); color: var(--pb-primary); font-size: var(--pb-fz-sm); } +.pb-svc-attachments a:hover { color: var(--pb-accent); text-decoration: underline; text-underline-offset: 3px; } + +.pb-svc-att-size { font-size: var(--pb-fz-xs); color: var(--pb-text-light); margin-left: var(--pb-sp-2); } + +.pb-svc-links { display: flex; flex-wrap: wrap; gap: var(--pb-sp-3); margin-top: var(--pb-sp-6); padding-top: var(--pb-sp-4); border-top: 1px dashed var(--pb-border); } +.pb-svc-links a { font-size: var(--pb-fz-sm); color: var(--pb-primary); padding: var(--pb-sp-1) var(--pb-sp-4); border: 1px solid var(--pb-primary); border-radius: var(--pb-radius-sm); transition: background var(--pb-speed), color var(--pb-speed); } +.pb-svc-links a:hover { background: var(--pb-primary); color: #fff; } + +.pb-svc-related { margin-top: var(--pb-sp-8); } + +.pb-svc-related-title { font-size: var(--pb-fz-xl); padding-left: var(--pb-sp-3); border-left: 4px solid var(--pb-primary); margin-bottom: var(--pb-sp-3); line-height: 1.5; } + +.pb-svc-related-list > li + li { border-top: 1px dashed var(--pb-border); } + +.pb-svc-related-list a { display: flex; align-items: center; justify-content: space-between; gap: var(--pb-sp-3); padding: var(--pb-sp-2) 0; min-width: 0; } + +.pb-svc-related-name { flex: 1; min-width: 0; font-size: var(--pb-fz-sm); color: var(--pb-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.pb-svc-related-list a:hover .pb-svc-related-name { color: var(--pb-primary-light); } + +.pb-svc-related-meta { flex: none; display: inline-flex; align-items: center; gap: var(--pb-sp-2); font-size: var(--pb-fz-xs); color: var(--pb-text-light); } + +/* --------------------------------------------------------------------- + 19. 页脚:深宝蓝多列(品牌+社媒 / 地址联系 / 二维码)+ 浅色友链层 + 更深色底条 + --------------------------------------------------------------------- */ +.pb-footer { margin-top: var(--pb-sp-12); background: var(--pb-footer-bg); color: var(--pb-ink-on-dark-soft); } + +.pb-footer-main { + display: grid; + grid-template-columns: minmax(0, 2fr) minmax(0, 2fr) auto; + gap: var(--pb-sp-12); + padding: var(--pb-sp-12) var(--pb-sp-4) var(--pb-sp-8); +} + +.pb-footer-logo-row { display: flex; align-items: center; gap: var(--pb-sp-3); min-width: 0; } + +.pb-footer-logo { + width: 52px; + height: 52px; + object-fit: contain; + background: rgba(255,255,255,.12); + border: 1px solid rgba(255,255,255,.28); + border-radius: var(--pb-radius); + padding: var(--pb-sp-1); +} + +.pb-footer-site { + font-size: var(--pb-fz-3xl); + font-weight: 700; + letter-spacing: 2px; + color: var(--pb-ink-on-dark); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.pb-social { display: flex; align-items: center; gap: var(--pb-sp-2); margin-top: var(--pb-sp-4); } + +.pb-social-icon { + width: 36px; + height: 36px; + display: inline-flex; + align-items: center; + justify-content: center; + color: var(--pb-ink-on-dark-soft); + border: 1px solid rgba(255,255,255,.28); + border-radius: var(--pb-radius); + transition: color var(--pb-speed), border-color var(--pb-speed), background var(--pb-speed), transform var(--pb-speed); +} +.pb-social-icon:hover { color: var(--pb-ink-on-dark); border-color: var(--pb-accent); background: var(--pb-accent); transform: translateY(-2px); } + +.pb-footer-info { min-width: 0; } + +.pb-footer-addr { display: flex; flex-direction: column; gap: var(--pb-sp-1); margin-bottom: var(--pb-sp-3); font-size: var(--pb-fz-sm); } +.pb-footer-addr li { position: relative; padding-left: var(--pb-sp-3); } +.pb-footer-addr li::before { + content: ""; + position: absolute; + left: 0; + top: 9px; + width: 5px; + height: 5px; + background: var(--pb-accent); + transform: rotate(45deg); +} + +.pb-footer-line { display: flex; align-items: baseline; gap: var(--pb-sp-2); font-size: var(--pb-fz-sm); line-height: 1.9; } + +.pb-dot { flex: none; width: 5px; height: 5px; border-radius: 50%; background: var(--pb-accent); transform: translateY(-2px); } + +.pb-footer-qr { display: flex; gap: var(--pb-sp-4); justify-content: flex-end; } + +.pb-qr { display: flex; flex-direction: column; align-items: center; gap: var(--pb-sp-2); } + +.pb-qr-frame { + display: block; + width: 96px; + height: 96px; + padding: var(--pb-sp-1); + background: #fff; + border-radius: var(--pb-radius); + overflow: hidden; + transition: transform var(--pb-speed), box-shadow var(--pb-speed); +} +.pb-qr:hover .pb-qr-frame { transform: scale(1.05); box-shadow: var(--pb-shadow-md); } +.pb-qr-frame img { width: 100%; height: 100%; object-fit: contain; } + +.pb-qr figcaption { font-size: var(--pb-fz-xs); color: var(--pb-ink-on-dark-faint); text-align: center; } + +/* 友链层:主底之上半透明白覆层(纯色叠加,非渐变) */ +.pb-footer-links { background: rgba(255,255,255,.05); border-top: 1px solid rgba(255,255,255,.12); } + +.pb-footer-links-inner { display: flex; flex-wrap: wrap; gap: var(--pb-sp-4) var(--pb-sp-12); padding: var(--pb-sp-4); } + +.pb-links-group { min-width: 0; } + +.pb-group-name { + display: inline-block; + font-size: var(--pb-fz-sm); + font-weight: 600; + color: var(--pb-ink-on-dark); + border-left: 3px solid var(--pb-accent); + padding-left: var(--pb-sp-2); + margin-bottom: var(--pb-sp-2); +} + +.pb-links-row { display: flex; flex-wrap: wrap; gap: var(--pb-sp-2) var(--pb-sp-4); } + +.pb-links-row a { display: inline-flex; align-items: center; gap: var(--pb-sp-1); color: var(--pb-ink-on-dark-soft); font-size: var(--pb-fz-sm); transition: color var(--pb-speed); } +.pb-links-row a:hover { color: var(--pb-accent); } + +.pb-link-logo { width: 16px; height: 16px; object-fit: contain; } + +/* 底条:更深色 */ +.pb-footer-bottom { background: var(--pb-footer-deep); } + +.pb-footer-bottom-inner { display: flex; justify-content: center; padding: var(--pb-sp-3) var(--pb-sp-4); font-size: var(--pb-fz-sm); color: var(--pb-ink-on-dark-faint); } + +/* --------------------------------------------------------------------- + 20. 响应式:≤1200 收窄 / ≤992 收侧栏 / ≤768 单列 + 汉堡导航 / ≤480 微调 + (网格一律 minmax(0,1fr),390px 不溢出) + --------------------------------------------------------------------- */ +@media (max-width: 1200px) { + .pb-brandbar-inner { padding: var(--pb-sp-3) var(--pb-sp-4); } + .pb-site-name { font-size: var(--pb-fz-3xl); letter-spacing: 1px; } + .pb-search { width: 220px; } + .pb-hotwords { display: none; } + .pb-channels { grid-template-columns: repeat(4, minmax(0, 1fr)); } +} + +@media (max-width: 992px) { + .pb-cols { grid-template-columns: minmax(0, 1fr); } + .pb-side-nav { display: none; } + .pb-footer-main { grid-template-columns: minmax(0, 1fr); gap: var(--pb-sp-6); } + .pb-footer-qr { justify-content: flex-start; } + .pb-split, + .pb-headline { grid-template-columns: minmax(0, 1fr); } + .pb-media-list { grid-template-columns: minmax(0, 1fr); column-gap: 0; } + .pb-wall, + .pb-wall--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .pb-brand-tools .pb-date { display: none; } +} + +/* ≤768:单列布局 + 品牌行纵排 + 汉堡导航 */ +@media (max-width: 768px) { + .pb-brandbar-inner { flex-direction: column; align-items: flex-start; gap: var(--pb-sp-3); padding: var(--pb-sp-3); } + + .pb-brand-side { width: 100%; align-items: stretch; } + + .pb-brand-tools { width: 100%; justify-content: space-between; flex-wrap: wrap; gap: var(--pb-sp-2); } + + .pb-audience { padding-left: 0; border-left: 0; flex-wrap: wrap; } + + .pb-search-row { width: 100%; } + .pb-search { flex: 1; width: auto; } + + /* 汉堡导航:按钮显示,列表纵排抽屉 */ + .pb-nav-toggle { display: block; } + + .pb-nav-list { display: none; flex-direction: column; align-items: stretch; width: 100%; padding-bottom: var(--pb-sp-2); } + .pb-nav-list.pb-open { display: flex; } + + .pb-nav-list > li > a { width: 100%; justify-content: space-between; padding: var(--pb-sp-3) var(--pb-sp-4); font-size: var(--pb-fz-md); } + .pb-nav-list > li > a::after { display: none; } + .pb-nav-list > li.active > a { background: var(--pb-tint-strong); } + + /* 二级:窄屏改手风琴展开(main.js 切换 .pb-sub-open) */ + .pb-sub { + position: static; + opacity: 1; + visibility: visible; + transform: none; + display: none; + min-width: 0; + border-radius: 0; + box-shadow: none; + margin: 0 calc(var(--pb-sp-4) * -1); + } + .pb-nav-list > li.pb-sub-open > .pb-sub { display: block; } + + .pb-banner-arrow { display: none; } + .pb-banner-title { font-size: var(--pb-fz-lg); padding: var(--pb-sp-8) var(--pb-sp-3) var(--pb-sp-3); } + .pb-banner-dots { right: var(--pb-sp-3); bottom: var(--pb-sp-2); } + + .pb-section { padding-top: var(--pb-sp-6); } + .pb-block { padding: var(--pb-sp-3) var(--pb-sp-3) var(--pb-sp-4); } + + .pb-news-body { padding: var(--pb-sp-3); } + .pb-news-title { font-size: var(--pb-fz-lg); } + + .pb-blocks { grid-template-columns: minmax(0, 1fr); } + + .pb-article-row { flex-direction: column; gap: var(--pb-sp-2); } + .pb-item-cover { width: 100%; } + + .pb-feat > a { flex-direction: column; } + .pb-feat-cover { width: 100%; } + + .pb-page-card { padding: var(--pb-sp-3); } + .pb-article-title { font-size: var(--pb-fz-3xl); } + .pb-sibling { grid-template-columns: minmax(0, 1fr); } + .pb-sibling .next { grid-column: auto; text-align: left; } + + .pb-ticker-inner { flex-wrap: wrap; gap: var(--pb-sp-2); } + .pb-ticker-list { flex-basis: 100%; } + .pb-ticker-item { max-width: 100%; } + + .pb-channels { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .pb-channel-icon { width: 44px; height: 44px; } +} + +@media (max-width: 480px) { + .pb-brand-badge { width: 44px; height: 44px; } + .pb-site-name { font-size: var(--pb-fz-xl); } + .pb-wall, + .pb-wall--4 { grid-template-columns: minmax(0, 1fr); } + .pb-channels { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .pb-footer-qr { flex-wrap: wrap; } + .pb-page-title { font-size: var(--pb-fz-xl); } + .pb-banner-title { font-size: var(--pb-fz-md); } + .pb-svc-apply-btn { width: 100%; justify-content: center; } +} + +/* --------------------------------------------------------------------- + 21. 无障碍与打印微调 + --------------------------------------------------------------------- */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + } +} + +@media print { + .pb-nav, + .pb-brandbar, + .pb-banner-arrow, + .pb-banner-dots, + .pb-footer-links, + .pb-nav-toggle { display: none !important; } + body { background: #fff; } + .pb-page-card, + .pb-block { box-shadow: none; border-color: var(--pb-border); } +} diff --git a/src/main/resources/templates/themes/poly-blue/assets/favicon.png b/src/main/resources/templates/themes/poly-blue/assets/favicon.png new file mode 100644 index 0000000..822653c Binary files /dev/null and b/src/main/resources/templates/themes/poly-blue/assets/favicon.png differ diff --git a/src/main/resources/templates/themes/poly-blue/assets/js/main.js b/src/main/resources/templates/themes/poly-blue/assets/js/main.js new file mode 100644 index 0000000..0e69098 --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/assets/js/main.js @@ -0,0 +1,192 @@ +/* poly-blue(理工蓝)皮肤包脚本:顶条日期 + 首页轮播(自动播放/圆点/箭头/悬停暂停/键盘/触摸) + + 白底主导航吸顶 + 移动端抽屉与二级手风琴。与 default 同源逻辑,无任何外部依赖。 */ +(function () { + 'use strict'; + + /* ---------- 顶条日期(本地时间,YYYY年M月D日 星期X;元素在深宝蓝品牌行) ---------- */ + var dateEl = document.getElementById('siteDate'); + if (dateEl) { + var now = new Date(); + var week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()]; + dateEl.textContent = now.getFullYear() + '年' + (now.getMonth() + 1) + '月' + + now.getDate() + '日 星期' + week; + } + + /* ---------- 白底主导航吸顶(桌面端;≤768 不吸顶,交还给抽屉形态) ---------- */ + var nav = document.getElementById('pbNav'); + var DESKTOP_MIN = 769; + var navBaseTop = 0; + var holder = null; + + function unlockNav() { + if (nav) { nav.classList.remove('pb-nav--fixed'); } + if (holder && holder.parentNode) { + holder.parentNode.removeChild(holder); + } + holder = null; + } + + function lockNav() { + if (!nav) { return; } + if (!nav.classList.contains('pb-nav--fixed')) { + holder = document.createElement('div'); + holder.className = 'pb-nav-holder'; + holder.style.height = nav.offsetHeight + 'px'; + nav.parentNode.insertBefore(holder, nav); + nav.classList.add('pb-nav--fixed'); + } else if (holder) { + holder.style.height = nav.offsetHeight + 'px'; + } + } + + function measureNavTop() { + if (!nav) { return; } + unlockNav(); + navBaseTop = nav.getBoundingClientRect().top + window.pageYOffset; + } + + function onScrollNav() { + if (window.innerWidth < DESKTOP_MIN) { + unlockNav(); + return; + } + if (window.pageYOffset > navBaseTop) { + lockNav(); + } else { + unlockNav(); + } + } + + if (nav) { + measureNavTop(); + window.addEventListener('scroll', onScrollNav, { passive: true }); + var resizeTimer = null; + window.addEventListener('resize', function () { + if (resizeTimer) { window.clearTimeout(resizeTimer); } + resizeTimer = window.setTimeout(function () { + measureNavTop(); + onScrollNav(); + }, 150); + }); + } + + /* ---------- 移动端抽屉 + 二级手风琴 ---------- */ + var navToggle = document.querySelector('.pb-nav-toggle'); + var navList = document.querySelector('.pb-nav-list'); + + if (navToggle && navList) { + navToggle.addEventListener('click', function () { + var open = navList.classList.toggle('pb-open'); + navToggle.setAttribute('aria-expanded', open ? 'true' : 'false'); + }); + } + + /* 窄屏下:点击带二级的项先展开面板,再点才跳转;宽屏交还给 CSS hover */ + if (navList) { + navList.addEventListener('click', function (e) { + if (window.innerWidth >= DESKTOP_MIN) { return; } + var link = e.target.closest ? e.target.closest('a') : null; + if (!link) { return; } + var li = link.parentElement; + if (!li || !li.classList.contains('has-sub')) { return; } + var sub = li.querySelector('.pb-sub'); + if (!sub) { return; } + if (!li.classList.contains('pb-sub-open')) { + e.preventDefault(); + li.classList.add('pb-sub-open'); + } + }); + } + + /* ---------- 首页轮播(自动播放/圆点/箭头/悬停暂停/键盘) ---------- */ + var root = document.querySelector('.pb-banner'); + var slides = document.querySelectorAll('.pb-banner-slide'); + var dots = document.querySelectorAll('.pb-banner-dots button'); + var prevBtn = document.querySelector('.pb-banner-arrow.prev'); + var nextBtn = document.querySelector('.pb-banner-arrow.next'); + if (!slides.length || !root) { + return; + } + var current = 0; + var timer = null; + var INTERVAL = 5000; + + function show(index) { + slides[current].classList.remove('active'); + if (dots[current]) { + dots[current].classList.remove('active'); + } + current = (index + slides.length) % slides.length; + slides[current].classList.add('active'); + if (dots[current]) { + dots[current].classList.add('active'); + } + } + + function start() { + stop(); + if (slides.length > 1) { + timer = window.setInterval(function () { + show(current + 1); + }, INTERVAL); + } + } + + function stop() { + if (timer) { + window.clearInterval(timer); + timer = null; + } + } + + dots.forEach(function (dot, index) { + dot.addEventListener('click', function () { + show(index); + start(); + }); + }); + if (prevBtn) { + prevBtn.addEventListener('click', function () { + show(current - 1); + start(); + }); + } + if (nextBtn) { + nextBtn.addEventListener('click', function () { + show(current + 1); + start(); + }); + } + root.addEventListener('mouseenter', stop); + root.addEventListener('mouseleave', start); + root.addEventListener('focusin', stop); + root.addEventListener('focusout', start); + root.setAttribute('tabindex', '-1'); + root.addEventListener('keydown', function (e) { + if (e.key === 'ArrowLeft') { + show(current - 1); + start(); + } else if (e.key === 'ArrowRight') { + show(current + 1); + start(); + } + }); + + /* 触摸滑动切页 */ + var touchX = null; + root.addEventListener('touchstart', function (e) { + touchX = e.changedTouches[0].clientX; + stop(); + }, { passive: true }); + root.addEventListener('touchend', function (e) { + if (touchX === null) { return; } + var dx = e.changedTouches[0].clientX - touchX; + if (Math.abs(dx) > 40) { + show(dx < 0 ? current + 1 : current - 1); + } + touchX = null; + start(); + }, { passive: true }); + + start(); +})(); diff --git a/src/main/resources/templates/themes/poly-blue/assets/screenshot.png b/src/main/resources/templates/themes/poly-blue/assets/screenshot.png new file mode 100644 index 0000000..2a59eea Binary files /dev/null and b/src/main/resources/templates/themes/poly-blue/assets/screenshot.png differ diff --git a/src/main/resources/templates/themes/poly-blue/detail.html b/src/main/resources/templates/themes/poly-blue/detail.html new file mode 100644 index 0000000..24be053 --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/detail.html @@ -0,0 +1,76 @@ + + + + +
+ +
+
+ + + +
+ + +
+

文章标题

+ + +
正文
+
+ + +
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/poly-blue/fragments/footer.html b/src/main/resources/templates/themes/poly-blue/fragments/footer.html new file mode 100644 index 0000000..e188562 --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/fragments/footer.html @@ -0,0 +1,101 @@ + + + + + diff --git a/src/main/resources/templates/themes/poly-blue/fragments/head.html b/src/main/resources/templates/themes/poly-blue/fragments/head.html new file mode 100644 index 0000000..c96f24d --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/fragments/head.html @@ -0,0 +1,24 @@ + + + + + + + 页面标题 + + + + + + + + + + + + + + + diff --git a/src/main/resources/templates/themes/poly-blue/fragments/header.html b/src/main/resources/templates/themes/poly-blue/fragments/header.html new file mode 100644 index 0000000..d120046 --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/fragments/header.html @@ -0,0 +1,109 @@ + + + +
+ + + +
+
+
+ + + + + 站点名称 +
+ +
+
+ 加载日期… + + +
+ + 专业院系 + + + +
+ + +
+ +
+ +

+ 热门搜索: + 招生 + 就业 + 科研 + 通知 +

+
+
+
+
+ + + +
+ diff --git a/src/main/resources/templates/themes/poly-blue/fragments/home-blocks.html b/src/main/resources/templates/themes/poly-blue/fragments/home-blocks.html new file mode 100644 index 0000000..e659537 --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/fragments/home-blocks.html @@ -0,0 +1,229 @@ + + +
+
+
+
+

理工要闻

+ 更多 + +
+ + +
+
+
+
+ + +
+
+
+

栏目名

+ 更多 + +
+ + + +
+
+
+
+ + +
+
+
+

通知公告

+ 更多 + +
+ + +
+
+
+
+ + +
+
+
+

媒体理工

+ 更多 + +
+ + +
+
+
+
+ + +
+
+

图片新闻

+ 更多 + +
+ + +
+
+
+ + +
+
+ 要闻速递 + +
+
+ + + + + +
+
+
+

快捷通道

+
+ +

分组

+ +
+
+
+ + +
+

栏目暂无内容

+

内容发布后将在此展示

+
diff --git a/src/main/resources/templates/themes/poly-blue/guide.html b/src/main/resources/templates/themes/poly-blue/guide.html new file mode 100644 index 0000000..fc26d1c --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/guide.html @@ -0,0 +1,134 @@ + + + + +
+ + +
+
+ + + +
+

事项服务暂时不可用,请稍后再试

+

事项数据服务暂不可达,稍后刷新即可恢复

+
+ +
+

事项名称

+ + + +
+ 我要办理 + 进入服务大厅在线办理 +
+ +

简介

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事项基本信息
服务对象服务对象
事项类别事项类别
办理地点办理地点
办理时限办理时限
承诺时限承诺时限
咨询电话咨询电话
监督投诉监督投诉电话
+ +
+

办理流程

+
办理流程
+
+
+

所需材料

+
所需材料
+
+
+

注意事项

+
注意事项
+
+ +
+

相关材料下载

+ +
+ + +
+ + +
+
+ + + + + diff --git a/src/main/resources/templates/themes/poly-blue/home.html b/src/main/resources/templates/themes/poly-blue/home.html new file mode 100644 index 0000000..2a80827 --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/home.html @@ -0,0 +1,148 @@ + + + + +
+ +
+ +
+ + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

头条推荐

+
+ +
+ +
+
+ + +
+
+
+
+

栏目名

+ 更多 + +
+ +
+

栏目暂无内容

+

内容发布后将在此展示

+
+
+
+
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/poly-blue/list.html b/src/main/resources/templates/themes/poly-blue/list.html new file mode 100644 index 0000000..4638723 --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/list.html @@ -0,0 +1,106 @@ + + + + +
+ +
+
+ + + +
+ + + +

栏目名

+

搜索词

+ + +
+

未找到相关内容

+

栏目暂无内容

+

换个关键词试试

+

内容发布后将在此展示

+
+ + + +
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/poly-blue/service.html b/src/main/resources/templates/themes/poly-blue/service.html new file mode 100644 index 0000000..23a79db --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/service.html @@ -0,0 +1,111 @@ + + + + +
+ + +
+
+ + +

服务中心

+ + +
+

事项服务暂时不可用,请稍后再试

+

事项数据服务暂不可达,稍后刷新即可恢复

+
+ +
+
+ 服务对象 + +
+
+ 事项类别 + +
+
+ 服务部门 + +
+
+ +
+ + 清除筛选 +
+ + +
+

未找到符合条件的服务事项

+

服务中心暂未上架事项

+

换个筛选条件或关键词试试

+

事项发布后将在此展示

+
+ + + +
+
+ + + + + diff --git a/src/main/resources/templates/themes/poly-blue/single.html b/src/main/resources/templates/themes/poly-blue/single.html new file mode 100644 index 0000000..66ffed0 --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/single.html @@ -0,0 +1,50 @@ + + + + +
+ +
+
+ + + +
+ + +
+

栏目名

+ +
单页内容
+
+

页面暂无内容

+

内容编辑后将在此展示

+
+
+
+
+
+ + + + + diff --git a/src/main/resources/templates/themes/poly-blue/theme.json b/src/main/resources/templates/themes/poly-blue/theme.json new file mode 100644 index 0000000..e34d5ae --- /dev/null +++ b/src/main/resources/templates/themes/poly-blue/theme.json @@ -0,0 +1,29 @@ +{ + "specVersion": 1, + "name": "poly-blue", + "title": "理工蓝(poly-blue)", + "version": "1.0.0", + "author": "yunhai", + "description": "深宝蓝+活力橙的理工院校风(设计语言参考浙江理工大学官网)。", + "screenshot": "assets/screenshot.png", + "bannerSize": "1920x560", + "params": [ + { "key": "primary", "cssVar": "--pb-primary", "label": "主色", "type": "color", "default": "#0558a5" }, + { "key": "primaryDark", "cssVar": "--pb-primary-dark", "label": "主色加深", "type": "color", "default": "#124489" }, + { "key": "primaryLight", "cssVar": "--pb-primary-light","label": "主色提亮", "type": "color", "default": "#258cff" }, + { "key": "accent", "cssVar": "--pb-accent", "label": "活力橙强调", "type": "color", "default": "#ff7b00" }, + { "key": "secondary", "cssVar": "--pb-secondary", "label": "绿色小标签", "type": "color", "default": "#1c7b46" }, + { "key": "navBg", "cssVar": "--pb-nav-bg", "label": "主导航底色", "type": "color", "default": "#ffffff" }, + { "key": "footerBg", "cssVar": "--pb-footer-bg", "label": "页脚底色", "type": "color", "default": "#124489" }, + { "key": "text", "cssVar": "--pb-text", "label": "正文文字色", "type": "color", "default": "#2f3a47" }, + { "key": "textLight", "cssVar": "--pb-text-light", "label": "次要文字色", "type": "color", "default": "#708090" }, + { "key": "bg", "cssVar": "--pb-bg", "label": "页面底色", "type": "color", "default": "#f5f8fc" }, + { "key": "cardBg", "cssVar": "--pb-card-bg", "label": "卡片底色", "type": "color", "default": "#ffffff" }, + { "key": "border", "cssVar": "--pb-border", "label": "边框色", "type": "color", "default": "#e2e8f2" }, + { "key": "headerStyle", "label": "头部样式", "type": "select", "default": "banner", + "options": [ + { "value": "banner", "label": "通栏横幅头图" }, + { "value": "plain", "label": "深色品牌行+白底吸顶" } + ] } + ] +} diff --git a/src/test/java/com/yunhai/cms/theme/ThemeRegistryTest.java b/src/test/java/com/yunhai/cms/theme/ThemeRegistryTest.java index 32d3b40..665155a 100644 --- a/src/test/java/com/yunhai/cms/theme/ThemeRegistryTest.java +++ b/src/test/java/com/yunhai/cms/theme/ThemeRegistryTest.java @@ -135,6 +135,30 @@ class ThemeRegistryTest { } } + @Test + @DisplayName("高校官网风第二批: poly-blue/agri-forest/jade-normal 注册成功,主色与存量全部互异") + void universitySkinsRegisteredWithDistinctPrimary() { + String defaultPrimary = registry.get(ThemeRegistry.DEFAULT_THEME).param("primary").getDefaultValue(); + String scholarPrimary = registry.get("scholar-blue").param("primary").getDefaultValue(); + java.util.Map seen = new java.util.LinkedHashMap<>(); + for (String name : new String[] {"poly-blue", "agri-forest", "jade-normal"}) { + ThemeInfo info = registry.get(name); + assertThat(info).as("%s 皮肤包必须注册(清单+必备模板+截图齐全)", name).isNotNull(); + assertThat(info.getTitle()).isNotBlank(); + ThemeParam primary = info.param("primary"); + assertThat(primary).as("%s 应声明 primary 参数", name).isNotNull(); + assertThat(primary.getDefaultValue()) + .as("%s 的 primary 不得与 default 相同", name).isNotEqualTo(defaultPrimary); + assertThat(primary.getDefaultValue()) + .as("%s 的 primary 不得与 scholar-blue 相同(拷贝忘改哨兵)", name) + .isNotEqualTo(scholarPrimary); + seen.put(name, primary.getDefaultValue()); + } + assertThat(seen.get("poly-blue")).isNotEqualTo(seen.get("agri-forest")); + assertThat(seen.get("poly-blue")).isNotEqualTo(seen.get("jade-normal")); + assertThat(seen.get("agri-forest")).isNotEqualTo(seen.get("jade-normal")); + } + @Test @DisplayName("default 包缺失时 fail-fast(方案 §5.1,启动失败防线)") void defaultMissingFailsFast() { diff --git a/src/test/java/com/yunhai/cms/theme/UniversitySkinContractTest.java b/src/test/java/com/yunhai/cms/theme/UniversitySkinContractTest.java new file mode 100644 index 0000000..d23e940 --- /dev/null +++ b/src/test/java/com/yunhai/cms/theme/UniversitySkinContractTest.java @@ -0,0 +1,200 @@ +package com.yunhai.cms.theme; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * 高校官网风皮肤契约·第二批(poly-blue / agri-forest / jade-normal,以 default 为基座派生)。 + * + * 与 AcademicSkinContractTest 同构,钉住同一组渲染不变量(自带九段首页区块、 + * home.html 按 homeStyle 分发到本包 fragment、中文防塌列、:root 契约变量别名、 + * 背景带层序、预览图必须是本皮肤自有图)。配色断言按三包定位分档: + * poly-blue 主色蓝通道主导(参考浙江理工大学 #0558A5),agri-forest/jade-normal + * 主色绿通道主导(参考信阳农林学院 #1C6E19 / 信阳师范大学 #008D3F)—— + * 粉/紫系已被用户否决(cherry-bloom/violet-iris 事故),此处锁死不回流。 + */ +@DisplayName("高校官网风皮肤契约·第二批 - 自带首页区块 + 高校官网配色") +class UniversitySkinContractTest { + + /** 皮肤名:结构类名前缀,两处必须一致(拷贝忘改前缀会让皮肤互相串样式)。 */ + private static final String[] SKINS = {"poly-blue:pb", "agri-forest:af", "jade-normal:jn"}; + + private static String skin(String spec) { + return spec.substring(0, spec.indexOf(':')); + } + + private static String prefix(String spec) { + return spec.substring(spec.indexOf(':') + 1); + } + + private static String text(String classpath) { + try (InputStream in = UniversitySkinContractTest.class.getResourceAsStream(classpath)) { + assertThat(in).as("classpath 资源必须存在:%s", classpath).isNotNull(); + return new String(readAll(in), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private static byte[] readAll(InputStream in) throws IOException { + java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); + byte[] buf = new byte[8192]; + int n; + while ((n = in.read(buf)) > 0) { + out.write(buf, 0, n); + } + return out.toByteArray(); + } + + private static String ruleOf(String css, String selector) { + Matcher m = Pattern.compile(Pattern.quote(selector) + "\\s*\\{([^}]*)\\}").matcher(css); + assertThat(m.find()).as("main.css 应含选择器 %s 的规则", selector).isTrue(); + return m.group(1).replaceAll("\\s+", ""); + } + + /** 抽出所有含 marker 的开始标签,用于检查同一标签上的属性组合。 */ + private static java.util.List tagsContaining(String html, String marker) { + java.util.List tags = new java.util.ArrayList<>(); + Matcher m = Pattern.compile("<[a-zA-Z][^>]*>").matcher(html); + while (m.find()) { + if (m.group().contains(marker)) { + tags.add(m.group()); + } + } + return tags; + } + + @Test + @DisplayName("派生包自带首页区块 fragment:布局模式下区块由皮肤渲染,不落通用骨架") + void skinOwnsHomeBlockFragments() { + for (String spec : SKINS) { + String html = text("/templates/themes/" + skin(spec) + "/fragments/home-blocks.html"); + for (String fragment : new String[] {"news_grid", "media_focus", "compact", "image_wall", + "card", "ticker", "gallery", "links", "empty"}) { + assertThat(html).as("%s 区块 fragment 必须自带", fragment) + .contains("th:fragment=\"" + fragment + "(block)\""); + } + // 空态:th:replace(优先级 100)先于 th:if(300),守卫写在同一标签上等于没写 + for (String tag : tagsContaining(html, ":: empty(")) { + assertThat(tag).as("%s 的空态守卫必须在外层 th:block 上", skin(spec)).doesNotContain("th:if"); + } + assertThat(html).contains("th:block th:if=\"${#lists.isEmpty(block.items)}\""); + } + } + + @Test + @DisplayName("home.html 把布局区块分发到本皮肤 fragment,区块头带右置「更多」") + void homeDispatchesToOwnFragments() { + for (String spec : SKINS) { + String html = text("/templates/themes/" + skin(spec) + "/home.html"); + assertThat(html).as("须按 layoutBlocks 分支渲染").contains("layoutBlocks != null"); + for (String style : new String[] {"news_grid", "media_focus", "compact", "image_wall"}) { + assertThat(html).as("%s 形态 %s 应走本皮肤 fragment", skin(spec), style) + .contains("'/fragments/home-blocks' :: " + style + "(${block})"); + } + assertThat(html).as("区块标题行须有右侧「更多」样式钩子").contains(prefix(spec) + "-more"); + } + } + + @Test + @DisplayName("中文行不被压塌:速递条单行可收缩、列表标题超长省略") + void rowsMustNotCollapseCjkText() { + for (String spec : SKINS) { + String css = text("/templates/themes/" + skin(spec) + "/assets/css/main.css"); + String p = prefix(spec); + String list = ruleOf(css, "." + p + "-ticker-list"); + assertThat(list).as("flex 列表须让出收缩权并锁单行").contains("min-width:0").contains("white-space:nowrap"); + String item = ruleOf(css, "." + p + "-ticker-item"); + assertThat(item).as("条目不被压缩且超长省略").contains("flex:none").contains("text-overflow:ellipsis"); + String title = ruleOf(css, "." + p + "-block-item-title"); + assertThat(title).contains("min-width:0").contains("overflow:hidden").contains("text-overflow:ellipsis"); + } + } + + @Test + @DisplayName("皮肤变量别名到主题契约变量,供 common 兜底骨架继承") + void skinAliasesContractVars() { + for (String spec : SKINS) { + String css = text("/templates/themes/" + skin(spec) + "/assets/css/main.css"); + String p = prefix(spec); + String root = ruleOf(css, ":root"); + assertThat(root).contains("--primary:var(--" + p + "-primary)") + .contains("--text:var(--" + p + "-text)") + .contains("--card-bg:var(--" + p + "-card-bg)") + .contains("--border:var(--" + p + "-border)"); + } + } + + @Test + @DisplayName("新闻背景带画在卡片之下:绝对定位层必须压 z-index,卡片抬起来") + void newsBandMustPaintBehindCard() { + for (String spec : SKINS) { + String css = text("/templates/themes/" + skin(spec) + "/assets/css/main.css"); + String p = prefix(spec); + assertThat(ruleOf(css, "." + p + "-sec-bg")).as("%s 背景带须压到卡片之下", p).contains("z-index:0"); + assertThat(ruleOf(css, "." + p + "-sec-bg + ." + p + "-block")) + .as("%s 卡片须抬到背景带之上,否则新闻带图片盖住正文", p).contains("z-index:1"); + } + } + + @Test + @DisplayName("皮肤预览图必须是本皮肤自有图,不得沿用基座 default 的截图") + void screenshotMustBeOwnCapture() { + byte[] base = bytes("/templates/themes/default/assets/screenshot.png"); + for (String spec : SKINS) { + String path = "/templates/themes/" + skin(spec) + "/assets/screenshot.png"; + byte[] shot = bytes(path); + assertThat(shot).as("%s 的预览图与基座雷同,等于没换肤", skin(spec)).isNotEqualTo(base); + assertThat(shot.length).as("%s 预览图不能是空文件", skin(spec)).isGreaterThan(20 * 1024); + } + } + + private static byte[] bytes(String classpath) { + try (InputStream in = UniversitySkinContractTest.class.getResourceAsStream(classpath)) { + assertThat(in).as("classpath 资源必须存在:%s", classpath).isNotNull(); + return readAll(in); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Test + @DisplayName("配色必须是高校官网主色:poly-blue 蓝通道主导、agri-forest/jade-normal 绿通道主导,粉紫禁入") + void primaryMustBeUniversityHue() throws IOException { + for (String spec : SKINS) { + JsonNode root = new ObjectMapper() + .readTree(text("/templates/themes/" + skin(spec) + "/theme.json")); + assertThat(root.path("name").asText()).as("name 必须等于目录名").isEqualTo(skin(spec)); + String primary = null; + for (JsonNode p : root.path("params")) { + if ("primary".equals(p.path("key").asText())) { + primary = p.path("default").asText(); + } + } + assertThat(primary).as("%s theme.json 须声明 primary 颜色参数", skin(spec)).isNotNull(); + Matcher m = Pattern.compile("#([0-9a-fA-F]{6})").matcher(primary); + assertThat(m.matches()).as("primary 需为 6 位 hex,实际 %s", primary).isTrue(); + int rgb = Integer.parseInt(m.group(1), 16); + int r = (rgb >> 16) & 0xFF, g = (rgb >> 8) & 0xFF, b = rgb & 0xFF; + double lightness = (Math.max(r, Math.max(g, b)) + Math.min(r, Math.min(g, b))) / 255d / 2d; + if ("poly-blue".equals(skin(spec))) { + assertThat(b).as("理工蓝主色须蓝通道主导,实际 %s", primary).isGreaterThan(r).isGreaterThan(g); + } else { + assertThat(g).as("%s 主色须绿通道主导(农林/师范绿),实际 %s", skin(spec), primary) + .isGreaterThan(r).isGreaterThan(b); + } + assertThat(lightness).as("官网主色应为沉稳深色而非粉彩,实际 %s", primary) + .isBetween(0.18d, 0.52d); + } + } +}