trmnl_preview 0.3.2 → 0.5.1

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +75 -28
  4. data/bin/trmnlp +14 -0
  5. data/lib/trmnlp/api_client.rb +72 -0
  6. data/lib/{trmnl_preview → trmnlp}/app.rb +24 -12
  7. data/lib/trmnlp/cli.rb +66 -0
  8. data/lib/trmnlp/commands/base.rb +40 -0
  9. data/lib/trmnlp/commands/build.rb +21 -0
  10. data/lib/trmnlp/commands/clone.rb +30 -0
  11. data/lib/trmnlp/commands/init.rb +55 -0
  12. data/lib/trmnlp/commands/login.rb +24 -0
  13. data/lib/trmnlp/commands/pull.rb +43 -0
  14. data/lib/trmnlp/commands/push.rb +61 -0
  15. data/lib/trmnlp/commands/serve.rb +25 -0
  16. data/lib/trmnlp/commands.rb +1 -0
  17. data/lib/trmnlp/config/app.rb +43 -0
  18. data/lib/trmnlp/config/plugin.rb +74 -0
  19. data/lib/trmnlp/config/project.rb +47 -0
  20. data/lib/trmnlp/config.rb +15 -0
  21. data/lib/trmnlp/context.rb +211 -0
  22. data/lib/{trmnl_preview → trmnlp}/custom_filters.rb +2 -1
  23. data/lib/trmnlp/paths.rb +56 -0
  24. data/lib/{trmnl_preview → trmnlp}/screen_generator.rb +1 -1
  25. data/lib/trmnlp/version.rb +5 -0
  26. data/lib/trmnlp.rb +14 -0
  27. data/templates/init/.trmnlp.yml +14 -0
  28. data/templates/init/bin/dev +25 -0
  29. data/templates/init/src/full.liquid +1 -0
  30. data/templates/init/src/half_horizontal.liquid +1 -0
  31. data/templates/init/src/half_vertical.liquid +1 -0
  32. data/templates/init/src/quadrant.liquid +1 -0
  33. data/templates/init/src/settings.yml +15 -0
  34. data/trmnl_preview.gemspec +22 -13
  35. data/web/public/index.js +5 -1
  36. data/web/views/index.erb +2 -0
  37. data/web/views/render_html.erb +1 -1
  38. metadata +110 -24
  39. data/.ruby-version +0 -1
  40. data/config.example.toml +0 -14
  41. data/docs/preview.png +0 -0
  42. data/exe/trmnlp +0 -14
  43. data/lib/trmnl_preview/cmd/build.rb +0 -25
  44. data/lib/trmnl_preview/cmd/serve.rb +0 -31
  45. data/lib/trmnl_preview/cmd/usage.rb +0 -11
  46. data/lib/trmnl_preview/cmd/version.rb +0 -1
  47. data/lib/trmnl_preview/context.rb +0 -135
  48. data/lib/trmnl_preview/version.rb +0 -5
  49. data/lib/trmnl_preview.rb +0 -10
@@ -1,33 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lib/trmnl_preview/version"
3
+ require_relative "lib/trmnlp/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "trmnl_preview"
7
- spec.version = TRMNLPreview::VERSION
7
+ spec.version = TRMNLP::VERSION
8
8
  spec.authors = ["Rockwell Schrock"]
9
9
  spec.email = ["rockwell@schrock.me"]
10
10
 
11
11
  spec.summary = "Local web server to preview TRMNL plugins"
12
12
  spec.description = "Automatically rebuild and preview TRNML plugins in multiple views"
13
- spec.homepage = "https://github.com/schrockwell/trmnl_preview"
13
+ spec.homepage = "https://github.com/usetrmnl/trmnlp"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = ">= 3.0.0"
16
16
 
17
17
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
18
 
19
19
  spec.metadata["homepage_uri"] = spec.homepage
20
- spec.metadata["source_code_uri"] = "https://github.com/schrockwell/trmnl_preview"
20
+ spec.metadata["source_code_uri"] = "https://github.com/usetrmnl/trmnlp"
21
21
 
22
- # Specify which files should be added to the gem when it is released.
23
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
22
  spec.files = Dir.chdir(__dir__) do
25
- `git ls-files -z`.split("\x0").reject do |f|
26
- (File.expand_path(f) == __FILE__) ||
27
- f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile Dockerfile])
28
- end
23
+ [
24
+ 'bin/**/*',
25
+ 'lib/**/*',
26
+ 'templates/**/{*,.*}',
27
+ 'web/**/*',
28
+ 'CHANGELOG.md',
29
+ 'LICENSE.txt',
30
+ 'README.md',
31
+ 'trmnl_preview.gemspec'
32
+ ].flat_map { |glob| Dir[glob] }
29
33
  end
