implemented floating labels on inputs & selects, with icons

This commit is contained in:
Adam Piontek 2021-03-07 17:17:16 -05:00
parent 74678bd3ad
commit 89d9bc0cce
10 changed files with 199 additions and 202 deletions

View file

@ -17,9 +17,8 @@ import "../node_modules/bootstrap-icons/icons/at.svg"; // email field
import "../node_modules/bootstrap-icons/icons/key.svg"; // new password field import "../node_modules/bootstrap-icons/icons/key.svg"; // new password field
import "../node_modules/bootstrap-icons/icons/key-fill.svg"; // pw confirm field import "../node_modules/bootstrap-icons/icons/key-fill.svg"; // pw confirm field
import "../node_modules/bootstrap-icons/icons/lock.svg"; // current pw field import "../node_modules/bootstrap-icons/icons/lock.svg"; // current pw field
import "../node_modules/bootstrap-icons/icons/shield-shaded.svg"; // role import "../node_modules/bootstrap-icons/icons/shield.svg"; // role
// live tables // live tables
import "../node_modules/bootstrap-icons/icons/filter.svg";
import "../node_modules/bootstrap-icons/icons/backspace.svg"; // clear filter import "../node_modules/bootstrap-icons/icons/backspace.svg"; // clear filter
import "../node_modules/bootstrap-icons/icons/sort-down-alt.svg"; import "../node_modules/bootstrap-icons/icons/sort-down-alt.svg";
import "../node_modules/bootstrap-icons/icons/sort-up-alt.svg"; import "../node_modules/bootstrap-icons/icons/sort-up-alt.svg";

View file

@ -9,42 +9,42 @@
<%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, novalidate: true, id: "reg_form"], fn f -> %> <%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, novalidate: true, id: "reg_form"], fn f -> %>
<div class="mb-3" phx-feedback-for="<%= input_id(f, :email) %>">
<%= label f, :email, class: "form-label" %> <div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :email) %>">
<div class="input-group has-validation"> <%= email_input f, :email,
<span class="input-group-text"> value: input_value(f, :email),
<%= icon_div @socket, "bi-at", [class: "icon"] %> class: input_class(f, :email, "form-control"),
</span> placeholder: "e.g., babka@73k.us",
<%= email_input f, :email, maxlength: User.max_email,
value: input_value(f, :email), autofocus: true,
class: input_class(f, :email, "form-control"), phx_debounce: "blur",
placeholder: "e.g., babka@73k.us", aria_describedby: error_ids(f, :email)
maxlength: User.max_email, %>
autofocus: true, <%= label f, :email do %>
phx_debounce: "blur", <%= icon_div @socket, "bi-at", [class: "icon baseline text-muted"] %>
aria_describedby: error_ids(f, :email) Email
%> <% end %>
<%= error_tag f, :email %> <%= error_tag f, :email %>
</div>
</div> </div>
<div class="mb-3" phx-feedback-for="<%= input_id(f, :password) %>">
<%= label f, :password, class: "form-label" %> <div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :password) %>">
<div class="input-group has-validation"> <%= password_input f, :password,
<span class="input-group-text"> value: input_value(f, :password),
<%= icon_div @socket, "bi-key", [class: "icon"] %> class: input_class(f, :password, "form-control"),
</span> placeholder: "Password",
<%= password_input f, :password, maxlength: User.max_password,
value: input_value(f, :password), phx_debounce: "250",
class: input_class(f, :password, "form-control"), aria_describedby: error_ids(f, :password)
maxlength: User.max_password, %>
phx_debounce: "250", <%= label f, :password do %>
aria_describedby: error_ids(f, :password) <%= icon_div @socket, "bi-key", [class: "icon baseline text-muted"] %>
%> Password
<%= error_tag f, :password %> <% end %>
</div> <%= error_tag f, :password %>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<%= submit (@trigger_submit && "Saving..." || "Register"), <%= submit (@trigger_submit && "Saving..." || "Register"),
class: "btn btn-primary", class: "btn btn-primary",

View file

