headmin 0.1.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.
Files changed (175) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.nvmrc +1 -0
  4. data/.rubocop.yml +13 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +5 -0
  7. data/CODE_OF_CONDUCT.md +84 -0
  8. data/Gemfile +12 -0
  9. data/Gemfile.lock +43 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +166 -0
  12. data/Rakefile +16 -0
  13. data/app/assets/images/avatar.jpg +0 -0
  14. data/app/controllers/admin/users/confirmations_controller.rb +31 -0
  15. data/app/controllers/admin/users/omniauth_callbacks_controller.rb +31 -0
  16. data/app/controllers/admin/users/passwords_controller.rb +35 -0
  17. data/app/controllers/admin/users/registrations_controller.rb +63 -0
  18. data/app/controllers/admin/users/sessions_controller.rb +28 -0
  19. data/app/controllers/admin/users/unlocks_controller.rb +31 -0
  20. data/app/controllers/concerns/headmin/acts_as_list.rb +16 -0
  21. data/app/controllers/concerns/headmin/authentication.rb +17 -0
  22. data/app/controllers/concerns/headmin/ckeditor.rb +27 -0
  23. data/app/controllers/concerns/headmin/filter.rb +5 -0
  24. data/app/controllers/concerns/headmin/pagination.rb +23 -0
  25. data/app/controllers/concerns/headmin/searchable.rb +15 -0
  26. data/app/controllers/concerns/headmin/sortable.rb +44 -0
  27. data/app/helpers/headmin/admin_helper.rb +65 -0
  28. data/app/helpers/headmin/filter_helper.rb +12 -0
  29. data/app/helpers/headmin/notification_helper.rb +31 -0
  30. data/app/views/admin/users/confirmations/new.html.erb +9 -0
  31. data/app/views/admin/users/mailer/confirmation_instructions.html.erb +5 -0
  32. data/app/views/admin/users/mailer/email_changed.html.erb +7 -0
  33. data/app/views/admin/users/mailer/password_change.html.erb +3 -0
  34. data/app/views/admin/users/mailer/reset_password_instructions.html.erb +8 -0
  35. data/app/views/admin/users/mailer/unlock_instructions.html.erb +7 -0
  36. data/app/views/admin/users/passwords/edit.html.erb +12 -0
  37. data/app/views/admin/users/passwords/new.html.erb +9 -0
  38. data/app/views/admin/users/registrations/edit.html.erb +24 -0
  39. data/app/views/admin/users/registrations/new.html.erb +11 -0
  40. data/app/views/admin/users/sessions/new.html.erb +13 -0
  41. data/app/views/admin/users/shared/_error_messages.html.erb +7 -0
  42. data/app/views/admin/users/shared/_links.html.erb +27 -0
  43. data/app/views/admin/users/unlocks/new.html.erb +10 -0
  44. data/app/views/headmin/_breadcrumbs.html.erb +23 -0
  45. data/app/views/headmin/_filters.html.erb +47 -0
  46. data/app/views/headmin/_form.html.erb +11 -0
  47. data/app/views/headmin/_heading.html.erb +9 -0
  48. data/app/views/headmin/_index.html.erb +12 -0
  49. data/app/views/headmin/_notifications.html.erb +12 -0
  50. data/app/views/headmin/_pagination.html.erb +13 -0
  51. data/app/views/headmin/_table.html.erb +13 -0
  52. data/app/views/headmin/filters/_date.html.erb +46 -0
  53. data/app/views/headmin/filters/_search.html.erb +22 -0
  54. data/app/views/headmin/filters/_select.html.erb +39 -0
  55. data/app/views/headmin/filters/filter/_button.html.erb +22 -0
  56. data/app/views/headmin/filters/filter/_menu_item.html.erb +12 -0
  57. data/app/views/headmin/filters/filter/_template.html.erb +13 -0
  58. data/app/views/headmin/forms/_actions.html.erb +32 -0
  59. data/app/views/headmin/forms/_errors.html.erb +20 -0
  60. data/app/views/headmin/forms/_group.html.erb +36 -0
  61. data/app/views/headmin/forms/fields/_checkbox.html.erb +23 -0
  62. data/app/views/headmin/forms/fields/_ckeditor.html.erb +28 -0
  63. data/app/views/headmin/forms/fields/_currency.html.erb +24 -0
  64. data/app/views/headmin/forms/fields/_date.html.erb +36 -0
  65. data/app/views/headmin/forms/fields/_email.html.erb +39 -0
  66. data/app/views/headmin/forms/fields/_file.html.erb +24 -0
  67. data/app/views/headmin/forms/fields/_image.html.erb +37 -0
  68. data/app/views/headmin/forms/fields/_label.html.erb +9 -0
  69. data/app/views/headmin/forms/fields/_multiple_select.html.erb +37 -0
  70. data/app/views/headmin/forms/fields/_password.html.erb +39 -0
  71. data/app/views/headmin/forms/fields/_repeater.html.erb +48 -0
  72. data/app/views/headmin/forms/fields/_select.html.erb +36 -0
  73. data/app/views/headmin/forms/fields/_select_tags.html.erb +32 -0
  74. data/app/views/headmin/forms/fields/_text.html.erb +39 -0
  75. data/app/views/headmin/forms/fields/_textarea.html.erb +29 -0
  76. data/app/views/headmin/forms/fields/_url.html.erb +38 -0
  77. data/app/views/headmin/forms/fields/_validation.html.erb +12 -0
  78. data/app/views/headmin/forms/fields/repeater/_row.html.erb +16 -0
  79. data/app/views/headmin/heading/_title.html.erb +24 -0
  80. data/app/views/headmin/kaminari/_first_page.html.erb +11 -0
  81. data/app/views/headmin/kaminari/_gap.html.erb +12 -0
  82. data/app/views/headmin/kaminari/_last_page.html.erb +12 -0
  83. data/app/views/headmin/kaminari/_next_page.html.erb +13 -0
  84. data/app/views/headmin/kaminari/_page.html.erb +12 -0
  85. data/app/views/headmin/kaminari/_paginator.html.erb +25 -0
  86. data/app/views/headmin/kaminari/_prev_page.html.erb +11 -0
  87. data/app/views/headmin/layout/_body.html.erb +9 -0
  88. data/app/views/headmin/layout/_content.html.erb +9 -0
  89. data/app/views/headmin/layout/_footer.html.erb +17 -0
  90. data/app/views/headmin/layout/_header.html.erb +13 -0
  91. data/app/views/headmin/layout/_main.html.erb +13 -0
  92. data/app/views/headmin/layout/_sidebar.html.erb +20 -0
  93. data/app/views/headmin/layout/dropdown/_divider.html.erb +9 -0
  94. data/app/views/headmin/layout/dropdown/_item.html.erb +17 -0
  95. data/app/views/headmin/layout/header/_account.html.erb +25 -0
  96. data/app/views/headmin/layout/header/_locale.html.erb +19 -0
  97. data/app/views/headmin/layout/sidebar/_bottom.html.erb +4 -0
  98. data/app/views/headmin/layout/sidebar/_menu.html.erb +9 -0
  99. data/app/views/headmin/layout/sidebar/menu/_account.html.erb +25 -0
  100. data/app/views/headmin/layout/sidebar/menu/_item.html.erb +16 -0
  101. data/app/views/headmin/layout/sidebar/menu/_locale.html.erb +18 -0
  102. data/app/views/headmin/table/_actions.html.erb +19 -0
  103. data/app/views/headmin/table/_body.html.erb +19 -0
  104. data/app/views/headmin/table/_foot.html.erb +15 -0
  105. data/app/views/headmin/table/_footer.html.erb +13 -0
  106. data/app/views/headmin/table/_head.html.erb +15 -0
  107. data/app/views/headmin/table/_header.html.erb +13 -0
  108. data/app/views/headmin/table/actions/_action.html.erb +10 -0
  109. data/app/views/headmin/table/actions/_delete.html.erb +8 -0
  110. data/app/views/headmin/table/actions/_export.html.erb +8 -0
  111. data/app/views/headmin/table/body/_association.html.erb +11 -0
  112. data/app/views/headmin/table/body/_boolean.erb +16 -0
  113. data/app/views/headmin/table/body/_currency.html.erb +10 -0
  114. data/app/views/headmin/table/body/_date.html.erb +11 -0
  115. data/app/views/headmin/table/body/_id.html.erb +3 -0
  116. data/app/views/headmin/table/body/_row.html.erb +9 -0
  117. data/app/views/headmin/table/body/_sort.html.erb +3 -0
  118. data/app/views/headmin/table/body/_string.html.erb +16 -0
  119. data/app/views/headmin/table/body/_text.html.erb +10 -0
  120. data/app/views/headmin/table/foot/_cell.html.erb +10 -0
  121. data/app/views/headmin/table/foot/_id.html.erb +9 -0
  122. data/app/views/headmin/table/head/_cell.html.erb +13 -0
  123. data/app/views/headmin/table/head/_empty.html.erb +1 -0
  124. data/app/views/headmin/table/head/_id.html.erb +9 -0
  125. data/app/views/headmin/table/head/_sort.html.erb +3 -0
  126. data/app/views/headmin/table/head/cell/_asc.html.erb +4 -0
  127. data/app/views/headmin/table/head/cell/_default.html.erb +7 -0
  128. data/app/views/headmin/table/head/cell/_desc.html.erb +4 -0
  129. data/app/views/layouts/admin/auth.html.erb +20 -0
  130. data/app/views/layouts/admin.html.erb +42 -0
  131. data/bin/console +15 -0
  132. data/bin/setup +8 -0
  133. data/config/locales/defaults/en.yml +215 -0
  134. data/config/locales/defaults/nl.yml +213 -0
  135. data/config/locales/devise/nl.yml +85 -0
  136. data/config/locales/en.yml +137 -0
  137. data/config/locales/nl.yml +138 -0
  138. data/dist/css/headmin.css +9874 -0
  139. data/dist/js/headmin.js +852 -0
  140. data/docs/README.md +4 -0
  141. data/docs/blocks.md +116 -0
  142. data/docs/devise.md +62 -0
  143. data/headmin.gemspec +35 -0
  144. data/lib/headmin/engine.rb +10 -0
  145. data/lib/headmin/version.rb +5 -0
  146. data/lib/headmin.rb +4 -0
  147. data/package.json +62 -0
  148. data/src/js/headmin/controllers/filter_controller.js +47 -0
  149. data/src/js/headmin/controllers/filters_controller.js +53 -0
  150. data/src/js/headmin/controllers/index_controller.js +79 -0
  151. data/src/js/headmin/controllers/repeater_controller.js +35 -0
  152. data/src/js/headmin/controllers/repeater_row_controller.js +54 -0
  153. data/src/js/headmin/controllers/table_actions_controller.js +22 -0
  154. data/src/js/headmin/controllers/table_controller.js +36 -0
  155. data/src/js/headmin/headmin.js +168 -0
  156. data/src/js/headmin.js +1 -0
  157. data/src/scss/headmin/filter.scss +33 -0
  158. data/src/scss/headmin/filters.scss +14 -0
  159. data/src/scss/headmin/form.scss +39 -0
  160. data/src/scss/headmin/general.scss +3 -0
  161. data/src/scss/headmin/layout/body.scss +6 -0
  162. data/src/scss/headmin/layout/sidebar.scss +22 -0
  163. data/src/scss/headmin/layout.scss +2 -0
  164. data/src/scss/headmin/login.scss +35 -0
  165. data/src/scss/headmin/table.scss +32 -0
  166. data/src/scss/headmin/utilities.scss +19 -0
  167. data/src/scss/headmin.scss +58 -0
  168. data/src/scss/vendor/bootstrap/variables.scss +71 -0
  169. data/src/scss/vendor/choices/cross-inverse.svg +6 -0
  170. data/src/scss/vendor/choices/cross.svg +6 -0
  171. data/src/scss/vendor/choices/custom.scss +28 -0
  172. data/src/scss/vendor/choices/variables.scss +16 -0
  173. data/webpack.config.js +30 -0
  174. data/yarn.lock +7512 -0
  175. metadata +220 -0
