bootstrap-cells 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.gitlab-ci.yml +13 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +27 -0
  6. data/CHANGELOG +29 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +200 -0
  9. data/Rakefile +8 -0
  10. data/app/assets/javascripts/bootstrap-cells/add_many_event_listeners.js +11 -0
  11. data/app/assets/javascripts/bootstrap-cells/index.js +3 -0
  12. data/app/assets/stylesheets/_bootstrap-cells.scss +7 -0
  13. data/app/views/kaminari/bootstrap/_first_page.html.erb +15 -0
  14. data/app/views/kaminari/bootstrap/_gap.html.erb +12 -0
  15. data/app/views/kaminari/bootstrap/_last_page.html.erb +16 -0
  16. data/app/views/kaminari/bootstrap/_next_page.html.erb +16 -0
  17. data/app/views/kaminari/bootstrap/_page.html.erb +17 -0
  18. data/app/views/kaminari/bootstrap/_paginator.html.erb +32 -0
  19. data/app/views/kaminari/bootstrap/_prev_page.html.erb +16 -0
  20. data/bin/console +15 -0
  21. data/bin/setup +8 -0
  22. data/bootstrap-cells.gemspec +36 -0
  23. data/lib/bootstrap-cells.rb +16 -0
  24. data/lib/bootstrap-cells/cells/alert/body.erb +7 -0
  25. data/lib/bootstrap-cells/cells/alert/show.erb +7 -0
  26. data/lib/bootstrap-cells/cells/alert/title.erb +9 -0
  27. data/lib/bootstrap-cells/cells/alert_cell.rb +39 -0
  28. data/lib/bootstrap-cells/cells/base_cell.rb +43 -0
  29. data/lib/bootstrap-cells/cells/button/show.erb +17 -0
  30. data/lib/bootstrap-cells/cells/button_cell.rb +41 -0
  31. data/lib/bootstrap-cells/cells/card/block.erb +14 -0
  32. data/lib/bootstrap-cells/cells/card/block_body.erb +5 -0
  33. data/lib/bootstrap-cells/cells/card/block_subtitle.erb +5 -0
  34. data/lib/bootstrap-cells/cells/card/block_text.erb +5 -0
  35. data/lib/bootstrap-cells/cells/card/block_title.erb +5 -0
  36. data/lib/bootstrap-cells/cells/card/footer.erb +9 -0
  37. data/lib/bootstrap-cells/cells/card/header.erb +9 -0
  38. data/lib/bootstrap-cells/cells/card/img_bottom.erb +9 -0
  39. data/lib/bootstrap-cells/cells/card/img_top.erb +9 -0
  40. data/lib/bootstrap-cells/cells/card/list_group.erb +9 -0
  41. data/lib/bootstrap-cells/cells/card/show.erb +9 -0
  42. data/lib/bootstrap-cells/cells/card/table.erb +9 -0
  43. data/lib/bootstrap-cells/cells/card_cell.rb +152 -0
  44. data/lib/bootstrap-cells/cells/column/td.erb +1 -0
  45. data/lib/bootstrap-cells/cells/column/th.erb +9 -0
  46. data/lib/bootstrap-cells/cells/column_cell.rb +49 -0
  47. data/lib/bootstrap-cells/cells/field/required_field.scss +5 -0
  48. data/lib/bootstrap-cells/cells/field/show.erb +15 -0
  49. data/lib/bootstrap-cells/cells/field_cell.rb +96 -0
  50. data/lib/bootstrap-cells/cells/fields_for/form.scss +12 -0
  51. data/lib/bootstrap-cells/cells/fields_for/form_horizontal.scss +33 -0
  52. data/lib/bootstrap-cells/cells/fields_for/show.erb +3 -0
  53. data/lib/bootstrap-cells/cells/fields_for_cell.rb +15 -0
  54. data/lib/bootstrap-cells/cells/kv_horizontal/show.erb +17 -0
  55. data/lib/bootstrap-cells/cells/kv_horizontal_cell.rb +34 -0
  56. data/lib/bootstrap-cells/cells/kv_vertical/show.erb +17 -0
  57. data/lib/bootstrap-cells/cells/kv_vertical_cell.rb +32 -0
  58. data/lib/bootstrap-cells/cells/modal/body.erb +9 -0
  59. data/lib/bootstrap-cells/cells/modal/button.erb +9 -0
  60. data/lib/bootstrap-cells/cells/modal/content.erb +12 -0
  61. data/lib/bootstrap-cells/cells/modal/footer.erb +10 -0
  62. data/lib/bootstrap-cells/cells/modal/header.erb +12 -0
  63. data/lib/bootstrap-cells/cells/modal/modal.js +15 -0
  64. data/lib/bootstrap-cells/cells/modal/show.erb +9 -0
  65. data/lib/bootstrap-cells/cells/modal_cell.rb +64 -0
  66. data/lib/bootstrap-cells/cells/pages/pages.scss +4 -0
  67. data/lib/bootstrap-cells/cells/pages/show.erb +3 -0
  68. data/lib/bootstrap-cells/cells/pages_cell.rb +16 -0
  69. data/lib/bootstrap-cells/cells/table/nubbin.scss +40 -0
  70. data/lib/bootstrap-cells/cells/table/show.erb +7 -0
  71. data/lib/bootstrap-cells/cells/table/table_sort.scss +17 -0
  72. data/lib/bootstrap-cells/cells/table/table_striped_nested.scss +8 -0
  73. data/lib/bootstrap-cells/cells/table/tbody.erb +3 -0
  74. data/lib/bootstrap-cells/cells/table/tbody_button_for_nested_row.erb +9 -0
  75. data/lib/bootstrap-cells/cells/table/tbody_final_row.erb +9 -0
  76. data/lib/bootstrap-cells/cells/table/tbody_first_row.erb +9 -0
  77. data/lib/bootstrap-cells/cells/table/tbody_nested_row.erb +6 -0
  78. data/lib/bootstrap-cells/cells/table/tbody_rows.erb +35 -0
  79. data/lib/bootstrap-cells/cells/table/thead.erb +11 -0
  80. data/lib/bootstrap-cells/cells/table_cell.rb +68 -0
  81. data/lib/bootstrap-cells/cells/tabs/show.erb +19 -0
  82. data/lib/bootstrap-cells/cells/tabs_cell.rb +40 -0
  83. data/lib/bootstrap-cells/engine.rb +9 -0
  84. metadata +307 -0