@ -9,39 +9,39 @@
<%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, novalidate: true, id: "pw_reset_form"], fn f -> %> <%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, novalidate: true, id: "pw_reset_form"], fn f -> %>
<div class="mb-3" phx-feedback-for="<%= input_id(f, :password) %>"> <div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :password) %>">
<%= label f, :password, "New password", class: "form-label" %> <%= password_input f, :password,
<div class="input-group has-validation"> value: input_value(f, :password),
<span class="input-group-text"> class: input_class(f, :password, "form-control"),
<%= icon_div @socket, "bi-key", [class: "icon"] %> placeholder: "New Password",
</span> maxlength: User.max_password,
<%= password_input f, :password, autofocus: true,
value: input_value(f, :password), aria_describedby: error_ids(f, :password)
class: input_class(f, :password, "form-control"), %>
maxlength: User.max_password, <%= label f, :password do %>
autofocus: true, <%= icon_div @socket, "bi-key", [class: "icon baseline text-muted"] %>
aria_describedby: error_ids(f, :password) New password
%> <% end %>
<%= error_tag f, :password %> <%= error_tag f, :password %>
</div>
</div> </div>
<div class="mb-3" phx-feedback-for="<%= input_id(f, :password_confirmation) %>">
<%= label f, :password_confirmation, "Confirm new password", class: "form-label" %> <div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :password_confirmation) %>">
<div class="input-group has-validation"> <%= password_input f, :password_confirmation,
<span class="input-group-text"> value: input_value(f, :password_confirmation),
<%= icon_div @socket, "bi-key-fill", [class: "icon"] %> class: input_class(f, :password_confirmation, "form-control"),
</span> placeholder: "Confirm new password",
<%= password_input f, :password_confirmation, maxlength: User.max_password,
value: input_value(f, :password_confirmation), aria_describedby: error_ids(f, :password_confirmation)
class: input_class(f, :password_confirmation, "form-control"), %>
maxlength: User.max_password, <%= label f, :password do %>
aria_describedby: error_ids(f, :password_confirmation) <%= icon_div @socket, "bi-key-fill", [class: "icon baseline text-muted"] %>
%> Confirm new password
<%= error_tag f, :password_confirmation %> <% end %>
</div> <%= error_tag f, :password_confirmation %>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<%= submit "Reset password", <%= submit "Reset password",
class: "btn btn-primary", class: "btn btn-primary",

View file

@ -4,40 +4,39 @@
<%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, phx_target: @myself], fn f -> %> <%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, phx_target: @myself], fn f -> %>
<div class="mb-3" phx-feedback-for="<%= input_id(f, :email) %>">
<%= label f, :email, class: "form-label" %> <div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :email) %>">
<div class="input-group has-validation"> <%= email_input f, :email,
<span class="input-group-text"> value: input_value(f, :email),
<%= icon_div @socket, "bi-at", [class: "icon"] %> class: input_class(f, :email, "form-control"),
</span> placeholder: "e.g., babka@73k.us",
<%= email_input f, :email, maxlength: User.max_email,
value: input_value(f, :email), phx_debounce: "500",
class: input_class(f, :email, "form-control"), aria_describedby: error_ids(f, :email)
placeholder: "e.g., babka@73k.us", %>
maxlength: User.max_email, <%= label f, :email do %>
phx_debounce: "500", <%= icon_div @socket, "bi-at", [class: "icon baseline text-muted"] %>
aria_describedby: error_ids(f, :email) Email
%> <% end %>
<%= error_tag f, :email %> <%= error_tag f, :email %>
</div>
</div> </div>
<div class="mb-3" phx-feedback-for="<%= input_id(f, :current_password) %>"> <div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :current_password) %>">
<%= label f, :current_password, class: "form-label" %> <%= password_input f, :current_password,
<div class="input-group"> value: input_value(f, :current_password),
<span class="input-group-text"> class: "form-control",
<%= icon_div @socket, "bi-lock", [class: "icon"] %> placeholder: "Current Password",
</span> aria_describedby: error_ids(f, :current_password)
<%= password_input f, :current_password, %>
value: input_value(f, :current_password), <%= label f, :current_password do %>
class: "form-control", <%= icon_div @socket, "bi-lock", [class: "icon baseline text-muted"] %>
aria_describedby: error_ids(f, :current_password) Current password
%> <% end %>
<%= error_tag f, :current_password %> <%= error_tag f, :current_password %>
</div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<%= submit "Change email", <%= submit "Change email",
class: "btn btn-primary", class: "btn btn-primary",

