【免费下载链接】answer-me-with-html
Answer me with HTML — an agent skill that answers hard questions with a one-page HTML you can actually read. 让 AI Agent 用一页 HTML 回答复杂问题。
本文以 answer-me-with-html 仓库中的timeline组件为对象,从它的三列行语法(时间 | 标题 | 备注)、*高亮标记和h/v方向参数讲起,结合组件源码、样式表与测试用例,完整拆解它的字段解析、横竖布局规则、渲染结构和报错机制。读完后你不仅能写出可复制运行的timeline代码块,还能理解每个语法细节背后对应的实现逻辑。
一、timeline 组件在仓库中的位置
answer-me-with-html 是一个让 AI Agent「用一页 HTML 回答复杂问题」的技能项目:把 Markdown 文本渲染成单页、分区块(panel)的信息页面。页面里的图表类内容不是靠图片,而是靠若干内置组件把围栏代码块(fenced code block)直接渲染成 HTML/CSS 图形。
timeline是这 9 个内置组件之一。组件注册表 src/components/index.js 中可以看到全部成员:callout、kv、timeline、annot、tree、limits、sequence、flow、ask,每个组件统一导出{ name, summary, syntax, example, render(text, ctx) }结构,并以围栏块的语言名(这里就是timeline)作为键注册进COMPONENTS这个 Map。
仓库为每个组件都准备了一张双语「用法卡片」,中文卡片即 site/presets/components/timeline.zh.md,对应英文版为 site/presets/components/timeline.md。卡片用 frontmatter 声明title: timeline,正文就是一个可直接使用的最小示例——一条三节点的发布计划:
5 月 | 设计评审 6 月 | 5% 用户灰度 *7 月 | 全量发布 | 灰度一周无报错后这张卡片虽然短,但它恰好覆盖了 timeline 语法的全部三个要素:两列基本行、可选第三列、*高亮项。下面以这个示例为骨架,逐层展开。
二、核心语法:每行一个节点,竖线分三列
timeline 的输入规则非常克制:
- 每行一个时间线节点;
- 用
|把一行分成至多三列:时间 | 标题 | 备注,前两列必填,第三列(备注/说明)可选; - 时间列以
*开头时,该节点被标记为高亮项(例如示例中的*7 月 | 全量发布,表示「当前最重要」或「目标」节点)。
把卡片示例逐行拆开看:
| 行 | 时间 | 标题 | 备注 | 高亮 |
|---|---|---|---|---|
5 月 \| 设计评审 | 5 月 | 设计评审 | 无 | 否 |
6 月 \| 5% 用户灰度 | 6 月 | 5% 用户灰度 | 无 | 否 |
*7 月 \| 全量发布 \| 灰度一周无报错后 | 7 月 | 全量发布 | 灰度一周无报错后 | 是 |
渲染结果就是横向排列的三个节点,中间用一条水平线串起,7 月节点的圆点会用主题强调色填充(高亮样式见第五节),标题下方再挂一行小字备注「灰度一周无报错后」。
组件在源码里也自带一份语法说明,位于 src/components/timeline.js 的syntax字段:
```timeline [h|v] time | title | note (optional) *time | title ← starts with *: highlights the item- By default ≤6 items are horizontal and >6 are vertical; the h / v argument forces a direction.
也就是说,围栏语言后面可以跟一个可选的方向参数(`h` 或 `v`),这属于卡片示例之外、源码 `syntax` 描述明确给出的完整能力。 ## 三、字段解析与校验:contentLines 和 fields timeline 的 `render` 函数([src/components/timeline.js#L14-L21](https://link.gitcode.com/i/4ab966a4b0d569dfc9c8b268eb9c40f4))对输入的解析只依赖 [src/components/error.js](https://link.gitcode.com/i/78c7a5975b8809f5705d50aae848f69b) 里两个共用工具: 1. **`contentLines(text)`**:把围栏块文本按行切开,去掉首尾空白,记录每行的相对行号(从 1 开始),并**跳过空行和以 `//` 开头的整行注释**。一个值得注意的细节:该函数的源码注释写的是「supports whole-line comments starting with `#`」,但实际过滤条件是 `startsWith('//')`——以源码实现为准,`//` 行会被当作注释略过,且这种跳过不影响行号计算,因为行号在过滤前就已记录。 2. **`fields(text)`**:用 `|` 切分一行并逐列 `trim`。 随后的逐行校验逻辑是([timeline.js#L15-L21](https://link.gitcode.com/i/63bec61297510f8af00e66bc57f14793)): - 切出的列数少于 2,或第二列为空 → 抛出 `ComponentError`,错误信息形如 `timeline line must be time | title | note: "只有一列"`,并携带**该行在围栏块内的相对行号**; - 第一列若以 `*` 开头,去掉星号后才是实际显示的时间(`parts[0].slice(1).trim()`); - 全部行解析完后,如果没有任何节点 → 抛出 `timeline needs at least one item`。 `ComponentError` 的 `line` 字段是「围栏块内相对行号」,[error.js 顶部注释](https://link.gitcode.com/i/16238be0df496e133b631f05a8509290) 说明由 `render.js` 负责把它换算回源码中的绝对行号——因此 Agent 在生成页面时若写错某一行,报错能精确定位到具体哪一行。测试用例 [test/components-basic.test.js#L66-L68](https://link.gitcode.com/i/1253d3bdcf56e46ed5ea75ec9375f82b) 验证了这一点:输入 `'a | b\n只有一列'` 时,断言错误抛在第 2 行(`throwsAt(..., 2)`)。 ## 四、横向还是纵向:6 个节点的分界线和 h/v 参数 timeline 唯一的可选参数是方向,完整判定逻辑在 [src/components/timeline.js#L22](https://link.gitcode.com/i/208d89214e42af2ddf6de21f051cd089) 一行: ```js const vertical = /\bv(ertical)?\b/.test(args) || (!/\bh(orizontal)?\b/.test(args) && items.length > 6);翻译成规则:
- 围栏语言后写
v或vertical→ 强制纵向; - 否则写了
h或horizontal→ 强制横向(两者同时出现时,v的判定在前,纵向优先); - 什么都没写 → 自动选择:不超过 6 个节点走横向,超过 6 个走纵向。
选择纵向的动机很直白:横向时间线每个节点是一等宽网格列,节点一多,标题和备注就会被挤得没法阅读,于是阈值 6 是「横向仍可读」的经验上限。
测试用例 test/components-basic.test.js#L60-L64 分别覆盖了这两条路径:拼 7 个节点断言输出含am-timeline--v;以及'a | b'加参数'v'也断言纵向。仓库内的真实预设也展示了显式用法,例如 site/presets/history.zh.md#L7-L14 用timeline h强制横向排了 6 个 Kubernetes 发展节点。
五、渲染结构:一个 ol、三四个 span、两条纯 CSS 连线
render的返回值是一个有序列表,方向体现在 class 和自定义属性上(timeline.js#L23-L26):
- 横向:
<ol class="am-timeline am-timeline--h" style="--n: N">,--n就是节点数; - 纵向:
<ol class="am-timeline am-timeline--v">; - 每个节点是
<li class="am-tl-item">(高亮项额外加am-tl-item--hi),内部依次是:<span class="am-tl-when">:时间,经esc()转义后输出;<span class="am-tl-dot">:圆点;<span class="am-tl-title">:标题,经mdInline()处理,即支持行内 Markdown;<span class="am-tl-text">:备注(仅第三列非空时生成),同样走mdInline()。
样式全部在 src/themes/base.css#L194-L216,关键机制:
- 横向连线:不是画一条贯穿全宽的线,而是每个
li用一个::before在top: 31px处画一段横跨本列的水平线,再由.am-timeline--h li:first-child::before { left: 50% }和li:last-child::before { right: 50% }让首尾两段只画到各自节点中点为止——这样连线天然对齐网格,列宽变化时不会错位; - 等宽网格:
grid-template-columns: repeat(var(--n, 1), minmax(0, 1fr))让 N 个节点均分整行宽度,minmax(0, 1fr)防止长标题把列撑爆; - 高亮点:
.am-tl-item--hi .am-tl-dot { background: var(--accent); border-color: var(--accent) }(base.css#L207)——所以卡片里*7 月的圆点会随主题变色(Blueprint 主题下为蓝色,见文首截图 F 面板中Now节点); - 纵向连线:改为每个
li的左边界线(border-left),li:last-child::before { display: none }让最后一项不再向下延伸;纵向模式下时间改用等宽字体(var(--font-mono))内联显示在圆点右侧; - 响应式:base.css#L423 在小屏断点下把横向时间线塌缩为单列堆叠。
关于安全性:时间、标题、备注中的 HTML 会被中和而非原样输出——test/raw-html.test.js#L185-L189 的测试标题即「kv, tree, timeline and callout filter their text too」,覆盖了Now | step <script> | wait <time>这类输入;test/images.test.js#L126-L128 则验证了第三列支持带空格路径的图片引用(如timeline\n2026 | UI | done)。
六、仓库中的真实用法
除了卡片示例,仓库里有两处可直接参考的 timeline 用法:
- examples/ste100.md#L88-L95:ASD-STE100 规范页的 F 区块「History」,4 个节点全部带第三列备注,最后一行
*Now | Free download | revised by the ASD STEMG高亮「现状」。这就是文首截图中那条横向时间线的来源;组件在 timeline.js#L13 的内置example(1979 | AECMA starts the study / 1986 | First guide published / *Now | Free download | ...)也取材自同一场景。 - site/presets/history.zh.md#L7-L14:6 个节点的
timeline h显式横向用例,展示了「备注列 + 高亮项 + 方向参数」三者的组合写法。
从源码结构看,timeline 还是视频模式的一部分容器:src/runtime/video.js#L111 把.am-timeline与.am-diagram、.am-tree、.am-kv、.am-limits并列为视频播放时可被定位/高亮的图表宿主,可推断该组件也参与页面的视频化呈现。
七、速查表
| 写法 | 效果 | 依据 |
|---|---|---|
5 月 \| 设计评审 | 一个基础节点(时间 + 标题) | timeline.js#L15-L20 |
第三列... \| 备注 | 标题下方的说明小字,可选 | 同上 |
*7 月 \| ... | 该节点圆点用主题强调色高亮 | base.css#L207 |
```timeline h | 强制横向(可写horizontal) | timeline.js#L22 |
```timeline v | 强制纵向(可写vertical;与h同现时v优先) | 同上 |
| 不写参数 | ≤6 节点横向,>6 节点纵向 | 同上 + 测试 |
空行 ///开头行 | 跳过,不生成节点,不影响行号 | error.js#L11-L16 |
缺\|或第二列为空 | 报错并给出围栏块内相对行号 | error.js#L2-L8、测试 |
这套语法的信息密度很高:三列文本、一个星号、一个单字母参数,就能表达「时间、标题、说明、重点、方向」五种信息,而渲染层完全由等宽网格加两条纯 CSS 伪元素连线完成,不依赖任何外部图表库——这正是 answer-me-with-html「一页 HTML 即可读」理念在时间线场景下的具体落点。
【免费下载链接】answer-me-with-html
Answer me with HTML — an agent skill that answers hard questions with a one-page HTML you can actually read. 让 AI Agent 用一页 HTML 回答复杂问题。
相关推荐
Answer Me with HTML 的 timeline 组件:用一行 Markdown 语法画出时间线与发布计划
Answer Me with HTML 的 timeline 组件:用一行 Markdown 语法画出时间线与发布计划 在 answer me with htm
answer-me-with-html 的 limits 组件详解:用一页预算条可视化“值 vs 上限”
answer me with html 的 limits 组件详解:用一页预算条可视化“值 vs 上限” limits 是 answer me with htm
answer-me-with-html 的 annot 组件:用逐句批注把写作点评画成一页 HTML
answer me with html 的 annot 组件:用逐句批注把写作点评画成一页 HTML annot(逐句点评)是 answer me with h
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考