zutils 3.0.5 → 4.0.0

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.
@@ -0,0 +1,90 @@
1
+ <% list ||= [] %>
2
+ <% pagy ||= nil %>
3
+
4
+ <% using_kaminari = defined?(Kaminari) %>
5
+ <% using_pagy = pagy && defined?(Pagy) %>
6
+
7
+ <% current_page = params[:page].presence || 1 %>
8
+
9
+ <% per_page =
10
+ params[:items].presence ||
11
+ (using_kaminari ? Kaminari.config.default_per_page :
12
+ using_pagy ? Pagy::DEFAULT[:limit] :
13
+ 25) %>
14
+
15
+ <% sizes ||= [5, 10, 25, 50, 100, 250, 500] %>
16
+
17
+ <div
18
+ class="
19
+ d-flex flex-column flex-md-row align-items-start justify-content-between
20
+ gap-2 mb-2
21
+ "
22
+ >
23
+ <div class="text-muted small mb-1 mb-md-0 text-nowrap">
24
+ <% if using_kaminari %>
25
+ <%= page_entries_info list, entry_name: '' %>
26
+ <% elsif using_pagy %>
27
+ <%== pagy_info pagy %>
28
+ <% end %>
29
+ </div>
30
+
31
+ <%= form_with method: :get, local: true, id: "pagination-form",
32
+ class: "w-100 w-sm-auto d-flex justify-content-center justify-content-md-end" do %>
33
+ <% request.query_parameters.except("page", "items").each do |key, value| %>
34
+ <% if value.is_a?(Array) %>
35
+ <% value.each do |v| %>
36
+ <%= hidden_field_tag "#{key}[]", v %>
37
+ <% end %>
38
+ <% elsif value.is_a?(Hash) %>
39
+ <% value.each do |k, v| %>
40
+ <% if v.is_a?(Array) %>
41
+ <% v.each do |vv| %>
42
+ <%= hidden_field_tag "#{key}[#{k}][]", vv %>
43
+ <% end %>
44
+ <% else %>
45
+ <%= hidden_field_tag "#{key}[#{k}]", v %>
46
+ <% end %>
47
+ <% end %>
48
+ <% else %>
49
+ <%= hidden_field_tag key, value %>
50
+ <% end %>
51
+ <% end %>
52
+
53
+ <div
54
+ class="
55
+ d-flex flex-column flex-md-row align-items-start
56
+ align-items-md-center gap-2
57
+ "
58
+ >
59
+ <div
60
+ class="
61
+ d-flex w-100 w-md-auto justify-content-between gap-2 order-2
62
+ order-md-1
63
+ "
64
+ >
65
+ <div class="d-flex align-items-center gap-1">
66
+ <div class="text-muted small">pag</div>
67
+ <%= number_field_tag :page, current_page, min: 1, class: "form-control", style: "width: 80px;" %>
68
+ </div>
69
+
70
+ <div class="d-flex align-items-center gap-1">
71
+ <%= select_tag :items,
72
+ options_for_select(sizes, per_page),
73
+ class: "form-select",
74
+ style: "width: 100px;",
75
+ onchange: "this.form.submit();" %>
76
+
77
+ <div class="text-muted small">p/pag</div>
78
+ </div>
79
+ </div>
80
+
81
+ <div class="mt-2 mt-md-0 order-1 order-md-2 align-self-center">
82
+ <% if using_kaminari %>
83
+ <%= paginate list, window: 1 %>
84
+ <% elsif using_pagy %>
85
+ <%== defined?(pagy_bootstrap_nav) ? pagy_bootstrap_nav(pagy) : pagy_nav(pagy) %>
86
+ <% end %>
87
+ </div>
88
+ </div>
89
+ <% end %>
90
+ </div>
@@ -1,52 +1,97 @@
1
- <% card_color ||= 'danger' %>
2
- <% search_object ||= @q%>
3
- <% default_field = {name: :id_eq, attrs: {label: false, required: false, placeholder: 'ID', wrapper: false}} %>
4
- <% received_field = defined?(main_field) ? main_field : {} %>
5
- <% main_field = default_field.deep_merge(received_field) %>
1
+ <% card_color ||= 'primary' %>
2
+ <% search_object ||= @q %>
6
3
  <% opened ||= false %>