View file

@ -4,52 +4,52 @@
<%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, phx_target: @myself], fn f -> %> <%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, phx_target: @myself], fn f -> %>
<div class="mb-3" phx-feedback-for="<%= input_id(f, :password) %>">
<%= label f, :password, "New password", class: "form-label" %> <div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :password) %>">
<div class="input-group has-validation"> <%= password_input f, :password,
<span class="input-group-text"> value: input_value(f, :password),
<%= icon_div @socket, "bi-key", [class: "icon"] %> class: input_class(f, :password, "form-control"),
</span> placeholder: "New Password",
<%= password_input f, :password, maxlength: User.max_password,
value: input_value(f, :password), phx_debounce: "500",
class: input_class(f, :password, "form-control"), aria_describedby: error_ids(f, :password)
maxlength: User.max_password, %>
phx_debounce: "500", <%= label f, :password do %>
aria_describedby: error_ids(f, :password) <%= icon_div @socket, "bi-key", [class: "icon baseline text-muted"] %>
%> New password
<%= error_tag f, :password %> <% end %>
</div> <%= error_tag f, :password %>
</div> </div>
<div class="mb-3" phx-feedback-for="<%= input_id(f, :password_confirmation) %>">
<%= label f, :password_confirmation, "Confirm new password", class: "form-label" %> <div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :password_confirmation) %>">
<div class="input-group has-validation"> <%= password_input f, :password_confirmation,
<span class="input-group-text"> value: input_value(f, :password_confirmation),
<%= icon_div @socket, "bi-key-fill", [class: "icon"] %> class: input_class(f, :password_confirmation, "form-control"),
</span> placeholder: "Confirm new password",
<%= password_input f, :password_confirmation, maxlength: User.max_password,
value: input_value(f, :password_confirmation), aria_describedby: error_ids(f, :password_confirmation)
class: input_class(f, :password_confirmation, "form-control"), %>
maxlength: User.max_password, <%= label f, :password_confirmation do %>
aria_describedby: error_ids(f, :password_confirmation) <%= icon_div @socket, "bi-key-fill", [class: "icon baseline text-muted"] %>
%> Confirm new password
<%= error_tag f, :password_confirmation %> <% end %>
</div> <%= error_tag f, :password_confirmation %>
</div> </div>
<div class="mb-3" phx-feedback-for="<%= input_id(f, :current_password) %>">
<%= label f, :current_password, class: "form-label" %> <div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :current_password) %>">
<div class="input-group"> <%= password_input f, :current_password,
<span class="input-group-text"> value: input_value(f, :current_password),
<%= icon_div @socket, "bi-lock", [class: "icon"] %> class: "form-control",
</span> placeholder: "Current Password",
<%= password_input f, :current_password, aria_describedby: error_ids(f, :current_password)
value: input_value(f, :current_password), %>
class: "form-control", <%= label f, :current_password do %>
aria_describedby: error_ids(f, :current_password) <%= icon_div @socket, "bi-lock", [class: "icon baseline text-muted"] %>
%> Current password
<%= error_tag f, :current_password %> <% end %>
</div> <%= error_tag f, :current_password %>
</div> </div>
<div class="mb-3"> <div class="mb-3">

View file

