version license GitHub issues open GitHub issues closed

Frontend version: Material Dashboard v2.1.2. More info at https://www.creative-tim.com/product/material-dashboard

Vue version: Vue Material Dashboard v1.4.0. More info at https://www.creative-tim.com/product/vue-material-dashboard

Product Image

What if your frontend came not only with reusable components, but also with a reusable backend? API-driven development is more than just a buzzword and we partnered with UPDIVISION to prove it. Build awesome-looking apps with a flexible architecture across a variety of devices and operating systems with Vue Material Dashboard Laravel.

Download

For the free version of the project you can either

  • download the .zip file from the Creative Tim site and extract it or
  • make a clone from the Github repository

You will get two project folders: one for the Laravel API project and one for the Vue frontend.

Laravel API Setup

Introduction

JSON:API is a specification for how a client should request that resources be fetched or modified, and how a server should respond to those requests. It is designed to minimize both the number of requests and the amount of data transmitted between clients and servers. This efficiency is achieved without compromising readability, flexibility, or discoverability.

Click here to go to the JSON:API docs

Prerequisites

The Laravel JSON:API project requires a working Apache/Nginx local environment with PHP, Composer and MySQL.

If you don't already have a local development environment, use one of the following links:

Laravel API Project Installation

  1. Navigate in your Laravel API project folder: cd your-laravel-json-api-project
  2. Install project dependencies: composer install
  3. Create a new .env file: cp .env.example .env
  4. Generate application key: php artisan key:generate
  5. Create users table: php artisan migrate --seed
  6. Add your own mailtrap.io credentials in MAIL_USERNAME and MAIL_PASSWORD in the .env file
  7. Add your own database credentials in the .env file in DB_DATABASE, DB_USERNAME, DB_PASSWORD
  8. Run php artisan passport:client --personal --name="Laravel Personal Access Client"
  9. Run php artisan passport:client --password --name="Laravel Password Grant Client"
  10. Add the "Laravel Password Grant Client" id to your .env file under the CLIENT_ID key
  11. Add the "Laravel Password Grant Client" secret to your .env file under the CLIENT_SECRET key

Vue Frontend Project Installation

Installation

  • Install Nodejs from Nodejs Official Page
  • Open your terminal
  • Navigate to the Vue frontend project folder: cd your-vue-frontend-project
  • Run npm install or yarn install if you use Yarn
  • Run npm run dev or yarn serve to start a local development server
  • A new tab will be opened in your browser
  • Set your enviroment variables from .env file found in root folder
    • VUE_APP_APP_BASE_URL - The base url of your application
    • VUE_APP_API_BASE_URL - The base url of your API consumed by your application

You can also run additional npm tasks such as

  • npm run build to build your app for production
  • npm run lint to run linting.

Vue-cli

We used the latest 3.x Vue CLI so you can configure your project in no time. You'll find everything you need inside package.json + some other related files such as .babelrc, .eslintrc.js and .postcssrc.js

Element-UI

Vue Material Dashboard json API also uses element-ui components, restyled to fit perfectly with the existing Material look & feel.

Usage

Register a user or login using admin@material.com and secret and start testing the theme.

Besides the dashboard and the auth pages this theme also has an edit profile page. All the necessary files are installed out of the box and all the needed routes are added to src\router\index.js. Keep in mind that all the features can be viewed once you log in using the credentials provided above or by registering your own user.

Dashboard

You can access the dashboard either by using the "Dashboards/Dashboard" link in the left sidebar or by adding /home in the URL.

Login

The login functionality is fully implemented in our theme helping you to start your project in no time. To login into dashboard you just have to add /login in the URL and fill the login form with the credentials (user: admin@material.com and password: secret).

The src\pages\Dashboard\Pages\Login.vue is the Vue component which handles the login functinality. You can easily adapt it to your needs.

It uses the auth store located in src\store\modules\auth.js.

Login card

<login-card header-color="green">
  <h4 slot="title" class="title">Log in</h4>
  <md-button slot="buttons" ref="#facebook" class="md-just-icon md-simple md-white">
    <i class="fab fa-facebook-square"></i>
  </md-button> 
  <md-button slot="buttons" href="#twitter" class="md-just-icon md-simple md-white">
    <i class="fab fa-twitter"></i>
  </md-button>
  <md-button slot="buttons" href="#google" class="md-just-icon md-simple md-white">
    <i class="fab fa-google-plus-g"></i>
  </md-button>
  <p slot="description" class="description">Or Be Classical</p>
  <md-field class="form-group md-invalid" slot="inputs" style="margin-bottom: 28px">
    <md-icon>email</md-icon>
    <label>Email...</label>
    <md-input v-model="email" type="email"/>
    <validation-error :errors="apiValidationErrors.email"/>
  </md-field>
  <md-field class="form-group md-invalid" slot="inputs">
    <md-icon>lock_outline</md-icon>
    <label>Password...</label>
    <md-input v-model="password" type="password"/>
  </md-field>
  <md-button slot="footer" @click="login" class="md-simple md-success md-lg">
    Lets Go
  </md-button>
