glimmer-dsl-web 0.2.5 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cefe3f3c8cf1e4e34eb1703d601e57a99e000ac5691542f275e8c998c6467914
4
- data.tar.gz: f70430fa7d665432a870e01bf69a6e42b328c5b8def261cd1b3fb330451dd54f
3
+ metadata.gz: ebc8e783bfbc67d9366e1887368e89bb7a75db102e56ca966268a2091c5a8e90
4
+ data.tar.gz: a44da8782e6ca10c5183f4f7377eac39bb2b7af4d7e03f088d885a2fce34b219
5
5
  SHA512:
6
- metadata.gz: 1610a4360edd9019218e7d483e97b45d636da381250edba3616503d5677c4109818ee81d1b9ae2715688632214edadc96762c81c2fde2706ace9d7bae9a0dbc2
7
- data.tar.gz: f35f136f78c03b53c264392cb1ee1c9bae16601b2992b721bea0a3748a6cbcff2e67012ef86d3e8cd4c2cdbfccec577921a4322833d5223bd27bbc0a114c16a4
6
+ metadata.gz: 577aea1ffced7cb27937958583c877416921d3f784fd4a2a9589ed3a3b95f39037b1a22f596ab03ed2c336abdab080fce67533b4120e800cb81d3cef144954a8
7
+ data.tar.gz: 05726c636474ad543649bb3200a51c2a238e79248f89207698b229a09fc3e3c6cb9b19489142d71c973505098c1809c8d2978c17ab8628ef9c339666f6fae2f5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.2.7
4
+
5
+ - Unidirectional Data-Binding of element `style` property
6
+ - Support `a` as a formatting element under `p`
7
+ - Todo MVC Sample: `require 'glimmer-dsl-web/samples/regular/todo_mvc'`
8
+
9
+ ## 0.2.6
10
+
11
+ - Upgrade to `glimmer-dsl-xml` 1.4.0 to provide access to `html_to_glimmer` converter command (converts legacy HTML to Glimmer DSL syntax)
12
+ - Upgrade to `glimmer-dsl-css` 1.4.0 to provide access to `css_to_glimmer` converter command (converts legacy CSS to Glimmer DSL syntax)
13
+
3
14
  ## 0.2.5
4
15
 
5
16
  - Support `Element#class_name` as an alternative to `Element#class` because `class` is a reserved method in Ruby
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for Web 0.2.5 (Beta)
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for Web 0.2.7 (Beta)
2
2
  ## Ruby in the Browser Web Frontend Framework
3
3
  ### Finally, Ruby Developer Productivity, Happiness, and Fun in the Frontend!!!
