I use transitions and transformations a lot in CSS. They are really useful tools that can help make a site look and feel really good. However, there is something I can never remember, so I am putting it in writing here for myself, and for anyone else that runs into this problem.


Tricky Tricky

There is a very small difference in the syntax between transitioning multiple properties versus transforming multiple properties on an element. In transitions, you separate the different transitions by a comma, but transformations omit this comma.

.my-class {

    transition: background-color 200ms, color 300ms, opacity 450ms;

    transform: rotateX(30deg) scale(1.1); /* no comma! */

}

I think this is poor design in CSS. It makes sense to separate each transition by a comma, and I would think that it would make the most sense to do the same in the transformations. I hope that if you are having an issue figuring out how to do multiple transitions or transformations that this has helped you out!

Last week, I wrote about my initial views of TailwindCSS.  I had a lot of interest from readers on Twitter to continue the post to cover the components aspect of Tailwind.  The Tailwind docs do contain a page on how to extract components already, so I want to take this time to cover my workflow and thought process on extracting components in an app.  In this article, I will be using the starter Laravel app, along with Laravel mix.  If you are unfamiliar with Laravel, that is okay, we will be mostly covering the HTML/CSS, and using Laravel as a jumping off point.  The source code for this project can be found on github.


Project Setup

To get things started, I used the Laravel installer to scaffold out a blank application:

laravel new tailwind-components

cd tailwind-components

npm install

php artisan make:auth

Next step is to install Tailwind:

npm install tailwindcss --save-dev

Now that we are done scaffolding our app, we have a layout file at resources/views/layouts/app.blade.php, and the main file we will work with today at resources/views/welcome.blade.php.  Let's go into welcome.blade.php and remove everything from the file, and start with a blank canvas.  We will now enter the following code to utilize the main app.blade.php layout file.

@extends('layouts.app')

@section('content')

@endsection

All of our code will exist between the @section('content') and @endsection blade directives.  Let's now visit app.blade.php and set it up.  We will remove the pre-built navigation bar so that we can build our own using Tailwind.  The body section of your file should look like this:

<body>
    <div id="app">
        @yield('content')
    </div>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}"></script>
</body>

The last bit is to setup Tailwind.  Open up webpack.mix.js and change it to look like the following:

let mix = require('laravel-mix');
let tailwindcss = require('tailwindcss');

mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css')
   .options({
       processCssUrls: false,
       postCss: [
           tailwindcss('./tailwind.js')
       ]
   });

Per the Tailwind installation docs, we need to setup the tailwind.js file that we have set on line 9 of our mix file.

./node_modules/.bin/tailwind init tailwind.js

For this example, we are going to leave the generated tailwind.js config file alone, and focus only on our components.  Last step for our project setup is to clear out resources/assets/sass/app.scss and set it to use the Tailwind preflight and utilities:

@tailwind preflight;

// Add component files here.

@tailwind utilities;

Setting up the Navigation Bar

Let's build a basic navigation bar using the Tailwind utilities.  We just need a bar with a title, we can always add links later if we choose.

    <div id="app">

        <nav class="py-4 px-2 mb-4 bg-grey-lightest shadow-md">
            <span class="font-medium">Tailwind Components</span>
        </nav>
        
        @yield('content')
    </div>

Now we must think about if this could make use of turning all of those classes into a component or not.  Since we are using a layout file that all of our pages will inherit, I do not think it is worth it to make a component for the navbar.  This is easy enough to update here in the HTML if we ever want to change the styles.


Application Buttons

We know that our app will need to use buttons.  Let's style one up using the Tailwind utilities, and then create a component for them.  For this example, we will be putting all of our code in the welcome.blade.php file, inside of the @section('content').  I'll first wrap all of these buttons that we will create into a container and center it, just to make it look a little nicer.

<div class="container px-4 mx-auto text-center">
   <button class="px-4 py-2 rounded shadow bg-blue hover:bg-blue-dark text-white">
      Button
   </button>
</div>

This is great!  We were able to use the utility classes to design a button that we want to use within our app.  Since we know we will need many buttons, this is a perfect candidate to turn it into a component.  Let's create a new file for our buttons: resources/assets/sass/buttons.scss, and load it into our app.scss file.

