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 +4 -4
- data/.ruby-version +1 -0
- data/CHANGELOG.md +20 -0
- data/README.md +33 -12
- data/config.example.toml +11 -0
- data/docs/preview.png +0 -0
- data/exe/trmnlp +8 -1
- data/lib/trmnl_preview/app.rb +38 -81
- data/lib/trmnl_preview/cmd/build.rb +25 -0
- data/lib/trmnl_preview/cmd/serve.rb +31 -0
- data/lib/trmnl_preview/cmd/usage.rb +10 -0
- data/lib/trmnl_preview/context.rb +102 -0
- data/lib/trmnl_preview/liquid_filters.rb +6 -4
- data/lib/trmnl_preview/version.rb +1 -1
- data/lib/trmnl_preview.rb +3 -5
- data/trmnl_preview.gemspec +1 -1
- data/web/public/black-case.jpg +0 -0
- data/web/public/clear-case.jpg +0 -0
- data/web/public/white-case.jpg +0 -0
- data/web/views/index.erb +113 -0
- metadata +16 -10
- data/Rakefile +0 -4
- data/sig/trmnl_preview.rbs +0 -4
- data/views/index.erb +0 -42
- /data/{views → web/views}/render_view.erb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3944c7a74517407dbb4ee683c628111668149c622be67a4ba3d69a2655d8b48e
|
4
|
+
data.tar.gz: e6c9d4f7472e4b56d818884ba6ca33307706891da62c40121398036507568fcd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
3
|
+
A basic self-hosted web server to ease the development and sharing of [TRMNL](https://usetrmnl.com/) plugins.
|
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
|
-
|
7
|
+

|
8
8
|
|
9
|
-
##
|
9
|
+
## Creating a Plugin
|
10
10
|
|
11
|
-
|
11
|
+
This is the structure of a plugin repository.
|
12
12
|
|
13
|
-
|
13
|
+
```
|
14
|
+
views/
|
15
|
+
full.liquid
|
16
|
+
half_horizontal.liquid
|
17
|
+
half_vertical.liquid
|
18
|
+
quadrant.liquid
|
19
|
+
config.toml
|
20
|
+
```
|
14
21
|
|
15
|
-
|
22
|
+
See [config.example.toml](config.example.toml) for an example config.
|
16
23
|
|
17
|
-
|
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
|
-
|
26
|
+
## Running the Server (Docker)
|
20
27
|
|
21
|
-
|
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
|
48
|
+
When the strategy is "polling", the specified URL will be fetched once, when the server starts.
|
28
49
|
|
29
|
-
When the
|
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
|
|
data/config.example.toml
ADDED
@@ -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
|
-
|
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
|
data/lib/trmnl_preview/app.rb
CHANGED
@@ -1,97 +1,54 @@
|
|
1
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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,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
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
data/lib/trmnl_preview.rb
CHANGED
@@ -2,11 +2,9 @@
|
|
2
2
|
|
3
3
|
module TRMNLPreview; end
|
4
4
|
|
5
|
-
require_relative "trmnl_preview/
|
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
|
-
|
11
|
-
|
12
|
-
end
|
9
|
+
VIEWS = %w{full half_horizontal half_vertical quadrant}
|
10
|
+
end
|
data/trmnl_preview.gemspec
CHANGED
@@ -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
|
data/web/views/index.erb
ADDED
@@ -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.
|
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-
|
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
|
-
-
|
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
|
-
-
|
102
|
-
-
|
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.
|
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
data/sig/trmnl_preview.rbs
DELETED
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
|