4
+
7
5
  <%= search_form_for search_object, url: url do |f| %>
8
- <div class="card card-outline card-<%= card_color %>" data-controller='filtering'>
9
- <div class="card-header with-border">
10
- <div class="input-group">
11
- <div class="input-group-prepend">
12
- <button type="button" class="btn btn-<%= card_color %>" data-action="click->filtering#toggle">
13
- <% if opened %>
14
- <i class="fa fa-fw fa-angle-down" data-filtering-target='icon'></i>
15
- <% else %>
16
- <i class="fa fa-fw fa-angle-right" data-filtering-target='icon'></i>
17
- <% end %>
18
- <span class="d-none d-sm-inline-block">
19
- Filtrar
20
- </span>
6
+ <div
7
+ class="card shadow-sm border rounded-2 mb-3 bg-body"
8
+ data-controller="filtering"
9
+ data-filtering-opened-value="<%= opened %>"
10
+ >
11
+ <div class="card-header bg-transparent border-0 pt-3 pb-0 px-3">
12
+ <h6 class="mb-0 fw-bold text-secondary">
13
+ <i class="fa fa-search me-2 opacity-50"></i>
14
+ Pesquisar
15
+ </h6>
16
+ </div>
17
+
18
+ <div class="card-body p-3">
19
+ <div class="d-flex align-items-center w-100">
20
+ <button
21
+ type="button"
22
+ class="btn bg-secondary-subtle px-0 rounded-circle me-2 flex-shrink-0"
23
+ style="width: 42px; height: 42px;"
24
+ data-action="click->filtering#toggle"
25
+ title="Filtros Avançados"
26
+ >
27
+ <i
28
+ class="fa <%= opened ? 'fa-angle-down' : 'fa-sliders-h' %>"
29
+ data-filtering-target="icon"
30
+ ></i>
31
+ </button>
32
+
33
+ <div class="flex-grow-1 position-relative d-flex align-items-center">
34
+ <% main_field_name = defined?(main_field) ? main_field[:name] : :id_eq
35
+ main_attrs = {
36
+ label: false,
37
+ required: false,
38
+ placeholder: 'ID',
39
+ wrapper: false,
40
+ input_html: { class: 'form-control pe-5' }
41
+ }.deep_merge(defined?(main_field) ? (main_field[:attrs] || {}) : {}) %>
42
+
43
+ <%= f.input main_field_name, main_attrs %>
44
+
45
+ <button
46
+ type="submit"
47
+ class="
48
+ btn border-0 position-absolute end-0 me-2 p-2 text-secondary
49
+ d-flex align-items-center justify-content-center
50
+ "
51
+ style="background: transparent; z-index: 5;"
52
+ >
53
+ <i class="fa fa-search fs-5"></i>
21
54
  </button>
22
55
  </div>
23
- <%= f.input (main_field&.dig(:name) || :id_eq), main_field&.dig(:attrs) %>
24
- <div class="input-group-append">
25
- <%= button_tag type: "submit", class: "btn btn-#{card_color}" do %>
26
- <i class="fa fa-search"></i>
27
- <span class="d-none d-sm-inline-block">
28
- Buscar
29
- </span>
30
- <% end %>
31
- </div>
32
- </div>
33
- <div class="row">
34
- <div class="col-md-12 active-filters" data-filtering-target='filters'></div>
35
56
  </div>
57
+
58
+ <div
59
+ class="active-filters d-flex gap-1 flex-wrap pt-2 ps-5"
60
+ data-filtering-target="filters"
61
+ style="margin-top: -5px;"
62
+ ></div>
36
63
  </div>
