Files
aurora-admin f1fbfc2ddb
Regression / regression (push) Canceled after 0s
feat(品牌标识): 几何 K 图标(favicon/顶栏标记/theme-color) + 并行会话成果入库
## 品牌标识(本次会话)

起因:品牌此前没有任何图形标识 —— 唯一 favicon 是内联 data-URI 里的字母「A」,
那是 v2.0.0「Aurora Admin → Kole UI」改名漏掉的一处(PC 顶栏也是「A」,
移动端站已是「K」;移动端文档站则完全没有 favicon)。

- 几何:24 网格三个互不接触的笔画(竖 + 两斜),圆头描边;
  描边 2.25 → 16px 标签页尺寸下正好 1.5px = 规范原文「描边1.5px」
- 取色分两套(刻意):favicon 硬编码品牌蓝/白(渲染在浏览器标签栏,不继承 kole-dark);
  顶栏标记走 currentColor(实测暗色下自动转 rgb(20,22,28))
- 新增 theme-color 双条(light #FFFFFF / dark #1C1F26,取 --kole-color-card-bg)
- 修 site/app.js hero 标语 KOLE ADMIN → KOLE UI(改名变形残留)
- 移动端 7 个模板补 favicon(此前计数 0)

验收:门禁 9 条全 OK(site-routing/site-routes/mobile-docs/mobile-site/isolation/
theme/nav/i18n/icons);PC 回归 1464/1464 · 移动端 807/807,各连跑 8 次一致;
两端 favicon 405 字节逐字节一致;PC 站控制台错误 1→0。

## 并行会话成果(本次一并入库)

- 图标系统:2576 图标(TDesign/Element Plus,MIT)+ 11 端注入 + 5 个构建门禁工具
  + IconPreview 预览页 + ICON-SPEC.md 冻结规格
- 移动端平台:47 组件 × 6 端 + 文档站 53 页 + 隔离门禁
- PC 组件:103 个大后台组件 / 组件11 批次
- uni-app:PC 端试点 + 移动端端实现 + 真实编译验证

## 工程

- .gitignore 补 .scratch/ 与 .zcode-preexisting-*.txt(会话中间产物,实测 9.1MB,不入库)
- CHANGELOG 补品牌标识条目
- ROADMAP 登 S8-P4(品牌标识任务包 + og:image/apple-touch-icon 未做部分)
2026-09-21 10:05:48 +08:00

196 lines
10 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Kole UI Mobile · Sticky(H5)</title>
<link rel="stylesheet" href="../.design_library/kole-ui-mobile/colors_and_type.css">
<link rel="stylesheet" href="Sticky.css">
<style>
body { margin: 0; background: var(--kole-color-page-bg); font-family: var(--kole-font-family); color: var(--kole-color-text-body); }
.demo { max-width: 375px; margin: 0 auto; padding: var(--kole-m-gutter) 0; }
.demo-label { margin: 0; padding: var(--kole-space-12) var(--kole-m-gutter) var(--kole-space-8);
font-size: var(--kole-m-font-size-label); color: var(--kole-color-text-secondary); }
/* 滚动容器:sticky 的贴合参照是**最近的可滚动祖先**,所以在框内滚动就能看到吸顶效果 */
.demo-scroll { position: relative; height: 200px; overflow-y: auto; -webkit-overflow-scrolling: touch;
background: var(--kole-color-card-bg); border-block: 1px solid var(--kole-color-border); }
/* 模拟页面级固定导航:吸顶条的默认偏移 = 导航栏高度,恰好贴在它下沿 */
.demo-navbar { position: absolute; top: 0; left: 0; right: 0; z-index: 2;
display: flex; align-items: center; height: var(--kole-m-navbar-height);
padding: 0 var(--kole-m-gutter); background: var(--kole-color-card-bg);
border-block-end: 1px solid var(--kole-color-border);
font-size: var(--kole-m-font-size-label); color: var(--kole-color-text-secondary); }
.demo-row { padding: var(--kole-space-12) var(--kole-m-gutter);
font-size: var(--kole-m-font-size-label); color: var(--kole-color-text-secondary);
border-bottom: 1px solid var(--kole-color-border); }
.demo-hint { margin: 0; padding: var(--kole-space-8) var(--kole-m-gutter) 0;
font-size: var(--kole-m-font-size-caption); color: var(--kole-color-text-tertiary); }
.demo-block[hidden] { display: none; }
</style>
</head>
<body>
<div class="demo">
<section class="demo-block" data-demo="basic">
<p class="demo-label">基础吸顶(position: sticky + 默认偏移 = 导航栏高度:在框内滚动,标题条贴住导航栏下沿)</p>
<div class="demo-scroll" id="scroll-basic" data-assert="sticky-basic">
<div class="demo-navbar" aria-hidden="true">模拟固定导航栏(高 44px)</div>
<div class="demo-row" style="height: 88px">(占位:让吸顶条初始位于阈值下方,滚动 44px 后才贴合)</div>
<div class="kole-m-sticky kole-m-sticky--top" id="sticky-basic" data-stuck="false">
<span class="kole-m-sticky__title">订单列表 · 共 6 条</span>
<span class="kole-m-sticky__extra">9 月</span>
</div>
<div class="demo-row">20260920-001 · 已发货</div>
<div class="demo-row">20260920-002 · 待付款</div>
<div class="demo-row">20260919-014 · 已完成</div>
<div class="demo-row">20260919-013 · 已完成</div>
<div class="demo-row">20260918-007 · 已取消</div>
<div class="demo-row">20260918-006 · 已完成</div>
<div class="demo-row">20260917-003 · 已完成</div>
</div>
<p class="demo-hint">滚动后标题条贴在导航栏下沿保持可见(sticky 不脱离文档流,因此无需补占位元素)</p>
</section>
<section class="demo-block" data-demo="shadow">
<p class="demo-label">吸顶后出阴影(shadow=true:未吸顶时与内容齐平,贴合后才有投影)</p>
<div class="demo-scroll" id="scroll-shadow" data-assert="sticky-shadow">
<div class="demo-navbar" aria-hidden="true">模拟固定导航栏(高 44px)</div>
<div class="demo-row" style="height: 88px">(占位:让吸顶条初始位于阈值下方,滚动 44px 后才贴合)</div>
<div class="kole-m-sticky kole-m-sticky--top kole-m-sticky--shadow" id="sticky-shadow" data-stuck="false">
<span class="kole-m-sticky__title">分组:待处理</span>
</div>
<div class="demo-row">工单 #4821 · 待分派</div>
<div class="demo-row">工单 #4822 · 待分派</div>
<div class="demo-row">工单 #4823 · 处理中</div>
<div class="demo-row">工单 #4824 · 处理中</div>
<div class="demo-row">工单 #4825 · 待回访</div>
<div class="demo-row">工单 #4826 · 待回访</div>
</div>
<p class="demo-hint">
<button class="kole-m-sticky__action" type="button" id="sticky-shadow-toggle"
data-behavior="click-toggles-class:#sticky-shadow|is-stuck">切换 is-stuck 对照</button>
手动切换贴合态,可直接对照有/无阴影两种形态
</p>
</section>
<section class="demo-block" data-demo="safe-area">
<p class="demo-label">安全区叠加(safeArea=true:偏移 = 容器偏移 + 刘海高度,无刘海时为 0px)</p>
<div class="demo-scroll" id="scroll-safe" data-assert="sticky-safe-area">
<div class="kole-m-sticky kole-m-sticky--top kole-m-sticky--safe is-stuck" data-stuck="true"
style="--kole-m-sticky-offset: 0px">
<span class="kole-m-sticky__title">安全区吸顶(覆盖 offset=0)</span>
</div>
<div class="demo-row">覆盖 --kole-m-sticky-offset: 0px 后贴合在框顶</div>
<div class="demo-row">真实设备上再叠加 env(safe-area-inset-top)</div>
<div class="demo-row">顶部安全区为 0px 时与不带 safe 的表现一致</div>
<div class="demo-row">内容行 4</div>
<div class="demo-row">内容行 5</div>
</div>
</section>
<section class="demo-block" data-demo="bottom">
<p class="demo-label">贴底吸顶(position=bottom:内容不足一屏时贴住框底,常用于底部合计条)</p>
<div class="demo-scroll" id="scroll-bottom" data-assert="sticky-bottom">
<div class="demo-row">商品 1 · ¥128.00</div>
<div class="demo-row">商品 2 · ¥256.00</div>
<div class="demo-row">商品 3 · ¥64.00</div>
<div class="kole-m-sticky kole-m-sticky--bottom kole-m-sticky--shadow" data-stuck="true"
style="--kole-m-sticky-offset: 0px">
<span class="kole-m-sticky__title">合计 ¥448.00</span>
<span class="kole-m-sticky__extra">已减 ¥12</span>
</div>
</div>
</section>
<section class="demo-block" data-demo="action">
<p class="demo-label">带动作(右侧动作是原生 button,热区 44px;点击回传 action 由宿主处理)</p>
<div class="demo-scroll" id="scroll-action" data-assert="sticky-action">
<div class="kole-m-sticky kole-m-sticky--top is-stuck" id="sticky-action" data-stuck="true">
<span class="kole-m-sticky__title">收货地址</span>
<button class="kole-m-sticky__action" type="button"
data-behavior="click-sets-attr:#sticky-action|data-clicked|true">管理</button>
</div>
<div class="demo-row">浙江省杭州市余杭区文一西路 969 号</div>
<div class="demo-row">收货人:张* | 138****8841</div>
<div class="demo-row">内容行 3</div>
<div class="demo-row">内容行 4</div>
<div class="demo-row">内容行 5</div>
</div>
</section>
</div>
<script>
/* 演示页交互:滚动容器里的 sticky 贴合时机只有浏览器知道 —— 演示页用 scrollTop 判断,
把 is-stuck / data-stuck 同步到**真源那一个函数**(避免类名与属性分叉)。
生产环境同样由宿主驱动;组件本体不监听滚动。 */
(function () {
/* 贴合态的唯一写入点:类名与属性在同一个函数里落笔,避免「视觉贴住了、属性还说没贴」 */
function setStuck(bar, stuck) {
bar.classList.toggle('is-stuck', stuck);
bar.setAttribute('data-stuck', stuck ? 'true' : 'false');
}
/* 贴合判定:比较吸顶条的实际 top 与「容器内容区 top + 偏移量」——
贴合后两者相等,未贴合时吸顶条还在偏移量之下。
容器内容区 top = 容器 border-box top + 上边框宽度(sticky 的偏移是相对 padding box 的,
漏掉这 1px 会把「刚刚贴住」误判成「还没贴」)。判据不依赖硬编码的偏移数值。 */
function isStuck(box, bar) {
var offset = parseFloat(getComputedStyle(bar).top) || 0;
var border = parseFloat(getComputedStyle(box).borderTopWidth) || 0;
var boxTop = box.getBoundingClientRect().top;
var barTop = bar.getBoundingClientRect().top;
return barTop <= boxTop + border + offset + 0.5;
}
function bind(scrollSel, stickySel) {
var box = document.querySelector(scrollSel);
var bar = document.querySelector(stickySel);
if (!box || !bar) return;
function sync() {
setStuck(bar, isStuck(box, bar));
}
box.addEventListener('scroll', sync, { passive: true });
sync();
}
bind('#scroll-basic', '#sticky-basic');
bind('#scroll-shadow', '#sticky-shadow');
/* 对照开关:手动翻转贴合态,用于并排看有/无阴影两种形态 */
var toggle = document.getElementById('sticky-shadow-toggle');
var shadowBar = document.getElementById('sticky-shadow');
if (toggle && shadowBar) {
toggle.addEventListener('click', function () {
setStuck(shadowBar, !shadowBar.classList.contains('is-stuck'));
});
}
})();
(function () {
var bar = document.getElementById('sticky-action');
if (!bar) return;
var btn = bar.querySelector('.kole-m-sticky__action');
if (!btn) return;
btn.addEventListener('click', function () {
bar.setAttribute('data-clicked', 'true');
});
})();
</script>
<script>
/* ?demo=<id> → 只显示该演示块(文档站按块预览用;无参数时全部显示,测试与回归走无参数路径) */
(function () {
var id = new URLSearchParams(location.search).get('demo');
if (!id) return;
var blocks = Array.prototype.slice.call(document.querySelectorAll('.demo-block'));
var hit = false;
blocks.forEach(function (b) {
var on = b.getAttribute('data-demo') === id;
if (on) hit = true;
b.hidden = !on;
});
if (!hit) { blocks.forEach(function (b) { b.hidden = false; }); return; }
document.body.classList.add('demo-single');
var demoBox = document.querySelector('.demo');
if (demoBox) demoBox.style.minHeight = 'auto';
blocks.forEach(function (b) {
var label = b.querySelector('.demo-label');
if (label && !b.hidden) label.hidden = true;
});
})();
</script>
</body>
</html>