tramway 0.5.4.1 → 0.5.5.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 +42 -0
 - data/app/components/tailwind_component.rb +32 -0
 - data/app/components/tailwinds/form/builder.rb +53 -20
 - data/app/components/tailwinds/form/file_field_component.html.haml +4 -1
 - data/app/components/tailwinds/form/multiselect/dropdown_container.html.haml +1 -1
 - data/app/components/tailwinds/form/multiselect/item_container.html.haml +3 -3
 - data/app/components/tailwinds/form/multiselect/select_as_input.html.haml +4 -1
 - data/app/components/tailwinds/form/multiselect/select_as_input.rb +1 -0
 - data/app/components/tailwinds/form/multiselect/selected_item_template.html.haml +1 -1
 - data/app/components/tailwinds/form/multiselect_component.html.haml +3 -3
 - data/app/components/tailwinds/form/multiselect_component.rb +8 -1
 - data/app/components/tailwinds/form/number_field_component.html.haml +8 -0
 - data/app/components/tailwinds/form/number_field_component.rb +9 -0
 - data/app/components/tailwinds/form/select_component.html.haml +5 -1
 - data/app/components/tailwinds/form/submit_button_component.html.haml +4 -1
 - data/app/components/tailwinds/form/submit_button_component.rb +11 -3
 - data/app/components/tailwinds/form/text_area_component.html.haml +4 -1
 - data/app/components/tailwinds/form/text_field_component.html.haml +4 -1
 - data/app/components/tailwinds/table/header_component.html.haml +1 -1
 - data/app/components/tailwinds/table/header_component.rb +6 -1
 - data/app/components/tailwinds/table/row_component.rb +2 -6
 - data/app/components/tailwinds/table_component.html.haml +1 -1
 - data/app/controllers/tramway/entities_controller.rb +11 -5
 - data/config/routes.rb +4 -4
 - data/lib/tramway/base_form.rb +1 -1
 - data/lib/tramway/decorators/association.rb +1 -1
 - data/lib/tramway/decorators/class_helper.rb +18 -16
 - data/lib/tramway/forms/properties.rb +6 -10
 - data/lib/tramway/helpers/views_helper.rb +7 -2
 - data/lib/tramway/navbar.rb +5 -5
 - data/lib/tramway/version.rb +1 -1
 - metadata +4 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 7e2e7bd75d61196a4ba4302fe3c05d5dfce6928a35ea0d97022b9170ce911ca8
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 1b89b1fb5a18ae6d28c8afb1b8a1d94da832f0855c1acf1f5ab4f9fb0f1d4bd7
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 4565144363a3419833bb267231fc403ff49c1da50caa3ee4ec936d6a2245fc2ddf89ab111af33cc7a5759cd9bc51d90cc456e5108acc78b73e99ca7ea5107158
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: a83591d638a439dcd659474cfd50b73f9f292bff11fd2e18987c821df25888a9de4ae68d16fb2d7048eb36949869350339b8c3104ffaa71f92f97042d2a84ba9
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -14,6 +14,16 @@ Unite Ruby on Rails brilliance. Streamline development with Tramway. 
     | 
|
| 
       14 