</login-card>

Register

The register functionality is fully implemented in our theme helping you to start your project in no time. To register a new user you just have to add /register in the URL or click on register link from login page and fill the register form with user details.

The src\pages\Dashboard\Pages\Register.vue is the Vue component which handles the login functinality. You can easily extend it to your needs.

It uses the auth store located in src\store\modules\auth.js.

Register card

<signup-card>
    <h2 class="title text-center" slot="title">Register</h2>
    <div
        class="md-layout-item md-size-50 md-medium-size-50 md-small-size-100 ml-auto"
        slot="content-left"
    >
        <div
        class="info info-horizontal"
        v-for="item in contentLeft"
        :key="item.title"
        >
        <div :class="`icon ${item.colorIcon}`">
            <md-icon>{{ item.icon }}</md-icon>
        </div>
        <div class="description">
            <h4 class="info-title">{{ item.title }}</h4>
            <p class="description">
            {{ item.description }}
            </p>
        </div>
        </div>
    </div>
    <div
        class="md-layout-item md-size-50 md-medium-size-50 md-small-size-100 mr-auto"
        slot="content-right"
    >
        <div class="social-line text-center">
        <md-button class="md-just-icon md-round md-twitter">
            <i class="fab fa-twitter"></i>
        </md-button>
        <md-button class="md-just-icon md-round md-dribbble">
            <i class="fab fa-dribbble"></i>
        </md-button>
        <md-button class="md-just-icon md-round md-facebook">
            <i class="fab fa-facebook-f"></i>
        </md-button>
        <h4 class="mt-3">or be classical</h4>
        </div>

        <md-field class="md-form-group md-invalid" style="margin-bottom: 2rem">
        <md-icon>face</md-icon>
        <label>Name</label>
        <md-input v-model="name"/>
        <validation-error :errors="apiValidationErrors.name"/>
        </md-field>

        <md-field class="md-form-group md-invalid" style="margin-bottom: 2rem">
        <md-icon>email</md-icon>
        <label>Email</label>
        <md-input v-model="email"/>
        <validation-error :errors="apiValidationErrors.email"/>
        </md-field>

        <md-field class="md-form-group md-invalid" style="margin-bottom: 2rem">
        <md-icon>lock_outline</md-icon>
        <label>Password</label>
        <md-input v-model="password" type="password"/>
        <validation-error :errors="apiValidationErrors.password"/>
        </md-field>

        <md-field class="md-form-group md-invalid">
        <md-icon>lock_outline</md-icon>
        <label>Confirm Password</label>
        <md-input v-model="password_confirmation" type="password"/>
        <validation-error :errors="apiValidationErrors.password_confirmation"/>
        </md-field>

        <md-checkbox v-model="boolean">I agree to the <a>terms and conditions</a>.</md-checkbox>

        <div class="button-container">
        <md-button class="md-success md-round mt-4" @click="register" slot="footer">
            Get Started
        </md-button>
        </div>

    </div>
</signup-card>

Profile edit

You have the option to edit the current logged in user's profile information (name, email, profile picture) and password. To access this page, just click the "Examples/Profile" link in the left sidebar or add /profile in the URL.

The src\pages\Dashboard\Examples\UserProfile is the folder with Vue components that handle the update of the user information and password.

Edit profile component

