trmnl_preview 0.3.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3944c7a74517407dbb4ee683c628111668149c622be67a4ba3d69a2655d8b48e
4
- data.tar.gz: e6c9d4f7472e4b56d818884ba6ca33307706891da62c40121398036507568fcd
3
+ metadata.gz: 3a39d955b3dbcc869cde5e0210671a94dfa7af0ea1403fb71c883534d85b6eac
4
+ data.tar.gz: f0159db40a383ce3149071fd4826bdb9035abab379d442e8a93012a35f6cce30
5
5
  SHA512:
6
- metadata.gz: 1fd0a512a23f1439cc4030543f92272682917d1024ae8ef6eed7449f51d7677add6a0974ed4783b56ad088729ac53a7343e0c00d9026c83d762fb9f825406eb2
7
- data.tar.gz: 70c1ba02c0df2d7e427fc079f0bee439fdeea0c120f348d562f734e10f10b210c11db34fbc99c76894afa5622714445efb1fee17fa44029080ba22c216462b1d
6
+ metadata.gz: cccd5ba2af16c057717ae4f0acb6843fad3cd9a7f305109817c5d195f278dd1102c39a20cbf21abbbae0e18395b41ac8e5b314f5c10ae763503cc3e877f1403b
7
+ data.tar.gz: 19eb007c4d077a3078cde135ca200873f5d050abe167306b878b3f7374e052c282d3cb348e806486ce62fa0d6c0913efb1b4feaf100e213ad16d6e5167426ed9
data/README.md CHANGED
@@ -4,6 +4,8 @@ A basic self-hosted web server to ease the development and sharing of [TRMNL](ht
4
4
 
5
5
  [Liquid](https://shopify.github.io/liquid/) templates are rendered locally as HTML, leveraging the [TRMNL Design System](https://usetrmnl.com/framework). This server does NOT generate a rendered BMP file. Hence, this is just a _preview_ of the final rendered dashboard.
6
6
 
7
+ The server watches the filesystem for changes to the Liquid templates, seamlessly updating the preview without the need to refresh.
8
+
7
9
  ![Screenshot](docs/preview.png)
8
10
 
9
11
  ## Creating a Plugin
@@ -53,6 +55,7 @@ When the strategy is "webhook", payloads can be POSTed to the `/webhook` endpoin
53
55
 
54
56
  - `strategy` - Either "polling" or "webhook"
55
57
  - `url` - The URL from which to fetch JSON data (polling strategy only)
58
+ - `live_render` - Set to `false` to disable automatic rendering when Liquid templates change (default `true`)
56
59
  - `[polling_headers]` - A section of headers to append to the HTTP poll request (polling strategy only)
57
60
 
58
61
  ## Contributing
data/config.example.toml CHANGED
@@ -5,6 +5,9 @@ strategy = "polling"
5
5
  # Poll URL (required for polling strategy)
6
6
  url = "https://example.com/data.json"
7
7
 
8
+ # Automatically re-render the view when Liquid templates change (default: true)
9
+ live_render = true
10
+
8
11
  # Polling headers (optional, for polling strategy)
9
12
  [polling_headers]
10
13
  authorization = "bearer 123"
@@ -1,4 +1,5 @@
1
1
 
2
+ require 'faye/websocket'
2
3
  require 'sinatra'
3
4
  require 'sinatra/base'
4
5
 
@@ -21,6 +22,13 @@ module TRMNLPreview
21
22
  end
22
23
 
23
24
  @context.poll_data if @context.strategy == 'polling'
25
+
26
+ @live_render_clients = VIEWS.each_with_object({}) { |view, hash| hash[view] = [] }
27
+ @context.on_view_change do |view|
28
+ @live_render_clients[view].each do |ws|
29
+ ws.send(@context.render_template(view))
30
+ end
31
+ end
24
32
  end
25
33
 
26
34
  post '/webhook' do
@@ -32,6 +40,21 @@ module TRMNLPreview
32
40
  redirect '/full'
33
41
  end
34
42
 
43
+ get '/live_render/:view' do
44
+ ws = Faye::WebSocket.new(request.env)
45
+ view = params['view']
46
+
47
+ ws.on(:open) do |event|
48
+ @live_render_clients[view] << ws
49
+ end
50
+
51
+ ws.on(:close) do |event|
52
+ @live_render_clients[view].delete(ws)
53
+ end
54
+
55
+ ws.rack_response
56
+ end
57
+
35
58
  get '/poll' do
36
59
  @context.poll_data
37
60
  redirect back
@@ -45,6 +68,7 @@ module TRMNLPreview
45
68
 
46
69
  get "/render/#{view}" do
47
70
  @view = view
71
+ @live_render = @context.live_render
48
72
  erb :render_view do
49
73
  @context.render_template(view)
50
74
  end
@@ -1,5 +1,6 @@
1
1
  require 'erb'
2
2
  require 'fileutils'
3
+ require 'filewatcher'
3
4
  require 'json'
4
5
  require 'liquid'
5
6
  require 'open-uri'
@@ -9,7 +10,7 @@ require_relative 'liquid_filters'
9
10
 
10
11
  module TRMNLPreview
11
12
  class Context
12
- attr_reader :strategy, :temp_dir
13
+ attr_reader :strategy, :temp_dir, :live_render
13
14
 
14
15
  def initialize(root)
15
16
  config_path = File.join(root, 'config.toml')
@@ -33,12 +34,36 @@ module TRMNLPreview
33
34
  @strategy = config['strategy']
34
35
  @url = config['url']
35
36
  @polling_headers = config['polling_headers'] || {}
37
+ @live_render = config['live_render'] != false
36
38
 
37
39
  unless ['polling', 'webhook'].include?(@strategy)
38
40
  raise "Invalid strategy: #{strategy} (must be 'polling' or 'webhook')"
39
41
  end
40
42
 
41
43
  FileUtils.mkdir_p(@temp_dir)
44
+
45
+ start_filewatcher_thread if @live_render
46
+ end
47
+
48
+ def start_filewatcher_thread
49
+ Thread.new do
50
+ loop do
51
+ begin
52
+ Filewatcher.new(@user_views_dir).watch do |changes|
53
+ views = changes.map { |path, _change| File.basename(path, '.liquid') }
54
+ views.each do |view|
55
+ @view_change_callback.call(view) if @view_change_callback
56
+ end
57
+ end
58
+ rescue => e
59
+ puts "Error during live render: #{e}"
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ def on_view_change(&block)
66
+ @view_change_callback = block
42
67
  end
43
68
 
44
69
  def user_data
@@ -75,13 +100,15 @@ module TRMNLPreview
75
100
  end
76
101
 
77
102
  def render_template(view)
78
- path = view_path(view)
79
- unless File.exist?(path)
80
- return "Missing plugin template: views/#{view}.liquid"
81
- end
82
-
83
- user_template = Liquid::Template.parse(File.read(path), environment: @liquid_environment)
84
- user_template.render(user_data)
103
+ path = view_path(view)
104
+ unless File.exist?(path)
105
+ return "Missing plugin template: views/#{view}.liquid"
106
+ end
107
+
108
+ user_template = Liquid::Template.parse(File.read(path), environment: @liquid_environment)
109
+ user_template.render(user_data)
110
+ rescue StandardError => e
111
+ e.message
85
112
  end
86
113
 
87
114
  def render_full_page(view)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TRMNLPreview
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
  end
@@ -37,6 +37,8 @@ Gem::Specification.new do |spec|
37
37
  spec.add_dependency "puma", "~> 6.5"
38
38
  spec.add_dependency "liquid", "~> 5.6"
39
39
  spec.add_dependency "toml-rb", "~> 3.0"
40
+ spec.add_dependency "filewatcher", "~> 2.1"
41
+ spec.add_dependency "faye-websocket", "~> 0.11.3"
40
42
 
41
43
  # For more information and examples about making a new gem, check out our
42
44
  # guide at: https://bundler.io/guides/creating_gem.html
@@ -0,0 +1,23 @@
1
+ live_render = {};
2
+
3
+ live_render.connect = function () {
4
+ const view = document.querySelector("meta[name='trmnl-view']").content;
5
+ const ws = new WebSocket("/live_render/" + view);
6
+
7
+ ws.onopen = function () {
8
+ console.log("Connected to live push server");
9
+ };
10
+
11
+ ws.onmessage = function (msg) {
12
+ document.querySelector(".view").innerHTML = msg.data;
13
+ };
14
+
15
+ ws.onclose = function () {
16
+ console.log("Reconnecting to live push server...");
17
+ setTimeout(live_render.connect, 1000);
18
+ };
19
+ };
20
+
21
+ document.addEventListener("DOMContentLoaded", function () {
22
+ live_render.connect();
23
+ });
@@ -9,6 +9,11 @@
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
10
  <link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap" rel="stylesheet">
11
11
  <!-- End Inter font -->
12
+
13
+ <% if @live_render %>
14
+ <meta name="trmnl-view" content="<%= @view %>">
15
+ <script src="/live-render.js"></script>
16
+ <% end %>
12
17
  </head>
13
18
  <body class="environment trmnl">
14
19
  <div class="screen">
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trmnl_preview
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rockwell Schrock
@@ -79,6 +79,34 @@ dependencies:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
81
  version: '3.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: filewatcher
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.1'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '2.1'
96
+ - !ruby/object:Gem::Dependency
97
+ name: faye-websocket
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 0.11.3
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: 0.11.3
82
110
  description: Automatically rebuild and preview TRNML plugins in multiple views
83
111
  email:
84
112
  - rockwell@schrock.me
@@ -105,6 +133,7 @@ files:
105
133
  - trmnl_preview.gemspec
106
134
  - web/public/black-case.jpg
107
135
  - web/public/clear-case.jpg
136
+ - web/public/live-render.js
108
137
  - web/public/white-case.jpg
109
138
  - web/views/index.erb
110
139
  - web/views/render_view.erb