b4um_generators 0.2.14 → 0.2.16

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1f1050f028cad2eefaf3b2643268bd1e55267aefd8029a8c286e56a5f64b27d
4
- data.tar.gz: be01b49c59c57796e2f9d83ae1d0f065119edc374a2addd64166063a17c6bc15
3
+ metadata.gz: 3872ce0dc22b0119d636611c3948c941da818ed3c8ee65301da95c0570ba677d
4
+ data.tar.gz: 77a2d8228dddbb5852325b81c1e1cc65482dc429912629884cf7c580438dac4e
5
5
  SHA512:
6
- metadata.gz: 107f73e822050fbe81d7a9e12419a988478d63ba929215e6aad778fcc4e8b37a93695b778b95b881b3476eda91c5dec04b497648ad6f1038c011971bfcb89bcf
7
- data.tar.gz: 94552c06de7aba5a9aa211f576447fa8a85dc45fb5eaee2158278d57f1ab8e3cc21727e94d21d2fac36fc356155cba4c2c07bbd7bed55f39cc9a6b4db369e05d
6
+ metadata.gz: 1e44802b32dc4e9ee22c7bd2b4507a34a692777ca0a940b904f0403223b0d36b7bbd9c403579a13cd2fe9409d76f86fd21cc487022d13b4abd7de0ef600f4e6a
7
+ data.tar.gz: 1a20c4ba742c086c788c5426085724d3bea2a3a01e30229ea1dc0f190b6ad4d2819a5c5609e326dd95fdfc4b70beb728260ded64a26416d0725322144e7f6b1b
data/README.de.md CHANGED
@@ -302,16 +302,34 @@ Das Partial verwendet eine lokale Collection und kann daher auch mit einer ander
302
302
  Erzeuge eine wiederverwendbare b4um-Tabelle für ein bestehendes Modell:
303
303
 
304
304
  ```bash
305
- bin/rails generate b4um:table MODEL FIELDS
305
+ bin/rails generate b4um:table MODEL [FIELDS]
306
306
  ```
307
307
 
308
- Beispiel:
308
+ Das Modell muss bereits vorhanden sein.
309
+
310
+ Die Felder sind optional. Werden keine Felder angegeben, erkennt der Generator automatisch die Datenbankfelder des
311
+ Modells, Action-Text-Felder und Active-Storage-Anhänge. `id`, `created_at` und `updated_at` werden automatisch
312
+ ausgeschlossen.
313
+
314
+ Empfohlen:
309
315
 
310
316
  ```bash
311
- bin/rails generate b4um:table Product name:string description:text price:decimal status:string
317
+ bin/rails generate b4um:table Product
312
318
  ```
313
319
 
314
- Das Modell muss bereits vorhanden sein.
320
+ Felder können weiterhin ausdrücklich angegeben werden:
321
+
322
+ ```bash
323
+ bin/rails generate b4um:table Product name price status
324
+ ```
325
+
326
+ Konfigurierte Select- und Radio-Werte können mit ihren Beschriftungen dargestellt werden:
327
+
328
+ ```bash
329
+ bin/rails generate b4um:table Product \
330
+ --select="status:active=Aktiv,inactive=Inaktiv" \
331
+ --radio="condition:new=Neu,used=Gebraucht"
332
+ ```
315
333
 
316
334
  Für ein `Product`-Modell wird das generierte Partial hier gespeichert:
317
335
 
@@ -321,20 +339,33 @@ app/views/products/_table.html.erb
321
339
 
322
340
  Die generierte Tabelle bietet:
323
341
 
342
+ - Automatische Felderkennung aus dem bestehenden Modell
324
343
  - Responsives Tabellenlayout
325
- - Typisierte Felddefinitionen
344
+ - Erkennung der tatsächlichen Feldtypen des Modells
326
345
  - Kürzung von Textfeldern auf 100 Zeichen
346
+ - Formatierung von Dezimalwerten mit zwei Nachkommastellen
327
347
  - Darstellung von Statusfeldern als b4um-Badges
