tramway 3.1.2.4 → 3.1.2.6

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: f525c9fd76a1edc7050318ead14629ddf7c4be7d9d53dcc14b61ee04b5563d18
4
- data.tar.gz: 486e418f27e02dae869e2ef625167998e737e0f9ff2a49fa47caa46fe1fc9d74
3
+ metadata.gz: c9b234f727ff8de6c0d6f910d4132ae760f304db2b2e4fb211c06a1983264a18
4
+ data.tar.gz: b94972e8d2862560cefca6f4343e15c3b362be56038426cda2b3a988b8705329
5
5
  SHA512:
6
- metadata.gz: 04111aad9852f77817a6f01f2b9e96f20ed6ffa24ba70f0a9bd9c12f08060aee26d9deba7fedd437fcedae1b7cb27782df2e82da5c629a090993443a05bb5f47
7
- data.tar.gz: 53117c53d931e58338947378b8c0de7cbb8b92d9b66ee7c918e56bea5a3c7d4dff7e62ebb310f1b1b57013a820f3a81dfc046fa89f39fffbe2553e9ccc042aa0
6
+ metadata.gz: 59d8c55e6c5300996bc0250d106715647180320c0ab044a1e99dde08188cc887f5de4d8d2f175246c06a73e25f90c7dcea537ff58f0ff29a07f01ba278f346e9
7
+ data.tar.gz: 5061f9357362cf45cfbfe5cc96ca937cdb4a1be8f58a6e156946c4ac2ea277ca3b3d5615f18fb66372a4ea33f57b39a71e33d15542ea2ff72ddf4b2bdf169ae3
data/README.md CHANGED
@@ -548,6 +548,24 @@ UserDecorator.decorate user # => nil
548
548
 
549
549
  Read [behave_as_ar](https://github.com/Purple-Magic/tramway#behave_as_ar) section
550
550
 
551
+ #### Actions column on index tables
552
+
553
+ When an entity has `update` or `destroy` pages configured, Tramway automatically
554
+ appends an `Actions` column to the end of the entity's index table headers,
555
+ holding the edit/destroy controls for each row.
556
+
557
+ This label is looked up through `I18n` (`tramway.table.actions_header`), so you
558
+ can rename it to your own language by overriding the key in your app's locale
559
+ file:
560
+
561
+ *config/locales/en.yml*
562
+ ```yaml
563
+ en:
564
+ tramway:
565
+ table:
566
+ actions_header: "Actions"
567
+ ```
568
+
551
569
  ### Tramway Form
552
570
 
553
571
  Tramway provides **convenient** form objects for Rails applications. List properties you want to change and the rules in Form classes. No controllers overloading.
@@ -1073,6 +1091,22 @@ details panel. Pass `preview: false` when you want a row without the preview pan
1073
1091
  <% end %>
1074
1092
  ```
1075
1093
 
1094
+ `tramway_cell` also forwards any HTML options to the underlying cell wrapper. Use this when you need per-cell classes,
1095
+ data attributes, ids, or other attributes:
1096
+
1097
+ ```erb
1098
+ <%= tramway_cell class: 'whitespace-nowrap', data: { turbo: false } do %>
1099
+ <%= user.name %>
1100
+ <% end %>
1101
+ ```
1102
+
1103
+ `tramway_header` forwards HTML options to the header wrapper as well. That makes it easy to add ids, classes, or data
1104
+ attributes to the header row:
1105
+
1106
+ ```erb
1107
+ <%= tramway_header headers: ['Name', 'Email'], class: 'sticky top-0', data: { controller: 'table-header' } %>
1108
+ ```
1109
+
1076
1110
  When you render a header you can either pass the `headers:` array, as in the examples above, or render custom header content in
1077
1111
  the block. `tramway_header` uses the length of the `headers` array to build the grid if the array is present.
1078
1112
  If you omit the array and provide custom content, pass the `columns:` argument so the component knows how many grid columns to
@@ -1196,7 +1230,8 @@ Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are
1196
1230
 
1197
1231
  Tramway provides `tramway_form_for` helper that renders Tailwind-styled forms by default. Form inputs use hardcoded
1198
1232
  dark shadcn-style classes; Tramway does not render a separate light form theme.
1199
- Checkboxes render dark while unchecked and use the light primary checked state.
1233
+ Checkboxes render with the same dark border and focus highlight treatment as other inputs, then use the light primary checked state.
1234
+ Checkbox controls, checkmarks, and vertically centered label line heights scale together with the form-level `size:` option.
1200
1235
 
1201
1236
  ```erb
1202
1237
  <%= tramway_form_for @user do |f| %>
@@ -388,15 +388,40 @@ class UiCheckbox extends Controller {
388
388
 
389
389
  this.buttonTarget.setAttribute("aria-checked", checked.toString())
390
390
  this.buttonTarget.dataset.state = state
391
+ this.syncBoxStyle(checked)
391
392
  this.buttonTarget.classList.toggle("border-zinc-50", checked)
393
+ this.buttonTarget.classList.toggle("border-zinc-800", !checked)
392
394
  this.buttonTarget.classList.toggle("bg-zinc-50", checked)
393
395
  this.buttonTarget.classList.toggle("text-zinc-950", checked)
394
- this.buttonTarget.classList.toggle("border-zinc-800", !checked)
395
396
  this.buttonTarget.classList.toggle("bg-zinc-950", !checked)
396
397
  this.buttonTarget.classList.toggle("text-zinc-50", !checked)
397
398
  this.indicatorTarget.classList.toggle("hidden", !checked)
398
399
  this.buttonTarget.toggleAttribute("disabled", this.inputTarget.disabled)
399
400
  }
401
+
402
+ syncBoxStyle(checked) {
403
+ const size = this.checkboxSize()
404
+
405
+ this.buttonTarget.style.width = size
406
+ this.buttonTarget.style.height = size
407
+ this.buttonTarget.style.minWidth = size
408
+ this.buttonTarget.style.minHeight = size
409
+ this.buttonTarget.style.display = "inline-flex"
410
+ this.buttonTarget.style.alignItems = "center"
411
+ this.buttonTarget.style.justifyContent = "center"
412
+ this.buttonTarget.style.padding = "0"
413
+ this.buttonTarget.style.lineHeight = "1"
414
+ this.buttonTarget.style.boxSizing = "border-box"
415
+ this.buttonTarget.style.backgroundColor = checked ? "#fafafa" : "#09090b"
416
+ this.buttonTarget.style.color = checked ? "#09090b" : "#fafafa"
417
+ }
418
+
419
+ checkboxSize() {
420
+ if (this.buttonTarget.classList.contains("h-4")) return "1rem"
421
+ if (this.buttonTarget.classList.contains("h-6")) return "1.5rem"
422
+
423
+ return "1.25rem"
424
+ }
400
425
  }
