Create a dashboard with TailwindCSS - Part 3
Tags: tailwindcss, tutorial, vue, storyblok
Published: 2020-06-01 08:19:34

{% tweet 1267193996587171841 %}

## Prerequisites

As this post is the continuation of a series, if you haven't read it yet you should start with the [Part 1](https://www.dawntraoz.com/blog/create-a-dashboard-with-tailwindcss-part-1).

Do you have everything up to date? So let's get on with it.

## Defining the main panel

As the dashboard consists of three main **KPI**s such as *weight loss*, *minutes active* and *steps*, we will represent these data through *blocks* and *charts*.

We can divide the dashboard into three parts:

- **Main block** (Activity)

  This block will be the first one we will see on the dashboard. It should be as wide as possible and show data from the last two weeks, compared to the previous month.

  > For this example, we will focus only on the steps and, at the moment, we will use test data generated by Math.random().

- **Create objective**

  In order to make sense of the results shown in the dashboard we need a block from which we can choose our objectives.

- **Today results**

  And clearly, we need a section where we can see at a glance how we're doing today.

---

## Create the main panel structure

After having a general idea of how our first version will be, let's shape it up!

### 1. Chart Block
  
The first thing we are going to do is to define a component that will allow us to define the title, size and aspect of each block.

For that, we go to the *Storyblok* panel and in the **Components** section we create a new one. In its **schema** I have defined the fields I show you below:

- **Title**, type text field.

- **Width**, a single-option selector with three options 'full', 'one third' and 'two third'.

- **Card**, a boolean that if checked the vue component will add TailwindCSS styles to simulate a card.

- **Body**, type block to add the content we want in each section.

The resultant schema will be:

![Schema ChartBlock](//a.storyblok.com/f/79165/468x600/1c7d46e70a/schema-chart.png)

---

After defining it, I have created its equivalent vue component named **ChartBlock.vue**, then I’ve added it in the plugin *components.js* with the rest of components:

  ```javascript
  /* Dashboard */
  import ChartBlock from '@/components/ChartBlock.vue'

  Vue.component('ChartBlock', ChartBlock)
  ```

  In this component we receive, in the prop **blok**, all the information defined in our schema.

  - **blok.width**: As the width is given by the values 'full', 'one-third', 'two-third', I have created an array in data that will return the equivalent tailwind class to the chosen width.

  - **blok.title**: The title will simply be represented between h2 tags. Depending on the width chosen its font size will be smaller, for example for the case 'x-third' its font size will be the one defined by the class 'text-xl'.

  - **blok.card**: In this case (a boolean), if its value is true we will represent the classes *'bg-white rounded-lg p-4 md:p-6'*, which will give it a card shape, and if not simply *'md:pl-8'*.

  - **blok.body**: As always, we will add it in a dynamic component that will represent the blocks we add from *Storyblok* in the body field.

  ```html
  <template>
    <div class="pt-6" :class="width[blok.width]">
      <section
        class="w-full"
        :class="blok.card ? 'bg-white rounded-lg p-4 md:p-6' : 'md:pl-8'"
      >
        <header class="pb-4">
          <h2 :class="{ 'text-xl': blok.width !== 'full' }">
            {{ blok.title }}
          </h2>
        </header>
        <div :class="{ 'flex flex-wrap md:-mr-6': !blok.card }">
          <component
            :is="blok.component"
            v-for="blok in blok.body"
            :key="blok._uid"
            :blok="blok"
          ></component>
        </div>
      </section>
    </div>
  </template>

  <script>
  export default {
    props: ['blok'],
    data: () => {
      return {
        width: {
          full: 'w-full',
          'one-third': 'w-full md:w-1/3',
          'two-third': 'w-full md:w-2/3'
        }
      }
    }
  }
  </script>
  ```

---

### 2. Chart Activity

  This will be the component that represents our main chart, created through [VueApexCharts](https://www.npmjs.com/package/vue-apexcharts), that I’ll tell you about below.

  Just as we defined the style guide components, we create **ChartActivity** in **Components** in the *Storyblok* panel without a schema. And now, we create **ChartActivity.vue** and add it to the components.js plugin as with **ChartBlock**:

  ```javascript
  /* Dashboard */
  import ChartActivity from '@/components/ChartActivity.vue'

  Vue.component('ChartActivity', ChartActivity)
  ```

  For this component, as we want to use **ApexCharts** for our charts and we’re working with **VueJS**, we’ll also need to add to our project the wrapper they have prepared for us.

  We are going to install the dependencies using the following commands:

  ```bash
  npm install --save apexcharts
  npm install --save vue-apexcharts
  ```

  Now, to start using it in our Nuxt.js project we're going to create a plugin called **vue-apex-charts.js** in the plugins folder with the content:

  ```javascript
  import Vue from 'vue'
  import VueApexCharts from 'vue-apexcharts'

  Vue.use(VueApexCharts)
  Vue.component('VueApexCharts', VueApexCharts)
  ```

  And, in our nuxt configuration file, we're going to add it with client mode enabled (necessary for it to work):

  ```javascript
  plugins: [
    …,
    { src: '~/plugins/vue-apex-charts.js', mode: 'client' }
  ],
  ```

  Surrounding by the *client-only* tags the **VueApexCharts** component, we can now use it in our ChartActivity component 🍾 Let’s see it:

  ```html
  <template>
    <client-only>
      <VueApexCharts
        height="350"
        type="bar"
        :options="chartOptions"
        :series="series"
      />
    </client-only>
  </template>
  ```

  > All the options available to bring our charts to life can be found at  [ApexCharts docs](https://apexcharts.com/docs), I recommend you keep an eye on it.

  This is how the test chart looks like, with a type **bar** chart and our main **colors**:

  ![Chart main activity](//a.storyblok.com/f/79165/1313x516/4c035477ab/main-chart.png)

---

### 3. Chart Objective

As above, I've created a new one component named **ChartObjective** without a schema. And I've created the component **ChartObjective.vue**, as before, adding it to the components.js:

  ```javascript
  /* Dashboard */
  import ChartObjective from '@/components/ChartObjective.vue'

  Vue.component('ChartObjective', ChartObjective)
  ```

As we are not yet going to add the post request that would go in this block, for now I have simply added an SVG illustration representing the action to be performed.

---

### 4. Chart Result

In this block we will represent the highlights of the day, the weight lost, the steps taken and the minutes of activity.

For that, as in the previous cases, we created the component both in Storyblok and in our project. In this case we will have three fields: **name**, **value** and **highlighted**.

That's how we represent it:

```html
<template>
  <div class="w-full md:w-1/3 md:pr-6 pb-4">
    <div
      class="rounded-lg p-8"
      :class="{
        'bg-complementary-300 text-white': blok.highlighted,
        'bg-white text-primary-500': !blok.highlighted
      }"
    >
      <strong class="text-xl">{{ blok.value }}</strong>
      <p>{{ blok.name }}</p>
    </div>
  </div>
</template>

<script>
export default {
  props: ['blok']
}
</script>
```

And that's how it would look:

![Chart results](//a.storyblok.com/f/79165/862x220/cb97895a16/main-results.png)

---

## Main page composition

Now that we have created all the components we need to create our main page, we just need to add them in the **Cabbage** page, already created in the [last article](https://www.dawntraoz.com/blog/create-a-dashboard-with-tailwindcss-adding-storyblok).

Our body will be composed by three **ChartBlock**s:

- **Main activity**: with 'Main activity' as **title**, true **card**, full **width** and *ChartActivity* as the only block on **body**.

- **Create objective**: with 'Create objective' as **title**, true **card**, one third **width** and *ChartObjective* as the only block on **body**.

- **Today results**: with 'Today results' as **title**, false **card**, two third **width** and three *ChartResult* blocks on **body**.

The resultant body page looks like now:

![Main page composition](//a.storyblok.com/f/79165/356x563/dd8b878de2/page-panel.png)

---

Great! I've finished telling you the progress on the dashboard 💜

This is how our main panel looks like:

![Dashboard main page](//a.storyblok.com/f/79165/1556x937/2cbccac4af/dashboard-panel.png)

---

I've updated the project in [Cabbage Dashboard DEMO](https://cabbage-dashboard.herokuapp.com/styleguide) 💜

And remember, I will be adding new functionalities and explaining how I did it 🥰

Here is the repository, in case you want to take a look: [https://github.com/Dawntraoz/cabbage](https://github.com/Dawntraoz/cabbage)