30
- spec.bindir = "exe"
34
+ spec.bindir = "bin"
31
35
  spec.executables = ["trmnlp"]
32
36
  spec.require_paths = ["lib"]
33
37
 
@@ -41,15 +45,20 @@ Gem::Specification.new do |spec|
41
45
  # HTML rendering
42
46
  spec.add_dependency "liquid", "~> 5.6"
43
47
  spec.add_dependency "activesupport", "~> 8.0"
44
-
48
+
45
49
  # BMP rendering
46
50
  spec.add_dependency "ferrum", "~> 0.16"
47
51
  spec.add_dependency 'puppeteer-ruby', '~> 0.45.6'
48
52
  spec.add_dependency 'mini_magick', '~> 4.12.0'
49
53
 
50
54
  # Utilities
51
- spec.add_dependency "toml-rb", "~> 3.0"
52
55
  spec.add_dependency "filewatcher", "~> 2.1"
56
+ spec.add_dependency "faraday", "~> 2.1"
57
+ spec.add_dependency "faraday-multipart", "~> 1.1"
58
+ spec.add_dependency "xdg", "~> 9.1"
59
+ spec.add_dependency "rubyzip", "~> 2.3.0"
60
+ spec.add_dependency "thor", "~> 1.3"
61
+ spec.add_dependency "oj", "~> 3.16.9"
53
62
 
54
63
  # For more information and examples about making a new gem, check out our
55
64
  # guide at: https://bundler.io/guides/creating_gem.html
data/web/public/index.js CHANGED
@@ -8,8 +8,11 @@ trmnlp.connectLiveRender = function () {
8
8
  };
9
9
 