37
- <div class="card-body" style='<%= 'display: none;' unless opened %>' data-filtering-target='body'>
64
+
65
+ <div
66
+ class="card-body pt-0 collapse <%= 'show' if opened %>"
67
+ data-filtering-target="body"
68
+ >
69
+ <div class="d-flex align-items-center">
70
+ <h6 class="mb-0 fw-bold">
71
+ <i class="fa fa-filter me-2 opacity-50"></i>
72
+ Filtros Detalhados
73
+ </h6>
74
+
75
+ <hr class="flex-grow-1 ms-3 opacity-10 border-black">
76
+ </div>
77
+
38
78
  <div class="row">
39
79
  <% search_fields ||= [] %>
80
+
40
81
  <% search_fields.each do |sf| %>
41
- <% default_attrs = {required: false, wrapper_html: {class: "col-md-3"}} %>
42
- <% received_attrs = sf.dig(:attrs) || {} %>
43
- <% attrs = default_attrs.deep_merge(received_attrs) %>
44
- <%= f.input sf.dig(:name), attrs %>
82
+ <% field_attrs = { required: false, wrapper_html: {class: "col-md-3"} }.deep_merge(sf[:attrs] || {}) %>
83
+
84
+ <%= f.input sf[:name], field_attrs %>
85
+ <% end %>
86
+ </div>
87
+
88
+ <div class="d-flex justify-content-end align-items-center gap-2">
89
+ <%= link_to "Limpar", url, class: "btn btn-link btn-sm text-decoration-none text-muted" %>
90
+
91
+ <%= button_tag type: "submit", class: "btn btn-sm btn-#{card_color} px-4" do %>
92
+ Aplicar
45
93
  <% end %>
46
94
  </div>
47
- <%= button_tag type: "submit", class: "btn btn-#{card_color}" do %>
48
- <i class="fa fa-search"></i> Buscar
49
- <% end %>
50
95
  </div>
51
96
  </div>
52
- <% end %>
97
+ <% end %>
@@ -5,209 +5,106 @@
5
5
  <% nested_resource ||= false %>
6
6
  <% relationships ||= {} %>
7
7
 
8
- <% card_color ||= 'danger' %>
9
- <% hide ||= %w[show delete] %>
10
- <% size ||= "xs" %>
8
+ <% color ||= 'primary' %>
9
+ <% hide ||= %w[new show] %>
10
+ <% size ||= "sm" %>
11
+ <% buttons_size ||= "md" %>
11
12
 
12
- <% new_color ||= 'primary' %>
13
- <% edit_color ||= 'warning' %>
14
- <% delete_color ||= 'danger' %>
13
+ <% edit_color ||= 'btn-warning' %>
14
+ <% delete_color ||= 'btn-outline-danger' %>
15
15
 
16
16
  <% if show_columns.empty? %>
17
17
  <% form_fields ||= (object.class.respond_to?('form_fields') ? object.class.form_fields : {}) %>
18
18
  <% form_ordered_fields ||= (form_fields.empty? ? object.class.column_names : form_fields.keys) %>
19
- <% show_columns = form_ordered_fields - ['id', 'created_at', 'updated_at', 'deleted_at'] - excluded_columns + additional_columns %>
19
+ <% show_columns = form_ordered_fields - ['id','created_at','updated_at','deleted_at'] - excluded_columns + additional_columns %>
20
20
  <% end %>
21
21
 
22
- <div class="card card-outline card-<%= card_color %>">
23
- <div class="card-header">
24
- <div class="row align-items-center">
25
- <div class="col-12 col-md-auto">
26
- <h3 class="card-title">
27
- <strong>
28
- <i class="fa fa<%= object.class.icon %>"></i>
29
- Visualizar <%=t object.class.model_name.human %>
30
- </strong>
31
- </h3>
32
- </div>
33
- <div class="col-12 col-md mr-auto">
34
- <% if can? :manage, object %>
35
- <%= render "shared/btn_action_links", size: "xs", object: object, labels: true, hide: hide, new_color: new_color, edit_color: edit_color, delete_color: delete_color %>
36
- <% end %>
22
+ <% unless hide.include? "top_bar" %>
23
+ <div class="card border-0 border-top border-4 border-<%= color %> shadow-sm mb-0 rounded-bottom-0">
24
+ <div class="card-header bg-body-tertiary border-bottom-0">
25
+ <div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
26
+ <h5 class="mb-0">
27
+ <i class="<%= object.class.icon %>"></i>
28
+ <%= t object.class.model_name.human %>
29
+ </h5>
37
30
  </div>