<template>
  <form>
    <md-card>

      <md-card-header class="md-card-header-icon">
        <div class="card-icon">
          <md-icon>perm_identity</md-icon>
        </div>
        <h4 class="title">
          Edit Profile
        </h4>
      </md-card-header>

      <md-card-content>
        <div class="md-layout">
          <label class="md-layout-item md-size-15 md-form-label">
            Profile Photo
          </label>
          <div class="md-layout-item">
            <div class="file-input">
              <div v-if="avatar_img">
                <div class="image-container">
                  <img :src="avatar_img"/>
                </div>
              </div>
              <div class="image-container" v-else>
                <img :src="default_img"/>
              </div>
              <div class="button-container">
                <md-button class="md-danger md-round" @click="removeImage" v-if="avatar_img">
                  <i class="fa fa-times"/>
                  Remove
                </md-button>
                <md-button class="md-success md-fileinput">
                  <template v-if="!avatar_img">Select image</template>
                  <template v-else>Change</template>
                  <input type="file" @change="onFileChange"/>
                </md-button>
              </div>
            </div>
          </div>
        </div>

        <div class="md-layout">
          <label class="md-layout-item md-size-15 md-form-label">
            Name
          </label>
          <div class="md-layout-item">
            <md-field class="md-invalid">
              <md-input v-model="user.name"/>
              <validation-error :errors="apiValidationErrors.name"/>
            </md-field>
          </div>
        </div>

        <div class="md-layout">
          <label class="md-layout-item md-size-15 md-form-label">
            Email
          </label>
          <div class="md-layout-item">
            <md-field class="md-invalid">
              <md-input v-model="user.email"/>
              <validation-error :errors="apiValidationErrors.email"/>
            </md-field>
          </div>
        </div>

      </md-card-content>

      <md-card-actions>
        <md-button @click="updateProfile()">
          Update Profile
        </md-button>
      </md-card-actions>

    </md-card>
  </form>
</template>
<script>
  import {ValidationError} from "@/components";
  import formMixin from "@/mixins/form-mixin";

  export default {
    name: "edit-profile-card",

    props: {
      user: Object
    },

    components: {ValidationError},

    mixins: [formMixin],

    data() {
      return {
        avatar_img: null,
        default_img: process.env.VUE_APP_APP_BASE_URL + "/img/placeholder.jpg",
        file: null
      }
    },

    methods: {

      onFileChange(e) {
        let files = e.target.files || e.dataTransfer.files;
        if (!files.length) return;
        this.createImage(files[0]);
      },

      createImage(file) {
        let reader = new FileReader();
        reader.onload = e => {
          this.avatar_img = e.target.result;
          this.file = file;
        }
        reader.readAsDataURL(file);
      },

      removeImage() {
        this.avatar_img = null;
      },

      async updateProfile() {
        try {
          if (!this.user.profile_image) {
            await this.$store.dispatch("users/upload", {user: this.user, image: this.file})
            this.user.profile_image = await this.$store.getters["profile/url"]
          }
          await this.$store.dispatch("profile/update", this.user)
          await this.$store.dispatch("alerts/success", "Profile updated successfully.")
          this.user = await this.$store.getters["profile/me"]
        } catch (e) {
          await this.$store.dispatch("alerts/error", "Oops, something went wrong!")
          this.setApiValidation(e.response.data.errors)
        }

      }

    }
  };
</script>

Edit password component

<template>
  <form ref="password_form">

    <md-card>

      <md-card-header class="md-card-header-icon">
        <div class="card-icon">
          <md-icon>perm_identity</md-icon>
        </div>
        <h4 class="title">
          Change Password
        </h4>
      </md-card-header>

      <md-card-content>
        <div class="md-layout">
          <div class="md-layout-item md-size-100">
            <md-field class="md-invalid">
              <label>Current Password</label>
              <md-input v-model="password" type="password"/>
              <validation-error :errors="apiValidationErrors.password"/>
            </md-field>
            <md-field class="md-invalid">
              <label>New Password</label>
              <md-input v-model="new_password" type="password"/>
              <validation-error :errors="apiValidationErrors.password_confirmation"/>
            </md-field>
            <md-field class="md-invalid">
              <label>Confirm New Password</label>
              <md-input v-model="confirm_password" type="password"/>
              <validation-error :errors="apiValidationErrors.password_confirmation"/>
            </md-field>
          </div>
        </div>
      </md-card-content>

      <md-card-actions>
        <md-button @click="changePassword()">
          Change Password
        </md-button>
      </md-card-actions>
    </md-card>

  </form>
</template>

<script>
  import {ValidationError} from "@/components";
  import formMixin from "@/mixins/form-mixin";
  export default {
    name: "edit-password-card",

    props: {
      user: Object
    },

    components: {ValidationError},

    mixins: [formMixin],

    data: () => ({
      password: null,
      new_password: null,
      confirm_password: null
    }),

    methods: {
      async changePassword() {

        this.user.password = this.password;
        this.user.password_new = this.new_password;
        this.user.password_confirmation = this.confirm_password;

        try {
          await this.$store.dispatch("users/update", this.user)
          await this.$store.dispatch("alerts/error", "Password changed successfully.")
          this.user = await this.$store.getters["profile/me"]
          this.$refs['password_form'].reset()
        } catch (e) {
          await this.$store.dispatch("alerts/error", "Oops, something went wrong!")
          this.setApiValidation(e.response.data.errors)
        }

      }
    }
  };
