tramway 0.5.5.1 → 0.6.0.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 +197 -66
 - data/app/components/tailwinds/back_button_component.html.haml +2 -0
 - data/app/components/tailwinds/back_button_component.rb +7 -0
 - data/app/components/tailwinds/base_component.rb +7 -0
 - data/app/components/tailwinds/button_component.html.haml +12 -0
 - data/app/components/tailwinds/button_component.rb +60 -0
 - data/app/components/tailwinds/containers/narrow_component.html.haml +3 -0
 - data/app/components/tailwinds/containers/narrow_component.rb +10 -0
 - data/app/components/tailwinds/form/builder.rb +18 -19
 - data/app/views/tramway/entities/_list.html.haml +8 -8
 - data/app/views/tramway/entities/index.html.haml +2 -1
 - data/config/tailwind.config.js +105 -25
 - data/lib/generators/tramway/install/install_generator.rb +133 -0
 - data/lib/tramway/helpers/views_helper.rb +39 -0
 - data/lib/tramway/version.rb +1 -1
 - metadata +10 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: a7d9322ff7e374d37c137d366bec17c0728b350eccf87b146655d7704f1e560d
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 045e0e118d1269095a241ce783ffb08bc282b8e885570341ad57878e4e0e1ac4
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 4d4594294bf08a6822a7b4a4d0bb8d777fdaed41fe0024d3fa29a5741c4c46c63ea921ea7c1742888502c42b5195e7198a23e4a80e8dc4216557e40da1e20953
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: e2e6f019d9e2b19e8fa32f6d3740c2a32473b9e070845b04756e20e53eb2abb9f51b37dd2aa721bbad98a557e90f55eb32054ed36f1a014056be4dfa8d3018a9
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -29,17 +29,18 @@ Add this line to your application's Gemfile: 
     | 
|
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
            ```ruby
         
     | 
| 
       31 
31 
     | 
    
         
             
            gem "tramway"
         
     | 
| 
       32 
     | 
    
         
            -
            gem "haml-rails"
         
     | 
| 
       33 
     | 
    
         
            -
            gem "kaminari"
         
     | 
| 
       34 
     | 
    
         
            -
            gem "view_component"
         
     | 
| 
       35 
32 
     | 
    
         
             
            ```
         
     | 
| 
       36 
33 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
      
 34 
     | 
    
         
            +
            Then install Tramway and its dependencies:
         
     | 
| 
       38 
35 
     | 
    
         | 
| 
       39 
36 
     | 
    
         
             
            ```shell
         
     | 
| 
       40 
     | 
    
         
            -
            bundle  
     | 
| 
      
 37 
     | 
    
         
            +
            bundle install
         
     | 
| 
      
 38 
     | 
    
         
            +
            bin/rails g tramway:install
         
     | 
| 
       41 
39 
     | 
    
         
             
            ```
         
     | 
| 
       42 
40 
     | 
    
         | 
| 
      
 41 
     | 
    
         
            +
            The install generator adds the required gems (`haml-rails`, `kaminari`, `view_component`, and `dry-initializer`) to your
         
     | 
| 
      
 42 
     | 
    
         
            +
            application's Gemfile—if they are not present—and appends the Tailwind safelist configuration Tramway ships with.
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
       43 
44 
     | 
    
         
             
            ## Getting Started
         
     | 
| 
       44 
45 
     | 
    
         | 
| 
       45 
46 
     | 
    
         
             
            **Step 1**
         
     | 
| 
         @@ -78,7 +79,9 @@ end 
     | 
|
| 
       78 
79 
     | 
    
         | 
| 
       79 
80 
     | 
    
         
             
            **Step 4**
         
     | 
| 
       80 
81 
     | 
    
         | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
      
 82 
     | 
    
         
            +
            If you ran `bin/rails g tramway:install`, the Tailwind safelist was already appended to `config/tailwind.config.js`.
         
     | 
