lato 3.26.0 → 3.26.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.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/app/assets/stylesheets/lato/application.scss +17 -0
- data/app/helpers/lato/components_helper.rb +10 -1
- data/app/views/lato/account/_form-web3.html.erb +2 -2
- data/app/views/lato/account/_form-webauthn.html.erb +3 -3
- data/app/views/lato/account/_security-confirmation.html.erb +7 -4
- data/app/views/lato/account/index.html.erb +1 -1
- data/app/views/lato/components/_form_item_input_signature.html.erb +1 -1
- data/app/views/lato/components/_index.html.erb +2 -2
- data/app/views/lato/components/_operation.html.erb +2 -2
- data/config/locales/en.yml +1 -0
- data/config/locales/fr.yml +1 -0
- data/config/locales/it.yml +1 -0
- data/config/locales/ro.yml +1 -0
- data/lib/lato/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 59109ceb11a3fb4c78126d99664864266b1d25ac77ff36ef8f6cf3bc5a66ab18
|
|
4
|
+
data.tar.gz: 7ca6befa9186b81529841c3b25409396beb26b154f99c605557c0b1106e32594
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 33934d542029ce620a7ff4e06c03a2eab2bc7fff362d07237641329724cdac95541b6ea98fb0ad171d84a007705593896a796d2e7648387c4269b22c6812665c
|
|
7
|
+
data.tar.gz: 5797d50477282510f006e201009aa8c0e7b21dd6c7cadf5e80c0dfbbda8eabbadf88669a06f7425d1d95953ac8ffa2a8ae809dd1333959849805491d3cec6bf8
|
data/README.md
CHANGED
|
@@ -8,6 +8,7 @@ This gem includes:
|
|
|
8
8
|
- User management with **full authentication system** (signin, signup, recover password, email validation, Google Authenticator and WebAuthn/passkey multi-factor authentication, ETH wallet connection) and **account management** (user settings, password change, email change, etc.);
|
|
9
9
|
- **Web interface** built with [Bootstrap](https://getbootstrap.com/) and [Bootstrap Icons](https://icons.getbootstrap.com/);
|
|
10
10
|
- **UI components integrated with Rails** (data tables, forms, modals, async job executions etc.);
|
|
11
|
+
- **Accessibility built in**: labelled form fields with linked error messages, keyboard friendly modals with focus return, skip link, `aria-sort` on tables, live regions for feedback and WCAG 2.2 target sizes. Core pages report zero axe-core violations on WCAG 2.2 AA rules;
|
|
11
12
|
|
|
12
13
|
The gem is **agnostic to the application stack**. You can use it with different databases (PostgreSQL, MySQL, SQLite), different Job processors (Solid queue, Sidekiq, Delayed Job, etc.), different cache systems (Redis, Memcached, etc.).
|
|
13
14
|
|
|
@@ -38,6 +38,20 @@ $tooltip-max-width: 300px;
|
|
|
38
38
|
margin: 0 4px;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// WCAG 2.2 target size (2.5.8): interactive targets of at least 24x24px.
|
|
42
|
+
.pagination > span > a {
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
min-width: 24px;
|
|
47
|
+
min-height: 24px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Bootstrap's pink code color fails contrast on tinted alert backgrounds.
|
|
51
|
+
.alert code {
|
|
52
|
+
color: inherit;
|
|
53
|
+
}
|
|
54
|
+
|
|
41
55
|
.pagination .current {
|
|
42
56
|
font-weight: bold;
|
|
43
57
|
}
|
|
@@ -143,6 +157,9 @@ main, aside {
|
|
|
143
157
|
.btn {
|
|
144
158
|
font-size: 12px;
|
|
145
159
|
padding: 0.15rem 0.3rem;
|
|
160
|
+
// 25px: btn-group overlaps adjacent buttons by 1px, the visible target must stay >= 24px (WCAG 2.5.8)
|
|
161
|
+
min-width: 25px;
|
|
162
|
+
min-height: 24px;
|
|
146
163
|
}
|
|
147
164
|
}
|
|
148
165
|
|
|
@@ -284,11 +284,20 @@ module Lato
|
|
|
284
284
|
form.submit label, options
|
|
285
285
|
end
|
|
286
286
|
|
|
287
|
+
# Kaminari labels every paginator "pager": several index tables on one page would expose
|
|
288
|
+
# identical navigation landmarks, so each one gets a label from its index key (unique per page).
|
|
289
|
+
def lato_index_paginate(collection, key, **options)
|
|
290
|
+
name = key.to_s == 'default' ? collection.model.model_name.human(count: 2) : key.to_s.humanize
|
|
291
|
+
label = I18n.t('lato.pagination_label', name: name)
|
|
292
|
+
paginate(collection, param_name: "#{key}_page", **options)
|
|
293
|
+
.to_str.sub('aria-label="pager"', "aria-label=\"#{ERB::Util.html_escape(label)}\"").html_safe
|
|
294
|
+
end
|
|
295
|
+
|
|
287
296
|
# Data
|
|
288
297
|
##
|
|
289
298
|
|
|
290
299
|
def lato_data_badge(label, color = 'primary')
|
|
291
|
-
content_tag :span, label, class: "badge rounded-pill bg-#{color}"
|
|
300
|
+
content_tag :span, label, class: "badge rounded-pill text-bg-#{color}"
|
|
292
301
|
end
|
|
293
302
|
|
|
294
303
|
def lato_data_user(label, image_url = nil)
|
|
@@ -30,7 +30,7 @@ user ||= Lato::User.new
|
|
|
30
30
|
</div>
|
|
31
31
|
<% elsif session[:web3_nonce] %>
|
|
32
32
|
<div class="alert alert-light mb-0">
|
|
33
|
-
<
|
|
33
|
+
<h3 class="alert-heading h4" role="status"><%= I18n.t('lato.connecting') %></h3>
|
|
34
34
|
<div class="progress" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
|
|
35
35
|
<div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 100%"></div>
|
|
36
36
|
</div>
|
|
@@ -73,7 +73,7 @@ user ||= Lato::User.new
|
|
|
73
73
|
</script>
|
|
74
74
|
<% else %>
|
|
75
75
|
<div class="alert alert-light mb-0">
|
|
76
|
-
<
|
|
76
|
+
<h3 class="alert-heading h4"><%= I18n.t('lato.account_web3_start_title') %></h3>
|
|
77
77
|
<p>
|
|
78
78
|
<%= raw I18n.t('lato.account_web3_start_description') %>
|
|
79
79
|
</p>
|
|
@@ -20,7 +20,7 @@ end
|
|
|
20
20
|
|
|
21
21
|
<% if user.webauthn_enabled? %>
|
|
22
22
|
<div class="alert alert-success mb-3">
|
|
23
|
-
<
|
|
23
|
+
<h3 class="alert-heading h4"><%= I18n.t('lato.account_webauthn_ready_title') %></h3>
|
|
24
24
|
<p class="mb-0">
|
|
25
25
|
<%= raw I18n.t('lato.account_webauthn_ready_description') %>
|
|
26
26
|
</p>
|
|
@@ -36,7 +36,7 @@ end
|
|
|
36
36
|
<%= form.hidden_field :webauthn_credential, data: { lato_account_webauthn_target: 'credentialInput' } %>
|
|
37
37
|
|
|
38
38
|
<div class="alert alert-light mb-3" data-lato-account-webauthn-target="status">
|
|
39
|
-
<
|
|
39
|
+
<h3 class="alert-heading h4"><%= I18n.t('lato.account_webauthn_in_progress_title') %></h3>
|
|
40
40
|
<p class="mb-0">
|
|
41
41
|
<%= raw I18n.t('lato.account_webauthn_in_progress_description') %>
|
|
42
42
|
</p>
|
|
@@ -53,7 +53,7 @@ end
|
|
|
53
53
|
</div>
|
|
54
54
|
<% else %>
|
|
55
55
|
<div class="alert alert-light mb-0">
|
|
56
|
-
<
|
|
56
|
+
<h3 class="alert-heading h4"><%= I18n.t('lato.account_webauthn_start_title') %></h3>
|
|
57
57
|
<p>
|
|
58
58
|
<%= raw I18n.t('lato.account_webauthn_start_description') %>
|
|
59
59
|
</p>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
<%# Rendered in several account forms on the same page: suffix ids so each label targets its own field. %>
|
|
2
|
+
<% password_id = form.field_id(:current_password, form.object_id) %>
|
|
3
|
+
<% code_id = form.field_id(:current_authenticator_code, form.object_id) %>
|
|
1
4
|
<div class="mb-3" data-controller="lato-account-security" data-lato-account-security-challenge-url-value="<%= lato.account_security_challenge_path %>" data-lato-account-security-webauthn-value="<%= user.webauthn_enabled? && !user.authenticator_enabled? %>">
|
|
2
|
-
<%= form.label :current_password, I18n.t('lato.current_password'), class: "form-label" %>
|
|
3
|
-
<%= form.password_field :current_password, class: "form-control", autocomplete: "current-password" %>
|
|
5
|
+
<%= form.label :current_password, I18n.t('lato.current_password'), class: "form-label", for: password_id %>
|
|
6
|
+
<%= form.password_field :current_password, id: password_id, class: "form-control", autocomplete: "current-password" %>
|
|
4
7
|
<% if user.authenticator_enabled? %>
|
|
5
|
-
<%= form.label :current_authenticator_code, I18n.t('lato.current_authenticator_code'), class: "form-label mt-2" %>
|
|
6
|
-
<%= form.text_field :current_authenticator_code, value: nil, class: "form-control", autocomplete: "one-time-code", inputmode: "numeric" %>
|
|
8
|
+
<%= form.label :current_authenticator_code, I18n.t('lato.current_authenticator_code'), class: "form-label mt-2", for: code_id %>
|
|
9
|
+
<%= form.text_field :current_authenticator_code, id: code_id, value: nil, class: "form-control", autocomplete: "one-time-code", inputmode: "numeric" %>
|
|
7
10
|
<% elsif user.webauthn_enabled? %>
|
|
8
11
|
<%= form.hidden_field :current_webauthn_credential, value: nil, data: { lato_account_security_target: "credential" } %>
|
|
9
12
|
<p class="text-muted mt-2"><%= I18n.t('lato.security_key_confirmation_help') %></p>
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
</div>
|
|
61
61
|
<div class="card-body">
|
|
62
62
|
<div class="alert alert-warning">
|
|
63
|
-
<
|
|
63
|
+
<h3 class="alert-heading h4"><%= I18n.t('lato.warning') %></h3>
|
|
64
64
|
<p>
|
|
65
65
|
<%= raw I18n.t('lato.account_delete_details') %>
|
|
66
66
|
</p>
|
|
@@ -102,7 +102,7 @@ default_tab = existing_url ? 'current' : 'draw'
|
|
|
102
102
|
<%# Clear button (solo nelle tab di editing) %>
|
|
103
103
|
<div class="d-flex justify-content-end mt-2" data-lato-input-signature-target="clearRow">
|
|
104
104
|
<button type="button"
|
|
105
|
-
class="btn btn-outline-
|
|
105
|
+
class="btn btn-outline-primary btn-sm"
|
|
106
106
|
style="font-size: 0.75rem;"
|
|
107
107
|
data-action="click->lato-input-signature#clearSignature">
|
|
108
108
|
<i class="bi bi-eraser"></i> <%= I18n.t('lato.signature_clear') %>
|
|
@@ -99,7 +99,7 @@ total_pages = collection.empty? ? params["#{key}_page"]&.to_i : 999_999_999 if s
|
|
|
99
99
|
<span class="text-muted"><%= collection_total %> <%= I18n.t('lato.total_results').downcase %></span>
|
|
100
100
|
<% end %>
|
|
101
101
|
<% if collection.respond_to?(:total_pages) %>
|
|
102
|
-
<div class="mt-3"><%=
|
|
102
|
+
<div class="mt-3"><%= lato_index_paginate(collection, key, total_pages: total_pages, window: 1) %></div>
|
|
103
103
|
<% end %>
|
|
104
104
|
</div>
|
|
105
105
|
|
|
@@ -161,7 +161,7 @@ total_pages = collection.empty? ? params["#{key}_page"]&.to_i : 999_999_999 if s
|
|
|
161
161
|
<td colspan="<%= columns.length %>">
|
|
162
162
|
<div class="d-flex justify-content-between align-items-center">
|
|
163
163
|
<% if collection.respond_to?(:total_pages) %>
|
|
164
|
-
<div><%=
|
|
164
|
+
<div><%= lato_index_paginate(collection, key, total_pages: total_pages) %></div>
|
|
165
165
|
<% else %>
|
|
166
166
|
<div></div>
|
|
167
167
|
<% end %>
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
<% if operation.completed_status? %>
|
|
31
31
|
<div class="text-center">
|
|
32
|
-
<div class="fs-1 text-success">
|
|
32
|
+
<div class="fs-1 text-success-emphasis">
|
|
33
33
|
<i class="bi bi-check-circle"></i>
|
|
34
34
|
</div>
|
|
35
35
|
<h2><%= I18n.t('lato.operation_completed_title') %></h2>
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
<% end %>
|
|
41
41
|
|
|
42
42
|
<% if operation.output_message? %>
|
|
43
|
-
<p class="text-success fw-bold">
|
|
43
|
+
<p class="text-success-emphasis fw-bold">
|
|
44
44
|
<%= operation.output_message %>
|
|
45
45
|
</p>
|
|
46
46
|
<% end %>
|
data/config/locales/en.yml
CHANGED
|
@@ -5,6 +5,7 @@ en:
|
|
|
5
5
|
alert_title: "Error"
|
|
6
6
|
sort_ascending: "Sort by %{column} ascending"
|
|
7
7
|
sort_descending: "Sort by %{column} descending"
|
|
8
|
+
pagination_label: "Pagination: %{name}"
|
|
8
9
|
password_requirements: "At least %{count} characters."
|
|
9
10
|
too_many_requests: "Too many requests, please wait %{minutes} minutes to retry."
|
|
10
11
|
hcaptcha_missing: "Please complete the captcha verification."
|
data/config/locales/fr.yml
CHANGED
|
@@ -7,6 +7,7 @@ fr:
|
|
|
7
7
|
alert_title: "Erreur"
|
|
8
8
|
sort_ascending: "Trier par %{column} croissant"
|
|
9
9
|
sort_descending: "Trier par %{column} d\u00E9croissant"
|
|
10
|
+
pagination_label: "Pagination : %{name}"
|
|
10
11
|
password_requirements: "Au moins %{count} caract\u00E8res."
|
|
11
12
|
too_many_requests: "Trop de requ\u00EAtes, veuillez attendre %{minutes} minutes avant de r\u00E9essayer."
|
|
12
13
|
hcaptcha_missing: "Veuillez compl\u00E9ter la v\u00E9rification captcha."
|
data/config/locales/it.yml
CHANGED
|
@@ -7,6 +7,7 @@ it:
|
|
|
7
7
|
alert_title: "Errore"
|
|
8
8
|
sort_ascending: "Ordina per %{column} crescente"
|
|
9
9
|
sort_descending: "Ordina per %{column} decrescente"
|
|
10
|
+
pagination_label: "Paginazione: %{name}"
|
|
10
11
|
password_requirements: "Almeno %{count} caratteri."
|
|
11
12
|
too_many_requests: "Troppe richieste, attendi %{minutes} minuti prima di riprovare."
|
|
12
13
|
hcaptcha_missing: "Completa la verifica captcha."
|
data/config/locales/ro.yml
CHANGED
|
@@ -7,6 +7,7 @@ ro:
|
|
|
7
7
|
alert_title: "Eroare"
|
|
8
8
|
sort_ascending: "Sorteaz\u0103 dup\u0103 %{column} cresc\u0103tor"
|
|
9
9
|
sort_descending: "Sorteaz\u0103 dup\u0103 %{column} descresc\u0103tor"
|
|
10
|
+
pagination_label: "Paginare: %{name}"
|
|
10
11
|
password_requirements: "Cel pu\u021Bin %{count} caractere."
|
|
11
12
|
too_many_requests: "Prea multe cereri, a\u0219tepta\u021Bi %{minutes} minute \u00EEnainte de a re\u00EEncerca."
|
|
12
13
|
hcaptcha_missing: "Completa\u021Bi verificarea captcha."
|
data/lib/lato/version.rb
CHANGED