Documentation v8.0.28

Preview 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. {
        "private": true,
        "scripts": {
            "dev": "npm run development",
            "development": "mix",
            "watch": "mix watch",
            "watch-poll": "mix watch -- --watch-options-poll=1000",
            "hot": "mix watch --hot",
            "prod": "npm run production",
            "production": "mix --production"
        },
        "dependencies": {
            "@amcharts/amcharts4": "^4.10.20",
            "@ckeditor/ckeditor5-alignment": "^23.1.0",
            "@ckeditor/ckeditor5-build-balloon": "^23.1.0",
            "@ckeditor/ckeditor5-build-balloon-block": "^23.1.0",
            "@ckeditor/ckeditor5-build-classic": "^23.1.0",
            "@ckeditor/ckeditor5-build-decoupled-document": "^23.1.0",
            "@ckeditor/ckeditor5-build-inline": "^23.1.0",
            "@fortawesome/fontawesome-free": "^5.15.3",
            "@popperjs/core": "^2.9.3",
            "@shopify/draggable": "^1.0.0-beta.8",
            "@yaireo/tagify": "^4.4.0",
            "acorn": "^8.0.4",
            "apexcharts": "^3.27.3",
            "autosize": "^5.0.1",
            "axios": "^0.21.1",
            "bootstrap": "5.1.1",
            "bootstrap-daterangepicker": "^3.1.0",
            "bootstrap-icons": "^1.5.0",
            "bootstrap-maxlength": "^1.10.1",
            "bootstrap-multiselectsplitter": "^1.0.4",
            "chalk": "^4.1.0",
            "chart.js": "^3.4.1",
            "clipboard": "^2.0.8",
            "countup.js": "^2.0.7",
            "cropperjs": "^1.5.12",
            "datatables.net": "^1.10.25",
            "datatables.net-bs5": "^1.10.25",
            "datatables.net-buttons": "^1.7.1",
            "datatables.net-buttons-bs5": "^1.7.1",
            "datatables.net-colreorder": "^1.5.4",
            "datatables.net-colreorder-bs5": "^1.5.4",
            "datatables.net-datetime": "^1.1.0",
            "datatables.net-fixedcolumns": "^3.3.3",
            "datatables.net-fixedcolumns-bs5": "^3.3.3",
            "datatables.net-fixedheader": "^3.1.9",
            "datatables.net-fixedheader-bs5": "^3.1.9",
            "datatables.net-responsive": "^2.2.9",
            "datatables.net-responsive-bs5": "^2.2.9",
            "datatables.net-rowgroup": "^1.1.3",
            "datatables.net-rowgroup-bs5": "^1.1.3",
            "datatables.net-rowreorder": "^1.2.8",
            "datatables.net-rowreorder-bs5": "^1.2.8",
            "datatables.net-scroller": "^2.0.4",
            "datatables.net-scroller-bs5": "^2.0.4",
            "datatables.net-select": "^1.3.3",
            "datatables.net-select-bs5": "^1.3.3",
            "dropzone": "^5.9.2",
            "es6-promise": "^4.2.8",
            "es6-promise-polyfill": "^1.2.0",
            "es6-shim": "^0.35.5",
            "esri-leaflet": "^3.0.2",
            "esri-leaflet-geocoder": "^3.0.0",
            "flatpickr": "^4.6.9",
            "flot": "^4.2.2",
            "fslightbox": "^3.3.0-2",
            "fullcalendar": "^5.8.0",
            "handlebars": "^4.7.7",
            "inputmask": "^5.0.6",
            "jkanban": "^1.3.1",
            "jquery": "3.6.0",
            "jstree": "^3.3.11",
            "jszip": "^3.6.0",
            "leaflet": "^1.7.1",
            "line-awesome": "^1.3.0",
            "moment": "^2.29.1",
            "nouislider": "^15.2.0",
            "npm": "^7.19.1",
            "pdfmake": "^0.2.0",
            "prism-themes": "^1.7.0",
            "prismjs": "^1.24.1",
            "quill": "^1.3.7",
            "select2": "^4.1.0-rc.0",
            "smooth-scroll": "^16.1.3",
            "sweetalert2": "^11.0.18",
            "tiny-slider": "^2.9.3",
            "tinymce": "^5.8.2",
            "toastr": "^2.1.4",
            "typed.js": "^2.0.12",
            "vis-timeline": "^7.4.9",
            "webpack-rtl-plugin": "^2.0.0",
            "wnumb": "^1.2.0"
        },
        "devDependencies": {
            "@babel/core": "^7.13.14",
            "@babel/plugin-transform-modules-commonjs": "^7.13.8",
            "@babel/preset-env": "^7.13.12",
            "@babel/register": "^7.13.14",
            "copy-webpack-plugin": "^8.1.0",
            "css-loader": "^5.2.0",
            "css-minimizer-webpack-plugin": "^1.3.0",
            "del": "^6.0.0",
            "extract-loader": "^5.1.0",
            "file-loader": "^6.2.0",
            "fs-extra": "^10.0.0",
            "gulp": "^4.0.2",
            "gulp-clean-css": "^4.3.0",
            "gulp-concat": "^2.6.1",
            "gulp-connect": "^5.7.0",
            "gulp-dart-sass": "^1.0.2",
            "gulp-if": "^3.0.0",
            "gulp-rename": "^2.0.0",
            "gulp-rewrite-css": "^1.1.2",
            "gulp-rtlcss": "^1.4.1",
            "gulp-sourcemaps": "^3.0.0",
            "gulp-terser": "^2.0.1",
            "imports-loader": "^1.2.0",
            "lazypipe": "^1.0.2",
            "merge-stream": "^2.0.0",
            "mini-css-extract-plugin": "^1.3.4",
            "postcss-loader": "^4.0.4",
            "pretty": "^2.0.0",
            "replace-in-file-webpack-plugin": "^1.0.6",
            "rtlcss-webpack-plugin": "^4.0.6",
            "sass-loader": "^10.1.0",
            "script-loader": "^0.7.2",
            "terser-webpack-plugin": "^5.0.3",
            "url-loader": "^4.1.1",
            "webpack": "^5.28.0",
            "webpack-cli": "^4.6.0",
            "webpack-dev-server": "^3.11.2",
            "webpack-exclude-assets-plugin": "^0.1.1",
            "webpack-merge-and-include-globally": "^2.3.4",
            "webpack-messages": "^2.0.4",
            "yargs": "^16.2.0",
            "yarn-install": "^1.0.0",
            "axios": "^0.21",
            "laravel-mix": "^6.0.6",
            "lodash": "^4.17.19"
        }
    }
    
    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 WebpackRTLPlugin = require("webpack-rtl-plugin");
    const del = require("del");
    
    /*
     |--------------------------------------------------------------------------
     | 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.
     |
     */
    
    // Remove existing generated assets from public folder
    del.sync([
        "public/assets/css/*",
        "public/assets/js/*",
        "public/assets/media/*",
        "public/assets/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/assets/fonts"), () => {});
            rimraf(path.resolve("public/assets/images"), () => {});
        })
        .sourceMaps(!mix.inProduction())
        // .setResourceRoot('./')
        .options({ processCssUrls: false })
        .js(
            ["resources/src/webpack/plugins/plugins.js"],
            "public/assets/plugins/global/plugins.bundle.js"
        );
    
    // Build css/js
    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"
        );
    
    // 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")}`
        );
    });
    
    // Build css pages (single page use)
    (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/extended/js/**/*.js") || []).forEach((file) => {
        var output = `public/assets/${file.replace("resources/extended/", "")}`;
        mix.js(file, output);
        extendedFiles.push(output);
    });
    
    // Js pages (single page use)
    (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);
        }
    });
    
    // Copy media folder
    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")
        );
    });
    
    mix.webpackConfig({
        resolve: {
            alias: {
                "@": path.resolve(__dirname, "./resources"),
            },
            extensions: [".js", ".scss"],
        },
        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)",
                        },
                    ],
                },
            ]),
            // Uncomment this part for RTL version
            /*new WebpackRTLPlugin({
                filename: '[name].rtl.css',
                options: {},
                plugins: [],
            })*/
        ],
        ignoreWarnings: [
            {
                module: /esri-leaflet/,
                message: /version/,
            },
        ],
    });
    
    // Webpack.mix does not copy fonts, manually copy
    (glob.sync("resources/src/plugins/**/*.+(woff|woff2|eot|ttf)") || []).forEach(
        (file) => {
            var folder = file.match(/resources\/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)}`
        );
    });
    
    // Optional: Output datatables.net
    mix.scripts(
        [
            "node_modules/datatables.net/js/jquery.dataTables.js",
            "node_modules/datatables.net-bs4/js/dataTables.bootstrap4.js",
            "node_modules/datatables.net-responsive/js/dataTables.responsive.min.js",
            "node_modules/datatables.net-responsive-bs4/js/responsive.bootstrap4.min.js",
            "node_modules/datatables.net-scroller/js/dataTables.scroller.min.js",
            "resources/src/js/vendors/plugins/datatables.init.js",
        ],
        "public/assets/plugins/custom/datatables/datatables.bundle.js"
    );
    mix.styles(
        [
            "node_modules/datatables.net-bs4/css/dataTables.bootstrap4.css",
            "node_modules/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css",
            "node_modules/datatables.net-scroller-bs4/css/scroller.bootstrap4.min.css",
        ],
        "public/assets/plugins/custom/datatables/datatables.bundle.css"
    );
    
    // Optional: Output fullcalendar
    // mix.scripts([
    //     'node_modules/fullcalendar/main.js',
    //     'node_modules/fullcalendar/locales-all.min.js',
    // ], 'public/assets/plugins/custom/fullcalendar/fullcalendar.bundle.js');
    // mix.styles([
    //     'node_modules/fullcalendar/main.min.css',
    // ], 'public/assets/plugins/custom/fullcalendar/fullcalendar.bundle.css');
    
    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.

Explore Metronic

Metronic Licenses

License FAQs
Regular License
For single end product used by you or one client
$ 39
Extended License
For single end product with paying users.
$ 939
Custom License
Reach us for custom license offers.
Buy Now

Metronic Demos

demo
Coming soon
demo
Coming soon
demo
Coming soon
demo
Coming soon
demo
Coming soon
demo
Coming soon
demo
Coming soon
demo
Coming soon
demo
Coming soon