401
426
 
402
427
  class Tooltip extends Controller {
@@ -19,7 +19,8 @@ class TailwindComponent < Tramway::BaseComponent
19
19
  file_button: 'text-sm px-3 py-1',
20
20
  submit_button: 'text-sm px-3 py-1',
21
21
  tramway_select_input: 'text-sm px-2 py-1 h-10',
22
- checkbox_input: 'min-h-4 min-w-4'
22
+ checkbox_input: 'h-4 w-4',
23
+ checkbox_indicator: 'h-3 w-3'
23
24
  },
24
25
  medium: {
25
26
  text_input: 'text-base px-3 py-2',
@@ -27,7 +28,8 @@ class TailwindComponent < Tramway::BaseComponent
27
28
  file_button: 'text-base px-4 py-2',
28
29
  submit_button: 'text-base px-4 py-2',
29
30
  tramway_select_input: 'text-base px-2 py-1 h-12',
30
- checkbox_input: 'min-h-5 min-w-5'
31
+ checkbox_input: 'h-5 w-5',
32
+ checkbox_indicator: 'h-4 w-4'
31
33
  },
32
34
  large: {
33
35
  text_input: 'text-xl px-4 py-3',
@@ -35,7 +37,8 @@ class TailwindComponent < Tramway::BaseComponent
35
37
  file_button: 'text-xl px-5 py-3',
36
38
  submit_button: 'text-xl px-5 py-3',
37
39
  tramway_select_input: 'text-xl px-3 py-2 h-15',
38
- checkbox_input: 'min-h-6 min-w-6'
40
+ checkbox_input: 'h-6 w-6',
41
+ checkbox_indicator: 'h-5 w-5'
39
42
  }
40
43
  }.freeze
41
44
 
@@ -69,7 +72,7 @@ class TailwindComponent < Tramway::BaseComponent
69
72
  end
70
73
 
71
74
  def checkbox_base_classes
72
- 'shrink-0 rounded-sm border border-zinc-800 bg-zinc-950 text-zinc-50 shadow-sm ' \
75
+ 'shrink-0 rounded-sm border border-zinc-800 bg-zinc-950 text-zinc-50 shadow-sm transition-colors ' \
73
76
  'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-300 ' \
74
77
  'focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 disabled:cursor-not-allowed ' \
75
78
  'disabled:opacity-50'
@@ -1,4 +1,4 @@
1
- .flex.items-center.space-x-2{ class: default_container_classes, data: { controller: 'ui--checkbox' } }
1
+ .flex.items-center.gap-2{ class: default_container_classes, data: { controller: 'ui--checkbox' } }
2
2
  - checkbox_checked = checked?
