ovto 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.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.gitmodules +3 -0
  4. data/CHANGELOG.md +22 -0
  5. data/Gemfile +7 -0
  6. data/Gemfile.lock +57 -0
  7. data/LICENSE.txt +44 -0
  8. data/README.md +84 -0
  9. data/Rakefile +41 -0
  10. data/book/README.md +1 -0
  11. data/book/SUMMARY.md +13 -0
  12. data/book/api/actions.md +77 -0
  13. data/book/api/app.md +86 -0
  14. data/book/api/component.md +175 -0
  15. data/book/api/fetch.md +42 -0
  16. data/book/api/state.md +97 -0
  17. data/book/guides/debugging.md +23 -0
  18. data/book/guides/development.md +11 -0
  19. data/book/guides/tutorial.md +288 -0
  20. data/book/screenshot.png +0 -0
  21. data/docs/api/Ovto/Actions.html +135 -0
  22. data/docs/api/Ovto/App.html +531 -0
  23. data/docs/api/Ovto/Component/MoreThanOneNode.html +135 -0
  24. data/docs/api/Ovto/Component.html +350 -0
  25. data/docs/api/Ovto/Runtime.html +315 -0
  26. data/docs/api/Ovto/State/MissingValue.html +135 -0
  27. data/docs/api/Ovto/State/UnknownKey.html +135 -0
  28. data/docs/api/Ovto/State.html +699 -0
  29. data/docs/api/Ovto/WiredActions.html +343 -0
  30. data/docs/api/Ovto.html +319 -0
  31. data/docs/api/_index.html +229 -0
  32. data/docs/api/actions.html +398 -0
  33. data/docs/api/app.html +411 -0
  34. data/docs/api/class_list.html +51 -0
  35. data/docs/api/component.html +469 -0
  36. data/docs/api/css/common.css +1 -0
  37. data/docs/api/css/full_list.css +58 -0
  38. data/docs/api/css/style.css +499 -0
  39. data/docs/api/file.README.html +162 -0
  40. data/docs/api/file_list.html +56 -0
  41. data/docs/api/frames.html +17 -0
  42. data/docs/api/index.html +162 -0
  43. data/docs/api/js/app.js +248 -0
  44. data/docs/api/js/full_list.js +216 -0
  45. data/docs/api/js/jquery.js +4 -0
  46. data/docs/api/method_list.html +243 -0
  47. data/docs/api/state.html +430 -0
  48. data/docs/api/top-level-namespace.html +110 -0
  49. data/docs/gitbook/fonts/fontawesome/FontAwesome.otf +0 -0
  50. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.eot +0 -0
  51. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.svg +685 -0
  52. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.ttf +0 -0
  53. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.woff +0 -0
  54. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.woff2 +0 -0
  55. data/docs/gitbook/gitbook-plugin-fontsettings/fontsettings.js +240 -0
  56. data/docs/gitbook/gitbook-plugin-fontsettings/website.css +291 -0
  57. data/docs/gitbook/gitbook-plugin-highlight/ebook.css +135 -0
  58. data/docs/gitbook/gitbook-plugin-highlight/website.css +434 -0
  59. data/docs/gitbook/gitbook-plugin-lunr/lunr.min.js +7 -0
  60. data/docs/gitbook/gitbook-plugin-lunr/search-lunr.js +59 -0
  61. data/docs/gitbook/gitbook-plugin-search/lunr.min.js +7 -0
  62. data/docs/gitbook/gitbook-plugin-search/search-engine.js +50 -0
  63. data/docs/gitbook/gitbook-plugin-search/search.css +35 -0
  64. data/docs/gitbook/gitbook-plugin-search/search.js +213 -0
  65. data/docs/gitbook/gitbook-plugin-sharing/buttons.js +90 -0
  66. data/docs/gitbook/gitbook.js +4 -0
  67. data/docs/gitbook/images/apple-touch-icon-precomposed-152.png +0 -0
  68. data/docs/gitbook/images/favicon.ico +0 -0
  69. data/docs/gitbook/style.css +9 -0
  70. data/docs/gitbook/theme.js +4 -0
  71. data/docs/guides/debugging.html +355 -0
  72. data/docs/guides/development.html +361 -0
  73. data/docs/guides/tutorial.html +571 -0
  74. data/docs/index.html +422 -0
  75. data/docs/screenshot.png +0 -0
  76. data/docs/search_index.json +1 -0
  77. data/example/sinatra/Gemfile +6 -0
  78. data/example/sinatra/Gemfile.lock +59 -0
  79. data/example/sinatra/README.md +21 -0
  80. data/example/sinatra/app.rb +18 -0
  81. data/example/sinatra/config.ru +30 -0
  82. data/example/sinatra/ovto/app.rb +171 -0
  83. data/example/sinatra/public/style.css +4 -0
  84. data/example/sinatra/public/todomvc-app-css_index.css +376 -0
  85. data/example/sinatra/public/todomvc-common_base.css +141 -0
  86. data/example/sinatra/views/index.erb +21 -0
  87. data/example/static/Gemfile +3 -0
  88. data/example/static/Gemfile.lock +30 -0
  89. data/example/static/README.md +10 -0
  90. data/example/static/Rakefile +4 -0
  91. data/example/static/app.js +24808 -0
  92. data/example/static/app.rb +43 -0
  93. data/example/static/index.html +11 -0
  94. data/lib/ovto/actions.rb +10 -0
  95. data/lib/ovto/app.rb +58 -0
  96. data/lib/ovto/component.rb +191 -0
  97. data/lib/ovto/fetch.rb +53 -0
  98. data/lib/ovto/runtime.rb +388 -0
  99. data/lib/ovto/state.rb +69 -0
  100. data/lib/ovto/version.rb +3 -0
  101. data/lib/ovto/wired_actions.rb +33 -0
  102. data/lib/ovto.rb +50 -0
  103. data/ovto.gemspec +22 -0
  104. data/screenshot.png +0 -0
  105. metadata +161 -0
