首页右栏接入单页入口与公告置顶/全部页;Markdown 编辑器支持可视化时间线与 Git 导入;隐藏块改为 [hide]/[timeline] 命名闭合,并修复单页/公告 GORM 更新只改 updated_at 的问题。 Co-authored-by: Cursor <cursoragent@cursor.com>
68 lines
2.4 KiB
TypeScript
68 lines
2.4 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import { ExternalLink } from "lucide-react";
|
|
import {
|
|
groupTimelineByDate,
|
|
type TimelineItem,
|
|
} from "@/lib/timelineBlocks";
|
|
|
|
type MdTimelineProps = {
|
|
items: TimelineItem[];
|
|
/** 每项正文已渲染的 React 节点(与 items 等长);缺省则只显示纯文本 */
|
|
renderBody?: (item: TimelineItem, index: number) => ReactNode;
|
|
};
|
|
|
|
/**
|
|
* 按日分组的垂直时间线(更新树)。颜色走 CSS 令牌。
|
|
*/
|
|
export default function MdTimeline({ items, renderBody }: MdTimelineProps) {
|
|
if (!items.length) {
|
|
return <p className="meta px-1 py-2">暂无时间线条目</p>;
|
|
}
|
|
const groups = groupTimelineByDate(items);
|
|
let flat = 0;
|
|
|
|
return (
|
|
<div className="j13-timeline" role="list" aria-label="时间线">
|
|
{groups.map((g) => (
|
|
<div key={g.date} className="j13-timeline-day">
|
|
<div className="j13-timeline-day-label">
|
|
<time dateTime={g.date}>{g.date}</time>
|
|
</div>
|
|
<ul className="j13-timeline-items">
|
|
{g.items.map((it) => {
|
|
const idx = flat++;
|
|
return (
|
|
<li key={`${g.date}-${idx}-${it.title}`} className="j13-timeline-item" role="listitem">
|
|
<span className="j13-timeline-dot" aria-hidden />
|
|
<div className="j13-timeline-card">
|
|
<div className="j13-timeline-head">
|
|
<h3 className="j13-timeline-title">{it.title}</h3>
|
|
{it.sourceUrl ? (
|
|
<a
|
|
href={it.sourceUrl}
|
|
className="j13-timeline-src"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
data-tip="查看提交"
|
|
aria-label="查看提交"
|
|
>
|
|
<ExternalLink size={13} />
|
|
</a>
|
|
) : null}
|
|
</div>
|
|
{renderBody ? (
|
|
<div className="j13-timeline-body">{renderBody(it, idx)}</div>
|
|
) : it.body.trim() ? (
|
|
<div className="j13-timeline-body whitespace-pre-wrap">{it.body}</div>
|
|
) : null}
|
|
</div>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|