3
3
  = @input.call @attribute, **hidden_checkbox_options
4
4
  %button{ type: 'button',
@@ -9,6 +9,7 @@
9
9
  'data-ui--checkbox-target' => 'button',
10
10
  value: 'on',
11
11
  class: checkbox_button_classes,
12
+ style: checkbox_button_style,
12
13
  for: @for,
13
14
  id: @for }
14
15
  %span{ class: checkbox_indicator_classes, style: 'pointer-events: none', data: { 'ui--checkbox-target' => 'indicator' } }
@@ -21,9 +22,8 @@
21
22
  'stroke-width' => '2',
22
23
  'stroke-linecap' => 'round',
23
24
  'stroke-linejoin' => 'round',
24
- class: 'h-4 w-4' }
25
+ class: size_class(:checkbox_indicator) }
25
26
  %polyline{ points: '20 6 9 17 4 12' }
26
27
  - if @label
27
- %div
28
- = component('tramway/form/label', for: @for, options: { class: label_classes, data: { action: 'click->ui--checkbox#toggle' } }) do
29
- = @label
28
+ = component('tramway/form/label', for: @for, options: { class: label_classes, style: label_style, data: { action: 'click->ui--checkbox#toggle' } }) do
29
+ = @label
@@ -4,17 +4,33 @@ module Tramway
4
4
  module Form
5
5
  # Tailwind-styled checkbox field
6
6
  class CheckboxComponent < TailwindComponent
7
+ CHECKBOX_BUTTON_BASE_STYLES = {
8
+ display: 'inline-flex',
9
+ 'align-items': 'center',
10
+ 'justify-content': 'center',
11
+ padding: '0',
12
+ 'line-height': '1',
13
+ 'box-sizing': 'border-box'
14
+ }.freeze
15
+
16
+ CHECKBOX_BUTTON_SIZES = {
17
+ small: '1rem',
18
+ medium: '1.25rem',
19
+ large: '1.5rem'
20
+ }.freeze
21
+
7
22
  def checkbox_button_classes
8
- 'peer h-4 w-4 shrink-0 rounded-sm border border-zinc-800 bg-zinc-950 text-zinc-50 ' \
9
- 'ring-offset-zinc-950 ' \
10
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-300 ' \
11
- 'focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ' \
23
+ "peer #{size_class(:checkbox_input)} #{checkbox_base_classes} " \
12
24
  'data-[state=checked]:border-zinc-50 data-[state=checked]:bg-zinc-50 ' \
13
25
  'data-[state=checked]:text-zinc-950'
14
26
  end
15
27
 
16
28
  def checkbox_indicator_classes
17
- 'flex items-center justify-center text-current hidden'
29
+ "flex hidden #{size_class(:checkbox_indicator)} items-center justify-center text-current"
30
+ end
31
+
32
+ def checkbox_button_style
33
+ checkbox_button_style_attributes.map { |key, value| "#{key}: #{value}" }.join('; ')
18
34
  end
19
35
 
20
36
  def checked?
@@ -36,19 +52,44 @@ module Tramway
36
52
  end
37
53
 
38
54
  def label_classes
39
- default_classes = 'cursor-pointer mb-0 leading-6'
55
+ default_classes = 'cursor-pointer mb-0'
40
56
 
41
57
  case size
42
58
  when :small
43
- default_classes += ' text-sm'
59
+ default_classes += ' text-sm leading-5'
44
60
  when :medium
45
- default_classes += ' text-base'
61
+ default_classes += ' text-base leading-6'
46
62
  when :large
47
- default_classes += ' text-lg'
63
+ default_classes += ' text-lg leading-7'
48
64
  end
49
65
 
50
66
  default_classes
51
67
  end
68
+
69
+ def label_style
70
+ {
71
+ 'align-self': 'center',
72
+ 'line-height': checkbox_button_size,
73
+ 'margin-bottom': '0'
74
+ }.map { |key, value| "#{key}: #{value}" }.join('; ')
75
+ end
76
+
77
+ private
78
+
79
+ def checkbox_button_style_attributes
80
+ CHECKBOX_BUTTON_BASE_STYLES.merge(
81
+ width: checkbox_button_size,
82
+ height: checkbox_button_size,
83
+ 'min-width': checkbox_button_size,
84
+ 'min-height': checkbox_button_size,
85
+ 'background-color': checked? ? '#fafafa' : '#09090b',
86
+ color: checked? ? '#09090b' : '#fafafa'
87
+ )
88
+ end
89
+
90
+ def checkbox_button_size
91
+ CHECKBOX_BUTTON_SIZES.fetch(size, CHECKBOX_BUTTON_SIZES.fetch(:medium))
92
+ end
52
93
  end