@@ -0,0 +1,171 @@
1
+ require 'opal'
2
+ require 'ovto'
3
+
4
+ class TodoApp < Ovto::App
5
+ FILTERS = [:All, :Active, :Completed]
6
+
7
+ class Todo < Ovto::State
8
+ item :id
9
+ item :value
10
+ item :done
11
+
12
+ def self.filter(todos, filter)
13
+ todos.select{|t|
14
+ case filter
15
+ when :Active then !t.done
16
+ when :Completed then t.done
17
+ else true
18
+ end
19
+ }
20
+ end
21
+ end
22
+
23
+ class State < Ovto::State
24
+ item :todos, default: []
25
+ item :filter, default: FILTERS.first
26
+ item :input, default: ""
27
+ end
28
+
29
+ class Actions < Ovto::Actions
30
+ def add_todo(state:)
31
+ new_todo = Todo.new(
32
+ id: state.todos.length + 1,
33
+ value: state.input,
34
+ done: false
35
+ )
36
+ return {
37
+ todos: state.todos + [new_todo],
38
+ input: ""
39
+ }
40
+ end
41
+
42
+ def destroy_todo(state:, id:)
43
+ return {todos: state.todos.reject{|t| t.id == id}}
44
+ end
45
+
46
+ def destroy_completed_todos(state:)
47
+ return {todos: state.todos.reject(&:done)}
48
+ end
49
+
50
+ def toggle_todo(state:, id:)
51
+ new_todos = state.todos.map{|t|
52
+ if t.id == id
53
+ t.merge(done: !t.done)
54
+ else
55
+ t
56
+ end
57
+ }
58
+ return {todos: new_todos}
59
+ end
60
+
61
+ def toggle_all(state:, done:)
62
+ return {todos: state.todos.map{|t| t.merge(done: done)}}
63
+ end
64
+
65
+ def set_input(state:, value:)
66
+ return {input: value}
67
+ end
68
+
69
+ def set_filter(state:, filter:)
70
+ return {filter: filter}
71
+ end
72
+ end
73
+
74
+ class Header < Ovto::Component
75
+ def render(input:)
76
+ o 'header.header' do
77
+ o 'h1', 'todos'
78
+ o 'input.new-todo', {
79
+ placeholder: "What needs to be done?",
80
+ autofocus: true,
81
+ value: input,
82
+ onkeydown: ->(e){ actions.add_todo if e.keyCode == 13 },
83
+ oninput: ->(e){ actions.set_input(value: e.target.value) },
84
+ }
85
+ end
86
+ end
87
+ end
88
+
89
+ class TodoItem < Ovto::Component
90
+ def render(todo:)
91
+ o 'li', {class: todo.done && 'completed'} do
92
+ o 'div.view' do
93
+ o 'input.toggle', {
94
+ type: 'checkbox',
95
+ checked: todo.done,
96
+ onchange: ->(){ actions.toggle_todo(id: todo.id) }
97
+ }
98
+ o 'label', todo.value
99
+ o 'button.destroy', onclick: ->{ actions.destroy_todo(id: todo.id) }
100
+ end
101
+ o 'input.edit', {
102
+ value: todo.value, #TODO
103
+ onblur: ->{ handle_submit },
104
+ onchange: ->{ handle_change },
105
+ onkeydown: ->{ handle_keydown },
106
+ }
107
+ end
108
+ end
109
+ end
110
+
111
+ class Main < Ovto::Component
112
+ def render(todos:, current_filter:)
113
+ o 'section.main' do
114
+ o 'input#toggle-all.toggle-all', {
115
+ type: 'checkbox',
116
+ onchange: ->(e){ actions.toggle_all(done: e.target.checked) },
117
+ checked: todos.all?(&:done)
118
+ }
119
+ o 'label', {for: 'toggle-all'}, 'Mark all as complete'
120
+ o 'ul.todo-list' do
121
+ Todo.filter(todos, current_filter).each do |todo|
122
+ o TodoItem, key: todo.id, todo: todo
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ class Footer < Ovto::Component
130
+ def render(left_count:, current_filter:)
131
+ o 'footer.footer' do
132
+ o 'span.todo-count' do
133
+ o 'strong', left_count
134
+ o 'text', ' item(s) left'
135
+ end
136
+
137
+ o 'ul.filters' do
138
+ FILTERS.each do |filter|
139
+ o 'li' do
140
+ o 'a', {
141
+ href: '#/',
142
+ class: ('selected' if current_filter == filter),
143
+ onclick: ->(){ actions.set_filter(filter: filter) }
144
+ }, filter
145
+ end
146
+ end
147
+ end
148
+ o 'button.clear-completed', {
149
+ onclick: ->(){ actions.destroy_completed_todos },
150
+ }, 'Clear completed'
151
+ end
152
+ end
153
+ end
154
+
155
+ class View < Ovto::Component
156
+ def render(state:)
157
+ o 'section.todoapp' do
158
+ o Header,
159
+ input: state.input
160
+ o Main,
161
+ todos: state.todos,
162
+ current_filter: state.filter
163
+ o Footer,
164
+ left_count: state.todos.count{|t| !t.done},
165
+ current_filter: state.filter
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ TodoApp.run(id: 'ovto-view')
@@ -0,0 +1,4 @@
1
+ li.done {
2
+ text-decoration: line-through;
3
+ color: gray;
4
+ }
@@ -0,0 +1,376 @@
1
+ html,
2
+ body {
3
+ margin: 0;
4
+ padding: 0;
5
+ }
6
+
7
+ button {
8
+ margin: 0;
9
+ padding: 0;
10
+ border: 0;
11
+ background: none;
12
+ font-size: 100%;
13
+ vertical-align: baseline;
14
+ font-family: inherit;
15
+ font-weight: inherit;
16
+ color: inherit;
17
+ -webkit-appearance: none;
18
+ appearance: none;
19
+ -webkit-font-smoothing: antialiased;
20
+ -moz-osx-font-smoothing: grayscale;
21
+ }
22
+
23
+ body {
24
+ font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
25
+ line-height: 1.4em;
26
+ background: #f5f5f5;
27
+ color: #4d4d4d;
28
+ min-width: 230px;
29
+ max-width: 550px;
30
+ margin: 0 auto;
31
+ -webkit-font-smoothing: antialiased;
32
+ -moz-osx-font-smoothing: grayscale;
33
+ font-weight: 300;
34
+ }
35
+
36
+ :focus {
37
+ outline: 0;
38
+ }
39
+
40
+ .hidden {
41
+ display: none;
42
+ }
43
+
44
+ .todoapp {
45
+ background: #fff;
46
+ margin: 130px 0 40px 0;
47
+ position: relative;
48
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
49
+ 0 25px 50px 0 rgba(0, 0, 0, 0.1);
50
+ }
51
+
52
+ .todoapp input::-webkit-input-placeholder {
53
+ font-style: italic;
54
+ font-weight: 300;
55
+ color: #e6e6e6;
56
+ }
57
+
58
+ .todoapp input::-moz-placeholder {
59
+ font-style: italic;
60
+ font-weight: 300;
61
+ color: #e6e6e6;
62
+ }
63
+
64
+ .todoapp input::input-placeholder {
65
+ font-style: italic;
66
+ font-weight: 300;
67
+ color: #e6e6e6;
68
+ }
69
+
70
+ .todoapp h1 {
71
+ position: absolute;
72
+ top: -155px;
73
+ width: 100%;
74
+ font-size: 100px;
75
+ font-weight: 100;
76
+ text-align: center;
77
+ color: rgba(175, 47, 47, 0.15);
78
+ -webkit-text-rendering: optimizeLegibility;
79
+ -moz-text-rendering: optimizeLegibility;
80
+ text-rendering: optimizeLegibility;
81
+ }
82
+
83
+ .new-todo,
84
+ .edit {
85
+ position: relative;
86
+ margin: 0;
87
+ width: 100%;
88
+ font-size: 24px;
89
+ font-family: inherit;
90
+ font-weight: inherit;
91
+ line-height: 1.4em;
92
+ border: 0;
93
+ color: inherit;
94
+ padding: 6px;
95
+ border: 1px solid #999;
96
+ box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
97
+ box-sizing: border-box;
98
+ -webkit-font-smoothing: antialiased;
99
+ -moz-osx-font-smoothing: grayscale;
100
+ }
101
+
102
+ .new-todo {
103
+ padding: 16px 16px 16px 60px;
104
+ border: none;
105
+ background: rgba(0, 0, 0, 0.003);
106
+ box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
107
+ }
108
+
109
+ .main {
110
+ position: relative;
111
+ z-index: 2;
112
+ border-top: 1px solid #e6e6e6;
113
+ }
114
+
115
+ .toggle-all {
116
+ text-align: center;
117
+ border: none; /* Mobile Safari */
118
+ opacity: 0;
119
+ position: absolute;
120
+ }
121
+
122
+ .toggle-all + label {
123
+ width: 60px;
124
+ height: 34px;
125
+ font-size: 0;
126
+ position: absolute;
127
+ top: -52px;
128
+ left: -13px;
129
+ -webkit-transform: rotate(90deg);
130
+ transform: rotate(90deg);
131
+ }
132
+
133
+ .toggle-all + label:before {
134
+ content: '❯';
135
+ font-size: 22px;
136
+ color: #e6e6e6;
137
+ padding: 10px 27px 10px 27px;
138
+ }
139
+
140
+ .toggle-all:checked + label:before {
141
+ color: #737373;
142
+ }
143
+
144
+ .todo-list {
145
+ margin: 0;
146
+ padding: 0;
147
+ list-style: none;
148
+ }
149
+
150
+ .todo-list li {
151
+ position: relative;
152
+ font-size: 24px;
153
+ border-bottom: 1px solid #ededed;
154
+ }
155
+
156
+ .todo-list li:last-child {
157
+ border-bottom: none;
158
+ }
159
+
160
+ .todo-list li.editing {
161
+ border-bottom: none;
162
+ padding: 0;
163
+ }
164
+
165
+ .todo-list li.editing .edit {
166
+ display: block;
167
+ width: 506px;
168
+ padding: 12px 16px;
169
+ margin: 0 0 0 43px;
170
+ }
171
+
172
+ .todo-list li.editing .view {
173
+ display: none;
174
+ }
175
+
176
+ .todo-list li .toggle {
177
+ text-align: center;
178
+ width: 40px;
179
+ /* auto, since non-WebKit browsers doesn't support input styling */
180
+ height: auto;
181
+ position: absolute;
182
+ top: 0;
183
+ bottom: 0;
184
+ margin: auto 0;
185
+ border: none; /* Mobile Safari */
186
+ -webkit-appearance: none;
187
+ appearance: none;
188
+ }
189
+
190
+ .todo-list li .toggle {
191
+ opacity: 0;
192
+ }
193
+
194
+ .todo-list li .toggle + label {
195
+ /*
196
+ Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
197
+ IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
198
+ */
199
+ 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%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
200
+ background-repeat: no-repeat;
201
+ background-position: center left;
202
+ }
203
+
204
+ .todo-list li .toggle:checked + label {
205
+ 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%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
206
+ }
207
+
208
+ .todo-list li label {
209
+ word-break: break-all;
210
+ padding: 15px 15px 15px 60px;
211
+ display: block;
212
+ line-height: 1.2;
213
+ transition: color 0.4s;
214
+ }
215
+
216
+ .todo-list li.completed label {
217
+ color: #d9d9d9;
218
+ text-decoration: line-through;
219
+ }
220
+
221
+ .todo-list li .destroy {
222
+ display: none;
223
+ position: absolute;
224
+ top: 0;
225
+ right: 10px;
226
+ bottom: 0;
227
+ width: 40px;
228
+ height: 40px;
229
+ margin: auto 0;
230
+ font-size: 30px;
231
+ color: #cc9a9a;
232
+ margin-bottom: 11px;
233
+ transition: color 0.2s ease-out;
234
+ }
235
+
236
+ .todo-list li .destroy:hover {
237
+ color: #af5b5e;
238
+ }
239
+
240
+ .todo-list li .destroy:after {
241
+ content: '×';
242
+ }
243
+
244
+ .todo-list li:hover .destroy {
245
+ display: block;
246
+ }
247
+
248
+ .todo-list li .edit {
249
+ display: none;
250
+ }
251
+
252
+ .todo-list li.editing:last-child {
253
+ margin-bottom: -1px;
254
+ }
255
+
256
+ .footer {
257
+ color: #777;
258
+ padding: 10px 15px;
259
+ height: 20px;
260
+ text-align: center;
261
+ border-top: 1px solid #e6e6e6;
262
+ }
263
+
264
+ .footer:before {
265
+ content: '';
266
+ position: absolute;
267
+ right: 0;
268
+ bottom: 0;
269
+ left: 0;
270
+ height: 50px;
271
+ overflow: hidden;
272
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
273
+ 0 8px 0 -3px #f6f6f6,
274
+ 0 9px 1px -3px rgba(0, 0, 0, 0.2),
275
+ 0 16px 0 -6px #f6f6f6,
276
+ 0 17px 2px -6px rgba(0, 0, 0, 0.2);
277
+ }
278
+
279
+ .todo-count {
280
+ float: left;
281
+ text-align: left;
282
+ }
283
+
284
+ .todo-count strong {
285
+ font-weight: 300;
286
+ }
287
+
288
+ .filters {
289
+ margin: 0;
290
+ padding: 0;
291
+ list-style: none;
292
+ position: absolute;
293
+ right: 0;
294
+ left: 0;
295
+ }
296
+
297
+ .filters li {
298
+ display: inline;
299
+ }
300
+
301
+ .filters li a {
302
+ color: inherit;
303
+ margin: 3px;
304
+ padding: 3px 7px;
305
+ text-decoration: none;
306
+ border: 1px solid transparent;
307
+ border-radius: 3px;
308
+ }
309
+
310
+ .filters li a:hover {
311
+ border-color: rgba(175, 47, 47, 0.1);
312
+ }
313
+
314
+ .filters li a.selected {
315
+ border-color: rgba(175, 47, 47, 0.2);
316
+ }
317
+
318
+ .clear-completed,
319
+ html .clear-completed:active {
320
+ float: right;
321
+ position: relative;
322
+ line-height: 20px;
323
+ text-decoration: none;
324
+ cursor: pointer;
325
+ }
326
+
327
+ .clear-completed:hover {
328
+ text-decoration: underline;
329
+ }
330
+
331
+ .info {
332
+ margin: 65px auto 0;
333
+ color: #bfbfbf;
334
+ font-size: 10px;
335
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
336
+ text-align: center;
337
+ }
338
+
339
+ .info p {
340
+ line-height: 1;
341
+ }
342
+
343
+ .info a {
344
+ color: inherit;
345
+ text-decoration: none;
346
+ font-weight: 400;
347
+ }
348
+
349
+ .info a:hover {
350
+ text-decoration: underline;
351
+ }
352
+
353
+ /*
354
+ Hack to remove background from Mobile Safari.
355
+ Can't use it globally since it destroys checkboxes in Firefox
356
+ */
357
+ @media screen and (-webkit-min-device-pixel-ratio:0) {
358
+ .toggle-all,
359
+ .todo-list li .toggle {
360
+ background: none;
361
+ }
362
+
363
+ .todo-list li .toggle {
364
+ height: 40px;
365
+ }
366
+ }
367
+
368
+ @media (max-width: 430px) {
369
+ .footer {
370
+ height: 50px;
371
+ }
372
+
373
+ .filters {
374
+ bottom: 10px;
375
+ }
376
+ }
@@ -0,0 +1,141 @@
1
+ hr {
2
+ margin: 20px 0;
3
+ border: 0;
4
+ border-top: 1px dashed #c5c5c5;
5
+ border-bottom: 1px dashed #f7f7f7;
6
+ }
7
+
8
+ .learn a {
9
+ font-weight: normal;
10
+ text-decoration: none;
11
+ color: #b83f45;
12
+ }
13
+
14
+ .learn a:hover {
15
+ text-decoration: underline;
16
+ color: #787e7e;
17
+ }
18
+
19
+ .learn h3,
20
+ .learn h4,
21
+ .learn h5 {
22
+ margin: 10px 0;
23
+ font-weight: 500;
24
+ line-height: 1.2;
25
+ color: #000;
26
+ }
27
+
28
+ .learn h3 {
29
+ font-size: 24px;
30
+ }
31
+
32
+ .learn h4 {
33
+ font-size: 18px;
34
+ }
35
+
36
+ .learn h5 {
37
+ margin-bottom: 0;
38
+ font-size: 14px;
39
+ }
40
+
41
+ .learn ul {
42
+ padding: 0;
43
+ margin: 0 0 30px 25px;
44
+ }
45
+
46
+ .learn li {
47
+ line-height: 20px;
48
+ }
49
+
50
+ .learn p {
51
+ font-size: 15px;
52
+ font-weight: 300;
53
+ line-height: 1.3;
54
+ margin-top: 0;
55
+ margin-bottom: 0;
56
+ }
57
+
58
+ #issue-count {
59
+ display: none;
60
+ }
61
+
62
+ .quote {
63
+ border: none;
64
+ margin: 20px 0 60px 0;
65
+ }
66
+
67
+ .quote p {
68
+ font-style: italic;
69
+ }
70
+
71
+ .quote p:before {
72
+ content: '“';
73
+ font-size: 50px;
74
+ opacity: .15;
75
+ position: absolute;
76
+ top: -20px;
77
+ left: 3px;
78
+ }
79
+
80
+ .quote p:after {
81
+ content: '”';
82
+ font-size: 50px;
83
+ opacity: .15;
84
+ position: absolute;
85
+ bottom: -42px;
86
+ right: 3px;
87
+ }
88
+
89
+ .quote footer {
90
+ position: absolute;
91
+ bottom: -40px;
92
+ right: 0;
93
+ }
94
+
95
+ .quote footer img {
96
+ border-radius: 3px;
97
+ }
98
+
99
+ .quote footer a {
100
+ margin-left: 5px;
101
+ vertical-align: middle;
102
+ }
103
+
104
+ .speech-bubble {
105
+ position: relative;
106
+ padding: 10px;
107
+ background: rgba(0, 0, 0, .04);
108
+ border-radius: 5px;
109
+ }
110
+
111
+ .speech-bubble:after {
112
+ content: '';
113
+ position: absolute;
114
+ top: 100%;
115
+ right: 30px;
116
+ border: 13px solid transparent;
117
+ border-top-color: rgba(0, 0, 0, .04);
118
+ }
119
+
120
+ .learn-bar > .learn {
121
+ position: absolute;
122
+ width: 272px;
123
+ top: 8px;
124
+ left: -300px;
125
+ padding: 10px;
126
+ border-radius: 5px;
127
+ background-color: rgba(255, 255, 255, .6);
128
+ transition-property: left;
129
+ transition-duration: 500ms;
130
+ }
131
+
132
+ @media (min-width: 899px) {
133
+ .learn-bar {
134
+ width: auto;
135
+ padding-left: 300px;
136
+ }
137
+
138
+ .learn-bar > .learn {
139
+ left: 8px;
140
+ }
141
+ }
@@ -0,0 +1,21 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset= "utf-8" />
5
+ <title>Ovto demo app</title>
6
+ <%= @js_tag %>
7
+ <link rel="stylesheet" href="/style.css" type="text/css" media="screen" />
8
+ <link rel="stylesheet" href="/todomvc-app-css_index.css" type="text/css" media="screen" />
9
+ <link rel="stylesheet" href="/todomvc-common_base.css" type="text/css" media="screen" />
10
+ </head>
11
+
12
+ <body>
13
+ <section id='ovto-view'></section>
14
+ <footer class="info">
15
+ <p>Double-click to edit a todo</p>
16
+ <p>Created by <a href="http://github.com/yhara/">yhara</a></p>
17
+ <p><a href="http://todomvc.com">TodoMVC</a></p>
18
+ </footer>
19
+ <div id='ovto-debug'></div>
20
+ </body>
21
+ </html>
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+ gem "ovto", path: '../../'
3
+ gem 'rake'