10
10
  ws.onmessage = function (msg) {
11
- if (msg.data === "reload") {
11
+ const payload = JSON.parse(msg.data);
12
+
13
+ if (payload.type === "reload") {
12
14
  trmnlp.setIframeSrc(trmnlp.iframe.src);
15
+ trmnlp.userData.textContent = JSON.stringify(payload.user_data, null, 2);
13
16
  }
14
17
  };
15
18
 
@@ -42,6 +45,7 @@ document.addEventListener("DOMContentLoaded", function () {
42
45
  trmnlp.iframe = document.querySelector("iframe");
43
46
  trmnlp.caseSelect = document.querySelector(".select-case");
44
47
  trmnlp.formatSelect = document.querySelector(".select-format");
48
+ trmnlp.userData = document.getElementById("user-data");
45
49
  trmnlp.isLiveReloadEnabled =
46
50
  document.querySelector("meta[name='live-reload']").content === "true";
47
51
 
data/web/views/index.erb CHANGED
@@ -41,6 +41,8 @@
41
41
  <iframe width="800" height="480"></iframe>
42
42
  <div class="case-overlay"></div>
43
43
  </div>
44
+
45
+ <pre id="user-data"><%= @user_data %></pre>
44
46
  </main>
45
47
  </body>
46
48
  </html>
@@ -11,7 +11,7 @@
11
11
  <!-- End Inter font -->
12
12
  </head>
13
13
  <body class="environment trmnl">
14
- <div class="screen">
14
+ <div class="<%= @screen_classes %>">
15
15
  <div class="view view--<%= @view %>">
16
16
  <%= yield %>
17
17
  </div>
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trmnl_preview
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rockwell Schrock
8
- bindir: exe
8
+ bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-08 00:00:00.000000000 Z
10
+ date: 2025-04-17 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: sinatra
@@ -136,21 +136,21 @@ dependencies:
136
136
  - !ruby/object:Gem::Version
137
137
  version: 4.12.0
138
138
  - !ruby/object:Gem::Dependency
139
- name: toml-rb
139
+ name: filewatcher
140
140
  requirement: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: '3.0'
144
+ version: '2.1'
145
145
  type: :runtime
146
146
  prerelease: false
147
147
  version_requirements: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: '3.0'
151
+ version: '2.1'
152
152
  - !ruby/object:Gem::Dependency
153
- name: filewatcher
153
+ name: faraday
154
154
  requirement: !ruby/object:Gem::Requirement
155
155
  requirements:
156
156
  - - "~>"
@@ -163,6 +163,76 @@ dependencies:
163
163
  - - "~>"
164
164
  - !ruby/object:Gem::Version
165
165
  version: '2.1'
166
+ - !ruby/object:Gem::Dependency
167
+ name: faraday-multipart
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '1.1'
173
+ type: :runtime
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '1.1'
180
+ - !ruby/object:Gem::Dependency
181
+ name: xdg
182
+ requirement: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - "~>"
185
+ - !ruby/object:Gem::Version
186
+ version: '9.1'
187
+ type: :runtime
188
+ prerelease: false
189
+ version_requirements: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: '9.1'
194
+ - !ruby/object:Gem::Dependency
195
+ name: rubyzip
196
+ requirement: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - "~>"
199
+ - !ruby/object:Gem::Version
200
+ version: 2.3.0
201
+ type: :runtime
202
+ prerelease: false
203
+ version_requirements: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: 2.3.0
208
+ - !ruby/object:Gem::Dependency
209
+ name: thor
210
+ requirement: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - "~>"
213
+ - !ruby/object:Gem::Version
214
+ version: '1.3'
215
+ type: :runtime
216
+ prerelease: false
217
+ version_requirements: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - "~>"
220
+ - !ruby/object:Gem::Version
221
+ version: '1.3'
222
+ - !ruby/object:Gem::Dependency
223
+ name: oj
224
+ requirement: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - "~>"
227
+ - !ruby/object:Gem::Version
228
+ version: 3.16.9
229
+ type: :runtime
230
+ prerelease: false
231
+ version_requirements: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - "~>"
234
+ - !ruby/object:Gem::Version
235
+ version: 3.16.9
166
236
  description: Automatically rebuild and preview TRNML plugins in multiple views
167
237
  email:
168
238
  - rockwell@schrock.me
@@ -171,23 +241,39 @@ executables:
171
241
  extensions: []
172
242
  extra_rdoc_files: []
173
243
  files:
174
- - ".ruby-version"
175
244
  - CHANGELOG.md
176
245
  - LICENSE.txt
177
246
  - README.md
178
- - config.example.toml
179
- - docs/preview.png
180
- - exe/trmnlp
181
- - lib/trmnl_preview.rb
182
- - lib/trmnl_preview/app.rb
183
- - lib/trmnl_preview/cmd/build.rb
184
- - lib/trmnl_preview/cmd/serve.rb
185
- - lib/trmnl_preview/cmd/usage.rb
186
- - lib/trmnl_preview/cmd/version.rb
187
- - lib/trmnl_preview/context.rb
188
- - lib/trmnl_preview/custom_filters.rb
189
- - lib/trmnl_preview/screen_generator.rb
190
- - lib/trmnl_preview/version.rb
247
+ - bin/trmnlp
248
+ - lib/trmnlp.rb
249
+ - lib/trmnlp/api_client.rb
250
+ - lib/trmnlp/app.rb
251
+ - lib/trmnlp/cli.rb
252
+ - lib/trmnlp/commands.rb
253
+ - lib/trmnlp/commands/base.rb
254
+ - lib/trmnlp/commands/build.rb
255
+ - lib/trmnlp/commands/clone.rb
256
+ - lib/trmnlp/commands/init.rb
257
+ - lib/trmnlp/commands/login.rb
258
+ - lib/trmnlp/commands/pull.rb
259
+ - lib/trmnlp/commands/push.rb
260
+ - lib/trmnlp/commands/serve.rb
261
+ - lib/trmnlp/config.rb
262
+ - lib/trmnlp/config/app.rb
263
+ - lib/trmnlp/config/plugin.rb
264
+ - lib/trmnlp/config/project.rb
265
+ - lib/trmnlp/context.rb
266
+ - lib/trmnlp/custom_filters.rb
267
+ - lib/trmnlp/paths.rb
268
+ - lib/trmnlp/screen_generator.rb
269
+ - lib/trmnlp/version.rb
270
+ - templates/init/.trmnlp.yml
271
+ - templates/init/bin/dev
272
+ - templates/init/src/full.liquid
273
+ - templates/init/src/half_horizontal.liquid
274
+ - templates/init/src/half_vertical.liquid
275
+ - templates/init/src/quadrant.liquid
276
+ - templates/init/src/settings.yml
191
277
  - trmnl_preview.gemspec
192
278
  - web/public/black-case.jpg
193
279
  - web/public/clear-case.jpg
@@ -196,13 +282,13 @@ files:
196
282
  - web/public/white-case.jpg
197
283
  - web/views/index.erb
198
284
  - web/views/render_html.erb
199
- homepage: https://github.com/schrockwell/trmnl_preview
285
+ homepage: https://github.com/usetrmnl/trmnlp
200
286
  licenses:
201
287
  - MIT
202
288
  metadata:
203
289
  allowed_push_host: https://rubygems.org
204
- homepage_uri: https://github.com/schrockwell/trmnl_preview
205
- source_code_uri: https://github.com/schrockwell/trmnl_preview
290
+ homepage_uri: https://github.com/usetrmnl/trmnlp
291
+ source_code_uri: https://github.com/usetrmnl/trmnlp
206
292
  rdoc_options: []
207
293
  require_paths:
208
294
  - lib
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 3.4.1
data/config.example.toml DELETED
@@ -1,14 +0,0 @@
1
- # strategy = "polling" ==> the data will be fetched once, at server start-up
2
- # strategy = "webhook" ==> POST new data to /webhook
3
- strategy = "polling"
4
-
5
- # Poll URL (required for polling strategy)
6
- url = "https://example.com/data.json"
7
-
8
- # Automatically re-render the view when Liquid templates change (default: true)
9
- live_render = true
10
-
11
- # Polling headers (optional, for polling strategy)
12
- [polling_headers]
13
- authorization = "bearer 123"
14
- content-type = "application/json"
data/docs/preview.png DELETED
Binary file
data/exe/trmnlp DELETED
@@ -1,14 +0,0 @@
1
- #! /usr/bin/env ruby
2
-
3
- require_relative '../lib/trmnl_preview'
4
-
5
- case ARGV[0].to_s.downcase
6
- when 'serve'
7
- require_relative '../lib/trmnl_preview/cmd/serve'
8
- when 'build'
9
- require_relative '../lib/trmnl_preview/cmd/build'
10
- when 'version'
11
- require_relative '../lib/trmnl_preview/cmd/version'
12
- else
13
- require_relative '../lib/trmnl_preview/cmd/usage'
14
- end
@@ -1,25 +0,0 @@
1
- require 'optionparser'
2
-
3
- require_relative '../context'
4
-
5
- OptionParser.new do |opts|
6
- opts.banner = "Usage: trmnlp build [directory]"
7
- end.parse!
8
-
9
- root = ARGV[1] || Dir.pwd
10
- begin
11
- context = TRMNLPreview::Context.new(root)
12
- rescue StandardError => e
13
- puts e.message
14
- exit 1
15
- end
16
-
17
- context.poll_data
18
-
19
- TRMNLPreview::VIEWS.each do |view|
20
- output_path = File.join(context.temp_dir, "#{view}.html")
21
- puts "Creating #{output_path}..."
22
- File.write(output_path, context.render_full_page(view))
23
- end
24
-
25
- puts "Done!"
@@ -1,31 +0,0 @@
1
- require 'optionparser'
2
-
3
- options = {
4
- bind: '127.0.0.1',
5
- port: 4567
6
- }
7
-
8
- # Parse options BEFORE requiring the Sinatra app, since it has its own option-parsing behavior.
9
- # This will remove the option items from ARGV, which is what we want.
10
- OptionParser.new do |opts|
11
- opts.banner = "Usage: trmnlp serve [directory] [options]"
12
-
13
- opts.on("-b", "--bind [HOST]", "Bind to host address (default: 127.0.0.1)") do |host|
14
- options[:bind] = host
15
- end
16
-
17
- opts.on("-p", "--port [PORT]", "Use port (default: 4567)") do |port|
18
- options[:port] = port
19
- end
20
- end.parse!
21
-
22
- # Must come AFTER parsing options
23
- require_relative '../app'
24
-
25
- # Now we can configure things
26
- TRMNLPreview::App.set(:user_dir, ARGV[1] || Dir.pwd)
27
- TRMNLPreview::App.set(:bind, options[:bind])
28
- TRMNLPreview::App.set(:port, options[:port])
29
-
30
- # Finally, start the app!
31
- TRMNLPreview::App.run!
@@ -1,11 +0,0 @@
1
- puts <<-USAGE
2
- Usage:
3
-
4
- trmnlp [command] [options]
5
-
6
- Commands (-h for command-specific help):
7
-
8
- build Generate static HTML files
9
- serve Start the TRMNL Preview server
10
- version Print the version number
11
- USAGE
@@ -1 +0,0 @@
1
- puts TRMNLPreview::VERSION
@@ -1,135 +0,0 @@
1
- require 'erb'
2
- require 'fileutils'
3
- require 'filewatcher'
4
- require 'json'
5
- require 'liquid'
6
- require 'open-uri'
7
- require 'toml-rb'
8
-
9
- require_relative 'custom_filters'
10
-
11
- module TRMNLPreview
12
- class Context
13
- attr_reader :strategy, :temp_dir, :live_render
14
-
15
- def initialize(root, opts = {})
16
- config_path = File.join(root, 'config.toml')
17
- @user_views_dir = File.join(root, 'views')
18
- @temp_dir = File.join(root, 'tmp')
19
- @data_json_path = File.join(@temp_dir, 'data.json')
20
-
21
- unless File.exist?(config_path)
22
- raise "No config.toml found in #{root}"
23
- end
24
-
25
- unless Dir.exist?(@user_views_dir)
26
- raise "No views found at #{@user_views_dir}"
27
- end
28
-
29
- config = TomlRB.load_file(config_path)
30
- @strategy = config['strategy']
31
- @url = config['url']
32
- @polling_headers = config['polling_headers'] || {}
33
- @live_render = config['live_render'] != false
34
- @user_filters = config['custom_filters'] || []
35
-
36
- unless ['polling', 'webhook'].include?(@strategy)
37
- raise "Invalid strategy: #{strategy} (must be 'polling' or 'webhook')"
38
- end
39
-
40
- FileUtils.mkdir_p(@temp_dir)
41
-
42
- @liquid_environment = Liquid::Environment.build do |env|
43
- env.register_filter(CustomFilters)
44
-
45
- @user_filters.each do |module_name, relative_path|
46
- require File.join(root, relative_path)
47
- env.register_filter(Object.const_get(module_name))
48
- end
49
- end
50
-
51
- start_filewatcher_thread if @live_render
52
- end
53
-
54
- def start_filewatcher_thread
55
- Thread.new do
56
- loop do
57
- begin
58
- Filewatcher.new(@user_views_dir).watch do |changes|
59
- views = changes.map { |path, _change| File.basename(path, '.liquid') }
60
- views.each do |view|
61
- @view_change_callback.call(view) if @view_change_callback
62
- end
63
- end
64
- rescue => e
65
- puts "Error during live render: #{e}"
66
- end
67
- end
68
- end
69
- end
70
-
71
- def on_view_change(&block)
72
- @view_change_callback = block
73
- end
74
-
75
- def user_data
76
- data = JSON.parse(File.read(@data_json_path))
77
- data = { data: data } if data.is_a?(Array) # per TRMNL docs, bare array is wrapped in 'data' key
78
- data
79
- end
80
-
81
- def poll_data
82
- if @url.nil?
83
- raise "URL is required for polling strategy"
84
- end
85
-
86
- print "Fetching #{@url}... "
87
-
88
- if @url.match?(/^https?:\/\//)
89
- payload = URI.open(@url, @polling_headers).read
90
- else
91
- payload = File.read(@url)
92
- end
93
-
94
- File.write(@data_json_path, payload)
95
- puts "got #{payload.size} bytes"
96
-
97
- user_data
98
- end
99
-
100
- def set_data(payload)
101
- File.write(@data_json_path, payload)
102
- end
103
-
104
- def view_path(view)
105
- File.join(@user_views_dir, "#{view}.liquid")
106
- end
107
-
108
- def render_template(view)
109
- path = view_path(view)
110
- unless File.exist?(path)
111
- return "Missing plugin template: views/#{view}.liquid"
112
- end
113
-
114
- user_template = Liquid::Template.parse(File.read(path), environment: @liquid_environment)
115
- user_template.render(user_data)
116
- rescue StandardError => e
117
- e.message
118
- end
119
-
120
- def render_full_page(view)
121
- page_erb_template = File.read(File.join(__dir__, '..', '..', 'web', 'views', 'render_html.erb'))
122
-
123
- ERB.new(page_erb_template).result(ERBBinding.new(view).get_binding do
124
- render_template(view)
125
- end)
126
- end
127
-
128
- private
129
-
130
- class ERBBinding
131
- def initialize(view) = @view = view
132
- def get_binding = binding
133
- end
134
- end
135
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TRMNLPreview
4
- VERSION = "0.3.2"
5
- end
data/lib/trmnl_preview.rb DELETED
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TRMNLPreview; end
4
-
5
- require_relative "trmnl_preview/context"
6
- require_relative "trmnl_preview/version"
7
-
8
- module TRMNLPreview
9
- VIEWS = %w{full half_horizontal half_vertical quadrant}
10
- end