summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-08-15 16:28:21 +0200
committererdgeist <erdgeist@erdgeist.org>2026-08-15 16:28:21 +0200
commit445362ed2f8591d54a3c34cb3c5a69049aefa8c6 (patch)
tree064f2d2e936639fa6ca412ed662203b144172c3d
parentaa984c8c0cad4ac4bff74fc38f60c0e06af6fc50 (diff)
Style totp input fields so that they work better on mobile
-rw-r--r--app/views/elevations/new.html.erb3
-rw-r--r--app/views/otp_challenges/new.html.erb9
-rw-r--r--app/views/otp_enrollments/show.html.erb5
-rw-r--r--app/views/users/edit.html.erb5
-rw-r--r--config/locales/de.yml1
-rw-r--r--config/locales/en.yml1
-rw-r--r--public/javascripts/admin_interface.js9
-rw-r--r--public/stylesheets/admin.css18
8 files changed, 43 insertions, 8 deletions
diff --git a/app/views/elevations/new.html.erb b/app/views/elevations/new.html.erb
index 8dd64e78..8e1b59c2 100644
--- a/app/views/elevations/new.html.erb
+++ b/app/views/elevations/new.html.erb
@@ -10,7 +10,8 @@
10 <div class="layout_row_label"><%= t(".code") %></div> 10 <div class="layout_row_label"><%= t(".code") %></div>
11 <div class="layout_row_content"> 11 <div class="layout_row_content">
12 <%= text_field_tag :code, nil, :autocomplete => "one-time-code", 12 <%= text_field_tag :code, nil, :autocomplete => "one-time-code",
13 :inputmode => "numeric", :autofocus => true %> 13 :inputmode => "numeric", :autofocus => true, :maxlength => 6,
14 :pattern => "[0-9]{6}", :class => "otp_code" %>
14 </div> 15 </div>
15 </div> 16 </div>
16 17
diff --git a/app/views/otp_challenges/new.html.erb b/app/views/otp_challenges/new.html.erb
index 8247b262..ff7df222 100644
--- a/app/views/otp_challenges/new.html.erb
+++ b/app/views/otp_challenges/new.html.erb
@@ -6,10 +6,13 @@
6 <div class="layout_row_content"> 6 <div class="layout_row_content">
7 <%= form_tag otp_challenge_path, :method => :post, :class => "otp_form" do %> 7 <%= form_tag otp_challenge_path, :method => :post, :class => "otp_form" do %>
8 <%= text_field_tag :code, nil, :autofocus => true, 8 <%= text_field_tag :code, nil, :autofocus => true,
9 :autocomplete => "one-time-code", :inputmode => "numeric" %> 9 :autocomplete => "one-time-code", :inputmode => "numeric",
10 <%= submit_tag t(".log_in") %> 10 :maxlength => 6, :pattern => "[0-9]{6}", :class => "otp_code" %>
11 <span class="field_hint"> <%= t(".hint") %> </span>
12 <%= button_tag :type => "submit", :class => "action_button" do %>
13 <%= icon("shield-check", library: "tabler", "aria-hidden": true) %> <%= t(".log_in") %>
14 <% end %>
11 <% end %> 15 <% end %>
12 <span class="field_hint"> <%= t(".hint") %> </span>
13 </div> 16 </div>
14 </div> 17 </div>
15</div> 18</div>
diff --git a/app/views/otp_enrollments/show.html.erb b/app/views/otp_enrollments/show.html.erb
index 16addb5b..a7604dd2 100644
--- a/app/views/otp_enrollments/show.html.erb
+++ b/app/views/otp_enrollments/show.html.erb
@@ -18,12 +18,13 @@
18 <div class="layout_row_content"> 18 <div class="layout_row_content">
19 <%= form_tag otp_enrollment_path, :method => :put, :class => "otp_form" do %> 19 <%= form_tag otp_enrollment_path, :method => :put, :class => "otp_form" do %>
20 <%= text_field_tag :code, nil, :autofocus => true, 20 <%= text_field_tag :code, nil, :autofocus => true,
21 :autocomplete => "one-time-code", :inputmode => "numeric" %> 21 :autocomplete => "one-time-code", :inputmode => "numeric",
22 :maxlength => 6, :pattern => "[0-9]{6}", :class => "otp_code" %>
23 <span class="field_hint"> <%= t(".app_hint", :issuer => OTP_ISSUER) %></span>
22 <%= button_tag :type => "submit", :class => "action_button" do %> 24 <%= button_tag :type => "submit", :class => "action_button" do %>
23 <%= icon("shield-check", library: "tabler", "aria-hidden": true) %> <%= t(".confirm") %> 25 <%= icon("shield-check", library: "tabler", "aria-hidden": true) %> <%= t(".confirm") %>
24 <% end %> 26 <% end %>
25 <% end %> 27 <% end %>
26 <span class="field_hint"> <%= t(".app_hint", :issuer => OTP_ISSUER) %></span>
27 </div> 28 </div>
28 </div> 29 </div>
29</div> 30</div>
diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb
index 2cf5a07c..14e19e39 100644
--- a/app/views/users/edit.html.erb
+++ b/app/views/users/edit.html.erb
@@ -59,8 +59,9 @@
59 <p><%= t(".enabled") %></p> 59 <p><%= t(".enabled") %></p>
60 <%= form_tag otp_enrollment_path, :method => :delete, :class => "otp_form" do %> 60 <%= form_tag otp_enrollment_path, :method => :delete, :class => "otp_form" do %>
61 <%= password_field_tag :current_password, nil, :placeholder => t(".current_password"), :autocomplete => "current-password" %> 61 <%= password_field_tag :current_password, nil, :placeholder => t(".current_password"), :autocomplete => "current-password" %>
62 <%= text_field_tag :code, nil, :placeholder => t(".current_code"), 62 <%= text_field_tag :code, nil, :autocomplete => "one-time-code", :inputmode => "numeric",
63 :autocomplete => "one-time-code", :inputmode => "numeric" %> 63 :maxlength => 6, :pattern => "[0-9]{6}", :class => "otp_code" %>
64 <span class="field_hint"> <%= t(".reset_hint") %> </span>
64 <%= button_tag :type => "submit", :class => "action_button" do %> 65 <%= button_tag :type => "submit", :class => "action_button" do %>
65 <%= icon("shield-off", library: "tabler", "aria-hidden": true) %> <%= t(".disable_second_factor") %> 66 <%= icon("shield-off", library: "tabler", "aria-hidden": true) %> <%= t(".disable_second_factor") %>
66 <% end %> 67 <% end %>
diff --git a/config/locales/de.yml b/config/locales/de.yml
index c6082bcd..ed263f6e 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -303,6 +303,7 @@ de:
303 enable_second_factor: "Zweiten Faktor aktivieren" 303 enable_second_factor: "Zweiten Faktor aktivieren"
304 disable_second_factor: "Zweiten Faktor entfernen" 304 disable_second_factor: "Zweiten Faktor entfernen"
305 reset_second_factor: "Zweiten Faktor zurücksetzen" 305 reset_second_factor: "Zweiten Faktor zurücksetzen"
306 reset_hint: "Gib den sechsstelligen Code aus deiner Authenticator-App ein."
306 reset_confirm: "Zweiten Faktor von %{login} zurücksetzen? Die Anmeldung ist danach nur mit Passwort möglich." 307 reset_confirm: "Zweiten Faktor von %{login} zurücksetzen? Die Anmeldung ist danach nur mit Passwort möglich."
307 labels: 308 labels:
308 login: "Anmeldename" 309 login: "Anmeldename"
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 5aafb612..78414dc5 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -255,6 +255,7 @@ en:
255 enable_second_factor: "Enable second factor" 255 enable_second_factor: "Enable second factor"
256 disable_second_factor: "Disable second factor" 256 disable_second_factor: "Disable second factor"
257 reset_second_factor: "Reset second factor" 257 reset_second_factor: "Reset second factor"
258 reset_hint: "Enter the six-digit code from your authenticator app."
258 reset_confirm: "Reset %{login}'s second factor? They will log in with password only afterwards." 259 reset_confirm: "Reset %{login}'s second factor? They will log in with password only afterwards."
259 labels: 260 labels:
260 login: "login" 261 login: "login"
diff --git a/public/javascripts/admin_interface.js b/public/javascripts/admin_interface.js
index b7cb1964..8fe105a7 100644
--- a/public/javascripts/admin_interface.js
+++ b/public/javascripts/admin_interface.js
@@ -90,6 +90,15 @@ $(document).ready(function () {
90 initialize_revision_diff_picker.initialize(); 90 initialize_revision_diff_picker.initialize();
91 } 91 }
92 92
93 if (document.querySelector('.otp_code')) {
94 document.querySelectorAll('.otp_code').forEach(function (field) {
95 field.addEventListener('input', function () {
96 var digits = field.value.replace(/\D/g, '').slice(0, 6);
97 if (field.value !== digits) { field.value = digits; }
98 });
99 });
100 }
101
93 var metadata_details = document.getElementById('metadata_details'); 102 var metadata_details = document.getElementById('metadata_details');
94 if (metadata_details) { 103 if (metadata_details) {
95 var desktop_mq = window.matchMedia('(min-width: 1016px)'); 104 var desktop_mq = window.matchMedia('(min-width: 1016px)');
diff --git a/public/stylesheets/admin.css b/public/stylesheets/admin.css
index 9d96acd0..0dc1a048 100644
--- a/public/stylesheets/admin.css
+++ b/public/stylesheets/admin.css
@@ -2245,6 +2245,24 @@ form.otp_form input[type=text] {
2245 margin-bottom: 0.5rem; 2245 margin-bottom: 0.5rem;
2246} 2246}
2247 2247
2248input[type=text].otp_code {
2249 font-family: monospace;
2250 font-weight: 800;
2251 font-variant-numeric: tabular-nums;
2252 font-size: 2rem;
2253 letter-spacing: 0.75em;
2254 text-align: left;
2255
2256 padding: 0.75rem 0 0.75rem 1.75rem;
2257 box-sizing: border-box;
2258 max-width: 18.5rem;
2259 background-color: var(--surface);
2260 background-image: repeating-linear-gradient(to right, var(--surface) 0 1ch, var(--surface-tint) 1ch calc(1ch + 0.75em));
2261 background-repeat: no-repeat;
2262 background-position: 0.45rem;
2263 background-size: calc(6ch + 4.5em) calc(100% - 1.25rem);
2264}
2265
2248.otp_qr svg { 2266.otp_qr svg {
2249 width: 220px; 2267 width: 220px;
2250 height: auto; 2268 height: auto;