@@ -0,0 +1 @@
1
+ <%= content_tag(:td, cell_text, **td_props) %>
@@ -0,0 +1,9 @@
1
+ <%= content_tag(:th, **th_props) do %>
2
+ <% if options[:sort] %>
3
+ <%= content_tag(:div, class: 'flex items-center justify-between') do %>
4
+ <%= content_tag(:span, header_text) %>
5
+ <% end %>
6
+ <% else %>
7
+ <%= header_text %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ColumnCell < BaseCell
4
+ def th
5
+ render
6
+ end
7
+
8
+ def td
9
+ render
10
+ end
11
+
12
+ private
13
+
14
+ def th_props
15
+ defaults = {
16
+ class: c(('sort' if options[:sort]),
17
+ ("col-xs-#{options[:columns]}" if options[:columns]),
18
+ ('text-center' if options[:center])),
19
+ data: { sort: options[:attribute] },
20
+ }
21
+ merge_props(from: defaults, to: options.dig(:props, :th))
22
+ end
23
+
24
+ def td_props
25
+ defaults = {
26
+ class: c(options[:attribute],
27
+ ('truncate' if options[:truncate]),
28
+ ('text-center' if options[:center])),
29
+ }
30
+ merge_props(from: defaults, to: options.dig(:props, :td))
31
+ end
32
+
33
+ def header_text
34
+ return options[:header] if options[:header]
35
+ return nil unless options[:attribute]
36
+ return options[:model].human_attribute_name(
37
+ options[:attribute],
38
+ default: I18n.t(options[:attribute],
39
+ scope: :attributes,
40
+ default: titleized_attribute_path(options[:attribute]))
41
+ ) if options[:model].respond_to?(:human_attribute_name)
42
+ titleized_attribute_path(options[:attribute])
43
+ end
44
+
45
+ def cell_text
46
+ return '—' unless options[:cell] || options[:attribute]
47
+ options[:cell]&.call(model, options[:index]) || render_attribute_path(options[:attribute], model)
48
+ end
49
+ end
@@ -0,0 +1,5 @@
1
+ .required label:before {
2
+ content: "*";
3
+ color: #d82c2c;
4
+ padding-right: 2px;
5
+ }
@@ -0,0 +1,15 @@
1
+ <% if field[:hidden] %>
2
+ <%= hidden_field(field_input_name, field_input_attribute, value: field_input_value) %>
3
+ <% else %>
4
+ <%= content_tag(:div, **container_props) do %>
5
+ <% unless field[:label] == false %>
6
+ <%= content_tag(:label, label_text, **label_props) %>
7
+ <% end %>
8
+ <%= content_tag(:div, **value_props) do %>
9
+ <%= value_text %>
10
+ <% end %>
11
+ <% if field[:errors] && field[:errors].present? %>
12
+ <span class="help-block"><%= field[:errors] %></span>
13
+ <% end %>
14
+ <% end %>
15
+ <% end %>
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FieldCell < BaseCell
4
+ private
5
+
6
+ def field
7
+ @field ||= field_props
8
+ end
9
+
10
+ def field_props
11
+ attribute = @options[:attribute]
12
+ defaults = {
13
+ attribute: attribute,
14
+ required: false,
15
+ hidden: false,
16
+ readonly: false,
17
+ props: {
18
+ container: {},
19
+ label: {},
20
+ value: {},
21
+ input: {},
22
+ },
23
+ }
24
+
25
+ params = merge_props(from: defaults, to: @options)
26
+ params[:required] = 'required' if params[:required]
27
+ params[:errors] ||= fetch_errors(model, attribute) if model
28
+ params
29
+ end
30
+
31
+ def attribute
32
+ field[:attribute].to_s
33
+ end
34
+
35
+ def container_props
36
+ defaults = {
37
+ class: %w[form-group px-0],
38
+ }
39
+ defaults[:class] << %w[has-error] if field[:errors]
40
+ defaults[:class] << %w[required] if field[:required]
41
+ merge_props(from: defaults, to: field.dig(:props, :container))
42
+ end
43
+
44
+ def label_props
45
+ defaults = {
46
+ class: %w[control-label],
47
+ }
48
+ merge_props(from: defaults, to: field.dig(:props, :label))
49
+ end
50
+
51
+ def label_text
52
+ return field[:label] if field[:label].is_a?(String)
53
+ return nil if field[:label] == false || !model
54
+ return model.class.human_attribute_name(
55
+ attribute,
56
+ default: I18n.t(attribute,
57
+ scope: :attributes,
58
+ default: titleized_attribute_path(attribute))
59
+ ) if model.class.respond_to?(:human_attribute_name)
60
+ titleized_attribute_path(attribute)
61
+ end
62
+
63
+ def value_props
64
+ defaults = {
65
+ class: %w[control-value],
66
+ }
67
+ defaults[:class] << %w[form-control-static] if field[:readonly]
68
+ merge_props(from: defaults, to: field.dig(:props, :value))
69
+ end
70
+
71
+ def value_text
72
+ return field[:output] if field[:output]
73
+ return render_attribute_path(attribute, model) if field[:readonly]
74
+ text_field(field_input_name,
75
+ field_input_attribute,
76
+ value: field_input_value,
77
+ class: c(field.dig(:props, :input, :class), 'form-control px-2'),
78
+ placeholder: field[:placeholder] || titleized_attribute_path(attribute),
79
+ **field.dig(:props, :input).except(:class))
80
+ end
81
+
82
+ def field_input_name
83
+ return nil unless model
84
+ param_name = (model.try(:model_name) || model.class.name.remove('Filterer').constantize.new.model_name)&.param_key
85
+ param_name.to_s + attribute.split('.')[0..-2].map { |a| '[' + a + ']' }.join
86
+ end
87
+
88
+ def field_input_attribute
89
+ attribute.split('.').last
90
+ end
91
+
92
+ def field_input_value
93
+ return field[:output] if field[:output]
94
+ render_attribute_path(attribute, model)
95
+ end
96
+ end
@@ -0,0 +1,12 @@
1
+ .form {
2
+ .form-group {
3
+ margin-bottom: 2rem;
4
+ }
5
+ .help-block {
6
+ margin-bottom: 0;
7
+ }
8
+ }
9
+
10
+ .form-group {
11
+ width: 100%;
12
+ }
@@ -0,0 +1,33 @@
1
+ .form-horizontal {
2
+ .form-group {
3
+ display: flex;
4
+ flex-wrap: wrap;
5
+ align-items: center;
6
+ margin-left: 0;
7
+ margin-right: 0;
8
+
9
+ .control-label, .sr-only {
10
+ flex-basis: 20%;
11
+ width: 20%;
12
+ text-align: right;
13
+ padding: 0;
14
+ }
15
+ > .control-value,
16
+ > .help-block {
17
+ flex-basis: 75%;
18
+ width: 75%;
19
+ margin-left: 2%;
20
+ }
21
+ > .control-value:only-child {
22
+ flex-basis: 100%;
23
+ width: 100%;
24
+ margin-left: 0;
25
+ }
26
+ .sr-only + .control-value {
27
+ margin-left: 22%;
28
+ }
29
+ > .help-block {
30
+ margin-left: 22%;
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,3 @@
1
+ <% fields.each do |field| %>
2
+ <%= cell(:field, model, options_for(field: field)).() %>
3
+ <% end %>
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bootstrap-cells/cells/field_cell'
4
+
5
+ class FieldsForCell < BaseCell
6
+ private
7
+
8
+ def fields
9
+ (options[:fields] || []).compact
10
+ end
11
+
12
+ def options_for(field:)
13
+ options.slice(:required, :hidden, :readonly).merge(field)
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ <%= content_tag(:dl, **item_props) do %>
2
+ <%= content_tag(:dt, **key_props) do %>
3
+ <% if renderable?(:key) %>
4
+ <%= render_option(:key) %>
5
+ <% else %>
6
+ <%= key_text %>
7
+ <% end %>
8
+ <% end %>
9
+
10
+ <%= content_tag(:dd, **value_props) do %>
11
+ <% if renderable?(:value) %>
12
+ <%= render_option(:value) %>
13
+ <% else %>
14
+ <%= value_text %>
15
+ <% end %>
16
+ <% end %>
17
+ <% end %>
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class KvHorizontalCell < BaseCell
4
+ private
5
+
6
+ def item_props
7
+ defaults = {
8
+ class: 'col-xs-12 my-0 mr-auto',
9
+ }
10
+ merge_props(from: defaults, to: options.dig(:props, :item))
11
+ end
12
+
13
+ def key_props
14
+ defaults = {
15
+ class: 'col-xs-3 right-align pr-2',
16
+ }
17
+ merge_props(from: defaults, to: options.dig(:props, :key))
18
+ end
19
+
20
+ def key_text
21
+ options[:key]
22
+ end
23
+
24
+ def value_props
25
+ defaults = {
26
+ class: 'col-xs-9',
27
+ }
28
+ merge_props(from: defaults, to: options.dig(:props, :value))
29
+ end
30
+
31
+ def value_text
32
+ options[:value] || '—'
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ <%= content_tag(:dl, **item_props) do %>
2
+ <%= content_tag(:dt, **key_props) do %>
3
+ <% if renderable?(:key) %>
4
+ <%= render_option(:key) %>
5
+ <% else %>
6
+ <%= key_text %>
7
+ <% end %>
8
+ <% end %>
9
+
10
+ <%= content_tag(:dd, **value_props) do %>
11
+ <% if renderable?(:value) %>
12
+ <%= render_option(:value) %>
13
+ <% else %>
14
+ <%= value_text %>
15
+ <% end %>
16
+ <% end %>
17
+ <% end %>
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class KvVerticalCell < BaseCell
4
+ private
5
+
6
+ def item_props
7
+ defaults = {
8
+ class: 'my-0',
9
+ }
10
+ merge_props(from: defaults, to: options.dig(:props, :item))
11
+ end
12
+
13
+ def key_props
14
+ defaults = {
15
+ }
16
+ merge_props(from: defaults, to: options.dig(:props, :key))
17
+ end
18
+
19
+ def key_text
20
+ options[:key]
21
+ end
22
+
23
+ def value_props
24
+ defaults = {
25
+ }
26
+ merge_props(from: defaults, to: options.dig(:props, :value))
27
+ end
28
+
29
+ def value_text
30
+ options[:value] || '—'
31
+ end
32
+ end
@@ -0,0 +1,9 @@
1
+ <div class="modal-body">
2
+ <% if renderable?(:body) %>
3
+ <%= render_option(:body) %>
4
+ <% else %>
5
+ <%= content_tag(:div, **body_props) do %>
6
+ <%= body_text %>
7
+ <% end %>
8
+ <% end %>
9
+ </div>
@@ -0,0 +1,9 @@
1
+ <span data-toggle="modal" style="cursor:pointer;">
2
+ <% if renderable?(:button) %>
3
+ <%= render_option(:button) %>
4
+ <% else %>
5
+ <%= content_tag(:button, **button_props) do %>
6
+ <%= button_text %>
7
+ <% end %>
8
+ <% end %>
9
+ </span>
@@ -0,0 +1,12 @@
1
+ <div class="modal-content">
2
+ <%= render :header %>
3
+
4
+ <% if renderable?(:content) %>
5
+ <%= render_option(:content) %>
6
+ <% else %>
7
+ <%= content_tag(:div, **content_props) do %>
8
+ <%= render :body %>
9
+ <%= render :footer %>
10
+ <% end %>
11
+ <% end %>
12
+ </div>
@@ -0,0 +1,10 @@
1
+ <div class="modal-footer">
2
+ <% if renderable?(:footer) %>
3
+ <%= render_option(:footer) %>
4
+ <% else %>
5
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
6
+ <%= content_tag(:span, **footer_props) do %>
7
+ <%= footer_text %>
8
+ <% end %>
9
+ <% end %>
10
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="modal-header">
2
+ <% if renderable?(:header) %>
3
+ <%= render_option(:header) %>
4
+ <% else %>
5
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
6
+ <span aria-hidden="true">&times;</span>
7
+ </button>
8
+ <%= content_tag(header_props[:tag], **header_props.except(:tag)) do %>
9
+ <%= header_text %>
10
+ <% end %>
11
+ <% end %>
12
+ </div>
@@ -0,0 +1,15 @@
1
+ var handleModals = function handleModals() {
2
+ document.querySelectorAll('.bootstrap-modal [data-toggle="modal"]').forEach(function(modalButton) {
3
+ var modal = modalButton.parentNode.querySelector('.modal');
4
+ var randomId = Math.random().toString().substr(-10);
5
+
6
+ modal.setAttribute('id', randomId);
7
+ modalButton.setAttribute('data-target', '#' + randomId);
8
+
9
+ document.querySelector('body').appendChild( modal )
10
+ });
11
+ }
12
+
13
+ addManyEventListeners(document,
14
+ "page:change turbolinks:load ajax:complete",
15
+ handleModals);
@@ -0,0 +1,9 @@
1
+ <%= content_tag(:div, **wrapper_props) do %>
2
+ <%= render :button %>
3
+
4
+ <div class="modal fade" tabindex="-1" role="dialog">
5
+ <div class="modal-dialog" role="document">
6
+ <%= render :content %>
7
+ </div>
8
+ </div>
9
+ <% end %>