trmnl_preview 0.1.2 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 683080e96cb1ad78c1e0a1bc0bff5553a2e29547c0324a3df5f609e7cb663dc7
4
- data.tar.gz: 38456c612e76196f9261234f2329690f0c5df66840a438eee927da48d588ad56
3
+ metadata.gz: 3944c7a74517407dbb4ee683c628111668149c622be67a4ba3d69a2655d8b48e
4
+ data.tar.gz: e6c9d4f7472e4b56d818884ba6ca33307706891da62c40121398036507568fcd
5
5
  SHA512:
6
- metadata.gz: bb489c533fbca1482f4f76ac8a984b961c2c57be3db296cd6fddc2c515897b3c745f1bd29a333a1592dd60389bfcb1e7fd72c39f7047f42a986a66a5c83e4bdc
7
- data.tar.gz: 6f91c8ffeb1ba92ca700da5d677fbb062d64f9338bf75627979f32ba33ebf4a2afaaa8a3072dfd4afea60436798a81bc64dcacb82a51c3bd273005c27e61697c
6
+ metadata.gz: 1fd0a512a23f1439cc4030543f92272682917d1024ae8ef6eed7449f51d7677add6a0974ed4783b56ad088729ac53a7343e0c00d9026c83d762fb9f825406eb2
7
+ data.tar.gz: 70c1ba02c0df2d7e427fc079f0bee439fdeea0c120f348d562f734e10f10b210c11db34fbc99c76894afa5622714445efb1fee17fa44029080ba22c216462b1d
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.1
data/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ ## 0.3.0
4
+
5
+ - Add poll button
6
+ - Add case image overlays
7
+ - Add `trmnlp build` command
8
+ - Add support for `url` pointing to a local JSON data file
9
+
10
+ ## 0.2.0
11
+
12
+ - Add "commands" concept to `trmnlp` executable
13
+ - `trmnlp serve` improvements
14
+ - Add argument for plugin directory
15
+ - Add options `-b` and `-p` for host bind and port, respectively
16
+ - Add Dockerfile
17
+
18
+ ## 0.1.2
19
+
20
+ - Initial working release
data/README.md CHANGED
@@ -1,32 +1,53 @@
1
1
  # trmnl_preview
2
2
 
