Modern WebApps - Style: Vuetify

In (Modern WebApps - Framework: Vue, Parcel & Workbox) we build a template for single-page, progressive web applications using vue.js and Workbox the result was funtional, but not nice-looking… In this article we will work on that.

There are many options for making a webapp good-looking, from hand-writting your css, using a css framework, or since we already use Vue.js, using a vue components library, which has the added benefit of adding functionality. There are various vue component libraries, one of the most promising is Vuetify.js which implements google’s material design and, thus, looks almost native in android phones.

Resources

The code for this tutorial can be found in project’s github repo in the vuetify branch

Integrating vuetify

Integrating vuetify is actually very simple.

  1. Install vuetify and material design icons by running the following commands:
\>npm i -s vuetify
\>npm i -s material-design-icons-iconfont
  1. Import the scripts and add them to Vue by adding the following in src\web\index.js (just after import Vue from 'vue')
    import Vuetify from 'vuetify'; import 'vuetify/dist/vuetify.min.css' // Ensure you are using css-loader import 'material-design-icons-iconfont' Vue.use(Vuetify);

Using vuetify

There is a lot of documentation and examples in Vuetify.js site but let’s build a very simple web app layout.

We will only touch the .vue files

In src\web\app.vue we will add a permanent toolbat at the top and a navigation drawer at the left side of the page. We will configure the toolbar to be always visible, and the navigation drawer open by default in pages wider that 640 pixels.

<template lang="pug">
    v-app
        v-toolbar(app)
            v-toolbar-side-icon(@click="drawer=!drawer")
            v-toolbar-title Home
            v-spacer
            v-toolbar-items
                v-btn(flat to="/") home
                v-btn(flat to="/profile") profile
                v-btn(flat to="/about") about    
        
        v-navigation-drawer(v-model="drawer" app fixed mobile-break-point=640)
            v-list()               
                v-list-tile( to="/profile")
                    v-list-tile-action
                        v-icon account_circle
                    v-list-tile-title Profile
              
                v-divider
                
                v-list-tile(to="/" exact)
                    v-list-tile-action
                        v-icon home
                    v-list-tile-title Home

                v-list-tile(to="/about" exact)
                    v-list-tile-action
                        v-icon notes
                    v-list-tile-title about 
                
        v-content           
            router-view
            
</template>


<script>
    import Vue from "vue";
    import {router} from './_router.js';
    import {store} from './_store.js'
   
    export default Vue.extend({ 
        data: () => ( { 
            drawer: null 
        } ),

        store: store,
        router: router    
    });    
</script>

In src\web\vues\profile.vue we add a (dummy) login form using a v-card component

<template lang="pug">
    v-container(fluid fill-height)
        v-layout(justify-center)
            v-flex(xs12 sm8 md4)
            
                v-card(class="elevation-12")
                
                    v-toolbar( dark color="primary")
                        v-toolbar-title Login

                    v-card-text
                        v-form
                            v-text-field(prepend-icon="person" name="login" label="Username" type="text")
                            v-text-field(id="password" prepend-icon="lock" name="password" label="Password" type="password")

                    v-card-actions
                        v-spacer
                        v-btn(color="primary") Login

</template>

<script>
    export default {
        
    }
</script>

We make some minor alterations in

src\web\vues\home.vue

<template lang="pug">
    v-container(fluid) 
        h1 Home
        p Welcome: {{$store.state.name}}
       
</template>


<script>
    export default {
    }
</script>

Finally we modify src\web\vues\about.vue

<template lang="pug">
    v-container(fluid fill-height)
        v-layout(justify-center)
            v-flex(xs12 sm8 md4)
            
                v-card(class="elevation-12")
                
                    v-toolbar( dark color="primary")
                        v-toolbar-title About

                    v-card-text
                        p Let's Vuetify the template!                       

                    v-card-actions
                        v-spacer                        

</template>

<script>
    export default {
        
    }
</script>

Pug ?

We opted to use pug instead of html as our markup language, it’s a personal preference mainly due to being more compact ( a well structured page in pug should have about half the lines versus the html version - due to not having closing tags).

The result

Time to see the end-result, in desktop browser:

and in mobile (with the navigation drawer closed, and with navigation drawer open):

Next steps

In the next post we will add some real functionality in our web app.