tramway 0.1.6 → 0.2.0

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: e5d6641dda4dedcf7e4d1a4e0638690e21b5f72fbfdccca6c40fa423eec9e3f8
4
- data.tar.gz: c0e4e0955c58b253c5aac6198302b6c11f3393f42d5edfd4fc317dd7b1a7894b
3
+ metadata.gz: c88b945e6fe61b58431c5598687538fb9514ec49333e11bfdb4b4027ff755e94
4
+ data.tar.gz: dde0abe3237e06f5aa5119e8cd28162643301fb534e949082cb930eca4a2b5dc
5
5
  SHA512:
6
- metadata.gz: f2b1fd87395239845d1eeb4e901e44063e1487bdd83f226a247746dc1bc4fc555cfba4c8357345486dd31e5f5e8c0b5be59e2831e599a87d9c10632b221ad64e
7
- data.tar.gz: eb6e88f325e65e1c49094a197a58419c11c71a5c24f78a5132167798ea4bff644c0a6d98320b073d16cea1b8baa258fa2300583474e95223e0f4ba09e9152327
6
+ metadata.gz: 7c27968e67c7c6da3047aadb5be9e39c52eb8049d558777674c8633e34cea10f996e0bf7d3dc04d2744fdd509f9e5019d321a730c2292c55336a2a5e32575b14
7
+ data.tar.gz: a5eab082d14d3c3158745135fdeedc5bf65789b59b6996523c0584e03522ceeeba63529b25b3549ab368123b6712257865e7098dd7641ec87cbb28358089f0ab
data/README.md CHANGED
@@ -13,7 +13,58 @@ gem "view_component"
13
13
 
14
14
  ### Tailwind components
15
15
 