53
94
  end
54
95
  end
@@ -1,2 +1,2 @@
1
- %div{ class: cell_classes }
1
+ %div{ class: [options[:class], cell_classes].compact.join(' '), **options.except(:class) }
2
2
  = content
@@ -4,6 +4,8 @@ module Tramway
4
4
  module Table
5
5
  # Component for rendering a cell in a table
6
6
  class CellComponent < Tramway::BaseComponent
7
+ option :options, optional: true, default: -> { {} }
8
+
7
9
  def cell_classes
8
10
  'div-table-cell hidden px-6 py-4 text-base font-medium text-zinc-100 first:block md:block'
9
11
  end
@@ -1,5 +1,5 @@
1
1
  - parsed_cells = headers.any? ? nil : visible_cells_from(content)
2
- %div{ class: "#{header_row_classes} md:grid-cols-#{columns_count(parsed_cells: parsed_cells)}", aria: { label: "Table Header" }, role: "row" }
2
+ %div{ class: [options[:class], "#{header_row_classes} md:grid-cols-#{columns_count(parsed_cells: parsed_cells)}"].compact.join(' '), aria: { label: "Table Header" }, role: "row", **options.except(:class) }
3
3
  - if headers.any?
4
4
  - headers.each do |header|
5
5
  .div-table-cell.border-b.border-zinc-800{ class: header_cell_classes }
@@ -8,6 +8,7 @@ module Tramway
8
8
 
9
9
  option :headers, optional: true, default: -> { [] }
10
10
  option :columns, optional: true, default: -> { 3 }
11
+ option :options, optional: true, default: -> { {} }
11
12
 
12
13
  def columns_count(content = nil, parsed_cells: nil)
13
14
  return headers.size if headers.present?
@@ -5,6 +5,8 @@ en:
5
5
  title: "Create %{model_name}"
6
6
  edit:
7
7
  title: "Edit %{model_name}"
8
+ table:
9
+ actions_header: "Actions"
8
10
  actions:
9
11
  new: "New"
10
12
  edit: "Edit"
@@ -516,8 +516,12 @@ module.exports = {
516
516
  'leading-none',
517
517
  'appearance-none',
518
518
  'peer',
519
+ 'h-3',
520
+ 'w-3',
519
521
  'h-4',
520
522
  'w-4',
523
+ 'h-6',
524
+ 'w-6',
521
525
  'text-current',
522
526
  'ring-offset-zinc-950',
523
527
  'data-[state=checked]:border-zinc-50',
@@ -578,6 +582,7 @@ module.exports = {
578
582
  'text-sm',
579
583
  'font-medium',
580
584
  'leading-6',
585
+ 'leading-7',
581
586
  'text-zinc-50',
582
587
  'text-green-400',
583
588
  'text-blue-400',
@@ -68,7 +68,9 @@ module Tramway
68
68
  (model_class || entity.model_class).human_attribute_name(attribute)
69
69
  end
70
70
 
71
- headers += ['Actions'] if entity&.page(:update).present? || entity&.page(:destroy).present?
71
+ if entity&.page(:update).present? || entity&.page(:destroy).present?
72
+ headers += [I18n.t('tramway.table.actions_header')]
73
+ end
72
74
 
73
75
  headers
74
76
  end
@@ -23,10 +23,11 @@ module Tramway
23
23
  component 'tramway/table', options:, &
24
24
  end
25
25
 
26
- def tramway_header(headers: nil, columns: nil, &)
26
+ def tramway_header(headers: nil, columns: nil, **options, &)
27
27
  component 'tramway/table/header',
28
28
  headers:,
29
29
  columns:,
30
+ options:,
30
31
  &
31
32
  end
32
33
 
@@ -39,8 +40,8 @@ module Tramway
39
40
  &
40
41
  end
41
42
 
42
- def tramway_cell(&)
43
- component 'tramway/table/cell', &
43
+ def tramway_cell(**options, &)
44
+ component 'tramway/table/cell', options:, &
44
45
  end
45
46
 
46
47
  def tramway_button(path: nil, text: nil, method: :get, form_options: {}, **options, &)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tramway
4
- VERSION = '3.1.2.4'
4
+ VERSION = '3.1.2.6'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tramway
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.2.4
4
+ version: 3.1.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - kalashnikovisme
@@ -325,7 +325,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
325
325
  - !ruby/object:Gem::Version
326
326
  version: '0'
327
327
  requirements: []
328
- rubygems_version: 4.0.10
328
+ rubygems_version: 4.0.16
329
329
  specification_version: 4
330
330
  summary: Tramway Rails Engine
331
331
  test_files: []