Advertisement

#4 Authenticator Inputs

In this article we will create and style the controls that we need for our authenticator component. In order to simplify the process we will learn how to create mixins in our pug files and define functions in our scss files. We will also see how Asp.Net will help us with the failure to load resources from a CDN by simplifying fallback to resources stored on our servers.

What are we making?

As we mentioned in the previous article the first step in creating our application is to allow people to login and register. To do this we are creating an angular component for the user interface. In (a) we see what the login screen will look like and in (b) we see what the register screen will look like.

(a) The login screen for our angular authenticator component.
(b) The register screen for our angular authenticator component.
You can view a completed example of the authenticator component here.

Probably shouldn't have deleted that lib folder wayback when

  • WebUi
    • wwwroot
      • css
        • font-awesome-4.7.0
          • css
          • fonts
    • Pages
      • _Layout.cshtml

During the setup of our project in the very first video one of the things that we deleted was the lib folder that was located in the wwwroot folder. While it is true that we did not need any of the contents I forgot that we would be using an icon set called Font Awesome. The primary way that we will be including the icons is through a cdn and not from our own servers but asp.net core provides us an easy way to test if a resource has been loaded from one source and if that fails to attempt to load it from another.

To be able to serve the backup copy from our server we need to visit Font Awesome and download the zip file. Once that is done we need to copy the result of extracting the contents to the 'wwwroot/css' folder (You can't make me add the lib folder back). If you would like you can of course add the lib folder back and place the font awesome folder into it. If you do just make sure that you update the fallback href in the link tag. You can leave the entire contents of the font awesome folder but there is no reason to leave the less and scss folders so we can freely delete them. Once that is done we can return to our _Layout.cshtml file and add the link tag shown in (c) to the head of the page. As I have already said this link will add code that will attempt to download the assets from the primary href and test if that succeeded. If it failed it will attempt to download it from the fallback href. In (d) we see the script that is used to determine if font awesome was loaded successfully from the primary location. It is not important that we analyze the script we just have to be aware that the fallback works by placing this script in the head tag of our browser.

_Layout.cshtml

<head>
    ...
    <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css"
        asp-fallback-href="~/css/font-awesome-4.7.0/css/font-awesome.min.css"
        asp-fallback-test-class="fa-lg"
        asp-fallback-test-property="vertical-align"
        asp-fallback-test-value="-15%" />
    ...
</head>
(c) Adding the font awesome icons to our application.

Font Awesome Fallback

<script>
    !function(a, b, c, d) {
        var e, f = document,
            g = f.getElementsByTagName("SCRIPT"),
            h = g[g.length - 1].previousElementSibling,
            i = f.defaultView && f.defaultView.getComputedStyle
                ? f.defaultView.getComputedStyle(h)
                : h.currentStyle;
        if (i && i[a] !== b) for (e = 0; e < c.length; e++) f.write("<link href='" + c[e] + "' " + d + " />")
    }("vertical-align", "-15%", ["\/css\/font-awesome-4.7.0\/css\/font-awesome.min.css"], "rel=\u0022stylesheet\u0022 type=\u0022text\/css\u0022 ");
</script>
(d) Code used to test whether font awesome has been loaded successfully.

I hate rounded corners

  • WebUi
    • Source
      • sass
        • 2-base
          • _variables.scss

I'm not completely sure why but I do not like rounded corners (e) on my ui elements. If you are with me on this we need to modify the _variables.scss file in our 2-base folder by setting the $base-border-radius: 0;. If on the other hand you like rounded corners you can make this change by a case by case basis but you will need to handle the design of the inputs and buttons which are next to each other shown in (a) and (b). The simple solution shown in the left side of (e) being to use input {border-top-right-radius: 0; border-bottom-right-radius: 0;} and button {border-top-left-radius: 0; border-bottom-left-radius: 0;}.

Image of inputs and buttons with and without rounded corners.
(e) [Left] Showing the outside corners of the input and button being rounded. [Right] Showing the result of setting the corner radius to zero for both inputs and buttons.

The journey of a thousand miles begins with one step

  • WebUi
    • Source
      • components
        • authenticator
          • authenticator.component.pug
          • authenticator.component.scss

I will not be giving a 'play by play' for each bit of the authenticator.component.pug and authenticator.component.scss files as we modify but I will point out overall design decisions and anything else that I feel should be talked about specifically. We begin by creating an over all container for our component and dividing it in half vertically. I have decided that I would like the component to take up 1/3 of a 1080px width display which means that the max width will be 640px. I also want the height of the component to be the same for logging in as well as registering so once we have completed the design we will see the which has the largest height and set the height of the container to it.

As we modify the pug and scss files their corresponding code in our code blocks will behave differently. The pug blocks will contain the code for the whole file whereas the scss files will contain code that is to be added to any previous code. The parenthesis in the names indicate which sets should be used to create the image that follows them, if any.

authenticator.component.pug (1)

div.authenticator
    div.inputs-container
        h3 Login
        form(novalidate)
            div.form-control-group
                label Username
                div.input-group.invalid
                    input
                    button
                        i.fa.fa-times

            div.input-buttons
                button Reset
                button(disabled="true") Send

    div.info-container
(f) The beginning template used to divided the component in half vertically with one form group on the inputs side (left).

authenticator.component.scss (1)

@import "../../sass/_bourbon-neat.scss";

@import "../../sass/2-base/_media-queries.scss";

$base-font-size: 16px;

$info-container-background-color: #484848;
$info-container-color: #dedede;

@function em($pixel) {
    @return #{strip-unit($pixel)/strip-unit($base-font-size)}em;
}

.authenticator {
    font-size: $base-font-size;
    background-color: white;
    margin: 0 auto;

    @include media-gt-or-eq(640px) {
        display: flex;
        flex-direction: row;
        width: em(640px);

        .inputs-container, .info-container {
            width: em(320px);
        }
    }

    a {
        text-decoration: underline;
        text-decoration-style: ink;
        color: #2593cc;
    }

    .inputs-container {
        padding: em(10px);
    }

    .form-control-group {
        label {
            font-weight: 600;
        }
    }

    .input-group {
        display: flex;
        flex-direction: row;
        margin-bottom: em(12px);
        
        input {
            margin-bottom: 0;
            min-width: 0;
        }

        button {
            padding: em(12px) em(16px);
            color: white;
            line-height: 1;
        }
    }

    .info-container {
        display: flex;
        flex-direction: column;
        color: $info-container-color;
        background-color: $info-container-background-color;
    }

    .info-pages {
        flex: 1;
    }

    .need-to-login, .need-to-register {
        text-align: right;
        padding: em(10px);

        a {
            color: $info-container-color;
        }
    }
}
(g) The beginning styles for our component.
The beginning of the ui for our authenticator component.
(h) The beginning of the ui for our authenticator component.
Advertisement

Our first pug mixin

  • WebUi
    • Source
      • components
        • authenticator
          • authenticator.component.pug

As shown in (a) and (b) we will need several groups of elements consisting of a label, an input and a button that I will call a form control group. One of the main reasons that we are bothering to use a language like pug instead of html is to address these types of issues. We could of course just copy and paste things all over the place and then be sure that we make changes to all of them but we are going to be smarter than that and use a mixin. As shown at the top of (i) we define a mixin by simply using the word mixin followed by a name and a pair of parenthesis that contain a comma separated list of parameters. We call the mixin by prepending its name with a '+' and of course passing in the required parameters. In (i) we are converting the six lines that make up our username form control group to +formControlGroup("Username").

authenticator.component.pug (2)

mixin formControlGroup(label)
    div.form-control-group
        label #{label}
        div.input-group.invalid
            input
            button
                i.fa.fa-times

div.authenticator
    div.inputs-container
        h3 Login
        form(novalidate)
            +formControlGroup("Username")            

            div.input-buttons
                button Reset
                button(disabled="true") Send
    div.info-container
(i) Simplifying the creation of a form control group by using a mixin.

The rest of the controls

  • WebUi
    • Source
      • components
        • authenticator
          • authenticator.component.pug
          • authenticator.component.scss

Of course only having the username control isn't going to do us much good. We need to add several more controls to make the component useful. In (j) we have add five new controls: password, confirm password, email, confirm email and remember me. We have also added additional styling which will color the inputs and buttons depending on a conditional class (for demonstation we have added the invalid class for now), place pairs of controls next to each other, and created an acceptable looking remember me checkbox among several other changes.

authenticator.component.pug (3)

mixin formControlGroup(label)
    div.form-control-group
        label #{label}
        div.input-group.invalid
            input
            button
                i.fa.fa-times

div.authenticator
    div.inputs-container
        h3 Login
        form(novalidate)
            +formControlGroup("Username")

            div.forgot
                a Forgot your username?

            div.dual-input-group
                +formControlGroup("Password")
                +formControlGroup("Confirm Password")
            
            div.forgot
                a Forgot your password?

            div.dual-input-group
                +formControlGroup("Email")
                +formControlGroup("Confirm Email")

            div.form-control-group.control-group-remember-me
                input#remember-me(type="checkbox")
                label(for="remember-me")
                    span #[i.fa]
                    | Remember me?

            div.input-buttons
                button Reset
                button(disabled="true") Send

    div.info-container
(j) We can't log in or register with just a username control so we have added all the other controls that we need.

authenticator.component.scss (3)

$indeterminate-color: #BDC3C7 !default;
$invalid-color: #D91E18 !default;
$valid-color: #26A65B !default;

@mixin inputGroup($color) {
    input, button {
        border-color: $color;

        &:focus {
            outline: none !important;
            box-shadow: 0 0 em(10px) $color;
        }
    }

    button {
        background-color: $color;
        opacity: 1;
    }
}

.authenticator {
    .input-group {
        &.indeterminate {
            @include inputGroup($indeterminate-color);
        }

        &.invalid {
            @include inputGroup($invalid-color);
        }

        &.valid {
            @include inputGroup($valid-color);
        }

        input, button {
            border-bottom: em(2px) solid;
            transition: all 1s;
            margin-bottom: 0;
        }
    }

    .dual-input-group {
        display: flex;
        flex-direction: row;

        .form-control-group {
            flex: 1;
        }
    }

    .forgot {
        text-align: right;
    }

    .control-group-remember-me {
        input[type="checkbox"] {
            display: none;

            + label {
                margin: em(10px) 0;

                &:focus {
                    outline: none !important;
                    box-shadow: 0 0 em(10px) #BDC3C7;
                }
            }
        }

        input[type="checkbox"] + label span {
            display: inline-block;
            width: em(19px);
            height: em(19px);
            margin: em(-1px) em(4px) 0 0;
            vertical-align: middle;
            background-color: white;
            cursor: pointer;
            position: relative;
            border: em(1px) solid $info-container-color;

            i {
                position: absolute;
                left: em(1px);
                top: 0;
            }
        }

        input[type="checkbox"]:checked + label span {
            i:before {
                font-family: FontAwesome;
                content: "\f00c";
            }
        }
    }
}
(k) Lets add some color and pair up our controls.
Ui with the addition of five more controls and a little color.
(l) We've added five new controls and a little color to our ui.

In this article we have defined the general layout of our component and added the controls along with their styles to their pug and scss files. In the next article we will add and style the 'info' or right hand side of our user interface.

Exciton Interactive LLC
Advertisement