</script>

Table of Contents

Versions

HTML Laravel
Material Dashboard HTML Material Dashboard Laravel
Vue Vue & Laravel
Vue Material Dashboard Vue Material Dashboard Laravel

Demo

Register Login Dashboard
Register Login Dashboard
Profile Page Users Page Tables Page
Profile Page Users Page Tables Page
View More

Documentation

The documentation for the Vue Material Dashboard Laravel is hosted at our website.

File Structure

|   .browserslistrc
|   .eslintrc.js
|   .gitignore
|   .jshintrc
|   babel.config.js
|   CHANGELOG.md
|   package-lock.json
|   package.json
|   postcss.config.js
|   README.md
|   yarn.lock
|
+---public
|   |   .DS_Store
|   |   favicon.png
|   |   index.html
|   |
|   \---img
|       |   apple-icon.png
|       |   bg-pricing.jpg
|       |   bg3.jpg
|       |   bg9.jpg
|       |   card-1.jpg
|       |   card-2.jpg
|       |   card-3.jpg
|       |   default-avatar.png
|       |   favicon.png
|       |   image_placeholder.jpg
|       |   laravel-vue.svg
|       |   lock.jpg
|       |   login.jpg
|       |   mask.png
|       |   new_logo.png
|       |   placeholder.jpg
|       |   product1.jpg
|       |   product2.jpg
|       |   product3.jpg
|       |   register.jpg
|       |   sidebar-1.jpg
|       |   sidebar-2.jpg
|       |   sidebar-3.jpg
|       |   sidebar-4.jpg
|       |   vue-logo.png
|       |
|       \---faces
|               avatar.jpg
|               card-profile1-square.jpg
|               card-profile2-square.jpg
|               marc.jpg
|
\---src
    |   .DS_Store
    |   App.vue
    |   globalComponents.js
    |   globalDirectives.js
    |   main.js
    |   material-dashboard.js
    |
    +---assets
    |   |   .DS_Store
    |   |
    |   +---css
    |   |       demo.css
    |   |
    |   +---images
    |   |       avatar.jpg
    |   |
    |   \---scss
    |       |   .DS_Store
    |       |   material-dashboard.scss
    |       |
    |       \---md
    |           |   .DS_Store
    |           |   _alerts.scss
    |           |   _autocomplete.scss
    |           |   _badges.scss
    |           |   _buttons.scss
    |           |   _cards.scss
    |           |   _chartist.scss
    |           |   _checkboxes.scss
    |           |   _collapse.scss
    |           |   _colors.scss
    |           |   _dialogs.scss
    |           |   _dropdown.scss
    |           |   _fileinput.scss
    |           |   _fixed-plugin.scss
    |           |   _footers.scss
    |           |   _forms.scss
    |           |   _headers.scss
    |           |   _info-areas.scss
    |           |   _inputs-size.scss
    |           |   _inputs.scss
    |           |   _layout.scss
    |           |   _misc.scss
    |           |   _mixins.scss
    |           |   _navbars.scss
    |           |   _pages.scss
    |           |   _pagination.scss
    |           |   _pills.scss
    |           |   _popups.scss
    |           |   _progress.scss
    |           |   _radios.scss
    |           |   _responsive.scss
    |           |   _rtl.scss
    |           |   _select.scss
    |           |   _shadows.scss
    |           |   _sidebar-and-main-panel.scss
    |           |   _tables.scss
    |           |   _tabs.scss
    |           |   _tags.scss
    |           |   _timeline.scss
    |           |   _togglebutton.scss
    |           |   _typography.scss
    |           |   _variables.scss
    |           |
    |           +---cards
    |           |       _card-global-sales.scss
    |           |       _card-login.scss
    |           |       _card-pricing.scss
    |           |       _card-product.scss
    |           |       _card-profile.scss
    |           |       _card-signup.scss
    |           |       _card-tabs.scss
    |           |       _card-testimonials.scss
    |           |
    |           +---mixins
    |           |       _chartist.scss
    |           |       _sidebar.scss
    |           |       _transparency.scss
    |           |       _vendor-prefixes.scss
    |           |
    |           \---plugins
    |                   _animate.scss
    |                   _fullcalendar.scss
    |                   _md-datepicker.scss
    |                   _perfect-scrollbar.scss
    |                   _plugin-jquery.jvectormap.scss
    |                   _plugin-nouislider.scss
    |                   _sweetalert2.scss
    |                   _wizard-card.scss
    |
    +---axios
    |       index.js
    |
    +---components
    |   |   .DS_Store
    |   |   Badge.vue
    |   |   Dropdown.vue
    |   |   index.js
    |   |   Logout.vue
    |   |   Pagination.vue
    |   |   Slider.vue
    |   |   Tabs.vue
    |   |   ValidationError.vue
    |   |
    |   +---Cards
    |   |       ChartCard.vue
    |   |       LoginCard.vue
    |   |       NavTabsCard.vue
    |   |       SignupCard.vue
    |   |       StatsCard.vue
    |   |
    |   +---NotificationPlugin
    |   |       index.js
    |   |       Notification.vue
    |   |       Notifications.vue
    |   |
    |   +---SidebarPlugin
    |   |       index.js
    |   |       SideBar.vue
    |   |       SidebarItem.vue
    |   |
    |   \---WorldMap
    |           WorldMap.vue
    |           world_map.js
    |
    +---middleware
    |       auth.js
    |       guest.js
    |
    +---mixins
    |       form-mixin.js
    |
    +---pages
    |   |   .DS_Store
    |   |   FixedPlugin.vue
    |   |
    |   \---Dashboard
    |       |   .DS_Store
    |       |   Dashboard.vue
    |       |
    |       +---Components
    |       |       Icons.vue
    |       |       Notifications.vue
    |       |       Typography.vue
    |       |
    |       +---Examples
    |       |   |   UserProfile.vue
    |       |   |
    |       |   +---UserManagement
    |       |   |       AddUserPage.vue
    |       |   |       EditUserPage.vue
    |       |   |       ListUserPage.vue
    |       |   |
    |       |   \---UserProfile
    |       |           EditPasswordCard.vue
    |       |           EditProfileCard.vue
    |       |           UserProfileCard.vue
    |       |
    |       +---Layout
    |       |   |   Content.vue
    |       |   |   ContentFooter.vue
    |       |   |   DashboardLayout.vue
    |       |   |   TopNavbar.vue
    |       |   |
    |       |   \---Extra
    |       |           MobileMenu.vue
    |       |           UserMenu.vue
    |       |
    |       +---Maps
    |       |       API_KEY.js
    |       |       FullScreenMap.vue
    |       |
    |       +---Pages
    |       |       AuthLayout.vue
    |       |       Login.vue
    |       |       Register.vue
    |       |       RtlSupport.vue
    |       |
    |       \---Tables
    |               RegularTables.vue
    |
    +---router
    |       index.js
    |       routes.js
    |
    \---store
        |   index.js
        |
        +---modules
        |       alerts-module.js
        |       auth.js
        |       categories-module.js
        |       items-module.js
        |       profile-module.js
        |       roles-module.js
        |       tags-module.js
        |       users-module.js
        |
        \---services
                categories-service.js
                items-service.js
                profile-service.js
                roles-service.js
                tags-service.js
                users-service.js

