From 445362ed2f8591d54a3c34cb3c5a69049aefa8c6 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Sat, 15 Aug 2026 16:28:21 +0200 Subject: Style totp input fields so that they work better on mobile --- app/views/elevations/new.html.erb | 3 ++- app/views/otp_challenges/new.html.erb | 9 ++++++--- app/views/otp_enrollments/show.html.erb | 5 +++-- app/views/users/edit.html.erb | 5 +++-- config/locales/de.yml | 1 + config/locales/en.yml | 1 + public/javascripts/admin_interface.js | 9 +++++++++ public/stylesheets/admin.css | 18 ++++++++++++++++++ 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 @@
<%= t(".code") %>
<%= text_field_tag :code, nil, :autocomplete => "one-time-code", - :inputmode => "numeric", :autofocus => true %> + :inputmode => "numeric", :autofocus => true, :maxlength => 6, + :pattern => "[0-9]{6}", :class => "otp_code" %>
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 @@
<%= form_tag otp_challenge_path, :method => :post, :class => "otp_form" do %> <%= text_field_tag :code, nil, :autofocus => true, - :autocomplete => "one-time-code", :inputmode => "numeric" %> - <%= submit_tag t(".log_in") %> + :autocomplete => "one-time-code", :inputmode => "numeric", + :maxlength => 6, :pattern => "[0-9]{6}", :class => "otp_code" %> + <%= t(".hint") %> + <%= button_tag :type => "submit", :class => "action_button" do %> + <%= icon("shield-check", library: "tabler", "aria-hidden": true) %> <%= t(".log_in") %> + <% end %> <% end %> - <%= t(".hint") %>
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 @@
<%= form_tag otp_enrollment_path, :method => :put, :class => "otp_form" do %> <%= text_field_tag :code, nil, :autofocus => true, - :autocomplete => "one-time-code", :inputmode => "numeric" %> + :autocomplete => "one-time-code", :inputmode => "numeric", + :maxlength => 6, :pattern => "[0-9]{6}", :class => "otp_code" %> + <%= t(".app_hint", :issuer => OTP_ISSUER) %> <%= button_tag :type => "submit", :class => "action_button" do %> <%= icon("shield-check", library: "tabler", "aria-hidden": true) %> <%= t(".confirm") %> <% end %> <% end %> - <%= t(".app_hint", :issuer => OTP_ISSUER) %>
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 @@

<%= t(".enabled") %>

<%= form_tag otp_enrollment_path, :method => :delete, :class => "otp_form" do %> <%= password_field_tag :current_password, nil, :placeholder => t(".current_password"), :autocomplete => "current-password" %> - <%= text_field_tag :code, nil, :placeholder => t(".current_code"), - :autocomplete => "one-time-code", :inputmode => "numeric" %> + <%= text_field_tag :code, nil, :autocomplete => "one-time-code", :inputmode => "numeric", + :maxlength => 6, :pattern => "[0-9]{6}", :class => "otp_code" %> + <%= t(".reset_hint") %> <%= button_tag :type => "submit", :class => "action_button" do %> <%= icon("shield-off", library: "tabler", "aria-hidden": true) %> <%= t(".disable_second_factor") %> <% 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: enable_second_factor: "Zweiten Faktor aktivieren" disable_second_factor: "Zweiten Faktor entfernen" reset_second_factor: "Zweiten Faktor zurücksetzen" + reset_hint: "Gib den sechsstelligen Code aus deiner Authenticator-App ein." reset_confirm: "Zweiten Faktor von %{login} zurücksetzen? Die Anmeldung ist danach nur mit Passwort möglich." labels: 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: enable_second_factor: "Enable second factor" disable_second_factor: "Disable second factor" reset_second_factor: "Reset second factor" + reset_hint: "Enter the six-digit code from your authenticator app." reset_confirm: "Reset %{login}'s second factor? They will log in with password only afterwards." labels: 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 () { initialize_revision_diff_picker.initialize(); } + if (document.querySelector('.otp_code')) { + document.querySelectorAll('.otp_code').forEach(function (field) { + field.addEventListener('input', function () { + var digits = field.value.replace(/\D/g, '').slice(0, 6); + if (field.value !== digits) { field.value = digits; } + }); + }); + } + var metadata_details = document.getElementById('metadata_details'); if (metadata_details) { 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] { margin-bottom: 0.5rem; } +input[type=text].otp_code { + font-family: monospace; + font-weight: 800; + font-variant-numeric: tabular-nums; + font-size: 2rem; + letter-spacing: 0.75em; + text-align: left; + + padding: 0.75rem 0 0.75rem 1.75rem; + box-sizing: border-box; + max-width: 18.5rem; + background-color: var(--surface); + background-image: repeating-linear-gradient(to right, var(--surface) 0 1ch, var(--surface-tint) 1ch calc(1ch + 0.75em)); + background-repeat: no-repeat; + background-position: 0.45rem; + background-size: calc(6ch + 4.5em) calc(100% - 1.25rem); +} + .otp_qr svg { width: 220px; height: auto; -- cgit v1.3