matestack-ui-vuejs 3.0.0.rc1
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 +7 -0
- data/LICENSE +20 -0
- data/README.md +492 -0
- data/Rakefile +64 -0
- data/lib/matestack/ui/component.rb +1 -0
- data/lib/matestack/ui/isolated_component.rb +1 -0
- data/lib/matestack/ui/vue_js/components/action.js +70 -0
- data/lib/matestack/ui/vue_js/components/action.rb +46 -0
- data/lib/matestack/ui/vue_js/components/app.js +122 -0
- data/lib/matestack/ui/vue_js/components/app.rb +46 -0
- data/lib/matestack/ui/vue_js/components/async.js +104 -0
- data/lib/matestack/ui/vue_js/components/async.rb +84 -0
- data/lib/matestack/ui/vue_js/components/cable.js +96 -0
- data/lib/matestack/ui/vue_js/components/cable.rb +69 -0
- data/lib/matestack/ui/vue_js/components/collection/content.js +96 -0
- data/lib/matestack/ui/vue_js/components/collection/content.rb +32 -0
- data/lib/matestack/ui/vue_js/components/collection/filter.js +45 -0
- data/lib/matestack/ui/vue_js/components/collection/filter.rb +29 -0
- data/lib/matestack/ui/vue_js/components/collection/filter_reset.rb +19 -0
- data/lib/matestack/ui/vue_js/components/collection/helper.rb +128 -0
- data/lib/matestack/ui/vue_js/components/collection/next.rb +19 -0
- data/lib/matestack/ui/vue_js/components/collection/order.js +45 -0
- data/lib/matestack/ui/vue_js/components/collection/order.rb +28 -0
- data/lib/matestack/ui/vue_js/components/collection/order_toggle.rb +21 -0
- data/lib/matestack/ui/vue_js/components/collection/order_toggle_indicator.rb +30 -0
- data/lib/matestack/ui/vue_js/components/collection/page.rb +21 -0
- data/lib/matestack/ui/vue_js/components/collection/previous.rb +19 -0
- data/lib/matestack/ui/vue_js/components/form/base.rb +179 -0
- data/lib/matestack/ui/vue_js/components/form/checkbox.js +13 -0
- data/lib/matestack/ui/vue_js/components/form/checkbox.rb +109 -0
- data/lib/matestack/ui/vue_js/components/form/checkbox_mixin.js +90 -0
- data/lib/matestack/ui/vue_js/components/form/context.rb +15 -0
- data/lib/matestack/ui/vue_js/components/form/fields_for_add_item.js +50 -0
- data/lib/matestack/ui/vue_js/components/form/fields_for_add_item.rb +35 -0
- data/lib/matestack/ui/vue_js/components/form/fields_for_remove_item.rb +19 -0
- data/lib/matestack/ui/vue_js/components/form/form.js +276 -0
- data/lib/matestack/ui/vue_js/components/form/form.rb +77 -0
- data/lib/matestack/ui/vue_js/components/form/input.js +13 -0
- data/lib/matestack/ui/vue_js/components/form/input.rb +54 -0
- data/lib/matestack/ui/vue_js/components/form/input_mixin.js +79 -0
- data/lib/matestack/ui/vue_js/components/form/nested_form.js +153 -0
- data/lib/matestack/ui/vue_js/components/form/nested_form.rb +57 -0
- data/lib/matestack/ui/vue_js/components/form/radio.js +13 -0
- data/lib/matestack/ui/vue_js/components/form/radio.rb +85 -0
- data/lib/matestack/ui/vue_js/components/form/radio_mixin.js +75 -0
- data/lib/matestack/ui/vue_js/components/form/select.js +13 -0
- data/lib/matestack/ui/vue_js/components/form/select.rb +96 -0
- data/lib/matestack/ui/vue_js/components/form/select_mixin.js +76 -0
- data/lib/matestack/ui/vue_js/components/form/textarea.js +13 -0
- data/lib/matestack/ui/vue_js/components/form/textarea.rb +37 -0
- data/lib/matestack/ui/vue_js/components/form/textarea_mixin.js +54 -0
- data/lib/matestack/ui/vue_js/components/helpers.js +5 -0
- data/lib/matestack/ui/vue_js/components/isolated.js +105 -0
- data/lib/matestack/ui/vue_js/components/isolated.rb +86 -0
- data/lib/matestack/ui/vue_js/components/mixin.js +66 -0
- data/lib/matestack/ui/vue_js/components/onclick.js +18 -0
- data/lib/matestack/ui/vue_js/components/onclick.rb +37 -0
- data/lib/matestack/ui/vue_js/components/page_switch.js +24 -0
- data/lib/matestack/ui/vue_js/components/page_switch.rb +35 -0
- data/lib/matestack/ui/vue_js/components/runtime_render.js +17 -0
- data/lib/matestack/ui/vue_js/components/toggle.js +70 -0
- data/lib/matestack/ui/vue_js/components/toggle.rb +38 -0
- data/lib/matestack/ui/vue_js/components/transition.js +44 -0
- data/lib/matestack/ui/vue_js/components/transition.rb +40 -0
- data/lib/matestack/ui/vue_js/components/transition_handling_mixin.js +100 -0
- data/lib/matestack/ui/vue_js/components.rb +118 -0
- data/lib/matestack/ui/vue_js/event_hub.js +12 -0
- data/lib/matestack/ui/vue_js/helpers/query_params_helper.js +56 -0
- data/lib/matestack/ui/vue_js/index.js +94 -0
- data/lib/matestack/ui/vue_js/initialize.rb +10 -0
- data/lib/matestack/ui/vue_js/utils.rb +67 -0
- data/lib/matestack/ui/vue_js/version.rb +7 -0
- data/lib/matestack/ui/vue_js/vue.rb +75 -0
- data/lib/matestack/ui/vue_js/vue_attributes.rb +13 -0
- data/lib/matestack/ui/vue_js.rb +52 -0
- data/lib/matestack/ui/vue_js_component.rb +1 -0
- metadata +150 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c794def649692d36847b14964ae62336f5caef8b6176c54dca0527933f699ef1
|
4
|
+
data.tar.gz: 6e588a4b84523a77133927ea8dd139e21cd8cb4f32fdff7a426613d50cd4d5ef
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fb1e2b903e3a37fe6d99608496d44bf946716ea6562bea64a9a61fd6867b8fe2b380e5732c44a37675d51004bb6f01f4e071a1ea4e410a6750f003b825683d20
|
7
|
+
data.tar.gz: 3a0a48ed03ffbb7241acda5908be725f827d859fa0ff83fc886df7841b9cddb35df4aa4521a6d49ef72bec080b415ba27e3f520b2096fb27ca6fab17c84a18b8
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) MateLab GmbH
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,492 @@
|
|
1
|
+
[](https://github.com/matestack/matestack-ui-vuejs/actions)
|
2
|
+
[](https://discord.com/invite/c6tQxFG)
|
3
|
+
[](https://badge.fury.io/rb/matestack-ui-vuejs)
|
4
|
+
[](https://docs.matestack.io)
|
5
|
+
[](https://twitter.com/matestack)
|
6
|
+
|
7
|
+

|
8
|
+
|
9
|
+
# matestack-ui-vuejs | Vue.js 3 based reactivity system for Rails
|
10
|
+
|
11
|
+
Boost your productivity & easily create reactive web UIs in pure Ruby. Easily extend with pure JavaScript if required. No Opal involved.
|
12
|
+
|
13
|
+
## About
|
14
|
+
|
15
|
+
`matestack-ui-vuejs` ships all you need to build **reactive** UIs in **pure Ruby** orchestrating prebuilt Vue.js components with a simple Ruby DSL.
|
16
|
+
|
17
|
+
The prebuilt reactive components built **on top of Vue.js** are covering typical features of a reactive web UI, such as async form submission, dynamic page transitions or async partial UI updates. **No Opal involved**
|
18
|
+
|
19
|
+
If required, it can be easily extended with pure JavaScript.
|
20
|
+
|
21
|
+
### Why matestack-ui-vuejs?
|
22
|
+
|
23
|
+
`matestack-ui-vuejs` was created because modern web app development became more and more complex due to the rise of JavaScript frontend frameworks and the SPA frontend/REST API/JSON backend architecture. This sophisticated approach might be suitable for big teams and applications but is way to complex for most of small to medium sized teams and application scopes.
|
24
|
+
|
25
|
+
In contrast, `matestack-ui-vuejs` helps Rails developers creating modern, reactive web apps while focusing on **simplicity**, **developer happiness** and **productivity**:
|
26
|
+
|
27
|
+
* [x] Use Ruby’s amazing language features while creating your UI
|
28
|
+
* [x] Skip using templating engine syntax and write pure Ruby instead
|
29
|
+
* [x] Reduce the amount of required JavaScript in order to build reactive web UIs
|
30
|
+
* [x] Create a single application, managing the full stack from database to a reactive UI in pure Ruby
|
31
|
+
* [x] **Drastically reduce the complexity of building reactive web applications**
|
32
|
+
|
33
|
+
### What makes matestack-ui-vuejs different?
|
34
|
+
|
35
|
+
[Hotwire](https://hotwire.dev) and [Stimulus Reflex](https://docs.stimulusreflex.com) are awesome gems. They reduce the amount of required JavaScript when implementing reactive web UIs. They allow us to use more Rails and less JavaScript. **Great!**
|
36
|
+
|
37
|
+
Matestack, developed since 2018, goes even one step further: **Use more Ruby and less of everything else** (JavaScript, ERB/HAML/SLIM, CSS).
|
38
|
+
|
39
|
+
**Why?** Because Ruby is just beautiful! More Ruby = More developer happiness = Higher productivity
|
40
|
+
|
41
|
+
Additionally, most of `matestack-ui-vuejs` does not require Action Cable or Redis, but can optionally use the power of these tools.
|
42
|
+
|
43
|
+
## Compatibility
|
44
|
+
|
45
|
+
`matestack-ui-vuejs` requires `matestack-ui-core`
|
46
|
+
|
47
|
+
`matestack-ui-vuejs` is tested against:
|
48
|
+
|
49
|
+
* Rails 7.0.1 + Ruby 3.0.0 + Vue.js 3.2.26
|
50
|
+
* Rails 6.1.1 + Ruby 3.0.0 + Vue.js 3.2.26
|
51
|
+
* Rails 6.1.1 + Ruby 2.7.2 + Vue.js 3.2.26
|
52
|
+
* Rails 6.0.3.4 + Ruby 2.6.6 + Vue.js 3.2.26
|
53
|
+
* Rails 5.2.4.4 + Ruby 2.6.6 + Vue.js 3.2.26
|
54
|
+
|
55
|
+
Rails versions below 5.2 are not officially supported.
|
56
|
+
|
57
|
+
Vue.js 2.x is supported when using the Compat build of Vue.js
|
58
|
+
|
59
|
+
## Documentation/Installation
|
60
|
+
|
61
|
+
Documentation can be found [here](https://docs.matestack.io/matestack-ui-vuejs)
|
62
|
+
|
63
|
+
## Getting started
|
64
|
+
|
65
|
+
A getting started guide can be found [here](https://docs.matestack.io/matestack-ui-vuejs/getting-started/hello-world)
|
66
|
+
|
67
|
+
## Changelog
|
68
|
+
|
69
|
+
Changelog can be found [here](./CHANGELOG.md)
|
70
|
+
|
71
|
+
## Community
|
72
|
+
|
73
|
+
As a low-barrier feedback channel for our early users, we have set up a Discord server that can be found [here](https://discord.com/invite/c6tQxFG). You are very welcome to ask questions and send us feedback there!
|
74
|
+
|
75
|
+
## Contribution
|
76
|
+
|
77
|
+
We are happy to accept contributors of any kind! In order to make it as easy and fun as possible to contribute to `matestack-ui-vuejs`, we would like to onboard contributors personally! Best way to become a contributor: Ping us on Discord! We will schedule a video call with you and show you, how and what to work on :)
|
78
|
+
|
79
|
+
## Feature walk-through
|
80
|
+
|
81
|
+
### 1. Use reactive UI components in pure Ruby
|
82
|
+
|
83
|
+
Matestack's generic, reactive components can be placed on your UI with a simple Ruby DSL. While putting these generic components in your UI code, you inject some configuration in order to adjust the behaviour to your needs. This enables you to create reactive UIs without touching JavaScript!
|
84
|
+
|
85
|
+
*Behind the scenes:* When calling a reactive component with the Ruby DSL, Matestack will render a special component tag with a bunch of attributes to the resulting, server-side rendered HTML. Within the browser, Vue.js will pick up these component tags and mount the JavaScript driven components on it.
|
86
|
+
|
87
|
+
**Toggle parts of the UI based on events**
|
88
|
+
|
89
|
+
`matestack-ui-vuejs` offers an event hub. Reactive components can emit and receive events through this event hub. "onclick" and "toggle" calling two of these reactive core components. "onclick" emits an event which causes the body of the "toggle" component to be visible for 5 seconds in this example.
|
90
|
+
|
91
|
+
`app/matestack/components/some_component.rb`
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
class Components::SomeComponent < Matestack::Ui::Component
|
95
|
+
|
96
|
+
def response
|
97
|
+
onclick emit: "some_event" do
|
98
|
+
button "click me"
|
99
|
+
end
|
100
|
+
toggle show_on: "some_event", hide_after: 5000 do
|
101
|
+
plain "Oh yes! You clicked me!"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
**Call controller actions without JavaScript**
|
109
|
+
|
110
|
+
Core components offer basic dynamic behaviour and let you easily call controller actions and react to server responses on the client side without full page reload. The "action" component is configured to emit an event after successfully performed an HTTP request against a Rails controller action, which is received by the "toggle" component, displaying the success message.
|
111
|
+
|
112
|
+
`app/matestack/components/some_component.rb`
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
class Components::SomeComponent < Matestack::Ui::Component
|
116
|
+
|
117
|
+
def response
|
118
|
+
action my_action_config do
|
119
|
+
button "click me"
|
120
|
+
end
|
121
|
+
toggle show_on: "some_event", hide_after: 5000 do
|
122
|
+
plain "Success!"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def my_action_config
|
127
|
+
{
|
128
|
+
path: some_rails_route_path,
|
129
|
+
method: :post,
|
130
|
+
success: {
|
131
|
+
emit: "some_event"
|
132
|
+
}
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
#### Dynamically handle form input without JavaScript
|
140
|
+
|
141
|
+
Create dynamic forms for ActiveRecord Models (or plain objects) and display server side responses, like validation errors or success messages, without relying on a full page reload. Events emitted by the "form" component can be used to toggle parts of the UI.
|
142
|
+
|
143
|
+
`app/matestack/components/some_component.rb`
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
class Components::SomeComponent < Matestack::Ui::Component
|
147
|
+
|
148
|
+
def response
|
149
|
+
matestack_form my_form_config do
|
150
|
+
form_input key: :some_model_attribute, type: :text
|
151
|
+
button "click me", type: :submit
|
152
|
+
end
|
153
|
+
toggle show_on: "submitted", hide_after: 5000 do
|
154
|
+
span class: "message success" do
|
155
|
+
plain "created successfully"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
toggle show_on: "failed", hide_after: 5000 do
|
159
|
+
span class: "message failure" do
|
160
|
+
plain "data was not saved, please check form"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def my_form_config
|
166
|
+
{
|
167
|
+
for: MyActiveRecordModel.new,
|
168
|
+
path: some_rails_route_path,
|
169
|
+
method: :post,
|
170
|
+
success: {
|
171
|
+
emit: "submitted"
|
172
|
+
},
|
173
|
+
failure: {
|
174
|
+
emit: "failed"
|
175
|
+
}
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
**Implement asynchronous, event-based UI rerendering in pure Ruby**
|
183
|
+
|
184
|
+
Using Matestack's built-in event system, you can rerender parts of the UI on client side events, such as form or action submissions. Even server side events pushed via ActionCable may be received! The "async" component requests a new version of its body at the server via an HTTP GET request after receiving the configured event. After successful server response, the DOM of the "async" component gets updated. Everything else stays untouched.
|
185
|
+
|
186
|
+
`app/matestack/components/some_component.rb`
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
class Components::SomeComponent < Matestack::Ui::Component
|
190
|
+
|
191
|
+
def response
|
192
|
+
matestack_form my_form_config do
|
193
|
+
#...
|
194
|
+
end
|
195
|
+
#...
|
196
|
+
async rerender_on: "submitted", id: "my-model-list" do
|
197
|
+
ul do
|
198
|
+
MyActiveRecordModel.last(5).each do |model|
|
199
|
+
li model.some_attribute
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def my_form_config
|
206
|
+
{
|
207
|
+
#...
|
208
|
+
success: {
|
209
|
+
emit: "submitted"
|
210
|
+
},
|
211
|
+
failure: {
|
212
|
+
emit: "failed"
|
213
|
+
}
|
214
|
+
}
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
```
|
219
|
+
|
220
|
+
**Manipulate parts of the UI via ActionCable**
|
221
|
+
|
222
|
+
"async" rerenders its whole body - but what about just appending the element to the list after successful form submission? The "cable" component can be configured to receive events and data pushed via ActionCable from the server side and just append/prepend new chunks of HTML (ideally rendered through a component) to the current "cable" component body. Updating and deleting is also supported!
|
223
|
+
|
224
|
+
`app/matestack/components/some_component.rb`
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
class Components::SomeComponent < Matestack::Ui::Component
|
228
|
+
|
229
|
+
def response
|
230
|
+
matestack_form my_form_config do
|
231
|
+
#...
|
232
|
+
end
|
233
|
+
#...
|
234
|
+
cable prepend_on: "new_element_created", id: "some-cable-driven-list" do
|
235
|
+
MyActiveRecordModel.last(5).each do |model|
|
236
|
+
Components::SomeListItemComponent.call(content: model.some_content)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
```
|
243
|
+
|
244
|
+
`app/controllers/some_controller.rb`
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
# within your controller action handling the form input
|
248
|
+
ActionCable.server.broadcast("matestack_ui_core", {
|
249
|
+
event: "new_element_created",
|
250
|
+
data: Components::SomeListItemComponent.call(content: model.some_content) # or plain HTML
|
251
|
+
})
|
252
|
+
```
|
253
|
+
|
254
|
+
### **2. Easily extend with Vue.js**
|
255
|
+
|
256
|
+
Matestack's dynamic parts are built on Vue.js. If you want to implement custom dynamic behaviour, you can simply create your own Vue components and use them along Matestack's components. It's even possible to interact with Matestack's components using the built-in event bus.
|
257
|
+
|
258
|
+
`app/matestack/components/some_component.rb`
|
259
|
+
|
260
|
+
```ruby
|
261
|
+
class Components::SomeComponent < Matestack::Ui::Component
|
262
|
+
|
263
|
+
def response
|
264
|
+
Components::MyVueJsComponent.call()
|
265
|
+
toggle show_on: "some_event", hide_after: "3000" do
|
266
|
+
span class: "message success" do
|
267
|
+
plain "event triggered from custom vuejs component"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|
273
|
+
```
|
274
|
+
|
275
|
+
`app/matestack/components/my_vue_js_component.rb`
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
class Components::MyVueJsComponent < Matestack::Ui::VueJsComponent
|
279
|
+
|
280
|
+
vue_name "my-vue-js-component"
|
281
|
+
|
282
|
+
def response
|
283
|
+
div class: "my-vue-js-component" do
|
284
|
+
button "@click": "vc.increaseValue"
|
285
|
+
br
|
286
|
+
plain "{{ vc.dynamicValue }}!"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
```
|
292
|
+
|
293
|
+
`app/matestack/components/my_vue_js_component.js`
|
294
|
+
|
295
|
+
```javascript
|
296
|
+
import MatestackUiVueJs from 'matestack-ui-vuejs'
|
297
|
+
|
298
|
+
const myComponent = {
|
299
|
+
mixins: [MatestackUiVueJs.componentMixin],
|
300
|
+
template: MatestackUiVueJs.componentHelpers.inlineTemplate,
|
301
|
+
data: () => {
|
302
|
+
return {
|
303
|
+
dynamicValue: 0
|
304
|
+
};
|
305
|
+
},
|
306
|
+
methods: {
|
307
|
+
increaseValue(){
|
308
|
+
this.dynamicValue++
|
309
|
+
MatestackUiVueJs.eventHub.$emit("some_event")
|
310
|
+
}
|
311
|
+
}
|
312
|
+
}
|
313
|
+
|
314
|
+
export default myComponent
|
315
|
+
|
316
|
+
// and then in your application pack file you register the component like:
|
317
|
+
|
318
|
+
appInstance.component('my-vue-js-component', myComponent) /
|
319
|
+
```
|
320
|
+
|
321
|
+
### 3. Create whole SPA-like apps in pure Ruby
|
322
|
+
|
323
|
+
The last step in order to leverage the full Matestack power: Create a Matestack layout (\~Rails layout) and Matestack page (Rails \~view) classes (as seen on `matestack-ui-core`) and implement dynamic page transitions with components coming from `matestack-ui-vuejs` without any custom JavaScript implementation required.
|
324
|
+
|
325
|
+
**Create your layouts and views in pure Ruby**
|
326
|
+
|
327
|
+
The layout class is used to define a layout, usually containing some kind of header, footer and navigation. The page class is used to define a view. Following the same principles as seen on components, you can use components (core or your own) in order to create the UI. The `matestack_vue_js_app` `page_switch` and `transition` components enable dynamic page transition, replacing the yielded content with new serverside rendered content rendered by the requested page.
|
328
|
+
|
329
|
+
`app/matestack/some_app/some_layout.rb`
|
330
|
+
|
331
|
+
```ruby
|
332
|
+
class SomeApp::SomeLayout < Matestack::Ui::Layout
|
333
|
+
|
334
|
+
def response
|
335
|
+
h1 "My App"
|
336
|
+
matestack_vue_js_app do
|
337
|
+
nav do
|
338
|
+
transition path: page1_path do
|
339
|
+
button "Page 1"
|
340
|
+
end
|
341
|
+
transition path: page2_path do
|
342
|
+
button "Page 2"
|
343
|
+
end
|
344
|
+
end
|
345
|
+
main do
|
346
|
+
div class: "container" do
|
347
|
+
page_switch do
|
348
|
+
yield
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
end
|
356
|
+
```
|
357
|
+
|
358
|
+
`app/matestack/some_app/pages/page1.rb`
|
359
|
+
|
360
|
+
```ruby
|
361
|
+
class SomeApp::Pages::Page1 < Matestack::Ui::Page
|
362
|
+
|
363
|
+
def response
|
364
|
+
div class: "row" do
|
365
|
+
div class: "col" do
|
366
|
+
plain "Page 1"
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
```
|
373
|
+
|
374
|
+
`app/matestack/some_app/pages/page2.rb`
|
375
|
+
|
376
|
+
```ruby
|
377
|
+
class SomeApp::Pages::Page2 < Matestack::Ui::Page
|
378
|
+
|
379
|
+
def response
|
380
|
+
div class: "row" do
|
381
|
+
div class: "col" do
|
382
|
+
plain "Page 2"
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
388
|
+
```
|
389
|
+
|
390
|
+
**Layouts and pages are referenced in your Rails controllers and actions**
|
391
|
+
|
392
|
+
Instead of referencing Rails layouts and views on your controllers, you just use apps and pages as substitutes. Work with controllers, actions and routing as you're used to! Controller hooks (e.g. devise's authenticate\_user) would still work!
|
393
|
+
|
394
|
+
`app/controllers/some_controller.rb`
|
395
|
+
|
396
|
+
```ruby
|
397
|
+
class SomeController < ApplicationController
|
398
|
+
|
399
|
+
include Matestack::Ui::Core::Helper
|
400
|
+
|
401
|
+
matestack_layout SomeApp::SomeLayout
|
402
|
+
|
403
|
+
def page1
|
404
|
+
render SomeApp::Page1
|
405
|
+
end
|
406
|
+
|
407
|
+
def page2
|
408
|
+
render SomeApp::Page2
|
409
|
+
end
|
410
|
+
|
411
|
+
end
|
412
|
+
```
|
413
|
+
|
414
|
+
`app/config/routes.rb`
|
415
|
+
|
416
|
+
```ruby
|
417
|
+
Rails.application.routes.draw do
|
418
|
+
|
419
|
+
root to: 'some#page1'
|
420
|
+
|
421
|
+
get :page1, to: 'some#page1'
|
422
|
+
get :page2, to: 'some#page2'
|
423
|
+
|
424
|
+
end
|
425
|
+
```
|
426
|
+
|
427
|
+
**Use CSS animations for fancy page transition animations**
|
428
|
+
|
429
|
+
Use Matestack's css classes applied to the wrapping DOM structure of a page in order to add CSS animiations, whenever a page transition is performed. You can even inject a loading state element, enriching your page transition effect.
|
430
|
+
|
431
|
+
`app/matestack/some_app/some_layout.rb`
|
432
|
+
|
433
|
+
```ruby
|
434
|
+
class SomeApp::SomeLayout < Matestack::Ui::Layout
|
435
|
+
|
436
|
+
def response
|
437
|
+
h1 "My App"
|
438
|
+
matestack_vue_js_app do
|
439
|
+
nav do
|
440
|
+
transition path: page1_path do
|
441
|
+
button "Page 1"
|
442
|
+
end
|
443
|
+
transition path: page2_path do
|
444
|
+
button "Page 2"
|
445
|
+
end
|
446
|
+
end
|
447
|
+
main do
|
448
|
+
div class: "container" do
|
449
|
+
page_switch do
|
450
|
+
yield
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
def loading_state_element
|
458
|
+
div class: 'some-loading-element-styles'
|
459
|
+
end
|
460
|
+
|
461
|
+
end
|
462
|
+
```
|
463
|
+
|
464
|
+
`app/assets/stylesheets/application.scss`
|
465
|
+
|
466
|
+
```scss
|
467
|
+
.matestack-page-container{
|
468
|
+
|
469
|
+
.matestack-page-wrapper {
|
470
|
+
opacity: 1;
|
471
|
+
transition: opacity 0.2s ease-in-out;
|
472
|
+
|
473
|
+
&.loading {
|
474
|
+
opacity: 0;
|
475
|
+
}
|
476
|
+
}
|
477
|
+
|
478
|
+
.loading-state-element-wrapper{
|
479
|
+
opacity: 0;
|
480
|
+
transition: opacity 0.3s ease-in-out;
|
481
|
+
|
482
|
+
&.loading {
|
483
|
+
opacity: 1;
|
484
|
+
}
|
485
|
+
}
|
486
|
+
|
487
|
+
}
|
488
|
+
```
|
489
|
+
|
490
|
+
## License
|
491
|
+
|
492
|
+
`matestack-ui-vuejs` is an Open Source project licensed under the terms of the [MIT license](./LICENSE)
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Matestack::Ui::Core'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
load 'rails/tasks/statistics.rake'
|
21
|
+
|
22
|
+
require 'bundler/gem_tasks'
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
# Rake::TestTask.new(:test) do |t|
|
27
|
+
# t.libs << 'test'
|
28
|
+
# t.pattern = 'test/**/*_test.rb'
|
29
|
+
# t.verbose = false
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# task default: :test
|
33
|
+
|
34
|
+
task :webpack => 'webpack:build'
|
35
|
+
|
36
|
+
namespace :webpack do
|
37
|
+
task :build => ['build:development', 'build:production']
|
38
|
+
|
39
|
+
namespace :build do
|
40
|
+
task :development => 'yarn:install' do
|
41
|
+
Bundler.with_unbundled_env do
|
42
|
+
sh "cd builder && bin/webpack"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
task :production => 'yarn:install' do
|
46
|
+
Bundler.with_unbundled_env do
|
47
|
+
sh "cd builder && bin/rake webpacker:compile"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
task :watch => 'yarn:install' do
|
53
|
+
Bundler.with_unbundled_env do
|
54
|
+
sh "cd builder && bin/webpack --watch"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
namespace :yarn do
|
59
|
+
task :install do
|
60
|
+
sh "yarn install && cd builder && yarn install"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
Matestack::Ui::Component = Matestack::Ui::Core::Component
|
@@ -0,0 +1 @@
|
|
1
|
+
Matestack::Ui::IsolatedComponent = Matestack::Ui::VueJs::Components::Isolated
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import { inject } from 'vue'
|
2
|
+
|
3
|
+
import axios from 'axios'
|
4
|
+
import matestackEventHub from '../event_hub'
|
5
|
+
import componentMixin from './mixin'
|
6
|
+
import componentHelpers from './helpers'
|
7
|
+
|
8
|
+
import transitionHandlingMixin from './transition_handling_mixin'
|
9
|
+
|
10
|
+
const componentDef = {
|
11
|
+
mixins: [componentMixin, transitionHandlingMixin],
|
12
|
+
template: componentHelpers.inlineTemplate,
|
13
|
+
data: function(){
|
14
|
+
return {}
|
15
|
+
},
|
16
|
+
setup() {
|
17
|
+
// conditionally inject appNavigateTo
|
18
|
+
// action component has to work in context without wrapping app as well!
|
19
|
+
const appNavigateTo = inject('appNavigateTo', undefined)
|
20
|
+
return {
|
21
|
+
appNavigateTo
|
22
|
+
}
|
23
|
+
},
|
24
|
+
methods: {
|
25
|
+
perform: function(){
|
26
|
+
const self = this
|
27
|
+
if (
|
28
|
+
(self.props["confirm"] == undefined) || confirm(self.props["confirm_text"])
|
29
|
+
)
|
30
|
+
{
|
31
|
+
if (self.props["emit"] != undefined) {
|
32
|
+
matestackEventHub.$emit(self.props["emit"]);
|
33
|
+
}
|
34
|
+
if (self.props["delay"] != undefined) {
|
35
|
+
setTimeout(function () {
|
36
|
+
self.sendRequest()
|
37
|
+
}, parseInt(self.props["delay"]));
|
38
|
+
} else {
|
39
|
+
this.sendRequest()
|
40
|
+
}
|
41
|
+
}
|
42
|
+
},
|
43
|
+
sendRequest: function(){
|
44
|
+
const self = this
|
45
|
+
axios({
|
46
|
+
method: self.props["method"],
|
47
|
+
url: self.props["action_path"],
|
48
|
+
data: self.props["data"],
|
49
|
+
headers: {
|
50
|
+
'X-CSRF-Token': self.getXcsrfToken()
|
51
|
+
}
|
52
|
+
}
|
53
|
+
)
|
54
|
+
.then(function(response){
|
55
|
+
if (self.props["success"] != undefined && self.props["success"]["emit"] != undefined) {
|
56
|
+
matestackEventHub.$emit(self.props["success"]["emit"], response.data);
|
57
|
+
}
|
58
|
+
self.successTransitionHandling(response)
|
59
|
+
})
|
60
|
+
.catch(function(error){
|
61
|
+
if (self.props["failure"] != undefined && self.props["failure"]["emit"] != undefined) {
|
62
|
+
matestackEventHub.$emit(self.props["failure"]["emit"], error.response.data);
|
63
|
+
}
|
64
|
+
self.failureTransitionHandling(error)
|
65
|
+
})
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
export default componentDef
|