Browser Support

At present, we officially aim to support the last two versions of the following browsers:

Resources

HTML Laravel
Material Dashboard HTML Material Dashboard Laravel
Vue Vue & Laravel
Vue Material Dashboard Vue Material Dashboard Laravel

Change log

Please see the changelog for more information on what has changed recently.

Credits

Reporting Issues

We use GitHub Issues as the official bug tracker for the Vue Material Dashboard Laravel. Here are some advices for our users that want to report an issue:

  1. Make sure that you are using the latest version of the Vue Material Dashboard Laravel. Check the CHANGELOG from your dashboard on our website.
  2. Providing us reproducible steps for the issue will shorten the time it takes for it to be fixed.
  3. Some issues may be browser specific, so specifying in what browser you encountered the issue might help.

Licensing

Useful Links

Social Media

Creative Tim:

Twitter: https://twitter.com/CreativeTim?ref=vmdl-readme

Facebook: https://www.facebook.com/CreativeTim?ref=vmdl-readme

Dribbble: https://dribbble.com/creativetim?ref=vmdl-readme

Instagram: https://www.instagram.com/CreativeTimOfficial?ref=vmdl-readme

Updivision:

Twitter: https://twitter.com/updivision?ref=vmdl-readme

Facebook: https://www.facebook.com/updivision?ref=vmdl-readme

Linkedin: https://www.linkedin.com/company/updivision?ref=vmdl-readme

Updivision Blog: https://updivision.com/blog/?ref=vmdl-readme

Credits