
Trmnl Paper Blade
- 4 installs
- 4 repo stars
- Updated April 9, 2026
- miantiao-me/trmnl-paper
Helps with ai & agent building tasks during AI-assisted development.
About
trmnl-paper-blade is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- trmnl-paper-blade
- AI & Agent Building
- AI-coding skill
Trmnl Paper Blade by the numbers
- 4 all-time installs (skills.sh)
- Ranked #13,348 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/miantiao-me/trmnl-paper --skill trmnl-paper-bladeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4 |
|---|---|
| repo stars | ★ 4 |
| Last updated | April 9, 2026 |
| Repository | miantiao-me/trmnl-paper ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
trmnl-paper-blade
概览
为 Laravel + trmnl-blade 生成可直接渲染的 Blade 组件 markup。优先复用 x-trmnl:: 组件和 Framework v3 的布局语义,避免自由拼接 CSS/HTML。
两个事实来源: 1. Framework v3 规则:结构层级、颜色系统、Overflow/Clamp/Content Limiter/Pixel Perfect 等运行时机制 2. trmnl-blade 实际封装范围:当前已有 Blade 组件(见下文),未封装的能力用原生 class
当前 Blade 组件
screen、mashup、view、layout、title-bar、columns、column、flex、grid、col、richtext、content、text、item、table、label、title、value、description、divider、meta、progress(progress-bar 封装)、track、clamp、background、aspect
未封装为 Blade 组件:chart(Highcharts/Chartkick JS)、image(原生 class)、progress-dots(原生 class)
工作流
1. 先确认目标:
- 新建一个 TRMNL 屏幕
- 把现有 HTML / 草图 / 数据说明改写成 TRMNL Blade
- 只要骨架,还是要完整屏幕
2. 再收集最小输入:
- 屏幕主题与核心数据
- 是否需要标题栏
- 是否需要双栏、列表、表格、图表、进度条、KPI、大字值、富文本
- 是否有设备、方向、位深等限制
3. 选择组件路径(优先使用高阶组件 / Components):
- 第一优先:Rich Text / Item / Table / Chart / Progress。当内容能落进这些现成模式时,不要先拆成零散
div、grid、flex - 文案、引言、通知、段落:
richtext(支持多级对齐、尺寸变体、Content Limiter);`markdown` 已废弃,改用 `richtext` - 列表、日程、事件:
item(支持 meta/index/icon/emphasis) - 结构化数据:简单表格可用
table(slot 内放<thead>/<tbody>,不要嵌套<table>);需要data-table-limit、table--indexed等附加属性时优先改用原生<table class="table ..."> - 数据可视化:Highcharts / Chartkick JS 原生用法(禁动画,灰度图案),无 Blade 组件封装
- 进度条:
<x-trmnl::progress>封装 progress-bar;progress-dots 用原生div.progress-dotsclass - KPI、大数字:
value(xxsmall~peta尺寸 +tnums)+label - 多区域 / 多列:
columns/mashup;严格列对齐用grid/colclass - 颜色背景:v3
bg--{token}/text--{token}优先直接写原生 class;backgroundBlade 封装是薄层,不覆盖 v3 全部 token
4. 从基础骨架开始,再填充模块。 5. 默认只负责生成 markup;API 推送说明交给 trmnl-paper-screen。
默认骨架
<x-trmnl::screen>
<x-trmnl::view>
<x-trmnl::layout>
<!-- content -->
</x-trmnl::layout>
<x-trmnl::title-bar title="..." />
</x-trmnl::view>
</x-trmnl::screen>- 无标题栏时可省略
title-bar - 需要分栏时优先用
columns/column - 需要居中堆叠时优先用
layout direction="col" alignment="center"
生成规则
- 优先使用
x-trmnl::组件,不先写自由 class - 当需求可直接映射到 Rich Text / Item / Table / Chart / Progress 时,先用这些高阶组件/模式,再考虑
columns、grid、flex - 先保证结构清晰,再考虑细节
- 保持层级少、信息密度可读
- 避免硬编码像素值
title/label/description默认不自动 clamp;可能溢出时显式使用data-clamp="1"等属性截断- 用户没有要求时,不要臆造未验证的 props
- props 不确定时,宁可使用默认 slot,也不要发明 API
- 输出完整屏幕时,优先给完整可渲染的 Blade 片段
- 输出局部模块时,说明它应插入
layout/column的位置
输出前自检
自动可校验(运行 validate_markup.py)
- [ ] 已运行
validate_markup.py校验结构层级与table使用规则(权威说明见references/design-rules.md)
python3 skills/trmnl-paper-blade/scripts/validate_markup.py <markup-file>仍需手工检查
- [ ] 优先使用已验证的
<x-trmnl::...>组件;chart/image/progress-dots用原生 class - [ ] 可能溢出的
title/label/description已显式加data-clamp - [ ] 如果只输出局部模块,已说明应插入
layout、column或mashup的位置
参考资料
- 组件速查(props / CSS 映射 / 用法):读
references/components/目录下对应组件文件 - v3 特性与升级差异:读
references/guides.md - 工具类与 data 属性(间距、尺寸、圆角、可见性等):读
references/attributes.md - 常用布局模板(可直接复制的完整示例):读
references/patterns.md - 官方示例索引:先读
references/examples/_index.md - 官方示例(完整 HTML 源码参考):读
references/examples/目录下对应文件 - v3 颜色系统完整参考(灰度 / 色度 / 语义色):读
references/colors.md - v3 设计约束(结构层级权威说明 / e-paper 规则):读
references/design-rules.md - 上游文档:https://trmnl.com/framework/docs/v3
- Blade 源码:https://github.com/bnussbau/trmnl-blade
可用脚本
- `scripts/validate_markup.py` — 校验 Blade markup 结构规则(title-bar 位置、layout 嵌套、view 必须且只能有一个 layout、table 内嵌原生 table、忽略 HTML/Blade 注释)
输出约定
默认按以下顺序输出:
1. Blade markup 2. 如有必要,补 1-3 条简短接入说明
如果用户只要代码,只输出代码。
管道输出
当 markup 需要直接传递给 trmnl-paper-screen 推送时:
- 保存到文件 →
trmnl-paper-screen通过--markup-file <path>读取 - 通过管道 →
echo '<markup>' | python3 skills/trmnl-paper-screen/scripts/push_screen.py --markup-stdin ...
交接格式
收到 trmnl-paper-screen 回传的问题清单时,每条问题使用以下最小字段格式:
- issue: 文案在标题栏溢出
location: x-trmnl::title-bar title 属性
suggested_fix: 缩短标题文案,或加 data-clamp="1"issue 描述问题现象,location 定位组件或属性,suggested_fix 给出最小修改方向。
属性与修饰符参考
本文件是工具类与 data-* 属性的主参考;utilities.md 保留为兼容入口,不再重复维护同类内容。所有能力均为纯 CSS 或 data-* 属性,无 Blade 封装。
---
内容调节
Clamp(文字截断)
截断文字到 N 行,基于单词 + 省略号,保留原始文本,宽度变化时自动重算。
<!-- 截断到 2 行 -->
<span class="description" data-clamp="2">很长的描述文字...</span>
<!-- 响应式:默认 2 行,中等屏 4 行,竖屏 1 行 -->
<span class="description"
data-clamp="2"
data-clamp-md="4"
data-clamp-portrait="1">描述文字</span>支持响应式后缀:data-clamp-sm、data-clamp-md、data-clamp-lg、data-clamp-portrait、data-clamp-sm-portrait、data-clamp-md-portrait、data-clamp-lg-portrait。
旧版 class 写法仍可用(会自动映射):clamp--none、clamp--1 ~ clamp--50。
Content Limiter(内容限高)
内容超出阈值时,自动添加 content--small class 并截断第一个溢出块。
<div class="content" data-content-limiter="true">
<p>内容段落...</p>
</div>
<!-- 自定义最大高度(像素) -->
<div class="content" data-content-limiter="true" data-content-max-height="140">
<p>内容段落...</p>
</div>Pixel Perfect(像素对齐)
1bit 渲染优化,确保文字锐利。高位深模式自动跳过。
<div data-pixel-perfect="true">...</div>Table Overflow(表格限行)
超出高度时自动截断行,末尾追加"and X more"。
<table class="table" data-table-limit="true">
...
</table>当前 trmnl-blade 的 x-trmnl::table 适合简单表格骨架。若需要 data-table-limit="true"、table--indexed 等附加属性/类,优先直接写原生 <table class="table ...">,避免属性丢失。
Overflow(列溢出)
columns 容器使用 Overflow 引擎自动分列:
<div class="columns" data-overflow-cols="2">...</div>
<div class="columns" data-overflow-max-cols="3">...</div>
<div class="columns" data-overflow-max-cols="2" data-overflow-max-cols-lg="3">...</div>
<!-- 显示溢出计数器 -->
<div class="columns" data-overflow-max-cols="2" data-overflow-counter="true">...</div>---
数值处理
Fit Value(自动缩放)
<!-- 单行自动缩放 -->
<span class="value value--xxxlarge" data-value-fit="true">$1,000,000</span>
<!-- 多行,限制最大高度 -->
<span class="value value--xxxlarge"
data-value-fit="true"
data-value-fit-max-height="340">长文本...</span>旧属性名 data-fit-value="true" 仍可用。
Format Value(数字格式化)
<!-- 自动千分位 + 缩写(K/M/B) -->
<span class="value value--xlarge value--tnums" data-value-format="true">2345678</span>
<!-- 货币 + 格式化 + 自动缩放 -->
<span class="value value--xlarge value--tnums"
data-value-format="true"
data-value-fit="true">$2345678</span>
<!-- 区域格式 -->
<span class="value value--large value--tnums"
data-value-format="true"
data-value-locale="de-DE">€123456.78</span>旧属性名 data-format-value="true" 仍可用。常用 locale:en-US、de-DE、fr-FR、en-GB、ja-JP。
支持的货币符号:$、€、£、¥、₴、₹、₪、₩、₫、₱、₽、₿。
---
颜色
详细色板见 references/colors.md。
背景色(Background)
<!-- 灰度 -->
<div class="bg--black">纯黑</div>
<div class="bg--gray-30">灰度背景</div>
<div class="bg--white">纯白</div>
<!-- 色度(hue 或 hue-step) -->
<div class="bg--red">纯红</div>
<div class="bg--blue-40">蓝 40</div>
<div class="bg--green-60">绿 60</div>
<!-- 语义色 -->
<div class="bg--primary">主色</div>
<div class="bg--success">成功</div>
<div class="bg--error">错误</div>
<div class="bg--warning">警告</div>文字颜色(Text Color)
<span class="text--black">黑色文字</span>
<span class="text--gray-40">灰色文字</span>
<span class="text--red">红色文字</span>
<span class="text--success">语义绿色文字</span>
<span class="text--white">白色文字</span>---
边框与描边
Border(抖动边框)
1(黑)~ 7(白),通过 dither pattern 模拟灰度强度,支持 high-density 1bit/2bit 渲染。
<div class="border--h-1">最深水平边框</div>
<div class="border--h-4">中间水平边框</div>
<div class="border--h-7">最浅水平边框</div>
<div class="border--v-1">最深垂直边框</div>v2 与 v1 不向后兼容:类名相同,但同一 N 值的视觉效果不同,升级时需重新评估 N 值。
Outline(像素级圆角边框)
1bit:CSS gradient 点阵;2bit/4bit:回退为标准 border-radius。
<div class="outline">有像素级圆角边框的内容</div>---
间距
Gap
<!-- 预设尺寸 -->
<div class="flex flex--col gap--none">...</div>
<div class="flex flex--col gap--xsmall">...</div>
<div class="flex flex--col gap--small">...</div>
<div class="flex flex--col gap">...</div> <!-- 默认 -->
<div class="flex flex--col gap--base">...</div> <!-- 同默认,用于响应式重置 -->
<div class="flex flex--col gap--medium">...</div>
<div class="flex flex--col gap--large">...</div>
<div class="flex flex--col gap--xlarge">...</div>
<div class="flex flex--col gap--xxlarge">...</div>
<!-- 分布修饰符 -->
<div class="flex flex--col gap--auto">...</div> <!-- space-evenly -->
<div class="flex flex--col gap--distribute">...</div> <!-- space-between -->
<!-- 任意像素值(0-50px,不支持响应式) -->
<div class="grid grid--cols-3 gap--[10px]">...</div>
<!-- 响应式 -->
<div class="grid grid--cols-3 gap--small md:gap--large lg:gap--xlarge portrait:gap--medium">...</div>Spacing(间距)
<div class="m--4">全方向 margin</div>
<div class="p--4">全方向 padding</div>
<div class="mt--2 mb--4 ml--2 mr--2">单方向 margin</div>
<div class="pt--2 pb--4 pl--2 pr--2">单方向 padding</div>---
尺寸
Size
<!-- 固定宽高 -->
<div class="w--32">宽度 32 单位</div>
<div class="h--full">满高</div>
<div class="w--full">满宽</div>
<!-- 任意像素值(支持响应式) -->
<div class="w--[250px] md:w--[400px]">响应式任意宽度</div>
<div class="h--[120px]">任意高度</div>
<!-- 容器查询单位(相对于 layout 容器,TRMNL X) -->
<div class="w--[50cqw]">layout 宽度的 50%</div>
<div class="h--[80cqh]">layout 高度的 80%</div>Aspect Ratio(宽高比,Beta)
<div class="aspect--1/1">正方形</div>
<div class="aspect--16/9">宽屏</div>
<div class="aspect--3/4">竖向</div>
<div class="aspect--auto">无约束</div>可用值:1/1、4/3、3/2、16/9、21/9、3/4、2/3、9/16、9/21。
---
圆角
<div class="rounded--none">无圆角(0px)</div>
<div class="rounded--xsmall">超小(5px)</div>
<div class="rounded--small">小(7px)</div>
<div class="rounded--base">默认(10px,用于响应式重置)</div>
<div class="rounded--medium">中(15px)</div>
<div class="rounded--large">大(20px)</div>
<div class="rounded--xlarge">超大(25px)</div>
<div class="rounded--xxlarge">最大(30px)</div>
<div class="rounded--full">完全圆形(9999px)</div>
<div class="rounded--[8px]">任意值(从 0px 起)</div>---
图片
Image(图片处理)
<img class="image image-dither" src="photo.jpg"> <!-- 1bit 抖动优化 -->Image Stroke(图片描边)
给透明/矢量图像添加描边,确保在着色背景上可读。
<!-- 默认白色描边(1.5px) -->
<img class="image-stroke" src="icon.svg">
<!-- 尺寸变体 -->
<img class="image-stroke image-stroke--small" src="icon.svg"> <!-- 1px -->
<img class="image-stroke image-stroke--base" src="icon.svg"> <!-- 1.5px -->
<img class="image-stroke image-stroke--medium" src="icon.svg"> <!-- 2px -->
<img class="image-stroke image-stroke--large" src="icon.svg"> <!-- 2.5px -->
<img class="image-stroke image-stroke--xlarge" src="icon.svg"> <!-- 3px -->
<!-- 黑色描边(用于暗背景上的白色图标) -->
<img class="image-stroke image-stroke--black" src="white-icon.svg">---
缩放(Beta)
<div class="scale--90">缩小至 90%</div>
<div class="scale--95">缩小至 95%</div>
<div class="scale--100">原始大小</div>
<div class="scale--105">放大至 105%</div>
<div class="scale--110">放大至 110%</div>---
文字工具
Text Alignment
<div class="text--left">左对齐</div>
<div class="text--center">居中</div>
<div class="text--right">右对齐</div>
<div class="text--justify">两端对齐</div>
<!-- 响应式 -->
<div class="text--left portrait:text--center">横屏左对齐,竖屏居中</div>Text Stroke(文字描边)
着色背景上的文字辅助描边:
<span class="value text-stroke">128</span>
<span class="value text-stroke text-stroke--base">128</span>---
可见性
<div class="hidden">隐藏</div>
<div class="visible">显示</div>
<div class="hidden-1bit">1bit 设备上隐藏</div>
<div class="hidden-2bit">2bit 设备上隐藏</div>
<div class="hidden-4bit">4bit 设备上隐藏</div>---
响应式前缀
| 前缀类型 | 值 | 说明 |
|---|---|---|
| 断点 | sm:, md:, lg: | 屏幕宽度(mobile-first) |
| 方向 | portrait: | 仅竖屏变体;横屏是默认态 |
| 位深 | 1bit:, 2bit:, 4bit: | 仅命中特定位深,不是渐进式 |
| 主题 | dark: | 仅 Visibility / Background / Text 支持,且必须放在最前 |
断点
| 前缀 | 最小宽度 | 常见设备 |
|---|---|---|
sm: | 600px | Kindle 2024 |
md: | 800px | TRMNL OG、TRMNL OG V2 |
lg: | 1024px | TRMNL V2 |
sm:/md:/lg:遵循 mobile-first:md:对中屏及更大屏生效- 位深前缀不遵循 mobile-first:
4bit:只对 4-bit 设备生效,不会命中 1-bit / 2-bit
组合顺序与优先级
- 标准顺序:
size:orientation:bit-depth:utility - 带暗色模式时:
dark:size:orientation:bit-depth:utility - 修饰符越多,优先级越高;例如
portrait:2bit:label--filled会覆盖portrait:label--underline
组件支持矩阵
Auto 表示框架已内建适配,通常不必手写该维度前缀。
| 能力 | Size | Orientation | Bit-Depth | 说明 |
|---|---|---|---|---|
| Background | ✅ | ✅ | Auto | 背景色自动适配位深 |
| Border | ❌ | ❌ | Auto | 无 md:border--* |
| Text | ✅ | ✅ | Auto | 文本工具自动适配位深 |
| Visibility | ✅ | ✅ | ✅ | 可与 1bit: / 2bit: / 4bit: 组合 |
| Value | ✅ | ✅ | ❌ | 无 4bit:value--large |
| Label | ✅ | ✅ | ✅ | 支持多重组合 |
| Spacing | ✅ | ✅ | ❌ | margin / padding |
| Gap | ✅ | ✅ | ❌ | gap 工具类 |
| Layout / Flex | ✅ | ✅ | ❌ | 布局方向/对齐 |
| Grid | ✅ | ✅ | ❌ | 列数 / span |
| Rounded / Size | ✅ | ✅ | ❌ | 圆角 / 宽高 |
| Clamp / Overflow | ✅ | ✅ | ❌ | data-clamp-* / data-overflow-* |
<span class="title sm:title--small lg:title--large">响应式标题</span>
<span class="value value--small md:value--base">响应式数值</span>
<div class="grid grid--cols-2 portrait:grid--cols-1">响应式网格</div>
<div class="dark:md:hidden">暗色中屏以上隐藏</div>---
v3 颜色系统
本文件是 v3 颜色 token、语义色与设备回退策略的完整参考。若关注升级差异或迁移注意事项,请读 references/guides.md。
---
灰度色阶
14 步灰度,从 gray-10(最深)到 gray-75(最浅)。大部分相邻步进为 6.25% 白像素密度,但 gray-40(43.75%)与 gray-45(56.25%)之间有一个 12.5% 的 center spacer。
| Token | 1bit 白像素密度 | 说明 |
|---|---|---|
gray-10 | 6.25% | 最深灰 |
gray-15 | 12.5% | |
gray-20 | 18.75% | |
gray-25 | 25% | |
gray-30 | 31.25% | |
gray-35 | 37.5% | |
gray-40 | 43.75% | |
gray-45 | 56.25% | |
gray-50 | 62.5% | |
gray-55 | 68.75% | |
gray-60 | 75% | |
gray-65 | 81.25% | |
gray-70 | 87.5% | |
gray-75 | 93.75% | 最浅灰 |
旧版gray-1~gray-7仍可用但已废弃,新代码应使用gray-10~gray-75。
- 1bit 模式:灰度使用 dither pattern(16×16 px 抖动)
- 2bit/4bit+ 模式:使用实色渲染
---
色度色(Chromatic Colors)
10 种色相,每种 14 级亮度步进(10 最深 ~ 75 最浅)。
色相列表:red、orange、yellow、lime、green、cyan、blue、violet、purple、pink
用法:
- 纯色相:
bg--red、text--blue(使用基础全饱和色) - 色相 + 步进:
bg--red-40、text--green-60(亮度变体)
<div class="bg--blue-30 p--3">
<span class="text--white">深蓝背景白字</span>
</div>---
语义颜色(Semantic Colors)
按意图而非具体色相来样式化,可通过 CSS 变量主题化。
| 语义 | 映射色相 | 用途 |
|---|---|---|
primary | blue | 高亮、重点 |
success | green | 确认、正向状态 |
error | red | 错误、严重状态 |
warning | orange | 警告、提醒 |
用法:bg--primary、text--success、label--error、bg--warning
覆盖默认映射:
.screen {
--color-primary: var(--violet);
--color-success: var(--cyan);
}---
背景工具类
bg--{token} 统一用法,支持灰度、色度、语义三种 token。
<div class="bg--gray-30">灰度背景</div>
<div class="bg--red-40">色度背景</div>
<div class="bg--primary">语义背景</div>
<div class="bg--black">纯黑背景</div>
<div class="bg--white">纯白背景</div>---
文字颜色
text--{token} 同样支持灰度、色度、语义 token。
<span class="text--gray-40">灰色文字</span>
<span class="text--red">红色文字</span>
<span class="text--success">语义绿色文字</span>---
Label 颜色变体 (v3)
<span class="label label--primary">Key Info</span>
<span class="label label--success">Passed</span>
<span class="label label--error">Failed</span>
<span class="label label--warning">Caution</span>
<span class="label label--filled">Default Black</span>---
设备适配
- 灰度设备:色度 token 自动回退为感知等效灰值(基于 LAB L*)
- 有限色彩设备(如 B/W/R/Y):不支持的色相自动映射到最近可用色
- 暗色模式:灰度 token 自动反转;色度色亮度步进镜像
- 无需编写条件逻辑,框架通过 CSS 变量自动处理
---
aspect
作用
宽高比容器,用于保持元素固定的宽高比(如 16:9、1:1、4:3 等),配合图片或图表使用,防止在不同屏幕尺寸下变形。
Blade / 原生写法
{{-- Blade 组件 --}}
<x-trmnl::aspect ratio="16/9">
<img class="image image--cover" src="/path/to/image.jpg" alt="">
</x-trmnl::aspect><!-- 原生 HTML(使用工具类) -->
<div class="aspect aspect--16/9">
<img class="image image--cover" src="/path/to/image.jpg" alt="">
</div>
<!-- 或使用 CSS 自定义属性 -->
<div style="aspect-ratio: 16/9;">
<img class="image image--cover" src="/path/to/image.jpg" alt="">
</div>关键 props / class / 属性
Blade prop ratio | 说明 |
|---|---|
1/1 | 正方形 |
4/3 | 传统横屏比例 |
16/9 | 宽屏比例 |
3/2 | 标准摄影比例 |
注意事项
- 内部图片通常配合
image--cover使用以填满比例容器 - e-paper 屏幕分辨率固定,aspect 主要用于图片/图表的一致性展示
最小示例
<x-trmnl::layout>
<x-trmnl::aspect ratio="16/9">
<img class="image image--cover" src="/screenshots/dashboard.jpg" alt="截图">
</x-trmnl::aspect>
</x-trmnl::layout>来源
- trmnl-blade 源码:
src/View/Components/Aspect.php
background
作用
背景色包装组件(x-trmnl::background),用于给区块设置背景色 token。但完整的 v3 颜色系统(bg--token / text--token 工具类)优先直接使用原生 class,而非依赖此组件。
重要:backgroundwrapper 不是 v3 颜色系统的完整封装。大多数颜色需求建议直接使用bg--*/text--*工具类。
Blade / 原生写法
{{-- Blade 组件(简单背景包装) --}}
<x-trmnl::background color="black">
内容
</x-trmnl::background><!-- 推荐:直接使用原生工具类 -->
<div class="bg--black text--white p--4">
<span class="label">深色区块</span>
</div>
<div class="bg--gray-20">
<span class="label">浅灰背景</span>
</div>颜色工具类(原生)
背景色:bg--black / bg--white / bg--gray-{N} / bg--{semantic-color}
文字色:text--black / text--white / text--{semantic-color}
灰度阶梯(bg--gray-N,N 越小越深):gray-10 / gray-20 / gray-30 / ... / gray-70 / gray-75
深色模式下颜色 token 自动重映射(通过 screen--dark-mode)。
注意事项
- 优先用
bg--*/text--*工具类,而非x-trmnl::background background组件当前接收colorprop,输出的是bg-{color}这一薄包装- 颜色详情见
references/colors.md
最小示例
<!-- 黑色背景区块(直接用工具类) -->
<div class="bg--black p--4 rounded">
<span class="value value--large text--white">42</span>
<span class="label text--white">完成</span>
</div>来源
- Framework v3 颜色文档:https://trmnl.com/framework/docs/v3/colors
- trmnl-blade 源码:
src/View/Components/Background.php - 详细颜色参考:
references/colors.md
chart
作用
在 TRMNL 屏幕上渲染折线图、柱状图、仪表盘等图表。使用 JS 图表库(Highcharts / Chartkick),通过 <div id="chart-xxx"> 作为挂载点。
注意:这是框架能力 + 原生 HTML + JS 用法,不是 trmnl-blade 的 Blade 组件。无 <x-trmnl::chart> 可用。原生写法
<!-- 1. 引入库(Highcharts 推荐) -->
<script src="https://trmnl.com/js/highcharts/12.3.0/highcharts.js"></script>
<script src="https://trmnl.com/js/chartkick/5.0.1/chartkick.min.js"></script>
<!-- 2. 挂载容器 -->
<div id="my-chart" class="w--full"></div>
<!-- 3. 初始化(关键:禁用动画) -->
<script>
new Chartkick["LineChart"]("my-chart", data, {
adapter: "highcharts",
colors: ["black"],
library: {
chart: { height: 260, backgroundColor: "transparent" },
plotOptions: { series: { animation: false } }
}
});
</script>关键配置要点
| 配置 | 说明 |
|---|---|
animation: false | 必须禁用,截图渲染服务无法捕获动画中间帧 |
backgroundColor: "transparent" | 透明背景,融合屏幕色 |
colors: ["black"] | 1-bit 显示只用黑色 |
height: null / 固定值 | null 自动填满容器;或指定像素 |
| 灰度 pattern | 多系列用 https://trmnl.com/images/grayscale/gray-N.png 填充 |
注意事项
- 所有动画必须关闭(
animation: false) - 多系列图使用灰度点阵图案区分(
pattern-fill.js) - 图表通常放在
layout layout--col gap--space-between内,顶部展示 KPI 数据,底部放图表容器 - 确保图表加载在截图之前完成(监听
chartkick:load)
最小示例(折线图)
<script src="https://trmnl.com/js/highcharts/12.3.0/highcharts.js"></script>
<script src="https://trmnl.com/js/chartkick/5.0.1/chartkick.min.js"></script>
<div class="layout layout--col gap--space-between">
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value value--tnums">1,234</span>
<span class="label">访问量</span>
</div>
</div>
<div id="visits-chart" class="w--full"></div>
</div>
<script>
var data = [["2024-01-01", 400], ["2024-01-02", 600], ["2024-01-03", 500]];
function initChart() {
new Chartkick["LineChart"]("visits-chart", data, {
adapter: "highcharts",
colors: ["black"],
library: {
chart: { height: 200, backgroundColor: "transparent" },
plotOptions: { series: { animation: false, lineWidth: 3 } }
}
});
}
if ("Chartkick" in window) { initChart(); }
else { window.addEventListener("chartkick:load", initChart, true); }
</script>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/chart
- Highcharts:https://highcharts.com
- Chartkick:https://chartkick.com
clamp
作用
文字截断(Clamp 引擎)工具,将文字限制在指定行数内,超出部分显示省略号。Framework v3 推荐直接在真实文字元素上使用 data-clamp="N"。
用法
文字截断(通用)
不需要单独的 Blade 组件,直接在任意文字元素上添加 data-clamp 属性:
<!-- 截断为 1 行 -->
<span class="label" data-clamp="1">很长的标题文字,超出后显示省略号...</span>
<!-- 截断为 2 行 -->
<span class="description" data-clamp="2">可以显示两行的说明内容...</span>
<!-- 截断为 3 行 -->
<span class="title" data-clamp="3">允许三行的长标题...</span>Blade 组件(兼容写法)
<x-trmnl::clamp lines="2">很长的说明文字</x-trmnl::clamp>关键属性
| 属性 | 说明 |
|---|---|
data-clamp="N" | 截断至 N 行,超出显示 ... |
使用场景
label、description、title内容过长时防溢出table单元格内截断长文本(data-clamp="1")item内的 description 限制行数
注意事项
- 框架默认不截断,必须显式添加
data-clamp - Clamp 引擎基于字宽测量,resize 时会重新计算
x-trmnl::clamp本质是一个便利包装;若你需要保留原本标签语义,优先直接给真实文字元素加data-clamp
最小示例
<!-- 表格单元格 1 行截断 -->
<td>
<span class="label label--small" data-clamp="1">很长的内容文字</span>
</td>
<!-- item 说明 2 行截断 -->
<span class="description" data-clamp="2">这是一段较长的说明文字,用来描述任务的背景和目的</span>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/clamp
- trmnl-blade 源码:
src/View/Components/Clamp.php
col
作用
grid 的子组件,表示网格内的一列/单元格。可控制跨列数和垂直对齐。
Blade / 原生写法
<x-trmnl::grid cols="3">
<x-trmnl::col span="2" position="center">
内容
</x-trmnl::col>
<x-trmnl::col span="1">
内容
</x-trmnl::col>
</x-trmnl::grid><div class="grid grid--cols-3">
<div class="col col--span-2 col--center">内容</div>
<div class="col col--span-1">内容</div>
</div>关键 props / class / 属性
| Blade prop | 原生 class | 说明 |
|---|---|---|
span="N" | col--span-N | 跨 N 个网格列(N 可为 1~12) |
position="start" | col--start | 内容顶部对齐 |
position="center" | col--center | 内容垂直居中 |
position="end" | col--end | 内容底部对齐 |
注意事项
- 必须作为
grid的直接子节点 - 所有
col--span-N之和应等于父grid--cols-N
最小示例
<x-trmnl::grid cols="4">
<x-trmnl::col span="3">主区域</x-trmnl::col>
<x-trmnl::col span="1">侧边</x-trmnl::col>
</x-trmnl::grid>来源
- trmnl-blade 源码:
src/View/Components/Col.php
column
作用
columns 的子组件,代表一列内容。通常直接包含 item 列表。
Blade / 原生写法
<x-trmnl::columns>
<x-trmnl::column>
<!-- 列内容 -->
</x-trmnl::column>
</x-trmnl::columns><div class="columns">
<div class="column">
<!-- 列内容 -->
</div>
</div>关键 props / class / 属性
- 无独立 props,宽度由父
columns等分决定 - 可在
column上附加 gap 类(如gap、gap--small)控制内部间距
注意事项
- 必须作为
columns的直接子节点 - 不要在
column内嵌套columns
最小示例
<x-trmnl::columns>
<x-trmnl::column>
<div class="item">
<div class="content">
<span class="title title--small">标题</span>
</div>
</div>
</x-trmnl::column>
<x-trmnl::column>
<div class="item">
<div class="content">
<span class="title title--small">标题</span>
</div>
</div>
</x-trmnl::column>
</x-trmnl::columns>来源
- trmnl-blade 源码:
src/View/Components/Column.php
columns
作用
用于同类型数据的多列布局。自动分配条目到各列,处理溢出(显示"还有 X 条"),适合列表、日程等不确定数量的内容。严格对齐或固定列宽请用 grid。
Blade / 原生写法
{{-- Blade 组件 --}}
<x-trmnl::columns>
<x-trmnl::column>
<!-- 列内容 -->
</x-trmnl::column>
<x-trmnl::column>
<!-- 列内容 -->
</x-trmnl::column>
</x-trmnl::columns><!-- 原生 HTML -->
<div class="columns">
<div class="column">...</div>
<div class="column">...</div>
<div class="column">...</div>
</div>关键 props / class / 属性
columns:父容器,等分所有columncolumn:单列,直接包含条目内容- 列数由 DOM 中
column的数量决定,无需手动设置列宽
注意事项
- 放在
layout内部 - 列数量固定(你写几个
column就有几列) - 溢出条目会被隐藏并附加"and X more"提示(需配合 Overflow 引擎)
- 与
grid的区别:columns用于同质列表,不需要跨列对齐;grid用于精确对齐结构
最小示例
<x-trmnl::layout>
<x-trmnl::columns>
<x-trmnl::column>
<div class="item">
<div class="content">
<span class="title title--small">任务 A</span>
<span class="description">描述</span>
</div>
</div>
</x-trmnl::column>
<x-trmnl::column>
<div class="item">
<div class="content">
<span class="title title--small">任务 B</span>
<span class="description">描述</span>
</div>
</div>
</x-trmnl::column>
</x-trmnl::columns>
</x-trmnl::layout>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/columns
- trmnl-blade 源码:
src/View/Components/Columns.php、Column.php
content
作用
richtext 的子组件,承载实际文字内容(段落、标题等)。控制文字块的尺寸、对齐和溢出适应。尺寸通过 class 控制,不是 prop。
Blade / 原生写法
{{-- 通常嵌套在 richtext 内使用 --}}
<x-trmnl::richtext>
<x-trmnl::content contentAlignment="center" textAlignment="center">
<p>正文内容</p>
</x-trmnl::content>
</x-trmnl::richtext><!-- 原生 HTML -->
<div class="content content--large text--center gap">
<p>正文内容</p>
</div>关键 props / class / 属性
Blade props
| prop | 可选值 | 说明 |
|---|---|---|
contentAlignment | left、center、right | content 块对齐(content--left 等) |
textAlignment | left、center、right | 文字对齐(text--left 等) |
gapSize | gap 值 | 内部 gap 间距 |
尺寸 class(加在 content div 上)
content--small / content--base / content--large / content--xlarge / content--xxlarge / content--xxxlarge
支持响应前缀:lg:content--xxlarge、portrait:content--small、1bit:content--large
溢出处理 data 属性
| 属性 | 说明 |
|---|---|
data-content-limiter="true" | 超出时自动缩小字号适应容器 |
data-content-max-height="140" | 手动限制最大高度(px) |
注意事项
- 尺寸用 class 附加,不是 Blade prop
content--base与无修饰符等价,用于响应式重置- 在
richtext外独立使用content也合法
最小示例
<div class="richtext richtext--center gap--large">
<div class="content content--xlarge text--center" data-content-limiter="true">
<p>今日名言:行动是治愈恐惧的良药。</p>
</div>
</div>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/rich_text(Content Limiter 节)
- trmnl-blade 源码:
src/View/Components/Content.php
description
作用
次要说明文字组件,用于条目副标题、补充说明、元信息等。字号比 label 更小,视觉层级低于 title。
Blade / 原生写法
{{-- trmnl-blade 提供 x-trmnl::description 组件 --}}
<x-trmnl::description>补充说明文字</x-trmnl::description><!-- 原生 HTML -->
<span class="description">补充说明文字</span>
<span class="description description--large">较大说明</span>关键 props / class / 属性
尺寸 class
| class | 字号(1-bit) |
|---|---|
description(默认) | 16px(NicoPups 字体) |
description--large | 16px(NicoClean,同字号但字形更清晰) |
description--xlarge | 21px |
description--xxlarge | 24px |
响应前缀:lg:description--xlarge、portrait:description--base
截断
data-clamp="1" / data-clamp="2" — 超出行数显示省略号
注意事项
x-trmnl::description支持属性透传,可直接在组件标签上加data-clamp- 默认不截断,在空间受限的条目中建议显式加
data-clamp - 在
item内通常紧跟title title--small之后
最小示例
<div class="item">
<div class="content">
<span class="title title--small">团队会议</span>
<span class="description" data-clamp="1">每周一次全员同步</span>
</div>
</div>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/description
- trmnl-blade 源码:
src/View/Components/Description.php
divider
作用
视觉分隔线,用于水平或垂直分割内容区域。x-trmnl::divider 适合基础水平分隔;垂直分隔与更细控制通常直接用原生 class。
Blade / 原生写法
{{-- trmnl-blade 提供 x-trmnl::divider 组件 --}}
<x-trmnl::divider /><!-- 原生 HTML -->
<div class="divider"></div> <!-- 水平 -->
<div class="divider divider--vertical"></div> <!-- 垂直 -->关键 props / class / 属性
方向
| class | 说明 |
|---|---|
divider | 水平分隔线 |
divider divider--vertical | 垂直分隔线 |
注意事项
x-trmnl::divider只输出基础<div class="divider">- 需要垂直分隔时直接写原生 HTML class 更明确
最小示例
<div class="layout layout--col gap">
<span class="label">区域 A</span>
<div class="divider"></div>
<span class="label">区域 B</span>
</div>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/divider
- trmnl-blade 源码:
src/View/Components/Divider.php
flex
作用
基于 CSS Flexbox 的布局容器,支持行/列方向、对齐、伸展、换行等。适合内容驱动的弹性布局(宽高随内容变化)。严格列对齐用 grid,同质数据列表用 columns。
Blade / 原生写法
{{-- Blade 组件 --}}
<x-trmnl::flex direction="row" alignment="center" stretch="y">
<div>...</div>
<div>...</div>
</x-trmnl::flex><!-- 原生 HTML -->
<div class="flex flex--row flex--center flex--stretch-y">
<div>...</div>
<div>...</div>
</div>关键 props / class / 属性
Blade props
| prop | 可选值 |
|---|---|
direction | row、col、row-reverse、col-reverse |
alignment | left、center、right、top、bottom、center-x、center-y、between、around、evenly |
stretch | true、x、y |
原生 class
方向:flex--row / flex--col / flex--row-reverse / flex--col-reverse
对齐:flex--left / flex--center / flex--right / flex--top / flex--bottom / flex--center-x / flex--center-y / flex--between / flex--around / flex--evenly
伸展(容器):flex--stretch / flex--stretch-x / flex--stretch-y
伸展(子元素):stretch / stretch-x / stretch-y / no-shrink
换行:flex--wrap / flex--nowrap / flex--wrap-reverse
子元素独立:grow / shrink-0 / flex-none / self--start / self--center / self--end / self--stretch
响应前缀:portrait:flex--col 等
注意事项
flex本身不产生 gap,需额外加gapclass- 可嵌套在
grid单元格内使用
最小示例
<x-trmnl::layout>
<x-trmnl::flex direction="row" alignment="between">
<span class="label">标签</span>
<span class="value">42</span>
</x-trmnl::flex>
</x-trmnl::layout>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/flex
- trmnl-blade 源码:
src/View/Components/Flex.php
grid
作用
CSS Grid 布局系统,提供精确的列数控制和跨列能力。适合需要严格列对齐的"网格型"设计。弹性内容用 flex,同质数据列表用 columns。
Blade / 原生写法
{{-- Blade 组件(cols 控制列数) --}}
<x-trmnl::grid cols="3">
<x-trmnl::col span="2">...</x-trmnl::col>
<x-trmnl::col span="1">...</x-trmnl::col>
</x-trmnl::grid><!-- 原生 HTML -->
<div class="grid grid--cols-3">
<div class="col col--span-2">...</div>
<div class="col col--span-1">...</div>
</div>关键 props / class / 属性
grid Blade props / class
Blade prop cols | 原生 class | 说明 |
|---|---|---|
2 ~ N | grid--cols-2 等 | 等宽列数 |
| — | grid--wrap | 启用自动换行 |
| — | grid--min-{size} | 换行时最小列宽(配合 grid--wrap) |
col Blade props / class
| Blade prop | 原生 class | 说明 |
|---|---|---|
span="N" | col--span-N | 跨 N 列 |
position="start/center/end" | col--start 等 | 列内垂直对齐 |
其他原生 class
row/row--start/row--center/row--end:行内水平对齐
注意事项
- 一行内所有
col--span-N的总和应等于grid--cols-N col在grid内表示"垂直排列的格子";row表示"水平排列的格子"- 可在
col/row内嵌套flex做二次布局
最小示例
<div class="layout">
<div class="grid grid--cols-3">
<div class="col">
<span class="value value--large">1</span>
<span class="label">指标 A</span>
</div>
<div class="col">
<span class="value value--large">2</span>
<span class="label">指标 B</span>
</div>
<div class="col">
<span class="value value--large">3</span>
<span class="label">指标 C</span>
</div>
</div>
</div>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/grid
- trmnl-blade 源码:
src/View/Components/Grid.php、Col.php
image
作用
图片显示,支持抖动(dithering)处理以适应 1-bit 黑白电子墨水屏,以及对象适应方式控制。
注意:这是框架级 HTML class 能力,不是 trmnl-blade 的完整 Blade 组件。直接使用原生 <img> 加 class。原生写法
<!-- 基础图片(title_bar 内的图标) -->
<img class="image" src="/icons/plugin.svg" alt="">
<!-- 带抖动(1-bit 灰度模拟) -->
<img class="image image-dither rounded" src="/path/to/photo.jpg" alt="">
<!-- 对象适应 -->
<img class="image image--fill" src="/path/to/photo.jpg" alt="">
<img class="image image--contain" src="/path/to/photo.jpg" alt="">
<img class="image image--cover" src="/path/to/photo.jpg" alt="">关键 class / 属性
| class | 说明 |
|---|---|
image | 基础图片样式 |
image-dither | 抖动处理(1-bit 灰度仿真) |
image--fill | 拉伸填满容器(可能变形) |
image--contain | 保持比例缩入容器(留白) |
image--cover | 保持比例裁剪填满容器 |
rounded | 圆角(可组合) |
注意事项
image-dither在截图渲染时将灰度图转换为黑白点阵图案- 图片尺寸建议通过
w--*/h--*工具类控制,不要硬编码 px title_bar内的图标使用class="image"即可(无需 dither)
最小示例
<!-- 在 item 内展示天气图标 -->
<div class="item">
<div class="icon">
<img class="image w--[6cqw] h--[6cqw]" src="/icons/wi-sunny.svg" alt="">
</div>
<div class="content">
<span class="value value--small">25°C</span>
<span class="label">晴天</span>
</div>
</div>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/image
item
作用
列表条目容器,用于日程、事件、待办等结构化列表内容。由 meta(可选,左侧细条/索引区域)+ 可选 icon + content(主体)组成。
Blade / 原生写法
{{-- 基础 item 可用 Blade 组件 --}}
<x-trmnl::item>
<div class="meta"></div>
<div class="content">
<span class="title title--small">任务标题</span>
<span class="description">描述文字</span>
</div>
</x-trmnl::item><!-- 基础结构(带 meta 区域) -->
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="title title--small">任务标题</span>
<span class="description">描述文字</span>
</div>
</div>
<!-- 带索引编号 -->
<div class="item">
<div class="meta">
<span class="index">1</span>
</div>
<div class="content">
<span class="title title--small">第一条</span>
</div>
</div>
<!-- 带图标 -->
<div class="item">
<div class="meta"></div>
<div class="icon">
<img src="/icons/weather.svg" class="w--[6cqw] h--[6cqw]" />
</div>
<div class="content">
<span class="value value--small">72°</span>
<span class="label">温度</span>
</div>
</div>关键 props / class / 属性
变体 class
| class | 说明 |
|---|---|
item | 基础条目 |
item--emphasis-1 | 左侧 meta 条 - 浅色强调 |
item--emphasis-2 | 左侧 meta 条 - 中等强调 |
item--emphasis-3 | 左侧 meta 条 - 深色强调 |
子结构
meta:左侧细条区域,可包含span.index(编号)icon:图标区域(可选)content:主体,包含title、description、label等
注意事项
x-trmnl::item是基础包装;若需要item--emphasis-*等额外 class,优先直接写原生 HTML- 无 meta 时可省略
<div class="meta"></div>(简洁变体) index在meta内,显示序号item通常配合columns/flex列表使用
最小示例
<div class="item item--emphasis-2">
<div class="meta"></div>
<div class="content">
<span class="title title--small">每日站会</span>
<span class="description">10:00 AM</span>
<div class="flex gap--small">
<span class="label label--small label--outline">已确认</span>
</div>
</div>
</div>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/item
- trmnl-blade 源码:
src/View/Components/Item.php
label
作用
行内文字标签,用于状态标记、标签、次要说明文字。支持多种外观变体(轮廓、下划线、填充等)和五档尺寸。
Blade / 原生写法
{{-- trmnl-blade 提供 x-trmnl::label 组件 --}}
<x-trmnl::label variant="outline" size="small">已确认</x-trmnl::label><!-- 原生 HTML -->
<span class="label label--small label--outline">已确认</span>关键 props / class / 属性
Blade props
| prop | 可选值 |
|---|---|
variant | outline、underline、gray、filled、primary、success、error、warning |
size | small、base(默认)、large、xlarge、xxlarge |
原生 class
变体:
label--outline:带边框label--underline:下划线label--gray:灰色(弱化)label--filled:黑色背景填充label--primary/label--success/label--error/label--warning:语义色
尺寸:label--small / label--large / label--xlarge / label--xxlarge
截断:data-clamp="1" 或 data-clamp="2"
响应前缀:lg:label--xlarge、portrait:label--small、1bit:label--filled
兼容别名
label--gray-out→label--gray(已弃用但有效)label--inverted→label--filled(已弃用但有效)
注意事项
- 默认无背景、无边框(纯文字)
label--filled使用黑色背景;语义色变体(primary等)用对应颜色 token- 默认不截断,可能溢出时显式加
data-clamp
最小示例
<span class="label label--small label--outline">待处理</span>
<span class="label label--small label--filled">已完成</span>
<span class="label label--small label--error">失败</span>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/label
- trmnl-blade 源码:
src/View/Components/Label.php
layout
作用
view 内的核心内容容器,每个 view 有且只有一个 layout。高度由框架根据设备/方向/是否有 title-bar 自动计算。内部用 flex、columns、grid 组织子内容。
Blade / 原生写法
{{-- Blade 组件(支持 direction / alignment / stretch) --}}
<x-trmnl::layout direction="col" alignment="center">
<!-- 内容 -->
</x-trmnl::layout><!-- 原生 HTML -->
<div class="layout layout--col layout--center">
<!-- 内容 -->
</div>关键 props / class / 属性
Blade props
| prop | 可选值 | 默认 |
|---|---|---|
direction | row、col | — |
alignment | left、center、right、top、bottom、center-x、center-y | — |
stretch | true、x、y | — |
原生 class
方向:layout--row / layout--col
对齐:layout--left / layout--center / layout--right / layout--top / layout--bottom / layout--center-x / layout--center-y
伸展(容器级):layout--stretch / layout--stretch-x / layout--stretch-y
伸展(子元素级):stretch-x / stretch-y(加在子元素上)
注意事项
view/layout/title-bar的结构层级以references/design-rules.md为准- 方向默认为垂直堆叠(无 modifier 时为 column flex)
- 对齐默认居中
最小示例
<x-trmnl::layout direction="col" alignment="center">
<span class="value value--large">42</span>
<span class="label">完成任务</span>
</x-trmnl::layout>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/layout
- trmnl-blade 源码:
src/View/Components/Layout.php
mashup
作用
将多个插件的 view 组合在单屏内,mashupLayout 决定排列方式,每个 view 的 size 决定占用空间。
Blade / 原生写法
{{-- Blade 组件 --}}
<x-trmnl::mashup mashupLayout="1Lx1R">
<x-trmnl::view size="half_vertical">
<x-trmnl::layout>...</x-trmnl::layout>
</x-trmnl::view>
<x-trmnl::view size="half_vertical">
<x-trmnl::layout>...</x-trmnl::layout>
</x-trmnl::view>
</x-trmnl::mashup><!-- 原生 HTML -->
<div class="mashup mashup--1Lx1R">
<div class="view view--half_vertical">
<div class="layout">...</div>
</div>
<div class="view view--half_vertical">
<div class="layout">...</div>
</div>
</div>关键 props / class / 属性
mashupLayout / class | 布局描述 | 子 view size |
|---|---|---|
1Lx1R | 左1右1(左右各半) | half_vertical × 2 |
1Tx1B | 上1下1(上下各半) | half_horizontal × 2 |
1Lx2R | 左1右2(左半 + 右两象限) | half_vertical + quadrant × 2 |
2Lx1R | 左2右1(左两象限 + 右半) | quadrant × 2 + half_vertical |
2Tx1B | 上2下1 | quadrant × 2 + half_horizontal |
1Tx2B | 上1下2 | half_horizontal + quadrant × 2 |
2x2 | 四象限 | quadrant × 4 |
注意事项
- TRMNL 平台多插件屏自动提供
mashup,无需手动写 - BYOS / 本地开发时需手动提供,并确保 view size 与 mashupLayout 对应
screen--backdrop可切换 mashup 背景为图案/纯灰样式
最小示例
<x-trmnl::screen>
<x-trmnl::mashup mashupLayout="1Lx1R">
<x-trmnl::view size="half_vertical">
<x-trmnl::layout>
<span class="label">左侧内容</span>
</x-trmnl::layout>
</x-trmnl::view>
<x-trmnl::view size="half_vertical">
<x-trmnl::layout>
<span class="label">右侧内容</span>
</x-trmnl::layout>
</x-trmnl::view>
</x-trmnl::mashup>
</x-trmnl::screen>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/mashup
- trmnl-blade 源码:
src/View/Components/Mashup.php
meta
作用
item 和 table 内的左侧辅助区域,用于放置索引编号(index)或空白的颜色强调条。不单独使用。
Blade / 原生写法
<x-trmnl::meta>
<span class="index">1</span>
</x-trmnl::meta><!-- item 内:空 meta(只显示左侧细条) -->
<div class="item">
<div class="meta"></div>
<div class="content">...</div>
</div>
<!-- item 内:带索引编号 -->
<div class="item">
<div class="meta">
<span class="index">1</span>
</div>
<div class="content">...</div>
</div>
<!-- table 内:索引列 -->
<td>
<span class="meta">
<span class="index">1</span>
</span>
</td>关键 class / 属性
| class | 说明 |
|---|---|
meta | 左侧辅助区容器,宽度由 --item-meta-width(10px)控制 |
index | 序号文字,放在 meta 内 |
- table 使用
table--indexed配合meta>index展示行号列
注意事项
x-trmnl::meta是薄包装;若你需要更复杂结构,直接写原生 HTML 更清晰- 空
meta(无子内容)仍会渲染左侧细条占位 item--emphasis-1/2/3影响meta区域的深浅颜色
最小示例
<div class="item item--emphasis-2">
<div class="meta">
<span class="index">3</span>
</div>
<div class="content">
<span class="title title--small">第三名</span>
<span class="description">42 分</span>
</div>
</div>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/item(item meta 节)
- trmnl-blade 源码:
src/View/Components/Meta.php
progress
作用
进度指示组件,分两类:
- progress-bar:连续进度条(带填充轨道),有 Blade 组件
x-trmnl::progress - progress-dots:离散步骤点,使用原生 class
当前x-trmnl::progress只输出基础div.progress-bar,尺寸与强调变体通常仍用原生 HTML class。
Blade / 原生写法
{{-- Blade 组件(基础 progress-bar) --}}
<x-trmnl::progress>
<div class="content">
<span class="label">下载进度</span>
<span class="value value--xxsmall">60%</span>
</div>
<x-trmnl::track>
<div class="fill" style="width: 60%"></div>
</x-trmnl::track>
</x-trmnl::progress><!-- 原生 HTML:progress-bar -->
<div class="progress-bar progress-bar--small">
<div class="content">
<span class="label label--small">下载进度</span>
<span class="value value--xxsmall">60%</span>
</div>
<div class="track">
<div class="fill" style="width: 60%"></div>
</div>
</div>
<!-- 原生 HTML:progress-dots(无 Blade 封装) -->
<div class="progress-dots">
<div class="track">
<div class="dot dot--filled"></div>
<div class="dot dot--filled"></div>
<div class="dot dot--current"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
</div>关键 props / class / 属性
progress-bar 尺寸
| class | 轨道高度 |
|---|---|
progress-bar--xsmall | 6px |
progress-bar--small | 12px |
progress-bar / progress-bar--base | 24px(默认) |
progress-bar--large | 32px |
progress-bar 强调
progress-bar--emphasis-2 / progress-bar--emphasis-3(填充颜色加深)
progress-dots 尺寸
progress-dots--xsmall / progress-dots--small / progress-dots / progress-dots--large
dot 状态
dot dot--filled:已完成dot dot--current:当前步骤dot:未完成
注意事项
progress-dots目前无完整 Blade 封装,使用原生 classfill的宽度通过内联style="width: N%"设置content(标签+数值)是可选区域,可省略- 若需要
progress-bar--small、progress-bar--large、progress-bar--emphasis-*等变体,当前优先直接写原生 HTML
最小示例
<div class="progress-bar">
<div class="content">
<span class="label">CPU 使用率</span>
<span class="value value--xxsmall">75%</span>
</div>
<div class="track">
<div class="fill" style="width: 75%"></div>
</div>
</div>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/progress
- trmnl-blade 源码:
src/View/Components/Progress.php(封装 progress-bar)
richtext
作用
富文本容器,用于段落、引言、长文案等文字为主的内容。richtext 是外层容器,content 是实际文字区域,两者有各自独立的对齐控制。
Blade / 原生写法
{{-- Blade 组件 --}}
<x-trmnl::richtext align="center" gapSize="large">
<x-trmnl::content contentAlignment="center" textAlignment="center">
<p>正文内容</p>
</x-trmnl::content>
</x-trmnl::richtext><!-- 原生 HTML -->
<div class="richtext richtext--center gap--large">
<div class="content content--center gap text--center">
<p>正文内容</p>
</div>
</div>关键 props / class / 属性
richtext Blade props
| prop | 可选值 | 说明 |
|---|---|---|
align | left、center、right | 整体容器在父元素中的对齐 |
gapSize | small、base、large 等 | 内部间距 |
content Blade props
| prop | 可选值 | 说明 |
|---|---|---|
contentAlignment | left、center、right | content 块自身对齐 |
textAlignment | left、center、right | 内部文字对齐(text--*) |
gapSize | gap 值 | 内部 gap |
尺寸通过 class 控制(见下),不是 content 的 prop。content 尺寸 class
content--small / content--base / content--large / content--xlarge / content--xxlarge / content--xxxlarge
支持响应前缀:lg:content--xxlarge、portrait:content--small、1bit:content--large 等
溢出处理
data-content-limiter="true":内容超出时自动缩小字号data-content-max-height="140":手动指定最大高度(像素)
注意事项
richtext和content是两层,对齐各自独立text--left/center/right控制段落内文字对齐,加在content上- 尺寸变体用 class 而非 prop
最小示例
<x-trmnl::layout alignment="center">
<x-trmnl::richtext align="center" gapSize="large">
<x-trmnl::content contentAlignment="center" textAlignment="center">
<p>今日格言</p>
</x-trmnl::content>
</x-trmnl::richtext>
</x-trmnl::layout>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/rich_text
- trmnl-blade 源码:
src/View/Components/Richtext.php、Content.php
screen
作用
所有内容的最外层容器,定义设备尺寸并向内层组件提供 CSS 变量。在 TRMNL 平台上由平台注入;自建栈(BYOS)时需手动提供。
Blade / 原生写法
{{-- Blade 组件(trmnl-blade) --}}
<x-trmnl::screen>
<x-trmnl::view>
...
</x-trmnl::view>
</x-trmnl::screen><!-- 原生 HTML -->
<div class="screen">
<div class="view view--full">...</div>
</div>关键 props / class / 属性
Blade props
| prop | 说明 |
|---|---|
noBleed | 移除屏幕边距,内容延伸至边缘 |
darkMode | 开启深色模式,重映射颜色 token |
deviceVariant | 设备型号,如 og、v2、amazon_kindle_2024 |
deviceOrientation | 方向:landscape(默认)、portrait |
colorDepth | 色深:1bit、2bit、4bit 等 |
scaleLevel | UI 缩放系数 |
原生 class 修饰符
| class | 说明 |
|---|---|
screen--og | TRMNL 原版设备(800×480px) |
screen--v2 | TRMNL V2(1040×780px) |
screen--portrait | 竖屏方向(宽高互换) |
screen--no-bleed | 去除边距 |
screen--dark-mode | 深色模式 |
screen--backdrop | Mashup 背景样式(图案/纯灰色背景) |
screen--1bit / screen--4bit | 色深标记 |
注意事项
- TRMNL 平台自动注入
screen,无需在插件 markup 中写 - 自建栈(BYOS)时需手动写
screen以及对应设备 class - 每个
screen只包含一个view(全屏)或一个mashup(多区域)
最小示例
<x-trmnl::screen deviceVariant="v2" colorDepth="4bit">
<x-trmnl::view>
<x-trmnl::layout>
<!-- 内容 -->
</x-trmnl::layout>
<x-trmnl::title-bar title="我的插件" />
</x-trmnl::view>
</x-trmnl::screen>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/screen
- trmnl-blade 源码:
src/View/Components/Screen.php
table
作用
结构化数据表格,使用标准 HTML <table> 元素配合框架 class。x-trmnl::table 组件本身已输出 `<table>` 标签,内部直接写 thead / tbody。适合简单表格;需要 data-table-limit、table--indexed 等附加属性/类时,优先改用原生 HTML。
Blade / 原生写法
{{-- Blade 组件 --}}
<x-trmnl::table size="small">
<thead>
<tr>
<th><span class="title title--small">名称</span></th>
<th><span class="title title--small">状态</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="label label--small" data-clamp="1">任务 A</span></td>
<td><span class="label label--small">进行中</span></td>
</tr>
</tbody>
</x-trmnl::table><!-- 原生 HTML -->
<table class="table table--small" data-table-limit="true">
<thead>
<tr>
<th><span class="title title--small">名称</span></th>
<th><span class="title title--small">状态</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="label label--small" data-clamp="1">任务 A</span></td>
<td><span class="label label--small">进行中</span></td>
</tr>
</tbody>
</table>关键 props / class / 属性
Blade prop size
| 值 | 原生 class | 行高 |
|---|---|---|
| (默认) | table | 46px tbody / 36px thead |
base | table--base | 同默认 |
large | table--large | 56px / 44px |
xlarge | table--xlarge | 72px / 56px |
small | table--small | 31px / 24px |
xsmall | table--xsmall | 22px / 18px |
溢出与截断
data-table-limit="true":超出高度时隐藏多余行并追加"and X more"(推荐加在原生<table>上)data-clamp="1":单元格内文字截断为 1 行(加在label/span上)
索引列
<table class="table table--indexed">
...
<td><span class="meta"><span class="index">1</span></span></td>注意事项
- Blade 组件已输出
<table>,内部不要再写 `<table>` - 当前 Blade 组件不适合承载
data-table-limit、table--indexed等附加属性/类 - 表头用
title/title--small,单元格用label/label--small - 长文本单元格建议加
data-clamp="1"避免破坏行高
最小示例
<x-trmnl::layout>
<table class="table table--small" data-table-limit="true">
<thead>
<tr>
<th><span class="title title--small">项目</span></th>
<th><span class="title title--small">进度</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="label label--small" data-clamp="1">官网重构</span></td>
<td><span class="label label--small">80%</span></td>
</tr>
</tbody>
</table>
</x-trmnl::layout>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/table
- trmnl-blade 源码:
src/View/Components/Table.php
text
作用
行内文字工具组件,控制文字对齐和底纹(shading)。通常作为文字修饰类使用,或通过 x-trmnl::text 组件包裹文字片段。
Blade / 原生写法
{{-- Blade 组件 --}}
<x-trmnl::text alignment="center" shading="gray-40">
辅助说明文字
</x-trmnl::text><!-- 原生 HTML,常见用法是在文字元素上附加 text-- 类 -->
<span class="text--center">居中文字</span>
<p class="text--left">左对齐段落</p>关键 props / class / 属性
Blade props
| prop | 可选值 | 说明 |
|---|---|---|
alignment | left、center、right | 文字对齐 |
shading | 如 gray-40 | 追加 text--{值} 样式 |
原生 class
对齐:text--left / text--center / text--right
注意事项
text--*对齐类可附加在任意文字元素上(p、span、div),不必用x-trmnl::text包裹- 在
content内控制段落文字对齐时通常直接加text--center到contentdiv
最小示例
<div class="content content--large text--center">
<p>今日格言</p>
</div>来源
- trmnl-blade 源码:
src/View/Components/Text.php
title-bar
作用
插件的标准化标题栏,显示图标、标题和可选实例标签。在 Mashup 中自动切换为紧凑样式。
Blade / 原生写法
{{-- 基础(图标使用 src 属性) --}}
<x-trmnl::title-bar title="我的插件" image="/icons/plugin.svg" instance="生产环境" />
{{-- 内联图标(image='inline' 时走 slot) --}}
<x-trmnl::title-bar title="我的插件" image="inline">
<x-slot name="image">
<img class="image" src="/icons/plugin.svg" alt="">
</x-slot>
</x-trmnl::title-bar><!-- 原生 HTML -->
<div class="title_bar">
<img class="image" src="/icons/plugin.svg" alt="">
<span class="title">我的插件</span>
<span class="instance">生产环境</span>
</div>关键 props / class / 属性
| Blade prop | 说明 |
|---|---|
title | 标题文本(必填) |
image | 图标 URL;传 'inline' 时启用 slot 模式 |
instance | 实例标签(可选,右侧小字) |
原生结构:div.title_bar > img.image + span.title + span.instance
注意事项
title-bar的放置位置与层级约束见references/design-rules.md- 在
mashup内的 view 中,框架自动应用紧凑高度样式(无需额外 class) instance可省略
最小示例
<x-trmnl::view>
<x-trmnl::layout>
<span class="value value--large">42°C</span>
</x-trmnl::layout>
<x-trmnl::title-bar title="天气" image="/icons/weather.svg" instance="北京" />
</x-trmnl::view>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/title_bar
- trmnl-blade 源码:
src/View/Components/TitleBar.php
title
作用
标题文字组件,用于内容标题、列表项标题、区块标头等。当前 Blade 组件仅明确提供 size="small" 这一快捷入口;更大尺寸建议直接使用原生 class。
Blade / 原生写法
{{-- trmnl-blade 提供 x-trmnl::title 组件 --}}
{{-- 当前仅 `size="small"` 有明确快捷支持 --}}
<x-trmnl::title size="small">任务名称</x-trmnl::title><!-- 原生 HTML(推荐直接用 class) -->
<span class="title title--small">任务名称</span>
<span class="title">默认标题</span>
<span class="title title--large">大标题</span>关键 props / class / 属性
Blade props
| prop | 说明 |
|---|---|
size="small" | 等同 title--small |
其他尺寸暂无对应的快捷 prop,直接在原生 class 上使用。
原生 class
| class | 尺寸 |
|---|---|
title title--small | 小(16px / NicoClean) |
title | 默认(26px / BlockKie) |
title title--base | 同默认(用于响应式重置) |
title title--large | 大(30px) |
title title--xlarge | 超大(35px) |
title title--xxlarge | 最大(40px) |
响应前缀:lg:title--base、portrait:title--small
注意事项
- Blade 组件只有
size="small"是源码明确支持的快捷写法,其他尺寸直接用 HTML class - 不要编造
size="large"之类的 prop x-trmnl::title不透传任意属性;需要data-clamp时优先直接写原生<span class="title ...">title--small是列表项标题最常用的变体
最小示例
<span class="title title--small">任务标题</span>
<span class="title title--large">每日摘要</span>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/title
- trmnl-blade 源码:
src/View/Components/Title.php
track
作用
progress-bar 内的轨道容器,包裹 fill(已完成部分)。也在 progress-dots 内包裹 dot 列表。通常不单独使用,作为 progress 组件的子结构。
原生写法
<!-- progress-bar 内的 track -->
<div class="progress-bar">
<div class="content">
<span class="label">进度</span>
<span class="value value--xxsmall">75%</span>
</div>
<div class="track">
<div class="fill" style="width: 75%"></div>
</div>
</div>
<!-- progress-dots 内的 track -->
<div class="progress-dots">
<div class="track">
<div class="dot dot--filled"></div>
<div class="dot dot--current"></div>
<div class="dot"></div>
</div>
</div>Blade 写法(trmnl-blade)
<x-trmnl::progress>
<x-trmnl::track>
<div class="fill" style="width: 60%"></div>
</x-trmnl::track>
</x-trmnl::progress>关键 class
| class | 说明 |
|---|---|
track | 进度条轨道背景容器 |
fill | 填充块,宽度通过 style="width: N%" 控制 |
dot | 步骤点(在 progress-dots 内) |
dot--filled | 已完成状态 |
dot--current | 当前步骤(激活状态) |
注意事项
fill宽度必须通过内联 style 设置,无工具 class 控制x-trmnl::track只是轨道包装,填充块仍使用原生<div class="fill">
最小示例
<div class="progress-bar">
<div class="track">
<div class="fill" style="width: 40%"></div>
</div>
</div>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/progress
- trmnl-blade 源码:
src/View/Components/Track.php
value
作用
数字/数值展示组件,提供 12 档尺寸(xxsmall → peta),适合 KPI 大字显示。value--tnums 启用等宽数字,对齐财务数据时使用。
Blade / 原生写法
{{-- trmnl-blade 提供 x-trmnl::value 组件 --}}
<x-trmnl::value size="large">48,206</x-trmnl::value><!-- 原生 HTML -->
<span class="value value--large value--tnums">48,206</span>关键 props / class / 属性
Blade props
| prop | 说明 |
|---|---|
size | 尺寸名称(见下表) |
textStroke | 可选字符串,传入后会拼成 text-stroke text-stroke--{值} |
尺寸 class 对照
| class | 字号(1-bit) |
|---|---|
value value--xxsmall | 16px |
value value--xsmall | 20px |
value value--small | 26px |
value / value--base | 38px(默认) |
value value--large | 58px |
value value--xlarge | 74px |
value value--xxlarge | 96px |
value value--xxxlarge | 128px |
value value--mega | 170px |
value value--giga | 220px |
value value--tera | 290px |
value value--peta | 380px |
修饰 class
value--tnums:等宽数字(财务/对齐场景)
响应前缀:md:value--large、portrait:value--small
注意事项
x-trmnl::value支持属性透传,可直接在组件标签上加data-value-fit/data-value-format- 大尺寸(mega 以上)通常单独占满屏幕
- 数字配合
value--tnums可避免数字宽度不一导致跳动 - 如需描边,可优先直接写原生 class;
textStroke的取值以 Framework Text Stroke 文档为准
最小示例
<div class="layout layout--col layout--center">
<span class="value value--xxxlarge value--tnums">42</span>
<span class="label">完成任务</span>
</div>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/value
- trmnl-blade 源码:
src/View/Components/Value.php
view
作用
内容容器,持有一个 layout(及可选的 title-bar)。全屏时直接放在 screen 内;多区域时放在 mashup 内。
Blade / 原生写法
{{-- Blade 组件 --}}
<x-trmnl::view size="full">
<x-trmnl::layout>...</x-trmnl::layout>
<x-trmnl::title-bar title="标题" />
</x-trmnl::view><!-- 原生 HTML -->
<div class="view view--full">
<div class="layout">...</div>
<div class="title_bar">...</div>
</div>关键 props / class / 属性
Blade prop size | 原生 class | 说明 |
|---|---|---|
full(默认) | view--full | 全屏,直接在 screen 内 |
half_horizontal | view--half_horizontal | 上下二分之一,在 mashup 内 |
half_vertical | view--half_vertical | 左右二分之一,在 mashup 内 |
quadrant | view--quadrant | 四分之一,在 mashup 内 |
注意事项
view与mashup/layout/title-bar的结构组合约束见references/design-rules.md- TRMNL 平台插件无需手动写
view,平台自动提供
最小示例
{{-- 全屏 --}}
<x-trmnl::view>
<x-trmnl::layout>
<span class="label">Hello</span>
</x-trmnl::layout>
</x-trmnl::view>
{{-- Mashup 内的半屏 --}}
<x-trmnl::view size="half_vertical">
<x-trmnl::layout>...</x-trmnl::layout>
</x-trmnl::view>来源
- Framework v3 文档:https://trmnl.com/framework/docs/v3/view
- trmnl-blade 源码:
src/View/Components/View.php
Framework v3 设计约束
本文件是 screen / mashup / view / layout / title-bar 结构层级与 e-paper 约束的权威说明;其他文档只保留最小必要提示,不重复定义同一套规则。
结构层级(不可违反)
固定层级:Screen → (Mashup →) View → Layout (+ 可选 Title Bar)
- 每个 View 内恰好有 一个 Layout。
- Title Bar 是 Layout 的兄弟,不是子节点。
- 绝对不要嵌套 Layout;内部组织必须改用
columns、grid、flex。 - 非
full的 View 必须包在 Mashup 里。 - TRMNL 平台自动提供 Screen/Mashup/View;插件只需写 Layout + 可选 Title Bar。BYOS 需自行提供完整层级。
✅ 正确 ❌ 错误
screen screen
view(full) view(full)
layout layout
columns / flex / grid layout ← 嵌套 layout
title-bar title-bar ← 在 layout 内组件选择优先级
1. 第一优先:高阶 Components — richtext、item、table、chart、progress 2. 第二优先:语义组合 — columns、value + label、title + description 3. 第三优先:布局原语与工具类 — flex、grid、progress-dots、bg--*、text--* 等 4. 最后:自定义 CSS/HTML — 仅框架组件无法满足时才动手
不要先写自由 HTML,先想:能不能直接落进 Rich Text / Item / Table / Chart / Progress 之一。
当前 Blade 组件清单
screen、mashup、view、layout、title-bar、columns、column、flex、grid、col、richtext、content、text、item、table、label、title、value、description、divider、meta、progress(progress-bar 封装)、track、clamp、background、aspect
重要使用说明
| 组件 / 能力 | 说明 |
|---|---|
richtext | 富文本容器(富段落、引言、通知),markdown 已 deprecated,统一改用 richtext |
table | 输出 <table class="table ..."> 元素,slot 内只放 <thead> / <tbody>,不要嵌套 `<table>` |
progress | 仅封装 progress-bar 结构;progress-dots 无 Blade 封装,使用原生 div.progress-dots class |
background | 薄封装,输出 bg-{color} class;v3 token(bg--gray-N、bg--primary)推荐直接写原生 class |
chart | 无 Blade 组件封装,使用 Highcharts / Chartkick JS;禁动画,灰度用 pattern,显式指定高度 |
image | 无专用 Blade 组件,使用框架原生 class:image-dither、image-stroke |
title-bar | image='inline' 时用 slot 传图;title-bar 始终是 layout 兄弟,不是子节点 |
e-paper 核心思维
- Adaptive in Context:框架自动适配 1-bit、2-bit、4-bit 位深及设备色板,不必硬编码设备条件。
- 优先信息层级、留白、对比;一屏聚焦一个主任务。
- 用
data-pixel-perfect="true"确保文字在 e-paper 上锐利。 - 用灰度 token(
bg--gray-N)代替纯灰色填充。
v3 颜色系统约束
| 规则 | 说明 |
|---|---|
| 优先语义色 | 用 primary/success/error/warning 表达状态,而非硬编码色相 |
| 自动回退 | 灰度设备自动降级,色彩受限设备自动映射最近色,不需条件代码 |
| 废弃旧灰度 | gray-1~gray-7 已废弃,新代码使用 gray-10~gray-75 |
| 暗色模式 | 灰度 token 自动反转,色度色亮度步进镜像,无需额外处理 |
| CSS 变量覆盖 | 可通过 --color-primary 等变量自定义语义色映射 |
| 不依赖颜色编码 | 仍需依靠灰度、形状、边框强度作为主要编码手段 |
v3 核心行为
| 特性 | 说明 |
|---|---|
| 内容截断 | title/label/description 不自动截断,必须显式加 data-clamp="N" |
| DOM 级截断引擎 | data-clamp="N" 基于单词 DOM 截断 + 省略号 |
| 表格限行引擎 | data-table-limit="true" 自动限高 + "and X more" |
| 列布局引擎 | columns Overflow 引擎接管列表排布,支持按组截断 |
| 分隔线 | divider 和 divider--vertical |
| 数值能力 | data-value-format="true" 格式化;data-value-fit="true" 自动缩放 |
| 圆角/比例/缩放 | rounded--*、aspect--*(Beta)、scale--*(Beta) |
| 可见性控制 | hidden-1bit、hidden-2bit 等按位深隐藏 |
| CSS 变量架构 | 内部从选择器规则改为 CSS custom properties,class name 不变 |
| High-density 支持 | Background/Border 支持 high-density 1bit/2bit 渲染 |
| 颜色系统 | 10 色相 × 14 步 + 语义色 + 14 步灰度 |
Layout 内部组织
- 同类列表 →
columns(自动分栏 + 溢出处理) - 严格列对齐 →
grid(固定列数 + span) - 弹性行内 →
flex(可独立也可放入 grid cell) - 结构化数据 →
table
内容溢出策略
| 场景 | 推荐做法 |
|---|---|
| Columns 超出 | data-overflow-max-cols="N" |
| Table 超出 | data-table-limit="true" |
| Richtext 超出 | data-content-limiter="true" |
| 文本超出 | data-clamp="N"(必须显式) |
| 数值太大 | data-value-fit="true" |
Chart 规则
- 图表用 CDN JS(Highcharts / Chartkick),不用纯 CSS,无 Blade 封装
- 始终禁用动画:
animation: false - 1bit:多系列用灰度 pattern,单系列
["black"] - v3:彩色设备可用 chromatic color patterns
- 显式指定高度
设备参数
用户明确给出设备信息时才设置 screen props,否则保持默认。
| Prop | 可选值 | 说明 |
|---|---|---|
deviceVariant | og / v2 | 800×480 / 1040×780 |
deviceOrientation | portrait | 竖屏 |
colorDepth | 1bit / 2bit / 4bit | 位深 |
---
官方示例索引
以下示例从 TRMNL Framework v3 Examples 提取,每个文件包含 Full View 的完整 HTML 源码。
每个示例均展示多种 Framework 特性的组合用法,可作为实际开发的参考起点。
| 文件 | 类型 | 演示特性 |
|---|---|---|
| weather.md | 天气看板 | grid 多列、响应式图片、data-fit-value、item/value 嵌套 |
| stock_price.md | 股票报价 | grid + col--span、value--tnums、data-fit-value、divider 分隔 |
| todo_list.md | 待办列表 | columns + overflow、group-header、index 编号、label--gray |
| shopify.md | 电商看板 | grid 混合布局、Highcharts 图表集成、data-value-type |
| lunar_calendar.md | 月相日历 | flex 自定义布局、grid--row、图片序列、label--inverted |
| days_left_year.md | 年度进度 | grid + JS 动态渲染、data-value-fit、自定义 CSS grid |
| wiki_random_article.md | 富文本阅读 | richtext + content-limiter、pixel-perfect、columns |
| github_commit_graph.md | GitHub 提交图 | grid 密度分布、热力图、自定义颜色块 |
| reddit.md | Reddit 热门帖子 | columns + overflow、group-header 分组、index 编号、label--underline 元数据 |
Days Left This Year — 年度进度
KPI 数值 + JS 动态生成的热力图式年度日历,展示自定义 CSS grid 与 JS 交互。
来源:https://trmnl.com/framework/examples/days_left_year?version=v3
Full View
<div class="layout layout--col gap--large lg:gap--xxlarge p--8 lg:p--16">
<div class="grid grid--cols-10">
<div class="col col--span-1"></div>
<div class="col col--span-4">
<div class="item">
<div class="meta"></div>
<div class="content text--center">
<span class="value value--xxxlarge days_passed" data-value-fit="true">value</span>
<span class="label">Days Passed</span>
</div>
</div>
</div>
<div class="col col--span-4">
<div class="item">
<div class="meta"></div>
<div class="content text--center">
<span class="value value--xxxlarge days_left" data-value-fit="true">value</span>
<span class="label">Days Left</span>
</div>
</div>
</div>
<div class="col col--span-1"></div>
</div>
<div id="days_left" data-today="2025-09-15T10:29:35+05:30"></div>
</div>
<div class="title_bar">
<img class="image" alt="" src="https://trmnl.com/images/plugins/days_left_year--render.svg">
<span class="title">Days Left This Year</span>
<span class="instance">2026</span>
</div>Shared CSS
#days_left {
--rows: 7;
--cols: 53;
--gap: 3px;
width: 100%;
height: 100%;
flex: 1 1 0;
justify-content: center;
display: grid;
grid-template-columns: repeat(var(--cols), round(down, calc((100% - (var(--cols) - 1) * var(--gap)) / var(--cols)), 1px));
grid-template-rows: repeat(var(--rows), round(down, calc((100% - (var(--rows) - 1) * var(--gap)) / var(--rows)), 1px));
grid-auto-flow: column;
gap: var(--gap);
}
#days_left .day {
height: 100%;
margin: 0;
border-radius: 4px;
}关键技巧
grid--cols-10+col--span-1空列实现居中留白data-value-fit="true"自适应字号- JS 通过
data-today属性获取当前日期,动态生成.day元素 - 使用 v3 灰度 token:
bg--gray-4(已过)、bg--gray-5(未来)、bg--black(当天) 2bit:bg--gray-50/2bit:bg--gray-65为 2bit 设备提供专用灰度
GitHub Commit Graph — GitHub 提交热力图
贡献统计 KPI + 53×7 热力图,使用自定义 CSS grid 与灰度 token 映射提交密度。
来源:https://trmnl.com/framework/examples/github_commit_graph?version=v3
Full View
<div class="layout layout--col gap">
<div class="grid grid--cols-2">
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value value--xxxlarge" data-value-fit="true" data-value-format="true">10004</span>
<span class="label mt--2">Contributions in last year</span>
</div>
</div>
<div class="flex flex--col gap--medium">
<div class="grid grid--cols-2">
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value lg:value--xlarge">19</span>
<span class="label">Longest streak</span>
</div>
</div>
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value lg:value--xlarge">3</span>
<span class="label">Current streak</span>
</div>
</div>
</div>
<div class="divider"></div>
<div class="grid grid--cols-2">
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value lg:value--xlarge">27</span>
<span class="label">Most in a day</span>
</div>
</div>
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value lg:value--xlarge">2.45</span>
<span class="label">Average per day</span>
</div>
</div>
</div>
</div>
</div>
<div class="divider"></div>
<div id="github_commit_graph" style="--columns: 53">
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-35 bg--gray-40"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-25 bg--gray-30"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-25 bg--gray-30"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-20 bg--gray-20"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-35 bg--gray-40"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-15 bg--gray-15"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day bg--black"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-35 bg--gray-40"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-25 bg--gray-30"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-10 bg--gray-10"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-25 bg--gray-30"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day bg--black"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-35 bg--gray-40"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-35 bg--gray-40"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-35 bg--gray-40"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day bg--black"></span>
<span class="day 1bit:bg--gray-35 bg--gray-40"></span>
<span class="day 1bit:bg--gray-25 bg--gray-30"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-35 bg--gray-40"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-25 bg--gray-30"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-15 bg--gray-15"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-25 bg--gray-30"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-35 bg--gray-40"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-40 bg--gray-50"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-15 bg--gray-15"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-35 bg--gray-40"></span>
<span class="day 1bit:bg--gray-15 bg--gray-15"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-20 bg--gray-20"></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-60 bg--gray-75"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-30 bg--gray-35"></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-15 bg--gray-15"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-50 bg--gray-65"></span>
<span class="day "></span>
<span class="day 1bit:bg--gray-45 bg--gray-60"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day 1bit:bg--gray-55 bg--gray-70"></span>
<span class="day "></span>
<span class="day "></span>
</div>
</div>
<div class="title_bar">
<img class="image" alt="" src="https://trmnl.com/images/plugins/github--render.svg">
<span class="title">GitHub</span>
<span class="instance">@ryanckulp</span>
</div>Shared CSS
.trmnl #github_commit_graph {
--rows: 7;
--columns: 52;
--gap: 3px;
width:100%;
height:100%;
padding:0px;
flex:1 1 0;
justify-content:center;
display:grid;
grid-template-columns:repeat(var(--columns), round(down, (100% - var(--gap) * (var(--columns) - 1)) / var(--columns), 1px));
grid-template-rows:repeat(var(--rows), round(down, (100% - var(--gap) * (var(--rows) - 1)) / var(--rows), 1px));
grid-auto-flow:column;
gap:var(--gap);
}
.trmnl #github_commit_graph .day {
display:block;
border-radius:4px;
width:100%;
height:100%;
}
.trmnl .view--quadrant #github_commit_graph {
--gap: 1px;
}
.trmnl .view--half_vertical #github_commit_graph {
--gap: 1px;
}
.trmnl .view--half_horizontal #github_commit_graph {
--gap: 2px;
}
.trmnl .view--full #github_commit_graph {
--gap: 3px;
}关键技巧
grid--cols-2将 KPI 统计区与热力图区并排id="github_commit_graph"+style="--columns: 53"通过 CSS 变量控制图表列数1bit:bg--gray-*/bg--gray-*两套灰度 token 分别适配 1bit 与彩色设备,映射提交密度bg--black标记当天格子(最高亮)data-value-fit="true"+data-value-format="true"自适应字号并添加千位分隔符- Shared CSS 用
.view--*前缀按视图尺寸调整 gap,避免小尺寸格子过密
Lunar Calendar — 月相日历
丰富的视觉信息展示,使用 flex 自定义布局、grid--row 水平排列、图片序列、label--inverted 高亮当前项。
来源:https://trmnl.com/framework/examples/lunar_calendar?version=v3
Full View
<div class="layout layout--col gap--space-between">
<div class="grid portrait:grid--cols-8 portrait:gap--xlarge">
<div class="item col--span-4 portrait:col--span-8">
<div class="meta"></div>
<div class="content">
<span class="value lg:value--xlarge" data-value-fit="true" data-value-fit-max-height="140px">Full Moon</span>
<span class="label">Current Phase</span>
</div>
</div>
<div class="item col--span-2 portrait:col--span-4">
<div class="meta"></div>
<div class="content">
<span class="value value--xsmall lg:value--base">99.8%</span>
<span class="label">Moon Illumination</span>
</div>
</div>
<div class="item col--span-2 portrait:col--span-4">
<div class="meta"></div>
<div class="content">
<span class="value value--xsmall lg:value--base">15.0</span>
<span class="label">Lunar Age</span>
</div>
</div>
</div>
<div class="divider"></div>
<div class="flex flex--col w--full gap--large rounded--large">
<div class="grid grid--row grid--top">
<div class="flex flex--row flex--center">
<span class="label label--small ">Jan 7</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small ">Jan 10</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small ">Jan 12</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small label--inverted">Jan 13</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small ">Jan 15</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small ">Jan 20</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small ">Jan 24</span>
</div>
</div>
<div class="grid grid--row grid--center">
<div class="flex flex--row flex--center">
<img class="image w--min-[12cqw] h--min-[12cqw] lg:w--min-[14cqw] lg:h--min-[14cqw]" alt="Moon phase" src="https://trmnl.com/images/plugins/lunar_calendar/wi-moon-alt-waxing-crescent-3.svg">
</div>
<div class="flex flex--row flex--center">
<img class="image w--min-[12cqw] h--min-[12cqw] lg:w--min-[14cqw] lg:h--min-[14cqw]" alt="Moon phase" src="https://trmnl.com/images/plugins/lunar_calendar/wi-moon-alt-first-quarter.svg">
</div>
<div class="flex flex--row flex--center">
<img class="image w--min-[12cqw] h--min-[12cqw] lg:w--min-[14cqw] lg:h--min-[14cqw]" alt="Moon phase" src="https://trmnl.com/images/plugins/lunar_calendar/wi-moon-alt-waxing-gibbous-3.svg">
</div>
<div class="flex flex--row flex--center">
<img class="image w--min-[14cqw] h--min-[14cqw] lg:w--min-[16cqw] lg:h--min-[16cqw]" alt="Moon phase" src="https://trmnl.com/images/plugins/lunar_calendar/wi-moon-alt-full.svg">
</div>
<div class="flex flex--row flex--center">
<img class="image w--min-[12cqw] h--min-[12cqw] lg:w--min-[14cqw] lg:h--min-[14cqw]" alt="Moon phase" src="https://trmnl.com/images/plugins/lunar_calendar/wi-moon-alt-waning-gibbous-3.svg">
</div>
<div class="flex flex--row flex--center">
<img class="image w--min-[12cqw] h--min-[12cqw] lg:w--min-[14cqw] lg:h--min-[14cqw]" alt="Moon phase" src="https://trmnl.com/images/plugins/lunar_calendar/wi-moon-alt-third-quarter.svg">
</div>
<div class="flex flex--row flex--center">
<img class="image w--min-[12cqw] h--min-[12cqw] lg:w--min-[14cqw] lg:h--min-[14cqw]" alt="Moon phase" src="https://trmnl.com/images/plugins/lunar_calendar/wi-moon-alt-waning-crescent-3.svg">
</div>
</div>
<div class="grid grid--row grid--top">
<div class="flex flex--row flex--center">
<span class="label label--small text--center ">Waxing Crescent</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small text--center ">First Quarter</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small text--center ">Waxing Gibbous</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small text--center label--inverted">Full Moon</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small text--center ">Waning Gibbous</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small text--center ">Third Quarter</span>
</div>
<div class="flex flex--row flex--center">
<span class="label label--small text--center ">Waning Crescent</span>
</div>
</div>
</div>
<div class="divider"></div>
<div class="grid portrait:grid--cols-8 portrait:gap--xlarge">
<div class="item col--span-4 portrait:col--span-8">
<div class="meta"></div>
<div class="content">
<span class="value value--xsmall lg:value--base">Waning Gibbous</span>
<span class="label">Next Phase (January 15)</span>
</div>
</div>
<div class="item col--span-2 portrait:col--span-4">
<div class="meta"></div>
<div class="content">
<span class="value value--xsmall lg:value--base">February 11</span>
<span class="label">Next Full Moon</span>
</div>
</div>
<div class="item col--span-2 portrait:col--span-4">
<div class="meta"></div>
<div class="content">
<span class="value value--xsmall lg:value--base">January 28</span>
<span class="label">Next New Moon</span>
</div>
</div>
</div>
</div>
<div class="title_bar">
<img class="image" alt="" src="https://trmnl.com/images/plugins/lunar_calendar--render.svg">
<span class="title">Lunar Calendar</span>
<span class="instance">Moon Phases</span>
</div>关键技巧
label--inverted反色高亮当前月相grid--row+grid--top/grid--center控制行内元素对齐data-value-fit="true"+data-value-fit-max-height限制大字体最大高度w--min-[Ncqw]/h--min-[Ncqh]容器查询单位用于响应式图片尺寸
Reddit — Reddit 热门帖子
多 subreddit 帖子列表,使用 columns + overflow 引擎自动截断,group-header 分组显示。
来源:https://trmnl.com/framework/examples/reddit?version=v3
Full View
<div class="layout">
<div class="columns">
<div class="column" data-overflow="true">
<span class="label label--medium group-header"># wallstreetbets</span>
<div class="item">
<div class="meta">
<span class="index">1</span>
</div>
<div class="content">
<span class="title title--small">Insights & Snap Inc: Analyzing Market Trends, Investment Opportunities, and Predictive Growth Scenarios for 2024</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">0 votes</span>
<span class="label label--small label--underline">via u/traderInsight</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">2</span>
</div>
<div class="content">
<span class="title title--small">Anticipating Market Shifts: Strategies for the Upcoming Year</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">1 votes</span>
<span class="label label--small label--underline">via u/futurePredictor</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">3</span>
</div>
<div class="content">
<span class="title title--small">Dreaming of Gains: Strategies for Long-Term Success</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">1 votes</span>
<span class="label label--small label--underline">via u/longTermDreamer</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">4</span>
</div>
<div class="content">
<span class="title title--small">Exploring Short-term Trading Tactics</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">0 votes</span>
<span class="label label--small label--underline">via u/tacticalTrader</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">5</span>
</div>
<div class="content">
<span class="title title--small">Navigating Through Financial Setbacks: Overcoming Challenges</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">30 votes</span>
<span class="label label--small label--underline">via u/setbackSurvivor</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">6</span>
</div>
<div class="content">
<span class="title title--small">Unpacking the Impact of Federal Reserve Policies on Stock Market Volatility</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">15 votes</span>
<span class="label label--small label--underline">via u/policyWatcher</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">7</span>
</div>
<div class="content">
<span class="title title--small">The Future of Meme Stocks</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">5 votes</span>
<span class="label label--small label--underline">via u/memeMaster</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">8</span>
</div>
<div class="content">
<span class="title title--small">Options Trading Strategies for Beginners</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">10 votes</span>
<span class="label label--small label--underline">via u/optionGuru</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">9</span>
</div>
<div class="content">
<span class="title title--small">Analyzing the Impact of Inflation on Stock Prices</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">8 votes</span>
<span class="label label--small label--underline">via u/inflationWatcher</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">10</span>
</div>
<div class="content">
<span class="title title--small">Top 10 Stocks to Watch in 2024</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">12 votes</span>
<span class="label label--small label--underline">via u/stockSleuth</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">11</span>
</div>
<div class="content">
<span class="title title--small">Understanding Market Corrections</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">7 votes</span>
<span class="label label--small label--underline">via u/marketAnalyst</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">12</span>
</div>
<div class="content">
<span class="title title--small">The Role of AI in Stock Trading</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">9 votes</span>
<span class="label label--small label--underline">via u/aiTrader</span>
</div>
</div>
</div>
</div>
<div class="column" data-overflow="true">
<span class="label label--medium group-header"># buttcoin</span>
<div class="item">
<div class="meta">
<span class="index">1</span>
</div>
<div class="content">
<span class="title title--small">Bitcoin's Uncertain Horizon: Perspectives on Volatility and Regulation</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">23 votes</span>
<span class="label label--small label--underline">via u/skepticViewer</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">2</span>
</div>
<div class="content">
<span class="title title--small">Cryptocurrency Myths and Realities</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">6 votes</span>
<span class="label label--small label--underline">via u/mythBusterCrypto</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">3</span>
</div>
<div class="content">
<span class="title title--small">The 'Digital Gold' Debate: Analyzing Bitcoin as a Safe Haven Asset</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">7 votes</span>
<span class="label label--small label--underline">via u/digitalGoldSkeptic</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">4</span>
</div>
<div class="content">
<span class="title title--small">Deciphering Crypto Through Data</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">36 votes</span>
<span class="label label--small label--underline">via u/dataDrivenAnalyst</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">5</span>
</div>
<div class="content">
<span class="title title--small">Broadening Perspectives: The Long View on Crypto Adoption</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">33 votes</span>
<span class="label label--small label--underline">via u/wideAngleCrypto</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">6</span>
</div>
<div class="content">
<span class="title title--small">Exploring the Rise and Fall of Altcoins: Lessons and Future Predictions</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">12 votes</span>
<span class="label label--small label--underline">via u/altCoinAnalyst</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">7</span>
</div>
<div class="content">
<span class="title title--small">The Future of DeFi</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">18 votes</span>
<span class="label label--small label--underline">via u/defiExpert</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">8</span>
</div>
<div class="content">
<span class="title title--small">Crypto Security Best Practices</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">20 votes</span>
<span class="label label--small label--underline">via u/securityGuru</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">9</span>
</div>
<div class="content">
<span class="title title--small">NFTs: Fad or Future?</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">14 votes</span>
<span class="label label--small label--underline">via u/nftNerd</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">10</span>
</div>
<div class="content">
<span class="title title--small">The Impact of Government Regulations on Crypto</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">22 votes</span>
<span class="label label--small label--underline">via u/regulationWatcher</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">11</span>
</div>
<div class="content">
<span class="title title--small">Crypto Market Predictions for 2024</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">19 votes</span>
<span class="label label--small label--underline">via u/cryptoOracle</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">12</span>
</div>
<div class="content">
<span class="title title--small">Understanding Blockchain Technology</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">25 votes</span>
<span class="label label--small label--underline">via u/blockchainBuff</span>
</div>
</div>
</div>
</div>
<div class="column" data-overflow="true">
<span class="label label--medium group-header"># investing</span>
<div class="item">
<div class="meta">
<span class="index">1</span>
</div>
<div class="content">
<span class="title title--small">Dividend Investing Strategies for Steady Income</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">17 votes</span>
<span class="label label--small label--underline">via u/dividendSeeker</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">2</span>
</div>
<div class="content">
<span class="title title--small">Index Funds vs. Active Management: What Works?</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">21 votes</span>
<span class="label label--small label--underline">via u/indexNerd</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">3</span>
</div>
<div class="content">
<span class="title title--small">Understanding P/E Ratios and Valuation</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">11 votes</span>
<span class="label label--small label--underline">via u/peGuru</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">4</span>
</div>
<div class="content">
<span class="title title--small">Value vs. Growth in 2024</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">14 votes</span>
<span class="label label--small label--underline">via u/valueHunter</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">5</span>
</div>
<div class="content">
<span class="title title--small">How to Read Earnings Reports</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">9 votes</span>
<span class="label label--small label--underline">via u/earningsReader</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">6</span>
</div>
<div class="content">
<span class="title title--small">Portfolio Diversification Essentials</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">13 votes</span>
<span class="label label--small label--underline">via u/diversifyPro</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">7</span>
</div>
<div class="content">
<span class="title title--small">Risk Management for Retail Investors</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">7 votes</span>
<span class="label label--small label--underline">via u/riskAverse</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">8</span>
</div>
<div class="content">
<span class="title title--small">Dollar-Cost Averaging Explained</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">12 votes</span>
<span class="label label--small label--underline">via u/dcaBeliever</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">9</span>
</div>
<div class="content">
<span class="title title--small">Tax-Efficient Investing Tips</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">10 votes</span>
<span class="label label--small label--underline">via u/taxSmart</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">10</span>
</div>
<div class="content">
<span class="title title--small">ETFs vs. Mutual Funds</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">8 votes</span>
<span class="label label--small label--underline">via u/fundsCompare</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">11</span>
</div>
<div class="content">
<span class="title title--small">Building a Long-Term Portfolio</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">16 votes</span>
<span class="label label--small label--underline">via u/longGame</span>
</div>
</div>
</div>
<div class="item">
<div class="meta">
<span class="index">12</span>
</div>
<div class="content">
<span class="title title--small">Rebalancing Strategies That Work</span>
<div class="flex gap--xsmall">
<span class="label label--small label--underline">6 votes</span>
<span class="label label--small label--underline">via u/rebalanceCoach</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="title_bar">
<img class="image" alt="" src="https://trmnl.com/images/plugins/reddit--render.svg">
<span class="title">Reddit</span>
<span class="instance">New posts</span>
</div>关键技巧
columns容器 + 每列data-overflow="true"启用 Overflow Engine,自动截断超出高度的条目group-headerclass 搭配label--medium实现 subreddit 分组标题index提供帖子序号flex gap--xsmall将票数与作者两个 label 横向紧排label--underline用于元数据的细节标注样式