tramway 0.3.1.2 → 0.4
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 +45 -1
- data/app/components/tailwind_component.rb +8 -0
- data/app/components/tailwinds/form/builder.rb +45 -7
- data/app/components/tailwinds/form/file_field_component.rb +1 -5
- data/app/components/tailwinds/form/select_component.html.haml +4 -0
- data/app/components/tailwinds/form/select_component.rb +10 -0
- data/app/components/tailwinds/form/text_field_component.html.haml +1 -1
- data/app/components/tailwinds/form/text_field_component.rb +0 -5
- 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 +2 -0
- data/lib/tramway/config.rb +8 -8
- data/lib/tramway/decorators/collection_decorator.rb +1 -1
- data/lib/tramway/engine.rb +36 -0
- data/lib/tramway/version.rb +1 -1
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68a5dd780d7427b0c2075f140c891af3a4c33210c88a00d86e33279dc27e6c28
|
4
|
+
data.tar.gz: 63701d608f5545ea95e98fac522624cc34092199fe839b16ba579d9c461c0383
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e6c295607acc32db6b7a0bea211ddb9ba2d8e2ca141804bce78b7b51fb74a08478c38ead05962f56ecd226a57b2e7398b97c86ac6dcc7aa46c3862bd8a49f30
|
7
|
+
data.tar.gz: bd89050c6d5b3391f457eea7a277cdaaa53c3fbe1f20a0567c39b659ab8a3187d2f161bed38a6b9226782191b884fe94eb63d7e7f8aa292e8ff121dcf149c521
|
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:
|
@@ -81,7 +82,7 @@ class UserDecorator < Tramway::BaseDecorator
|
|
81
82
|
end
|
82
83
|
```
|
83
84
|
|
84
|
-
#### Decorate single object
|
85
|
+
#### Decorate a single object
|
85
86
|
|
86
87
|
You can use the same method to decorate a single object either
|
87
88
|
|
@@ -91,6 +92,20 @@ def show
|
|
91
92
|
end
|
92
93
|
```
|
93
94
|
|
95
|
+
#### Decorate a collection of objects
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
def index
|
99
|
+
@users = tramway_decorate User.all
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
def index
|
105
|
+
@posts = tramway_decorate user.posts
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
94
109
|
#### Decorate with a specific decorator
|
95
110
|
|
96
111
|
You can implement a specific decorator and ask Tramway to decorate with it
|
@@ -334,6 +349,7 @@ Tramway provides `tramway_form_for` helper that renders Tailwind-styled forms by
|
|
334
349
|
= tramway_form_for User.new do |f|
|
335
350
|
= f.text_field :text
|
336
351
|
= f.password_field :password
|
352
|
+
= f.select :role, [:admin, :user]
|
337
353
|
= f.file_field :file
|
338
354
|
= f.submit "Create User"
|
339
355
|
```
|
@@ -344,8 +360,35 @@ Available form helpers:
|
|
344
360
|
* text_field
|
345
361
|
* password_field
|
346
362
|
* file_field
|
363
|
+
* select
|
347
364
|
* submit
|
348
365
|
|
366
|
+
### Tailwind-styled pagination for Kaminari
|
367
|
+
|
368
|
+
Tramway uses [Tailwind](https://tailwindcss.com/) by default. It has tailwind-styled pagination for [kaminari](https://github.com/kaminari/kaminari).
|
369
|
+
|
370
|
+
#### How to use
|
371
|
+
|
372
|
+
*Gemfile*
|
373
|
+
```ruby
|
374
|
+
gem 'tramway'
|
375
|
+
gem 'kaminari'
|
376
|
+
```
|
377
|
+
|
378
|
+
*config/initializers/tramway.rb*
|
379
|
+
```ruby
|
380
|
+
Tramway.configure do |config|
|
381
|
+
config.pagination = { enabled: true } # enabled is false by default
|
382
|
+
end
|
383
|
+
```
|
384
|
+
|
385
|
+
*app/views/users/index.html.haml*
|
386
|
+
```haml
|
387
|
+
= paginate @users # it will render tailwind-styled pagination buttons by default
|
388
|
+
```
|
389
|
+
|
390
|
+
Pagination buttons looks like [this](https://play.tailwindcss.com/mqgDS5l9oY)
|
391
|
+
|
349
392
|
## Contributing
|
350
393
|
|
351
394
|
Install [lefthook](https://github.com/evilmartians/lefthook)
|
@@ -353,6 +396,7 @@ Install [lefthook](https://github.com/evilmartians/lefthook)
|
|
353
396
|
```
|
354
397
|
bundle
|
355
398
|
lefthook install
|
399
|
+
rspec
|
356
400
|
```
|
357
401
|
|
358
402
|
## License
|
@@ -4,4 +4,12 @@ require 'view_component'
|
|
4
4
|
|
5
5
|
# Base TailwindComponent. Contains base features for all tailwind components
|
6
6
|
class TailwindComponent < ViewComponent::Base
|
7
|
+
extend Dry::Initializer[undefined: false]
|
8
|
+
|
9
|
+
option :input
|
10
|
+
option :attribute
|
11
|
+
option :value, optional: true
|
12
|
+
option :options
|
13
|
+
option :label
|
14
|
+
option :for
|
7
15
|
end
|
@@ -3,21 +3,36 @@
|
|
3
3
|
module Tailwinds
|
4
4
|
module Form
|
5
5
|
# Provides Tailwind-styled forms
|
6
|
+
# :reek:InstanceVariableAssumption
|
6
7
|
class Builder < Tramway::Views::FormBuilder
|
7
8
|
def text_field(attribute, **options, &)
|
8
|
-
|
9
|
-
|
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
|
-
|
14
|
-
|
17
|
+
render(Tailwinds::Form::TextFieldComponent.new(
|
18
|
+
input: input(:password_field),
|
19
|
+
**default_options(attribute, options)
|
20
|
+
), &)
|
15
21
|
end
|
16
22
|
|
17
23
|
def file_field(attribute, **options, &)
|
18
24
|
input = super(attribute, **options.merge(class: :hidden))
|
19
25
|
|
20
|
-
render(Tailwinds::Form::FileFieldComponent.new(input
|
26
|
+
render(Tailwinds::Form::FileFieldComponent.new(input:, **default_options(attribute, options)), &)
|
27
|
+
end
|
28
|
+
|
29
|
+
def select(attribute, collection, **options, &)
|
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
|
+
), &)
|
21
36
|
end
|
22
37
|
|
23
38
|
def submit(action, **options, &)
|
@@ -26,8 +41,31 @@ module Tailwinds
|
|
26
41
|
|
27
42
|
private
|
28
43
|
|
29
|
-
def
|
30
|
-
|
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
|
+
|
53
|
+
def default_options(attribute, options)
|
54
|
+
{
|
55
|
+
attribute:,
|
56
|
+
label: label(attribute, options),
|
57
|
+
for: for_id(attribute),
|
58
|
+
options:
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
# :reek:UtilityFunction
|
63
|
+
def label(attribute, options)
|
64
|
+
options[:label] || attribute.to_s.humanize
|
65
|
+
end
|
66
|
+
|
67
|
+
def for_id(attribute)
|
68
|
+
"#{object_name}_#{attribute}"
|
31
69
|
end
|
32
70
|
end
|
33
71
|
end
|
@@ -4,11 +4,7 @@ module Tailwinds
|
|
4
4
|
module Form
|
5
5
|
# Tailwind-styled file_field input
|
6
6
|
class FileFieldComponent < TailwindComponent
|
7
|
-
|
8
|
-
@label = options[:label] || attribute.to_s.capitalize
|
9
|
-
@for = "#{object_name}_#{attribute}"
|
10
|
-
@input = input
|
11
|
-
end
|
7
|
+
option :input
|
12
8
|
end
|
13
9
|
end
|
14
10
|
end
|
@@ -0,0 +1,4 @@
|
|
1
|
+
.mb-4
|
2
|
+
%label.block.text-gray-700.text-sm.font-bold.mb-2{ for: @for }
|
3
|
+
= @label
|
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'))
|
@@ -4,11 +4,6 @@ module Tailwinds
|
|
4
4
|
module Form
|
5
5
|
# Tailwind-styled text field
|
6
6
|
class TextFieldComponent < TailwindComponent
|
7
|
-
def initialize(input, attribute, object_name: nil, **options)
|
8
|
-
@label = options[:label] || attribute.to_s.humanize
|
9
|
-
@for = "#{object_name}_#{attribute}"
|
10
|
-
@input = input
|
11
|
-
end
|
12
7
|
end
|
13
8
|
end
|
14
9
|
end
|
@@ -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
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'
|
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:
|
12
|
+
date: 2024-01-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: dry-struct
|
@@ -96,6 +96,8 @@ files:
|
|
96
96
|
- app/components/tailwinds/form/builder.rb
|
97
97
|
- app/components/tailwinds/form/file_field_component.html.haml
|
98
98
|
- app/components/tailwinds/form/file_field_component.rb
|
99
|
+
- app/components/tailwinds/form/select_component.html.haml
|
100
|
+
- app/components/tailwinds/form/select_component.rb
|
99
101
|
- app/components/tailwinds/form/submit_button_component.html.haml
|
100
102
|
- app/components/tailwinds/form/submit_button_component.rb
|
101
103
|
- app/components/tailwinds/form/text_field_component.html.haml
|
@@ -104,6 +106,13 @@ files:
|
|
104
106
|
- app/components/tailwinds/nav/item_component.rb
|
105
107
|
- app/components/tailwinds/navbar_component.html.haml
|
106
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
|
107
116
|
- config/routes.rb
|
108
117
|
- lib/rules/turbo_html_attributes_rules.rb
|
109
118
|
- lib/tasks/tramway_tasks.rake
|