@ -6,32 +6,49 @@
<div class="modal-body"> <div class="modal-body">
<div class="mb-3" phx-feedback-for="<%= input_id(f, :email)%>"> <div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :email) %>">
<%= label f, :email, class: "form-label" %> <%= email_input f, :email,
<div class="input-group has-validation"> value: input_value(f, :email),
<span class="input-group-text"> class: input_class(f, :email, "form-control"),
<%= icon_div @socket, "bi-at", [class: "icon"] %> placeholder: "e.g., babka@73k.us",
</span> maxlength: User.max_email,
<%= email_input f, :email, autofocus: true,
value: input_value(f, :email), phx_debounce: "250",
class: input_class(f, :email, "form-control"), aria_describedby: error_ids(f, :email)
placeholder: "e.g., babka@73k.us", %>
maxlength: User.max_email, <%= label f, :email do %>
autofocus: true, <%= icon_div @socket, "bi-at", [class: "icon baseline text-muted"] %>
phx_debounce: "250", Email
aria_describedby: error_ids(f, :email) <% end %>
%> <%= error_tag f, :email %>
<%= error_tag f, :email %>
</div>
</div> </div>
<div class="form-floating mb-3" phx-feedback-for="<%= input_id(f, :password) %>">
<%= password_input f, :password,
value: input_value(f, :password),
class: input_class(f, :password, "form-control"),
placeholder: "Password",
maxlength: User.max_password,
aria_describedby: error_ids(f, :password)
%>
<%= label f, :password do %>
<%= icon_div @socket, "bi-key", [class: "icon baseline text-muted"] %>
Password
<% end %>
<%= error_tag f, :password %>
</div>
<%= if Roles.can?(@current_user, %User{}, :edit_role) do %> <%= if Roles.can?(@current_user, %User{}, :edit_role) do %>
<%= label f, :role, class: "form-label" %> <div class="form-floating">
<div class="input-group mb-3">
<span class="input-group-text">
<%= icon_div @socket, "bi-shield-shaded", [class: "icon"] %>
</span>
<%= select f, :role, Enum.map(User.roles(), fn {k, _v} -> {String.capitalize(Atom.to_string(k)), k} end), class: "form-select" %> <%= select f, :role, Enum.map(User.roles(), fn {k, _v} -> {String.capitalize(Atom.to_string(k)), k} end), class: "form-select" %>
<%= label f, :role do %>
<%= icon_div @socket, "bi-shield", [class: "icon baseline text-muted"] %>
User role
<% end %>
<span class="valid-feedback text-primary" style="display: block;"> <span class="valid-feedback text-primary" style="display: block;">
<%= role_description(input_value(f, :role)) %> <%= role_description(input_value(f, :role)) %>
</span> </span>
@ -40,21 +57,6 @@
<%= hidden_input f, :role, value: input_value(f, :role) %> <%= hidden_input f, :role, value: input_value(f, :role) %>
<% end %> <% end %>
<div phx-feedback-for="<%= input_id(f, :password) %>">
<%= label f, :password, class: "form-label" %>
<div class="input-group has-validation">
<span class="input-group-text">
<%= icon_div @socket, "bi-key", [class: "icon"] %>
</span>
<%= password_input f, :password,
value: input_value(f, :password),
class: input_class(f, :password, "form-control"),
maxlength: User.max_password,
aria_describedby: error_ids(f, :password)
%>
<%= error_tag f, :password %>
</div>
</div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">

View file

@ -33,18 +33,12 @@
<%= form_for :filter, "#", [phx_change: "filter-change"], fn flt -> %> <%= form_for :filter, "#", [phx_change: "filter-change"], fn flt -> %>
<div class="input-group"> <div class="input-group">
<span class="input-group-text">
<%= icon_div @socket, "bi-filter", [class: "icon"] %>
</span>
<%= text_input flt, :filter, name: "filter", class: "form-control", placeholder: "Filter users...", value: @query.filter %> <%= text_input flt, :filter, name: "filter", class: "form-control", placeholder: "Filter users...", value: @query.filter %>
</button>
<%= if @query.filter == "" do %> <%= if @query.filter == "" do %>
<button class="btn btn-outline-secondary" type="button" aria-label="Clear filter" aria-disabled="true" disabled> <button class="btn btn-outline-primary" type="button" aria-label="Clear filter" aria-disabled="true" disabled>
<% else %> <% else %>
<button class="btn btn-outline-secondary" type="button" aria-label="Clear filter" phx-click="filter-clear"> <button class="btn btn-primary" type="button" aria-label="Clear filter" phx-click="filter-clear">
<% end %> <% end %>
<%= icon_div @socket, "bi-backspace", [class: "icon baseline"], [role: "img", aria_hidden: false] %> <%= icon_div @socket, "bi-backspace", [class: "icon baseline"], [role: "img", aria_hidden: false] %>
</button> </button>

View file