348
+ - Beschriftungen für konfigurierte `--select`- und `--radio`-Werte
349
+ - Action-Text-/Trix-Inhalte
350
+ - Lightbox für Bilder innerhalb von Rich Text
351
+ - Übernahme von Trix-Bildbeschriftungen in die Lightbox
352
+ - Active-Storage-`has_one_attached`-Bilder
353
+ - Active-Storage-`has_many_attached`-Galerien
354
+ - Vorschaubilder, Lightbox-Navigation und Ziehen/Wischen
328
355
  - Aktionsspalte mit Show-Button
329
356
  - Empty-State-Darstellung
330
357
 
331
- Einbindung:
358
+ Beim Aufruf des Tabellen-Generators wird eine vorhandene b4um-Index-Ansicht automatisch auf das Tabellen-Partial
359
+ umgestellt:
332
360
 
333
361
  ```erb
334
362
  <%= render "table", products: @products %>
335
363
  ```
336
364
 
337
- Das Partial kann auch mit einer anderen Collection verwendet werden:
365
+ Wird später `b4um:bento Product` ausgeführt, stellt der Generator den Index wieder auf das Bento-Partial zurück. Das
366
+ gilt auch für die Bento-Layouts `grid`, `list` und `alternating`.
367
+
368
+ Das Tabellen-Partial kann auch mit einer anderen Collection verwendet werden:
338
369
 
339
370
  ```erb
340
371
  <%= render "products/table", products: @featured_products %>
@@ -1104,7 +1135,7 @@ wird.
1104
1135
 
1105
1136
  ## Version
1106
1137
 
1107
- Aktuelle Version: `0.2.14`
1138
+ Aktuelle Version: `0.2.16`
1108
1139
 
1109
1140
  ## Autor
1110
1141
 
data/README.md CHANGED
@@ -299,16 +299,33 @@ The partial uses a local collection and can therefore also be reused with anothe
299
299
  Generate a reusable b4um table for an existing model:
300
300
 
301
301
  ```bash
302
- bin/rails generate b4um:table MODEL FIELDS
302
+ bin/rails generate b4um:table MODEL [FIELDS]
303
303
  ```
304
304
 
305
- Example:
305
+ The model must already exist.
306
+
307
+ Fields are optional. If no fields are supplied, the generator automatically detects the model's database fields, Action
308
+ Text fields and Active Storage attachments. `id`, `created_at` and `updated_at` are excluded automatically.
309
+
310
+ Recommended:
306
311
 
307
312
  ```bash
308
- bin/rails generate b4um:table Product name:string description:text price:decimal status:string
313
+ bin/rails generate b4um:table Product
309
314
  ```
310
315
 
311
- The model must already exist.
316
+ Fields can also be specified explicitly:
317
+
318
+ ```bash
319
+ bin/rails generate b4um:table Product name price status
320
+ ```
321
+
322
+ Configured select and radio values can be displayed using their labels:
323
+
324
+ ```bash
325
+ bin/rails generate b4um:table Product \
326
+ --select="status:active=Active,inactive=Inactive" \
327
+ --radio="condition:new=New,used=Used"
328
+ ```
312
329
 
313
330
  For a `Product` model, the generated partial is stored at:
314
331
 
@@ -318,20 +335,32 @@ app/views/products/_table.html.erb
318
335
 
319
336
  The generated table provides:
320
337
 
338
+ - Automatic field detection from the existing model
321
339
  - Responsive table layout
322
- - Typed field definitions
340
+ - Model-aware field types
323
341
  - Text fields shortened to 100 characters
342
+ - Decimal values formatted with two decimal places
324
343
  - Status fields displayed as b4um badges
344
+ - Labels for configured `--select` and `--radio` values
345
+ - Action Text / Trix content
346
+ - Lightbox support for images embedded in rich text
347
+ - Trix image captions in the Lightbox
348
+ - Active Storage `has_one_attached` images
349
+ - Active Storage `has_many_attached` galleries
350
+ - Thumbnails, Lightbox navigation and drag/swipe support
325
351
  - Actions column with a Show button
326
352
  - Empty-state handling
327
353
 
328
- Render it with:
354
+ Running the Table generator automatically switches an existing b4um index view to the table partial:
329
355
 
330
356
  ```erb
331
357
  <%= render "table", products: @products %>