@tailwind preflight;

// Add component files here.
@import 'buttons';

@tailwind utilities;

Now within our newly created buttons.scss file, we will create a class .btn.  Note, that the hover attributes cannot be used as a class name, and must use the CSS :hover selector.

.btn {
    @apply .px-4 .py-2 .rounded .shadow .bg-blue .text-white;

    &:hover {
        @apply .bg-blue-dark;
    }
}

We can now change all of those classes on our button element to use just btn.  The @apply directive that ships with Tailwind allows this magic to happen above.  We are now looking at a very clean file that clearly states what our buttons look like.  However, we now need to have a couple other button types: one that is a light grey, and one that is red.  All of the buttons should look the same other than the colors, so we will want to extract the reusable utilities.  Later on, if we are asked to change the buttons to not have rounded corners, we will only have one class to change.  Here is how it will look:

.btn {
    @apply .px-4 .py-2 .rounded .shadow;
}

.btn-primary {
    @apply .bg-blue .text-white;

    &:hover {
        @apply .bg-blue-dark;
    }
}

.btn-normal {
    @apply .bg-grey-lightest;

    &:hover {
        @apply .bg-grey-lighter;
    }
}

.btn-danger {
    @apply .bg-red-light .text-white;

    &:hover {
        @apply .bg-red;
    }
}

That's it!  We have just a few lines of code that completely define how we want our buttons to look.  Each button will use the btn class, as well as a class to denote what color to use. Here is an example of using these classes:

        <button class="btn btn-primary">
            Button
        </button>

        <button class="btn btn-normal">
            Normal
        </button>

        <button class="btn btn-danger">
            Danger
        </button>


Building Some Forms

Forms are also an important part of any application.  Let's steal an example form from the Tailwind examples.  We are going to use the first login form example.  Our app needs to have a login form, but also a registration form.  It would be nice if they looked the same.  We may need other forms in the future, so having components for each of these inputs would be nice.

<div class="w-full max-w-xs">
  <form class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
    <div class="mb-4">
      <label class="block text-grey-darker text-sm font-bold mb-2" for="username">
        Username
      </label>
      <input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker" id="username" type="text" placeholder="Username">
    </div>
    <div class="mb-4">
      <label class="block text-grey-darker text-sm font-bold mb-2" for="password">
        Password
      </label>
      <input class="shadow appearance-none border border-red rounded w-full py-2 px-3 text-grey-darker mb-3" id="password" type="password" placeholder="******************">
      <p class="text-red text-xs italic">Please choose a password.</p>
    </div>
    <div class="flex items-center justify-between">
      <button class="bg-blue hover:bg-blue-dark text-white font-bold py-2 px-4 rounded" type="button">
        Sign In
      </button>
      <a class="inline-block align-baseline font-bold text-sm text-blue hover:text-blue-darker" href="#">
        Forgot Password?
      </a>
    </div>
  </form>
  <p class="text-center text-grey text-xs">
    ©2017 Acme Corp. All rights reserved.
  </p>
</div>

Whoa! That's a lot of classes! Let's take a look at what we can already change: the button. We want the button to match our primary button, so by just changing the class to be .btn .btn-primary, we will have it match our theme. We also have a link here for 'Forgot Password'. We should have our links all look the same on the site. Let's make a file for HTML elements: resources/assets/sass/elements.scss.

a {
    @apply .inline-block .align-baseline .font-bold .text-sm .text-blue;

    &:hover {
        @apply .text-blue-darker;
    }
}

We can now remove all of the classes from the Forgot Password hyperlink. Be sure to include this new file in app.scss.

@tailwind preflight;

// Add component files here.
@import 'buttons';
@import 'elements';

@tailwind utilities;

We may or may not want all forms to look the same. Let's say we want the login and register forms to exist in this small white card, and others will not have these features. We can refactor the classes on the form tag into a component. We will create a new file: resources/assets/sass/forms.scss, and you guessed it, we will need to import it into app.scss.

