tramway 0.3.2 → 0.4

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: fc95797d7be71f61b7a8350b3ef71905d41c8281d3a134feefc4e8477b910b44
4
- data.tar.gz: 9fc4aa0e0bbec968e96620532082142b3ad48ab701e97ab52c2bd05a8236c047
3
+ metadata.gz: 68a5dd780d7427b0c2075f140c891af3a4c33210c88a00d86e33279dc27e6c28
4
+ data.tar.gz: 63701d608f5545ea95e98fac522624cc34092199fe839b16ba579d9c461c0383
5
5
  SHA512:
6
- metadata.gz: ef921bd83394ebde2404a8e5e1b7332af573713553ed73676850955ff8e32f9fc93cdddfa0124658ad40c096557fcd60ed420a55d252f5e5c3fb40ea34cae19e
7
- data.tar.gz: d0a2b72e6e35ea9a297a9af346e794cf1833e8b5922c2e09d98a5f8f06a2d283db49b33753510535a0594365b072aff666712ee50a0b2c9d6036aa530ab52e38
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:
@@ -362,6 +363,32 @@ Available form helpers:
362
363
  * select
363
364
  * submit
364
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
+
365
392
  ## Contributing
366
393
 
367
394
  Install [lefthook](https://github.com/evilmartians/lefthook)
@@ -369,6 +396,7 @@ Install [lefthook](https://github.com/evilmartians/lefthook)
369
396
  ```
370
397
  bundle
371
398
  lefthook install
399
+ rspec
372
400
  ```
373
401
 
374
402
  ## 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 :template
9
+ option :input
10
10
  option :attribute
11
- option :object_name
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(**default_options(attribute, options)), &)
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(**default_options(attribute, options)), &)
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
- render(Tailwinds::Form::FileFieldComponent.new(**default_options(attribute, options)), &)
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(**default_options(attribute, options).merge(collection:)), &)
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.inline-block.bg-blue-500.hover:bg-blue-700.text-white.font-bold.py-2.px-4.rounded.cursor-pointer.mt-4{ for: @for }
3
3
  = @label
4
- = @template.file_field @object_name, @attribute
4
+ = @input
@@ -4,6 +4,7 @@ module Tailwinds
4
4
  module Form
5
5
  # Tailwind-styled file_field input
6
6
  class FileFieldComponent < TailwindComponent
7
+ option :input
7
8
  end
8
9
  end
9
10
  end
@@ -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
- = @template.select @object_name, @attribute, @collection, {}, @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
+ = @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
- = @template.text_field @object_name, @attribute, **@options.merge(class: 'w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:border-red-500')
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
@@ -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
- def initialize
13
- @entities = []
14
- end
13
+ attr_config(
14
+ pagination: { enabled: false },
15
+ entities: []
16
+ )
15
17
 
16
18
  def entities=(collection)
17
- @entities = collection.map do |entity|
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
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tramway
4
- VERSION = '0.3.2'
4
+ VERSION = '0.4'
5
5
  end
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.3.2
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: 2024-01-04 00:00:00.000000000 Z
12
+ date: 2024-01-20 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