332
358
  ```
333
359
 
334
- The partial can also be reused with another collection:
360
+ Running `b4um:bento Product` later switches the index back to the Bento partial. This also applies to the `grid`, `list`
361
+ and `alternating` Bento layouts.
362
+
363
+ The table partial can also be reused with another collection:
335
364
 
336
365
  ```erb
337
366
  <%= render "products/table", products: @featured_products %>
@@ -1095,7 +1124,7 @@ The gem can be tested locally by referencing the repository with `path:` from a
1095
1124
 
1096
1125
  ## Version
1097
1126
 
1098
- Current version: `0.2.14`
1127
+ Current version: `0.2.16`
1099
1128
 
1100
1129
  ## Author
1101
1130
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module B4umGenerators
4
- VERSION = "0.2.14"
4
+ VERSION = "0.2.16"
5
5
  end
@@ -45,6 +45,21 @@ module B4um
45
45
  )
46
46
  end
47
47
 
48
+ def update_index_layout
49
+ return unless File.exist?(index_path)
50
+
51
+ index = File.read(index_path)
52
+
53
+ updated_index = index.sub(
54
+ /render\s+["'](?:bento|table|list|alternating)["']/,
55
+ 'render "bento"'
56
+ )
57
+
58
+ return if updated_index == index
59
+
60
+ File.write(index_path, updated_index)
61
+ end
62
+
48
63
  private
49
64
 
50
65
  def model_path
@@ -55,6 +70,15 @@ module B4um
55
70
  )
56
71
  end
57
72
 
73
+ def index_path
74
+ File.join(
75
+ destination_root,
76
+ "app/views",
77
+ plural_table_name,
78
+ "index.html.erb"
79
+ )
80
+ end
81
+
58
82
  def resource_partial_path
