recourse 4.2.0 → 4.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37d576acaaf1fd87766eb000852a30004862d606e02ea950577f76a3d4f8c8ee
4
- data.tar.gz: af168a49adf4d3df402ee1f6f093cefe3528dbcfb77727ada7b1270539006475
3
+ metadata.gz: 00e1253a6c0a7e462efb88f9c46765d51cbc90b20073cf72fefc38ac468d31b2
4
+ data.tar.gz: 51271fdc26d6a06cf53089e747f70a842b51d71ffa1fe163e4dc08927e1ba005
5
5
  SHA512:
6
- metadata.gz: bf99a21586c91bb03722206dc18f289cc49338c659e6ef0c3ffeac37ede0aba147ac80f1da437df3ab21c0b59951fcb2ecf86e0d6c2b411e8c465a59a17b48c3
7
- data.tar.gz: 966f579457d4917bf4b9f17f2efe65bda9445b0e013d7cff33712fc07e027bfe6606cb0e78c45d2b11c26c42dfdcaf014c78e54ad3e9df8ca71c167b94cfef8c
6
+ metadata.gz: 3526cb175143ce2fae2919654b9f7afb7c1e44e6188462084e56c784f81aaf624cc128b760499991d79bf809fab97b14a50156c15f1e4969fff710309bfee4e2
7
+ data.tar.gz: a4aac6c9576b269c9df0f66fa4f0e60ca4e8da4461500be1a534caa2f25f33ff6c08d88e4e7ec431edc15d3ad4cb6c9af80725245f45d82557586640c79cab46
data/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
5
5
  For more information about changelogs, check [Keep a Changelog](http://keepachangelog.com) and
6
6
  [Vandamme](http://tech-angels.github.io/vandamme).
7
7
 
8
+ ## 4.3.0 - 2026-09-08
9
+
10
+ * [Feature] On a phone a stacked cell reads as one line, `Estimate hi: 600`
11
+ * [Feature] On a phone the sidebar's icons carry their words: `Dark mode`, `Light mode`, `Exit`
12
+ * [Fix] A page never scrolls sideways on a phone, and Safari no longer zooms out of it
13
+
14
+ Safari laid the stacked table's hidden header row out at its full width; the page
15
+ now clips what would run past the window.
16
+
17
+ * [Fix] Safari no longer zooms in on the search box or a filter when it is focused
18
+
19
+ The small controls were 14px, and Safari zooms on any field under 16; on a phone
20
+ they take the body's size.
21
+
22
+ * [Fix] The footer's sentence stands above the pages on a phone rather than beside them
23
+ * [Fix] A filter's menu drops over the first rows of the table rather than under them
24
+ * [Feature] A date or a time is headed `Created` and `Updated`, not `Created at` and `Updated at`
25
+ * [Fix] A touch screen gets no hover tint on a table's rows
26
+
8
27
  ## 4.2.0 - 2026-09-08
9
28
 
10
29
  * [Feature] The log-out button sits beside the light/dark toggle
@@ -101,6 +101,25 @@
101
101
  --bs-breadcrumb-link-hover-color: var(--bs-breadcrumb-link-active-color);
102
102
  }
103
103
 
104
+ /* Nothing here is meant to be wider than the window: the one thing that is, a
105
+ table, scrolls inside its own wrapper. Safari lays a stacked table's hidden
106
+ header row out at its full width all the same, and a page that can be
107
+ scrolled to it is a page Safari zooms out of and draws the navbar short on. */
108
+ html, .recourse-shell { overflow-x: hidden; }
109
+
110
+ /* A finger does not hover. The tint a pointer leaves on the row under it would
111
+ stay on whatever row was last touched, so a touch screen gets none. */
112
+ @media (hover: none) {
113
+ .table-hover > tbody > tr:hover > * {
114
+ --bs-table-color-state: initial;
115
+ --bs-table-bg-state: initial;
116
+ }
117
+ }
118
+
119
+ /* The navbar and the sidebar stack over the main column: a menu opened from a
120
+ filter or a link's tooltip drops over the first rows rather than under them. */
121
+ .recourse-shell > nav, .recourse-sidebar { position: relative; z-index: 2; }
122
+
104
123
  /* An action column is as wide as a row is tall — an icon in a square — and a
105
124
  counter column starts at the same square, widening only when a figure like
106
125
  38,405 needs the room: a table laying out to 100% reads the width as a
@@ -116,6 +135,23 @@
116
135
  }
117
136
  }
118
137
 
138
+ /* Stacked, a cell reads as one line — `Estimate hi: 600`, the heading semibold
139
+ and the value after it — where Bootstrap puts the heading on a line of its own
140
+ and leaves the row's first cell with no heading at all, bold in its place: a
141
+ status opening a row would be a bare badge. Every cell is headed here. And a
142
+ value with no space in it — an address, a token — breaks rather than widening
143
+ the row past the phone. */
144
+ @container (width < 576px) {
145
+ .sm\:table-stacked > tbody > tr > td[data-cell]::before {
146
+ content: attr(data-cell) ': ';
147
+ display: inline;
148
+ font-weight: var(--bs-font-weight-semibold);
149
+ }
150
+ .sm\:table-stacked > tbody > tr > td:first-child { font-weight: inherit; }
151
+ .sm\:table-stacked > tbody > tr > td:not(:first-child) + td::before { margin-block-start: 0; }
152
+ .sm\:table-stacked > tbody > tr > td { overflow-wrap: anywhere; }
153
+ }
154
+
119
155
  /* A counter says what it counts in one of two ways, and the table's own width is
120
156
  what picks: the icon and a bare figure where the column is a square, the
121
157
  counted model's words where there is room to read them. Bootstrap's `xl`, so
@@ -224,6 +260,9 @@
224
260
  .recourse-search { max-width: none; }
225
261
  .recourse-search-box,
226
262
  .recourse-search .combobox-toggle { flex: 1 1 100%; }
263
+ /* Safari zooms in on a field whose text is under 16px, and the small controls
264
+ are 14px: on a phone they take the body's size, and focusing one moves nothing. */
265
+ .recourse-search { --bs-btn-input-sm-font-size: var(--bs-body-font-size); }
227
266
  }