@@ -0,0 +1,5 @@
1
+ module Headmin
2
+ module Filter
3
+ include Headmin::FilterHelper
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ module Headmin
2
+ module Pagination
3
+ def paginate(collection)
4
+ @records_filtered = collection.count
5
+ collection.page(page).per(per_page)
6
+ end
7
+
8
+ def page
9
+ if params[:page]
10
+ params[:page]
11
+ elsif params[:start]
12
+ (params[:start].to_i / per_page) + 1
13
+ else
14
+ 1
15
+ end
16
+ end
17
+
18
+ def per_page
19
+ length = (params[:per_page] || params[:length]).to_i
20
+ length > 0 ? length : 24
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module Headmin
2
+ module Searchable
3
+ def search(collection)
4
+ if search_params&.present?
5
+ collection.search(search_params)
6
+ else
7
+ collection
8
+ end
9
+ end
10
+
11
+ def search_params
12
+ @search_params ||= params[:search] && params[:search].to_s
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,44 @@
1
+ module Headmin
2
+ module Sortable
3
+ def sort(collection)
4
+ if sort_params.to_h.any?
5
+ sort_by_params(collection)
6
+ elsif collection.attribute_names.include?(:created_at.to_s)
7
+ collection.order(created_at: :desc)
8
+ else
9
+ collection
10
+ end
11
+ end
12
+
13
+ def sort_by_params(collection)
14
+ sort_params.each do |key, value|
15
+ next unless %w(asc desc).include?(value)
16
+ attribute = key.gsub('sort_', '')
17
+
18
+ # Sort on model columns first, then check for translation columns
19
+ if collection.attribute_names.include?(attribute.to_s)
20
+ column = collection.arel_table[attribute]
21
+ elsif collection.respond_to?(:translation_class) && collection.translation_class.attribute_names.include?(attribute.to_s)
22
+ column = collection.translation_class.arel_table[attribute]
23
+ else
24
+ next
25
+ end
26
+
27
+ order_scope = "order_by_#{attribute}".to_sym
28
+ sort_scope = "sort_by_#{attribute}".to_sym
29
+ if collection.respond_to?(order_scope)
30
+ collection = collection.send(order_scope, value)
31
+ elsif collection.respond_to?(sort_scope)
32
+ collection = collection.send(sort_scope, value)
33
+ else
34
+ collection = collection.order(column.send(value))
35
+ end
36
+ end
37
+ collection
38
+ end
39
+
40
+ def sort_params
41
+ params.permit!.select { |p| p.to_s.include?('sort_') }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,65 @@
1
+ module Headmin
2
+ module AdminHelper
3
+ include Headmin::FilterHelper
4
+ include Headmin::NotificationHelper
5
+
6
+ def current_model
7
+ controller_name.classify.constantize
8
+ end
9
+
10
+ def bootstrap_icon(icon, options = {})
11
+ data = options.has_key?(:data) ? options[:data] : nil
12
+ klass = options.has_key?(:class) ? options[:class] : nil
13
+ content_tag(:i, class: "bi bi-#{icon} #{klass}", data: data) {}
14
+ end
15
+
16
+ def menu_item_active?(link)
17
+ uri = URI(link)
18
+ path = uri.path
19
+ query_string = uri.query
20
+ matches_path = request.path.include?(path)
21
+ matches_query = uri.query ? request.query_string.include?(query_string) : true
22
+ is_root = request.fullpath == link
23
+ if link == admin_root_path
24
+ is_root
25
+ else
26
+ matches_path && matches_query
27
+ end
28
+ end
29
+
30
+ def form_field_valid?(form, name)
31
+ !form.object.errors.has_key?(name)
32
+ end
33
+
34
+ def form_field_validation_id(form, name)
35
+ [form.object_name, name.to_s, 'validation'].join('_').parameterize.underscore
36
+ end
37
+
38
+ def form_field_validation_class(form, name)
39
+ return nil if request.get?
40
+ form.object.errors.has_key?(name) ? 'is-invalid' : 'is-valid'
41
+ end
42
+
43
+ def default_params
44
+ params.select { |key, value| is_default_param?(key) }
45
+ end
46
+
47
+ def add_default_param_key(key)
48
+ keys = default_param_keys || []
49
+ keys.push(key)
50
+ @default_param_keys = keys
51
+ end
52
+
53
+ def default_param_keys
54
+ @default_param_keys ||= [:page, :start, :length, :per_page]
55
+ end
56
+
57
+ def is_default_param?(key)
58
+ default_param_keys.include?(key.to_sym) || is_sort_param_key?(key)
59
+ end
60
+
61
+ def is_sort_param_key?(key)
62
+ key.to_s.include?('sort_')
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,12 @@
1
+ module Headmin
2
+ module FilterHelper
3
+ def filter_param_exists?(name)
4
+ return false unless params.has_key?(name)
5
+ if params[name].is_a?(Array)
6
+ params[name].reject { |c| c.empty? }.present?
7
+ else
8
+ params[name].present?
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,31 @@
1
+ module Headmin
2
+ module NotificationHelper
3
+ def notification_color(name)
4
+ color = {
5
+ notice: {
6
+ background: 'bg-success',
7
+ text: 'text-white'
8
+ },
9
+ error: {
10
+ text: 'text-dark',
11
+ background: 'bg-danger'
12
+ },
13
+ alert: {
14
+ text: 'text-dark',
15
+ background: 'bg-warning'
16
+ },
17
+ timedout: {
18
+ text: 'text-dark',
19
+ background: 'bg-warning'
20
+ },
21
+ fallback: {
22
+ text: 'text-light',
23
+ background: 'bg-info',
24
+ }
25
+ }
26
+
27
+ name = name.to_sym
28
+ color.key?(name) ? color[name] : color[:fallback]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: {method: :post}) do |f| %>
2
+ <%= render "admin/users/shared/error_messages", resource: resource %>
3
+
4
+ <%= render 'headmin/forms/fields/email', form: f, attribute: :email, required: true, label: :float %>
5
+
6
+ <%= f.submit t('.resend'), class: 'btn btn-lg btn-primary w-100' %>
7
+
8
+ <%= render "admin/users/shared/links" %>
9
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <p><%= t('.welcome', email: @email) %></p>
2
+
3
+ <p><%= t('.confirm_email') %></p>
4
+
5
+ <p><%= link_to t('.confirm'), confirmation_url(@resource, confirmation_token: @token) %></p>
@@ -0,0 +1,7 @@
1
+ <p><%= t('.greeting', email: @email) %></p>
2
+
3
+ <% if @resource.try(:unconfirmed_email?) %>
4
+ <p><%= t('.email_is_changing_to', email: @resource.unconfirmed_email) %></p>
5
+ <% else %>
6
+ <p><%= t('.email_is_changed_to', email: @resource.email) %></p>
7
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <p><%= t('.greeting', email: @resource.email) %></p>
2
+
3
+ <p><%= t('.password_has_changed') %></p>
@@ -0,0 +1,8 @@
1
+ <p><%= t('.greeting', email: @resource.email) %></p>
2
+
3
+ <p><%= t('.someone_requested') %></p>
4
+
5
+ <p><%= link_to t('.change'), edit_password_url(@resource, reset_password_token: @token) %></p>
6
+
7
+ <p><%= t('.not_requested')%></p>
8
+ <p><%= t('.password_not_changed_until') %></p>
@@ -0,0 +1,7 @@
1
+ <p><%= t('.greeting', email: @resource.email) %></p>
2
+
3
+ <p><%= t('.account_locked') %></p>
4
+
5
+ <p><%= t('.click_link') %></p>
6
+
7
+ <p><%= link_to t('.unlock_account'), unlock_url(@resource, unlock_token: @token) %></p>
@@ -0,0 +1,12 @@
1
+ <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: {method: :put}) do |f| %>
2
+ <%= render "admin/users/shared/error_messages", resource: resource %>
3
+
4
+ <%= f.hidden_field :reset_password_token %>
5
+
6
+ <%= render 'headmin/forms/fields/password', form: f, attribute: :password, required: true, label: :float %>
7
+ <%= render 'headmin/forms/fields/password', form: f, attribute: :password_confirmation, required: true, label: :float %>
8
+
9
+ <%= f.submit t('.change_password'), class: 'btn btn-lg btn-primary w-100' %>
10
+
11
+ <%= render "admin/users/shared/links" %>
12
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: {method: :post}) do |f| %>
2
+ <%= render "admin/users/shared/error_messages", resource: resource %>
3
+
4
+ <%= render 'headmin/forms/fields/email', form: f, attribute: :email, required: true, label: :float %>
5
+
6
+ <%= f.submit t('.send_instructions'), class: 'btn btn-lg btn-primary w-100' %>
7
+
8
+ <%= render "admin/users/shared/links" %>
9
+ <% end %>
@@ -0,0 +1,24 @@
1
+ <div>
2
+ <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: {method: :put}) do |f| %>
3
+ <%= render "admin/users/shared/error_messages", resource: resource %>
4
+
5
+ <%= render 'headmin/forms/fields/email', form: f, attribute: :email, required: true, label: :float %>
6
+
7
+ <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
8
+ <div><%= t('.waiting_confirmation', email: resource.unconfirmed_email) %></div>
9
+ <% end %>
10
+
11
+ <%= render 'headmin/forms/fields/password', form: f, attribute: :password, required: true, label: :float %>
12
+ <%= render 'headmin/forms/fields/password', form: f, attribute: :password_confirmation, required: true, label: :float %>
13
+ <%= render 'headmin/forms/fields/password', form: f, attribute: :current_password, required: true, label: :float %>
14
+
15
+ <%= f.submit t('.change'), class: 'btn btn-lg btn-primary w-100' %>
16
+ <% end %>
17
+
18
+ <div class="mt-5">
19
+ <h4><%= t('.cancel') %></h4>
20
+
21
+ <p><%= t('.unhappy') %></p>
22
+ <%= button_to t('.cancel'), registration_path(resource_name), class: 'btn btn-lg btn-danger w-100', data: {confirm: "Are you sure?"}, method: :delete %>
23
+ </div>
24
+ </div>
@@ -0,0 +1,11 @@
1
+ <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
2
+ <%= render "admin/users/shared/error_messages", resource: resource %>
3
+
4
+ <%= render 'headmin/forms/fields/email', form: f, attribute: :email, required: true, label: :float %>
5
+ <%= render 'headmin/forms/fields/password', form: f, attribute: :password, required: true, label: :float %>
6
+ <%= render 'headmin/forms/fields/password', form: f, attribute: :password_confirmation, required: true, label: :float %>
7
+
8
+ <%= f.submit t('.sign_up'), class: 'btn btn-lg btn-primary w-100' %>
9
+
10
+ <%= render "admin/users/shared/links" %>
11
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
2
+
3
+ <%= render 'headmin/forms/fields/email', form: f, attribute: :email, required: true, label: :float %>
4
+ <%= render 'headmin/forms/fields/password', form: f, attribute: :password, required: true, label: :float %>
5
+
6
+ <% if devise_mapping.rememberable? %>
7
+ <%= render 'headmin/forms/fields/checkbox', form: f, attribute: :remember_me, label: true %>
8
+ <% end %>
9
+
10
+ <%= f.submit t('.login'), class: 'btn btn-lg btn-primary w-100' %>
11
+
12
+ <%= render "admin/users/shared/links" %>
13
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <% if resource.errors.any? %>
2
+ <% resource.errors.full_messages.each do |message| %>
3
+ <div class="alert alert-danger" role="alert">
4
+ <%= message %>
5
+ </div>
6
+ <% end %>
7
+ <% end %>
@@ -0,0 +1,27 @@
1
+ <div class="bg-light mt-5 text-end">
2
+ <%- if controller_name != 'sessions' %>
3
+ <%= link_to "Log in", new_session_path(resource_name) %><br />
4
+ <% end %>
5
+
6
+ <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
7
+ <%= link_to "Sign up", new_registration_path(resource_name) %><br />
8
+ <% end %>
9
+
10
+ <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
11
+ <%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
12
+ <% end %>
13
+
14
+ <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
15
+ <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
16
+ <% end %>
17
+
18
+ <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
19
+ <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
20
+ <% end %>
21
+
22
+ <%- if devise_mapping.omniauthable? %>
23
+ <%- resource_class.omniauth_providers.each do |provider| %>
24
+ <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %><br />
25
+ <% end %>
26
+ <% end %>
27
+ </div>
@@ -0,0 +1,10 @@
1
+ <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: {method: :post}) do |f| %>
2
+ <%= render "admin/users/shared/error_messages", resource: resource %>
3
+
4
+ <%= render 'headmin/forms/fields/email', form: f, attribute: :email, required: true, label: :float %>
5
+
6
+ <%= f.submit t('.resend'), class: 'btn btn-lg btn-primary w-100' %>
7
+
8
+ <%= render "admin/users/shared/links" %>
9
+
10
+ <% end %>
@@ -0,0 +1,23 @@
1
+ <%#
2
+ name: headmin/heading/breadcrumbs
3
+ accepts block: no
4
+ parameters:
5
+ breadcrumbs: Breadcrumbs collection
6
+ %>
7
+
8
+ <nav aria-label="breadcrumb">
9
+ <ol class="breadcrumb">
10
+ <% breadcrumb_count = breadcrumbs.count %>
11
+ <% breadcrumbs.each_with_index do |breadcrumb, index| %>
12
+ <% last = (index == breadcrumb_count - 1) %>
13
+ <li class="breadcrumb-item text-muted" aria-current="<%= last ? 'page' : nil %>">
14
+ <% if last %>
15
+ <%= breadcrumb.name %>
16
+ <% else %>
17
+ <%= link_to_unless_current(breadcrumb.name, breadcrumb.path, class: 'text-muted text-decoration-none') %>
18
+ <% end %>
19
+ </li>
20
+ <% end %>
21
+ <li>&nbsp;</li>
22
+ </ol>
23
+ </nav>
@@ -0,0 +1,47 @@
1
+ <%#
2
+ name: headmin/filters
3
+ accepts block: yes
4
+ parameters:
5
+ url: base url to send filter query to
6
+ %>
7
+ <% action = local_assigns.has_key?(:url) ? url : request.url %>
8
+
9
+ <form class="h-filters d-flex align-items-center mb-2" action="<%= action %>" data-controller="filters" data-filters-target="form">
10
+ <%= yield if block_given? %>
11
+
12
+ <!-- Default parameters (e.g. sorting, pagination) -->
13
+ <% default_params.each do |name, value| %>
14
+ <%= hidden_field_tag(name.to_sym, value) %>
15
+ <% end %>
16
+
17
+ <!-- Filter buttons -->
18
+ <div class="h-filter-list d-flex" data-filters-target="list">
19
+ <%= content_for :filters_buttons %>
20
+ </div>
21
+
22
+ <!-- Filter templates -->
23
+ <%= content_for :filters_templates %>
24
+
25
+ <!-- Menu -->
26
+ <% if content_for :filters_menu %>
27
+ <div class="btn-group">
28
+ <button type="button" class="btn btn-link dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
29
+ <%= bootstrap_icon('funnel-fill') %>
30
+ <%= t('.button') %>
31
+ </button>
32
+ <ul class="dropdown-menu">
33
+ <%= content_for :filters_menu %>
34
+ <li><hr class="dropdown-divider"></li>
35
+ <li><a class="dropdown-item text-danger" href="#" data-action="click->filters#removeAll"><%= t('.remove_all') %></a></li>
36
+ </ul>
37
+ </div>
38
+ <% end %>
39
+
40
+ <!-- Separator -->
41
+ <% if content_for(:filters_menu) && content_for(:filters_search) %>
42
+ <span class="separator"></span>
43
+ <% end %>
44
+
45
+ <!-- Search -->
46
+ <%= content_for :filters_search %>
47
+ </form>
@@ -0,0 +1,11 @@
1
+ <%#
2
+ name: headmin/form
3
+ accepts block: yes (required)
4
+ parameters: model
5
+ %>
6
+
7
+ <div class="headmin-form container">
8
+ <%= form_with model: model do |form| %>
9
+ <%= yield(form) %>
10
+ <% end %>
11
+ </div>
@@ -0,0 +1,9 @@
1
+ <%#
2
+ name: headmin/heading
3
+ accepts block: yes
4
+ parameters: none
5
+ %>
6
+
7
+ <div class="h-heading d-flex flex-column flex-md-row align-items-start align-items-md-end justify-content-between">
8
+ <%= yield if block_given? %>
9
+ </div>
@@ -0,0 +1,12 @@
1
+ <%#
2
+ name: headmin/index
3
+ accepts block: yes (required)
4
+ parameters:
5
+ search:
6
+ url: base url to send search query to
7
+ placeholder: placeholder for search field
8
+ %>
9
+
10
+ <div class="headmin-index container-fluid" data-controller="index">
11
+ <%= yield %>
12
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="toast-container position-absolute top-0 end-0 p-3">
2
+ <% flash.each do |name, message| %>
3
+ <div class="toast align-items-center text-white show <%= notification_color(name.to_sym)[:background] %>" role="alert" aria-live="assertive" aria-atomic="true">
4
+ <div class="d-flex">
5
+ <div class="toast-body <%= notification_color(name.to_sym)[:text] %>">
6
+ <%= message %>
7
+ </div>
8
+ <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
9
+ </div>
10
+ </div>
11
+ <% end %>
12
+ </div>
@@ -0,0 +1,13 @@
1
+ <%#
2
+ name: headmin/pagination
3
+ accepts block: no
4
+ parameters:
5
+ collection: Kaminari collection that accepts a method .total_count
6
+ %>
7
+
8
+ <div class="d-flex flex-row-reverse flex-md-row align-items-center w-100 justify-content-between justify-content-md-end">
9
+ <div class="ms-2 me-md-2 text-secondary">
10
+ <%= t('.items', count: collection.total_count) %>
11
+ </div>
12
+ <%= paginate collection, views_prefix: 'headmin' %>
13
+ </div>
@@ -0,0 +1,13 @@
1
+ <%#
2
+ name: headmin/table
3
+ accepts block: yes
4
+ parameters: none
5
+ %>
6
+ <% sort_url = local_assigns.has_key?(:sort_url) ? sort_url : nil %>
7
+ <div class="h-table card my-2 shadow-sm <%= 'table-drag-sort' if sort_url %>" data-sort-url="<%= sort_url %>">
8
+ <div class="table-responsive">
9
+ <table class="table table-hover m-0" data-controller="table" data-table-target="table" data-table-url-value="<%= sort_url %>">
10
+ <%= yield if block_given? %>
11
+ </table>
12
+ </div>
13
+ </div>
@@ -0,0 +1,46 @@
1
+ <%#
2
+ name: headmin/filters/date_range
3
+ accepts block: no
4
+ parameters:
5
+ name: (string) Name of the parameter
6
+ label: (string) Display name
7
+ %>
8
+ <% label = local_assigns.has_key?(:label) ? label : nil %>
9
+ <% name = local_assigns.has_key?(:name) ? name : nil %>
10
+
11
+ <% input_options = {
12
+ placeholder: 'dd/mm/yyyy',
13
+ class: "form-control flatpickr",
14
+ required: true,
15
+ 'data-filters-target': 'input',
16
+ 'data-action': "change->filters#update"
17
+ } %>
18
+
19
+ <%= content_for :filters_menu do %>
20
+ <%= render 'headmin/filters/filter/menu_item', name: name, label: label %>
21
+ <% end %>
22
+
23
+ <%= content_for :filters_templates do %>
24
+ <%= render 'headmin/filters/filter/template', name: name, label: label do %>
25
+ <div class="input-group">
26
+ <span class="input-group-text">
27
+ <%= bootstrap_icon('calendar') %>
28
+ </span>
29
+ <%= date_field_tag(name, nil, input_options) %>
30
+ </div>
31
+ <% end %>
32
+ <% end %>
33
+
34
+ <%= content_for :filters_buttons do %>
35
+ <% if filter_param_exists?(name) %>
36
+ <% value_formatted = Date.parse(params[name]).strftime('%d/%m/%Y') %>
37
+ <%= render 'headmin/filters/filter/button', name: name, label: label, value: value_formatted do %>
38
+ <div class="input-group">
39
+ <span class="input-group-text">
40
+ <%= bootstrap_icon('calendar') %>
41
+ </span>
42
+ <%= date_field_tag(name, params[name], input_options) %>
43
+ </div>
44
+ <% end %>
45
+ <% end %>
46
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <%#
2
+ name: headmin/filters/search
3
+ accepts block: no
4
+ parameters:
5
+ name: (string) Name of the parameter
6
+ model: (Object) model to create a placeholder for
7
+ placeholder: (string) placeholder for search field. Defaults to model name
8
+ %>
9
+ <% name = local_assigns.has_key?(:name) ? name : :search %>
10
+ <% label = local_assigns.has_key?(:label) ? label : nil %>
11
+ <% placeholder = local_assigns.has_key?(:placeholder) ? placeholder : t('.placeholder', resource: label) %>
12
+
13
+ <% value = filter_param_exists?(name) ? params[name] : nil %>
14
+
15
+ <% content_for :filters_search do %>
16
+ <div class="h-filters-search d-flex">
17
+ <input class="form-control me-1" type="search" placeholder="<%= raw placeholder.capitalize %>" aria-label="Search" name="<%= name %>" value="<%= value %>">
18
+ <button class="btn h-btn-outline-light d-none d-md-block" type="submit">
19
+ <%= t('.button') %>
20
+ </button>
21
+ </div>
22
+ <% end %>
@@ -0,0 +1,39 @@
1
+ <%#
2
+ name: headmin/filters/select
3
+ accepts block: no
4
+ parameters:
5
+ name: (string) Name of the parameter
6
+ label: (string) Display name
7
+ options: (array) List of options to select from
8
+ %>
9
+ <% label = local_assigns.has_key?(:label) ? label : nil %>
10
+ <% name = local_assigns.has_key?(:name) ? name : nil %>
11
+ <% options = local_assigns.has_key?(:options) ? options : [] %>
12
+
13
+ <% select_options = {
14
+ class: "form-select",
15
+ prompt: t('.blank'),
16
+ include_blank: false,
17
+ required: true,
18
+ 'data-filters-target': 'input',
19
+ 'data-action': "change->filters#update"
20
+ } %>
21
+
22
+ <%= content_for :filters_menu do %>
23
+ <%= render 'headmin/filters/filter/menu_item', name: name, label: label %>
24
+ <% end %>
25
+
26
+ <%= content_for :filters_templates do %>
27
+ <%= render 'headmin/filters/filter/template', name: name, label: label do %>
28
+ <%= select_tag("#{name}[]", options_for_select(options), select_options) %>
29
+ <% end %>
30
+ <% end %>
31
+
32
+ <%= content_for :filters_buttons do %>
33
+ <% if filter_param_exists?(name) %>
34
+ <% option_name = options.select { |value, key| params[name].include?(key.to_s)}.map{|value, key| value}.join(', ') %>
35
+ <%= render 'headmin/filters/filter/button', name: name, label: label, value: option_name do %>
36
+ <%= select_tag("#{name}[]", options_for_select(options, params[name]), select_options) %>
37
+ <% end %>
38
+ <% end %>
39
+ <% end %>