59
83
  File.join(
60
84
  destination_root,
@@ -758,15 +758,39 @@ module B4um
758
758
 
759
759
  TABLE
760
760
 
761
- bin/rails generate b4um:table MODEL FIELDS
761
+ bin/rails generate b4um:table MODEL [FIELDS]
762
762
 
763
763
  Generates a reusable b4um table partial for an existing model.
764
764
 
765
- Example:
765
+ The model must already exist.
766
766
 
767
- bin/rails generate b4um:table Product name:string description:text price:decimal status:string
767
+ Fields are optional. If no fields are supplied, the generator
768
+ automatically detects:
768
769
 
769
- The model must already exist.
770
+ - Database fields
771
+ - Action Text rich text fields
772
+ - Active Storage single attachments
773
+ - Active Storage multiple attachments
774
+
775
+ id, created_at and updated_at are excluded automatically.
776
+
777
+ Recommended:
778
+
779
+ bin/rails generate b4um:table Product
780
+
781
+ Fields can also be specified explicitly:
782
+
783
+ bin/rails generate b4um:table Product name price status
784
+
785
+ Select fields can be configured with --select:
786
+
787
+ bin/rails generate b4um:table Product --select='status:active=Active,inactive=Inactive'
788
+
789
+ Radio fields can be configured with --radio:
790
+
791
+ bin/rails generate b4um:table Product --radio='condition:new=New,used=Used'
792
+
793
+ The configured database values are displayed using their labels.
770
794
 
771
795
  The generated partial is created at:
772
796
 
@@ -774,18 +798,34 @@ module B4um
774
798
 
775
799
  Table features:
776
800
 
801
+ - Automatic field detection from the existing model
777
802
  - Responsive b4um table component
778
- - Typed field definitions
803
+ - Model-aware field types
779
804
  - Text fields shortened to 100 characters
780
- - Status field displayed as a b4um badge
805
+ - Decimal values formatted with two decimal places
806
+ - Status fields displayed as b4um badges
807
+ - Select and radio labels
808
+ - Action Text / Trix content
809
+ - Lightbox for images embedded in rich text
810
+ - Trix image captions in the lightbox
811
+ - Active Storage single images
812
+ - Active Storage multiple image galleries
813
+ - Image thumbnails and lightbox navigation
814
+ - Mouse and touch drag / swipe
781
815
  - Actions column with a Show button
816
+ - Empty-state handling
782
817
  - No migrations, routes or controllers are generated
783
818
 
784
- Render the partial from an index view with:
819
+ Running the Table generator automatically switches an existing
820
+ b4um index view to the table partial:
785
821
 
786
822
  <%= render "table", products: @products %>
787
823
 
788
- The partial uses a local collection, so it can also be
824
+ Running b4um:bento later switches the index back to the Bento
825
+ partial. This also applies to the grid, list and alternating
826
+ Bento layouts.
827
+
828
+ The table partial uses a local collection, so it can also be
789
829
  reused with another collection:
790
830
 
791
831
  <%= render "products/table", products: @featured_products %>
@@ -65,3 +65,52 @@
65
65
  .b4um-table td:last-child {
66
66
  padding-right: 1.25rem;
67
67
  }
68
+
69
+ /* -------------------------------------------------------
70
+ Table media
71
+ ------------------------------------------------------- */
72
+
73
+ .b4um-table__media {
74
+ display: flex;
75
+ flex-wrap: wrap;
76
+ gap: 0.5rem;
77
+
78
+ min-width: 100px;
79
+ }
80
+
81
+ .b4um-table__image-button {
82
+ display: block;
83
+
84
+ width: 100px;
85
+ height: 75px;
86
+
87
+ flex: 0 0 100px;
88
+
89
+ padding: 0;
90
+
91
+ border: 0;
92
+ border-radius: 8px;
93
+
94
+ overflow: hidden;
95
+
96
+ background: transparent;
97
+
98
+ cursor: zoom-in;
99
+ }
100
+
101
+ .b4um-table__image {
102
+ display: block;
103
+
104
+ width: 100%;
105
+ height: 100%;
106
+
107
+ border: 0;
108
+ border-radius: 8px;
109
+
110
+ object-fit: cover;
111
+ }
112
+
113
+ .b4um-table__media-empty {
114
+ color: var(--b4um-text-muted);
115
+ font-style: italic;
116
+ }
@@ -32,10 +32,14 @@ export default class extends Controller {
32
32
  if (image.closest('[data-image-lightbox-target="item"]')) return
33
33
 
34
34
  const item = image.closest('a') || image
35
+ const figure = image.closest('figure.attachment')
36
+ const figcaption = figure?.querySelector('figcaption')
37
+ const caption = figcaption?.textContent?.trim() || ''
35
38
 
36
39
  item.dataset.imageLightboxTarget = 'item'
37
40
  item.dataset.imageLightboxUrl = image.currentSrc || image.src
38
41
  item.dataset.imageLightboxAlt = image.alt || ''
42
+ item.dataset.imageLightboxCaption = caption
39
43
 
40
44
  const actions = [item.dataset.action, 'click->image-lightbox#open']
41
45
 
@@ -487,7 +491,7 @@ export default class extends Controller {
487
491
  if (!item) return
488
492
 
489
493
  if (this.hasCaptionTarget) {
490
- this.captionTarget.textContent = item.dataset.imageLightboxAlt || ''
494
+ this.captionTarget.textContent = item.dataset.imageLightboxCaption || item.dataset.imageLightboxAlt || ''
491
495
  }
492
496
 
493
497
  if (this.hasCounterTarget) {
@@ -14,6 +14,14 @@ module B4um
14
14
  default: [],
15
15
  banner: "field:type field:type"
16
16
 
17
+ class_option :select,
18
+ type: :string,
19
+ desc: "Renders a field as a select value. Example: status:Active=Aktiv,Inactive=Inaktiv"
20
+
21
+ class_option :radio,
22
+ type: :string,
23
+ desc: "Renders a field as a radio value. Example: condition:new=Neu,used=Gebraucht"
24
+
17
25
  class << self
18
26
  def desc(_description = nil)
19
27
  "Generates a B4UM table partial for an existing model."
@@ -27,6 +35,22 @@ module B4um
27
35
  "Model not found: app/models/#{file_name}.rb"
28
36
  end
29
37
 
38
+ def validate_editor_configurations
39
+ configurations = {
40
+ select: select_configuration,
41
+ radio: radio_configuration
42
+ }
43
+
44
+ configurations.each do |option_name, configuration|
45
+ validate_editor_configuration(
46
+ option_name,
47
+ configuration
48
+ )
49
+ end
50
+
51
+ validate_editor_configuration_conflict(configurations)
52
+ end
53
+
30
54
  def create_table_partial
31
55
  template(
32
56
  "_table.html.erb.tt",
@@ -38,19 +62,177 @@ module B4um
38
62
  )
39
63
  end
40
64
 
65
+ def update_index_layout
66
+ return unless File.exist?(index_path)
67
+
68
+ index = File.read(index_path)
69
+
70
+ updated_index = index.sub(
71
+ /render\s+["'](?:bento|table|list|alternating)["']/,
72
+ 'render "table"'
73
+ )
74
+
75
+ return if updated_index == index
76
+
77
+ File.write(index_path, updated_index)
78
+ end
79
+
41
80
  private
42
81
 
43
- def table_attributes
44
- fields.map do |field|
45
- name, type = field.split(":", 2)
82
+ def model_class
83
+ class_name.constantize
84
+ end
85
+
86
+ def database_columns
87
+ model_class.columns.index_by(&:name)
88
+ end
89
+
90
+ def rich_text_fields
91
+ model_class.reflect_on_all_associations(:has_one)
92
+ .filter_map do |association|
93
+ association.name.to_s.delete_prefix("rich_text_") if
94
+ association.name.to_s.start_with?("rich_text_")
95
+ end
96
+ end
97
+
98
+ def single_attachment_fields
99
+ model_class.reflect_on_all_attachments
100
+ .select { |reflection| reflection.macro == :has_one_attached }
101
+ .map { |reflection| reflection.name.to_s }
102
+ end
103
+
104
+ def multiple_attachment_fields
105
+ model_class.reflect_on_all_attachments
106
+ .select { |reflection| reflection.macro == :has_many_attached }
107
+ .map { |reflection| reflection.name.to_s }
108
+ end
109
+
110
+ def available_field_names
111
+ (
112
+ database_field_names +
113
+ rich_text_fields +
114
+ single_attachment_fields +
115
+ multiple_attachment_fields
116
+ ).uniq
117
+ end
118
+
119
+ def database_field_names
120
+ database_columns.keys - %w[id created_at updated_at]
121
+ end
122
+
123
+ def field_type(field)
124
+ return :rich_text if rich_text_fields.include?(field)
125
+ return :attachment if single_attachment_fields.include?(field)
126
+ return :attachments if multiple_attachment_fields.include?(field)
127
+
128
+ database_columns.fetch(field).type
129
+ end
130
+
131
+ def table_field_names
132
+ return available_field_names if fields.empty?
133
+
134
+ fields.map { |field| field.split(":", 2).first }
135
+ end
136
+
137
+ def validate_editor_configuration(option_name, configuration)
138
+ return unless options[option_name].present?
139
+
140
+ unless configuration
141
+ raise Thor::Error,
142
+ "Invalid --#{option_name} configuration. " \
143
+ "Expected FIELD:VALUE[,VALUE...]"
144
+ end
145
+
146
+ return if table_field_names.include?(configuration[:field])
147
+
148
+ raise Thor::Error,
149
+ "--#{option_name} field #{configuration[:field]} " \
150
+ "must be one of the generated fields: #{fields.join(", ")}"
151
+ end
152
+
153
+ def validate_editor_configuration_conflict(configurations)
154
+ select = configurations[:select]
155
+ radio = configurations[:radio]
156
+
157
+ return unless select && radio
158
+ return unless select[:field] == radio[:field]
159
+
160
+ raise Thor::Error,
161
+ "Field #{select[:field]} cannot use both --select and --radio"
162
+ end
46
163
 
164
+ def select_configuration
165
+ field_configuration(:select)
166
+ end
167
+
168
+ def radio_configuration
169
+ field_configuration(:radio)
170
+ end
171
+
172
+ def field_configuration(option_name)
173
+ value = options[option_name]
174
+ return unless value.present?
175
+
176
+ field, values = value.split(":", 2)
177
+
178
+ return unless field.present? && values.present?
179
+
180
+ choices = field_choices(values)
181
+ return if choices.empty?
182
+
183
+ {
184
+ field: field,
185
+ values: choices
186
+ }
187
+ end
188
+
189
+ def field_choices(values)
190
+ values.split(",").filter_map do |choice|
191
+ value, label = choice.strip.split("=", 2)
192
+
193
+ next if value.blank?
194
+
195
+ {
196
+ value: value,
197
+ label: label.presence || value
198
+ }
199
+ end
200
+ end
201
+
202
+ def select_field?(field)
203
+ configuration = select_configuration
204
+
205
+ configuration &&
206
+ configuration[:field] == field &&
207
+ configuration[:values].any?
208
+ end
209
+
210
+ def radio_field?(field)
211
+ configuration = radio_configuration
212
+
213
+ configuration &&
214
+ configuration[:field] == field &&
215
+ configuration[:values].any?
216
+ end
217
+
218
+ def table_attributes
219
+ table_field_names.map do |field|
47
220
  TableAttribute.new(
48
- name,
49
- (type || "string").to_sym
221
+ field,
222
+ field_type(field)
50
223
  )
51
224
  end
52
225
  end
53
226
 
227
+ def index_path
228
+ File.join(
229
+ destination_root,
230
+ "app/views",
231
+ plural_table_name,
232
+ "index.html.erb"
233
+ )
234
+ end
235
+
54
236
  def model_path
55
237
  File.join(
56
238
  destination_root,
@@ -14,12 +14,298 @@
14
14
  <tr>
15
15
  <% table_attributes.each do |attribute| -%>
16
16
  <td>
17
+ <% if select_field?(attribute.name) -%>
17
18
  <% if attribute.name == "status" -%>
19
+ <span class="b4um-badge">
20
+ <%%=
21
+ <%= select_configuration[:values].inspect %>.to_h {
22
+ |choice| [choice[:value], choice[:label]]
23
+ }.fetch(
24
+ <%= file_name %>.<%= attribute.name %>,
25
+ <%= file_name %>.<%= attribute.name %>
26
+ )
27
+ %>
28
+ </span>
29
+ <% else -%>
30
+ <%%=
31
+ <%= select_configuration[:values].inspect %>.to_h {
32
+ |choice| [choice[:value], choice[:label]]
33
+ }.fetch(
34
+ <%= file_name %>.<%= attribute.name %>,
35
+ <%= file_name %>.<%= attribute.name %>
36
+ )
37
+ %>
38
+ <% end -%>
39
+ <% elsif radio_field?(attribute.name) -%>
40
+ <%%=
41
+ <%= radio_configuration[:values].inspect %>.to_h {
42
+ |choice| [choice[:value], choice[:label]]
43
+ }.fetch(
44
+ <%= file_name %>.<%= attribute.name %>,
45
+ <%= file_name %>.<%= attribute.name %>
46
+ )
47
+ %>
48
+ <% elsif attribute.type == :rich_text -%>
49
+ <div
50
+ class="b4um-table__rich-text trix-content"
51
+ data-controller="image-lightbox rich-text"
52
+ data-action="keydown->image-lightbox#keydown"
53
+ >
54
+ <%%= <%= file_name %>.<%= attribute.name %> %>
55
+
56
+ <div
57
+ class="image-lightbox"
58
+ data-image-lightbox-target="overlay"
59
+ data-action="click->image-lightbox#closeOnBackground"
60
+ tabindex="-1"
61
+ role="dialog"
62
+ aria-modal="true"
63
+ aria-label="Image preview"
64
+ hidden
65
+ >
66
+ <div
67
+ class="image-lightbox__counter"
68
+ data-image-lightbox-target="counter"
69
+ ></div>
70
+
71
+ <button
72
+ type="button"
73
+ class="image-lightbox__close"
74
+ aria-label="Close image"
75
+ data-action="click->image-lightbox#close"
76
+ >
77
+ &times;
78
+ </button>
79
+
80
+ <button
81
+ type="button"
82
+ class="image-lightbox__navigation image-lightbox__navigation--previous"
83
+ aria-label="Previous image"
84
+ data-action="click->image-lightbox#previous"
85
+ >
86
+ &#8249;
87
+ </button>
88
+
89
+ <div
90
+ class="image-lightbox__stage"
91
+ data-image-lightbox-target="stage"
92
+ data-action="
93
+ pointerdown->image-lightbox#pointerDown
94
+ pointermove->image-lightbox#pointerMove
95
+ pointerup->image-lightbox#pointerUp
96
+ pointercancel->image-lightbox#pointerCancel
97
+ "
98
+ >
99
+ <img
100
+ class="image-lightbox__image"
101
+ data-image-lightbox-target="image"
102
+ alt=""
103
+ >
104
+ </div>
105
+
106
+ <button
107
+ type="button"
108
+ class="image-lightbox__navigation image-lightbox__navigation--next"
109
+ aria-label="Next image"
110
+ data-action="click->image-lightbox#next"
111
+ >
112
+ &#8250;
113
+ </button>
114
+
115
+ <div
116
+ class="image-lightbox__thumbnails"
117
+ data-image-lightbox-target="thumbnails"
118
+ ></div>
119
+
120
+ <div
121
+ class="image-lightbox__caption"
122
+ data-image-lightbox-target="caption"
123
+ ></div>
124
+ </div>
125
+ </div>
126
+ <% elsif attribute.type == :attachment -%>
127
+ <%% if <%= file_name %>.<%= attribute.name %>.attached? %>
128
+ <div
129
+ class="b4um-table__media"
130
+ data-controller="image-lightbox"
131
+ data-action="keydown->image-lightbox#keydown"
132
+ >
133
+ <button
134
+ type="button"
135
+ class="b4um-table__image-button"
136
+ data-image-lightbox-target="item"
137
+ data-image-lightbox-url="<%%= url_for(<%= file_name %>.<%= attribute.name %>) %>"
138
+ data-image-lightbox-alt="<%%= <%= file_name %>.<%= attribute.name %>.filename.to_s %>"
139
+ data-action="click->image-lightbox#open"
140
+ >
141
+ <%%= image_tag <%= file_name %>.<%= attribute.name %>,
142
+ class: "b4um-table__image",
143
+ alt: <%= file_name %>.<%= attribute.name %>.filename.to_s %>
144
+ </button>
145
+
146
+ <div
147
+ class="image-lightbox"
148
+ data-image-lightbox-target="overlay"
149
+ data-action="click->image-lightbox#closeOnBackground"
150
+ tabindex="-1"
151
+ role="dialog"
152
+ aria-modal="true"
153
+ aria-label="Image preview"
154
+ hidden
155
+ >
156
+ <div
157
+ class="image-lightbox__counter"
158
+ data-image-lightbox-target="counter"
159
+ ></div>
160
+
161
+ <button
162
+ type="button"
163
+ class="image-lightbox__close"
164
+ aria-label="Close image"
165
+ data-action="click->image-lightbox#close"
166
+ >
167
+ &times;
168
+ </button>
169
+
170
+ <div
171
+ class="image-lightbox__stage"
172
+ data-image-lightbox-target="stage"
173
+ data-action="
174
+ pointerdown->image-lightbox#pointerDown
175
+ pointermove->image-lightbox#pointerMove
176
+ pointerup->image-lightbox#pointerUp
177
+ pointercancel->image-lightbox#pointerCancel
178
+ "
179
+ >
180
+ <img
181
+ class="image-lightbox__image"
182
+ data-image-lightbox-target="image"
183
+ alt=""
184
+ >
185
+ </div>
186
+
187
+ <div
188
+ class="image-lightbox__thumbnails"
189
+ data-image-lightbox-target="thumbnails"
190
+ ></div>
191
+
192
+ <div
193
+ class="image-lightbox__caption"
194
+ data-image-lightbox-target="caption"
195
+ ></div>
196
+ </div>
197
+ </div>
198
+ <%% else %>
199
+ <span class="b4um-table__media-empty">No image</span>
200
+ <%% end %>
201
+ <% elsif attribute.type == :attachments -%>
202
+ <%% if <%= file_name %>.<%= attribute.name %>.attached? %>
203
+ <div
204
+ class="b4um-table__media"
205
+ data-controller="image-lightbox"
206
+ data-action="keydown->image-lightbox#keydown"
207
+ >
208
+ <%% <%= file_name %>.<%= attribute.name %>.each do |image| %>
209
+ <button
210
+ type="button"
211
+ class="b4um-table__image-button"
212
+ data-image-lightbox-target="item"
213
+ data-image-lightbox-url="<%%= url_for(image) %>"
214
+ data-image-lightbox-alt="<%%= image.filename.to_s %>"
215
+ data-action="click->image-lightbox#open"
216
+ >
217
+ <%%= image_tag image,
218
+ class: "b4um-table__image",
219
+ alt: image.filename.to_s %>
220
+ </button>
221
+ <%% end %>
222
+
223
+ <div
224
+ class="image-lightbox"
225
+ data-image-lightbox-target="overlay"
226
+ data-action="click->image-lightbox#closeOnBackground"
227
+ tabindex="-1"
228
+ role="dialog"
229
+ aria-modal="true"
230
+ aria-label="Image gallery"
231
+ hidden
232
+ >
233
+ <div
234
+ class="image-lightbox__counter"
235
+ data-image-lightbox-target="counter"
236
+ ></div>
237
+
238
+ <button
239
+ type="button"
240
+ class="image-lightbox__close"
241
+ aria-label="Close image"
242
+ data-action="click->image-lightbox#close"
243
+ >
244
+ &times;
245
+ </button>
246
+
247
+ <button
248
+ type="button"
249
+ class="image-lightbox__navigation image-lightbox__navigation--previous"
250
+ aria-label="Previous image"
251
+ data-action="click->image-lightbox#previous"
252
+ >
253
+ &#8249;
254
+ </button>
255
+
256
+ <div
257
+ class="image-lightbox__stage"
258
+ data-image-lightbox-target="stage"
259
+ data-action="
260
+ pointerdown->image-lightbox#pointerDown
261
+ pointermove->image-lightbox#pointerMove
262
+ pointerup->image-lightbox#pointerUp
263
+ pointercancel->image-lightbox#pointerCancel
264
+ "
265
+ >
266
+ <img
267
+ class="image-lightbox__image"
268
+ data-image-lightbox-target="image"
269
+ alt=""
270
+ >
271
+ </div>
272
+
273
+ <button
274
+ type="button"
275
+ class="image-lightbox__navigation image-lightbox__navigation--next"
276
+ aria-label="Next image"
277
+ data-action="click->image-lightbox#next"
278
+ >
279
+ &#8250;
280
+ </button>
281
+
282
+ <div
283
+ class="image-lightbox__thumbnails"
284
+ data-image-lightbox-target="thumbnails"
285
+ ></div>
286
+
287
+ <div
288
+ class="image-lightbox__caption"
289
+ data-image-lightbox-target="caption"
290
+ ></div>
291
+ </div>
292
+ </div>
293
+ <%% else %>
294
+ <span class="b4um-table__media-empty">No images</span>
295
+ <%% end %>
296
+ <% elsif attribute.name == "status" -%>
18
297
  <span class="b4um-badge">
19
298
  <%%= <%= file_name %>.<%= attribute.name %> %>
20
299
  </span>
21
300
  <% elsif attribute.type == :text -%>
22
301
  <%%= truncate(<%= file_name %>.<%= attribute.name %>, length: 100) %>
302
+ <% elsif attribute.type == :decimal -%>
303
+ <%%= number_with_precision(
304
+ <%= file_name %>.<%= attribute.name %>,
305
+ precision: 2,
306
+ delimiter: ".",
307
+ separator: ","
308
+ ) %>
23
309
  <% else -%>
24
310
  <%%= <%= file_name %>.<%= attribute.name %> %>
25
311
  <% end -%>
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: b4um_generators
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.14
4
+ version: 0.2.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Baum
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
10
+ date: 2026-10-09 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: railties
@@ -171,7 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
171
  - !ruby/object:Gem::Version
172
172
  version: '0'
173
173
  requirements: []
174
- rubygems_version: 3.6.9
174
+ rubygems_version: 3.6.2
175
175
  specification_version: 4
176
176
  summary: Rails generators for b4um applications
177
177
  test_files: []