14 
     | 
    
         
             
              * [Tailwind-styled pagination](https://github.com/Purple-Magic/tramway?tab=readme-ov-file#tailwind-styled-pagination-for-kaminari)
         
     | 
| 
       15 
15 
     | 
    
         
             
            * [Articles](https://github.com/Purple-Magic/tramway#usage)
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
      
 17 
     | 
    
         
            +
            ## Compatibility
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            Tramway is actively verified against the following Ruby and Rails versions.
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            | Ruby \ Rails | 7.1 | 7.2 | 8.0 | 8.1 |
         
     | 
| 
      
 22 
     | 
    
         
            +
            | ------------- | --- | --- | --- | --- |
         
     | 
| 
      
 23 
     | 
    
         
            +
            | 3.2           | ✅  | ✅  | ✅  | ✅  |
         
     | 
| 
      
 24 
     | 
    
         
            +
            | 3.3           | ✅  | ✅  | ✅  | ✅  |
         
     | 
| 
      
 25 
     | 
    
         
            +
            | 3.4           | ✅  | ✅  | ✅  | ✅  |
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
       17 
27 
     | 
    
         
             
            ## Installation
         
     | 
| 
       18 
28 
     | 
    
         
             
            Add this line to your application's Gemfile:
         
     | 
| 
       19 
29 
     | 
    
         | 
| 
         @@ -528,6 +538,38 @@ Tramway provides a responsive, tailwind-styled table with light and dark themes. 
     | 
|
| 
       528 
538 
     | 
    
         
             
                  Another
         
     | 
| 
       529 
539 
     | 
    
         
             
            ```
         
     | 
| 
       530 
540 
     | 
    
         | 
| 
      
 541 
     | 
    
         
            +
            `Tailwinds::TableComponent` accepts an optional `options` hash that is merged into the outer `.div-table` element. The hash is
         
     | 
| 
      
 542 
     | 
    
         
            +
            forwarded as HTML attributes, so you can pass things like `id`, `data` attributes, or additional classes. If you do not supply
         
     | 
| 
      
 543 
     | 
    
         
            +
            your own width utility (e.g. a class that starts with `w-`), the component automatically appends `w-full` to keep the table
         
     | 
| 
      
 544 
     | 
    
         
            +
            responsive. This allows you to extend the default styling without losing the sensible defaults provided by the component.
         
     | 
| 
      
 545 
     | 
    
         
            +
             
     | 
| 
      
 546 
     | 
    
         
            +
            ```haml
         
     | 
| 
      
 547 
     | 
    
         
            +
            = component 'tailwinds/table', options: { class: 'max-w-3xl border border-gray-200', data: { controller: 'table' } } do
         
     | 
| 
      
 548 
     | 
    
         
            +
              = component 'tailwinds/table/header', headers: ['Name', 'Email']
         
     | 
| 
      
 549 
     | 
    
         
            +
              = component 'tailwinds/table/row' do
         
     | 
| 
      
 550 
     | 
    
         
            +
                = component 'tailwinds/table/cell' do
         
     | 
| 
      
 551 
     | 
    
         
            +
                  = user.name
         
     | 
| 
      
 552 
     | 
    
         
            +
                = component 'tailwinds/table/cell' do
         
     | 
| 
      
 553 
     | 
    
         
            +
                  = user.email
         
     | 
| 
      
 554 
     | 
    
         
            +
            ```
         
     | 
| 
      
 555 
     | 
    
         
            +
             
     | 
| 
      
 556 
     | 
    
         
            +
            When you render a header you can either pass the `headers:` array, as in the examples above, or render custom header content in
         
     | 
| 
      
 557 
     | 
    
         
            +
            the block. `Tailwinds::Table::HeaderComponent` uses the length of the `headers` array to build the grid if the array is present.
         
     | 
| 
      
 558 
     | 
    
         
            +
            If you omit the array and provide custom content, pass the `columns:` argument so the component knows how many grid columns to
         
     | 
| 
      
 559 
     | 
    
         
            +
            generate.
         
     | 
| 
      
 560 
     | 
    
         
            +
             
     | 
| 
      
 561 
     | 
    
         
            +
            ```haml
         
     | 
| 
      
 562 
     | 
    
         
            +
            = component 'tailwinds/table/header', columns: 4 do
         
     | 
| 
      
 563 
     | 
    
         
            +
              = component 'tailwinds/table/cell' do
         
     | 
| 
      
 564 
     | 
    
         
            +
                Custom header cell
         
     | 
| 
      
 565 
     | 
    
         
            +
              = component 'tailwinds/table/cell' do
         
     | 
| 
      
 566 
     | 
    
         
            +
                Another header cell
         
     | 
| 
      
 567 
     | 
    
         
            +
              / ...
         
     | 
| 
      
 568 
     | 
    
         
            +
            ```
         
     | 
| 
      
 569 
     | 
    
         
            +
             
     | 
| 
      
 570 
     | 
    
         
            +
            With this approach you control the header layout while still benefiting from the default Tailwind grid classes that the header
         
     | 
| 
      
 571 
     | 
    
         
            +
            component applies.
         
     | 
| 
      
 572 
     | 
    
         
            +
             
     | 
| 
       531 
573 
     | 
    
         
             
            ### Tailwind-styled forms
         
     | 
| 
       532 
574 
     | 
    
         | 
| 
       533 
575 
     | 
    
         
             
            Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are implemented with [ViewComponent](https://github.com/viewcomponent/view_component).
         
     | 
| 
         @@ -10,4 +10,36 @@ class TailwindComponent < Tramway::Component::Base 
     | 
|
| 
       10 
10 
     | 
    
         
             
              option :options
         
     | 
| 
       11 
11 
     | 
    
         
             
              option :label
         
     | 
| 
       12 
12 
     | 
    
         
             
              option :for
         
     | 
| 
      
 13 
     | 
    
         
            +
              option :size, default: -> { :middle }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              SIZE_CLASSES = {
         
     | 
| 
      
 16 
     | 
    
         
            +
                small: {
         
     | 
| 
      
 17 
     | 
    
         
            +
                  text_input: 'text-sm px-2 py-1',
         
     | 
| 
      
 18 
     | 
    
         
            +
                  select_input: 'text-sm px-2 py-1',
         
     | 
| 
      
 19 
     | 
    
         
            +
                  file_button: 'text-sm px-3 py-1',
         
     | 
| 
      
 20 
     | 
    
         
            +
                  submit_button: 'text-sm px-3 py-1',
         
     | 
| 
      
 21 
     | 
    
         
            +
                  multiselect_input: 'text-sm px-2 py-1'
         
     | 
| 
      
 22 
     | 
    
         
            +
                },
         
     | 
| 
      
 23 
     | 
    
         
            +
                middle: {
         
     | 
| 
      
 24 
     | 
    
         
            +
                  text_input: 'text-base px-3 py-2',
         
     | 
| 
      
 25 
     | 
    
         
            +
                  select_input: 'text-base px-3 py-2',
         
     | 
| 
      
 26 
     | 
    
         
            +
                  file_button: 'text-base px-4 py-2',
         
     | 
| 
      
 27 
     | 
    
         
            +
                  submit_button: 'text-base px-4 py-2',
         
     | 
| 
      
 28 
     | 
    
         
            +
                  multiselect_input: 'text-base px-3 py-2'
         
     | 
| 
      
 29 
     | 
    
         
            +
                },
         
     | 
| 
      
 30 
     | 
    
         
            +
                large: {
         
     | 
| 
      
 31 
     | 
    
         
            +
                  text_input: 'text-lg px-4 py-3',
         
     | 
| 
      
 32 
     | 
    
         
            +
                  select_input: 'text-lg px-4 py-3',
         
     | 
| 
      
 33 
     | 
    
         
            +
                  file_button: 'text-lg px-5 py-3',
         
     | 
| 
      
 34 
     | 
    
         
            +
                  submit_button: 'text-lg px-5 py-3',
         
     | 
| 
      
 35 
     | 
    
         
            +
                  multiselect_input: 'text-lg px-4 py-3'
         
     | 
| 
      
 36 
     | 
    
         
            +
                }
         
     | 
| 
      
 37 
     | 
    
         
            +
              }.freeze
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              private
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              def size_class(key)
         
     | 
| 
      
 42 
     | 
    
         
            +
                size_classes = SIZE_CLASSES.fetch(size) { SIZE_CLASSES[:middle] }
         
     | 
| 
      
 43 
     | 
    
         
            +
                size_classes.fetch(key) { SIZE_CLASSES[:middle].fetch(key) }
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
       13 
45 
     | 
    
         
             
            end
         
     | 
| 
         @@ -5,59 +5,90 @@ module Tailwinds 
     | 
|
| 
       5 
5 
     | 
    
         
             
                # Provides Tailwind-styled forms
         
     | 
| 
       6 
6 
     | 
    
         
             
                # :reek:InstanceVariableAssumption
         
     | 
| 
       7 
7 
     | 
    
         
             
                class Builder < Tramway::Views::FormBuilder
         
     | 
| 
      
 8 
     | 
    
         
            +
                  def initialize(object_name, object, template, options)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    super
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    @form_size = options[:size] || options['size'] || :middle
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
       8 
14 
     | 
    
         
             
                  def text_field(attribute, **options, &)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
       9 
17 
     | 
    
         
             
                    render(Tailwinds::Form::TextFieldComponent.new(
         
     | 
| 
       10 
18 
     | 
    
         
             
                             input: input(:text_field),
         
     | 
| 
       11 
     | 
    
         
            -
                             value: get_value(attribute,  
     | 
| 
       12 
     | 
    
         
            -
                             **default_options(attribute,  
     | 
| 
      
 19 
     | 
    
         
            +
                             value: get_value(attribute, sanitized_options),
         
     | 
| 
      
 20 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
      
 21 
     | 
    
         
            +
                           ), &)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def number_field(attribute, **options, &)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    render(Tailwinds::Form::NumberFieldComponent.new(
         
     | 
| 
      
 28 
     | 
    
         
            +
                             input: input(:number_field),
         
     | 
| 
      
 29 
     | 
    
         
            +
                             value: get_value(attribute, sanitized_options),
         
     | 
| 
      
 30 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       13 
31 
     | 
    
         
             
                           ), &)
         
     | 
| 
       14 
32 
     | 
    
         
             
                  end
         
     | 
| 
       15 
33 
     | 
    
         | 
| 
       16 
34 
     | 
    
         
             
                  def text_area(attribute, **options, &)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
       17 
37 
     | 
    
         
             
                    render(Tailwinds::Form::TextAreaComponent.new(
         
     | 
| 
       18 
38 
     | 
    
         
             
                             input: input(:text_area),
         
     | 
| 
       19 
     | 
    
         
            -
                             value: get_value(attribute,  
     | 
| 
       20 
     | 
    
         
            -
                             **default_options(attribute,  
     | 
| 
      
 39 
     | 
    
         
            +
                             value: get_value(attribute, sanitized_options),
         
     | 
| 
      
 40 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       21 
41 
     | 
    
         
             
                           ), &)
         
     | 
| 
       22 
42 
     | 
    
         
             
                  end
         
     | 
| 
       23 
43 
     | 
    
         | 
| 
       24 
44 
     | 
    
         
             
                  def password_field(attribute, **options, &)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
       25 
47 
     | 
    
         
             
                    render(Tailwinds::Form::TextFieldComponent.new(
         
     | 
| 
       26 
48 
     | 
    
         
             
                             input: input(:password_field),
         
     | 
| 
       27 
     | 
    
         
            -
                             **default_options(attribute,  
     | 
| 
      
 49 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       28 
50 
     | 
    
         
             
                           ), &)
         
     | 
| 
       29 
51 
     | 
    
         
             
                  end
         
     | 
| 
       30 
52 
     | 
    
         | 
| 
       31 
53 
     | 
    
         
             
                  def file_field(attribute, **options, &)
         
     | 
| 
       32 
     | 
    
         
            -
                     
     | 
| 
      
 54 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    input = super(attribute, **sanitized_options.merge(class: :hidden))
         
     | 
| 
       33 
56 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                    render(Tailwinds::Form::FileFieldComponent.new(input:, **default_options(attribute,  
     | 
| 
      
 57 
     | 
    
         
            +
                    render(Tailwinds::Form::FileFieldComponent.new(input:, **default_options(attribute, sanitized_options)), &)
         
     | 
| 
       35 
58 
     | 
    
         
             
                  end
         
     | 
| 
       36 
59 
     | 
    
         | 
| 
       37 
60 
     | 
    
         
             
                  def select(attribute, collection, **options, &)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
       38 
63 
     | 
    
         
             
                    render(Tailwinds::Form::SelectComponent.new(
         
     | 
| 
       39 
64 
     | 
    
         
             
                             input: input(:select),
         
     | 
| 
       40 
     | 
    
         
            -
                             value:  
     | 
| 
       41 
     | 
    
         
            -
                             collection: explicitly_add_blank_option(collection,  
     | 
| 
       42 
     | 
    
         
            -
                             **default_options(attribute,  
     | 
| 
      
 65 
     | 
    
         
            +
                             value: sanitized_options[:selected] || object.public_send(attribute),
         
     | 
| 
      
 66 
     | 
    
         
            +
                             collection: explicitly_add_blank_option(collection, sanitized_options),
         
     | 
| 
      
 67 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       43 
68 
     | 
    
         
             
                           ), &)
         
     | 
| 
       44 
69 
     | 
    
         
             
                  end
         
     | 
| 
       45 
70 
     | 
    
         | 
| 
       46 
71 
     | 
    
         
             
                  def multiselect(attribute, collection, **options, &)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
       47 
74 
     | 
    
         
             
                    render(Tailwinds::Form::MultiselectComponent.new(
         
     | 
| 
       48 
75 
     | 
    
         
             
                             input: input(:text_field),
         
     | 
| 
       49 
     | 
    
         
            -
                             value:  
     | 
| 
      
 76 
     | 
    
         
            +
                             value: sanitized_options[:value] || sanitized_options[:selected] || object.public_send(attribute),
         
     | 
| 
       50 
77 
     | 
    
         
             
                             collection:,
         
     | 
| 
       51 
     | 
    
         
            -
                             **default_options(attribute,  
     | 
| 
      
 78 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       52 
79 
     | 
    
         
             
                           ), &)
         
     | 
| 
       53 
80 
     | 
    
         
             
                  end
         
     | 
| 
       54 
81 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
                  def submit(action,  
     | 
| 
       56 
     | 
    
         
            -
                     
     | 
| 
      
 82 
     | 
    
         
            +
                  def submit(action, **options, &)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    render(Tailwinds::Form::SubmitButtonComponent.new(action, size: form_size, **sanitized_options), &)
         
     | 
| 
       57 
86 
     | 
    
         
             
                  end
         
     | 
| 
       58 
87 
     | 
    
         | 
| 
       59 
88 
     | 
    
         
             
                  private
         
     | 
| 
       60 
89 
     | 
    
         | 
| 
      
 90 
     | 
    
         
            +
                  attr_reader :form_size
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
       61 
92 
     | 
    
         
             
                  def input(method_name)
         
     | 
| 
       62 
93 
     | 
    
         
             
                    unbound_method = self.class.superclass.instance_method(method_name)
         
     | 
| 
       63 
94 
     | 
    
         
             
                    unbound_method.bind(self)
         
     | 
| 
         @@ -68,12 +99,7 @@ module Tailwinds 
     | 
|
| 
       68 
99 
     | 
    
         
             
                  end
         
     | 
| 
       69 
100 
     | 
    
         | 
| 
       70 
101 
     | 
    
         
             
                  def default_options(attribute, options)
         
     | 
| 
       71 
     | 
    
         
            -
                    {
         
     | 
| 
       72 
     | 
    
         
            -
                      attribute:,
         
     | 
| 
       73 
     | 
    
         
            -
                      label: label_build(attribute, options),
         
     | 
| 
       74 
     | 
    
         
            -
                      for: for_id(attribute),
         
     | 
| 
       75 
     | 
    
         
            -
                      options:
         
     | 
| 
       76 
     | 
    
         
            -
                    }
         
     | 
| 
      
 102 
     | 
    
         
            +
                    { attribute:, label: label_build(attribute, options), for: for_id(attribute), options:, size: form_size }
         
     | 
| 
       77 
103 
     | 
    
         
             
                  end
         
     | 
| 
       78 
104 
     | 
    
         | 
| 
       79 
105 
     | 
    
         
             
                  # :reek:UtilityFunction
         
     | 
| 
         @@ -88,6 +114,13 @@ module Tailwinds 
     | 
|
| 
       88 
114 
     | 
    
         
             
                    "#{object_name}_#{attribute}"
         
     | 
| 
       89 
115 
     | 
    
         
             
                  end
         
     | 
| 
       90 
116 
     | 
    
         | 
| 
      
 117 
     | 
    
         
            +
                  def sanitize_options(options)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    options.dup.tap do |opts|
         
     | 
| 
      
 119 
     | 
    
         
            +
                      opts.delete(:size)
         
     | 
| 
      
 120 
     | 
    
         
            +
                      opts.delete('size')
         
     | 
| 
      
 121 
     | 
    
         
            +
                    end
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
       91 
124 
     | 
    
         
             
                  # REMOVE IT. WE MUST UNDERSTAND WHY INCLUDE_BLANK DOES NOT WORK
         
     | 
| 
       92 
125 
     | 
    
         
             
                  # :reek:UtilityFunction
         
     | 
| 
       93 
126 
     | 
    
         
             
                  def explicitly_add_blank_option(collection, options)
         
     | 
| 
         @@ -1,5 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            .mb-4
         
     | 
| 
       2 
2 
     | 
    
         
             
              - if @label
         
     | 
| 
       3 
     | 
    
         
            -
                 
     | 
| 
      
 3 
     | 
    
         
            +
                - base_classes = 'inline-block bg-blue-500 hover:bg-blue-700 text-white font-bold rounded cursor-pointer mt-4 '
         
     | 
| 
      
 4 
     | 
    
         
            +
                - base_classes += 'dark:bg-blue-600 dark:hover:bg-blue-500'
         
     | 
| 
      
 5 
     | 
    
         
            +
                - classes = "#{size_class(:file_button)} #{base_classes}"
         
     | 
| 
      
 6 
     | 
    
         
            +
                %label{ for: @for, class: classes }
         
     | 
| 
       4 
7 
     | 
    
         
             
                  = @label
         
     | 
| 
       5 
8 
     | 
    
         
             
              = @input
         
     | 
| 
         @@ -1,3 +1,3 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #dropdown.absolute.shadow.top-11.bg-white.z-40.w-full.lef-0.rounded.max-h-select.overflow-y-auto{ data: { action: "click@window->multiselect#closeOnClickOutside" } }
         
     | 
| 
      
 1 
     | 
    
         
            +
            #dropdown.absolute.shadow.top-11.bg-white.z-40.w-full.lef-0.rounded.max-h-select.overflow-y-auto.dark:bg-gray-800.dark:shadow-lg.dark:ring-1.dark:ring-gray-700{ data: { action: "click@window->multiselect#closeOnClickOutside" } }
         
     | 
| 
       2 
2 
     | 
    
         
             
              .flex.flex-col.w-full
         
     | 
| 
       3 
3 
     | 
    
         
             
                {{content}}
         
     | 
| 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            .cursor-pointer.w-full.border-gray-100.rounded-t.border-b.hover:bg-teal-100{ data: { action: "click->multiselect#toggleItem", text: "{{text}}", value: "{{value}}" } }
         
     | 
| 
       2 
     | 
    
         
            -
              .flex.w-full.items-center.p-2.pl-2.border-transparent.border-l-2.relative.hover:border-teal-100
         
     | 
| 
       3 
     | 
    
         
            -
                .w-full.items-center.flex
         
     | 
| 
      
 1 
     | 
    
         
            +
            .cursor-pointer.w-full.border-gray-100.rounded-t.border-b.hover:bg-teal-100.dark:border-gray-700.dark:hover:bg-gray-700{ data: { action: "click->multiselect#toggleItem", text: "{{text}}", value: "{{value}}" } }
         
     | 
| 
      
 2 
     | 
    
         
            +
              .flex.w-full.items-center.p-2.pl-2.border-transparent.border-l-2.relative.hover:border-teal-100.dark:hover:border-gray-600
         
     | 
| 
      
 3 
     | 
    
         
            +
                .w-full.items-center.flex.dark:text-gray-100
         
     | 
| 
       4 
4 
     | 
    
         
             
                  .mx-2.leading-6
         
     | 
| 
       5 
5 
     | 
    
         
             
                    {{text}}
         
     | 
| 
         @@ -1,2 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            .flex-1
         
     | 
| 
       2 
     | 
    
         
            -
               
     | 
| 
      
 2 
     | 
    
         
            +
              - base_classes = 'bg-transparent appearance-none outline-none h-full w-full text-gray-800 hidden '
         
     | 
| 
      
 3 
     | 
    
         
            +
              - base_classes += 'dark:text-white dark:placeholder-white'
         
     | 
| 
      
 4 
     | 
    
         
            +
              - classes = "#{@size_class} #{base_classes}"
         
     | 
| 
      
 5 
     | 
    
         
            +
              = @input.call(@attribute, @options.merge(placeholder: "{{placeholder}}", class: classes, data: { 'multiselect-target' => 'hiddenInput' }))
         
     | 
| 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            .flex.justify-center.items-center.m-1.font-medium.py-1.px-2.bg-white.rounded-full.text-teal-700.bg-teal-100.border.border-teal-300
         
     | 
| 
      
 1 
     | 
    
         
            +
            .flex.justify-center.items-center.m-1.font-medium.py-1.px-2.bg-white.rounded-full.text-teal-700.bg-teal-100.border.border-teal-300.dark:bg-teal-900.dark:text-teal-100.dark:border-teal-700
         
     | 
| 
       2 
2 
     | 
    
         
             
              .text-xs.font-normal.leading-none.max-w-full.flex-initial
         
     | 
| 
       3 
3 
     | 
    
         
             
                {{text}}
         
     | 
| 
       4 
4 
     | 
    
         
             
              .flex.flex-auto.flex-row-reverse
         
     | 
| 
         @@ -2,9 +2,9 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
              - if @label
         
     | 
| 
       3 
3 
     | 
    
         
             
                = component('tailwinds/form/label', for: @for) do
         
     | 
| 
       4 
4 
     | 
    
         
             
                  = @label
         
     | 
| 
       5 
     | 
    
         
            -
              .flex.flex-col.relative{ data: multiselect_hash, id: "#{@for}_multiselect" }
         
     | 
| 
      
 5 
     | 
    
         
            +
              .flex.flex-col.relative.dark:text-gray-100{ data: multiselect_hash, id: "#{@for}_multiselect" }
         
     | 
| 
       6 
6 
     | 
    
         
             
                .min-w-96.w-fit
         
     | 
| 
       7 
     | 
    
         
            -
                  .p-1.flex.border.border-gray-200.bg-white.rounded{ data: { "multiselect-target" => "dropdown" } }
         
     | 
| 
      
 7 
     | 
    
         
            +
                  .p-1.flex.border.border-gray-200.bg-white.rounded.dark:border-gray-600.dark:bg-gray-800{ data: { "multiselect-target" => "dropdown" } }
         
     | 
| 
       8 
8 
     | 
    
         
             
                    .flex.flex-auto.flex-wrap{ data: { "multiselect-target" => "showSelectedArea" } }
         
     | 
| 
       9 
     | 
    
         
            -
                    .text-gray-300.w-8.py-1.pl-2.pr-1.border-l.flex.items-center.border-gray-200
         
     | 
| 
      
 9 
     | 
    
         
            +
                    .text-gray-300.w-8.py-1.pl-2.pr-1.border-l.flex.items-center.border-gray-200.dark:text-gray-500.dark:border-gray-600
         
     | 
| 
       10 
10 
     | 
    
         
             
                      ^
         
     | 
| 
         @@ -45,7 +45,14 @@ module Tailwinds 
     | 
|
| 
       45 
45 
     | 
    
         
             
                  end
         
     | 
| 
       46 
46 
     | 
    
         | 
| 
       47 
47 
     | 
    
         
             
                  def select_as_input
         
     | 
| 
       48 
     | 
    
         
            -
                    render( 
     | 
| 
      
 48 
     | 
    
         
            +
                    render(
         
     | 
| 
      
 49 
     | 
    
         
            +
                      Tailwinds::Form::Multiselect::SelectAsInput.new(
         
     | 
| 
      
 50 
     | 
    
         
            +
                        options:,
         
     | 
| 
      
 51 
     | 
    
         
            +
                        attribute:,
         
     | 
| 
      
 52 
     | 
    
         
            +
                        input:,
         
     | 
| 
      
 53 
     | 
    
         
            +
                        size_class: size_class(:multiselect_input)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      )
         
     | 
| 
      
 55 
     | 
    
         
            +
                    )
         
     | 
| 
       49 
56 
     | 
    
         
             
                  end
         
     | 
| 
       50 
57 
     | 
    
         | 
| 
       51 
58 
     | 
    
         
             
                  def on_change
         
     | 
| 
         @@ -0,0 +1,8 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            .mb-4
         
     | 
| 
      
 2 
     | 
    
         
            +
              - if @label
         
     | 
| 
      
 3 
     | 
    
         
            +
                = component('tailwinds/form/label', for: @for) do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  = @label
         
     | 
| 
      
 5 
     | 
    
         
            +
              - base_classes = 'w-full bg-white border border-gray-300 rounded focus:outline-none focus:border-red-500 '
         
     | 
| 
      
 6 
     | 
    
         
            +
              - base_classes += 'dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:border-red-400 dark:placeholder-white'
         
     | 
| 
      
 7 
     | 
    
         
            +
              - classes = "#{size_class(:text_input)} #{base_classes}"
         
     | 
| 
      
 8 
     | 
    
         
            +
              = @input.call @attribute, **@options.merge(class: classes), value: @value
         
     | 
| 
         @@ -2,4 +2,8 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
              - if @label
         
     | 
| 
       3 
3 
     | 
    
         
             
                = component('tailwinds/form/label', for: @for) do
         
     | 
| 
       4 
4 
     | 
    
         
             
                  = @label
         
     | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
      
 5 
     | 
    
         
            +
              - base_classes = 'bg-white border border-gray-300 text-gray-700 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 '
         
     | 
| 
      
 6 
     | 
    
         
            +
              - base_classes += 'focus:border-transparent disabled:bg-gray-100 disabled:text-gray-400 disabled:cursor-not-allowed '
         
     | 
| 
      
 7 
     | 
    
         
            +
              - base_classes += 'dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:focus:ring-red-400 dark:disabled:bg-gray-800 dark:disabled:text-gray-500'
         
     | 
| 
      
 8 
     | 
    
         
            +
              - classes = "#{size_class(:select_input)} #{base_classes}"
         
     | 
| 
      
 9 
     | 
    
         
            +
              = @input.call(@attribute, @collection, { selected: @value }, @options.merge(class: classes))
         
     | 
| 
         @@ -1,4 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            .flex.items-center.justify-between
         
     | 
| 
       2 
     | 
    
         
            -
               
     | 
| 
      
 2 
     | 
    
         
            +
              - base_classes = 'bg-red-500 hover:bg-red-700 text-white font-bold rounded focus:outline-none focus:shadow-outline cursor-pointer '
         
     | 
| 
      
 3 
     | 
    
         
            +
              - base_classes += 'dark:text-white dark:bg-red-600 dark:hover:bg-red-500 dark:focus:ring-2 dark:focus:ring-red-400'
         
     | 
| 
      
 4 
     | 
    
         
            +
              - classes = "#{size_class(:submit_button)} #{base_classes}"
         
     | 
| 
      
 5 
     | 
    
         
            +
              %button{ type: :submit, name: :commit, class: classes, **@options }
         
     | 
| 
       3 
6 
     | 
    
         
             
                = @text
         
     | 
| 
       4 
7 
     | 
    
         
             
              = @content
         
     | 
| 
         @@ -4,10 +4,18 @@ module Tailwinds 
     | 
|
| 
       4 
4 
     | 
    
         
             
              module Form
         
     | 
| 
       5 
5 
     | 
    
         
             
                # Tailwind-styled submit button
         
     | 
| 
       6 
6 
     | 
    
         
             
                class SubmitButtonComponent < TailwindComponent
         
     | 
| 
       7 
     | 
    
         
            -
                  def initialize(action, **options)
         
     | 
| 
       8 
     | 
    
         
            -
                    @options = options.except :type
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 7 
     | 
    
         
            +
                  def initialize(action, size: :middle, **options)
         
     | 
| 
       10 
8 
     | 
    
         
             
                    @text = action.is_a?(String) ? action : action.to_s.capitalize
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                    super(
         
     | 
| 
      
 11 
     | 
    
         
            +
                      input: nil,
         
     | 
| 
      
 12 
     | 
    
         
            +
                      attribute: nil,
         
     | 
| 
      
 13 
     | 
    
         
            +
                      value: nil,
         
     | 
| 
      
 14 
     | 
    
         
            +
                      options: options.except(:type),
         
     | 
| 
      
 15 
     | 
    
         
            +
                      label: nil,
         
     | 
| 
      
 16 
     | 
    
         
            +
                      for: nil,
         
     | 
| 
      
 17 
     | 
    
         
            +
                      size:
         
     | 
| 
      
 18 
     | 
    
         
            +
                    )
         
     | 
| 
       11 
19 
     | 
    
         
             
                  end
         
     | 
| 
       12 
20 
     | 
    
         
             
                end
         
     | 
| 
       13 
21 
     | 
    
         
             
              end
         
     | 
| 
         @@ -2,4 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
              - if @label
         
     | 
| 
       3 
3 
     | 
    
         
             
                = component('tailwinds/form/label', for: @for) do
         
     | 
| 
       4 
4 
     | 
    
         
             
                  = @label
         
     | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
      
 5 
     | 
    
         
            +
              - base_classes = 'w-full bg-white border border-gray-300 rounded focus:outline-none focus:border-red-500 '
         
     | 
| 
      
 6 
     | 
    
         
            +
              - base_classes += 'dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:border-red-400 dark:placeholder-white'
         
     | 
| 
      
 7 
     | 
    
         
            +
              - classes = "#{size_class(:text_input)} #{base_classes}"
         
     | 
| 
      
 8 
     | 
    
         
            +
              = @input.call @attribute, **@options.merge(class: classes), value: @value
         
     | 
| 
         @@ -2,4 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
              - if @label
         
     | 
| 
       3 
3 
     | 
    
         
             
                = component('tailwinds/form/label', for: @for) do
         
     | 
| 
       4 
4 
     | 
    
         
             
                  = @label
         
     | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
      
 5 
     | 
    
         
            +
              - base_classes = 'w-full bg-white border border-gray-300 rounded focus:outline-none focus:border-red-500 '
         
     | 
| 
      
 6 
     | 
    
         
            +
              - base_classes += 'dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:border-red-400 dark:placeholder-white'
         
     | 
| 
      
 7 
     | 
    
         
            +
              - classes = "#{size_class(:text_input)} #{base_classes}"
         
     | 
| 
      
 8 
     | 
    
         
            +
              = @input.call @attribute, **@options.merge(class: classes), value: @value
         
     | 
| 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            .div-table-row.grid.text-white.text-small.gap-4.bg-purple-700.dark:bg-gray-700.dark:text-gray-400{ class: "grid-cols-#{ 
     | 
| 
      
 1 
     | 
    
         
            +
            .div-table-row.grid.text-white.text-small.gap-4.bg-purple-700.dark:bg-gray-700.dark:text-gray-400{ class: "grid-cols-#{columns_count}", aria: { label: "Table Header" }, role: "row" }
         
     | 
| 
       2 
2 
     | 
    
         
             
              - if headers.any?
         
     | 
| 
       3 
3 
     | 
    
         
             
                - headers.each do |header|
         
     | 
| 
       4 
4 
     | 
    
         
             
                  .div-table-cell.py-4.px-6
         
     | 
| 
         @@ -4,7 +4,12 @@ module Tailwinds 
     | 
|
| 
       4 
4 
     | 
    
         
             
              module Table
         
     | 
| 
       5 
5 
     | 
    
         
             
                # Component for rendering a header in a table
         
     | 
| 
       6 
6 
     | 
    
         
             
                class HeaderComponent < Tramway::Component::Base
         
     | 
| 
       7 
     | 
    
         
            -
                  option :headers
         
     | 
| 
      
 7 
     | 
    
         
            +
                  option :headers, optional: true, default: -> { [] }
         
     | 
| 
      
 8 
     | 
    
         
            +
                  option :columns, optional: true, default: -> { 3 }
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def columns_count
         
     | 
| 
      
 11 
     | 
    
         
            +
                    headers.present? ? headers.size : columns
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
       8 
13 
     | 
    
         
             
                end
         
     | 
| 
       9 
14 
     | 
    
         
             
              end
         
     | 
| 
       10 
15 
     | 
    
         
             
            end
         
     | 
| 
         @@ -12,26 +12,22 @@ module Tailwinds 
     | 
|
| 
       12 
12 
     | 
    
         
             
                    default_attributes = { role: :row }
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
                    if href.present?
         
     | 
| 
       15 
     | 
    
         
            -
                       
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                      link_to(href, options.merge(class: klass, **default_attributes)) do
         
     | 
| 
      
 15 
     | 
    
         
            +
                      link_to(href, options.merge(class: "#{options[:class] || ''} #{link_row_classes}", **default_attributes)) do
         
     | 
| 
       18 
16 
     | 
    
         
             
                        yield if block_given?
         
     | 
| 
       19 
17 
     | 
    
         
             
                      end
         
     | 
| 
       20 
18 
     | 
    
         
             
                    else
         
     | 
| 
       21 
     | 
    
         
            -
                      tag.div(**options 
     | 
| 
      
 19 
     | 
    
         
            +
                      tag.div(**options, **default_attributes) do
         
     | 
| 
       22 
20 
     | 
    
         
             
                        yield if block_given?
         
     | 
| 
       23 
21 
     | 
    
         
             
                      end
         
     | 
| 
       24 
22 
     | 
    
         
             
                    end
         
     | 
| 
       25 
23 
     | 
    
         
             
                  end
         
     | 
| 
       26 
24 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                  # :reek:UtilityFunction { enabled: false }
         
     | 
| 
       28 
25 
     | 
    
         
             
                  def desktop_row_classes(cells_count)
         
     | 
| 
       29 
26 
     | 
    
         
             
                    [
         
     | 
| 
       30 
27 
     | 
    
         
             
                      'div-table-row', 'grid', 'gap-4', 'bg-white', 'border-b', 'last:border-b-0', 'dark:bg-gray-800',
         
     | 
| 
       31 
28 
     | 
    
         
             
                      'dark:border-gray-700', "grid-cols-#{cells_count}"
         
     | 
| 
       32 
29 
     | 
    
         
             
                    ].join(' ')
         
     | 
| 
       33 
30 
     | 
    
         
             
                  end
         
     | 
| 
       34 
     | 
    
         
            -
                  # :reek:UtilityFunction { enabled: true }
         
     | 
| 
       35 
31 
     | 
    
         | 
| 
       36 
32 
     | 
    
         
             
                  def link_row_classes
         
     | 
| 
       37 
33 
     | 
    
         
             
                    'cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700'
         
     | 
| 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            = helpers.component 'tailwinds/table/row/preview'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            - width_class = options[:class]&.include?('w-') ? '' : 'w-full'
         
     | 
| 
       4 
     | 
    
         
            -
            .div-table.text-left.rtl:text-right.text-gray-500.dark:text-gray-400 
     | 
| 
      
 4 
     | 
    
         
            +
            .div-table.text-left.rtl:text-right.text-gray-500.dark:text-gray-400{ class: "#{options[:class]} #{width_class}", **options.except(:class) }
         
     | 
| 
       5 
5 
     | 
    
         
             
              = content
         
     | 
| 
         @@ -11,11 +11,13 @@ module Tramway 
     | 
|
| 
       11 
11 
     | 
    
         
             
                include Rails.application.routes.url_helpers
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
                def index
         
     | 
| 
       14 
     | 
    
         
            -
                   
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
      
 14 
     | 
    
         
            +
                  if index_scope.present?
         
     | 
| 
      
 15 
     | 
    
         
            +
                    model_class.public_send(index_scope)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  else
         
     | 
| 
      
 17 
     | 
    
         
            +
                    model_class.order(id: :desc)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end.page(params[:page]) => entities
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  @entities = entities
         
     | 
| 
       19 
21 
     | 
    
         | 
| 
       20 
22 
     | 
    
         
             
                  @namespace = entity.route&.namespace
         
     | 
| 
       21 
23 
     | 
    
         
             
                end
         
     | 
| 
         @@ -29,5 +31,9 @@ module Tramway 
     | 
|
| 
       29 
31 
     | 
    
         
             
                def entity
         
     | 
| 
       30 
32 
     | 
    
         
             
                  @entity ||= Tramway.config.entities.find { |e| e.name == params[:entity][:name] }
         
     | 
| 
       31 
33 
     | 
    
         
             
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def index_scope
         
     | 
| 
      
 36 
     | 
    
         
            +
                  entity.page(:index).scope
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
       32 
38 
     | 
    
         
             
              end
         
     | 
| 
       33 
39 
     | 
    
         
             
            end
         
     | 
    
        data/config/routes.rb
    CHANGED
    
    | 
         @@ -3,13 +3,13 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            Tramway::Engine.routes.draw do
         
     | 
| 
       4 
4 
     | 
    
         
             
              Tramway.config.entities.each do |entity|
         
     | 
| 
       5 
5 
     | 
    
         
             
                segments      = entity.name.split('/')
         
     | 
| 
       6 
     | 
    
         
            -
                resource_name = segments.pop 
     | 
| 
      
 6 
     | 
    
         
            +
                resource_name = segments.pop
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                define_resource = proc do
         
     | 
| 
       9 
9 
     | 
    
         
             
                  resources resource_name.pluralize.to_sym,
         
     | 
| 
       10 
     | 
    
         
            -
                            only: 
     | 
| 
       11 
     | 
    
         
            -
                            controller:'/tramway/entities',
         
     | 
| 
       12 
     | 
    
         
            -
                            defaults: 
     | 
| 
      
 10 
     | 
    
         
            +
                            only: [:index],
         
     | 
| 
      
 11 
     | 
    
         
            +
                            controller: '/tramway/entities',
         
     | 
| 
      
 12 
     | 
    
         
            +
                            defaults: { entity: entity }
         
     | 
| 
       13 
13 
     | 
    
         
             
                end
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
                if segments.empty?
         
     | 
    
        data/lib/tramway/base_form.rb
    CHANGED
    
    
| 
         @@ -20,26 +20,19 @@ module Tramway 
     | 
|
| 
       20 
20 
     | 
    
         
             
                  end
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
                  def decorator_class_name(object_or_array_or_class, namespace)
         
     | 
| 
       23 
     | 
    
         
            -
                     
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 23 
     | 
    
         
            +
                    if Tramway::Decorators::CollectionDecorators.collection?(object_or_array_or_class)
         
     | 
| 
      
 24 
     | 
    
         
            +
                      object_or_array_or_class.first.class
         
     | 
| 
      
 25 
     | 
    
         
            +
                    elsif object_or_array_or_class.is_a?(Class)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      object_or_array_or_class
         
     | 
| 
      
 27 
     | 
    
         
            +
                    else
         
     | 
| 
      
 28 
     | 
    
         
            +
                      object_or_array_or_class.class
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end => klass
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                    base_class_name = Tramway::Decorators::NameBuilder.default_decorator_class_name(klass)
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
                     
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                    if klass_name.safe_constantize
         
     | 
| 
       36 
     | 
    
         
            -
                      klass_name
         
     | 
| 
       37 
     | 
    
         
            -
                    else
         
     | 
| 
       38 
     | 
    
         
            -
                      raise NameError, "You should define #{klass_name} decorator class in app/decorators/ folder."
         
     | 
| 
       39 
     | 
    
         
            -
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                    build_klass_name(base_class_name, namespace)
         
     | 
| 
       40 
34 
     | 
    
         
             
                  end
         
     | 
| 
       41 
35 
     | 
    
         | 
| 
       42 
     | 
    
         
            -
                  # :reek:NilCheck { enabled: false }
         
     | 
| 
       43 
36 
     | 
    
         
             
                  def raise_error_if_object_empty(object_or_array, decorator)
         
     | 
| 
       44 
37 
     | 
    
         
             
                    return unless object_or_array.blank? && decorator.nil?
         
     | 
| 
       45 
38 
     | 
    
         | 
| 
         @@ -47,7 +40,16 @@ module Tramway 
     | 
|
| 
       47 
40 
     | 
    
         | 
| 
       48 
41 
     | 
    
         
             
                    raise ArgumentError, text
         
     | 
| 
       49 
42 
     | 
    
         
             
                  end
         
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  def build_klass_name(base_class_name, namespace)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    klass_name = namespace.present? ? "#{namespace.to_s.camelize}::#{base_class_name}" : base_class_name
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    unless klass_name.safe_constantize
         
     | 
| 
      
 48 
     | 
    
         
            +
                      raise NameError, "You should define #{klass_name} decorator class in app/decorators/ folder."
         
     | 
| 
      
 49 
     | 
    
         
            +
                    end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                    klass_name
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
       51 
53 
     | 
    
         
             
                end
         
     | 
| 
       52 
54 
     | 
    
         
             
              end
         
     | 
| 
       53 
55 
     | 
    
         
             
            end
         
     | 
| 
         @@ -10,21 +10,17 @@ module Tramway 
     | 
|
| 
       10 
10 
     | 
    
         
             
                      @properties << attribute
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                      define_method(attribute) do
         
     | 
| 
       13 
     | 
    
         
            -
                         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                         
     | 
| 
       16 
     | 
    
         
            -
                          raise NoMethodError, "#{self.class}##{attribute} is not defined"
         
     | 
| 
       17 
     | 
    
         
            -
                        end
         
     | 
| 
      
 13 
     | 
    
         
            +
                        raise NoMethodError, "#{self.class}##{attribute} is not defined" unless object.respond_to?(attribute)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                        object.public_send(attribute)
         
     | 
| 
       18 
16 
     | 
    
         
             
                      end
         
     | 
| 
       19 
17 
     | 
    
         | 
| 
       20 
18 
     | 
    
         
             
                      set_method = "#{attribute}="
         
     | 
| 
       21 
19 
     | 
    
         | 
| 
       22 
20 
     | 
    
         
             
                      define_method(set_method) do |value|
         
     | 
| 
       23 
     | 
    
         
            -
                         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                         
     | 
| 
       26 
     | 
    
         
            -
                          raise NoMethodError, "#{self.class}##{set_method} is not defined"
         
     | 
| 
       27 
     | 
    
         
            -
                        end
         
     | 
| 
      
 21 
     | 
    
         
            +
                        raise NoMethodError, "#{self.class}##{set_method} is not defined" unless object.respond_to?(set_method)
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                        object.public_send(set_method, value)
         
     | 
| 
       28 
24 
     | 
    
         
             
                      end
         
     | 
| 
       29 
25 
     | 
    
         
             
                    end
         
     | 
| 
       30 
26 
     | 
    
         | 
| 
         @@ -4,8 +4,13 @@ module Tramway 
     | 
|
| 
       4 
4 
     | 
    
         
             
              module Helpers
         
     | 
| 
       5 
5 
     | 
    
         
             
                # Provides view-oriented helpers for ActionView
         
     | 
| 
       6 
6 
     | 
    
         
             
                module ViewsHelper
         
     | 
| 
       7 
     | 
    
         
            -
                  def tramway_form_for(object, *, **options, &)
         
     | 
| 
       8 
     | 
    
         
            -
                    form_for( 
     | 
| 
      
 7 
     | 
    
         
            +
                  def tramway_form_for(object, *, size: :middle, **options, &)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    form_for(
         
     | 
| 
      
 9 
     | 
    
         
            +
                      object,
         
     | 
| 
      
 10 
     | 
    
         
            +
                      *,
         
     | 
| 
      
 11 
     | 
    
         
            +
                      **options.merge(builder: Tailwinds::Form::Builder, size:),
         
     | 
| 
      
 12 
     | 
    
         
            +
                      &
         
     | 
| 
      
 13 
     | 
    
         
            +
                    )
         
     | 
| 
       9 
14 
     | 
    
         
             
                  end
         
     | 
| 
       10 
15 
     | 
    
         
             
                end
         
     | 
| 
       11 
16 
     | 
    
         
             
              end
         
     | 
    
        data/lib/tramway/navbar.rb
    CHANGED
    
    | 
         @@ -10,13 +10,13 @@ module Tramway 
     | 
|
| 
       10 
10 
     | 
    
         
             
                  @items = { left: [], right: [] }
         
     | 
| 
       11 
11 
     | 
    
         
             
                  @filling = nil
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
                   
     | 
| 
       14 
     | 
    
         
            -
                    entities = Tramway.config.entities
         
     | 
| 
      
 13 
     | 
    
         
            +
                  return unless with_entities
         
     | 
| 
       15 
14 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
      
 15 
     | 
    
         
            +
                  entities = Tramway.config.entities
         
     | 
| 
       17 
16 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
      
 17 
     | 
    
         
            +
                  return unless entities.any?
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  preset_left entities
         
     | 
| 
       20 
20 
     | 
    
         
             
                end
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
                def left
         
     | 
    
        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.5. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.5.5.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: 2025- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2025-10-23 00:00:00.000000000 Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: anyway_config
         
     | 
| 
         @@ -158,6 +158,8 @@ files: 
     | 
|
| 
       158 
158 
     | 
    
         
             
            - app/components/tailwinds/form/multiselect/selected_item_template.rb
         
     | 
| 
       159 
159 
     | 
    
         
             
            - app/components/tailwinds/form/multiselect_component.html.haml
         
     | 
| 
       160 
160 
     | 
    
         
             
            - app/components/tailwinds/form/multiselect_component.rb
         
     | 
| 
      
 161 
     | 
    
         
            +
            - app/components/tailwinds/form/number_field_component.html.haml
         
     | 
| 
      
 162 
     | 
    
         
            +
            - app/components/tailwinds/form/number_field_component.rb
         
     | 
| 
       161 
163 
     | 
    
         
             
            - app/components/tailwinds/form/select_component.html.haml
         
     | 
| 
       162 
164 
     | 
    
         
             
            - app/components/tailwinds/form/select_component.rb
         
     | 
| 
       163 
165 
     | 
    
         
             
            - app/components/tailwinds/form/submit_button_component.html.haml
         
     |