b4um_generators 0.1.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.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +28 -0
  4. data/CHANGELOG.md +5 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.de.md +821 -0
  7. data/README.md +815 -0
  8. data/Rakefile +12 -0
  9. data/b4um_generators.gemspec +30 -0
  10. data/bin/console +11 -0
  11. data/bin/setup +8 -0
  12. data/lib/b4um_generators/version.rb +5 -0
  13. data/lib/b4um_generators.rb +8 -0
  14. data/lib/generators/b4um/bento/bento_generator.rb +81 -0
  15. data/lib/generators/b4um/bento/templates/_alternating.html.erb.tt +15 -0
  16. data/lib/generators/b4um/bento/templates/_bento.html.erb.tt +26 -0
  17. data/lib/generators/b4um/bento/templates/_grid.html.erb.tt +13 -0
  18. data/lib/generators/b4um/bento/templates/_list.html.erb.tt +15 -0
  19. data/lib/generators/b4um/comments/comments_generator.rb +259 -0
  20. data/lib/generators/b4um/comments/templates/_comments.html.erb.tt +63 -0
  21. data/lib/generators/b4um/comments/templates/comment.rb.tt +5 -0
  22. data/lib/generators/b4um/comments/templates/comments_controller.rb.tt +45 -0
  23. data/lib/generators/b4um/comments/templates/create_comments.rb.tt +14 -0
  24. data/lib/generators/b4um/controller/controller_generator.rb +397 -0
  25. data/lib/generators/b4um/help/help_generator.rb +755 -0
  26. data/lib/generators/b4um/infinite_scroll/infinite_scroll_generator.rb +199 -0
  27. data/lib/generators/b4um/infinite_scroll/templates/infinite_scroll_controller.js +61 -0
  28. data/lib/generators/b4um/install/install_generator.rb +492 -0
  29. data/lib/generators/b4um/install/templates/_cookie_consent.html.erb +27 -0
  30. data/lib/generators/b4um/install/templates/_footer.html.erb +17 -0
  31. data/lib/generators/b4um/install/templates/_hero.html.erb +33 -0
  32. data/lib/generators/b4um/install/templates/_navigation.html.erb +31 -0
  33. data/lib/generators/b4um/install/templates/_sitemap.html.erb +48 -0
  34. data/lib/generators/b4um/install/templates/_theme_switcher.html.erb +57 -0
  35. data/lib/generators/b4um/install/templates/b4um/badges.css +43 -0
  36. data/lib/generators/b4um/install/templates/b4um/base.css +42 -0
  37. data/lib/generators/b4um/install/templates/b4um/callouts.css +58 -0
  38. data/lib/generators/b4um/install/templates/b4um/cards.css +401 -0
  39. data/lib/generators/b4um/install/templates/b4um/comments.css +52 -0
  40. data/lib/generators/b4um/install/templates/b4um/cookie-consent.css +83 -0
  41. data/lib/generators/b4um/install/templates/b4um/empty-state.css +26 -0
  42. data/lib/generators/b4um/install/templates/b4um/flash.css +86 -0
  43. data/lib/generators/b4um/install/templates/b4um/footer.css +338 -0
  44. data/lib/generators/b4um/install/templates/b4um/forms.css +924 -0
  45. data/lib/generators/b4um/install/templates/b4um/hero.css +149 -0
  46. data/lib/generators/b4um/install/templates/b4um/layout.css +166 -0
  47. data/lib/generators/b4um/install/templates/b4um/lightbox.css +268 -0
  48. data/lib/generators/b4um/install/templates/b4um/navigation.css +257 -0
  49. data/lib/generators/b4um/install/templates/b4um/pagination.css +85 -0
  50. data/lib/generators/b4um/install/templates/b4um/resources.css +121 -0
  51. data/lib/generators/b4um/install/templates/b4um/search.css +41 -0
  52. data/lib/generators/b4um/install/templates/b4um/tables.css +67 -0
  53. data/lib/generators/b4um/install/templates/b4um/theme-switcher.css +178 -0
  54. data/lib/generators/b4um/install/templates/b4um/theme.css +132 -0
  55. data/lib/generators/b4um/install/templates/b4um.css +20 -0
  56. data/lib/generators/b4um/install/templates/b4um.yml +12 -0
  57. data/lib/generators/b4um/install/templates/b4um_helper.rb +27 -0
  58. data/lib/generators/b4um/install/templates/cookie_consent_controller.js +76 -0
  59. data/lib/generators/b4um/install/templates/dismissible_controller.js +7 -0
  60. data/lib/generators/b4um/install/templates/image_lightbox_controller.js +414 -0
  61. data/lib/generators/b4um/install/templates/image_preview_controller.js +85 -0
  62. data/lib/generators/b4um/install/templates/navigation_controller.js +25 -0
  63. data/lib/generators/b4um/install/templates/navigation_helper.rb +26 -0
  64. data/lib/generators/b4um/install/templates/sitemap_controller.js +35 -0
  65. data/lib/generators/b4um/install/templates/theme_controller.js +122 -0
  66. data/lib/generators/b4um/pagination/pagination_generator.rb +179 -0
  67. data/lib/generators/b4um/pagination/templates/_pagination.html.erb.tt +48 -0
  68. data/lib/generators/b4um/pagination/templates/pagination.rb +36 -0
  69. data/lib/generators/b4um/scaffold/scaffold_generator.rb +333 -0
  70. data/lib/generators/b4um/scaffold/templates/_bento.html.erb.tt +26 -0
  71. data/lib/generators/b4um/scaffold/templates/_form.html.erb.tt +218 -0
  72. data/lib/generators/b4um/scaffold/templates/_resource.html.erb.tt +144 -0
  73. data/lib/generators/b4um/scaffold/templates/_table.html.erb.tt +40 -0
  74. data/lib/generators/b4um/scaffold/templates/edit.html.erb.tt +21 -0
  75. data/lib/generators/b4um/scaffold/templates/index.html.erb.tt +24 -0
  76. data/lib/generators/b4um/scaffold/templates/new.html.erb.tt +17 -0
  77. data/lib/generators/b4um/scaffold/templates/show.html.erb.tt +31 -0
  78. data/lib/generators/b4um/search/search_generator.rb +165 -0
  79. data/lib/generators/b4um/search/templates/search.rb +34 -0
  80. data/lib/generators/b4um/search/templates/search_form.html.erb.tt +15 -0
  81. data/lib/generators/b4um/table/table_generator.rb +63 -0
  82. data/lib/generators/b4um/table/templates/_table.html.erb.tt +40 -0
  83. data/lib/generators/b4um/trix/templates/b4um_rich_text_helper.rb +58 -0
  84. data/lib/generators/b4um/trix/templates/b4um_trix.js +551 -0
  85. data/lib/generators/b4um/trix/trix_generator.rb +383 -0
  86. data/sig/b4um_generators.rbs +4 -0
  87. metadata +148 -0
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/named_base"
5
+
6
+ module B4um
7
+ module Generators
8
+ class PaginationGenerator < Rails::Generators::NamedBase
9
+ source_root File.expand_path("templates", __dir__)
10
+
11
+ class_option :per_page,
12
+ type: :numeric,
13
+ default: 20,
14
+ desc: "Number of records per page"
15
+
16
+ class << self
17
+ def desc(_description = nil)
18
+ "Adds B4UM pagination to an existing resource."
19
+ end
20
+ end
21
+
22
+ def validate_model
23
+ return if File.exist?(model_path)
24
+
25
+ raise Thor::Error,
26
+ "Model not found: app/models/#{file_name}.rb"
27
+ end
28
+
29
+ def validate_controller
30
+ return if File.exist?(controller_path)
31
+
32
+ raise Thor::Error,
33
+ "Controller not found: app/controllers/#{plural_table_name}_controller.rb"
34
+ end
35
+
36
+ def validate_index_view
37
+ return if File.exist?(index_view_path)
38
+
39
+ raise Thor::Error,
40
+ "Index view not found: app/views/#{plural_table_name}/index.html.erb"
41
+ end
42
+
43
+ def validate_per_page
44
+ return if options[:per_page].positive?
45
+
46
+ raise Thor::Error,
47
+ "--per-page must be greater than 0"
48
+ end
49
+
50
+ def create_pagination_concern
51
+ template(
52
+ "pagination.rb",
53
+ "app/controllers/concerns/b4um_pagination.rb"
54
+ )
55
+ end
56
+
57
+ def create_pagination_partial
58
+ template(
59
+ "_pagination.html.erb.tt",
60
+ "app/views/shared/_pagination.html.erb"
61
+ )
62
+ end
63
+
64
+ def update_controller
65
+ controller_content = File.read(controller_path)
66
+
67
+ unless controller_content.include?("include B4umPagination")
68
+ inject_into_class(
69
+ controller_path,
70
+ "#{class_name.pluralize}Controller",
71
+ " include B4umPagination\n\n"
72
+ )
73
+
74
+ controller_content = File.read(controller_path)
75
+ end
76
+
77
+ return if controller_content.include?(paginated_collection)
78
+
79
+ if controller_content.match?(search_pattern)
80
+ paginate_existing_search
81
+ return
82
+ end
83
+
84
+ paginate_plain_collection(controller_content)
85
+ end
86
+
87
+ def update_index_view
88
+ index_content = File.read(index_view_path)
89
+
90
+ return if index_content.include?('render "shared/pagination"')
91
+
92
+ append_to_file(
93
+ index_view_path,
94
+ <<~ERB
95
+
96
+ <%= render "shared/pagination", pagination: @pagination %>
97
+ ERB
98
+ )
99
+ end
100
+
101
+ private
102
+
103
+ def paginated_collection
104
+ "@#{plural_table_name}, @pagination = b4um_paginate("
105
+ end
106
+
107
+ def search_pattern
108
+ /
109
+ @#{Regexp.escape(plural_table_name)}\s*=\s*
110
+ b4um_search\(\s*
111
+ #{Regexp.escape(class_name)}\.all,\s*
112
+ params\[:q\]\s*
113
+ \)
114
+ /x
115
+ end
116
+
117
+ def paginate_existing_search
118
+ gsub_file(
119
+ controller_path,
120
+ search_pattern,
121
+ [
122
+ "@#{plural_table_name}, @pagination = b4um_paginate(",
123
+ " b4um_search(",
124
+ " #{class_name}.all,",
125
+ " params[:q]",
126
+ " ),",
127
+ " per_page: #{options[:per_page]}",
128
+ " )"
129
+ ].join("\n")
130
+ )
131
+ end
132
+
133
+ def paginate_plain_collection(controller_content)
134
+ old_index = "@#{plural_table_name} = #{class_name}.all"
135
+
136
+ unless controller_content.include?(old_index)
137
+ raise Thor::Error,
138
+ "Could not find the index collection in app/controllers/#{plural_table_name}_controller.rb"
139
+ end
140
+
141
+ gsub_file(
142
+ controller_path,
143
+ old_index,
144
+ [
145
+ "@#{plural_table_name}, @pagination = b4um_paginate(",
146
+ " #{class_name}.all,",
147
+ " per_page: #{options[:per_page]}",
148
+ " )"
149
+ ].join("\n")
150
+ )
151
+ end
152
+
153
+ def model_path
154
+ File.join(
155
+ destination_root,
156
+ "app/models",
157
+ "#{file_name}.rb"
158
+ )
159
+ end
160
+
161
+ def controller_path
162
+ File.join(
163
+ destination_root,
164
+ "app/controllers",
165
+ "#{plural_table_name}_controller.rb"
166
+ )
167
+ end
168
+
169
+ def index_view_path
170
+ File.join(
171
+ destination_root,
172
+ "app/views",
173
+ plural_table_name,
174
+ "index.html.erb"
175
+ )
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,48 @@
1
+ <%% if pagination.total_pages > 1 %>
2
+ <nav class="b4um-pagination" aria-label="Pagination">
3
+ <div class="b4um-pagination__previous">
4
+ <%% if pagination.previous_page %>
5
+ <%%= link_to "Previous",
6
+ url_for(request.query_parameters.merge(page: pagination.previous_page)),
7
+ class: "button button--secondary" %>
8
+ <%% end %>
9
+ </div>
10
+
11
+ <div class="b4um-pagination__pages">
12
+ <%% pages = (1..pagination.total_pages).select do |page| %>
13
+ <%% page == 1 ||
14
+ page == pagination.total_pages ||
15
+ (page - pagination.current_page).abs <= 2 %>
16
+ <%% end %>
17
+
18
+ <%% previous_page = nil %>
19
+
20
+ <%% pages.each do |page| %>
21
+ <%% if previous_page && page > previous_page + 1 %>
22
+ <span class="b4um-pagination__ellipsis" aria-hidden="true">…</span>
23
+ <%% end %>
24
+
25
+ <%% if page == pagination.current_page %>
26
+ <span class="b4um-pagination__current"
27
+ aria-current="page">
28
+ <%%= page %>
29
+ </span>
30
+ <%% else %>
31
+ <%%= link_to page,
32
+ url_for(request.query_parameters.merge(page: page)),
33
+ class: "b4um-pagination__page" %>
34
+ <%% end %>
35
+
36
+ <%% previous_page = page %>
37
+ <%% end %>
38
+ </div>
39
+
40
+ <div class="b4um-pagination__next">
41
+ <%% if pagination.next_page %>
42
+ <%%= link_to "Next",
43
+ url_for(request.query_parameters.merge(page: pagination.next_page)),
44
+ class: "button button--secondary" %>
45
+ <%% end %>
46
+ </div>
47
+ </nav>
48
+ <%% end %>
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module B4umPagination
4
+ Pagination = Data.define(
5
+ :current_page,
6
+ :per_page,
7
+ :total_count,
8
+ :total_pages,
9
+ :previous_page,
10
+ :next_page
11
+ )
12
+
13
+ private
14
+
15
+ def b4um_paginate(scope, per_page:)
16
+ current_page = [params.fetch(:page, 1).to_i, 1].max
17
+ total_count = scope.count
18
+ total_pages = [(total_count.to_f / per_page).ceil, 1].max
19
+ current_page = [current_page, total_pages].min
20
+
21
+ records = scope
22
+ .limit(per_page)
23
+ .offset((current_page - 1) * per_page)
24
+
25
+ pagination = Pagination.new(
26
+ current_page: current_page,
27
+ per_page: per_page,
28
+ total_count: total_count,
29
+ total_pages: total_pages,
30
+ previous_page: current_page > 1 ? current_page - 1 : nil,
31
+ next_page: current_page < total_pages ? current_page + 1 : nil
32
+ )
33
+
34
+ [records, pagination]
35
+ end
36
+ end
@@ -0,0 +1,333 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "action_dispatch"
5
+ require "rails/generators/rails/scaffold/scaffold_generator"
6
+
7
+ module B4um
8
+ module Generators
9
+ class ScaffoldGenerator < Rails::Generators::ScaffoldGenerator
10
+ source_root File.expand_path("templates", __dir__)
11
+
12
+ class << self
13
+ def desc(_description = nil)
14
+ "Generates a B4UM scaffold."
15
+ end
16
+ end
17
+
18
+ class_option :param,
19
+ type: :string,
20
+ desc: "Attribute used for a readable URL parameter"
21
+
22
+ class_option :layout,
23
+ type: :string,
24
+ default: "bento",
25
+ enum: %w[bento table],
26
+ desc: "Index layout: bento or table"
27
+
28
+ def create_b4um_form
29
+ form_path = File.join(
30
+ "app/views",
31
+ plural_table_name,
32
+ "_form.html.erb"
33
+ )
34
+
35
+ remove_file form_path
36
+
37
+ template(
38
+ "_form.html.erb.tt",
39
+ form_path
40
+ )
41
+ end
42
+
43
+ def create_b4um_resource
44
+ resource_path = File.join(
45
+ "app/views",
46
+ plural_table_name,
47
+ "_#{singular_table_name}.html.erb"
48
+ )
49
+
50
+ remove_file resource_path
51
+
52
+ template(
53
+ "_resource.html.erb.tt",
54
+ resource_path
55
+ )
56
+ end
57
+
58
+ def create_b4um_index
59
+ index_path = File.join(
60
+ "app/views",
61
+ plural_table_name,
62
+ "index.html.erb"
63
+ )
64
+
65
+ partial_path = File.join(
66
+ "app/views",
67
+ plural_table_name,
68
+ "_#{options[:layout]}.html.erb"
69
+ )
70
+
71
+ remove_file index_path
72
+
73
+ template(
74
+ "index.html.erb.tt",
75
+ index_path
76
+ )
77
+
78
+ template(
79
+ "_#{options[:layout]}.html.erb.tt",
80
+ partial_path
81
+ )
82
+ end
83
+
84
+ def create_b4um_show
85
+ show_path = File.join(
86
+ "app/views",
87
+ plural_table_name,
88
+ "show.html.erb"
89
+ )
90
+
91
+ remove_file show_path
92
+
93
+ template(
94
+ "show.html.erb.tt",
95
+ show_path
96
+ )
97
+ end
98
+
99
+ def create_b4um_new
100
+ new_path = File.join(
101
+ "app/views",
102
+ plural_table_name,
103
+ "new.html.erb"
104
+ )
105
+
106
+ remove_file new_path
107
+
108
+ template(
109
+ "new.html.erb.tt",
110
+ new_path
111
+ )
112
+ end
113
+
114
+ def create_b4um_edit
115
+ edit_path = File.join(
116
+ "app/views",
117
+ plural_table_name,
118
+ "edit.html.erb"
119
+ )
120
+
121
+ remove_file edit_path
122
+
123
+ template(
124
+ "edit.html.erb.tt",
125
+ edit_path
126
+ )
127
+ end
128
+
129
+ def add_secure_password
130
+ return unless attributes.any? { |attribute| attribute.name == "password_digest" }
131
+
132
+ inject_into_class(
133
+ File.join("app/models", "#{singular_table_name}.rb"),
134
+ class_name,
135
+ " has_secure_password\n"
136
+ )
137
+ end
138
+
139
+ def add_bcrypt
140
+ return unless attributes.any? { |attribute| attribute.name == "password_digest" }
141
+
142
+ gemfile_path = "Gemfile"
143
+ gemfile = File.read(gemfile_path)
144
+
145
+ if gemfile.match?(/^#\s*gem ["']bcrypt["']/)
146
+ uncomment_lines gemfile_path, /gem ["']bcrypt["']/
147
+ elsif !gemfile.match?(/^gem ["']bcrypt["']/)
148
+ gem "bcrypt", "~> 3.1"
149
+ end
150
+ end
151
+
152
+ def update_password_params
153
+ return unless attributes.any? { |attribute| attribute.name == "password_digest" }
154
+
155
+ controller_path = File.join(
156
+ "app/controllers",
157
+ "#{plural_table_name}_controller.rb"
158
+ )
159
+
160
+ gsub_file(
161
+ controller_path,
162
+ ":password_digest",
163
+ ":password, :password_confirmation"
164
+ )
165
+ end
166
+
167
+ def update_multiple_attachments
168
+ attachment_attributes = attributes.select do |attribute|
169
+ attribute.type == :attachments
170
+ end
171
+
172
+ return if attachment_attributes.empty?
173
+
174
+ controller_path = File.join(
175
+ "app/controllers",
176
+ "#{plural_table_name}_controller.rb"
177
+ )
178
+
179
+ attachment_names = attachment_attributes.map(&:name)
180
+
181
+ setup_lines = attachment_names.map do |name|
182
+ [
183
+ " new_#{name} = update_params.delete(\"#{name}\")",
184
+ " remove_#{name}_ids = update_params.delete(\"remove_#{name}_ids\")"
185
+ ]
186
+ end.flatten.join("\n")
187
+
188
+ attachment_lines = attachment_names.map do |name|
189
+ [
190
+ " @#{singular_table_name}.#{name}.attach(new_#{name}) if new_#{name}.present?",
191
+ "",
192
+ " if remove_#{name}_ids.present?",
193
+ " @#{singular_table_name}.#{name}.attachments",
194
+ " .where(id: remove_#{name}_ids)",
195
+ " .find_each(&:purge)",
196
+ " end"
197
+ ]
198
+ end.flatten.join("\n")
199
+
200
+ gsub_file(
201
+ controller_path,
202
+ " def update\n respond_to do |format|\n",
203
+ [
204
+ " def update",
205
+ " update_params = #{singular_table_name}_params",
206
+ setup_lines,
207
+ "",
208
+ " respond_to do |format|",
209
+ ""
210
+ ].join("\n")
211
+ )
212
+
213
+ gsub_file(
214
+ controller_path,
215
+ " if @#{singular_table_name}.update(#{singular_table_name}_params)\n",
216
+ [
217
+ " if @#{singular_table_name}.update(update_params)",
218
+ attachment_lines,
219
+ ""
220
+ ].join("\n")
221
+ )
222
+
223
+ attachment_names.each do |name|
224
+ gsub_file(
225
+ controller_path,
226
+ "#{name}: []",
227
+ "#{name}: [], remove_#{name}_ids: []"
228
+ )
229
+ end
230
+ end
231
+
232
+ def add_readable_param
233
+ param_name = options[:param]
234
+
235
+ return if param_name.blank?
236
+
237
+ unless attributes.any? { |attribute| attribute.name == param_name }
238
+ say_status(
239
+ :warning,
240
+ "--param=#{param_name} ignored: attribute does not exist",
241
+ :yellow
242
+ )
243
+
244
+ return
245
+ end
246
+
247
+ inject_into_class(
248
+ File.join("app/models", "#{singular_table_name}.rb"),
249
+ class_name,
250
+ <<~RUBY
251
+ def to_param
252
+ "\#{id} \#{#{param_name}}".parameterize
253
+ end
254
+ RUBY
255
+ )
256
+ end
257
+
258
+ def update_destroy_flash
259
+ controller_path = File.join(
260
+ "app/controllers",
261
+ "#{plural_table_name}_controller.rb"
262
+ )
263
+
264
+ controller = File.read(
265
+ File.join(destination_root, controller_path)
266
+ )
267
+
268
+ # Rails-Scaffold mit respond_to / format.html
269
+ if controller.match?(
270
+ /format\.html \{ redirect_to ([^,]+), notice: ("[^"]* was successfully destroyed\."), status: :see_other \}/
271
+ )
272
+ gsub_file(
273
+ controller_path,
274
+ /
275
+ format\.html\ \{\ redirect_to\ ([^,]+),
276
+ \ notice:\ ("[^"]*\ was\ successfully\ destroyed\."),
277
+ \ status:\ :see_other\ \}
278
+ /x,
279
+ <<~RUBY.chomp
280
+ format.html do
281
+ flash[:deleted] = \\2
282
+ redirect_to \\1, status: :see_other
283
+ end
284
+ RUBY
285
+ )
286
+
287
+ return
288
+ end
289
+
290
+ # Rails-Scaffold ohne respond_to
291
+ gsub_file(
292
+ controller_path,
293
+ /redirect_to ([^,]+), notice: ("[^"]* was successfully destroyed\."), status: :see_other/,
294
+ <<~RUBY.chomp
295
+ flash[:deleted] = \\2
296
+ redirect_to \\1, status: :see_other
297
+ RUBY
298
+ )
299
+ end
300
+
301
+ def add_navigation_link
302
+ navigation_path = "app/views/shared/_navigation.html.erb"
303
+ full_navigation_path = File.join(destination_root, navigation_path)
304
+
305
+ return unless File.exist?(full_navigation_path)
306
+
307
+ navigation = File.read(full_navigation_path)
308
+
309
+ return if navigation.include?(
310
+ "controller: :#{plural_table_name}"
311
+ )
312
+
313
+ marker = "<%# B4UM_NAVIGATION_LINKS %>"
314
+
315
+ return unless navigation.include?(marker)
316
+
317
+ navigation_link = <<~ERB
318
+ <%= navigation_link_to "#{plural_table_name.humanize}",
319
+ #{plural_route_name}_path,
320
+ controller: :#{plural_table_name} %>
321
+
322
+ #{marker}
323
+ ERB
324
+
325
+ gsub_file(
326
+ navigation_path,
327
+ marker,
328
+ navigation_link.chomp
329
+ )
330
+ end
331
+ end
332
+ end
333
+ end
@@ -0,0 +1,26 @@
1
+ <div id="<%= plural_table_name %>" class="b4um-grid">
2
+ <%% <%= plural_table_name %>.each_with_index do |<%= singular_table_name %>, index| %>
3
+ <%% card_class =
4
+ case index % 5
5
+ when 0
6
+ "b4um-card b4um-card--wide"
7
+ when 1
8
+ "b4um-card b4um-card--soft"
9
+ when 3
10
+ "b4um-card b4um-card--large"
11
+ else
12
+ "b4um-card"
13
+ end
14
+ %>
15
+
16
+ <article class="<%%= card_class %>">
17
+ <%%= render <%= singular_table_name %>, compact: true %>
18
+
19
+ <div class="b4um-card__actions">
20
+ <%%= link_to "Show",
21
+ <%= singular_table_name %>,
22
+ class: "button button--secondary" %>
23
+ </div>
24
+ </article>
25
+ <%% end %>
26
+ </div>