16
- Tramway use [Tailwind](https://tailwindcss.com/) by default. All UI helpers implemented with [ViewComponent](https://github.com/viewcomponent/view_component).
16
+ Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are implemented with [ViewComponent](https://github.com/viewcomponent/view_component).
17
+
18
+ ### Decorators
19
+
20
+ Tramway provides convenient decorators for your objects. **NOTE:** This is not the decorator pattern in its usual representation.
21
+
22
+ *app/controllers/users_controller.rb*
23
+ ```ruby
24
+ def index
25
+ # this line of code decorates the users collection with the default UserDecorator
26
+ @users = tramway_decorate User.all
27
+ end
28
+ ```
29
+
30
+ *app/decorators/user_decorator.rb*
31
+ ```ruby
32
+ class UserDecorator < Tramway::BaseDecorator
33
+ # delegates attributes to decorated object
34
+ delegate_attributes :email, :first_name, :last_name
35
+
36
+ # you can provide your own methods with access to decorated object attributes with the method `object`
37
+ def created_at
38
+ I18n.l object.created_at
39
+ end
40
+
41
+ # you can provide representations with ViewComponent to avoid implementing views with Rails Helpers
42
+ def posts_table
43
+ render TableComponent.new(object.posts)
44
+ end
45
+ end
46
+ ```
47
+
48
+ #### Decorate single object
49
+
50
+ You can use the same method to decorate a single object either
51
+
52
+ ```ruby
53
+ def show
54
+ @user = tramway_decorate User.find params[:id]
55
+ end
56
+ ```
57
+
58
+ #### Decorate with a specific decorator
59
+
60
+ You can implement a specific decorator and ask Tramway to decorate with it
61
+
62
+ ```ruby
63
+ def show
64
+ @user = tramway_decorate User.find(params[:id]), decorator: Users::ShowDecorator
65
+ end
66
+ ```
67
+
17
68
 
18
69
  ### Navbar
19
70
 
@@ -2,5 +2,6 @@
2
2
 
3
3
  require 'view_component'
4
4
 
5
+ # Base TailwindComponent. Contains base features for all tailwind components
5
6
  class TailwindComponent < ViewComponent::Base
6
7
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rules/turbo_html_attributes_rules'
4
+
3
5
  module Tailwinds
4
6
  module Nav
5
7
  # Render button styled with Tailwind using button_to or link_to methods
@@ -8,20 +10,7 @@ module Tailwinds
8
10
  def initialize(**options)
9
11
  @href = options[:href]
10
12
  @style = 'text-white hover:bg-red-300 px-4 py-2 rounded'
11
- @options = prepare(options:)
12
- end
13
-
14
- private
15
-
16
- def prepare(options:)
17
- options.reduce({}) do |hash, (key, value)|
18
- case key
19
- when :method, :confirm
20
- hash.deep_merge data: { "turbo_#{key}".to_sym => value }
21
- else
22
- hash.merge key => value
23
- end
24
- end
13
+ @options = Rules::TurboHtmlAttributesRules.prepare_turbo_html_attributes(options:)
25
14
  end
26
15
  end
27
16
  end
@@ -1,26 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tailwinds
4
- # Navbar class main class
4
+ # Background helper module
5
5
  #
6
- class NavbarComponent < TailwindComponent
7
- def initialize(**options)
8
- @title = options[:title]
9
- @left_items = options[:left_items]
10
- @right_items = options[:right_items]
11
- @color = background(options)
12
- end
13
-
14
- private
15
-
6
+ module BackgroundHelper
16
7
  CSS_COLORS = %i[aqua black blue fuchsia gray green lime maroon navy olive orange purple red
17
8
  silver teal white yellow].freeze
18
9
  MIN_INTENSITY = 100
19
10
  MAX_INTENSITY = 950
11
+ DEFAULT_BACKGROUND_COLOR = :purple
12
+ DEFAULT_BACKGROUND_INTENSITY = 700
20
13
 
21
- def background(options)
22
- color = options.dig(:background, :color) || :purple
23
- intensity = options.dig(:background, :intensity) || 700
14
+ def self.background(options)
15
+ color = options.dig(:background, :color) || DEFAULT_BACKGROUND_COLOR
16
+ intensity = options.dig(:background, :intensity) || DEFAULT_BACKGROUND_INTENSITY
24
17
 
25
18
  unless (MIN_INTENSITY..MAX_INTENSITY).cover?(intensity)
26
19
  raise "Navigation Background Color intensity should be between #{MIN_INTENSITY} and #{MAX_INTENSITY}"
@@ -33,4 +26,17 @@ module Tailwinds
33
26
  end
34
27
  end
35
28
  end
29
+
30
+ # Navbar class main class
31
+ #
32
+ class NavbarComponent < TailwindComponent
33
+ include Tailwinds::BackgroundHelper
34
+
35
+ def initialize(**options)
36
+ @title = options[:title]
37
+ @left_items = options[:left_items]
38
+ @right_items = options[:right_items]
39
+ @color = BackgroundHelper.background(options)
40
+ end
41
+ end
36
42
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rules
4
+ # Provides rules for turbo html attributes
5
+ # It allows users to :method and :confirm attributes instead of data-turbo_method and data-turbo_confirm
6
+ module TurboHtmlAttributesRules
7
+ def self.prepare_turbo_html_attributes(options:)
8
+ options.reduce({}) do |hash, (key, value)|
9
+ case key
10
+ when :method, :confirm
11
+ hash.deep_merge data: { "turbo_#{key}".to_sym => value }
12
+ else
13
+ hash.merge key => value
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tramway/decorators/collection_decorator'
4
+
5
+ module Tramway
6
+ # Provides decorate function for Tramway projects
7
+ #
8
+ class BaseDecorator
9
+ include Tramway::Decorators::CollectionDecorators
10
+
11
+ attr_reader :object, :context
12
+
13
+ def initialize(object, context)
14
+ @object = object
15
+ @context = context
16
+ end
17
+
18
+ def render(*args)
19
+ context.render(*args, layout: false)
20
+ end
21
+
22
+ class << self
23
+ def decorate(object_or_array, context)
24
+ if Tramway::Decorators::CollectionDecorators.collection?(object_or_array)
25
+ Tramway::Decorators::CollectionDecorators.decorate_collection(collection: object_or_array, context:)
26
+ else
27
+ new(object_or_array, context)
28
+ end
29
+ end
30
+
31
+ def delegate_attributes(*args)
32
+ args.each do |attribute|
33
+ delegate attribute, to: :object
34
+ end
35
+ end
36
+ end
37
+
38
+ delegate_attributes :id
39
+
40
+ def to_partial_path
41
+ underscored_class_name = object.class.name.underscore
42
+
43
+ "#{underscored_class_name.pluralize}/#{underscored_class_name}"
44
+ end
45
+
46
+ def to_param
47
+ id.to_s
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway
4
+ module Decorators
5
+ # Provides method to determine decorators classes
6
+ module ClassHelper
7
+ module_function
8
+
9
+ def decorator_class(object_or_array, decorator)
10
+ if decorator.present?
11
+ decorator
12
+ else
13
+ klass = if Tramway::Decorators::CollectionDecorators.collection?(object_or_array)
14
+ object_or_array.first.class
15
+ else
16
+ object_or_array.class
17
+ end
18
+
19
+ "#{klass}Decorator".constantize
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway
4
+ module Decorators
5
+ # Provides functions for collection decorating
6
+ #
7
+ module CollectionDecorators
8
+ module_function
9
+
10
+ def decorate_collection(collection:, context:)
11
+ collection.map do |item|
12
+ Tramway::Decorators::BaseDecorator.decorate item, context
13
+ end
14
+ end
15
+
16
+ def collection?(object)
17
+ object.class.name.in? ['ActiveRecord::Relation', 'Array']
18
+ end
19
+ end
20
+ end
21
+ end
@@ -7,10 +7,16 @@ module Tramway
7
7
  isolate_namespace Tramway
8
8
 
9
9
  initializer 'tramway.load_helpers' do
10
- ActiveSupport.on_load(:action_view) do
10
+ ActiveSupport.on_load(:action_view) do |loaded_class|
11
11
  require 'tramway/helpers/navbar_helper'
12
12
 
13
- ActionView::Base.include Tramway::Helpers::NavbarHelper
13
+ loaded_class.include Tramway::Helpers::NavbarHelper
14
+ end
15
+
16
+ ActiveSupport.on_load(:action_controller) do |loaded_class|
17
+ require 'tramway/helpers/decorate_helper'
18
+
19
+ loaded_class.include Tramway::Helpers::DecorateHelper
14
20
  end
15
21
  end
16
22
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tramway/decorators/class_helper'
4
+
5
+ module Tramway
6
+ module Helpers
7
+ # Provides methods into Rails ActionController
8
+ #
9
+ module DecorateHelper
10
+ def tramway_decorate(object_or_array, decorator: nil)
11
+ Tramway::Decorators::ClassHelper.decorator_class(object_or_array, decorator).decorate object_or_array, self
12
+ end
13
+ end
14
+ end
15
+ end
@@ -5,18 +5,40 @@ require 'tramway/navbar'
5
5
  module Tramway
6
6
  module Helpers
7
7
  # Providing navbar helpers for ActionView
8
- #
9
8
  module NavbarHelper
10
9
  def tramway_navbar(**options)
11
10
  if block_given?
12
- @navbar = Tramway::Navbar.new self
11
+ initialize_navbar
13
12
 
14
13
  yield @navbar
15
14
 
16
- options[:left_items] = @navbar.items[:left]
17
- options[:right_items] = @navbar.items[:right]
15
+ assign_navbar_items(options)
18
16
  end
19
17
 
18
+ render_navbar_component(options)
19
+ end
20
+
21
+ private
22
+
23
+ def initialize_navbar
24
+ @navbar = Tramway::Navbar.new(self)
25
+ end
26
+
27
+ def assign_navbar_items(options)
28
+ navbar_items = @navbar.items
29
+ navbar_items.each do |(key, value)|
30
+ key_to_merge = case key
31
+ when :left, :right
32
+ "#{key}_items".to_sym
33
+ else
34
+ key
35
+ end
36
+
37
+ options.merge! key_to_merge => value
38
+ end
39
+ end
40
+
41
+ def render_navbar_component(options)
20
42
  render(Tailwinds::NavbarComponent.new(**options))
21
43
  end
22
44
  end
@@ -1,48 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tramway
4
- # Navbar class for Tramway navbars
5
- #
4
+ # Navbar object provides left and right elements
6
5
  class Navbar
7
6
  attr_reader :items
8
7
 
9
8
  def initialize(context)
10
9
  @items = {}
11
10
  @context = context
11
+ @filling = nil
12
12
  end
13
13
 
14
14
  def left
15
15
  return unless block_given?
16
16
 
17
17
  @items[:left] = []
18
-
19
- @filling = :left
20
-
18
+ filling_side(:left)
21
19
  yield self
20
+ reset_filling
22
21
  end
23
22
 
24
23
  def right
25
24
  return unless block_given?
26
25
 
27
26
  @items[:right] = []
28
-
29
- @filling = :right
30
-
27
+ filling_side(:right)
31
28
  yield self
29
+ reset_filling
32
30
  end
33
31
 
34
32
  def item(text_or_url, url = nil, **options, &block)
35
- raise 'You can not provide argument and code block in the same time' if url.present? && block_given?
33
+ raise 'You cannot provide an argument and a code block at the same time' if provided_url_and_block?(url, &block)
36
34
 
37
35
  rendered_item = if url.present?
38
- options.merge! href: url
39
- @context.render(Tailwinds::Nav::ItemComponent.new(**options)) { text_or_url }
36
+ render_ignoring_block(text_or_url, url, options)
40
37
  else
41
- options.merge! href: text_or_url
42
- @context.render(Tailwinds::Nav::ItemComponent.new(**options), &block)
38
+ render_using_block(text_or_url, options, &block)
43
39
  end
44
40
 
45
41
  @items[@filling] << rendered_item
46
42
  end
43
+
44
+ private
45
+
46
+ def provided_url_and_block?(url)
47
+ url.present? && block_given?
48
+ end
49
+
50
+ def filling_side(side)
51
+ @filling = side
52
+ end
53
+
54
+ def reset_filling
55
+ @filling = nil
56
+ end
57
+
58
+ def render_ignoring_block(text_or_url, url, options)
59
+ options.merge!(href: url)
60
+ @context.render(Tailwinds::Nav::ItemComponent.new(**options)) { text_or_url }
61
+ end
62
+
63
+ def render_using_block(text_or_url, options, &block)
64
+ options.merge!(href: text_or_url)
65
+ @context.render(Tailwinds::Nav::ItemComponent.new(**options), &block)
66
+ end
47
67
  end
48
68
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tramway
4
- VERSION = '0.1.6'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/tramway.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'tramway/version'
4
4
  require 'tramway/engine'
5
+ require 'tramway/base_decorator'
5
6
  require 'view_component/compiler'
6
7
  require 'view_component/engine'
7
8
 
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.1.6
4
+ version: 0.2.0
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: 2023-06-22 00:00:00.000000000 Z
12
+ date: 2023-06-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: haml-rails
@@ -84,9 +84,14 @@ files:
84
84
  - app/components/tailwinds/navbar_component.html.haml
85
85
  - app/components/tailwinds/navbar_component.rb
86
86
  - config/routes.rb
87
+ - lib/rules/turbo_html_attributes_rules.rb
87
88
  - lib/tasks/tramway_tasks.rake
88
89
  - lib/tramway.rb
90
+ - lib/tramway/base_decorator.rb
91
+ - lib/tramway/decorators/class_helper.rb
92
+ - lib/tramway/decorators/collection_decorator.rb
89
93
  - lib/tramway/engine.rb
94
+ - lib/tramway/helpers/decorate_helper.rb
90
95
  - lib/tramway/helpers/navbar_helper.rb
91
96
  - lib/tramway/navbar.rb
92
97
  - lib/tramway/version.rb