3
- A little self-hosted web server to ease the development and sharing of [TRMNL](https://usetrmnl.com/) plugins.
3
+ A basic self-hosted web server to ease the development and sharing of [TRMNL](https://usetrmnl.com/) plugins.
4
4
 
5
- ## Prerequisites
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
- - Ruby 3.x
7
+ ![Screenshot](docs/preview.png)
8
8
 
9
- ## Getting Started
9
+ ## Creating a Plugin
10
10
 
11
- Clone a fork of https://github.com/schrockwell/trmnl-hello.
11
+ This is the structure of a plugin repository.
12
12
 
13
- Run `bundle`.
13
+ ```
14
+ views/
15
+ full.liquid
16
+ half_horizontal.liquid
17
+ half_vertical.liquid
18
+ quadrant.liquid
19
+ config.toml
20
+ ```
14
21
 
15
- Modify `config.toml` (see below for reference).
22
+ See [config.example.toml](config.example.toml) for an example config.
16
23
 
17
- Modify the four view templates in `views/*.liquid`
24
+ The [trmnl-hello](https://github.com/schrockwell/trmnl-hello) repository is provided as a jumping-off point for creating new plugins. Simply fork the repo, clone it, and start hacking.
18
25
 
19
- Run `trmnlp` to start the local web server.
26
+ ## Running the Server (Docker)
20
27
 
21
- Browse it locally at http://127.0.0.1:4567/
28
+ ```sh
29
+ docker run \
30
+ -p 4567:4567 \
31
+ -v /path/to/plugin/on/host:/plugin \
32
+ schrockwell/trmnlp
33
+ ```
34
+
35
+ ## Running the Server (Local Ruby)
36
+
37
+ Ruby 3.x is required. In the plugin repository:
38
+
39
+ ```sh
40
+ bundle add trmnl_preview # Creates Gemfile and Gemfile.lock
41
+ trmnlp serve # Starts the server
42
+ ```
22
43
 
23
44
  ## Usage Notes
24
45
 
25
46
  Simply refresh the page to re-render.
26
47
 
27
- When the polling strategy is "polling", the specified URL will be fetched once when the server starts.
48
+ When the strategy is "polling", the specified URL will be fetched once, when the server starts.
28
49
 
29
- When the polling strategy is "webhook", you can POST payloads to the `/webhook` endpoint. They are saved to `tmp/data.json` for future renders.
50
+ When the strategy is "webhook", payloads can be POSTed to the `/webhook` endpoint. They are saved to `tmp/data.json` for future renders.
30
51
 
31
52
  ## `config.toml` Reference
32
53
 
@@ -0,0 +1,11 @@
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
+ # Polling headers (optional, for polling strategy)
9
+ [polling_headers]
10
+ authorization = "bearer 123"
11
+ content-type = "application/json"
data/docs/preview.png ADDED
Binary file
data/exe/trmnlp CHANGED
@@ -2,4 +2,11 @@
2
2
 
3
3
  require_relative '../lib/trmnl_preview'
4
4
 
5
- TRMNLPreview::App.run!
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
+ else
11
+ require_relative '../lib/trmnl_preview/cmd/usage'
12
+ end
@@ -1,97 +1,54 @@
1
- require 'json'
2
- require 'liquid'
3
- require 'open-uri'
1
+
4
2
  require 'sinatra'
5
3
  require 'sinatra/base'
6
- require 'toml-rb'
7
-
8
- require_relative '../trmnl_preview'
9
- require_relative 'liquid_filters'
10
-
11
- class TRMNLPreview::App < Sinatra::Base
12
- set :views, File.join(File.dirname(__FILE__), '..', '..', 'views')
13
-
14
- # Constants
15
- VIEWS = %w{full half_horizontal half_vertical quadrant}
16
- CONFIG_PATH = File.join(Dir.pwd, 'config.toml')
17
- USER_VIEWS_DIR = File.join(Dir.pwd, 'views')
18
- TEMP_DIR = File.join(Dir.pwd, 'tmp')
19
- DATA_JSON_PATH = File.join(TEMP_DIR, 'data.json')
20
-
21
- unless File.exist?(CONFIG_PATH)
22
- puts "No config.toml found in #{Dir.pwd}"
23
- exit 1
24
- end
25
-
26
- unless Dir.exist?(USER_VIEWS_DIR)
27
- puts "No views found at #{USER_VIEWS_DIR}"
28
- exit 1
29
- end
30
4
 
31
- FileUtils.mkdir_p(TEMP_DIR)
32
-
33
- config = TomlRB.load_file(CONFIG_PATH)
34
- strategy = config['strategy']
35
-
36
- unless ['polling', 'webhook'].include?(strategy)
37
- puts "Invalid strategy: #{strategy} (must be 'polling' or 'webhook')"
38
- exit 1
39
- end
40
-
41
- url = config['url']
42
- polling_headers = config['polling_headers'] || {}
5
+ require_relative 'context'
6
+
7
+ module TRMNLPreview
8
+ class App < Sinatra::Base
9
+ # Sinatra settings
10
+ set :views, File.join(File.dirname(__FILE__), '..', '..', 'web', 'views')
11
+ set :public_folder, File.join(File.dirname(__FILE__), '..', '..', 'web', 'public')
12
+
13
+ def initialize(*args)
14
+ super
15
+
16
+ begin
17
+ @context = Context.new(settings.user_dir)
18
+ rescue StandardError => e
19
+ puts e.message
20
+ exit 1
21
+ end
43
22
 
44
- if strategy == 'polling'
45
- if url.nil?
46
- puts "URL is required for polling strategy"
47
- exit 1
23
+ @context.poll_data if @context.strategy == 'polling'
48
24
  end
49
25
 
50
- print "Fetching #{url}... "
51
- payload = URI.open(url, polling_headers).read
52
- File.write(DATA_JSON_PATH, payload)
53
- puts "got #{payload.size} bytes"
54
- end
55
-
56
- environment = Liquid::Environment.build do |env|
57
- env.register_filter(TRMNLPreview::LiquidFilters)
58
- end
59
-
60
- get '/' do
61
- redirect '/full'
62
- end
63
-
64
- if config['strategy'] == 'webhook'
65
26
  post '/webhook' do
66
- body = request.body.read
67
- File.write(DATA_JSON_PATH, body)
27
+ @context.set_data(request.body.read)
68
28
  "OK"
69
29
  end
30
+
31
+ get '/' do
32
+ redirect '/full'
33
+ end
70
34
 
71
- puts "Listening for POSTs to /webhook"
72
- end
73
-
74
- VIEWS.each do |view|
75
- get "/render/#{view}" do
76
- path = File.join(USER_VIEWS_DIR, "#{view}.liquid")
77
- unless File.exist?(path)
78
- halt 404, "Plugin template not found: views/#{view}.liquid"
35
+ get '/poll' do
36
+ @context.poll_data
37
+ redirect back
38
+ end
39
+
40
+ VIEWS.each do |view|
41
+ get "/#{view}" do
42
+ @view = view
43
+ erb :index
79
44
  end
80
45
 
81
- user_template = Liquid::Template.parse(File.read(path), environment: environment)
82
-
83
- @view = view
84
- erb :render_view do
85
- data = JSON.parse(File.read(DATA_JSON_PATH))
86
- data = { data: data } if data.is_a?(Array) # per TRMNL docs, bare array is wrapped in 'data' key
87
-
88
- user_template.render(data)
46
+ get "/render/#{view}" do
47
+ @view = view
48
+ erb :render_view do
49
+ @context.render_template(view)
50
+ end
89
51
  end
90
52
  end
91
-
92
- get "/#{view}" do
93
- @view = view
94
- erb :index
95
- end
96
53
  end
97
54
  end
@@ -0,0 +1,25 @@
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!"
@@ -0,0 +1,31 @@
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!
@@ -0,0 +1,10 @@
1
+ puts <<-USAGE
2
+ Usage:
3
+
4
+ trmnlp [command] [options]
5
+
6
+ Commands (-h for command-specific help):
7
+
8
+ serve Start the TRMNL Preview server
9
+ build Generate static HTML files
10
+ USAGE
@@ -0,0 +1,102 @@
1
+ require 'erb'
2
+ require 'fileutils'
3
+ require 'json'
4
+ require 'liquid'
5
+ require 'open-uri'
6
+ require 'toml-rb'
7
+
8
+ require_relative 'liquid_filters'
9
+
10
+ module TRMNLPreview
11
+ class Context
12
+ attr_reader :strategy, :temp_dir
13
+
14
+ def initialize(root)
15
+ config_path = File.join(root, 'config.toml')
16
+ @user_views_dir = File.join(root, 'views')
17
+ @temp_dir = File.join(root, 'tmp')
18
+ @data_json_path = File.join(@temp_dir, 'data.json')
19
+
20
+ @liquid_environment = Liquid::Environment.build do |env|
21
+ env.register_filter(LiquidFilters)
22
+ end
23
+
24
+ unless File.exist?(config_path)
25
+ raise "No config.toml found in #{root}"
26
+ end
27
+
28
+ unless Dir.exist?(@user_views_dir)
29
+ raise "No views found at #{@user_views_dir}"
30
+ end
31
+
32
+ config = TomlRB.load_file(config_path)
33
+ @strategy = config['strategy']
34
+ @url = config['url']
35
+ @polling_headers = config['polling_headers'] || {}
36
+
37
+ unless ['polling', 'webhook'].include?(@strategy)
38
+ raise "Invalid strategy: #{strategy} (must be 'polling' or 'webhook')"
39
+ end
40
+
41
+ FileUtils.mkdir_p(@temp_dir)
42
+ end
43
+
44
+ def user_data
45
+ data = JSON.parse(File.read(@data_json_path))
46
+ data = { data: data } if data.is_a?(Array) # per TRMNL docs, bare array is wrapped in 'data' key
47
+ data
48
+ end
49
+
50
+ def poll_data
51
+ if @url.nil?
52
+ raise "URL is required for polling strategy"
53
+ end
54
+
55
+ print "Fetching #{@url}... "
56
+
57
+ if @url.match?(/^https?:\/\//)
58
+ payload = URI.open(@url, @polling_headers).read
59
+ else
60
+ payload = File.read(@url)
61
+ end
62
+
63
+ File.write(@data_json_path, payload)
64
+ puts "got #{payload.size} bytes"
65
+
66
+ user_data
67
+ end
68
+
69
+ def set_data(payload)
70
+ File.write(@data_json_path, payload)
71
+ end
72
+
73
+ def view_path(view)
74
+ File.join(@user_views_dir, "#{view}.liquid")
75
+ end
76
+
77
+ 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)
85
+ end
86
+
87
+ def render_full_page(view)
88
+ page_erb_template = File.read(File.join(__dir__, '..', '..', 'web', 'views', 'render_view.erb'))
89
+
90
+ ERB.new(page_erb_template).result(ERBBinding.new(view).get_binding do
91
+ render_template(view)
92
+ end)
93
+ end
94
+
95
+ private
96
+
97
+ class ERBBinding
98
+ def initialize(view) = @view = view
99
+ def get_binding = binding
100
+ end
101
+ end
102
+ end
@@ -1,6 +1,8 @@
1
- module TRMNLPreview::LiquidFilters
2
- def number_with_delimiter(number)
3
- # TODO: Replace with ActiveSupport's number_with_delimiter
4
- number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
1
+ module TRMNLPreview
2
+ module LiquidFilters
3
+ def number_with_delimiter(number)
4
+ # TODO: Replace with ActiveSupport's number_with_delimiter
5
+ number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
6
+ end
5
7
  end
6
8
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TRMNLPreview
4
- VERSION = "0.1.2"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/trmnl_preview.rb CHANGED
@@ -2,11 +2,9 @@
2
2
 
3
3
  module TRMNLPreview; end
4
4
 
5
- require_relative "trmnl_preview/app"
6
- require_relative "trmnl_preview/liquid_filters"
5
+ require_relative "trmnl_preview/context"
7
6
  require_relative "trmnl_preview/version"
8
7
 
9
8
  module TRMNLPreview
10
- class Error < StandardError; end
11
- # Your code goes here...
12
- end
9
+ VIEWS = %w{full half_horizontal half_vertical quadrant}
10
+ end
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.files = Dir.chdir(__dir__) do
25
25
  `git ls-files -z`.split("\x0").reject do |f|
26
26
  (File.expand_path(f) == __FILE__) ||
27
- f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
27
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile Dockerfile])
28
28
  end
29
29
  end
30
30
  spec.bindir = "exe"
Binary file
Binary file
Binary file
@@ -0,0 +1,113 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>TRMNL Preview</title>
7
+ <style>
8
+ body {
9
+ font-family: sans-serif;
10
+ margin: 10px;
11
+ }
12
+ main {
13
+ display: flex;
14
+ flex-direction: column;
15
+ width: fit-content;
16
+ }
17
+ menu {
18
+ padding: 0;
19
+ margin: 0;
20
+ display: flex;
21
+ justify-content: space-between;
22
+ }
23
+ menu a {
24
+ padding: 0.5em 1em;
25
+ background: #ddd;
26
+ border-radius: 0.5em;
27
+ display: inline-block;
28
+ text-decoration: none;
29
+ color: black;
30
+ }
31
+ menu a:hover {
32
+ background: #ccc;
33
+ }
34
+ menu a.active {
35
+ background: #333;
36
+ color: white;
37
+ }
38
+ .case {
39
+ width: 1000px;
40
+ height: 680px;
41
+ position: relative;
42
+ }
43
+ iframe {
44
+ position: absolute;
45
+ border: none;
46
+ left: 98px;
47
+ top: 65px;
48
+ filter: grayscale(100%);
49
+ }
50
+ .case .case-overlay {
51
+ position: absolute;
52
+ width: 100%;
53
+ height: 100%;
54
+ top: 0;
55
+ left: 0;
56
+ background-size: cover;
57
+ mix-blend-mode: multiply;
58
+ pointer-events: none;
59
+ }
60
+ .case--none .case-overlay { background: none; }
61
+ .case--white .case-overlay { background-image: url('white-case.jpg') }
62
+ .case--black .case-overlay { background-image: url('black-case.jpg') }
63
+ .case--clear .case-overlay { background-image: url('clear-case.jpg') }
64
+ .case--none iframe {
65
+ border: 1px solid black;
66
+ }
67
+ </style>
68
+ <script>
69
+ function updateCase() {
70
+ const value = document.querySelector('.select-case').value;
71
+ document.querySelector('.case').className = `case case--${value}`;
72
+ localStorage.setItem('trmnlp-case', value);
73
+ }
74
+
75
+ document.addEventListener('DOMContentLoaded', () => {
76
+ const caseValue = localStorage.getItem('trmnlp-case') || 'black';
77
+
78
+ const select = document.querySelector('.select-case');
79
+ select.value = caseValue;
80
+ select.addEventListener('change', () => { updateCase() });
81
+
82
+ updateCase();
83
+ });
84
+ </script>
85
+ </head>
86
+ <body>
87
+ <main>
88
+ <menu>
89
+ <div>
90
+ <a class="<%= 'active' if @view == 'full' %>" href="/full">Full</a>
91
+ <a class="<%= 'active' if @view == 'half_horizontal' %>" href="/half_horizontal">Half Horizontal</a>
92
+ <a class="<%= 'active' if @view == 'half_vertical' %>" href="/half_vertical">Half Vertical</a>
93
+ <a class="<%= 'active' if @view == 'quadrant' %>" href="/quadrant">Quadrant</a>
94
+ </div>
95
+ <div>
96
+ <select class="select-case">
97
+ <option value="none">None</option>
98
+ <option value="white">White</option>
99
+ <option value="black" selected>Black</option>
100
+ <option value="clear">Clear</option>
101
+ </select>
102
+
103
+ <a href="/poll">Poll</a>
104
+ </div>
105
+ </menu>
106
+
107
+ <div class="case case--black">
108
+ <iframe src="/render/<%= @view %>" width="800" height="480"></iframe>
109
+ <div class="case-overlay"></div>
110
+ </div>
111
+ </main>
112
+ </body>
113
+ </html>
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trmnl_preview
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rockwell Schrock
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-01-05 00:00:00.000000000 Z
10
+ date: 2025-01-06 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: sinatra
@@ -88,18 +87,27 @@ executables:
88
87
  extensions: []
89
88
  extra_rdoc_files: []
90
89
  files:
90
+ - ".ruby-version"
91
+ - CHANGELOG.md
91
92
  - LICENSE.txt
92
93
  - README.md
93
- - Rakefile
94
+ - config.example.toml
95
+ - docs/preview.png
94
96
  - exe/trmnlp
95
97
  - lib/trmnl_preview.rb
96
98
  - lib/trmnl_preview/app.rb
99
+ - lib/trmnl_preview/cmd/build.rb
100
+ - lib/trmnl_preview/cmd/serve.rb
101
+ - lib/trmnl_preview/cmd/usage.rb
102
+ - lib/trmnl_preview/context.rb
97
103
  - lib/trmnl_preview/liquid_filters.rb
98
104
  - lib/trmnl_preview/version.rb
99
- - sig/trmnl_preview.rbs
100
105
  - trmnl_preview.gemspec
101
- - views/index.erb
102
- - views/render_view.erb
106
+ - web/public/black-case.jpg
107
+ - web/public/clear-case.jpg
108
+ - web/public/white-case.jpg
109
+ - web/views/index.erb
110
+ - web/views/render_view.erb
103
111
  homepage: https://github.com/schrockwell/trmnl_preview
104
112
  licenses:
105
113
  - MIT
@@ -107,7 +115,6 @@ metadata:
107
115
  allowed_push_host: https://rubygems.org
108
116
  homepage_uri: https://github.com/schrockwell/trmnl_preview
109
117
  source_code_uri: https://github.com/schrockwell/trmnl_preview
110
- post_install_message:
111
118
  rdoc_options: []
112
119
  require_paths:
113
120
  - lib
@@ -122,8 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
129
  - !ruby/object:Gem::Version
123
130
  version: '0'
124
131
  requirements: []
125
- rubygems_version: 3.4.10
126
- signing_key:
132
+ rubygems_version: 3.6.2
127
133
  specification_version: 4
128
134
  summary: Local web server to preview TRMNL plugins
129
135
  test_files: []
data/Rakefile DELETED
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- task default: %i[]
@@ -1,4 +0,0 @@
1
- module TRMNLPreview
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end
data/views/index.erb DELETED
@@ -1,42 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>TRMNL Preview</title>
7
- <style>
8
- body {
9
- font-family: sans-serif;
10
- background: #eee;
11
- }
12
- .menu {
13
- margin-bottom: 1em;
14
- }
15
- .menu a {
16
- padding: 0.5em 1em;
17
- background: #ddd;
18
- border-radius: 0.5em;
19
- display: inline-block;
20
- text-decoration: none;
21
- color: black;
22
- }
23
- .menu a:hover {
24
- background: #ccc;
25
- }
26
- .menu a.active {
27
- background: #333;
28
- color: white;
29
- }
30
- </style>
31
- </head>
32
- <body>
33
- <div class="menu">
34
- <a class="<%= 'active' if @view == 'full' %>" href="/full">Full</a>
35
- <a class="<%= 'active' if @view == 'half_horizontal' %>" href="/half_horizontal">Half Horizontal</a>
36
- <a class="<%= 'active' if @view == 'half_vertical' %>" href="/half_vertical">Half Vertical</a>
37
- <a class="<%= 'active' if @view == 'quadrant' %>" href="/quadrant">Quadrant</a>
38
- </div>
39
-
40
- <iframe src="/render/<%= @view %>" width="800" height="480"></iframe>
41
- </body>
42
- </html>
File without changes