38
31
  </div>
39
32
  </div>
40
- </div>
33
+ <% end %>
34
+
41
35
  <% if lookup_context.find_all("#{object.class.model_name.plural}/_#{object.class.model_name.singular}").any? %>
42
- <%= render object %>
36
+ <div class="mb-3"><%= render object %></div>
43
37
  <% else %>
44
- <div class="card card-outline card-<%= card_color %>">
45
- <div class="card-body p-0">
46
- <table class="table table-bordered table-striped p-0">
38
+ <div class="card shadow-sm border-0 rounded-0 rounded-bottom mb-3">
39
+ <div class="card-body p-1" data-controller="bootstrap-table">
40
+ <table class="table table-striped table-hover align-middle mb-0">
47
41
  <thead>
48
42
  <tr>
49
- <th width='15%'>Campo</th>
43
+ <th data-width="20" data-width-unit="%">Campo</th>
50
44
  <th>Valor</th>
51
45
  </tr>
52
46
  </thead>
53
- <% show_columns.each do |column| %>
54
- <% unless /_currency$/ =~ column %>
55
- <tr>
56
- <th>
57
- <% if /_id$/ =~ column && object.respond_to?(column.split('_id')[0]) %>
58
- <%= object.class.human_attribute_name(column.split("_id")[0]) %>
59
- <% elsif /_cents$/ =~ column %>
60
- <%= object.class.human_attribute_name(column.split("_cents")[0]) %>
61
- <% else %>
62
- <%= object.class.human_attribute_name(column) %>
63
- <% end %>
64
- </th>
65
- <td>
66
- <% if column.to_s.include?('.') %>
67
- <% o = object %>
68
- <% column.split('.').each{|m| o = o.send(m) if o } %>
69
- <%= o %>
70
- <% elsif object.send(column).class == Date or
71
- object.send(column).class == DateTime or
72
- object.send(column).class == ActiveSupport::TimeWithZone or
73
- object.send(column).class == Time %>
74
- <%=l object.send(column) %>
75
- <% elsif object.send(column).respond_to? 'attached?' %>
76
- <% if object.send(column).class == ActiveStorage::Attached::One %>
77
- <% if object.send(column).attached? %>
78
- <%= link_to rails_blob_path(object.send(column)), class: "btn btn-#{card_color} btn-xs", target: '_blank' do %>
79
- <i class="fa fa-file-o"></i> Arquivo
47
+
48
+ <tbody>
49
+ <% show_columns.each do |column| %>
50
+ <% value = object.send(column) %>
51
+
52
+ <% unless /_currency$/ =~ column %>
53
+ <tr>
54
+ <th class="fw-semibold">
55
+ <% if /_id$/ =~ column && object.respond_to?(column.split('_id')[0]) %>
56
+ <%= object.class.human_attribute_name(column.split("_id")[0]) %>
57
+ <% elsif /_cents$/ =~ column %>
58
+ <%= object.class.human_attribute_name(column.split("_cents")[0]) %>
59
+ <% else %>
60
+ <%= object.class.human_attribute_name(column) %>
61
+ <% end %>
62
+ </th>
63
+
64
+ <td>
65
+ <% if column.to_s.include?('.') %>
66
+ <% o = object %>
67
+ <% column.split('.').each{|m| o = o.send(m) if o } %>
68
+ <%= o %>
69
+ <% elsif value.is_a?(Date) ||
70
+ value.is_a?(Time) ||
71
+ value.is_a?(DateTime) ||
72
+ value.is_a?(ActiveSupport::TimeWithZone) %>
73
+ <%= l value %>
74
+ <% elsif value.respond_to? 'attached?' %>
75
+ <% if value.attached? %>
76
+ <%= link_to rails_blob_path(value),
77
+ class: "btn btn-outline-#{color} btn-sm",
78
+ target: '_blank' do %>
79
+ <i class="fa fa-file"></i>
80
+ <span class="d-none d-md-inline">Arquivo</span>
80
81
  <% end %>
