Regression / regression (push) Canceled after 0s
## 品牌标识(本次会话) 起因:品牌此前没有任何图形标识 —— 唯一 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 未做部分)
94 lines
2.5 KiB
React
94 lines
2.5 KiB
React
import React, { useRef, useState } from 'react';
|
||
import './PullRefresh.css';
|
||
|
||
/* 下拉刷新(移动端)— 规格 §4;Pointer Events 手势,阈值默认 60px,
|
||
松手达阈值进入 refreshing;横向分量更大时放弃本次下拉。 */
|
||
export default function PullRefresh({
|
||
threshold = 60,
|
||
refreshing = false,
|
||
done = false,
|
||
onRefresh,
|
||
fallbackLabel = '刷新列表',
|
||
children,
|
||
}) {
|
||
const [offset, setOffset] = useState(0);
|
||
const [drag, setDrag] = useState('');
|
||
const start = useRef({ y: 0, x: 0 });
|
||
const dy = useRef(0);
|
||
const active = useRef(false);
|
||
|
||
const stateText = refreshing
|
||
? '正在刷新…'
|
||
: done
|
||
? '刷新完成'
|
||
: drag === 'ready'
|
||
? '松开立即刷新'
|
||
: '下拉即可刷新';
|
||
|
||
const cls =
|
||
'kole-m-pullrefresh' +
|
||
(refreshing ? ' is-refreshing' : done ? ' is-done' : drag ? ' is-' + drag : '');
|
||
|
||
function onPointerDown(e) {
|
||
if (refreshing) return;
|
||
active.current = true;
|
||
start.current = { y: e.clientY, x: e.clientX };
|
||
dy.current = 0;
|
||
}
|
||
|
||
function onPointerMove(e) {
|
||
if (!active.current) return;
|
||
dy.current = e.clientY - start.current.y;
|
||
if (Math.abs(e.clientX - start.current.x) > Math.abs(dy.current)) {
|
||
active.current = false;
|
||
return;
|
||
}
|
||
if (dy.current <= 0) {
|
||
setOffset(0);
|
||
setDrag('');
|
||
return;
|
||
}
|
||
setOffset(dy.current);
|
||
setDrag(dy.current >= threshold ? 'ready' : 'pulling');
|
||
}
|
||
|
||
function release() {
|
||
if (!active.current) return;
|
||
active.current = false;
|
||
if (dy.current >= threshold) {
|
||
setOffset(threshold);
|
||
setDrag('');
|
||
if (onRefresh) onRefresh();
|
||
} else {
|
||
setOffset(0);
|
||
setDrag('');
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div
|
||
className={cls}
|
||
style={{ '--kole-m-pullrefresh-offset': offset + 'px' }}
|
||
onPointerDown={onPointerDown}
|
||
onPointerMove={onPointerMove}
|
||
onPointerUp={release}
|
||
onPointerCancel={release}
|
||
>
|
||
<div className="kole-m-pullrefresh__indicator" role="status" aria-live="polite">
|
||
<span className="kole-m-pullrefresh__spinner" aria-hidden="true" />
|
||
<span className="kole-m-pullrefresh__text">{stateText}</span>
|
||
</div>
|
||
<div className="kole-m-pullrefresh__content">
|
||
{children}
|
||
<button
|
||
className="kole-m-pullrefresh__fallback"
|
||
type="button"
|
||
onClick={() => onRefresh && onRefresh()}
|
||
>
|
||
{fallbackLabel}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|