form.login-register-form {
    @apply .bg-white .shadow-md .rounded .px-8 pt-6 .pb-8 .mb-4;
}

Labels and inputs should be uniform, so let's create components for those, pulling the utility classes out of the HTML. We also want the same padding between each input, so let's refactor that out as a component as well. Even though it is just a single utility class, this will make it easy to adjust the sizing to all form fields later.

form.login-register-form {
    @apply .bg-white .shadow-md .rounded .px-8 pt-6 .pb-8 .mb-4;

    .input-group {
        @apply .pb-4;
    }

    label {
        @apply .block .text-grey-darker .text-sm .font-bold .mb-2;
    }

    input.form-input {
        @apply .shadow .appearance-none .border .rounded .w-full .py-2 .px-3 .text-grey-darker;
    }
}

One more thing that I noticed when looking at this form is that an input field can be invalid. Let's make these classes so that invalid fields on other forms will have the same look.

form.login-register-form {
    @apply .bg-white .shadow-md .rounded .px-8 pt-6 .pb-8 .mb-4;

    .input-group {
        @apply .pb-4;
    }

    label {
        @apply .block .text-grey-darker .text-sm .font-bold .mb-2;
    }

    input.form-input {
        @apply .shadow .appearance-none .border .rounded .w-full .py-2 .px-3 .text-grey-darker;
    }

    input.invalid {
        @apply .border-red .mb-3;
    }

    p.warning-text {
        @apply .text-red .text-xs .italic;
    }
}

We have cleaned up the form quite a bit. We still have utility classes, but that is fine. They only exist in spots that are specific to this particular form. We don't want to over-think the components!

    <div class="container w-full max-w-xs mx-auto my-8">
        <form class="login-register-form">
            <div class="input-group">
                <label for="username">
                    Username
                </label>
                <input class="form-input" id="username" type="text" placeholder="Username">
            </div>
            <div class="input-group">
                <label for="password">
                    Password
                </label>
                <input class="form-input invalid" id="password" type="password" placeholder="******************">
                <p class="warning-text">Please choose a password.</p>
            </div>
            <div class="flex items-center justify-between">
                <button class="btn btn-primary" type="button">
                    Sign In
                </button>
                <a href="#">
                    Forgot Password?
                </a>
            </div>
        </form>
        <p class="text-center text-grey text-xs">
            ©2017 Acme Corp. All rights reserved.
        </p>
    </div>

We can now easily create a registration form, and have it look similar to the sign in form.

    <div class="w-full max-w-xs mx-auto mt-8">
        <form class="login-register-form">
            <div class="input-group">
                <label for="username">Username</label>
                <input class="form-input" type="text" id="username" placeholder="Username">
            </div>
            <div class="input-group">
                <label for="email">Email</label>
                <input class="form-input" type="email" id="email" placeholder="email@email.com">
            </div>
            <div class="input-group">
                <label for="password">Password</label>
                <input class="form-input" type="password" id="password" placeholder="********">
            </div>
            <div class="input-group mb-6">
                <label for="confirm-password">Confirm Password</label>
                <input class="form-input" type="password" id="confirm-password" placeholder="********">
            </div>
            <div class="input-group text-center">
                <div class="btn btn-primary">Register</div>
            </div>
            <div class="text-center">
                <a href="">
                    Already have an account?
                </a>
            </div>
        </form>
    </div>


Conclusion

In closing, I hope that this article has made it clear how easy it is to create components out of the Tailwind utility classes, and how easy it is to read and modify these components. I personally like to build out these components using the utility classes in the HTML. Only when I start to see patterns of re-usability do I think it is a good idea to refactor the classes out into a single component. Using the @apply directive allows us to have small, concise CSS that is easy to modify.

A few months ago, I remember Adam Wathan tweeting about a CSS framework he was building, titled Tailwind (it came from building his KiteTail app).  I turned thirty this year, and that seems to have made me a grumpy old developer.  I used to see something new and want to be the first one using it, on the bleeding edge of technology.  Five years ago I would have been so excited to see this.  Why was I grumpy?  Utility-first CSS was why!