| 
      
 83 
     | 
    
         
            +
            Otherwise, copy this [file](https://github.com/Purple-Magic/tramway/blob/main/config/tailwind.config.js) to
         
     | 
| 
      
 84 
     | 
    
         
            +
            `config/tailwind.config.js`.
         
     | 
| 
       82 
85 
     | 
    
         | 
| 
       83 
86 
     | 
    
         | 
| 
       84 
87 
     | 
    
         
             
            **Step 5**
         
     | 
| 
         @@ -130,13 +133,30 @@ Tramway Entity supports several options that are used in different features. 
     | 
|
| 
       130 
133 
     | 
    
         
             
            ```ruby
         
     | 
| 
       131 
134 
     | 
    
         
             
            Tramway.configure do |config|
         
     | 
| 
       132 
135 
     | 
    
         
             
              config.entities = [
         
     | 
| 
       133 
     | 
    
         
            -
                { 
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
      
 136 
     | 
    
         
            +
                {
         
     | 
| 
      
 137 
     | 
    
         
            +
                  name: :user,
         
     | 
| 
      
 138 
     | 
    
         
            +
                  route: { namespace: :admin }
         
     | 
| 
      
 139 
     | 
    
         
            +
                }, # `/admin/users` link in the Tramway Navbar
         
     | 
| 
      
 140 
     | 
    
         
            +
                {
         
     | 
| 
      
 141 
     | 
    
         
            +
                  name: :episodes,
         
     | 
| 
      
 142 
     | 
    
         
            +
                  route: {
         
     | 
| 
      
 143 
     | 
    
         
            +
                    namespace: :podcasts,
         
     | 
| 
      
 144 
     | 
    
         
            +
                    route_method: :episodes
         
     | 
| 
      
 145 
     | 
    
         
            +
                  }
         
     | 
| 
      
 146 
     | 
    
         
            +
                }, # `/podcasts/episodes` link in the Tramway Navbar
         
     | 
| 
       136 
147 
     | 
    
         
             
              ]
         
     | 
| 
       137 
148 
     | 
    
         
             
            end
         
     | 
| 
       138 
149 
     | 
    
         
             
            ```
         
     | 
| 
       139 
150 
     | 
    
         | 
| 
      
 151 
     | 
    
         
            +
            **route_helper**
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
            To get routes Tramway generated just Tramway::Engine.
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 156 
     | 
    
         
            +
            Tramway::Engine.routes.url_helpers.users_path => '/admin/users'
         
     | 
| 
      
 157 
     | 
    
         
            +
            Tramway::Engine.routes.url_helpers.podcasts_episodes_path => '/podcasts/episodes'
         
     | 
| 
      
 158 
     | 
    
         
            +
            ```
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
       140 
160 
     | 
    
         
             
            ### Tramway Decorators
         
     | 
| 
       141 
161 
     | 
    
         | 
| 
       142 
162 
     | 
    
         
             
            Tramway provides convenient decorators for your objects. **NOTE:** This is not the decorator pattern in its usual representation.
         
     | 
| 
         @@ -452,15 +472,19 @@ tramway_navbar title: 'Purple Magic', background: { color: :red, intensity: 500 
     | 
|
| 
       452 
472 
     | 
    
         
             
            end
         
     | 
| 
       453 
473 
     | 
    
         
             
            ```
         
     | 
| 
       454 
474 
     | 
    
         | 
| 
       455 
     | 
    
         
            -
            #  
     | 
| 
      
 475 
     | 
    
         
            +
            # ERB example
         
     | 
| 
       456 
476 
     | 
    
         | 
| 
       457 
     | 
    
         
            -
            ``` 
     | 
| 
       458 
     | 
    
         
            -
             
     | 
| 
       459 
     | 
    
         
            -
               
     | 
| 
       460 
     | 
    
         
            -
                 
     | 
| 
       461 
     | 
    
         
            -
                 
     | 
| 
       462 
     | 
    
         
            -
               
     | 
| 
       463 
     | 
    
         
            -
             
     | 
| 
      
 477 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 478 
     | 
    
         
            +
            <%= tramway_navbar title: 'Purple Magic', background: { color: :red, intensity: 500 } do |nav| %>
         
     | 
| 
      
 479 
     | 
    
         
            +
              <% nav.left do %>
         
     | 
| 
      
 480 
     | 
    
         
            +
                <%= nav.item 'Users', '/users' %>
         
     | 
| 
      
 481 
     | 
    
         
            +
                <%= nav.item 'Podcasts', '/podcasts' %>
         
     | 
| 
      
 482 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 483 
     | 
    
         
            +
             
     | 
| 
      
 484 
     | 
    
         
            +
              <% nav.right do %>
         
     | 
| 
      
 485 
     | 
    
         
            +
                <%= nav.item 'Sign out', '/users/sessions', method: :delete, confirm: 'Wanna quit?' %>
         
     | 
| 
      
 486 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 487 
     | 
    
         
            +
            <% end %>
         
     | 
| 
       464 
488 
     | 
    
         
             
            ```
         
     | 
| 
       465 
489 
     | 
    
         | 
| 
       466 
490 
     | 
    
         
             
            will render [this](https://play.tailwindcss.com/UZPTCudFw5)
         
     | 
| 
         @@ -482,13 +506,16 @@ with_entities: Show Tramway Entities index page links to navbar. Default: true 
     | 
|
| 
       482 
506 
     | 
    
         | 
| 
       483 
507 
     | 
    
         
             
            In case you want to hide entity links you can pass `with_entities: false`.
         
     | 
| 
       484 
508 
     | 
    
         | 
| 
       485 
     | 
    
         
            -
            ``` 
     | 
| 
       486 
     | 
    
         
            -
             
     | 
| 
       487 
     | 
    
         
            -
               
     | 
| 
       488 
     | 
    
         
            -
                 
     | 
| 
       489 
     | 
    
         
            -
                   
     | 
| 
       490 
     | 
    
         
            -
             
     | 
| 
       491 
     | 
    
         
            -
               
     | 
| 
      
 509 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 510 
     | 
    
         
            +
            <% if current_user.present? %>
         
     | 
| 
      
 511 
     | 
    
         
            +
              <%= tramway_navbar title: 'WaiWai' do |nav| %>
         
     | 
| 
      
 512 
     | 
    
         
            +
                <% nav.left do %>
         
     | 
| 
      
 513 
     | 
    
         
            +
                  <%= nav.item 'Board', admin_board_path %>
         
     | 
| 
      
 514 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 515 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 516 
     | 
    
         
            +
            <% else %>
         
     | 
| 
      
 517 
     | 
    
         
            +
              <%= tramway_navbar title: 'WaiWai', with_entities: false %>
         
     | 
| 
      
 518 
     | 
    
         
            +
            <% end %>
         
     | 
| 
       492 
519 
     | 
    
         
             
            ```
         
     | 
| 
       493 
520 
     | 
    
         | 
| 
       494 
521 
     | 
    
         
             
            #### nav.left and nav.right
         
     | 
| 
         @@ -526,31 +553,43 @@ end 
     | 
|
| 
       526 
553 
     | 
    
         | 
| 
       527 
554 
     | 
    
         
             
            ### Tramway Table Component
         
     | 
| 
       528 
555 
     | 
    
         | 
| 
       529 
     | 
    
         
            -
            Tramway provides a responsive, tailwind-styled table with light and dark themes.
         
     | 
| 
      
 556 
     | 
    
         
            +
            Tramway provides a responsive, tailwind-styled table with light and dark themes. Use the `tramway_table`, `tramway_row`, and
         
     | 
| 
      
 557 
     | 
    
         
            +
            `tramway_cell` helpers to build tables with readable ERB templates while still leveraging the underlying ViewComponent
         
     | 
| 
      
 558 
     | 
    
         
            +
            implementations.
         
     | 
| 
      
 559 
     | 
    
         
            +
             
     | 
| 
      
 560 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 561 
     | 
    
         
            +
            <%= tramway_table do %>
         
     | 
| 
      
 562 
     | 
    
         
            +
              <%= component 'tailwinds/table/header', headers: ['Column 1', 'Column 2'] %>
         
     | 
| 
       530 
563 
     | 
    
         | 
| 
       531 
     | 
    
         
            -
             
     | 
| 
       532 
     | 
    
         
            -
             
     | 
| 
       533 
     | 
    
         
            -
              = component 'tailwinds/table/header', headers: ['Column 1', 'Column 2']
         
     | 
| 
       534 
     | 
    
         
            -
              = component 'tailwinds/table/row' do
         
     | 
| 
       535 
     | 
    
         
            -
                = component 'tailwinds/table/cell' do
         
     | 
| 
      
 564 
     | 
    
         
            +
              <%= tramway_row do %>
         
     | 
| 
      
 565 
     | 
    
         
            +
                <%= tramway_cell do %>
         
     | 
| 
       536 
566 
     | 
    
         
             
                  Something
         
     | 
| 
       537 
     | 
    
         
            -
                 
     | 
| 
      
 567 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 568 
     | 
    
         
            +
                <%= tramway_cell do %>
         
     | 
| 
       538 
569 
     | 
    
         
             
                  Another
         
     | 
| 
      
 570 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 571 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 572 
     | 
    
         
            +
            <% end %>
         
     | 
| 
       539 
573 
     | 
    
         
             
            ```
         
     | 
| 
       540 
574 
     | 
    
         | 
| 
       541 
     | 
    
         
            -
            ` 
     | 
| 
       542 
     | 
    
         
            -
             
     | 
| 
       543 
     | 
    
         
            -
             
     | 
| 
       544 
     | 
    
         
            -
             
     | 
| 
      
 575 
     | 
    
         
            +
            `tramway_table` accepts the same optional `options` hash as `Tailwinds::TableComponent`. The hash is forwarded as HTML
         
     | 
| 
      
 576 
     | 
    
         
            +
            attributes, so you can pass things like `id`, `data` attributes, or additional classes. If you do not supply your own width
         
     | 
| 
      
 577 
     | 
    
         
            +
            utility (e.g. a class that starts with `w-`), the component automatically appends `w-full` to keep the table responsive. This
         
     | 
| 
      
 578 
     | 
    
         
            +
            allows you to extend the default styling without losing the sensible defaults provided by the component.
         
     | 
| 
      
 579 
     | 
    
         
            +
             
     | 
| 
      
 580 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 581 
     | 
    
         
            +
            <%= tramway_table class: 'max-w-3xl border border-gray-200', data: { controller: 'table' } do %>
         
     | 
| 
      
 582 
     | 
    
         
            +
              <%= component 'tailwinds/table/header', headers: ['Name', 'Email'] %>
         
     | 
| 
       545 
583 
     | 
    
         | 
| 
       546 
     | 
    
         
            -
             
     | 
| 
       547 
     | 
    
         
            -
             
     | 
| 
       548 
     | 
    
         
            -
             
     | 
| 
       549 
     | 
    
         
            -
             
     | 
| 
       550 
     | 
    
         
            -
                 
     | 
| 
       551 
     | 
    
         
            -
                   
     | 
| 
       552 
     | 
    
         
            -
                 
     | 
| 
       553 
     | 
    
         
            -
             
     | 
| 
      
 584 
     | 
    
         
            +
              <%= tramway_row do %>
         
     | 
| 
      
 585 
     | 
    
         
            +
                <%= tramway_cell do %>
         
     | 
| 
      
 586 
     | 
    
         
            +
                  <%= user.name %>
         
     | 
| 
      
 587 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 588 
     | 
    
         
            +
                <%= tramway_cell do %>
         
     | 
| 
      
 589 
     | 
    
         
            +
                  <%= user.email %>
         
     | 
| 
      
 590 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 591 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 592 
     | 
    
         
            +
            <% end %>
         
     | 
| 
       554 
593 
     | 
    
         
             
            ```
         
     | 
| 
       555 
594 
     | 
    
         | 
| 
       556 
595 
     | 
    
         
             
            When you render a header you can either pass the `headers:` array, as in the examples above, or render custom header content in
         
     | 
| 
         @@ -558,18 +597,48 @@ the block. `Tailwinds::Table::HeaderComponent` uses the length of the `headers` 
     | 
|
| 
       558 
597 
     | 
    
         
             
            If you omit the array and provide custom content, pass the `columns:` argument so the component knows how many grid columns to
         
     | 
| 
       559 
598 
     | 
    
         
             
            generate.
         
     | 
| 
       560 
599 
     | 
    
         | 
| 
       561 
     | 
    
         
            -
            ``` 
     | 
| 
       562 
     | 
    
         
            -
             
     | 
| 
       563 
     | 
    
         
            -
               
     | 
| 
      
 600 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 601 
     | 
    
         
            +
            <%= component 'tailwinds/table/header', columns: 4 do %>
         
     | 
| 
      
 602 
     | 
    
         
            +
              <%= tramway_cell do %>
         
     | 
| 
       564 
603 
     | 
    
         
             
                Custom header cell
         
     | 
| 
       565 
     | 
    
         
            -
               
     | 
| 
      
 604 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 605 
     | 
    
         
            +
              <%= tramway_cell do %>
         
     | 
| 
       566 
606 
     | 
    
         
             
                Another header cell
         
     | 
| 
       567 
     | 
    
         
            -
               
     | 
| 
      
 607 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 608 
     | 
    
         
            +
              <!-- ... -->
         
     | 
| 
      
 609 
     | 
    
         
            +
            <% end %>
         
     | 
| 
       568 
610 
     | 
    
         
             
            ```
         
     | 
| 
       569 
611 
     | 
    
         | 
| 
       570 
612 
     | 
    
         
             
            With this approach you control the header layout while still benefiting from the default Tailwind grid classes that the header
         
     | 
| 
       571 
613 
     | 
    
         
             
            component applies.
         
     | 
| 
       572 
614 
     | 
    
         | 
| 
      
 615 
     | 
    
         
            +
            ### Tramway Buttons and Containers
         
     | 
| 
      
 616 
     | 
    
         
            +
             
     | 
| 
      
 617 
     | 
    
         
            +
            Tramway ships with helpers for common UI patterns built on top of Tailwind components.
         
     | 
| 
      
 618 
     | 
    
         
            +
             
     | 
| 
      
 619 
     | 
    
         
            +
            * `tramway_button` renders a button-styled link and accepts `path`, optional `text`, HTTP `method`, and styling options such as
         
     | 
| 
      
 620 
     | 
    
         
            +
              `color`, `type`, and `size`. All additional keyword arguments are forwarded to the underlying component as HTML attributes.
         
     | 
| 
      
 621 
     | 
    
         
            +
             
     | 
| 
      
 622 
     | 
    
         
            +
              ```erb
         
     | 
| 
      
 623 
     | 
    
         
            +
              <%= tramway_button path: user_path(user), text: 'View profile', color: :emerald, data: { turbo: false } %>
         
     | 
| 
      
 624 
     | 
    
         
            +
              ```
         
     | 
| 
      
 625 
     | 
    
         
            +
             
     | 
| 
      
 626 
     | 
    
         
            +
            * `tramway_back_button` renders a standardized "Back" link.
         
     | 
| 
      
 627 
     | 
    
         
            +
             
     | 
| 
      
 628 
     | 
    
         
            +
              ```erb
         
     | 
| 
      
 629 
     | 
    
         
            +
              <%= tramway_back_button %>
         
     | 
| 
      
 630 
     | 
    
         
            +
              ```
         
     | 
| 
      
 631 
     | 
    
         
            +
             
     | 
| 
      
 632 
     | 
    
         
            +
            * `tramway_container` wraps content in a responsive, narrow layout container. Pass an `id` if you need to target the container
         
     | 
| 
      
 633 
     | 
    
         
            +
              with JavaScript or CSS.
         
     | 
| 
      
 634 
     | 
    
         
            +
             
     | 
| 
      
 635 
     | 
    
         
            +
              ```erb
         
     | 
| 
      
 636 
     | 
    
         
            +
              <%= tramway_container id: 'user-settings' do %>
         
     | 
| 
      
 637 
     | 
    
         
            +
                <h2 class="text-xl font-semibold">Settings</h2>
         
     | 
| 
      
 638 
     | 
    
         
            +
                <p class="mt-2 text-gray-600">Update your preferences below.</p>
         
     | 
| 
      
 639 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 640 
     | 
    
         
            +
              ```
         
     | 
| 
      
 641 
     | 
    
         
            +
             
     | 
| 
       573 
642 
     | 
    
         
             
            ### Tailwind-styled forms
         
     | 
| 
       574 
643 
     | 
    
         | 
| 
       575 
644 
     | 
    
         
             
            Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are implemented with [ViewComponent](https://github.com/viewcomponent/view_component).
         
     | 
| 
         @@ -578,26 +647,56 @@ Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are 
     | 
|
| 
       578 
647 
     | 
    
         | 
| 
       579 
648 
     | 
    
         
             
            Tramway provides `tramway_form_for` helper that renders Tailwind-styled forms by default.
         
     | 
| 
       580 
649 
     | 
    
         | 
| 
       581 
     | 
    
         
            -
            ``` 
     | 
| 
       582 
     | 
    
         
            -
             
     | 
| 
       583 
     | 
    
         
            -
               
     | 
| 
       584 
     | 
    
         
            -
               
     | 
| 
       585 
     | 
    
         
            -
               
     | 
| 
       586 
     | 
    
         
            -
               
     | 
| 
       587 
     | 
    
         
            -
               
     | 
| 
       588 
     | 
    
         
            -
               
     | 
| 
      
 650 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 651 
     | 
    
         
            +
            <%= tramway_form_for @user do |f| %>
         
     | 
| 
      
 652 
     | 
    
         
            +
              <%= f.text_field :text %>
         
     | 
| 
      
 653 
     | 
    
         
            +
              <%= f.email_field :email %>
         
     | 
| 
      
 654 
     | 
    
         
            +
              <%= f.password_field :password %>
         
     | 
| 
      
 655 
     | 
    
         
            +
              <%= f.select :role, [:admin, :user] %>
         
     | 
| 
      
 656 
     | 
    
         
            +
              <%= f.multiselect :permissions, [['Create User', 'create_user'], ['Update user', 'update_user']] %>
         
     | 
| 
      
 657 
     | 
    
         
            +
              <%= f.file_field :file %>
         
     | 
| 
      
 658 
     | 
    
         
            +
              <%= f.submit 'Create User' %>
         
     | 
| 
      
 659 
     | 
    
         
            +
            <% end %>
         
     | 
| 
       589 
660 
     | 
    
         
             
            ```
         
     | 
| 
       590 
661 
     | 
    
         | 
| 
       591 
662 
     | 
    
         
             
            will render [this](https://play.tailwindcss.com/xho3LfjKkK)
         
     | 
| 
       592 
663 
     | 
    
         | 
| 
       593 
664 
     | 
    
         
             
            Available form helpers:
         
     | 
| 
       594 
665 
     | 
    
         
             
            * text_field
         
     | 
| 
      
 666 
     | 
    
         
            +
            * email_field
         
     | 
| 
       595 
667 
     | 
    
         
             
            * password_field
         
     | 
| 
       596 
668 
     | 
    
         
             
            * file_field
         
     | 
| 
       597 
669 
     | 
    
         
             
            * select
         
     | 
| 
       598 
670 
     | 
    
         
             
            * multiselect ([Stimulus-based](https://github.com/Purple-Magic/tramway#stimulus-based-inputs))
         
     | 
| 
       599 
671 
     | 
    
         
             
            * submit
         
     | 
| 
       600 
672 
     | 
    
         | 
| 
      
 673 
     | 
    
         
            +
            **Examples**
         
     | 
| 
      
 674 
     | 
    
         
            +
             
     | 
| 
      
 675 
     | 
    
         
            +
            1. Sign In Form for `devise` authentication
         
     | 
| 
      
 676 
     | 
    
         
            +
             
     | 
| 
      
 677 
     | 
    
         
            +
            *app/views/devise/sessions/new.html.erb*
         
     | 
| 
      
 678 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 679 
     | 
    
         
            +
            <%= tramway_form_for(resource, as: resource_name, url: session_path(resource_name), class: 'bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4') do |f| %>
         
     | 
| 
      
 680 
     | 
    
         
            +
              <%= component 'forms/errors', record: resource %>
         
     | 
| 
      
 681 
     | 
    
         
            +
             
     | 
| 
      
 682 
     | 
    
         
            +
              <%= f.text_field :email, placeholder: 'Your email' %>
         
     | 
| 
      
 683 
     | 
    
         
            +
              <%= f.password_field :password, placeholder: 'Your password' %>
         
     | 
| 
      
 684 
     | 
    
         
            +
             
     | 
| 
      
 685 
     | 
    
         
            +
              <%= f.submit 'Sign In' %>
         
     | 
| 
      
 686 
     | 
    
         
            +
            <% end %>
         
     | 
| 
      
 687 
     | 
    
         
            +
            ```
         
     | 
| 
      
 688 
     | 
    
         
            +
             
     | 
| 
      
 689 
     | 
    
         
            +
            2. Sign In Form for Rails authorization
         
     | 
| 
      
 690 
     | 
    
         
            +
             
     | 
| 
      
 691 
     | 
    
         
            +
            *app/views/sessions/new.html.erb*
         
     | 
| 
      
 692 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 693 
     | 
    
         
            +
            <%= form_with url: login_path, scope: :session, local: true, builder: Tailwinds::Form::Builder do |form| %>
         
     | 
| 
      
 694 
     | 
    
         
            +
              <%= form.email_field :email %>
         
     | 
| 
      
 695 
     | 
    
         
            +
              <%= form.password_field :password %>
         
     | 
| 
      
 696 
     | 
    
         
            +
              <%= form.submit 'Log in' %>
         
     | 
| 
      
 697 
     | 
    
         
            +
            <% end %>
         
     | 
| 
      
 698 
     | 
    
         
            +
            ```
         
     | 
| 
      
 699 
     | 
    
         
            +
             
     | 
| 
       601 
700 
     | 
    
         
             
            #### Stimulus-based inputs
         
     | 
| 
       602 
701 
     | 
    
         | 
| 
       603 
702 
     | 
    
         
             
            `tramway_form_for` provides Tailwind-styled Stimulus-based custom inputs.
         
     | 
| 
         @@ -606,10 +705,11 @@ Available form helpers: 
     | 
|
| 
       606 
705 
     | 
    
         | 
| 
       607 
706 
     | 
    
         
             
            In case you want to use tailwind-styled multiselect this way
         
     | 
| 
       608 
707 
     | 
    
         | 
| 
       609 
     | 
    
         
            -
            ``` 
     | 
| 
       610 
     | 
    
         
            -
             
     | 
| 
       611 
     | 
    
         
            -
               
     | 
| 
       612 
     | 
    
         
            -
               
     | 
| 
      
 708 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 709 
     | 
    
         
            +
            <%= tramway_form_for @user do |f| %>
         
     | 
| 
      
 710 
     | 
    
         
            +
              <%= f.multiselect :permissions, [['Create User', 'create_user'], ['Update user', 'update_user']] %>
         
     | 
| 
      
 711 
     | 
    
         
            +
              <%# ... %>
         
     | 
| 
      
 712 
     | 
    
         
            +
            <% end %>
         
     | 
| 
       613 
713 
     | 
    
         
             
            ```
         
     | 
| 
       614 
714 
     | 
    
         | 
| 
       615 
715 
     | 
    
         
             
            you should add Tramway Multiselect Stimulus controller to your application.
         
     | 
| 
         @@ -633,9 +733,10 @@ application.register('multiselect', Multiselect) // register Multiselect control 
     | 
|
| 
       633 
733 
     | 
    
         | 
| 
       634 
734 
     | 
    
         
             
            Use Stimulus `change` action with Tramway Multiselect
         
     | 
| 
       635 
735 
     | 
    
         | 
| 
       636 
     | 
    
         
            -
            ``` 
     | 
| 
       637 
     | 
    
         
            -
             
     | 
| 
       638 
     | 
    
         
            -
               
     | 
| 
      
 736 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 737 
     | 
    
         
            +
            <%= tramway_form_for @user do |f| %>
         
     | 
| 
      
 738 
     | 
    
         
            +
              <%= f.multiselect :role, data: { action: 'change->user-form#updateForm' } %>
         
     | 
| 
      
 739 
     | 
    
         
            +
            <% end %>
         
     | 
| 
       639 
740 
     | 
    
         
             
            ```
         
     | 
| 
       640 
741 
     | 
    
         | 
| 
       641 
742 
     | 
    
         
             
            ### Tailwind-styled pagination for Kaminari
         
     | 
| 
         @@ -657,9 +758,9 @@ Tramway.configure do |config| 
     | 
|
| 
       657 
758 
     | 
    
         
             
            end
         
     | 
| 
       658 
759 
     | 
    
         
             
            ```
         
     | 
| 
       659 
760 
     | 
    
         | 
| 
       660 
     | 
    
         
            -
            *app/views/users/index.html. 
     | 
| 
       661 
     | 
    
         
            -
            ``` 
     | 
| 
       662 
     | 
    
         
            -
             
     | 
| 
      
 761 
     | 
    
         
            +
            *app/views/users/index.html.erb*
         
     | 
| 
      
 762 
     | 
    
         
            +
            ```erb
         
     | 
| 
      
 763 
     | 
    
         
            +
            <%= paginate @users %> <%# it will render tailwind-styled pagination buttons by default %>
         
     | 
| 
       663 
764 
     | 
    
         
             
            ```
         
     | 
| 
       664 
765 
     | 
    
         | 
| 
       665 
766 
     | 
    
         
             
            Pagination buttons looks like [this](https://play.tailwindcss.com/mqgDS5l9oY)
         
     | 
| 
         @@ -680,11 +781,41 @@ user_2 = tramway_form User.first 
     | 
|
| 
       680 
781 
     | 
    
         
             
            user_2.object #=> returns pure user object
         
     | 
| 
       681 
782 
     | 
    
         
             
            ```
         
     | 
| 
       682 
783 
     | 
    
         | 
| 
      
 784 
     | 
    
         
            +
            ## Configuration
         
     | 
| 
      
 785 
     | 
    
         
            +
             
     | 
| 
      
 786 
     | 
    
         
            +
            ### Custom layout
         
     | 
| 
      
 787 
     | 
    
         
            +
             
     | 
| 
      
 788 
     | 
    
         
            +
            In case you wanna use a custom layout:
         
     | 
| 
      
 789 
     | 
    
         
            +
             
     | 
| 
      
 790 
     | 
    
         
            +
            1. Create a controller
         
     | 
| 
      
 791 
     | 
    
         
            +
            2. Set the layout there
         
     | 
| 
      
 792 
     | 
    
         
            +
            3. Set this controller as `application_controller` in Tramway initializer
         
     | 
| 
      
 793 
     | 
    
         
            +
            4. Reload your server
         
     | 
| 
      
 794 
     | 
    
         
            +
             
     | 
| 
      
 795 
     | 
    
         
            +
            **Example**
         
     | 
| 
      
 796 
     | 
    
         
            +
             
     | 
| 
      
 797 
     | 
    
         
            +
            *app/controllers/admin/application_controller.rb*
         
     | 
| 
      
 798 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 799 
     | 
    
         
            +
            class Admin::ApplicationController < ApplicationController
         
     | 
| 
      
 800 
     | 
    
         
            +
              layout 'admin/application'
         
     | 
| 
      
 801 
     | 
    
         
            +
            end
         
     | 
| 
      
 802 
     | 
    
         
            +
            ```
         
     | 
| 
      
 803 
     | 
    
         
            +
             
     | 
| 
      
 804 
     | 
    
         
            +
            *config/initializers/tramway.rb*
         
     | 
| 
      
 805 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 806 
     | 
    
         
            +
            Tramway.configure do |config|
         
     | 
| 
      
 807 
     | 
    
         
            +
              config.application_controller = 'Admin::ApplicationController'
         
     | 
| 
      
 808 
     | 
    
         
            +
            end
         
     | 
| 
      
 809 
     | 
    
         
            +
            ```
         
     | 
| 
      
 810 
     | 
    
         
            +
             
     | 
| 
       683 
811 
     | 
    
         
             
            ## Articles
         
     | 
| 
       684 
812 
     | 
    
         
             
            * [Tramway on Rails](https://kalashnikovisme.medium.com/tramway-on-rails-32158c35ed68)
         
     | 
| 
      
 813 
     | 
    
         
            +
            * [Tramway is the way to deal with little things for Rails developers](https://medium.com/@kalashnikovisme/tramway-is-the-way-to-deal-with-little-things-for-rails-developers-4f502172a18c)
         
     | 
| 
       685 
814 
     | 
    
         
             
            * [Delegating ActiveRecord methods to decorators in Rails](https://kalashnikovisme.medium.com/delegating-activerecord-methods-to-decorators-in-rails-4e4ec1c6b3a6)
         
     | 
| 
       686 
815 
     | 
    
         
             
            * [Behave as ActiveRecord. Why do we want objects to be AR lookalikes?](https://kalashnikovisme.medium.com/behave-as-activerecord-why-do-we-want-objects-to-be-ar-lookalikes-d494d692e1d3)
         
     | 
| 
       687 
816 
     | 
    
         
             
            * [Decorating associations in Rails with Tramway](https://kalashnikovisme.medium.com/decorating-associations-in-rails-with-tramway-b46a28392f9e)
         
     | 
| 
      
 817 
     | 
    
         
            +
            * [Easy-to-use Tailwind-styled multi-select built with Stimulus](https://medium.com/@kalashnikovisme/easy-to-use-tailwind-styled-multi-select-built-with-stimulus-b3daa9e307aa)
         
     | 
| 
      
 818 
     | 
    
         
            +
            * 
         
     | 
| 
       688 
819 
     | 
    
         | 
| 
       689 
820 
     | 
    
         
             
            ## Contributing
         
     | 
| 
       690 
821 
     | 
    
         | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            - if text.present?
         
     | 
| 
      
 2 
     | 
    
         
            +
              - if method == :get
         
     | 
| 
      
 3 
     | 
    
         
            +
                = link_to text, path, class: classes, **options.except(:class)
         
     | 
| 
      
 4 
     | 
    
         
            +
              - else
         
     | 
| 
      
 5 
     | 
    
         
            +
                = button_to text, path, method:, class: classes, **options.except(:class)
         
     | 
| 
      
 6 
     | 
    
         
            +
            - else
         
     | 
| 
      
 7 
     | 
    
         
            +
              - if method == :get
         
     | 
| 
      
 8 
     | 
    
         
            +
                = link_to path, class: classes, **options.except(:class) do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  = content
         
     | 
| 
      
 10 
     | 
    
         
            +
              - else
         
     | 
| 
      
 11 
     | 
    
         
            +
                = button_to path, method:, class: classes, **options.except(:class) do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  = content
         
     | 
| 
         @@ -0,0 +1,60 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tailwinds
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Default Tramway button
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              class ButtonComponent < BaseComponent
         
     | 
| 
      
 7 
     | 
    
         
            +
                option :text, optional: true, default: -> {}
         
     | 
| 
      
 8 
     | 
    
         
            +
                option :path
         
     | 
| 
      
 9 
     | 
    
         
            +
                option :color, default: -> { :blue }
         
     | 
| 
      
 10 
     | 
    
         
            +
                option :type, default: -> { :default }
         
     | 
| 
      
 11 
     | 
    
         
            +
                option :size, default: -> { :middle }
         
     | 
| 
      
 12 
     | 
    
         
            +
                option :method, optional: true, default: -> { :get }
         
     | 
| 
      
 13 
     | 
    
         
            +
                option :options, optional: true, default: -> { {} }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def size_classes
         
     | 
| 
      
 16 
     | 
    
         
            +
                  case size
         
     | 
| 
      
 17 
     | 
    
         
            +
                  when :small
         
     | 
| 
      
 18 
     | 
    
         
            +
                    'text-sm py-1 px-1'
         
     | 
| 
      
 19 
     | 
    
         
            +
                  when :middle
         
     | 
| 
      
 20 
     | 
    
         
            +
                    'py-2 px-4'
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def classes
         
     | 
| 
      
 25 
     | 
    
         
            +
                  (default_classes +
         
     | 
| 
      
 26 
     | 
    
         
            +
                    light_mode_classes +
         
     | 
| 
      
 27 
     | 
    
         
            +
                    dark_mode_classes +
         
     | 
| 
      
 28 
     | 
    
         
            +
                    (method == :get ? %w[px-1 h-fit] : ['cursor-pointer'])).compact.join(' ')
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def default_classes
         
     | 
| 
      
 32 
     | 
    
         
            +
                  [
         
     | 
| 
      
 33 
     | 
    
         
            +
                    'btn',
         
     | 
| 
      
 34 
     | 
    
         
            +
                    'btn-primary',
         
     | 
| 
      
 35 
     | 
    
         
            +
                    'font-bold',
         
     | 
| 
      
 36 
     | 
    
         
            +
                    'rounded-sm',
         
     | 
| 
      
 37 
     | 
    
         
            +
                    'flex',
         
     | 
| 
      
 38 
     | 
    
         
            +
                    'flex-row',
         
     | 
| 
      
 39 
     | 
    
         
            +
                    size_classes.to_s,
         
     | 
| 
      
 40 
     | 
    
         
            +
                    options[:class].to_s
         
     | 
| 
      
 41 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def light_mode_classes
         
     | 
| 
      
 45 
     | 
    
         
            +
                  [
         
     | 
| 
      
 46 
     | 
    
         
            +
                    "bg-#{color}-500",
         
     | 
| 
      
 47 
     | 
    
         
            +
                    "hover:bg-#{color}-700",
         
     | 
| 
      
 48 
     | 
    
         
            +
                    'text-white'
         
     | 
| 
      
 49 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def dark_mode_classes
         
     | 
| 
      
 53 
     | 
    
         
            +
                  [
         
     | 
| 
      
 54 
     | 
    
         
            +
                    "dark:bg-#{color}-600",
         
     | 
| 
      
 55 
     | 
    
         
            +
                    "dark:hover:bg-#{color}-800",
         
     | 
| 
      
 56 
     | 
    
         
            +
                    'dark:text-gray-300'
         
     | 
| 
      
 57 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -11,34 +11,33 @@ module Tailwinds 
     | 
|
| 
       11 
11 
     | 
    
         
             
                    @form_size = options[:size] || options['size'] || :middle
         
     | 
| 
       12 
12 
     | 
    
         
             
                  end
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
                  def  
     | 
| 
      
 14 
     | 
    
         
            +
                  def common_field(component_name, input_method, attribute, **options, &)
         
     | 
| 
       15 
15 
     | 
    
         
             
                    sanitized_options = sanitize_options(options)
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
                     
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
      
 17 
     | 
    
         
            +
                    component_class = "Tailwinds::Form::#{component_name.to_s.camelize}Component".constantize
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    render(component_class.new(
         
     | 
| 
      
 20 
     | 
    
         
            +
                             input: input(input_method),
         
     | 
| 
       19 
21 
     | 
    
         
             
                             value: get_value(attribute, sanitized_options),
         
     | 
| 
       20 
22 
     | 
    
         
             
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       21 
     | 
    
         
            -
                           ), 
     | 
| 
      
 23 
     | 
    
         
            +
                           ),
         
     | 
| 
      
 24 
     | 
    
         
            +
                           &)
         
     | 
| 
       22 
25 
     | 
    
         
             
                  end
         
     | 
| 
       23 
26 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
                  def  
     | 
| 
       25 
     | 
    
         
            -
                     
     | 
| 
      
 27 
     | 
    
         
            +
                  def text_field(attribute, **, &)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    common_field(:text_field, :text_field, attribute, **, &)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
       26 
30 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                             value: get_value(attribute, sanitized_options),
         
     | 
| 
       30 
     | 
    
         
            -
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       31 
     | 
    
         
            -
                           ), &)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  def email_field(attribute, **, &)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    common_field(:text_field, :email_field, attribute, **, &)
         
     | 
| 
       32 
33 
     | 
    
         
             
                  end
         
     | 
| 
       33 
34 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                  def  
     | 
| 
       35 
     | 
    
         
            -
                     
     | 
| 
      
 35 
     | 
    
         
            +
                  def number_field(attribute, **, &)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    common_field(:number_field, :number_field, attribute, **, &)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
       36 
38 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                             value: get_value(attribute, sanitized_options),
         
     | 
| 
       40 
     | 
    
         
            -
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       41 
     | 
    
         
            -
                           ), &)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  def text_area(attribute, **, &)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    common_field(:text_area, :text_area, attribute, **, &)
         
     | 
| 
       42 
41 
     | 
    
         
             
                  end
         
     | 
| 
       43 
42 
     | 
    
         | 
| 
       44 
43 
     | 
    
         
             
                  def password_field(attribute, **options, &)
         
     | 
| 
         @@ -95,7 +94,7 @@ module Tailwinds 
     | 
|
| 
       95 
94 
     | 
    
         
             
                  end
         
     | 
| 
       96 
95 
     | 
    
         | 
| 
       97 
96 
     | 
    
         
             
                  def get_value(attribute, options)
         
     | 
| 
       98 
     | 
    
         
            -
                    options[:value] || object.public_send(attribute)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    options[:value] || (object.present? ? object.public_send(attribute) : nil)
         
     | 
| 
       99 
98 
     | 
    
         
             
                  end
         
     | 
| 
       100 
99 
     | 
    
         | 
| 
       101 
100 
     | 
    
         
             
                  def default_options(attribute, options)
         
     | 
| 
         @@ -17,12 +17,12 @@ 
     | 
|
| 
       17 
17 
     | 
    
         
             
                %p.text-center.mt-10
         
     | 
| 
       18 
18 
     | 
    
         
             
                  You should fill class-level method `self.list_attributes` inside your
         
     | 
| 
       19 
19 
     | 
    
         
             
                  = decorator
         
     | 
| 
      
 20 
     | 
    
         
            +
              - else
         
     | 
| 
      
 21 
     | 
    
         
            +
                = component 'tailwinds/table' do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  = component 'tailwinds/table/header', headers: list_attributes.map { |attribute| @model_class.human_attribute_name(attribute) }
         
     | 
| 
      
 23 
     | 
    
         
            +
                  - @entities.each do |item|
         
     | 
| 
      
 24 
     | 
    
         
            +
                    = render 'tramway/entities/entity', entity: item
         
     | 
| 
       20 
25 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                  = render 'tramway/entities/entity', entity: item
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                - if Tramway.config.pagination[:enabled]
         
     | 
| 
       27 
     | 
    
         
            -
                  .flex.mt-4
         
     | 
| 
       28 
     | 
    
         
            -
                    = paginate @entities, custom_path_method: "#{@model_class.model_name.plural}_path"
         
     | 
| 
      
 26 
     | 
    
         
            +
                  - if Tramway.config.pagination[:enabled]
         
     | 
| 
      
 27 
     | 
    
         
            +
                    .flex.mt-4
         
     | 
| 
      
 28 
     | 
    
         
            +
                      = paginate @entities, custom_path_method: "#{@model_class.model_name.plural}_path"
         
     | 
| 
         @@ -1 +1,2 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            =  
     | 
| 
      
 1 
     | 
    
         
            +
            = tramway_container do
         
     | 
| 
      
 2 
     | 
    
         
            +
              = render 'tramway/entities/list'
         
     | 
    
        data/config/tailwind.config.js
    CHANGED
    
    | 
         @@ -1,13 +1,25 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module.exports = {
         
     | 
| 
       2 
2 
     | 
    
         
             
              safelist: [
         
     | 
| 
      
 3 
     | 
    
         
            +
                // === Navbar ===
         
     | 
| 
      
 4 
     | 
    
         
            +
                'ml-4',
         
     | 
| 
      
 5 
     | 
    
         
            +
                
         
     | 
| 
      
 6 
     | 
    
         
            +
                // === Custom table layout utilities ===
         
     | 
| 
       3 
7 
     | 
    
         
             
                'div-table',
         
     | 
| 
       4 
8 
     | 
    
         
             
                'div-table-row',
         
     | 
| 
       5 
9 
     | 
    
         
             
                'div-table-cell',
         
     | 
| 
      
 10 
     | 
    
         
            +
                'sm:text-base',
         
     | 
| 
      
 11 
     | 
    
         
            +
                'last:border-b-0',
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                // === Visibility and typography helpers ===
         
     | 
| 
       6 
14 
     | 
    
         
             
                'hidden',
         
     | 
| 
      
 15 
     | 
    
         
            +
                'xl:hidden',
         
     | 
| 
       7 
16 
     | 
    
         
             
                'text-xl',
         
     | 
| 
       8 
17 
     | 
    
         
             
                'text-4xl',
         
     | 
| 
       9 
18 
     | 
    
         
             
                'font-bold',
         
     | 
| 
       10 
     | 
    
         
            -
                ' 
     | 
| 
      
 19 
     | 
    
         
            +
                'text-right',
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                // === Grid templates used for configurable layouts ===
         
     | 
| 
      
 22 
     | 
    
         
            +
                'grid',
         
     | 
| 
       11 
23 
     | 
    
         
             
                'grid-cols-1',
         
     | 
| 
       12 
24 
     | 
    
         
             
                'grid-cols-2',
         
     | 
| 
       13 
25 
     | 
    
         
             
                'grid-cols-3',
         
     | 
| 
         @@ -18,44 +30,112 @@ module.exports = { 
     | 
|
| 
       18 
30 
     | 
    
         
             
                'grid-cols-8',
         
     | 
| 
       19 
31 
     | 
    
         
             
                'grid-cols-9',
         
     | 
| 
       20 
32 
     | 
    
         
             
                'grid-cols-10',
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                 
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                // === Page container and alignment helpers ===
         
     | 
| 
      
 35 
     | 
    
         
            +
                'container',
         
     | 
| 
      
 36 
     | 
    
         
            +
                'mx-auto',
         
     | 
| 
      
 37 
     | 
    
         
            +
                'align-center',
         
     | 
| 
      
 38 
     | 
    
         
            +
                'justify-center',
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                // === Flexbox layout utilities ===
         
     | 
| 
       23 
41 
     | 
    
         
             
                'flex',
         
     | 
| 
       24 
     | 
    
         
            -
                ' 
     | 
| 
      
 42 
     | 
    
         
            +
                'flex-col',
         
     | 
| 
      
 43 
     | 
    
         
            +
                'flex-wrap',
         
     | 
| 
      
 44 
     | 
    
         
            +
                'flex-row-reverse',
         
     | 
| 
      
 45 
     | 
    
         
            +
                'flex-auto',
         
     | 
| 
      
 46 
     | 
    
         
            +
                'flex-initial',
         
     | 
| 
      
 47 
     | 
    
         
            +
                'justify-between',
         
     | 
| 
      
 48 
     | 
    
         
            +
                'justify-end',
         
     | 
| 
      
 49 
     | 
    
         
            +
                'space-x-1',
         
     | 
| 
      
 50 
     | 
    
         
            +
                'items-center',
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                // === Responsive visibility helpers ===
         
     | 
| 
      
 53 
     | 
    
         
            +
                'sm:hidden',
         
     | 
| 
      
 54 
     | 
    
         
            +
                'sm:flex',
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                // === Sizing utilities ===
         
     | 
| 
      
 57 
     | 
    
         
            +
                'w-2/3',
         
     | 
| 
      
 58 
     | 
    
         
            +
                'w-full',
         
     | 
| 
      
 59 
     | 
    
         
            +
                'w-fit',
         
     | 
| 
      
 60 
     | 
    
         
            +
                'w-8',
         
     | 
| 
      
 61 
     | 
    
         
            +
                'min-w-96',
         
     | 
| 
      
 62 
     | 
    
         
            +
                'max-w-full',
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                // === Spacing utilities ===
         
     | 
| 
      
 65 
     | 
    
         
            +
                'p-4',
         
     | 
| 
       25 
66 
     | 
    
         
             
                'px-6',
         
     | 
| 
       26 
     | 
    
         
            -
                'px-3',
         
     | 
| 
       27 
67 
     | 
    
         
             
                'px-4',
         
     | 
| 
      
 68 
     | 
    
         
            +
                'px-3',
         
     | 
| 
      
 69 
     | 
    
         
            +
                'py-8',
         
     | 
| 
       28 
70 
     | 
    
         
             
                'py-4',
         
     | 
| 
       29 
71 
     | 
    
         
             
                'py-2',
         
     | 
| 
       30 
72 
     | 
    
         
             
                'mb-2',
         
     | 
| 
       31 
     | 
    
         
            -
                ' 
     | 
| 
      
 73 
     | 
    
         
            +
                'mt-8',
         
     | 
| 
      
 74 
     | 
    
         
            +
                'mt-2',
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                // === Pagination styles ===
         
     | 
| 
      
 77 
     | 
    
         
            +
                'bg-white',
         
     | 
| 
      
 78 
     | 
    
         
            +
                'rounded-md',
         
     | 
| 
      
 79 
     | 
    
         
            +
                'hover:bg-purple-100',
         
     | 
| 
      
 80 
     | 
    
         
            +
                'hover:bg-gray-100',
         
     | 
| 
      
 81 
     | 
    
         
            +
                'hover:bg-gray-300',
         
     | 
| 
      
 82 
     | 
    
         
            +
                'hover:text-gray-800',
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                // === Dark mode pagination styles ===
         
     | 
| 
       32 
85 
     | 
    
         
             
                'dark:text-white',
         
     | 
| 
       33 
86 
     | 
    
         
             
                'dark:bg-gray-800',
         
     | 
| 
       34 
     | 
    
         
            -
                'dark:bg-gray-900',
         
     | 
| 
       35 
87 
     | 
    
         
             
                'dark:hover:bg-gray-700',
         
     | 
| 
      
 88 
     | 
    
         
            +
                'dark:bg-gray-900',
         
     | 
| 
       36 
89 
     | 
    
         
             
                'dark:bg-gray-700',
         
     | 
| 
       37 
90 
     | 
    
         
             
                'dark:text-gray-400',
         
     | 
| 
       38 
     | 
    
         
            -
                'dark:hover:bg-gray-700',
         
     | 
| 
       39 
91 
     | 
    
         
             
                'dark:hover:text-gray-400',
         
     | 
| 
       40 
     | 
    
         
            -
                ' 
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                 
     | 
| 
       43 
     | 
    
         
            -
                ' 
     | 
| 
       44 
     | 
    
         
            -
                ' 
     | 
| 
       45 
     | 
    
         
            -
                ' 
     | 
| 
       46 
     | 
    
         
            -
                ' 
     | 
| 
       47 
     | 
    
         
            -
                ' 
     | 
| 
       48 
     | 
    
         
            -
                ' 
     | 
| 
       49 
     | 
    
         
            -
                ' 
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
                 
     | 
| 
       52 
     | 
    
         
            -
                'mt-2',
         
     | 
| 
      
 92 
     | 
    
         
            +
                'dark:placeholder-gray-400',
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                // === Button and badge helpers ===
         
     | 
| 
      
 95 
     | 
    
         
            +
                'bg-purple-700',
         
     | 
| 
      
 96 
     | 
    
         
            +
                'rounded',
         
     | 
| 
      
 97 
     | 
    
         
            +
                'rounded-full',
         
     | 
| 
      
 98 
     | 
    
         
            +
                'rounded-t',
         
     | 
| 
      
 99 
     | 
    
         
            +
                'font-medium',
         
     | 
| 
      
 100 
     | 
    
         
            +
                'font-normal',
         
     | 
| 
      
 101 
     | 
    
         
            +
                'text-xs',
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                // === Form state helpers ===
         
     | 
| 
       53 
104 
     | 
    
         
             
                'disabled:bg-gray-100',
         
     | 
| 
       54 
105 
     | 
    
         
             
                'disabled:text-gray-400',
         
     | 
| 
       55 
106 
     | 
    
         
             
                'disabled:cursor-not-allowed',
         
     | 
| 
       56 
     | 
    
         
            -
                 
     | 
| 
       57 
     | 
    
         
            -
                'bg- 
     | 
| 
       58 
     | 
    
         
            -
                 
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
      
 107 
     | 
    
         
            +
                'mb-4',
         
     | 
| 
      
 108 
     | 
    
         
            +
                'bg-red-500',
         
     | 
| 
      
 109 
     | 
    
         
            +
                'hover:bg-red-700',
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                // === Multiselect dropdown positioning ===
         
     | 
| 
      
 112 
     | 
    
         
            +
                'absolute',
         
     | 
| 
      
 113 
     | 
    
         
            +
                'relative',
         
     | 
| 
      
 114 
     | 
    
         
            +
                'shadow',
         
     | 
| 
      
 115 
     | 
    
         
            +
                'top-11',
         
     | 
| 
      
 116 
     | 
    
         
            +
                'z-40',
         
     | 
| 
      
 117 
     | 
    
         
            +
                'left-0',
         
     | 
| 
      
 118 
     | 
    
         
            +
                'max-h-select',
         
     | 
| 
      
 119 
     | 
    
         
            +
                'overflow-y-auto',
         
     | 
| 
      
 120 
     | 
    
         
            +
                'cursor-pointer',
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                // === Multiselect option styling ===
         
     | 
| 
      
 123 
     | 
    
         
            +
                'border-b',
         
     | 
| 
      
 124 
     | 
    
         
            +
                'border',
         
     | 
| 
      
 125 
     | 
    
         
            +
                'border-l',
         
     | 
| 
      
 126 
     | 
    
         
            +
                'border-l-2',
         
     | 
| 
      
 127 
     | 
    
         
            +
                'border-transparent',
         
     | 
| 
      
 128 
     | 
    
         
            +
                'border-teal-300',
         
     | 
| 
      
 129 
     | 
    
         
            +
                'hover:border-teal-100',
         
     | 
| 
      
 130 
     | 
    
         
            +
                'bg-teal-100',
         
     | 
| 
      
 131 
     | 
    
         
            +
                'bg-transparent',
         
     | 
| 
      
 132 
     | 
    
         
            +
                'text-teal-700',
         
     | 
| 
      
 133 
     | 
    
         
            +
                'leading-6',
         
     | 
| 
      
 134 
     | 
    
         
            +
                'leading-none',
         
     | 
| 
      
 135 
     | 
    
         
            +
                'appearance-none',
         
     | 
| 
      
 136 
     | 
    
         
            +
                'outline-none',
         
     | 
| 
      
 137 
     | 
    
         
            +
                'h-full',
         
     | 
| 
      
 138 
     | 
    
         
            +
                'm-1',
         
     | 
| 
      
 139 
     | 
    
         
            +
                'hover:bg-teal-100',
         
     | 
| 
       60 
140 
     | 
    
         
             
              ],
         
     | 
| 
       61 
141 
     | 
    
         
             
            }
         
     | 
| 
         @@ -0,0 +1,133 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rails/generators'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'fileutils'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Tramway
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Generators
         
     | 
| 
      
 8 
     | 
    
         
            +
                # Running `rails generate tramway:install` will invoke this generator
         
     | 
| 
      
 9 
     | 
    
         
            +
                #
         
     | 
| 
      
 10 
     | 
    
         
            +
                class InstallGenerator < Rails::Generators::Base
         
     | 
| 
      
 11 
     | 
    
         
            +
                  desc 'Installs Tramway dependencies and Tailwind safelist configuration.'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def ensure_dependencies
         
     | 
| 
      
 14 
     | 
    
         
            +
                    missing_dependencies = gem_dependencies.reject do |dependency|
         
     | 
| 
      
 15 
     | 
    
         
            +
                      gemfile_contains?(dependency[:name])
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    return if missing_dependencies.empty?
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    append_to_file 'Gemfile', <<~GEMS
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                      # Tramway dependencies
         
     | 
| 
      
 23 
     | 
    
         
            +
                      #{missing_dependencies.pluck(:declaration).join("\n")}
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    GEMS
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  def ensure_tailwind_safelist
         
     | 
| 
      
 29 
     | 
    
         
            +
                    return create_tailwind_config unless File.exist?(tailwind_config_path)
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    source_entries = extract_safelist_entries(File.read(gem_tailwind_config_path))
         
     | 
| 
      
 32 
     | 
    
         
            +
                    target_content = File.read(tailwind_config_path)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    target_entries = extract_safelist_entries(target_content)
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    missing_entries = source_entries - target_entries
         
     | 
| 
      
 36 
     | 
    
         
            +
                    return if missing_entries.empty?
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    File.write(tailwind_config_path, insert_entries(target_content, missing_entries))
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def ensure_tailwind_application_stylesheet
         
     | 
| 
      
 42 
     | 
    
         
            +
                    path = tailwind_application_stylesheet_path
         
     | 
| 
      
 43 
     | 
    
         
            +
                    FileUtils.mkdir_p(File.dirname(path))
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    return create_file(path, "#{tailwind_css_import_line}\n") unless File.exist?(path)
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    content = File.read(path)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    return if content.include?(tailwind_css_import_line)
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    File.open(path, 'a') do |file|
         
     | 
| 
      
 51 
     | 
    
         
            +
                      file.write("\n") unless content.empty? || content.end_with?("\n")
         
     | 
| 
      
 52 
     | 
    
         
            +
                      file.write("#{tailwind_css_import_line}\n")
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  private
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  def gem_dependencies
         
     | 
| 
      
 59 
     | 
    
         
            +
                    @gem_dependencies ||= [
         
     | 
| 
      
 60 
     | 
    
         
            +
                      { name: 'haml-rails', declaration: 'gem "haml-rails"' },
         
     | 
| 
      
 61 
     | 
    
         
            +
                      { name: 'kaminari', declaration: 'gem "kaminari"' },
         
     | 
| 
      
 62 
     | 
    
         
            +
                      { name: 'view_component', declaration: 'gem "view_component"' },
         
     | 
| 
      
 63 
     | 
    
         
            +
                      { name: 'dry-initializer', declaration: "gem 'dry-initializer'" }
         
     | 
| 
      
 64 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  def gemfile_path
         
     | 
| 
      
 68 
     | 
    
         
            +
                    @gemfile_path ||= File.join(destination_root, 'Gemfile')
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  def gemfile_contains?(name)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    return false unless File.exist?(gemfile_path)
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                    content = File.read(gemfile_path)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    content.match?(/^\s*gem ['"]#{Regexp.escape(name)}['"]/)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  def tailwind_config_path
         
     | 
| 
      
 79 
     | 
    
         
            +
                    @tailwind_config_path ||= File.join(destination_root, 'config/tailwind.config.js')
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  def gem_tailwind_config_path
         
     | 
| 
      
 83 
     | 
    
         
            +
                    @gem_tailwind_config_path ||= File.expand_path('../../../../config/tailwind.config.js', __dir__)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  def tailwind_application_stylesheet_path
         
     | 
| 
      
 87 
     | 
    
         
            +
                    @tailwind_application_stylesheet_path ||= File.join(destination_root, 'app/assets/tailwind/application.css')
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  def tailwind_css_import_line
         
     | 
| 
      
 91 
     | 
    
         
            +
                    '@import "tailwindcss";'
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  def create_tailwind_config
         
     | 
| 
      
 95 
     | 
    
         
            +
                    create_file tailwind_config_path, File.read(gem_tailwind_config_path)
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  def extract_safelist_entries(content)
         
     | 
| 
      
 99 
     | 
    
         
            +
                    section = safelist_section(content)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    return [] if section.nil?
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    section.scan(/'([^']+)'/).flatten.map(&:strip).reject(&:empty?).uniq
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                  def safelist_section(content)
         
     | 
| 
      
 106 
     | 
    
         
            +
                    match = content.match(/safelist\s*:\s*\[(.*?)\]\s*,?/m)
         
     | 
| 
      
 107 
     | 
    
         
            +
                    match&.[](1)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  def insert_entries(content, entries)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    match = content.match(/safelist\s*:\s*\[(.*?)\](\s*,?)/m)
         
     | 
| 
      
 112 
     | 
    
         
            +
                    return content unless match
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                    closing_index = match.begin(0) + match[0].rindex(']')
         
     | 
| 
      
 115 
     | 
    
         
            +
                    indentation = closing_indentation(content, closing_index)
         
     | 
| 
      
 116 
     | 
    
         
            +
                    formatted_entries = entries.map { |entry| "#{indentation}'#{entry}',\n" }.join
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                    needs_leading_newline = content[closing_index - 1] != "\n"
         
     | 
| 
      
 119 
     | 
    
         
            +
                    insertion = String.new
         
     | 
| 
      
 120 
     | 
    
         
            +
                    insertion << "\n" if needs_leading_newline
         
     | 
| 
      
 121 
     | 
    
         
            +
                    insertion << formatted_entries
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                    content.dup.insert(closing_index, insertion)
         
     | 
| 
      
 124 
     | 
    
         
            +
                  end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                  def closing_indentation(content, index)
         
     | 
| 
      
 127 
     | 
    
         
            +
                    line_start = content.rindex("\n", index - 1) || 0
         
     | 
| 
      
 128 
     | 
    
         
            +
                    line = content[line_start..index]
         
     | 
| 
      
 129 
     | 
    
         
            +
                    line[/^\s*/] || '  '
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
                end
         
     | 
| 
      
 132 
     | 
    
         
            +
              end
         
     | 
| 
      
 133 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -12,6 +12,45 @@ module Tramway 
     | 
|
| 
       12 
12 
     | 
    
         
             
                      &
         
     | 
| 
       13 
13 
     | 
    
         
             
                    )
         
     | 
| 
       14 
14 
     | 
    
         
             
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def tramway_table(**options, &)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    component 'tailwinds/table', options:, &
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def tramway_row(**options, &)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    component 'tailwinds/table/row',
         
     | 
| 
      
 22 
     | 
    
         
            +
                              cells: options.delete(:cells),
         
     | 
| 
      
 23 
     | 
    
         
            +
                              href: options.delete(:href),
         
     | 
| 
      
 24 
     | 
    
         
            +
                              options:,
         
     | 
| 
      
 25 
     | 
    
         
            +
                              &
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  def tramway_cell(&)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    component 'tailwinds/table/cell', &
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def tramway_button(path:, text: nil, method: :get, **options)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    component 'tailwinds/button',
         
     | 
| 
      
 34 
     | 
    
         
            +
                              text:,
         
     | 
| 
      
 35 
     | 
    
         
            +
                              path:,
         
     | 
| 
      
 36 
     | 
    
         
            +
                              method:,
         
     | 
| 
      
 37 
     | 
    
         
            +
                              color: options.delete(:color),
         
     | 
| 
      
 38 
     | 
    
         
            +
                              type: options.delete(:type),
         
     | 
| 
      
 39 
     | 
    
         
            +
                              size: options.delete(:size),
         
     | 
| 
      
 40 
     | 
    
         
            +
                              options:
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def tramway_back_button
         
     | 
| 
      
 44 
     | 
    
         
            +
                    component 'tailwinds/back_button'
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def tramway_container(id: nil, &)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    if id.present?
         
     | 
| 
      
 49 
     | 
    
         
            +
                      component 'tailwinds/containers/narrow', id: id, &
         
     | 
| 
      
 50 
     | 
    
         
            +
                    else
         
     | 
| 
      
 51 
     | 
    
         
            +
                      component 'tailwinds/containers/narrow', &
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
       15 
54 
     | 
    
         
             
                end
         
     | 
| 
       16 
55 
     | 
    
         
             
              end
         
     | 
| 
       17 
56 
     | 
    
         
             
            end
         
     | 
    
        data/lib/tramway/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: tramway
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.6.0.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-10- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2025-10-26 00:00:00.000000000 Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: anyway_config
         
     | 
| 
         @@ -143,6 +143,13 @@ files: 
     | 
|
| 
       143 
143 
     | 
    
         
             
            - app/assets/javascripts/tramway/table_row_preview_controller.js
         
     | 
| 
       144 
144 
     | 
    
         
             
            - app/components/tailwind_component.html.haml
         
     | 
| 
       145 
145 
     | 
    
         
             
            - app/components/tailwind_component.rb
         
     | 
| 
      
 146 
     | 
    
         
            +
            - app/components/tailwinds/back_button_component.html.haml
         
     | 
| 
      
 147 
     | 
    
         
            +
            - app/components/tailwinds/back_button_component.rb
         
     | 
| 
      
 148 
     | 
    
         
            +
            - app/components/tailwinds/base_component.rb
         
     | 
| 
      
 149 
     | 
    
         
            +
            - app/components/tailwinds/button_component.html.haml
         
     | 
| 
      
 150 
     | 
    
         
            +
            - app/components/tailwinds/button_component.rb
         
     | 
| 
      
 151 
     | 
    
         
            +
            - app/components/tailwinds/containers/narrow_component.html.haml
         
     | 
| 
      
 152 
     | 
    
         
            +
            - app/components/tailwinds/containers/narrow_component.rb
         
     | 
| 
       146 
153 
     | 
    
         
             
            - app/components/tailwinds/form/builder.rb
         
     | 
| 
       147 
154 
     | 
    
         
             
            - app/components/tailwinds/form/file_field_component.html.haml
         
     | 
| 
       148 
155 
     | 
    
         
             
            - app/components/tailwinds/form/file_field_component.rb
         
     | 
| 
         @@ -214,6 +221,7 @@ files: 
     | 
|
| 
       214 
221 
     | 
    
         
             
            - app/views/tramway/layouts/application.html.haml
         
     | 
| 
       215 
222 
     | 
    
         
             
            - config/routes.rb
         
     | 
| 
       216 
223 
     | 
    
         
             
            - config/tailwind.config.js
         
     | 
| 
      
 224 
     | 
    
         
            +
            - lib/generators/tramway/install/install_generator.rb
         
     | 
| 
       217 
225 
     | 
    
         
             
            - lib/kaminari/helpers/tag.rb
         
     | 
| 
       218 
226 
     | 
    
         
             
            - lib/rules/turbo_html_attributes_rules.rb
         
     | 
| 
       219 
227 
     | 
    
         
             
            - lib/tasks/tramway_tasks.rake
         
     |