Documentation v8.1.6

Preview Downloads Purchase

Overview

This documentation manual will explain how to implement Keenthemes designed admin dashboard theme Metronic  in Laravel application. This article provided assuming you have a commom knowledge/understanding of Metronic, Laravel and Webpack.

Requirements

  1. PHP.
  2. Composer - a Dependency Manager for PHP.
  3. Install Node.js, NPM, Yarn, Webpack dependencies as explained in Webpack Quick Start.

Create Laravel Application

  1. In your terminal, run the following command to create your Laravel  app:
    composer create-project --prefer-dist laravel/laravel laravel
    
  2. This command creates your new Laravel  app project and places it in a new directory called laravelinside your current location. Navigate into the newly created laraveldirectory by the following command:
    cd laravel
    

Preparing Theme Assets

  1. Copy source folder from theme/srcand paste it into laravel/resources.
  2. In Metronic some plugins and components pages are located inside tools/webpackfolder, so we need to move them into the same src folder in laravel project.
    Copy tools/webpackfolder and paste it into laravel/resources/src.

Fix Style Import Paths

  1. Since Metronic theme use node_modulesfolder which is located inside tools, but in laravel app we will use a root node_modules.
    Inside file laravel/resources/src/sass/components/components.scsswe need to update import path and change ../../../tools/node_modules/to ~which is alias for node_modulesfolder.

Preparing Theme Dependencies

  1. To prepare theme dependencies we can just copy devDependencies and dependencies sections from theme/tools/package.jsonand paste them into laravel/package.json.
  2. The default dev dependency laravel-mixis required for next steps, you should leave it in the npm/package.json.
    Remove default package-lock.json file first from laravel's root directory before the next step.
  3. Now we can fetch the dependencies. Run this command in Laravel application root (where package.jsonis placed)
  4. npm install
    

