tramway 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +46 -0
- data/app/components/tailwind_component.rb +2 -2
- data/app/components/tailwinds/form/builder.rb +27 -6
- data/app/components/tailwinds/form/file_field_component.html.haml +1 -1
- data/app/components/tailwinds/form/file_field_component.rb +1 -0
- data/app/components/tailwinds/form/select_component.html.haml +1 -1
- data/app/components/tailwinds/form/text_field_component.html.haml +1 -1
- data/app/views/kaminari/_first_page.html.haml +9 -0
- data/app/views/kaminari/_gap.html.haml +8 -0
- data/app/views/kaminari/_last_page.html.haml +9 -0
- data/app/views/kaminari/_next_page.html.haml +9 -0
- data/app/views/kaminari/_page.html.haml +14 -0
- data/app/views/kaminari/_paginator.html.haml +12 -0
- data/app/views/kaminari/_prev_page.html.haml +9 -0
- data/lib/tramway/base_form.rb +27 -8
- data/lib/tramway/config.rb +8 -8
- data/lib/tramway/engine.rb +36 -0
- data/lib/tramway/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dee256141e588202061885354d7669ee2a5bb1ce99a57a709129031002ab13c8
|
4
|
+
data.tar.gz: 36b036fc2890c2710a12684f78ea36f9a2d8ae7e5f11f252973d81ae905f9e3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8ee38fd18865625ffdb1c9671cedbba4c780d001b47743f3b0be3657e525eb0d96c84529a9023dc6a68acc6507df1646ca712f4c26dd47df8caadc174c66aa3
|
7
|
+
data.tar.gz: 453471063d91beecf588b590008b37546a36b035fed4065499b87f4ef6182ea8fd2a551fcc124f88f1ee07a1ec4df501bfbbafa607a03ea05d1ca28925f5f7c9
|
data/README.md
CHANGED
@@ -8,6 +8,7 @@ Unite Ruby on Rails brilliance. Streamline development with Tramway.
|
|
8
8
|
* [Tramway Form](https://github.com/Purple-Magic/tramway#tramway-form)
|
9
9
|
* [Tramway Navbar](https://github.com/Purple-Magic/tramway#tramway-navbar)
|
10
10
|
* [Tailwind-styled forms](https://github.com/Purple-Magic/tramway#tailwind-styled-forms)
|
11
|
+
* [Tailwind-styled pagination](https://github.com/Purple-Magic/tramway#tailwind-styled-pagination)
|
11
12
|
|
12
13
|
## Installation
|
13
14
|
Add this line to your application's Gemfile:
|
@@ -248,6 +249,24 @@ class Admin::UsersController < Admin::ApplicationController
|
|
248
249
|
end
|
249
250
|
```
|
250
251
|
|
252
|
+
### Form inheritance
|
253
|
+
|
254
|
+
Tramway Form supports inheritance of `properties`
|
255
|
+
|
256
|
+
**Example**
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
class UserForm < TramwayForm
|
260
|
+
properties :email, :password
|
261
|
+
end
|
262
|
+
|
263
|
+
class AdminForm < UserForm
|
264
|
+
properties :permissions
|
265
|
+
end
|
266
|
+
|
267
|
+
AdminForm.properties # returns [:email, :password, :permissions]
|
268
|
+
```
|
269
|
+
|
251
270
|
### Make flexible and extendable forms
|
252
271
|
|
253
272
|
Tramway Form properties are not mapped to a model. You're able to make extended forms.
|
@@ -362,6 +381,32 @@ Available form helpers:
|
|
362
381
|
* select
|
363
382
|
* submit
|
364
383
|
|
384
|
+
### Tailwind-styled pagination for Kaminari
|
385
|
+
|
386
|
+
Tramway uses [Tailwind](https://tailwindcss.com/) by default. It has tailwind-styled pagination for [kaminari](https://github.com/kaminari/kaminari).
|
387
|
+
|
388
|
+
#### How to use
|
389
|
+
|
390
|
+
*Gemfile*
|
391
|
+
```ruby
|
392
|
+
gem 'tramway'
|
393
|
+
gem 'kaminari'
|
394
|
+
```
|
395
|
+
|
396
|
+
*config/initializers/tramway.rb*
|
397
|
+
```ruby
|
398
|
+
Tramway.configure do |config|
|
399
|
+
config.pagination = { enabled: true } # enabled is false by default
|
400
|
+
end
|
401
|
+
```
|
402
|
+
|
403
|
+
*app/views/users/index.html.haml*
|
404
|
+
```haml
|
405
|
+
= paginate @users # it will render tailwind-styled pagination buttons by default
|
406
|
+
```
|
407
|
+
|
408
|
+
Pagination buttons looks like [this](https://play.tailwindcss.com/mqgDS5l9oY)
|
409
|
+
|
365
410
|
## Contributing
|
366
411
|
|
367
412
|
Install [lefthook](https://github.com/evilmartians/lefthook)
|
@@ -369,6 +414,7 @@ Install [lefthook](https://github.com/evilmartians/lefthook)
|
|
369
414
|
```
|
370
415
|
bundle
|
371
416
|
lefthook install
|
417
|
+
rspec
|
372
418
|
```
|
373
419
|
|
374
420
|
## License
|
@@ -6,9 +6,9 @@ require 'view_component'
|
|
6
6
|
class TailwindComponent < ViewComponent::Base
|
7
7
|
extend Dry::Initializer[undefined: false]
|
8
8
|
|
9
|
-
option :
|
9
|
+
option :input
|
10
10
|
option :attribute
|
11
|
-
option :
|
11
|
+
option :value, optional: true
|
12
12
|
option :options
|
13
13
|
option :label
|
14
14
|
option :for
|
@@ -6,19 +6,33 @@ module Tailwinds
|
|
6
6
|
# :reek:InstanceVariableAssumption
|
7
7
|
class Builder < Tramway::Views::FormBuilder
|
8
8
|
def text_field(attribute, **options, &)
|
9
|
-
render(Tailwinds::Form::TextFieldComponent.new(
|
9
|
+
render(Tailwinds::Form::TextFieldComponent.new(
|
10
|
+
input: input(:text_field),
|
11
|
+
value: get_value(attribute, options),
|
12
|
+
**default_options(attribute, options)
|
13
|
+
), &)
|
10
14
|
end
|
11
15
|
|
12
16
|
def password_field(attribute, **options, &)
|
13
|
-
render(Tailwinds::Form::TextFieldComponent.new(
|
17
|
+
render(Tailwinds::Form::TextFieldComponent.new(
|
18
|
+
input: input(:password_field),
|
19
|
+
**default_options(attribute, options)
|
20
|
+
), &)
|
14
21
|
end
|
15
22
|
|
16
23
|
def file_field(attribute, **options, &)
|
17
|
-
|
24
|
+
input = super(attribute, **options.merge(class: :hidden))
|
25
|
+
|
26
|
+
render(Tailwinds::Form::FileFieldComponent.new(input:, **default_options(attribute, options)), &)
|
18
27
|
end
|
19
28
|
|
20
29
|
def select(attribute, collection, **options, &)
|
21
|
-
render(Tailwinds::Form::SelectComponent.new(
|
30
|
+
render(Tailwinds::Form::SelectComponent.new(
|
31
|
+
input: input(:select),
|
32
|
+
value: options[:selected] || object.public_send(attribute),
|
33
|
+
collection:,
|
34
|
+
**default_options(attribute, options)
|
35
|
+
), &)
|
22
36
|
end
|
23
37
|
|
24
38
|
def submit(action, **options, &)
|
@@ -27,11 +41,18 @@ module Tailwinds
|
|
27
41
|
|
28
42
|
private
|
29
43
|
|
44
|
+
def input(method_name)
|
45
|
+
unbound_method = self.class.superclass.instance_method(method_name)
|
46
|
+
unbound_method.bind(self)
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_value(attribute, options)
|
50
|
+
options[:value] || object.public_send(attribute)
|
51
|
+
end
|
52
|
+
|
30
53
|
def default_options(attribute, options)
|
31
54
|
{
|
32
|
-
template: @template,
|
33
55
|
attribute:,
|
34
|
-
object_name:,
|
35
56
|
label: label(attribute, options),
|
36
57
|
for: for_id(attribute),
|
37
58
|
options:
|
@@ -1,4 +1,4 @@
|
|
1
1
|
.mb-4
|
2
2
|
%label.block.text-gray-700.text-sm.font-bold.mb-2{ for: @for }
|
3
3
|
= @label
|
4
|
-
= @
|
4
|
+
= @input.call(@attribute, @collection, { selected: @value }, @options.merge(class: 'bg-white border border-gray-300 text-gray-700 py-2 px-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent'))
|
@@ -1,4 +1,4 @@
|
|
1
1
|
.mb-4
|
2
2
|
%label.block.text-gray-700.text-sm.font-bold.mb-2{ for: @for }
|
3
3
|
= @label
|
4
|
-
= @
|
4
|
+
= @input.call @attribute, **@options.merge(class: 'w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:border-red-500'), value: @value
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-# Link to the "First" page
|
2
|
+
-# available local variables
|
3
|
+
-# url: url to the first page
|
4
|
+
-# current_page: a page object for the currently displayed page
|
5
|
+
-# total_pages: total number of pages
|
6
|
+
-# per_page: number of items to fetch per page
|
7
|
+
-# remote: data-remote
|
8
|
+
%span.first{ class: 'px-3 py-2 text-sm font-medium text-purple-700 bg-white rounded-md hover:bg-purple-100' }
|
9
|
+
= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote
|
@@ -0,0 +1,8 @@
|
|
1
|
+
-# Non-link tag that stands for skipped pages...
|
2
|
+
-# available local variables
|
3
|
+
-# current_page: a page object for the currently displayed page
|
4
|
+
-# total_pages: total number of pages
|
5
|
+
-# per_page: number of items to fetch per page
|
6
|
+
-# remote: data-remote
|
7
|
+
%span.page.gap{ class: 'px-3 py-2 text-sm font-medium text-purple-700' }
|
8
|
+
= t('views.pagination.truncate').html_safe
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-# Link to the "Last" page
|
2
|
+
-# available local variables
|
3
|
+
-# url: url to the last page
|
4
|
+
-# current_page: a page object for the currently displayed page
|
5
|
+
-# total_pages: total number of pages
|
6
|
+
-# per_page: number of items to fetch per page
|
7
|
+
-# remote: data-remote
|
8
|
+
%span.last{ class: 'px-3 py-2 text-sm font-medium text-purple-700 bg-white rounded-md hover:bg-purple-100' }
|
9
|
+
= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-# Link to the "Next" page
|
2
|
+
-# available local variables
|
3
|
+
-# url: url to the next page
|
4
|
+
-# current_page: a page object for the currently displayed page
|
5
|
+
-# total_pages: total number of pages
|
6
|
+
-# per_page: number of items to fetch per page
|
7
|
+
-# remote: data-remote
|
8
|
+
%span.next{ class: 'px-3 py-2 text-sm font-medium text-purple-700 bg-white rounded-md hover:bg-purple-100' }
|
9
|
+
= link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote
|
@@ -0,0 +1,14 @@
|
|
1
|
+
-# Link showing page number
|
2
|
+
-# available local variables
|
3
|
+
-# page: a page object for "this" page
|
4
|
+
-# url: url to this page
|
5
|
+
-# current_page: a page object for the currently displayed page
|
6
|
+
-# total_pages: total number of pages
|
7
|
+
-# per_page: number of items to fetch per page
|
8
|
+
-# remote: data-remote
|
9
|
+
- if page.current?
|
10
|
+
%span{class: "px-3 py-2 font-medium rounded-md bg-purple-500 text-white" }
|
11
|
+
= page
|
12
|
+
- else
|
13
|
+
%span{class: "cursor px-3 py-2 font-medium text-purple-700 bg-white rounded-md hover:bg-purple-100"}
|
14
|
+
= link_to_unless page.current?, page, url, {remote: remote, rel: page.rel}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
= paginator.render do
|
2
|
+
%nav.pagination.flex.items-center.justify-center.space-x-1
|
3
|
+
= first_page_tag unless current_page.first?
|
4
|
+
= prev_page_tag unless current_page.first?
|
5
|
+
- each_page do |page|
|
6
|
+
- if page.display_tag?
|
7
|
+
= page_tag page
|
8
|
+
- elsif !page.was_truncated?
|
9
|
+
= gap_tag
|
10
|
+
= next_page_tag unless current_page.last?
|
11
|
+
= last_page_tag unless current_page.last?
|
12
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-# Link to the "Previous" page
|
2
|
+
-# available local variables
|
3
|
+
-# url: url to the previous page
|
4
|
+
-# current_page: a page object for the currently displayed page
|
5
|
+
-# total_pages: total number of pages
|
6
|
+
-# per_page: number of items to fetch per page
|
7
|
+
-# remote: data-remote
|
8
|
+
%span.prev{ class: 'px-3 py-2 text-sm font-medium text-purple-700 bg-white rounded-md hover:bg-purple-100' }
|
9
|
+
= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote
|
data/lib/tramway/base_form.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :reek:ClassVariable { enabled: false }
|
3
4
|
module Tramway
|
4
5
|
# Provides form object for Tramway
|
5
6
|
#
|
@@ -17,22 +18,40 @@ module Tramway
|
|
17
18
|
end
|
18
19
|
|
19
20
|
class << self
|
20
|
-
def
|
21
|
-
|
21
|
+
def inherited(subclass)
|
22
|
+
subclass.instance_variable_set(:@properties, [])
|
23
|
+
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def property(attribute)
|
22
28
|
@properties << attribute
|
23
29
|
|
24
30
|
delegate attribute, to: :object
|
25
31
|
end
|
26
32
|
|
27
33
|
def properties(*attributes)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
+
attributes.any? ? __set_properties(attributes) : __properties
|
35
|
+
end
|
36
|
+
|
37
|
+
def __set_properties(attributes)
|
38
|
+
attributes.each do |attribute|
|
39
|
+
property(attribute)
|
34
40
|
end
|
35
41
|
end
|
42
|
+
|
43
|
+
def __properties
|
44
|
+
(__ancestor_properties + @properties).uniq
|
45
|
+
end
|
46
|
+
|
47
|
+
# :reek:ManualDispatch { enabled: false }
|
48
|
+
def __ancestor_properties(klass = superclass)
|
49
|
+
superklass = klass.superclass
|
50
|
+
|
51
|
+
return [] unless superklass.respond_to?(:properties)
|
52
|
+
|
53
|
+
klass.properties + __ancestor_properties(superklass)
|
54
|
+
end
|
36
55
|
end
|
37
56
|
|
38
57
|
def submit(params)
|
data/lib/tramway/config.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'anyway'
|
3
4
|
require 'singleton'
|
4
5
|
require 'tramway/configs/entity'
|
5
6
|
|
6
7
|
module Tramway
|
7
8
|
# Basic configuration of Tramway
|
8
9
|
#
|
9
|
-
class Config
|
10
|
+
class Config < Anyway::Config
|
10
11
|
include Singleton
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
attr_config(
|
14
|
+
pagination: { enabled: false },
|
15
|
+
entities: []
|
16
|
+
)
|
15
17
|
|
16
18
|
def entities=(collection)
|
17
|
-
|
19
|
+
super(collection.map do |entity|
|
18
20
|
entity_options = entity.is_a?(Hash) ? entity : { name: entity }
|
19
21
|
|
20
22
|
Tramway::Configs::Entity.new(**entity_options)
|
21
|
-
end
|
23
|
+
end)
|
22
24
|
end
|
23
|
-
|
24
|
-
attr_reader :entities
|
25
25
|
end
|
26
26
|
end
|
data/lib/tramway/engine.rb
CHANGED
@@ -7,29 +7,65 @@ module Tramway
|
|
7
7
|
isolate_namespace Tramway
|
8
8
|
|
9
9
|
initializer 'tramway.load_helpers' do
|
10
|
+
load_navbar_helper
|
11
|
+
load_views_helper
|
12
|
+
load_decorator_helper
|
13
|
+
load_form_helper
|
14
|
+
configure_pagination if Tramway.config.pagination[:enabled]
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def load_navbar_helper
|
10
20
|
ActiveSupport.on_load(:action_view) do |loaded_class|
|
11
21
|
require 'tramway/helpers/navbar_helper'
|
12
22
|
|
13
23
|
loaded_class.include Tramway::Helpers::NavbarHelper
|
14
24
|
end
|
25
|
+
end
|
15
26
|
|
27
|
+
def load_views_helper
|
16
28
|
ActiveSupport.on_load(:action_view) do |loaded_class|
|
17
29
|
require 'tramway/helpers/views_helper'
|
18
30
|
|
19
31
|
loaded_class.include Tramway::Helpers::ViewsHelper
|
20
32
|
end
|
33
|
+
end
|
21
34
|
|
35
|
+
def load_decorator_helper
|
22
36
|
ActiveSupport.on_load(:action_controller) do |loaded_class|
|
23
37
|
require 'tramway/helpers/decorate_helper'
|
24
38
|
|
25
39
|
loaded_class.include Tramway::Helpers::DecorateHelper
|
26
40
|
end
|
41
|
+
end
|
27
42
|
|
43
|
+
def load_form_helper
|
28
44
|
ActiveSupport.on_load(:action_controller) do |loaded_class|
|
29
45
|
require 'tramway/helpers/form_helper'
|
30
46
|
|
31
47
|
loaded_class.include Tramway::Helpers::FormHelper
|
32
48
|
end
|
33
49
|
end
|
50
|
+
|
51
|
+
# :reek:NestedIterators { enabled: false }
|
52
|
+
# :reek:TooManyStatements { enabled: false }
|
53
|
+
def configure_pagination
|
54
|
+
ActiveSupport.on_load(:action_controller) do
|
55
|
+
# Detecting tramway views path
|
56
|
+
tramway_spec = Gem.loaded_specs['tramway']
|
57
|
+
tramway_views_path = File.join(tramway_spec.full_gem_path, 'app/views')
|
58
|
+
|
59
|
+
paths = view_paths.to_ary
|
60
|
+
|
61
|
+
# Determine index to insert tramway views path
|
62
|
+
rails_views_index = paths.find_index { |path| path.to_s.ends_with?('app/views') }
|
63
|
+
insert_index = rails_views_index ? rails_views_index + 1 : 0
|
64
|
+
|
65
|
+
# Inserting tramway views path
|
66
|
+
paths.insert(insert_index, tramway_views_path)
|
67
|
+
self.view_paths = paths
|
68
|
+
end
|
69
|
+
end
|
34
70
|
end
|
35
71
|
end
|
data/lib/tramway/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tramway
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kalashnikovisme
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-02-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: dry-struct
|
@@ -106,6 +106,13 @@ files:
|
|
106
106
|
- app/components/tailwinds/nav/item_component.rb
|
107
107
|
- app/components/tailwinds/navbar_component.html.haml
|
108
108
|
- app/components/tailwinds/navbar_component.rb
|
109
|
+
- app/views/kaminari/_first_page.html.haml
|
110
|
+
- app/views/kaminari/_gap.html.haml
|
111
|
+
- app/views/kaminari/_last_page.html.haml
|
112
|
+
- app/views/kaminari/_next_page.html.haml
|
113
|
+
- app/views/kaminari/_page.html.haml
|
114
|
+
- app/views/kaminari/_paginator.html.haml
|
115
|
+
- app/views/kaminari/_prev_page.html.haml
|
109
116
|
- config/routes.rb
|
110
117
|
- lib/rules/turbo_html_attributes_rules.rb
|
111
118
|
- lib/tasks/tramway_tasks.rake
|