4
4
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-web.svg)](http://badge.fury.io/rb/glimmer-dsl-web)
@@ -8,9 +8,11 @@
8
8
 
9
9
  **(Talk Videos: [Intro to Ruby in the Browser](https://youtu.be/4AdcfbI6A4c?si=MmxOrkhIXTDHQoYi) & [Frontend Ruby with Glimmer DSL for Web](https://youtu.be/rIZ-ILUv9ME?si=raygUXVPd_7ypWuE))**
10
10
 
11
- You can finally have Ruby developer happiness and productivity in the Frontend! No more wasting time splitting your resources across multiple languages, using badly engineered, over-engineered, or premature-optimization-obsessed JavaScript libraries, fighting JavaScript build issues (e.g. webpack), or rewriting Ruby Backend code in Frontend JavaScript. With [Ruby in the Browser](https://www.youtube.com/watch?v=4AdcfbI6A4c), you can have an exponential jump in development productivity (2x or higher), time-to-release (1/2 or less time), cost (1/2 or cheaper), and maintainability (~50% the code that is simpler and more readable) over JavaScript libraries like React, Angular, Ember, Vue, and Svelte, while being able to reuse Backend Ruby code as is in the Frontend for faster interactions when needed. [Ruby in the Browser](https://www.youtube.com/watch?v=4AdcfbI6A4c) finally fulfills every highly-productive Rubyist's dream by bringing Ruby productivity fun to Frontend Development, the same productivity fun you had for years and decades in Backend Development.
11
+ [![Todo MVC](/images/glimmer-dsl-web-samples-regular-todo-mvc.gif)](/lib/glimmer-dsl-web/samples/regular/todo_mvc.rb)
12
12
 
13
- [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for Web enables building Web Frontends using [Ruby in the Browser](https://www.youtube.com/watch?v=4AdcfbI6A4c), as per [Matz's recommendation in his RubyConf 2022 keynote speech to replace JavaScript with Ruby](https://youtu.be/knutsgHTrfQ?t=789). It supports Rails' principle of the One Person Framework by not requiring any extra developers with JavaScript expertise, yet enabling Ruby (Backend) Software Engineers to develop the Frontend with Ruby code that is better than any JavaScript code produced by JS developers. It aims at providing the simplest, most intuitive, most straight-forward, and most productive frontend framework in existence. The framework follows the Ruby way (with [DSLs](https://martinfowler.com/books/dsl.html) and [TIMTOWTDI](https://en.wiktionary.org/wiki/TMTOWTDI#English)) and the Rails way ([Convention over Configuration](https://rubyonrails.org/doctrine)) in building Isomorphic Ruby on Rails Applications. It provides a Ruby [HTML DSL](#usage), which uniquely enables writing both structure code and logic code in one language. It supports both Unidirectional (One-Way) [Data-Binding](#hello-data-binding) (using `<=`) and Bidirectional (Two-Way) [Data-Binding](#hello-data-binding) (using `<=>`). Dynamic rendering (and re-rendering) of HTML content is also supported via [Content Data-Binding](#hello-content-data-binding). Modular design is supported with [Glimmer Web Components](#hello-component). And, a Ruby CSS DSL is supported with the included [Glimmer DSL for CSS](https://github.com/AndyObtiva/glimmer-dsl-css). Many [samples](#samples) are demonstrated in the [Rails sample app](https://github.com/AndyObtiva/sample-glimmer-dsl-web-rails7-app) (there is a very minimal [Standalone [No Rails] static site sample app](https://github.com/Largo/glimmer-dsl-web-standalone-demo) too). You can finally live in pure Rubyland on the Web in both the frontend and backend with [Glimmer DSL for Web](https://rubygems.org/gems/glimmer-dsl-web)!
13
+ You can finally have Ruby developer happiness and productivity in the Frontend! No more wasting time splitting your resources across multiple languages, using badly engineered, over-engineered, or premature-optimization-obsessed JavaScript libraries, fighting JavaScript build issues (e.g. webpack), or rewriting Ruby Backend code in Frontend JavaScript. With [Ruby in the Browser](https://www.youtube.com/watch?v=4AdcfbI6A4c), you can have an exponential jump in development productivity (2x or higher), time-to-release (1/2 or less time), cost (1/2 or cheaper), and maintainability (~50% the code that is simpler and more readable) over JavaScript libraries like React, Angular, Ember, Vue, and Svelte, while being able to reuse Backend Ruby code as is in the Frontend for faster interactions when needed. Also, companies can cut their hiring budget in half by having Backend Ruby Software Engineers do Frontend Development with Ruby! [Ruby in the Browser](https://www.youtube.com/watch?v=4AdcfbI6A4c) finally fulfills every highly-productive Rubyist's dream by bringing Ruby productivity fun to Frontend Development, the same productivity fun you had for years and decades in Backend Development.
14
+
15
+ [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for Web enables building Web Frontends using [Ruby in the Browser](https://www.youtube.com/watch?v=4AdcfbI6A4c), as per [Matz's recommendation in his RubyConf 2022 keynote speech to replace JavaScript with Ruby](https://youtu.be/knutsgHTrfQ?t=789). It supports Rails' principle of the One Person Framework by not requiring any extra developers with JavaScript expertise, yet enabling Ruby (Backend) Software Engineers to develop the Frontend with Ruby code that is better than any JavaScript code produced by JS developers. It aims at providing the simplest, most intuitive, most straight-forward, and most productive frontend framework in existence. The framework follows the Ruby way (with [DSLs](https://martinfowler.com/books/dsl.html) and [TIMTOWTDI](https://en.wiktionary.org/wiki/TMTOWTDI#English)) and the Rails way ([Convention over Configuration](https://rubyonrails.org/doctrine)) in building Isomorphic Ruby on Rails Applications. It provides a Ruby [HTML DSL](#usage), which uniquely enables writing both structure code and logic code in one language. It supports both Unidirectional (One-Way) [Data-Binding](#hello-data-binding) (using `<=`) and Bidirectional (Two-Way) [Data-Binding](#hello-data-binding) (using `<=>`). Dynamic rendering (and re-rendering) of HTML content is also supported via [Content Data-Binding](#hello-content-data-binding). Modular design is supported with [Glimmer Web Components](#hello-component). And, a Ruby CSS DSL is supported with the included [Glimmer DSL for CSS](https://github.com/AndyObtiva/glimmer-dsl-css). To automatically convert legacy HTML & CSS code to Glimmer DSL Ruby code, Software Engineers could use the included [`html_to_glimmer`](https://github.com/AndyObtiva/glimmer-dsl-xml#html-to-glimmer-converter) and [`css_to_glimmer`](https://github.com/AndyObtiva/glimmer-dsl-css#css-to-glimmer-converter) commands. Many [samples](#samples) are demonstrated in the [Rails sample app](https://github.com/AndyObtiva/sample-glimmer-dsl-web-rails7-app) (there is a very minimal [Standalone [No Rails] static site sample app](https://github.com/Largo/glimmer-dsl-web-standalone-demo) too). You can finally live in pure Rubyland on the Web in both the frontend and backend with [Glimmer DSL for Web](https://rubygems.org/gems/glimmer-dsl-web)!
14
16
 
15
17
  [Glimmer DSL for Web](https://rubygems.org/gems/glimmer-dsl-web) aims to be a very simple Ruby-based drop-in replacement for your existing JavaScript Frontend library (e.g. React, Angular, Vue, Ember, Svelte) or your JavaScript Frontend layer in general. It does not change how your Frontend interacts with the Backend, meaning you can continue to write Rails Backend API endpoints as needed and make Ajax HTTP requests or read data embedded in elements, but from [Ruby in the Browser](https://www.youtube.com/watch?v=4AdcfbI6A4c). Whatever is possible in JavaScript is possible when using Glimmer DSL for Web as it integrates with any existing JavaScript library. The [Rails sample app](https://github.com/AndyObtiva/sample-glimmer-dsl-web-rails7-app) demonstrates how to [make Ajax HTTP calls](https://github.com/AndyObtiva/sample-glimmer-dsl-web-rails7-app/blob/master/app/assets/opal/sample_selector/models/sample_selector_presenter.rb) and how to [integrate with a JavaScript library](https://github.com/AndyObtiva/sample-glimmer-dsl-web-rails7-app/blob/master/app/views/layouts/application.html.erb) (highlightjs) that performs [code syntax highlighting](https://github.com/AndyObtiva/sample-glimmer-dsl-web-rails7-app/blob/master/app/assets/opal/sample_selector.rb).
16
18
 
@@ -1148,6 +1150,100 @@ Screenshot:
1148
1150
 
1149
1151
  ![Hello, Observer!](/images/glimmer-dsl-web-samples-hello-hello-observer.gif)
1150
1152
 
1153
+ **Todo MVC**
1154
+
1155
+ ```ruby
1156
+ require 'glimmer-dsl-web'
1157
+
1158
+ require_relative 'todo_mvc/presenters/todo_presenter'
1159
+
1160
+ require_relative 'todo_mvc/views/new_todo_form'
1161
+ require_relative 'todo_mvc/views/todo_list'
1162
+ require_relative 'todo_mvc/views/todo_filters'
1163
+ require_relative 'todo_mvc/views/todo_mvc_footer'
1164
+
1165
+ class TodoMvc
1166
+ include Glimmer::Web::Component
1167
+
1168
+ before_render do
1169
+ @presenter = TodoPresenter.new
1170
+ end
1171
+
1172
+ after_render do
1173
+ @presenter.setup_filter_routes
1174
+ end
1175
+
1176
+ markup {
1177
+ div(class: 'todomvc') {
1178
+ section(class: 'todoapp') {
1179
+ new_todo_form(presenter: @presenter)
1180
+
1181
+ todo_list(presenter: @presenter)
1182
+
1183
+ todo_filters(presenter: @presenter)
1184
+
1185
+ style {
1186
+ todo_mvc_styles
1187
+ }
1188
+ }
1189
+
1190
+ todo_mvc_footer
1191
+
1192
+ on_remove do
1193
+ @presenter.unsetup_filter_routes
1194
+ end
1195
+ }
1196
+ }
1197
+
1198
+ def todo_mvc_styles
1199
+ rule('body, button, html') {
1200
+ margin '0'
1201
+ padding '0'
1202
+ }
1203
+
1204
+ rule('button') {
1205
+ _webkit_font_smoothing 'antialiased'
1206
+ _webkit_appearance 'none'
1207
+ appearance 'none'
1208
+ background 'none'
1209
+ border '0'
1210
+ color 'inherit'
1211
+ font_family 'inherit'
1212
+ font_size '100%'
1213
+ font_weight 'inherit'
1214
+ vertical_align 'baseline'
1215
+ }
1216
+
1217
+ rule('.todoapp') {
1218
+ background '#fff'
1219
+ margin '130px 0 40px 0'
1220
+ position 'relative'
1221
+ box_shadow '0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1)'
1222
+ }
1223
+
1224
+ media('screen and (-webkit-min-device-pixel-ratio:0)') {
1225
+ rule('body') {
1226
+ font "14px 'Helvetica Neue', Helvetica, Arial, sans-serif"
1227
+ line_height '1.4em'
1228
+ background '#f5f5f5'
1229
+ color '#111111'
1230
+ min_width '230px'
1231
+ max_width '550px'
1232
+ margin '0 auto'
1233
+ _webkit_font_smoothing 'antialiased'
1234
+ font_weight '300'
1235
+ }
1236
+ }
1237
+ end
1238
+ end
1239
+
1240
+ Document.ready? do
1241
+ TodoMvc.render
1242
+ end
1243
+ ```
1244
+
1245
+ ![Todo MVC](/images/glimmer-dsl-web-samples-regular-todo-mvc.gif)
1246
+
1151
1247
  To get started, [Setup](#setup) Ruby gem, read [Usage](#usage) instructions, and check out more [Samples](#samples) (including playing around with a [Rails sample app](https://github.com/AndyObtiva/sample-glimmer-dsl-web-rails7-app)).
1152
1248
 
1153
1249
  --
@@ -1211,6 +1307,8 @@ You can setup Glimmer DSL for Web in [Rails 7](#rails-7), [Rails 6](#rails-6), o
1211
1307
 
1212
1308
  ### Rails 7
1213
1309
 
1310
+ (NOTE: In the future, we plan to automate the setup steps below. If you would like to help contribute that to the project, please do so and open a Pull Request.)
1311
+
1214
1312
  Please follow these steps to setup.
1215
1313
 
1216
1314
  Install a Rails 7 gem:
@@ -1228,7 +1326,7 @@ rails new glimmer_app_server
1228
1326
  Add the following to `Gemfile`:
1229
1327
 
1230
1328
  ```
1231
- gem 'glimmer-dsl-web', '~> 0.2.5'
1329
+ gem 'glimmer-dsl-web', '~> 0.2.7'
1232
1330
  ```
1233
1331
 
1234
1332
  Run:
@@ -1430,6 +1528,8 @@ Next, read [Usage](#usage) instructions, and check out [Samples](#samples).
1430
1528
 
1431
1529
  ### Rails 6
1432
1530
 
1531
+ (NOTE: In the future, we plan to automate the setup steps below. If you would like to help contribute that to the project, please do so and open a Pull Request.)
1532
+
1433
1533
  Please follow these steps to setup.
1434
1534
 
1435
1535
  Install a Rails 6 gem:
@@ -1453,7 +1553,7 @@ Disable the `webpacker` gem line in `Gemfile`:
1453
1553
  Add the following to `Gemfile`:
1454
1554
 
1455
1555
  ```ruby
1456
- gem 'glimmer-dsl-web', '~> 0.2.5'
1556
+ gem 'glimmer-dsl-web', '~> 0.2.7'
1457
1557
  ```
1458
1558
 
1459
1559
  Run:
@@ -3184,9 +3284,13 @@ Learn more by reading the [GPG](https://github.com/AndyObtiva/glimmer/blob/maste
3184
3284
 
3185
3285
  F.A.Q. (Frequently Asked Questions):
3186
3286
 
3287
+ **Can I reuse JavaScript libraries from Glimmer DSL for Web in Ruby?**
3288
+
3289
+ Absolutely. Glimmer DSL for Web can integrate with any JavaScript libraries. You can either load the JavaScript libraries in advance by linking to them in the Rails View/Layout (e.g. linking to JS library CDN URLs) or by including JavaScript files in the lookup directories of Opal Ruby, and adding a Ruby `require('path_to_js_lib')` call in the code. In Ruby, the `$$` global variable gives access to the top-level JavaScript global scope, which enables invocations on any JavaScript objects. For example, `$$.hljs` gives access to the loaded `window.hljs` object for the Highlight.js library, and that enables invoking any functions from that library as needed, like `$$.hljs.highlightAll` to activate code syntax highlighting.
3290
+
3187
3291
  **How does Glimmer DSL for Web compare to Rails Hotwire (Turbo)?**
3188
3292
 
3189
- Glimmer DSL for Web is a Frontend library, meaning it replaces the JavaScript layer in a web application (e.g. Rails app) with Ruby code. On the other hand, Rails Hotwire (Turbo) is mostly a Backend-driven technology that enables automatically replacing HTML DOM elements with HTML markup sent over the wire from a Rails Backend. So, the two technologies are mostly orthogonal, but can be used in the same Rails web application, albeit exclusively on separate web pages at the moment. In the future, we might explore supporting the ability to combine both technologies in the same pages, but until then, use on separate pages. Glimmer DSL for Web can handle any sort of Frontend interactions even without making HTTP calls to the Backend, so it can implement more use-cases than Hotwire. Using Glimmer DSL for Web with Rails API end-points is simpler than using Hotwire overall. That is because Glimmer Content Data-Binding is a simpler version of Turbo Frames that does not require worrying about setting and using element IDs (as that is handled automatically) and that operates at a more correct abstraction level for how we think about View component updates in relation to Model changes (we make updates at the Model layer, and they automatically get reflected in the View through data-binding). Also, Glimmer DSL for Web supports Glimmer Web Components, which enable better division of View code with higher readability than ERB. It is true that Hotwire is an improvement over using JavaScript frameworks like React when there is not much logic beyond updating elements with Server-Side rendered HTML. And, Glimmer DSL for Web is the next big advancement that brings a big improvement over the Hotwire approach.
3293
+ Glimmer DSL for Web is a Frontend library, meaning it replaces the JavaScript layer in a web application (e.g. Rails app) with Ruby code. On the other hand, Rails Hotwire (Turbo) is mostly a Backend-driven technology that enables automatically replacing HTML DOM elements with HTML markup sent over the wire from a Rails Backend. So, the two technologies are mostly orthogonal, but can be used in the same Rails web application, albeit exclusively on separate web pages at the moment. In the future, we might explore supporting the ability to combine both technologies in the same pages, but until then, use on separate pages. Glimmer DSL for Web can handle any sort of Frontend interactions even without making HTTP calls to the Backend, so it can implement more use-cases than Hotwire. Using Glimmer DSL for Web with Rails API end-points is simpler than using Hotwire overall. That is because Glimmer Content Data-Binding is a simpler version of Turbo Frames that does not require worrying about setting and using element IDs (as that is handled automatically) and that operates at a more correct abstraction level for how we think about View component updates in relation to Model changes (we make updates at the Model layer, and they automatically get reflected in the View through data-binding). Also, Glimmer DSL for Web supports Glimmer Web Components, which enable better division and organization of View code into modular components than ERB plus having higher readability. It is true that Hotwire is an improvement over using JavaScript frameworks like React when there is not much logic beyond updating elements with Server-Side rendered HTML. And, Glimmer DSL for Web is the next big advancement that provides an even simpler approach while also giving you full Frontend Development capabilities using Ruby in the Browser.
3190
3294
 
3191
3295
  **How does Glimmer DSL for Web compare to Phlex or ViewComponent?**
3192
3296
 
@@ -3204,6 +3308,7 @@ Without delving into details, Glimmer DSL for Web is meant to be a Ruby-based dr
3204
3308
 
3205
3309
  In the future, support for HTML Web Components will be added, and that will enable reuse of React components by using a library that converts them to HTML Web Components first like [react-to-web-component](https://github.com/bitovi/react-to-web-component) or [react-webcomponent](https://github.com/adobe/react-webcomponent).
3206
3310
 
3311
+
3207
3312
  ### Issues
3208
3313
 
3209
3314
  You may submit [issues](https://github.com/AndyObtiva/glimmer-dsl-web/issues) on [GitHub](https://github.com/AndyObtiva/glimmer-dsl-web/issues).
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.5
1
+ 0.2.7
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: glimmer-dsl-web 0.2.5 ruby lib
5
+ # stub: glimmer-dsl-web 0.2.7 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-dsl-web".freeze
9
- s.version = "0.2.5"
9
+ s.version = "0.2.7"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Andy Maleh".freeze]
14
- s.date = "2024-05-12"
14
+ s.date = "2024-06-15"
15
15
  s.description = "Glimmer DSL for Web (Ruby in the Browser Web Frontend Framework) enables building Web Frontends using Ruby in the Browser, as per Matz's recommendation in his RubyConf 2022 keynote speech to replace JavaScript with Ruby. It aims at providing the simplest, most intuitive, most straight-forward, and most productive frontend framework in existence. The framework follows the Ruby way (with DSLs and TIMTOWTDI) and the Rails way (Convention over Configuration) in building Isomorphic Ruby on Rails Applications. It provides a Ruby HTML DSL, which uniquely enables writing both structure code and logic code in one language. It supports both Unidirectional (One-Way) Data-Binding (using <=) and Bidirectional (Two-Way) Data-Binding (using <=>). Dynamic rendering (and re-rendering) of HTML content is also supported via Content Data-Binding. Modular design is supported with Glimmer Web Components. And, a Ruby CSS DSL is supported with the included Glimmer DSL for CSS. Many samples are demonstrated in the Rails sample app (there is a very minimal Standalone [No Rails] sample app too). You can finally live in pure Rubyland on the Web in both the frontend and backend with Glimmer DSL for Web! This gem relies on Opal Ruby.".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.extra_rdoc_files = [
@@ -48,9 +48,21 @@ Gem::Specification.new do |s|
48
48
  "lib/glimmer-dsl-web/samples/hello/hello_paragraph.rb",
49
49
  "lib/glimmer-dsl-web/samples/hello/hello_world.rb",
50
50
  "lib/glimmer-dsl-web/samples/regular/button_counter.rb",
51
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc.rb",
52
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc/models/todo.rb",
53
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc/presenters/todo_presenter.rb",
54
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc/views/edit_todo_input.rb",
55
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc/views/new_todo_form.rb",
56
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc/views/new_todo_input.rb",
57
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_filters.rb",
58
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_input.rb",
59
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_list.rb",
60
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_list_item.rb",
61
+ "lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_mvc_footer.rb",
51
62
  "lib/glimmer-dsl-web/vendor/jquery.js",
52
63
  "lib/glimmer/config/opal_logger.rb",
53
64
  "lib/glimmer/data_binding/element_binding.rb",
65
+ "lib/glimmer/dsl/web/a_expression.rb",
54
66
  "lib/glimmer/dsl/web/bind_expression.rb",
55
67
  "lib/glimmer/dsl/web/component_expression.rb",
56
68
  "lib/glimmer/dsl/web/content_data_binding_expression.rb",
@@ -82,14 +94,14 @@ Gem::Specification.new do |s|
82
94
  s.specification_version = 4
83
95
 
84
96
  s.add_runtime_dependency(%q<glimmer>.freeze, ["~> 2.7.6"])
85
- s.add_runtime_dependency(%q<glimmer-dsl-xml>.freeze, ["~> 1.3.2"])
86
- s.add_runtime_dependency(%q<glimmer-dsl-css>.freeze, ["~> 1.2.3"])
97
+ s.add_runtime_dependency(%q<glimmer-dsl-xml>.freeze, ["~> 1.4.0"])
98
+ s.add_runtime_dependency(%q<glimmer-dsl-css>.freeze, ["~> 1.4.0"])
87
99
  s.add_runtime_dependency(%q<opal>.freeze, ["= 1.8.2"])
88
100
  s.add_runtime_dependency(%q<opal-rails>.freeze, ["= 2.0.3"])
89
101
  s.add_runtime_dependency(%q<opal-async>.freeze, ["~> 1.4.1"])
90
102
  s.add_runtime_dependency(%q<opal-jquery>.freeze, ["~> 0.5.1"])
91
103
  s.add_runtime_dependency(%q<to_collection>.freeze, [">= 2.0.1", "< 3.0.0"])
92
- s.add_development_dependency(%q<puts_debuggerer>.freeze, [">= 0"])
104
+ s.add_development_dependency(%q<puts_debuggerer>.freeze, [">= 1.0.0"])
93
105
  s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
94
106
  s.add_development_dependency(%q<rake-tui>.freeze, [">= 0"])
95
107
  s.add_development_dependency(%q<jeweler>.freeze, [">= 2.3.9", "< 3.0.0"])
@@ -0,0 +1,17 @@
1
+ require 'glimmer/dsl/static_expression'
2
+ require 'glimmer/dsl/web/general_element_expression'
3
+
4
+ module Glimmer
5
+ module DSL
6
+ module Web
7
+ class AExpression < StaticExpression
8
+ include GeneralElementExpression
9
+
10
+ def can_interpret?(parent, keyword, *args, &block)
11
+ (parent.nil? ||
12
+ (parent.respond_to?(:keyword) && parent.keyword != 'p'))
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -24,6 +24,7 @@ require 'glimmer/dsl/web/element_expression'
24
24
  require 'glimmer/dsl/web/formatting_element_expression'
25
25
  require 'glimmer/dsl/web/listener_expression'
26
26
  require 'glimmer/dsl/web/property_expression'
27
+ require 'glimmer/dsl/web/a_expression'
27
28
  require 'glimmer/dsl/web/span_expression'
28
29
  require 'glimmer/dsl/web/style_expression'
29
30
  require 'glimmer/dsl/web/bind_expression'
@@ -45,6 +46,7 @@ module Glimmer
45
46
  property
46
47
  content_data_binding
47
48
  shine_data_binding
49
+ style
48
50
  formatting_element
49
51
  ]
50
52
  )
@@ -24,7 +24,7 @@ end
24
24
  module Glimmer
25
25
  # Optimize performance through shortcut methods for all HTML elements that circumvent the DSL chain of responsibility
26
26
  element_expression = Glimmer::DSL::Web::ElementExpression.new
27
- (Glimmer::Web::ElementProxy::ELEMENT_KEYWORDS - ['span', 'style']).each do |keyword|
27
+ (Glimmer::Web::ElementProxy::ELEMENT_KEYWORDS - ['a', 'span', 'style']).each do |keyword|
28
28
  Glimmer::DSL::Engine.static_expressions[keyword] ||= Concurrent::Hash.new
29
29
  element_expression_dsl = element_expression.class.dsl
30
30
  Glimmer::DSL::Engine.static_expressions[keyword][element_expression_dsl] = element_expression
@@ -1,13 +1,18 @@
1
- require 'glimmer/dsl/static_expression'
1
+ require 'glimmer/dsl/expression'
2
2
  require 'glimmer/dsl/web/general_element_expression'
3
3
 
4
4
  module Glimmer
5
5
  module DSL
6
6
  module Web
7
- class StyleExpression < StaticExpression
7
+ class StyleExpression < Expression
8
8
  include GeneralElementExpression
9
9
  include Glimmer
10
10
 
11
+ def can_interpret?(parent, keyword, *args, &block)
12
+ keyword == 'style' &&
13
+ !block.nil?
14
+ end
15
+
11
16
  def add_content(parent, keyword, *args, &block)
12
17
  if parent.rendered? || parent.skip_content_on_render_blocks?
13
18
  return_value = css(&block).to_s
@@ -33,7 +33,8 @@ module Glimmer
33
33
  keyword = keyword.to_s
34
34
  (
35
35
  FORMATTING_ELEMENT_KEYWORDS.include?(keyword) ||
36
- (keyword == 'span' && parent&.keyword == 'p')
36
+ (keyword == 'span' && parent&.keyword == 'p') ||
37
+ (keyword == 'a' && parent&.keyword == 'p')
37
38
  )
38
39
  end
39
40
 
@@ -0,0 +1,44 @@
1
+ Todo = Struct.new(:task, :completed, :editing, keyword_init: true) do
2
+ class << self
3
+ attr_writer :all
4
+
5
+ def all
6
+ @all ||= []
7
+ end
8
+
9
+ def active
10
+ all.select(&:active?)
11
+ end
12
+
13
+ def completed
14
+ all.select(&:completed?)
15
+ end
16
+ end
17
+
18
+ FILTERS = [:all, :active, :completed]
19
+
20
+ alias completed? completed
21
+ alias editing? editing
22
+
23
+ def active
24
+ !completed
25
+ end
26
+ alias active? active
27
+
28
+ def start_editing
29
+ return if editing?
30
+ @original_task = task
31
+ self.editing = true
32
+ end
33
+
34
+ def cancel_editing
35
+ return unless editing?
36
+ self.task = @original_task
37
+ self.editing = false
38
+ end
39
+
40
+ def save_editing
41
+ return unless editing?
42
+ self.editing = false
43
+ end
44
+ end
@@ -0,0 +1,102 @@
1
+ require 'glimmer/data_binding/observer'
2
+
3
+ require_relative '../models/todo'
4
+
5
+ class TodoPresenter
6
+ FILTER_ROUTE_REGEXP = /\#\/([^\/]*)$/
7
+
8
+ attr_accessor :todos, :can_clear_completed, :active_todo_count
9
+ attr_reader :new_todo, :filter
10
+
11
+ def initialize
12
+ @todos = Todo.all.clone
13
+ @new_todo = Todo.new(task: '')
14
+ @filter = :all
15
+ refresh_todo_stats
16
+ end
17
+
18
+ def create_todo(todo = nil)
19
+ todo ||= new_todo.clone
20
+ Todo.all.prepend(todo)
21
+ observers_for_todo_stats[todo.object_id] = todo_stat_observer.observe(todo, :completed) unless observers_for_todo_stats.has_key?(todo.object_id)
22
+ refresh_todos_with_filter
23
+ refresh_todo_stats
24
+ new_todo.task = ''
25
+ end
26
+
27
+ def refresh_todos_with_filter
28
+ self.todos = Todo.send(filter).clone
29
+ end
30
+
31
+ def filter=(filter)
32
+ return if filter == @filter
33
+ @filter = filter
34
+ refresh_todos_with_filter
35
+ end
36
+
37
+ def destroy(todo)
38
+ delete(todo)
39
+ refresh_todos_with_filter
40
+ refresh_todo_stats
41
+ end
42
+
43
+ def clear_completed
44
+ Todo.completed.each { |todo| delete(todo) }
45
+ refresh_todos_with_filter
46
+ refresh_todo_stats
47
+ end
48
+
49
+ def toggle_all_completed
50
+ target_completed_value = Todo.active.any?
51
+ todos_to_update = target_completed_value ? Todo.active : Todo.completed
52
+ todos_to_update.each { |todo| todo.completed = target_completed_value }
53
+ end
54
+
55
+ def setup_filter_routes
56
+ @filter_router_function = -> (event) { apply_route_filter }
57
+ $$.addEventListener('popstate', &@filter_router_function)
58
+ apply_route_filter
59
+ end
60
+
61
+ def apply_route_filter
62
+ route_filter_match = $$.document.location.href.to_s.match(FILTER_ROUTE_REGEXP)
63
+ return if route_filter_match.nil?
64
+ route_filter = route_filter_match[1]
65
+ route_filter = 'all' if route_filter == ''
66
+ self.filter = route_filter
67
+ end
68
+
69
+ def unsetup_filter_routes
70
+ $$.removeEventListener('popstate', &@filter_router_function)
71
+ @filter_router_function = nil
72
+ end
73
+
74
+ private
75
+
76
+ def delete(todo)
77
+ Todo.all.delete(todo)
78
+ observer_registration = observers_for_todo_stats.delete(todo.object_id)
79
+ observer_registration&.deregister
80
+ end
81
+
82
+ def observers_for_todo_stats
83
+ @observers_for_todo_stats = {}
84
+ end
85
+
86
+ def todo_stat_observer
87
+ @todo_stat_observer ||= Glimmer::DataBinding::Observer.proc { refresh_todo_stats }
88
+ end
89
+
90
+ def refresh_todo_stats
91
+ refresh_can_clear_completed
92
+ refresh_active_todo_count
93
+ end
94
+
95
+ def refresh_can_clear_completed
96
+ self.can_clear_completed = Todo.completed.any?
97
+ end
98
+
99
+ def refresh_active_todo_count
100
+ self.active_todo_count = Todo.active.count
101
+ end
102
+ end
@@ -0,0 +1,55 @@
1
+ require_relative 'todo_input'
2
+
3
+ class EditTodoInput < TodoInput
4
+ option :presenter
5
+ option :todo
6
+
7
+ markup {
8
+ input(class: todo_input_class) { |edit_input|
9
+ style <= [ todo, :editing,
10
+ on_read: ->(editing) { editing ? '' : 'display: none;' },
11
+ after_read: ->(_) { edit_input.focus if todo.editing? }
12
+ ]
13
+
14
+ value <=> [todo, :task]
15
+
16
+ onkeyup do |event|
17
+ if event.key == 'Enter' || event.keyCode == "\r"
18
+ todo.save_editing
19
+ presenter.destroy(todo) if todo.task.strip.empty?
20
+ elsif event.key == 'Escape' || event.keyCode == 27
21
+ todo.cancel_editing
22
+ end
23
+ end
24
+
25
+ onblur do |event|
26
+ todo.save_editing
27
+ end
28
+
29
+ style {
30
+ todo_input_styles
31
+ }
32
+ }
33
+ }
34
+
35
+ def todo_input_class
36
+ 'edit-todo'
37
+ end
38
+
39
+ def todo_input_styles
40
+ super
41
+
42
+ rule("*:has(> .#{todo_input_class})") {
43
+ position 'relative'
44
+ }
45
+
46
+ rule(".#{todo_input_class}") {
47
+ position 'absolute'
48
+ display 'block'
49
+ width 'calc(100% - 43px)'
50
+ padding '12px 16px'
51
+ margin '0 0 0 43px'
52
+ top '0'
53
+ }
54
+ end
55
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'new_todo_input'
2
+
3
+ class NewTodoForm
4
+ include Glimmer::Web::Component
5
+
6
+ option :presenter
7
+
8
+ markup {
9
+ header(class: 'header') {
10
+ h1('todos')
11
+
12
+ new_todo_input(presenter: presenter)
13
+
14
+ style {
15
+ rule('.header h1') {
16
+ color '#b83f45'
17
+ font_size '80px'
18
+ font_weight '200'
19
+ position 'absolute'
20
+ text_align 'center'
21
+ _webkit_text_rendering 'optimizeLegibility'
22
+ _moz_text_rendering 'optimizeLegibility'
23
+ text_rendering 'optimizeLegibility'
24
+ top '-140px'
25
+ width '100%'
26
+ }
27
+ }
28
+ }
29
+ }
30
+ end
@@ -0,0 +1,41 @@
1
+ require_relative 'todo_input'
2
+
3
+ class NewTodoInput < TodoInput
4
+ option :presenter
5
+
6
+ markup {
7
+ input(class: todo_input_class, placeholder: "What needs to be done?", autofocus: "") {
8
+ value <=> [presenter.new_todo, :task]
9
+
10
+ onkeyup do |event|
11
+ presenter.create_todo if event.key == 'Enter' || event.keyCode == "\r"
12
+ end
13
+
14
+ style {
15
+ todo_input_styles
16
+ }
17
+ }
18
+ }
19
+
20
+ def todo_input_class
21
+ 'new-todo'
22
+ end
23
+
24
+ def todo_input_styles
25
+ super
26
+
27
+ rule(".#{todo_input_class}") {
28
+ padding '16px 16px 16px 60px'
29
+ height '65px'
30
+ border 'none'
31
+ background 'rgba(0, 0, 0, 0.003)'
32
+ box_shadow 'inset 0 -2px 1px rgba(0,0,0,0.03)'
33
+ }
34
+
35
+ rule(".#{todo_input_class}::placeholder") {
36
+ font_style 'italic'
37
+ font_weight '400'
38
+ color 'rgba(0, 0, 0, 0.4)'
39
+ }
40
+ end
41
+ end
@@ -0,0 +1,123 @@
1
+ class TodoFilters
2
+ include Glimmer::Web::Component
3
+
4
+ option :presenter
5
+
6
+ markup {
7
+ footer(class: 'todo-filters') {
8
+ style <= [ Todo, :all,
9
+ on_read: ->(todos) { todos.empty? ? 'display: none;' : '' }
10
+ ]
11
+
12
+ span(class: 'todo-count') {
13
+ span('.strong') {
14
+ inner_text <= [presenter, :active_todo_count]
15
+ }
16
+ span {
17
+ " items left"
18
+ }
19
+ }
20
+
21
+ ul(class: 'filters') {
22
+ Todo::FILTERS.each do |filter|
23
+ li {
24
+ a(filter.to_s.capitalize, href: "#/#{filter unless filter == :all}") {
25
+ class_name <= [ presenter, :filter,
26
+ on_read: -> (presenter_filter) { presenter_filter == filter ? 'selected' : '' }
27
+ ]
28
+
29
+ onclick do |event|
30
+ presenter.filter = filter
31
+ end
32
+ }
33
+ }
34
+ end
35
+ }
36
+
37
+ button('Clear completed', class: 'clear-completed') {
38
+ style <= [ presenter, :can_clear_completed,
39
+ on_read: -> (can_clear_completed) { can_clear_completed ? '' : 'display: none;' },
40
+ ]
41
+
42
+ onclick do |event|
43
+ presenter.clear_completed
44
+ end
45
+ }
46
+
47
+ style {
48
+ rule('.todo-filters') {
49
+ border_top '1px solid #e6e6e6'
50
+ font_size '15px'
51
+ height '20px'
52
+ padding '10px 15px'
53
+ text_align 'center'
54
+ }
55
+
56
+ rule('.todo-filters:before') {
57
+ bottom '0'
58
+ box_shadow '0 1px 1px rgba(0,0,0,.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0,0,0,.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0,0,0,.2)'
59
+ content '""'
60
+ height '50px'
61
+ left '0'
62
+ overflow 'hidden'
63
+ position 'absolute'
64
+ right '0'
65
+ }
66
+
67
+ rule('.todo-count') {
68
+ float 'left'
69
+ text_align 'left'
70
+ }
71
+
72
+ rule('.todo-count .strong') {
73
+ font_weight '300'
74
+ }
75
+
76
+ rule('.filters') {
77
+ left '0'
78
+ list_style 'none'
79
+ margin '0'
80
+ padding '0'
81
+ position 'absolute'
82
+ right '0'
83
+ }
84
+
85
+ rule('.filters li') {
86
+ display 'inline'
87
+ }
88
+
89
+ rule('.filters li a') {
90
+ border '1px solid transparent'
91
+ border_radius '3px'
92
+ color 'inherit'
93
+ margin '3px'
94
+ padding '3px 7px'
95
+ text_decoration 'none'
96
+ cursor 'pointer'
97
+ }
98
+
99
+ rule('.filters li a.selected') {
100
+ border_color '#ce4646'
101
+ }
102
+
103
+ rule('.clear-completed, html .clear-completed:active') {
104
+ cursor 'pointer'
105
+ float 'right'
106
+ line_height '19px'
107
+ position 'relative'
108
+ text_decoration 'none'
109
+ }
110
+
111
+ media('(max-width: 430px)') {
112
+ rule('.todo-filters') {
113
+ height '50px'
114
+ }
115
+
116
+ rule('.filters') {
117
+ bottom '10px'
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ end
@@ -0,0 +1,30 @@
1
+ # Superclass for NewTodoInput and EditTodoInput with common styles
2
+ class TodoInput
3
+ include Glimmer::Web::Component
4
+
5
+ def todo_input_class
6
+ 'todo-input'
7
+ end
8
+
9
+ def todo_input_styles
10
+ rule(".#{todo_input_class}") {
11
+ position 'relative'
12
+ margin '0'
13
+ width '100%'
14
+ font_size '24px'
15
+ font_family 'inherit'
16
+ font_weight 'inherit'
17
+ line_height '1.4em'
18
+ color 'inherit'
19
+ padding '6px'
20
+ border '1px solid #999'
21
+ box_shadow 'inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2)'
22
+ box_sizing 'border-box'
23
+ _webkit_font_smoothing 'antialiased'
24
+ }
25
+
26
+ rule(".#{todo_input_class}::selection") {
27
+ background 'red'
28
+ }
29
+ end
30
+ end
@@ -0,0 +1,88 @@
1
+ require_relative 'todo_list_item'
2
+
3
+ class TodoList
4
+ include Glimmer::Web::Component
5
+
6
+ option :presenter
7
+
8
+ markup {
9
+ main(class: 'main') {
10
+ style <= [ Todo, :all,
11
+ on_read: ->(todos) { todos.empty? ? 'display: none;' : '' }
12
+ ]
13
+
14
+ div(class: 'toggle-all-container') {
15
+ input(class: 'toggle-all', type: 'checkbox')
16
+
17
+ label('Mark all as complete', class: 'toggle-all-label', for: 'toggle-all') {
18
+ onclick do |event|
19
+ presenter.toggle_all_completed
20
+ end
21
+ }
22
+ }
23
+
24
+ ul(class: 'todo-list') {
25
+ content(presenter, :todos) {
26
+ presenter.todos.each do |todo|
27
+ todo_list_item(presenter:, todo:)
28
+ end
29
+ }
30
+ }
31
+
32
+ style {
33
+ todo_list_styles
34
+ }
35
+ }
36
+ }
37
+
38
+ def todo_list_styles
39
+ rule('.main') {
40
+ border_top '1px solid #e6e6e6'
41
+ position 'relative'
42
+ z_index '2'
43
+ }
44
+
45
+ rule('.toggle-all') {
46
+ border 'none'
47
+ bottom '100%'
48
+ height '1px'
49
+ opacity '0'
50
+ position 'absolute'
51
+ right '100%'
52
+ width '1px'
53
+ }
54
+
55
+ rule('.toggle-all+label') {
56
+ align_items 'center'
57
+ display 'flex'
58
+ font_size '0'
59
+ height '65px'
60
+ justify_content 'center'
61
+ left '0'
62
+ position 'absolute'
63
+ top '-65px'
64
+ width '45px'
65
+ }
66
+
67
+ rule('.toggle-all+label:before') {
68
+ color '#949494'
69
+ content '"❯"'
70
+ display 'inline-block'
71
+ font_size '22px'
72
+ padding '10px 27px'
73
+ _webkit_transform 'rotate(90deg)'
74
+ transform 'rotate(90deg)'
75
+ }
76
+
77
+ rule('.toggle-all:focus+label, .toggle:focus+label, :focus') {
78
+ box_shadow '0 0 2px 2px #cf7d7d'
79
+ outline '0'
80
+ }
81
+
82
+ rule('.todo-list') {
83
+ list_style 'none'
84
+ margin '0'
85
+ padding '0'
86
+ }
87
+ end
88
+ end
@@ -0,0 +1,158 @@
1
+ require_relative 'edit_todo_input'
2
+
3
+ class TodoListItem
4
+ include Glimmer::Web::Component
5
+
6
+ option :presenter
7
+ option :todo
8
+
9
+ markup {
10
+ li {
11
+ class_name <= [ todo, :completed,
12
+ on_read: -> (completed) { li_class_name(todo) }
13
+ ]
14
+ class_name <= [ todo, :editing,
15
+ on_read: -> (editing) { li_class_name(todo) }
16
+ ]
17
+
18
+ div(class: 'view') {
19
+ input(class: 'toggle', type: 'checkbox') {
20
+ checked <=> [ todo, :completed,
21
+ after_write: -> (_) { presenter.refresh_todos_with_filter if presenter.filter != :all }
22
+ ]
23
+ }
24
+
25
+ label {
26
+ inner_html <= [todo, :task]
27
+
28
+ ondblclick do |event|
29
+ todo.start_editing
30
+ end
31
+ }
32
+
33
+ button(class: 'destroy') {
34
+ onclick do |event|
35
+ presenter.destroy(todo)
36
+ end
37
+ }
38
+ }
39
+
40
+ edit_todo_input(presenter:, todo:)
41
+
42
+ if todo == presenter.todos.first
43
+ style {
44
+ todo_list_item_styles
45
+ }
46
+ end
47
+ }
48
+ }
49
+
50
+ def li_class_name(todo)
51
+ classes = []
52
+ classes << 'completed' if todo.completed?
53
+ classes << 'editing' if todo.editing?
54
+ classes.join(' ')
55
+ end
56
+
57
+ def todo_list_item_styles
58
+ rule('.todo-list li.completed label') {
59
+ color '#949494'
60
+ text_decoration 'line-through'
61
+ }
62
+
63
+ rule('.todo-list li') {
64
+ border_bottom '1px solid #ededed'
65
+ font_size '24px'
66
+ position 'relative'
67
+ }
68
+
69
+ rule('.todo-list li .toggle') {
70
+ _webkit_appearance 'none'
71
+ appearance 'none'
72
+ border 'none'
73
+ bottom '0'
74
+ height 'auto'
75
+ margin 'auto 0'
76
+ opacity '0'
77
+ position 'absolute'
78
+ text_align 'center'
79
+ top '0'
80
+ width '40px'
81
+ }
82
+
83
+ rule('.todo-list li label') {
84
+ color '#484848'
85
+ display 'block'
86
+ font_weight '400'
87
+ line_height '1.2'
88
+ min_height '40px'
89
+ padding '15px 15px 15px 60px'
90
+ transition 'color .4s'
91
+ word_break 'break-all'
92
+ }
93
+
94
+ rule('.todo-list li .toggle+label') {
95
+ background_image 'url(data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23949494%22%20stroke-width%3D%223%22/%3E%3C/svg%3E)'
96
+ background_position '0'
97
+ background_repeat 'no-repeat'
98
+ }
99
+
100
+ rule('.todo-list li.completed label') {
101
+ color '#949494'
102
+ text_decoration 'line-through'
103
+ }
104
+
105
+ rule('.todo-list li .toggle:checked+label') {
106
+ background_image 'url(data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%2359A193%22%20stroke-width%3D%223%22%2F%3E%3Cpath%20fill%3D%22%233EA390%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22%2F%3E%3C%2Fsvg%3E)'
107
+ }
108
+
109
+ rule('.todo-list li.editing') {
110
+ border_bottom 'none'
111
+ padding '0'
112
+ }
113
+
114
+ rule('.todo-list li.editing input[type=checkbox], .todo-list li.editing label') {
115
+ opacity '0'
116
+ }
117
+
118
+ rule('.todo-list li .destroy') {
119
+ bottom '0'
120
+ color '#949494'
121
+ display 'none'
122
+ font_size '30px'
123
+ height '40px'
124
+ margin 'auto 0'
125
+ position 'absolute'
126
+ right '10px'
127
+ top '0'
128
+ transition 'color .2s ease-out'
129
+ width '40px'
130
+ }
131
+
132
+ rule('.todo-list li:focus .destroy, .todo-list li:hover .destroy') {
133
+ display 'block'
134
+ }
135
+
136
+ rule('.todo-list li .destroy:focus, .todo-list li .destroy:hover') {
137
+ color '#c18585'
138
+ }
139
+
140
+ rule('.todo-list li .destroy:after') {
141
+ content '"×"'
142
+ display 'block'
143
+ height '100%'
144
+ line_height '1.1'
145
+ }
146
+
147
+ media ('screen and (-webkit-min-device-pixel-ratio: 0)') {
148
+ rule('.todo-list li .toggle, .toggle-all') {
149
+ background 'none'
150
+ }
151
+
152
+ rule('.todo-list li .toggle') {
153
+ height '40px'
154
+ }
155
+ }
156
+ end
157
+ end
158
+
@@ -0,0 +1,45 @@
1
+ class TodoMvcFooter
2
+ include Glimmer::Web::Component
3
+
4
+ markup {
5
+ footer(class: 'info') {
6
+ p {
7
+ "Double-click to edit a todo"
8
+ }
9
+ p {
10
+ "Created by #{a('Andy Maleh', href: 'https://github.com/AndyObtiva')}"
11
+ }
12
+ p {
13
+ "Part of #{a('TodoMVC', href: 'http://todomvc.com')}"
14
+ }
15
+
16
+ style {
17
+ todo_mvc_styles
18
+ }
19
+ }
20
+ }
21
+
22
+ def todo_mvc_styles
23
+ rule('footer.info') {
24
+ margin '65px auto 0'
25
+ color '#4d4d4d'
26
+ font_size '11px'
27
+ text_shadow '0 1px 0 rgba(255, 255, 255, 0.5)'
28
+ text_align 'center'
29
+ }
30
+
31
+ rule('footer.info p') {
32
+ line_height '1'
33
+ }
34
+
35
+ rule('footer.info a') {
36
+ color 'inherit'
37
+ text_decoration 'none'
38
+ font_weight '400'
39
+ }
40
+
41
+ rule('footer.info a:hover') {
42
+ text_decoration 'underline'
43
+ }
44
+ end
45
+ end
@@ -0,0 +1,87 @@
1
+ require 'glimmer-dsl-web'
2
+
3
+ require_relative 'todo_mvc/presenters/todo_presenter'
4
+
5
+ require_relative 'todo_mvc/views/new_todo_form'
6
+ require_relative 'todo_mvc/views/todo_list'
7
+ require_relative 'todo_mvc/views/todo_filters'
8
+ require_relative 'todo_mvc/views/todo_mvc_footer'
9
+
10
+ class TodoMvc
11
+ include Glimmer::Web::Component
12
+
13
+ before_render do
14
+ @presenter = TodoPresenter.new
15
+ end
16
+
17
+ after_render do
18
+ @presenter.setup_filter_routes
19
+ end
20
+
21
+ markup {
22
+ div(class: 'todomvc') {
23
+ section(class: 'todoapp') {
24
+ new_todo_form(presenter: @presenter)
25
+
26
+ todo_list(presenter: @presenter)
27
+
28
+ todo_filters(presenter: @presenter)
29
+
30
+ style {
31
+ todo_mvc_styles
32
+ }
33
+ }
34
+
35
+ todo_mvc_footer
36
+
37
+ on_remove do
38
+ @presenter.unsetup_filter_routes
39
+ end
40
+ }
41
+ }
42
+
43
+ def todo_mvc_styles
44
+ rule('body, button, html') {
45
+ margin '0'
46
+ padding '0'
47
+ }
48
+
49
+ rule('button') {
50
+ _webkit_font_smoothing 'antialiased'
51
+ _webkit_appearance 'none'
52
+ appearance 'none'
53
+ background 'none'
54
+ border '0'
55
+ color 'inherit'
56
+ font_family 'inherit'
57
+ font_size '100%'
58
+ font_weight 'inherit'
59
+ vertical_align 'baseline'
60
+ }
61
+
62
+ rule('.todoapp') {
63
+ background '#fff'
64
+ margin '130px 0 40px 0'
65
+ position 'relative'
66
+ box_shadow '0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1)'
67
+ }
68
+
69
+ media('screen and (-webkit-min-device-pixel-ratio:0)') {
70
+ rule('body') {
71
+ font "14px 'Helvetica Neue', Helvetica, Arial, sans-serif"
72
+ line_height '1.4em'
73
+ background '#f5f5f5'
74
+ color '#111111'
75
+ min_width '230px'
76
+ max_width '550px'
77
+ margin '0 auto'
78
+ _webkit_font_smoothing 'antialiased'
79
+ font_weight '300'
80
+ }
81
+ }
82
+ end
83
+ end
84
+
85
+ Document.ready? do
86
+ TodoMvc.render
87
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-12 00:00:00.000000000 Z
11
+ date: 2024-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.3.2
33
+ version: 1.4.0
34
34
  type: :runtime
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: 1.3.2
40
+ version: 1.4.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: glimmer-dsl-css
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.2.3
47
+ version: 1.4.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.2.3
54
+ version: 1.4.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: opal
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -134,14 +134,14 @@ dependencies:
134
134
  requirements:
135
135
  - - ">="
136
136
  - !ruby/object:Gem::Version
137
- version: '0'
137
+ version: 1.0.0
138
138
  type: :development
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - ">="
143
143
  - !ruby/object:Gem::Version
144
- version: '0'
144
+ version: 1.0.0
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: rake
147
147
  requirement: !ruby/object:Gem::Requirement
@@ -281,9 +281,21 @@ files:
281
281
  - lib/glimmer-dsl-web/samples/hello/hello_paragraph.rb
282
282
  - lib/glimmer-dsl-web/samples/hello/hello_world.rb
283
283
  - lib/glimmer-dsl-web/samples/regular/button_counter.rb
284
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc.rb
285
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc/models/todo.rb
286
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc/presenters/todo_presenter.rb
287
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc/views/edit_todo_input.rb
288
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc/views/new_todo_form.rb
289
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc/views/new_todo_input.rb
290
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_filters.rb
291
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_input.rb
292
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_list.rb
293
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_list_item.rb
294
+ - lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_mvc_footer.rb
284
295
  - lib/glimmer-dsl-web/vendor/jquery.js
285
296
  - lib/glimmer/config/opal_logger.rb
286
297
  - lib/glimmer/data_binding/element_binding.rb
298
+ - lib/glimmer/dsl/web/a_expression.rb
287
299
  - lib/glimmer/dsl/web/bind_expression.rb
288
300
  - lib/glimmer/dsl/web/component_expression.rb
289
301
  - lib/glimmer/dsl/web/content_data_binding_expression.rb