Utility-first CSS seemed to me like nothing better than writing inline styles.  We, as an industry, moved away from writing inline styles and started using style-sheets for many reasons.  Separations of concerns was one, and also the ability to refactor your code.  I saw some examples of Tailwind online, and was disgusted to see code like this:

<img class="w-24 rounded rounded-full border-4 border-white absolute pin-l pin-b -mb-8 ml-4" src="..." />

Can you imagine if you wanted to have a bunch of images look the same, re-using the same massive group of classes?  Think of what would happen if management or your client came to you and said "Hey, let's make all the images not have that white border".  Now you will have to search through your files and find all of those classes scattered among your HTML (or JavaScript if you are using templates in a framework such as React, Vue, etc).

The Good Parts

Tailwind does allow you to make extremely quick mock-ups and proof of concepts.  I finally gave in to my grumpiness and read through the docs, and started playing with the code on CodePen.  The first thing I did was a recreation of a Twitter profile card, which actually landed on the front-page of Codepen.  You can view the pen and the source code here.

I also started playing with making my own set of alert boxes.  First, I started by recreating a couple of the examples from the Tailwind docs, then made some modifications to design my own.  Again, you can view the code on Codepen.

I'm Not So Grumpy Anymore

The ability to make these components is super simple with Tailwind.  But what about a real application?  I'm not talking about a TODO app or something you just bang out one afternoon; I'm talking a large application.  How do we manage all of these classes, and how do we manage large design changes on a project?  Here is the answer that changed my opinion of Tailwind: it is component-friendly!  This means that you can actually take those globs of classes that you want to use for every image, or button, or notification box, and create a component out of them.  This single feature is what really made me see the light.  You still get the ability to make awesome design components extremely quickly, and you can put those ideas to use into components that you can use throughout your project!

I am too far into KickoffWP.com to be willing to refactor everything to use Tailwind, but I do plan to utilize the framework in my next project.

Next: TailwindCSS Components Workflow Process

Previous: Part 1

Setup Firebase Authentication

Let's get started.  In the last post, we got our project setup locally and started a new Firebase app.  It currently has no data or anything setup.  Let's go ahead and get the authentication ready on Firebase's end so that we can move forward with coding.  Go ahead and log into your Firebase account and open up the new project you setup last time.  You should see an Authentication card.  Click 'Get Started'.

 

You should have an empty table.  Click the large 'Set Up Sign-In Method' button.  You will be prompted with a variety of options.  For this example, we will only be using Email/Password.  I may later come back and add social media logins, but for now, let's keep it simple.

 


Setup Authentication in Angular

Now that we have Firebase setup, let's get busy on our app.

Go ahead and run npm start to get your app running!

 

I like to give it the path to a directory called components.  This just helps me organize my code. Next we will need to install the firebase and angularfire2 modules.  We can use the shortcut 'i' for 'install'.

npm i firebase angularfire2 --save

We now need to import our AngularFire module as well as the authentication providers and methods into our app.  Inside of app.module.ts, add the following import:

import { AngularFireModule, AuthProviders, AuthMethods } from 'angularfire2';

You will also need to setup your configuration:

const myFirebaseAuthConfig = { provider: AuthProviders.Password, method: AuthMethods.Password };

Next, we will want to set the import for the module itself.

Uh-oh, we have the angry red squiggly line under myFirebaseConfig.  If you read the firebase docs, it shows how to setup the config right here in the module code.  I do not like this, especially if you are going to have this as a public repository on GitHub.  Let's make a new class that we won't check into the repo.

ng generate class firebaseConfig

Now, inside the newly created class, add the configuration:

static myFirebaseConfig = {
  apiKey: '<your-key>',
  authDomain: '<your-project-authdomain>',
  databaseURL: '<your-database-URL>',
  storageBucket: '<your-storage-bucket>',
  messagingSenderId: '<your-messaging-sender-id>'
};

Here's a trick to find the data you need.  In the Authentication page on Firebase, click the Web Setup link on the top-right.  You will be given a snippet of javascript that will contain everything you need.  I won't post an image since it contains my personal key.  Now, go ahead and open up your .gitignore, and add firebase-config.ts in here.  This will prevent your configuration code from accidentally being committed to the repository.