228
267
 
229
268
  /* Held Option marks the letter each sidebar link answers to. Marked rather than
@@ -376,6 +415,17 @@
376
415
  }
377
416
  }
378
417
 
418
+ /* While the sidebar is a row its foot has room for words, so each icon is followed
419
+ by its own; as a column the words are read but not seen, the way Bootstrap's
420
+ `.visually-hidden` does it. */
421
+ .recourse-foot-word { margin-inline-start: .4em; }
422
+ @media (width >= 768px) {
423
+ .recourse-foot-word {
424
+ position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
425
+ overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
426
+ }
427
+ }
428
+
379
429
  /* The toggle draws both icons and shows the one that names where a click
380
430
  would go: a moon on a light page, a sun on a dark one. Three states rather than
381
431
  two, because a page nobody has chosen for carries no attribute at all, and the
@@ -1,6 +1,7 @@
1
1
  <%# locals: (pagy:) %>
2
2
  <% if pagy %>
3
- <div class='d-flex align-items-center' <%= tag.attributes data: limit_data(pagy) %>>
3
+ <%# A column on a phone, the sentence above the pages, and one row from `sm` up. -%>
4
+ <div class='d-flex flex-column sm:flex-row sm:align-items-center' <%= tag.attributes data: limit_data(pagy) %>>
4
5
  <%# The gem's own sentence from pagy's public readers, every figure delimited —
5
6
  rewriting pagy's English with a regex delimited one figure, only in English.
6
7
  The switch follows it after a dot: how much of the table is showing, then the
@@ -17,6 +18,6 @@
17
18
  <%= t 'recourse.displaying', count: pagy.count %>
18
19
  <% end %>
19
20
  </div>
20
- <div class='pe-2'><%== pagy.series_nav(:bootstrap, classes: 'pagination mb-0') if pagy.last > 1 %></div>
21
+ <div class='px-2 mt-2 sm:mt-0'><%== pagy.series_nav(:bootstrap, classes: 'pagination mb-0') if pagy.last > 1 %></div>
21
22
  </div>
22
23
  <% end %>
@@ -24,11 +24,11 @@
24
24
  data: scheme_data do %>
25
25
  <span class='recourse-scheme-light'>
26
26
  <i class='bi bi-moon-fill'></i>
27
- <span class='visually-hidden'><%= t 'recourse.darken' %></span>
27
+ <span class='recourse-foot-word'><%= t 'recourse.darken' %></span>
28
28
  </span>
29
29
  <span class='recourse-scheme-dark'>
30
30
  <i class='bi bi-sun-fill'></i>
31
- <span class='visually-hidden'><%= t 'recourse.lighten' %></span>
31
+ <span class='recourse-foot-word'><%= t 'recourse.lighten' %></span>
32
32
  </span>
33
33
  <% end %>
34
34
  </div>
@@ -38,7 +38,7 @@
38
38
  <%= button_to exit_path, method: :delete, class: 'nav-link border-0 bg-transparent',
39
39
  form: { data: { turbo: false } } do %>
40
40
  <i class='bi bi-box-arrow-right'></i>
41
- <span class='visually-hidden'><%= t 'recourse.exit' %></span>
41
+ <span class='recourse-foot-word'><%= t 'recourse.exit' %></span>
42
42
  <% end %>
43
43
  <% end %>
44
44
  </li>
@@ -21,10 +21,10 @@ en:
21
21
  create: Create
22
22
  created: "%{model} was created."
23
23
  created_error: "%{model} could not be created."
24
- darken: Darken the page
24
+ darken: Dark mode
25
25
  delete: Delete %{model}
26
26
  deleted: "%{model} was deleted."
27
- exit: Log out
27
+ exit: Exit
28
28
  displaying:
29
29
  one: Displaying 1 item
30
30
  other: Displaying %{count} items
@@ -37,7 +37,7 @@ en:
37
37
  items:
38
38
  one: 1 item
39
39
  other: "%{count} items"
40
- lighten: Lighten the page
40
+ lighten: Light mode
41
41
  missing_model: You declared `recourses :%{name}` in your routes file, but this app
42
42
  has no %{model} model.
43
43
  nested: You nested `recourses %{names}` inside `resources :%{parent}`, which does
@@ -59,11 +59,20 @@ module Recourse
59
59
  # column holds a number and the heading says what the number is of.
60
60
  def resource_column_title(column)
61
61
  counted = resource_model.recourse_counters[column]
62
- return resource_model.human_attribute_name column unless counted
62
+ return dated_title column unless counted
63
63
 
64
64
  Recourse.model_title counted.klass
65
65
  end
66
66
 
67
+ # The model's own name for a column, less the `at` or `on` a date's name ends in:
68
+ # `Created`, not `Created at`, since when it happened is what the column holds.
69
+ def dated_title(column)
70
+ title = resource_model.human_attribute_name column
71
+ dated = column.end_with?('_at', '_on') && Columns::DATE_KINDS.include?(attribute_type(column))
72
+
73
+ dated ? title.sub(/ (at|on)\z/, '') : title
74
+ end
75
+
67
76
  # Value for one cell, formatted according to what the column holds.
68
77
  def resource_cell(resource, column)
69
78
  association = belongs_to_association column
@@ -1,4 +1,4 @@
1
1
  module Recourse
2
2
  # Version of the gem, read by the gemspec and by hosts checking compatibility.
3
- VERSION = '4.2.0'
3
+ VERSION = '4.3.0'
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recourse
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0
4
+ version: 4.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - claudiob