joplin-plugin-trmnl-plugin 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # Joplin TRMNL Plugin
2
+
3
+ Push Joplin search results to a [TRMNL](https://usetrmnl.com/) private plugin webhook.
4
+
5
+ ## Features
6
+
7
+ - Configure a Joplin search query to find matching notes
8
+ - Push results to TRMNL as merge variables
9
+ - Two display modes: list of notes, or single note with body
10
+ - Manual push via Tools menu command
11
+ - Optional periodic automatic push
12
+ - Configurable result limit
13
+ - Optional updated time for each note
14
+
15
+ ## Installation
16
+
17
+ 1. Download the latest `.jpl` file from the releases
18
+ 2. In Joplin, go to **Settings** > **Plugins**
19
+ 3. Click the gear icon and select **Install from file**
20
+ 4. Select the downloaded `.jpl` file
21
+
22
+ ## TRMNL Setup
23
+
24
+ Before configuring the Joplin plugin, set up a Private Plugin on the TRMNL side:
25
+
26
+ 1. Log into [usetrmnl.com](https://usetrmnl.com/) and go to **Plugins**.
27
+ 2. Add a new **Private Plugin**.
28
+ 3. Give it a name (e.g. "Joplin Search").
29
+ 4. Set the **Strategy** to **Webhook** — TRMNL will generate a unique webhook URL.
30
+ 5. Copy that URL — you'll paste it into the Joplin plugin settings below.
31
+ 6. In the TRMNL plugin editor, paste the markup template (see [TRMNL Template](#trmnl-template) below). Merge variables become available once data has been pushed at least once.
32
+ 7. After completing the Joplin configuration, run **Tools** > **Test TRMNL connection** (or **Push search results to TRMNL**) to send the first payload — this registers the variable schema with TRMNL.
33
+ 8. Add the plugin to a **Playlist** so it appears in your device's screen rotation.
34
+
35
+ See the [TRMNL Private Plugins documentation](https://docs.usetrmnl.com/go/private-plugins) for the canonical reference on the webhook strategy, payload shape, and Liquid templating.
36
+
37
+ ## Configuration
38
+
39
+ Go to **Settings** > **TRMNL** and configure:
40
+
41
+ | Setting | Description |
42
+ |---------|-------------|
43
+ | TRMNL Webhook URL | The webhook URL from your TRMNL private plugin |
44
+ | Search Query | Joplin search query (e.g., `tag:todo type:note`) |
45
+ | Display Mode | `List of notes` (titles only) or `Single note (with body)` |
46
+ | Result Limit | Maximum number of notes to include in list mode (default: 5) |
47
+ | Push Interval | Automatic push interval in minutes (0 to disable) |
48
+ | Include Updated Time | Include last updated time for each note |
49
+
50
+ In **Single note** mode, the most recent matching note is sent with its body
51
+ (truncated to fit the device). `Result Limit` is ignored in this mode.
52
+
53
+ ## Usage
54
+
55
+ ### Manual Push
56
+
57
+ Go to **Tools** > **Push search results to TRMNL**
58
+
59
+ ### Test Connection
60
+
61
+ Go to **Tools** > **Test TRMNL connection**
62
+
63
+ ## TRMNL Template
64
+
65
+ The plugin sends data in this format. The `mode` field indicates which view to render.
66
+
67
+ **List mode payload:**
68
+
69
+ ```json
70
+ {
71
+ "merge_variables": {
72
+ "title": "Joplin Search",
73
+ "query": "tag:todo type:note",
74
+ "count": 3,
75
+ "mode": "list",
76
+ "items": [
77
+ { "title": "Review PR", "updated": "2026-03-13 09:20" },
78
+ { "title": "Release notes", "updated": "2026-03-12 18:05" }
79
+ ],
80
+ "pushed_at": "2026-03-13 14:00"
81
+ }
82
+ }
83
+ ```
84
+
85
+ **Single-note mode payload:** (no `query` field — the note's title is the headline)
86
+
87
+ ```json
88
+ {
89
+ "merge_variables": {
90
+ "title": "Joplin Search",
91
+ "count": 1,
92
+ "mode": "single",
93
+ "items": [ { "title": "Review PR", "updated": "2026-03-13 09:20" } ],
94
+ "note": {
95
+ "title": "Review PR",
96
+ "updated": "2026-03-13 09:20",
97
+ "body": "Check the auth refactor and the migration script before Friday..."
98
+ },
99
+ "pushed_at": "2026-03-13 14:00"
100
+ }
101
+ }
102
+ ```
103
+
104
+ The note body is stripped of basic Markdown syntax (images, links, emphasis, code
105
+ fences) and truncated to ~1200 characters so it fits the TRMNL "full" view on
106
+ the device.
107
+
108
+ The following template handles both modes and renders correctly on the TRMNL
109
+ e-ink display. Paste it into the **Markup** field of your Private Plugin's
110
+ **Full** view:
111
+
112
+ ```html
113
+ <div class="view view--full">
114
+ {% if mode == "single" and note %}
115
+ <div class="title title--bold">{{ note.title }}</div>
116
+ {% if note.updated %}
117
+ <div class="meta">{{ note.updated }}</div>
118
+ {% endif %}
119
+ <div class="content content--center" style="margin-top: 12px; line-height: 1.35; font-size: 22px; white-space: pre-wrap;">
120
+ {{ note.body }}
121
+ </div>
122
+ {% else %}
123
+ <div class="title title--bold">{{ title }}</div>
124
+ <div class="meta">{{ query }} • {{ count }} notes</div>
125
+
126
+ <div class="list" style="margin-top: 12px;">
127
+ {% for item in items %}
128
+ <div class="item" style="padding: 6px 0; border-bottom: 1px solid #000;">
129
+ <span class="item__title" style="font-weight: bold;">{{ item.title }}</span>
130
+ {% if item.updated %}
131
+ <span class="item__meta" style="float: right; opacity: 0.7;">{{ item.updated }}</span>
132
+ {% endif %}
133
+ </div>
134
+ {% endfor %}
135
+ </div>
136
+ {% endif %}
137
+
138
+ <div class="footer" style="position: absolute; bottom: 8px; left: 0; right: 0; text-align: center; font-size: 14px; opacity: 0.6;">
139
+ Updated {{ pushed_at }}
140
+ </div>
141
+ </div>
142
+ ```
143
+
144
+ Notes for getting it to render well on the device:
145
+
146
+ - TRMNL's "full" layout is ~800×480 pixels of 1-bit e-ink — keep font sizes
147
+ generous (20–24px for body text) and avoid color, shadows, or thin strokes.
148
+ - The `white-space: pre-wrap` on the single-note body preserves paragraph
149
+ breaks from the original Joplin note.
150
+ - If your notes are short, lower `SINGLE_NOTE_BODY_MAX_CHARS` in the source
151
+ for a tighter fit; if they're long, raise it and reduce the font size in
152
+ the template.
153
+
154
+ ## Building
155
+
156
+ ```bash
157
+ npm install
158
+ npm run dist
159
+ ```
160
+
161
+ The plugin will be created at `publish/org.joplinapp.TrmnlPlugin.jpl`.
162
+
163
+ ## License
164
+
165
+ MIT
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "joplin-plugin-trmnl-plugin",
3
+ "version": "1.0.0",
4
+ "scripts": {
5
+ "dist": "webpack --env joplin-plugin-config=buildMain && webpack --env joplin-plugin-config=buildExtraScripts && webpack --env joplin-plugin-config=createArchive",
6
+ "prepare": "npm run dist",
7
+ "updateVersion": "webpack --env joplin-plugin-config=updateVersion",
8
+ "update": "npm install -g generator-joplin && yo joplin --node-package-manager npm --update --force"
9
+ },
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "joplin-plugin"
13
+ ],
14
+ "files": [
15
+ "publish"
16
+ ],
17
+ "devDependencies": {
18
+ "@types/node": "^18.7.13",
19
+ "chalk": "^4.1.0",
20
+ "copy-webpack-plugin": "^11.0.0",
21
+ "fs-extra": "^10.1.0",
22
+ "glob": "^8.0.3",
23
+ "tar": "^6.1.11",
24
+ "ts-loader": "^9.3.1",
25
+ "typescript": "^4.8.2",
26
+ "webpack": "^5.74.0",
27
+ "webpack-cli": "^4.10.0"
28
+ }
29
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "manifest_version": 1,
3
+ "id": "org.joplinapp.plugins.TrmnlPlugin",
4
+ "app_min_version": "3.5",
5
+ "version": "1.0.0",
6
+ "name": "TRMNL",
7
+ "description": "Push Joplin search results to a TRMNL private plugin webhook",
8
+ "author": "Laurent Cozic",
9
+ "homepage_url": "https://github.com/laurent22/joplin-plugin-trmnl",
10
+ "repository_url": "https://github.com/laurent22/joplin-plugin-trmnl",
11
+ "keywords": [
12
+ "trmnl",
13
+ "e-ink",
14
+ "dashboard",
15
+ "search"
16
+ ],
17
+ "categories": [
18
+ "integrations"
19
+ ],
20
+ "screenshots": [],
21
+ "icons": {},
22
+ "promo_tile": {},
23
+ "_publish_hash": "sha256:68d1848d97413c996b78fd447f8d7a95223161d284b9c512e6d04a3ed28ffb67",
24
+ "_publish_commit": "master:d73d1e44e1fc8b613319ac614611a71b3fa9fb55"
25
+ }