@ -9,11 +9,7 @@
<%= form_for :user, Routes.user_confirmation_path(@conn, :create), [class: "needs-validation", novalidate: true], fn f -> %> <%= form_for :user, Routes.user_confirmation_path(@conn, :create), [class: "needs-validation", novalidate: true], fn f -> %>
<%= label f, :email, class: "form-label" %> <div class="form-floating mb-3">
<div class="input-group has-validation mb-3">
<span class="input-group-text">
<%= icon_div @conn, "bi-at", [class: "icon fs-5"] %>
</span>
<%= email_input f, :email, <%= email_input f, :email,
value: @current_user && @current_user.email || "", value: @current_user && @current_user.email || "",
placeholder: "e.g., babka@73k.us", placeholder: "e.g., babka@73k.us",
@ -22,6 +18,10 @@
required: true, required: true,
autofocus: !@current_user autofocus: !@current_user
%> %>
<%= label f, :email do %>
<%= icon_div @conn, "bi-at", [class: "icon baseline text-muted"] %>
Email
<% end %>
<span class="invalid-feedback">must be a valid email address</span> <span class="invalid-feedback">must be a valid email address</span>
</div> </div>

View file

@ -9,18 +9,17 @@
<%= form_for :user, Routes.user_reset_password_path(@conn, :create), [class: "needs-validation", novalidate: true], fn f -> %> <%= form_for :user, Routes.user_reset_password_path(@conn, :create), [class: "needs-validation", novalidate: true], fn f -> %>
<%= label f, :email, class: "form-label" %> <div class="form-floating mb-3">
<div class="input-group has-validation mb-3">
<span class="input-group-text">
<%= icon_div @conn, "bi-at", [class: "icon"] %>
</span>
<%= email_input f, :email, <%= email_input f, :email,
placeholder: "e.g., babka@73k.us",
class: "form-control", class: "form-control",
placeholder: "e.g., babka@73k.us",
maxlength: User.max_email, maxlength: User.max_email,
required: true, required: true
autofocus: true
%> %>
<%= label f, :email do %>
<%= icon_div @conn, "bi-at", [class: "icon baseline text-muted"] %>
Email
<% end %>
<span class="invalid-feedback">must be a valid email address</span> <span class="invalid-feedback">must be a valid email address</span>
</div> </div>

View file

@ -15,32 +15,36 @@
</div> </div>
<% end %> <% end %>
<%= label f, :email, class: "form-label" %>
<div class="input-group has-validation mb-3"> <div class="form-floating mb-3">
<span class="input-group-text">
<%= icon_div @conn, "bi-at", [class: "icon"] %>
</span>
<%= email_input f, :email, <%= email_input f, :email,
class: "form-control", class: "form-control",
placeholder: "e.g., babka@73k.us", placeholder: "e.g., babka@73k.us",
maxlength: User.max_email, maxlength: User.max_email,
required: true required: true
%> %>
<%= label f, :email do %>
<%= icon_div @conn, "bi-at", [class: "icon baseline text-muted"] %>
Email
<% end %>
<span class="invalid-feedback">must be a valid email address</span> <span class="invalid-feedback">must be a valid email address</span>
</div> </div>
<%= label f, :password, class: "form-label" %>
<div class="input-group has-validation mb-3"> <div class="form-floating mb-3">
<span class="input-group-text">
<%= icon_div @conn, "bi-lock", [class: "icon"] %>
</span>
<%= password_input f, :password, <%= password_input f, :password,
class: "form-control", class: "form-control",
placeholder: "Password",
required: true required: true
%> %>
<%= label f, :password do %>
<%= icon_div @conn, "bi-lock", [class: "icon baseline text-muted"] %>
Password
<% end %>
<span class="invalid-feedback">password is required</span> <span class="invalid-feedback">password is required</span>
</div> </div>
<div class="form-check mb-3 no-valid-style"> <div class="form-check mb-3 no-valid-style">
<%= checkbox f, :remember_me, class: "form-check-input" %> <%= checkbox f, :remember_me, class: "form-check-input" %>
<%= label f, :remember_me, "Keep me logged in for 60 days", class: "form-check-label" %> <%= label f, :remember_me, "Keep me logged in for 60 days", class: "form-check-label" %>