Preparing Mix Config

  1. Find and open laravel/webpack.mix.jsfile. Copy and paste below code.
    const mix = require('laravel-mix');
    const glob = require('glob');
    const path = require('path');
    const ReplaceInFileWebpackPlugin = require('replace-in-file-webpack-plugin');
    const rimraf = require('rimraf');
    const del = require('del');
    const fs = require('fs');
    
    /*
     |--------------------------------------------------------------------------
     | Mix Asset Management
     |--------------------------------------------------------------------------
     |
     | Mix provides a clean, fluent API for defining some Webpack build steps
     | for your Laravel applications. By default, we are compiling the CSS
     | file for the application as well as bundling up all the JS files.
     |
     */
    
    // arguments/params from the line command
    const args = getParameters();
    
    mix.options({
        cssNano: {
            discardComments: false,
        }
    });
    
    // Remove existing generated assets from public folder
    del.sync(['public/css/*', 'public/js/*', 'public/media/*', 'public/plugins/*',]);
    
    // Build 3rd party plugins css/js
    mix.sass(`resources/src/webpack/plugins/plugins.scss`, `public/assets/plugins/global/plugins.bundle.css`).then(() => {
        // remove unused preprocessed fonts folder
        rimraf(path.resolve('public/fonts'), () => {
        });
        rimraf(path.resolve('public/images'), () => {
        });
    }).sourceMaps(!mix.inProduction())
        // .setResourceRoot('./')
        .options({processCssUrls: false}).js([`resources/src/webpack/plugins/plugins.js`], `public/assets/plugins/global/plugins.bundle.js`);
    
    // Build extended plugin styles
    mix.sass(`resources/src/sass/plugins.scss`, `public/assets/plugins/global/plugins-custom.bundle.css`);
    
    mix.sass(`resources/src/sass/style.scss`, `public/assets/css/style.bundle.css`, {sassOptions: {includePaths: ['node_modules']}})
        // .options({processCssUrls: false})
        .js([`resources/src/webpack/scripts.js`], `public/assets/js/scripts.bundle.js`);
    
        mix.js('./resources/src/js/widgets/**/!(_)*.js', 'public/assets/js/widgets.bundle.js');
    
    
    // Dark skin mode css files
    if (args.indexOf('dark_mode') !== -1) {
        mix.sass(`resources/src/plugins/plugins.dark.scss`, `public/assets/plugins/global/plugins.dark.bundle.css`);
        mix.sass(`resources/src/sass/plugins.dark.scss`, `public/assets/plugins/global/plugins-custom.dark.bundle.css`);
        mix.sass(`resources/src/sass/style.dark.scss`, `public/assets/css/style.dark.bundle.css`, {sassOptions: {includePaths: ['node_modules']}});
    }
    
    
    // Build custom 3rd party plugins
    (glob.sync(`resources/src/plugins/custom/**/*.js`) || []).forEach(file => {
        mix.js(file, `public/assets/${file.replace(`resources/src/`, '').replace('.js', '.bundle.js')}`);
    });
    (glob.sync(`resources/src/plugins/custom/**/*.scss`) || []).forEach(file => {
        mix.sass(file, `public/assets/${file.replace(`resources/src/`, '').replace('.scss', '.bundle.css')}`);
    });
    
    (glob.sync(`resources/src/sass/pages/**/!(_)*.scss`) || []).forEach(file => {
        file = file.replace(/[\\\/]+/g, '/');
        mix.sass(file, file.replace(`resources/src/sass`, `public/assets/css`).replace(/\.scss$/, '.css'));
    });
    
    var extendedFiles = [];
    // Extend custom js files for laravel
    (glob.sync('resources/src/extended/js/**/*.js') || []).forEach(file => {
        var output = `public/assets/${file.replace('resources/src/extended/', '')}`;
        mix.js(file, output);
        extendedFiles.push(output);
    });
    
    (glob.sync('resources/src/js/custom/**/*.js') || []).forEach(file => {
        var output = `public/assets/${file.replace('resources/src/', '')}`;
        if (extendedFiles.indexOf(output) === -1) {
            mix.js(file, output);
        }
    });
    
    mix.copyDirectory('resources/src/media', `public/assets/media`);
    mix.copyDirectory(`resources/src/media`, `public/assets/media`);
    
    (glob.sync(`resources/src/sass/themes/**/!(_)*.scss`) || []).forEach(file => {
        file = file.replace(/[\\\/]+/g, '/');
        mix.sass(file, file.replace(`resources/src/sass`, `public/assets/css`).replace(/\.scss$/, '.css'));
    });
    
    let plugins = [
        new ReplaceInFileWebpackPlugin([
            {
                // rewrite font paths
                dir: path.resolve(`public/assets/plugins/global`),
                test: /\.css$/,
                rules: [
                    {
                        // fontawesome
                        search: /url\((\.\.\/)?webfonts\/(fa-.*?)"?\)/g,
                        replace: 'url(./fonts/@fortawesome/$2)',
                    },
                    {
                        // flaticon
                        search: /url\(("?\.\/)?font\/(Flaticon\..*?)"?\)/g,
                        replace: 'url(./fonts/flaticon/$2)',
                    },
                    {
                        // flaticon2
                        search: /url\(("?\.\/)?font\/(Flaticon2\..*?)"?\)/g,
                        replace: 'url(./fonts/flaticon2/$2)',
                    },
                    {
                        // keenthemes fonts
                        search: /url\(("?\.\/)?(Ki\..*?)"?\)/g,
                        replace: 'url(./fonts/keenthemes-icons/$2)',
                    },
                    {
                        // lineawesome fonts
                        search: /url\(("?\.\.\/)?fonts\/(la-.*?)"?\)/g,
                        replace: 'url(./fonts/line-awesome/$2)',
                    },
                    {
                        // socicons
                        search: /url\(("?\.\.\/)?font\/(socicon\..*?)"?\)/g,
                        replace: 'url(./fonts/socicon/$2)',
                    },
                    {
                        // bootstrap-icons
                        search: /url\(.*?(bootstrap-icons\..*?)"?\)/g,
                        replace: 'url(./fonts/bootstrap-icons/$1)',
                    },
                ],
            },
        ]),
    ];
    
    mix.webpackConfig({
        plugins: plugins,
        ignoreWarnings: [{
            module: /esri-leaflet/,
            message: /version/,
        }],
        resolve: {
        alias: {
            "@": path.resolve(__dirname, "resources/"),
            'handlebars': 'handlebars/dist/handlebars.js',
        },
        extensions: ['.js', '.scss'],
        fallback: {
            util: false,
        },
    }
    });
    
    // Webpack.mix does not copy fonts, manually copy
    (glob.sync(`resources/src/plugins/**/*.+(woff|woff2|eot|ttf)`) || []).forEach(file => {
        var folder = file.match(/resources\/src\/plugins\/(.*?)\//)[1];
        mix.copy(file, `public/assets/plugins/global/fonts/${folder}/${path.basename(file)}`);
    });
    (glob.sync('node_modules/+(@fortawesome|socicon|line-awesome|bootstrap-icons)/**/*.+(woff|woff2|eot|ttf)') || []).forEach(file => {
        var folder = file.match(/node_modules\/(.*?)\//)[1];
        mix.copy(file, `public/assets/plugins/global/fonts/${folder}/${path.basename(file)}`);
    });
    
    // Raw plugins
    (glob.sync(`resources/src/plugins/custom/**/*.js.json`) || []).forEach(file => {
        let filePaths = JSON.parse(fs.readFileSync(file, 'utf-8'));
        const fileName = path.basename(file).replace('.js.json', '');
        mix.scripts(filePaths, `public/assets/plugins/custom/${fileName}/${fileName}.bundle.js`);
    });
    
    function getParameters() {
        var possibleArgs = [
            'dark_mode'
        ];
        for (var i = 0; i <= 13; i++) {
            possibleArgs.push('demo' + i);
        }
    
        var args = [];
        possibleArgs.forEach(function (key) {
            if (process.env['npm_config_' + key]) {
                args.push(key);
            }
        });
    
        return args;
    }
    
    This webpack.mix.js configuration file will bundle all source files which theme is requiring. Bundled files will be placed into laravel/publicfolder.

Compile Assets

  1. Run the following command to compile source files.
    npm run dev
    
    We now can implement Metronic theme layout into Laravel application and include scripts/styles we have compiled.

Sample Page

For the sample page you can use dist/index.htmlcode or Layout Builder to export the layout's HTML code and paste it into laravel/resources/views/welcome.blade.php
The Layout builder allows you to export the layout HTML code with structure partials that can be organized in separate folder with your Laravel views folder and included as partials within your layout view.

Run Application:

  1. In your terminal, run the following command:
    php artisan serve
    
  2. Wait for the app to display that it's listening on http://127.0.0.1:8000  and open this url in your browser.
Learn & Get Inspired

Support at devs.keenthemes.com

Join our developers community to find answer to your question and help others. FAQs
Get Support
Video Tutorials
From guides and how-tos, to live demos and code examples to get started right away.
Metronic Downloads
Download your prefered framework and demo with one click.
What's New ?
Latest features and improvements added with our users feedback in mind.
Buy now