Now, go back to app.module.ts and update the import for the AngularFireModule

AngularFireModule.initializeApp(FirebaseConfig.myFirebaseConfig, myFirebaseAuthConfig)


Creating the Authentication Component in Angular

Let's create a new component to keep our authentication separate from anything else.  This will allow us to easily move it or reuse it later.  We will use the Angular CLI for this.  We can use the shortcut 'g' for 'generate'.

ng g component components/authentication

Let's put the new fancy component into our app.  Looking at authentication.component.ts, there is a selector in the @Component decorator.  I'm going to rename mine to just authentication.  Now, over in the main root component, app.component.html, we can add the authentication component.

<h1>{{title}}</h1>

<authentication></authentication>

Your app should now display the authentication component:

Well, that's not exactly what we want...  Let's fix it.  We will worry about styling the component later, right now we want to focus on just getting it to work.

<div class="form form-authentication">
 <div class="form-group">
   <label for="inputEmail">Email: </label>
   <input id="inputEmail" type="email" [(ngModel)]="email" />
 </div>

 <div class="form-group">
   <label for="inputPassword">Password: </label>
   <input id="inputPassword" type="password" [(ngModel)]="password" />
 </div>

 <button (click)="register()">Register</button>
</div>

We now have a basic form, and a button wired up to a function that we need to write, and the two input fields are set with two-way data-binding to fields with the same name.  Let's setup our component class.

export class AuthenticationComponent implements OnInit {

 email: String;
 password: String;

 constructor() { }

 ngOnInit() { }

 register() { }

}

Now we have everything wired up to our component, we can handle everything in typescript.  First, we need to import AngularFire2 into our component.  Add this to the top of the file:

import { AngularFire } from 'angularfire2';

Set the constructor to inject it into the component:

constructor(public angularFire: AngularFire) { }

We can now access it by using this.angularFire anywhere in our component.  Let's wire up the register function:

register() {
 this.angularFire.auth.createUser({
   email: this.email.toString(),
   password: this.password.toString()
 });
}

Now, users can register on the site!  If you look at your firebase authentication page and refresh it, you can now register your email address and password.  After doing so, you will see your email address listed as a user!  We still need to style the component, handle exceptions (such as if the user is already registered), and create a login form.  We will continue that next post!


Handling User Data from Firebase

Let's do one last thing before wrapping up Part 2.  Let's get the current user object and hide the registration form when the user is already logged in.  Add the user object to the authentication.component.ts file:

...
export class AuthenticationComponent implements OnInit {
  email: String;
  password: String;
  user: any;
...
Now, in the ngOnInit function, let's subscribe to the angular fire's auth object, and get the data.  The subscribe we are doing here is basically just waiting until firebase has returned with the auth data, and then we tell it what to do once it is loaded.
this.angularFire.auth.subscribe(auth => this.user = auth);

Great, now we have a property on our component that will hold the user information.  Let's hide the component when the user is logged in.  In your authentication.component.html file:

<div class="form form-authentication" *ngIf="user === null">

We are now saying that we will display everything inside this form when the user is null.  That's it!  I've added my own styling (it's not that pretty) to the github repo, but feel free to style it yourself!

In the next post, we will allow the user to switch between the registration form we have now, and a login form.  We will also add the ability to log out of the app.  After that, it's on to building the address book functionality.

Project Setup

This will be a multi-part post in which we will build an address book app using Angular (well, Angular 2, but they call it 'just Angular' now) and Firebase.  I really like using Firebase as a backend, especially for proof of concepts and demos.  It allows us to focus on the front-end and not have to deal with standing up a RESTful API.  It also comes with cool authentication built in.


The Tools we Need

Firstly, you will need to have nodejs installed.  Node will be used to install NPM packages used in the project.  Next, go ahead and install the super handy Angular CLI (Command Line Interface).  You can do so easily in your command prompt by typing:

npm install -g @angular/cli

If you aren't used to using npm, the -g stands for global, meaning once you run this once on your computer, you won't need to do it for future projects.  Now that we have the Angular CLI installed, we can simply stand up a new project by typing:

ng new angular-address-book --style=scss

Here we are telling the CLI (the ng command) that we want a new project, called angular-address-book.  We are also telling it to build it using SCSS as our CSS pre-processor.  To see our app working, simply type:

npm start

This will run the ng serve command (you can see all of the different scripts registered for this project inside of the package.json file).  Go ahead and go to http://localhost:4200.  You will see your beautiful app running.  Keep this command running in the background as you work on your project.  It will automatically reload the page for you whenever you change a file, and will warn you when you make mistakes.

The last tool that we will be using is VS Code.  This editor is free from Microsoft.  I used to be a hardcore Atom fan, but for Angular2, I prefer VS Code.  It's up to you what editor you use.


Angular Project Overview

Let's go ahead and open our fancy new project in our editor and see what we're working with.  We will be focusing on the files under the src directory.

The project is already setup with our index.html starting point.  If you look inside the file, you will see only one line inside the <body> tags:

<app-root>Loading...</app-root>

This is where we will bootstrap our app into our webpage.  The Loading... text will disappear as soon as it is loaded.  Right now the app is so small, you probably won't even see it when loading it in your browser.

The styles.scss file will be used for our global styles.  This is where we will define global fonts, sizes for common elements such as h1 and p tags, etc.  We really won't do much outside of the app directory.

The App Directory

Ahh, the App directory.  This is where we get to have some fun!  The CLI has already given us a starting component.  We will talk more about components in the future posts.  Go ahead and peek at app.component.ts.

This is where the app gets bootstrapped.  See that selector of 'app-root'?  Yep, that matches what we saw in the index.html file.  The HTML that is rendered can be found in the app.component.html, and any styling we want to apply here will be found in app.component.css.  Easy, right?

Tip!

You may see in the angular.io examples the use of moduleId: module.id inside of the @Component decorator. The Angular CLI's webpack setup already uses relative paths for the other attributes of the @Component decorator, so we do not need it.


Setup Firebase

Firebase is a BaaS (Backend as a Service) that we will use for our real-time database.  If you don't already have an account, go ahead and sign up.  Don't worry, it is free until you start having a lot of users and data using it.  Once in your console, click the Create New Project button, give it a name, and you're done!  In the next lesson, we will work to setup authentication in both Firebase and in our Angular application.

Feel free to follow along with my GitHub repository.  Each part will be separated out so you can check your work and follow along.

Next: Part 2 - Authentication

What is BrowserSync Anyway?

If you found this page from searching Google, you probably are already aware of what it is.  If not, BrowserSync allows the developer to instantly see changes in the browser when developing a site or app.  It is extremely useful and has been a nice productivity booster for my own development work.  Click here to learn more.

The Problem

Part of my workflow when developing sites and apps is to use BrowserSync.  BrowserSync allows me to code away, and update the browser without me having to change my focus and refresh the page.  Stylesheet changes are injected automagically, and changes to javascript or html files refresh right away.

When I first started using BrowserSync with Gulp, I ran into an issue that took me way too long to fix.  I figured I would write this small post in case any of you out there have run into this problem as well.

Here is the Gulp task:

Browsersync in Gulp.js

I spent a long time staring at this code trying to figure out WHY nothing was happening when I changed a file.  The task was running, and there were no errors....

 

Solution #1

The answer was simple!  I forgot to add the browsersync.js file into my html:

Include script in HTML

So, next time you start a new project and your automated syncing is just not working, remember to check and see if you included the javascript file needed for the sync to work.

Solution #2

Still not working?  Browsersync also has a little trick up it's sleeve.  It will inject some other scripts into the page that it needs to do its magic.  The following shows the scripts that are in the html when running in the browser:

Scripts added when running in browser

In order for this to happen, your code needs a <body> tag.  This has happened to me before when first setting up a gulpfile.js for a new project and not actually fleshing out your typical html, head and body.

I hope this has helped someone out there.  Leave a comment below if you've had any other issues related to this that should be added to this post!

Copyright © 2019 Chris Perko

linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram