Files
aurora-admin/frameworks-mobile/Message.html
T
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

224 lines
12 KiB
HTML
Raw 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 · Message(H5)</title>
<link rel="stylesheet" href="../.design_library/kole-ui-mobile/colors_and_type.css">
<link rel="stylesheet" href="Message.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); }
/* 展示框:transform 建立包含块,让 position: fixed 的消息层落在本框内(生产环境落在视口顶部)。
不做这一步,同页并列的多个消息层会全部叠在视口顶部,看起来「只渲染了一个」。 */
.demo-frame { position: relative; max-width: 375px; margin: 0 auto; height: 200px; overflow: hidden;
transform: translateZ(0); background: var(--kole-color-card-bg);
border-block: 1px solid var(--kole-color-border); }
.demo-frame__body { padding: var(--kole-space-12) var(--kole-m-gutter);
font-size: var(--kole-m-font-size-label); color: var(--kole-color-text-secondary); line-height: 1.7; }
.demo-actions { display: flex; flex-wrap: wrap; gap: var(--kole-space-8); }
.demo-trigger { min-height: var(--kole-m-touch-target); padding: 0 var(--kole-space-12);
border: 1px solid var(--kole-color-border); border-radius: var(--kole-radius-base);
background: var(--kole-color-card-bg); color: var(--kole-color-text-body);
font-family: inherit; font-size: var(--kole-m-font-size-label); cursor: pointer; touch-action: manipulation; }
.demo-trigger:focus-visible { outline: 2px solid var(--kole-color-focus-ring); outline-offset: 2px; }
.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="tones">
<p class="demo-label">四种语气(tone=info / success / warning / error:图标与侧边描边同族,文字保持正文色)</p>
<div class="demo-frame" data-assert="message-tones">
<div class="demo-frame__body">
<div class="demo-actions">
<button class="demo-trigger" type="button" id="msg-info-trigger"
data-behavior="click-toggles-class:#msg-info|is-open">信息</button>
<button class="demo-trigger" type="button" id="msg-success-trigger"
data-behavior="click-toggles-class:#msg-success|is-open">成功</button>
<button class="demo-trigger" type="button" id="msg-warning-trigger"
data-behavior="click-toggles-class:#msg-warning|is-open">警告</button>
<button class="demo-trigger" type="button" id="msg-error-trigger"
data-behavior="click-toggles-class:#msg-error|is-open">错误</button>
</div>
</div>
<div class="kole-m-message">
<div class="kole-m-message__item kole-m-message__item--info" id="msg-info"
role="status" aria-live="polite" data-open="false">
<span class="kole-m-message__icon" aria-hidden="true">ℹ</span>
<span class="kole-m-message__text">已为你切换到最近使用的收货地址</span>
</div>
<div class="kole-m-message__item kole-m-message__item--success" id="msg-success"
role="status" aria-live="polite" data-open="false">
<span class="kole-m-message__icon" aria-hidden="true">✓</span>
<span class="kole-m-message__text">提交成功,预计 2 小时内审核完成</span>
</div>
<div class="kole-m-message__item kole-m-message__item--warning" id="msg-warning"
role="status" aria-live="polite" data-open="false">
<span class="kole-m-message__icon" aria-hidden="true">⚠</span>
<span class="kole-m-message__text">库存仅剩 2 件,下单后可能延迟发货</span>
</div>
<div class="kole-m-message__item kole-m-message__item--error" id="msg-error"
role="status" aria-live="polite" data-open="false">
<span class="kole-m-message__icon" aria-hidden="true">✕</span>
<span class="kole-m-message__text">网络异常,请检查连接后重试</span>
</div>
</div>
</div>
<p class="demo-hint">四条消息同一层并列,各自独立开关;点一次展开、再点一次收起。</p>
</section>
<section class="demo-block" data-demo="closable">
<p class="demo-label">可关闭(closable=true:右侧 × 是原生 button,热区 44px,点它立即收起)</p>
<div class="demo-frame" data-assert="message-closable">
<div class="demo-frame__body">
<button class="demo-trigger" type="button" id="msg-closable-trigger"
data-behavior="click-toggles-class:#msg-closable|is-open">显示可关闭消息</button>
</div>
<div class="kole-m-message">
<div class="kole-m-message__item kole-m-message__item--info" id="msg-closable"
role="status" aria-live="polite" data-open="false">
<span class="kole-m-message__icon" aria-hidden="true">ℹ</span>
<span class="kole-m-message__text">本次更新包含 3 项改进,点右侧 ✕ 立即收起</span>
<button class="kole-m-message__close" type="button" aria-label="关闭消息">✕</button>
</div>
</div>
</div>
</section>
<section class="demo-block" data-demo="duration">
<p class="demo-label">自动消失(duration=3000:到点回传 close 由宿主收起;duration=0 时不自动收)</p>
<div class="demo-frame" data-assert="message-duration">
<div class="demo-frame__body">
<button class="demo-trigger" type="button" id="msg-duration-trigger"
data-behavior="click-sets-attr:#msg-duration|data-open|true">显示并在 3 秒后自动收起</button>
<p class="demo-hint" id="msg-duration-tip">计时归宿主:组件只负责显示态,到点回传 close</p>
</div>
<div class="kole-m-message">
<div class="kole-m-message__item kole-m-message__item--success" id="msg-duration"
role="status" aria-live="polite" data-open="false">
<span class="kole-m-message__icon" aria-hidden="true">✓</span>
<span class="kole-m-message__text">已保存,3 秒后这条消息自动收起</span>
</div>
</div>
</div>
</section>
<section class="demo-block" data-demo="stack">
<p class="demo-label">多条并列(消息层纵向排列:新消息追加在下方,可同时在场)</p>
<div class="demo-frame" data-assert="message-stack">
<div class="demo-frame__body">两条消息同时在场,各自语气独立。</div>
<div class="kole-m-message">
<div class="kole-m-message__item kole-m-message__item--success is-open" data-open="true">
<span class="kole-m-message__icon" aria-hidden="true">✓</span>
<span class="kole-m-message__text">图片上传完成(1/2)</span>
</div>
<div class="kole-m-message__item kole-m-message__item--warning is-open" data-open="true">
<span class="kole-m-message__icon" aria-hidden="true">⚠</span>
<span class="kole-m-message__text">第 2 张超出 5MB,已跳过</span>
</div>
</div>
</div>
</section>
<section class="demo-block" data-demo="plain">
<p class="demo-label">默认形态(不带关闭按钮、不阻断操作:消息层自身 pointer-events: none)</p>
<div class="demo-frame" data-assert="message-plain">
<div class="demo-frame__body">
<button class="demo-trigger" type="button" id="msg-plain-trigger"
data-behavior="click-sets-attr:#msg-plain|data-open|true">显示默认消息</button>
<p class="demo-hint">消息浮在顶部,下面这行文字仍然可以正常选中与点击。</p>
</div>
<div class="kole-m-message">
<div class="kole-m-message__item kole-m-message__item--info" id="msg-plain"
role="status" aria-live="polite" data-open="false">
<span class="kole-m-message__icon" aria-hidden="true">ℹ</span>
<span class="kole-m-message__text">已复制到剪贴板</span>
</div>
</div>
</div>
</section>
</div>
<script>
/* 演示页交互:类名与 data-open 由**同一个函数**写入(避免视觉与状态分叉)。
每块自带开关,互不依赖:触发器 id 与消息 id 成对写在下方映射里,
因此任一 `?demo=<id>` 单块预览都能独立工作。 */
(function () {
function setOpen(el, open) {
el.classList.toggle('is-open', open);
el.setAttribute('data-open', open ? 'true' : 'false');
}
function bind(triggerId, itemId, mode) {
var trig = document.getElementById(triggerId);
var item = document.getElementById(itemId);
if (!trig || !item) return;
trig.addEventListener('click', function () {
if (mode === 'show') setOpen(item, true);
else setOpen(item, !item.classList.contains('is-open'));
});
}
/* 四种语气:点一次展开、再点一次收起 */
bind('msg-info-trigger', 'msg-info', 'toggle');
bind('msg-success-trigger', 'msg-success', 'toggle');
bind('msg-warning-trigger', 'msg-warning', 'toggle');
bind('msg-error-trigger', 'msg-error', 'toggle');
bind('msg-closable-trigger', 'msg-closable', 'toggle');
bind('msg-plain-trigger', 'msg-plain', 'show');
/* 可关闭:点 × 只关它自己那一条 */
document.querySelectorAll('.kole-m-message__close').forEach(function (btn) {
btn.addEventListener('click', function () {
var item = btn.closest('.kole-m-message__item');
if (item) setOpen(item, false);
});
});
/* 自动消失:时长由宿主决定(这里演示 3000ms),到点收起。
组件不持有默认时长 —— 规格 §42.7 明确把这条留给宿主。 */
var dur = document.getElementById('msg-duration');
var durTrig = document.getElementById('msg-duration-trigger');
var tip = document.getElementById('msg-duration-tip');
var timer = null;
if (dur && durTrig) {
durTrig.addEventListener('click', function () {
if (timer) clearTimeout(timer);
setOpen(dur, true);
if (tip) tip.textContent = '显示中…3 秒后自动收起';
timer = setTimeout(function () {
setOpen(dur, false);
timer = null;
if (tip) tip.textContent = '已自动收起(计时归宿主:组件只负责显示态)';
}, 3000);
});
}
})();
</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>