25 lines
1.5 KiB
TypeScript
25 lines
1.5 KiB
TypeScript
import { h } from '@ui-arch/frame';
|
|
import type { TimelineItem, TimelineProps } from './types.js';
|
|
|
|
/*** 单个时间线节点:绝对定位的语义色圆点 + 标题 / 时间 / 正文,pending 节点为虚线空心圈 ***/
|
|
function node(item: TimelineItem, pending: boolean): HTMLElement {
|
|
const dot = h('span', { class: `ua-tl-dot ua-tl-dot-${pending ? 'pending' : item.variant ?? 'default'}` });
|
|
const head = h('div', { class: 'ua-tl-head' },
|
|
h('span', { class: 'ua-tl-title' }, item.title),
|
|
item.time ? h('span', { class: 'ua-tl-time' }, item.time) : null);
|
|
const body = item.content ? h('p', { class: 'ua-tl-content' }, item.content) : null;
|
|
return h('li', { class: `ua-tl-item${pending ? ' is-pending' : ''}` }, dot, h('div', { class: 'ua-tl-body' }, head, body));
|
|
}
|
|
|
|
/*** 时间线:纵向事件流,mode 决定轴线在左 / 右 / 双侧交替;pending 为真时末尾补一个进行中节点 ***/
|
|
export function timeline(props: TimelineProps): HTMLElement {
|
|
const rows: TimelineItem[] = [...props.items]; // 复制入参,避免改动调用方数组
|
|
if (props.pending) rows.push({ title: '进行中…' }); // 尾部虚节点表示流程尚未结束
|
|
const items = rows.map((row, i) => {
|
|
const el = node(row, !!props.pending && i === rows.length - 1);
|
|
if (props.mode === 'alternate') el.classList.add(i % 2 ? 'is-right' : 'is-left'); // 交替排布:奇偶决定左右,轴线由样式表居中
|
|
return el;
|
|
});
|
|
return h('ol', { class: `ua-tl ua-tl-${props.mode ?? 'left'}` }, ...items);
|
|
}
|