Display your Linear issues from current and past cycles on your TRMNL display
The fastest way to get started is using the pre-configured recipe:
Add Linear Issues Recipe →Or follow these steps to set it up manually:
The {{ linear_api_key }} variable will be automatically replaced with the user's API key from the form field
Copy and paste this YAML into the Form Fields section in TRMNL
Optional — choose based on your preference
Copy this template and paste it into TRMNL's markup editor:
{% comment %}
TRMNL Plugin: Linear Issues - Current Cycle & Overdue
Displays Linear issues assigned to you that are due in the current cycle or earlier
API Key: {{ trmnl.plugin_settings.custom_fields_values.linear_api_key }}
{% endcomment %}
<style>
.priority-badge {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
}
.priority-1 {
background: #000;
box-shadow: 0 0 0 2px rgba(0,0,0,0.2);
}
.priority-2 {
background: #666;
box-shadow: 0 0 0 2px rgba(0,0,0,0.1);
}
.priority-3 { background: #999; }
.priority-4 { background: #ccc; }
.image.linear-icon {
width: 1.5em;
height: 1.5em;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' width='200' height='200' viewBox='0 0 100 100'%3E%3Cpath fill='%23000' d='M1.22541 61.5228c-.2225-.9485.90748-1.5459 1.59638-.857L39.3342 97.1782c.6889.6889.0915 1.8189-.857 1.5964C20.0515 94.4522 5.54779 79.9485 1.22541 61.5228ZM.00189135 46.8891c-.01764375.2833.08887215.5599.28957165.7606L52.3503 99.7085c.2007.2007.4773.3075.7606.2896 2.3692-.1476 4.6938-.46 6.9624-.9259.7645-.157 1.0301-1.0963.4782-1.6481L2.57595 39.4485c-.55186-.5519-1.49117-.2863-1.648174.4782-.465915 2.2686-.77832 4.5932-.92588465 6.9624ZM4.21093 29.7054c-.16649.3738-.08169.8106.20765 1.1l64.77602 64.776c.2894.2894.7262.3742 1.1.2077 1.7861-.7956 3.5171-1.6927 5.1855-2.684.5521-.328.6373-1.0867.1832-1.5407L8.43566 24.3367c-.45409-.4541-1.21271-.3689-1.54074.1832-.99132 1.6684-1.88843 3.3994-2.68399 5.1855ZM12.6587 18.074c-.3701-.3701-.393-.9637-.0443-1.3541C21.7795 6.45931 35.1114 0 49.9519 0 77.5927 0 100 22.4073 100 50.0481c0 14.8405-6.4593 28.1724-16.7199 37.3375-.3903.3487-.984.3258-1.3542-.0443L12.6587 18.074Z'/%3E%3C/svg%3E");
background-size: contain;
background-repeat: no-repeat;
vertical-align: middle;
}
</style>
<style>
:is(.view--half_vertical, .view--quadrant, .view--half_horizontal) .full-table-view {
display: none;
}
:is(.view--full) .compact-list-view {
display: none;
}
/* Increase font sizes */
.full-table-view .title--small,
.full-table-view .label--small {
font-size: 1.15em;
}
.compact-list-view .title--small,
.compact-list-view .label--small {
font-size: 1.15em;
}
.title_bar .title,
.title_bar .instance {
font-size: 1.15em;
}
/* Half-screen optimizations */
.compact-list-view {
display: flex;
flex-direction: column;
height: 100%;
justify-content: space-between;
}
.compact-list-view .layout {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.compact-list-view .item {
padding: 0.75em 0;
flex-shrink: 0;
}
.compact-list-view .item .content {
flex: 1;
min-width: 0;
}
.compact-list-view .item .title {
word-break: break-word;
overflow-wrap: break-word;
}
.compact-list-view .meta {
flex-shrink: 0;
}
/* Limit items by view size */
.view--quadrant .compact-list-view .item:nth-child(n+3) {
display: none;
}
:is(.view--half_vertical, .view--half_horizontal) .compact-list-view .item:nth-child(n+6) {
display: none;
}
</style>
{% comment %} Full Table Layout {% endcomment %}
<div class="layout layout--top full-table-view">
<table class="table" id="linear-issues">
<thead>
<tr>
<th><span class="title title--small">ID</span></th>
<th><span class="title title--small">Title</span></th>
<th><span class="title title--small">Status</span></th>
<th><span class="title title--small">Cycle</span></th>
</tr>
</thead>
<tbody>
{% assign max_issues = trmnl.plugin_settings.custom_fields_values.max_issues | default: 15 %}
{% for issue in issues limit: max_issues %}
<tr>
<td>
<span class="label label--small issue-id">
{% if issue.priority > 0 and issue.priority < 3 %}
<span class="priority-badge priority-{{ issue.priority }} mr--xsmall"></span>
{% endif %}
{{ issue.identifier }}
</span>
</td>
<td>
<span class="label label--small clamp clamp--2 issue-title">{{ issue.title }}</span>
</td>
<td>
<span class="label label--small issue-status">{{ issue.status }}</span>
</td>
<td class="text--center">
<span class="label label--small cycle-info">
{% if issue.cycleNumber %}
#{{ issue.cycleNumber }}
{% if issue.cycleStatus == 'current' %}
<small>●</small>
{% elsif issue.cycleStatus == 'past' %}
<small>◄</small>
{% elsif issue.cycleStatus == 'future' %}
<small>►</small>
{% endif %}
{% else %}
-
{% endif %}
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% comment %} Compact List Layout (Half Vertical / Half Horizontal / Quadrant) {% endcomment %}
<div class="compact-list-view">
<div class="layout layout--fill">
{% assign max_issues_compact = trmnl.plugin_settings.custom_fields_values.max_issues | default: 10 %}
{% for issue in issues limit: max_issues_compact %}
<div class="item">
<div class="meta">
{% if issue.priority > 0 and issue.priority < 3 %}
<span class="priority-badge priority-{{ issue.priority }}"></span>
{% else %}
<span class="index">{{ forloop.index }}</span>
{% endif %}
</div>
<div class="content">
<div class="flex gap--xsmall" style="flex-wrap: wrap;">
<span class="label label--small" style="font-weight: 600;">{{ issue.identifier }}</span>
<span class="label label--small clamp clamp--2" style="flex: 1; min-width: 0;">{{ issue.title }}</span>
</div>
<div class="flex gap--xsmall" style="margin-top: 0.25em;">
<span class="label label--small">{{ issue.status }}</span>
{% if issue.cycleNumber %}
<span class="label label--small">
#{{ issue.cycleNumber }}
{% if issue.cycleStatus == 'current' %}
<small>●</small>
{% elsif issue.cycleStatus == 'past' %}
<small>◄</small>
{% elsif issue.cycleStatus == 'future' %}
<small>►</small>
{% endif %}
</span>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="title_bar">
<span class="image linear-icon image-stroke"></span>
<span class="title">{{ trmnl.plugin_settings.instance_name }}</span>
<span class="instance">{{ issues | size }} Issues{% if current_cycle %} • Cycle #{{ current_cycle }}{% endif %}</span>
</div>
<script>
var issues_table = document.querySelector("#linear-issues");
if (issues_table.clientHeight >= issues_table.parentNode.clientHeight) {
issues_table.classList.add("table--condensed");
}
</script>