snabberb 0.1.1 → 0.2.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/.gitignore +1 -0
- data/.rubocop.yml +2 -2
- data/README.md +12 -0
- data/examples/rack/Gemfile.lock +6 -6
- data/examples/roda/Gemfile +11 -0
- data/examples/roda/Gemfile.lock +49 -0
- data/examples/roda/README.md +14 -0
- data/examples/roda/app/application.rb +106 -0
- data/examples/roda/app/polyfill.js +2 -0
- data/examples/roda/app/requires.rb +5 -0
- data/examples/roda/config.ru +53 -0
- data/examples/roda/roda_example.png +0 -0
- data/lib/snabberb/version.rb +1 -1
- data/lib/snabberb.rb +16 -1
- data/opal/snabberb/component.rb +23 -3
- data/snabberb.gemspec +5 -4
- metadata +27 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9905574c98d778f67508b52d3195f97d3d95b00b6d8a729a086f74c48e03b532
|
4
|
+
data.tar.gz: 770cb2d53f5aa816c0e156ba231ad5bacc26b77fc118ce8c2963930b56faaf25
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1590dacc07bd3dab3da4c7cc5b799744242f29d08e2bd87bff32f56aedfdb50c70225910f4dd8d0ed95372c5f6a45f7fe359db42c7221e78133273b35c8c4cb2
|
7
|
+
data.tar.gz: 3d13da1d38258a606df13c4bdccb8afc2a38d15860f42a900718b903492cfdbe7a84d0342187cdde9bb3239075463cd5651785122bf7f00bcf008c745e1fccd6
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -43,6 +43,8 @@ TextBox.html(text: 'hello world')
|
|
43
43
|
## Examples
|
44
44
|
[Rack App](examples/rack)
|
45
45
|
|
46
|
+
[Roda App with HTML Prerendering](examples/roda)
|
47
|
+
|
46
48
|
## Usage
|
47
49
|
|
48
50
|
### Creating DOM Elements With h
|
@@ -136,6 +138,16 @@ The precedence of need values is stored > passed needs > default value.
|
|
136
138
|
|
137
139
|
Needs can be set with #store which will trigger a view update. Snabberb uses Snabbdom to update the DOM, so only the differences in the DOM are changed.
|
138
140
|
|
141
|
+
### Prerendering
|
142
|
+
|
143
|
+
You can prerender your HTML by calling
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
Snabberb.prerender_script('LayoutClass', 'ApplicationClass', 'application_id', javascript_include_tags: '', **needs)
|
147
|
+
```
|
148
|
+
|
149
|
+
A detailed example can be found [in the Roda example](examples/roda).
|
150
|
+
|
139
151
|
## Installation
|
140
152
|
|
141
153
|
Add this line to your application's Gemfile:
|
data/examples/rack/Gemfile.lock
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ../..
|
3
3
|
specs:
|
4
|
-
snabberb (0.
|
4
|
+
snabberb (0.2.0)
|
5
5
|
opal (~> 1.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
10
|
ast (2.4.0)
|
11
|
-
c_lexer (2.
|
11
|
+
c_lexer (2.6.4.1.1)
|
12
12
|
ast (~> 2.4.0)
|
13
|
-
parser (= 2.
|
14
|
-
opal (1.0.
|
13
|
+
parser (= 2.6.4.1)
|
14
|
+
opal (1.0.1)
|
15
15
|
ast (>= 2.3.0)
|
16
|
-
parser (
|
17
|
-
parser (2.
|
16
|
+
parser (~> 2.6)
|
17
|
+
parser (2.6.4.1)
|
18
18
|
ast (~> 2.4.0)
|
19
19
|
rack (2.0.7)
|
20
20
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../..
|
3
|
+
specs:
|
4
|
+
snabberb (0.2.0)
|
5
|
+
opal (~> 1.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
ast (2.4.0)
|
11
|
+
c_lexer (2.6.4.1.1)
|
12
|
+
ast (~> 2.4.0)
|
13
|
+
parser (= 2.6.4.1)
|
14
|
+
concurrent-ruby (1.1.5)
|
15
|
+
execjs (2.7.0)
|
16
|
+
libv8 (7.3.492.27.1)
|
17
|
+
mini_racer (0.2.8)
|
18
|
+
libv8 (>= 6.9.411)
|
19
|
+
opal (1.0.1)
|
20
|
+
ast (>= 2.3.0)
|
21
|
+
parser (~> 2.6)
|
22
|
+
opal-sprockets (0.4.8.1.0.3.7)
|
23
|
+
opal (~> 1.0.0)
|
24
|
+
sprockets (~> 3.7)
|
25
|
+
tilt (>= 1.4)
|
26
|
+
parser (2.6.4.1)
|
27
|
+
ast (~> 2.4.0)
|
28
|
+
rack (2.0.7)
|
29
|
+
roda (3.26.0)
|
30
|
+
rack
|
31
|
+
sprockets (3.7.2)
|
32
|
+
concurrent-ruby (~> 1.0)
|
33
|
+
rack (> 1, < 3)
|
34
|
+
tilt (2.0.10)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
c_lexer
|
41
|
+
execjs
|
42
|
+
mini_racer
|
43
|
+
opal
|
44
|
+
opal-sprockets
|
45
|
+
roda
|
46
|
+
snabberb!
|
47
|
+
|
48
|
+
BUNDLED WITH
|
49
|
+
2.0.2
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
class Tile < Snabberb::Component
|
6
|
+
def render
|
7
|
+
h(:g, { attrs: { transform: 'rotate(60)' } }, [
|
8
|
+
h(:path, attrs: { d: 'm 0 87 L 0 -87', stroke: 'black', 'stroke-width' => 8 }),
|
9
|
+
h(:path, attrs: { d: 'm -4 86 L -4 -86', stroke: 'white', 'stroke-width' => 2 }),
|
10
|
+
h(:path, attrs: { d: 'm 4 86 L 4 -86', stroke: 'white', 'stroke-width' => 2 }),
|
11
|
+
])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Hex < Snabberb::Component
|
16
|
+
SIZE = 100
|
17
|
+
POINTS = '100,0 50,-87 -50,-87 -100,-0 -50,87 50,87'
|
18
|
+
|
19
|
+
needs :x
|
20
|
+
needs :y
|
21
|
+
needs :selected, default: Set.new, store: true
|
22
|
+
|
23
|
+
def translation
|
24
|
+
offset = self.class::SIZE
|
25
|
+
x = self.class::SIZE * Math.sqrt(3) / 2 * @x + offset
|
26
|
+
y = self.class::SIZE * 3 / 2 * @y + offset
|
27
|
+
"translate(#{x}, #{y})"
|
28
|
+
end
|
29
|
+
|
30
|
+
def transform
|
31
|
+
"#{translation} rotate(30)"
|
32
|
+
end
|
33
|
+
|
34
|
+
def render
|
35
|
+
coordinates = [@x, @y]
|
36
|
+
selected = @selected.include?(coordinates)
|
37
|
+
children = [h(:polygon, attrs: { points: self.class::POINTS })]
|
38
|
+
children << h(Tile) if selected
|
39
|
+
|
40
|
+
onclick = lambda do
|
41
|
+
if selected
|
42
|
+
store(:selected, @selected - [coordinates])
|
43
|
+
else
|
44
|
+
store(:selected, @selected | [coordinates])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
props = {
|
49
|
+
attrs: {
|
50
|
+
transform: transform,
|
51
|
+
fill: selected ? 'yellow' : 'white',
|
52
|
+
stroke: 'black',
|
53
|
+
},
|
54
|
+
style: { cursor: 'pointer' },
|
55
|
+
on: { click: onclick }
|
56
|
+
}
|
57
|
+
|
58
|
+
h(:g, props, children)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Map < Snabberb::Component
|
63
|
+
needs :size_x
|
64
|
+
needs :size_y
|
65
|
+
|
66
|
+
def render
|
67
|
+
hexes = @size_x.times.flat_map do |x|
|
68
|
+
@size_y.times.map do |y|
|
69
|
+
h(Hex, x: y.even? ? x + 1 : x, y: x.even? ? y + 1 : y)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
container_style = {
|
74
|
+
width: '100%',
|
75
|
+
height: '100%',
|
76
|
+
overflow: 'auto',
|
77
|
+
}
|
78
|
+
|
79
|
+
svg_style = {
|
80
|
+
width: "#{@size_x * 50}px",
|
81
|
+
height: "#{@size_y * 80}px",
|
82
|
+
}
|
83
|
+
|
84
|
+
h(:div, { props: { id: 'map_id' }, style: container_style }, [
|
85
|
+
h(:svg, { style: svg_style }, [
|
86
|
+
h(:g, { attrs: { transform: 'scale(0.5)' } }, hexes)
|
87
|
+
])
|
88
|
+
])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class Index < Snabberb::Layout
|
93
|
+
def render
|
94
|
+
h(:html, [
|
95
|
+
h(:head, [
|
96
|
+
h(:meta, props: { charset: 'utf-8' }),
|
97
|
+
h(:title, 'Roda Demo'),
|
98
|
+
]),
|
99
|
+
h(:body, [
|
100
|
+
@application,
|
101
|
+
h(:div, props: { innerHTML: @javascript_include_tags }),
|
102
|
+
h(:script, props: { innerHTML: @attach_func }),
|
103
|
+
]),
|
104
|
+
])
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'execjs'
|
4
|
+
require 'json'
|
5
|
+
require 'opal'
|
6
|
+
require 'opal/sprockets'
|
7
|
+
require 'roda'
|
8
|
+
require 'sprockets'
|
9
|
+
require 'snabberb'
|
10
|
+
|
11
|
+
LIB_NAME = 'lib.js'
|
12
|
+
LIB_PATH = "./public/#{LIB_NAME}"
|
13
|
+
Opal.append_path('app')
|
14
|
+
File.write(LIB_PATH, Opal::Builder.build('requires')) unless File.file?(LIB_PATH)
|
15
|
+
|
16
|
+
class App < Roda
|
17
|
+
plugin :public
|
18
|
+
|
19
|
+
context = ExecJS.compile(File.read(LIB_PATH) + Opal::Builder.build('application').to_s)
|
20
|
+
|
21
|
+
environment = Sprockets::Environment.new
|
22
|
+
Opal.paths.each { |p| environment.append_path(p) }
|
23
|
+
|
24
|
+
javascript_include_tags = "<script src=#{LIB_NAME}></script>" + Opal::Sprockets.javascript_include_tag(
|
25
|
+
'application',
|
26
|
+
sprockets: environment,
|
27
|
+
prefix: '/assets',
|
28
|
+
debug: true,
|
29
|
+
)
|
30
|
+
|
31
|
+
route do |r|
|
32
|
+
r.public
|
33
|
+
|
34
|
+
r.on 'assets' do
|
35
|
+
r.run environment
|
36
|
+
end
|
37
|
+
|
38
|
+
r.root do
|
39
|
+
context.eval(
|
40
|
+
Snabberb.prerender_script(
|
41
|
+
'Index',
|
42
|
+
'Map',
|
43
|
+
'map_id',
|
44
|
+
javascript_include_tags: javascript_include_tags,
|
45
|
+
size_x: 30,
|
46
|
+
size_y: 30,
|
47
|
+
)
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
run App.freeze.app
|
Binary file
|
data/lib/snabberb/version.rb
CHANGED
data/lib/snabberb.rb
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'json'
|
3
4
|
require 'opal'
|
4
5
|
require 'snabberb/version'
|
5
6
|
|
6
|
-
Opal.append_path
|
7
|
+
Opal.append_path(File.expand_path('../opal', __dir__))
|
8
|
+
|
9
|
+
module Snabberb
|
10
|
+
def self.prerender_script(layout, application, application_id, javascript_include_tags: '', **needs)
|
11
|
+
needs = JSON.generate(needs)
|
12
|
+
|
13
|
+
<<~JS
|
14
|
+
Opal.$$.#{layout}.$html(Opal.hash({
|
15
|
+
application: Opal.$$.#{application}.$new(null, Opal.hash(#{needs})).$render(),
|
16
|
+
javascript_include_tags: '#{javascript_include_tags.gsub("\n", '')}',
|
17
|
+
attach_func: 'Opal.$$.#{application}.$attach("#{application_id}", Opal.hash(#{needs}))'
|
18
|
+
}))
|
19
|
+
JS
|
20
|
+
end
|
21
|
+
end
|
data/opal/snabberb/component.rb
CHANGED
@@ -16,12 +16,11 @@ module Snabberb
|
|
16
16
|
# :default - Sets the default value, if not passed the need is considered required.
|
17
17
|
# :store - Whether or not to store the need as state. The default is false.
|
18
18
|
def self.needs(key, **opts)
|
19
|
-
|
20
|
-
@class_needs[key] = opts
|
19
|
+
class_needs[key] = opts
|
21
20
|
end
|
22
21
|
|
23
22
|
def self.class_needs
|
24
|
-
@class_needs
|
23
|
+
@class_needs ||= superclass.respond_to?(:class_needs) ? superclass.class_needs.clone : {}
|
25
24
|
end
|
26
25
|
|
27
26
|
# Attach the root component to a dom element by container id.
|
@@ -145,4 +144,25 @@ module Snabberb
|
|
145
144
|
end
|
146
145
|
end
|
147
146
|
end
|
147
|
+
|
148
|
+
# Sublcass this to prerender applications.
|
149
|
+
class Layout < Snabberb::Component
|
150
|
+
needs :application # the rendered application
|
151
|
+
needs :attach_func # function to reattach the application after dom load
|
152
|
+
needs :javascript_include_tags # all necessary javascript tags
|
153
|
+
|
154
|
+
# Example render function.
|
155
|
+
# def render
|
156
|
+
# h(:html, [
|
157
|
+
# h(:head, [
|
158
|
+
# h(:meta, { props: { charset: 'utf-8'} }),
|
159
|
+
# ]),
|
160
|
+
# h(:body, [
|
161
|
+
# @application,
|
162
|
+
# h(:div, { props: { innerHTML: @javascript_include_tags } }),
|
163
|
+
# h(:script, { props: { innerHTML: @attach_func} }),
|
164
|
+
# ]),
|
165
|
+
# ])
|
166
|
+
# end
|
167
|
+
end
|
148
168
|
end
|
data/snabberb.gemspec
CHANGED
@@ -25,13 +25,14 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.bindir = 'exe'
|
26
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
27
|
spec.require_paths = %w[lib opal]
|
28
|
+
spec.required_ruby_version = '>= 2.3'
|
28
29
|
|
29
30
|
spec.add_dependency 'opal', '~> 1.0'
|
30
31
|
|
31
|
-
spec.add_development_dependency 'bundler'
|
32
|
+
spec.add_development_dependency 'bundler'
|
32
33
|
spec.add_development_dependency 'c_lexer'
|
33
34
|
spec.add_development_dependency 'execjs'
|
34
|
-
spec.add_development_dependency 'rake'
|
35
|
-
spec.add_development_dependency 'rspec'
|
36
|
-
spec.add_development_dependency 'rubocop'
|
35
|
+
spec.add_development_dependency 'rake'
|
36
|
+
spec.add_development_dependency 'rspec'
|
37
|
+
spec.add_development_dependency 'rubocop'
|
37
38
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snabberb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Toby Mao
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: opal
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: c_lexer
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,44 +70,44 @@ dependencies:
|
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rubocop
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0
|
103
|
+
version: '0'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0
|
110
|
+
version: '0'
|
111
111
|
description: 'Snabberb is a minimalistic Opal view framework based on Snabbdom. You
|
112
112
|
can write efficient reactive Javascript in pure Ruby. Snabberb also provides a simple
|
113
113
|
way to track state.
|
@@ -133,6 +133,14 @@ files:
|
|
133
133
|
- examples/rack/app/application.rb
|
134
134
|
- examples/rack/config.ru
|
135
135
|
- examples/rack/index.html.erb
|
136
|
+
- examples/roda/Gemfile
|
137
|
+
- examples/roda/Gemfile.lock
|
138
|
+
- examples/roda/README.md
|
139
|
+
- examples/roda/app/application.rb
|
140
|
+
- examples/roda/app/polyfill.js
|
141
|
+
- examples/roda/app/requires.rb
|
142
|
+
- examples/roda/config.ru
|
143
|
+
- examples/roda/roda_example.png
|
136
144
|
- lib/snabberb.rb
|
137
145
|
- lib/snabberb/version.rb
|
138
146
|
- opal/snabberb.rb
|
@@ -159,7 +167,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
159
167
|
requirements:
|
160
168
|
- - ">="
|
161
169
|
- !ruby/object:Gem::Version
|
162
|
-
version: '
|
170
|
+
version: '2.3'
|
163
171
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
172
|
requirements:
|
165
173
|
- - ">="
|