81
82
  <% end %>
83
+ <% elsif /_id$/ =~ column && object.respond_to?(column.split('_id')[0]) %>
84
+ <%= object.send(column.split("_id")[0])&.name %>
85
+ <% elsif /_cents$/ =~ column %>
86
+ <%= number_to_currency object.send(column.split("_cents")[0]) %>
87
+ <% else %>
88
+ <%= value %>
82
89
  <% end %>
83
- <% elsif /_id$/ =~ column && object.respond_to?(column.split('_id')[0]) %>
84
- <%= object.send(column.split("_id")[0])&.name %>
85
- <% elsif /_cents$/ =~ column %>
86
- <%= number_to_currency object.send(column.split("_cents")[0]) %>
87
- <% else %>
88
- <%= object.send(column) %>
89
- <% end %>
90
- </td>
91
- </tr>
90
+ </td>
91
+ </tr>
92
+ <% end %>
92
93
  <% end %>
93
- <% end %>
94
+ </tbody>
94
95
  </table>
95
96
  </div>
96
97
  </div>
98
+ <% end %>
97
99
 
98
- <% if relationships.any? %>
99
- <% relationships.each do |key, value| %>
100
- <% if object.association(key.to_s).kind_of?(ActiveRecord::Associations::BelongsToAssociation) ||
101
- object.association(key.to_s).kind_of?(ActiveRecord::Associations::HasOneAssociation) %>
102
- <div class="box card-<%= card_color %>">
103
- <div class="card-header with-border">
104
- <h3 class="card-title">
105
- <%= Kernel.const_get(key.to_s.singularize.camelize).model_name.human %>
106
- </h3>
107
- </div>
108
- <div class="card-body p-0">
109
- <table class="table table-bordered table-striped p-0">
110
- <% unless hide_table_header %>
111
- <thead>
112
- <tr>
113
- <th width='15%'><%= t('field') %></th>
114
- <th><%= t('value') %></th>
115
- </tr>
116
- </thead>
117
- <% end %>
118
- <tbody>
119
- <% value.each do |v| %>
120
- <tr>
121
- <td>
122
- <strong>
123
- <% if /_id$/ =~ v && Kernel.const_get(key.to_s.singularize.camelize).new.respond_to?(v.split('_id')[0]) %>
124
- <%= Kernel.const_get(key.to_s.singularize.camelize).human_attribute_name(v.split('_id')[0]) %>
125
- <% elsif /_cents$/ =~ v %>
126
- <%= Kernel.const_get(key.to_s.singularize.camelize).human_attribute_name(v.split("_cents")[0]) %>
127
- <% else %>
128
- <%= Kernel.const_get(key.to_s.singularize.camelize).human_attribute_name(v) %>
129
- <% end %>
130
- </strong>
131
- </td>
132
- <td>
133
- <% if object.send(key.to_s).send(v).class == Date or
134
- object.send(key.to_s).send(v).class == DateTime or
135
- object.send(key.to_s).send(v).class == ActiveSupport::TimeWithZone or
136
- object.send(key.to_s).send(v).class == Time %>
137
- <%=l object.send(key.to_s).send(v) %>
138
- <% elsif /_id$/ =~ v && object.send(key.to_s).respond_to?(v.split('_id')[0]) %>
139
- <%= object.send(key.to_s).send(v.split("_id")[0])&.name %>
140
- <% elsif /_cents$/ =~ v %>
141
- <%= number_to_currency object.send(key.to_s).send(v.split("_cents")[0]) %>
142
- <% else %>
143
- <%= object.send(key.to_s).send(v) %>
144
- <% end %>
145
- </td>
146
- </tr>
147
- <% end %>
148
- </tbody>
149
- </table>
150
- </div>
151
- </div>
152
- <% else %>
153
- <div class="box card-<%= card_color %>">
154
- <div class="card-header with-border">
155
- <h3 class="card-title">
156
- <%= Kernel.const_get(key.to_s.singularize.camelize).model_name.human.pluralize %>
157
- </h3>
158
- </div>
159
- <div class="card-body p-0">
160
- <table class="table table-bordered table-striped p-0">
161
- <thead>
162
- <tr>
163
- <% value.each do |v| %>
164
- <th>
165
- <% if /_id$/ =~ v && Kernel.const_get(key.to_s.singularize.camelize).new.respond_to?(v.split('_id')[0]) %>
166
- <%= Kernel.const_get(key.to_s.singularize.camelize).human_attribute_name(v.split('_id')[0]) %>
167
- <% else %>
168
- <%= Kernel.const_get(key.to_s.singularize.camelize).human_attribute_name(v) %>
169
- <% end %>
170
- </th>
171
- <% end %>
172
- </tr>
173
- </thead>
174
- <tbody>
175
- <% object.send(key.to_s).each do |r| %>
176
- <tr>
177
- <% value.each do |v| %>
178
- <td>
179
- <% if v.include?('.') %>
180
- <% o = r %>
181
- <% v.split('.').each{|m| o = o.send(m) if o } %>
182
- <%= o %>
183
- <% elsif r.send(v).class == Date or
184
- r.send(v).class == DateTime or
185
- r.send(v).class == ActiveSupport::TimeWithZone or
186
- r.send(v).class == Time %>
187
- <%=l r.send(v) %>
188
- <% elsif r.send(v).respond_to? 'attached?' %>
189
- <% if r.send(v).class == ActiveStorage::Attached::One %>
190
- <% if r.send(v).attached? %>
191
- <%= link_to rails_blob_path(r.send(v)), class: "btn btn-#{card_color} btn-xs", target: '_blank' do %>
192
- <i class="fa fa-file-o"></i> Arquivo
193
- <% end %>
194
- <% end %>
195
- <% end %>
196
- <% elsif /_id$/ =~ v && r.respond_to?(v.split('_id')[0]) %>
197
- <%= r.send(v.split("_id")[0])&.name %>
198
- <% else %>
199
- <%= r.send(v) %>
200
- <% end %>
201
- </td>
202
- <% end %>
203
- </tr>
204
- <% end %>
205
- </tbody>
206
- </table>
207
- </div>
208
- </div>
209
- <% end %>
210
- <% end %>
100
+ <div class="card-footer">
101
+ <% unless hide.include? "bottom_bar" %>
102
+ <%= render "shared/btn_action_links",
103
+ object: object,
104
+ labels: true,
105
+ hide: hide,
106
+ edit_color: edit_color,
107
+ delete_color: delete_color,
108
+ size: buttons_size %>
211
109
  <% end %>
212
- <% end %>
213
- <%= render "shared/btn_action_links", object: object, labels: true, hide: hide, new_color: new_color, edit_color: edit_color, delete_color: delete_color %>
110
+ </div>
@@ -0,0 +1,21 @@
1
+ <% title ||= '' %>
2
+ <% size ||= 'lg' %>
3
+ <% hide_header ||= false %>
4
+ <% modal_frame_tag ||= "turbo_modal" %>
5
+
6
+ <%= turbo_frame_tag modal_frame_tag do %>
7
+ <% unless hide_header %>
8
+ <div class="modal-header">
9
+ <h5 class="modal-title"><%= title %></h5>
10
+
11
+ <button
12
+ type="button"
13
+ class="btn-close"
14
+ data-bs-dismiss="modal"
15
+ aria-label="Fechar"
16
+ ></button>
17
+ </div>
18
+ <% end %>
19
+
20
+ <div class="modal-body p-0"><%= yield %></div>
21
+ <% end %>
data/lib/zutils/engine.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Zutils
2
2
  class Engine < Rails::Engine
3
- # Make it a Rails Engine
3
+ config.to_prepare do
4
+ ActionView::Base.include(Zutils::Helpers)
5
+ end
4
6
  end
5
7
  end