Browse Source

dev Setup for AdminLTE v4

Daniel 4 years ago
parent
commit
bb8be82e5b

+ 6 - 5
.browserslistrc

@@ -1,10 +1,11 @@
 # https://github.com/browserslist/browserslist#readme
 
->= 0.2%
+>= 0.5%
 last 2 major versions
 not dead
+Chrome >= 60
+Firefox >= 60
 Firefox ESR
-Edge >= 16
-Explorer >= 10
-iOS >= 9
-Safari >= 9
+iOS >= 12
+Safari >= 12
+not Explorer <= 11

+ 12 - 0
.bundlewatch.config.json

@@ -0,0 +1,12 @@
+{
+  "files": [
+    {
+      "path": "./dist/css/adminlte.css",
+      "maxSize": "25 kB"
+    },
+    {
+      "path": "./dist/css/adminlte.min.css",
+      "maxSize": "23 kB"
+    }
+  ]
+}

+ 72 - 0
.eslintrc.json

@@ -0,0 +1,72 @@
+{
+  "root": true,
+  "extends": [
+    "plugin:import/errors",
+    "plugin:import/warnings",
+    "plugin:unicorn/recommended",
+    "xo",
+    "xo/browser"
+  ],
+  "rules": {
+    "capitalized-comments": "off",
+    "indent": [
+      "error",
+      2,
+      {
+        "MemberExpression": "off",
+        "SwitchCase": 1
+      }
+    ],
+    "max-params": [
+      "warn",
+      5
+    ],
+    "multiline-ternary": [
+      "error",
+      "always-multiline"
+    ],
+    "new-cap": [
+      "error",
+      {
+        "properties": false
+      }
+    ],
+    "no-eq-null": "off",
+    "no-negated-condition": "off",
+    "no-console": "error",
+    "object-curly-spacing": [
+      "error",
+      "always"
+    ],
+    "prefer-object-spread": "off",
+    "semi": [
+      "error",
+      "never"
+    ],
+    "unicorn/filename-case": "off",
+    "unicorn/no-null": "off",
+    "unicorn/prevent-abbreviations": "off"
+  },
+  "overrides": [
+    {
+      "files": ["*.ts", "*.tsx"],
+      "extends": [
+        "xo-typescript"
+      ],
+      "rules": {
+        "@typescript-eslint/indent": [
+          "error",
+          2,
+          {
+            "MemberExpression": "off",
+            "SwitchCase": 1
+          }
+        ],
+        "@typescript-eslint/semi": [
+          "error",
+          "never"
+        ]
+      }
+    }
+  ]
+}

+ 1 - 0
.stylelintignore

@@ -4,3 +4,4 @@
 **/dist/
 **/docs_html/
 **/plugins/
+**/.cache/

+ 21 - 0
.stylelintrc

@@ -0,0 +1,21 @@
+{
+  "extends": [
+    "stylelint-config-twbs-bootstrap/scss"
+  ],
+  "rules": {
+    "declaration-no-important": null,
+    "function-disallowed-list": [
+      "calc",
+      "lighten",
+      "darken"
+    ],
+    "order/properties-order": null,
+    "selector-max-class": null,
+    "selector-max-combinators": null,
+    "selector-max-compound-selectors": null,
+    "selector-max-id": null,
+    "selector-max-specificity": null,
+    "selector-max-type": null,
+    "selector-no-qualifying-type": null
+  }
+}

+ 15 - 0
build/config/.eslintrc.json

@@ -0,0 +1,15 @@
+{
+  "env": {
+    "browser": false,
+    "node": true
+  },
+  "parserOptions": {
+    "sourceType": "script"
+  },
+  "extends": "../../.eslintrc.json",
+  "rules": {
+    "no-console": "off",
+    "strict": "error",
+    "unicorn/prefer-module": "off"
+  }
+}

+ 12 - 0
build/config/esbuild.config-min.js

@@ -0,0 +1,12 @@
+'use strict'
+
+const esbuild = require('esbuild')
+
+esbuild.build({
+  entryPoints: ['dist/js/adminlte.js'],
+  bundle: false,
+  minify: true,
+  sourcemap: true,
+  outfile: 'dist/js/adminlte.min.js'
+}).catch(error => console.error(error))
+

+ 24 - 0
build/config/esbuild.config.js

@@ -0,0 +1,24 @@
+'use strict'
+
+const esbuild = require('esbuild')
+const { getTarget } = require('./getTarget')
+
+const pkg = require('../../package')
+const year = new Date().getFullYear()
+const banner = `/*!
+ * AdminLTE v${pkg.version} (${pkg.homepage})
+ * Copyright 2014-${year} ${pkg.author}
+ * Licensed under MIT (https://github.com/ColorlibHQ/AdminLTE/blob/master/LICENSE)
+ */`
+
+esbuild.build({
+  entryPoints: ['build/ts/adminlte.ts'],
+  bundle: true,
+  minify: false,
+  sourcemap: true,
+  banner: {
+    js: banner
+  },
+  target: getTarget(['es', 'chrome', 'edge', 'firefox', 'ios', 'safari']),
+  outfile: 'dist/js/adminlte.js'
+}).catch(error => console.error(error))

+ 39 - 0
build/config/getTarget.js

@@ -0,0 +1,39 @@
+'use strict'
+
+const browserslist = require('browserslist')
+
+function getBuildTargets(targ) {
+  const SUPPORTED_BUILD_TARGETS = targ !== 'default' ?
+    targ :
+    [
+      'es',
+      'chrome',
+      'edge',
+      'firefox',
+      'ios',
+      'node',
+      'safari'
+    ]
+
+  const getEveryTar = browserslist().reverse()
+  const sep = ' '
+  const targets = []
+  let singleTar = ''
+  let i = 0
+
+  for (const tar of getEveryTar) {
+    for (const selTar of SUPPORTED_BUILD_TARGETS) {
+      if (tar.startsWith(selTar + sep) && !singleTar.startsWith(selTar)) {
+        i++
+        singleTar = tar.replace(sep, '')
+        targets[i] = singleTar
+      }
+    }
+  }
+
+  return targets.filter(Boolean)
+}
+
+module.exports.getTarget = targ => {
+  return getBuildTargets(targ)
+}

+ 14 - 0
build/config/postcss.config.js

@@ -0,0 +1,14 @@
+'use strict'
+
+module.exports = {
+  map: {
+    inline: false,
+    annotation: true,
+    sourcesContent: true
+  },
+  plugins: [
+    require('autoprefixer')({
+      cascade: false
+    })
+  ]
+}

+ 87 - 0
build/scss/_bootstrap-variables-alt.scss

@@ -0,0 +1,87 @@
+//
+// Color system (PCS - prefers-color-scheme)
+//
+
+$white-alt:    $white !default;
+$gray-100-alt: $gray-100 !default;
+$gray-200-alt: $gray-200 !default;
+$gray-300-alt: $gray-300 !default;
+$gray-400-alt: $gray-400 !default;
+$gray-500-alt: $gray-500 !default;
+$gray-600-alt: $gray-600 !default;
+$gray-700-alt: $gray-700 !default;
+$gray-800-alt: $gray-800 !default;
+$gray-900-alt: $gray-900 !default;
+$black-alt:    $black !default;
+
+// stylelint-disable
+$grays-alt: () !default;
+$grays-alt: map-merge((
+  "100": $gray-100-alt,
+  "200": $gray-200-alt,
+  "300": $gray-300-alt,
+  "400": $gray-400-alt,
+  "500": $gray-500-alt,
+  "600": $gray-600-alt,
+  "700": $gray-700-alt,
+  "800": $gray-800-alt,
+  "900": $gray-900-alt
+), $grays-alt);
+// stylelint-enable
+
+$blue-alt:    #0d6efd !default;
+$indigo-alt:  #6610f2 !default;
+$purple-alt:  #6f42c1 !default;
+$pink-alt:    #d63384 !default;
+$red-alt:     #dc3545 !default;
+$orange-alt:  #fd7e14 !default;
+$yellow-alt:  #ffc107 !default;
+$green-alt:   #198754 !default;
+$teal-alt:    #20c997 !default;
+$cyan-alt:    #0dcaf0 !default;
+
+// stylelint-disable
+$colors-alt: () !default;
+$colors-alt: map-merge((
+  "blue":       $blue-alt,
+  "indigo":     $indigo-alt,
+  "purple":     $purple-alt,
+  "pink":       $pink-alt,
+  "red":        $red-alt,
+  "orange":     $orange-alt,
+  "yellow":     $yellow-alt,
+  "green":      $green-alt,
+  "teal":       $teal-alt,
+  "cyan":       $cyan-alt,
+  "white":      $white-alt,
+  "gray":       $gray-600-alt,
+  "gray-dark":  $gray-800-alt
+), $colors-alt);
+// stylelint-enable
+
+// Color scheme
+
+$primary-alt:       $blue-alt !default;
+$secondary-alt:     $gray-600-alt !default;
+$success-alt:       $green-alt !default;
+$info-alt:          $cyan-alt !default;
+$warning-alt:       $yellow-alt !default;
+$danger-alt:        $red-alt !default;
+$light-alt:         $gray-100-alt !default;
+$dark-alt:          $gray-800-alt !default;
+
+// stylelint-disable
+$theme-colors-alt: () !default;
+$theme-colors-alt: map-merge((
+  "primary":    $primary-alt,
+  "secondary":  $secondary-alt,
+  "success":    $success-alt,
+  "info":       $info-alt,
+  "warning":    $warning-alt,
+  "danger":     $danger-alt,
+  "light":      $light-alt,
+  "dark":       $dark-alt
+), $theme-colors-alt);
+// stylelint-enable
+
+//

+ 136 - 0
build/scss/_bootstrap-variables.scss

@@ -0,0 +1,136 @@
+// Variables
+//
+// Variables should follow the `$component-state-property-size` formula for
+// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs.
+
+//
+// Color system
+//
+
+$white:    #fff !default;
+$gray-100: #f8f9fa !default;
+$gray-200: #e9ecef !default;
+$gray-300: #dee2e6 !default;
+$gray-400: #ced4da !default;
+$gray-500: #adb5bd !default;
+$gray-600: #6c757d !default;
+$gray-700: #495057 !default;
+$gray-800: #343a40 !default;
+$gray-900: #212529 !default;
+$black:    #000 !default;
+
+// stylelint-disable
+$grays: () !default;
+$grays: map-merge((
+  "100": $gray-100,
+  "200": $gray-200,
+  "300": $gray-300,
+  "400": $gray-400,
+  "500": $gray-500,
+  "600": $gray-600,
+  "700": $gray-700,
+  "800": $gray-800,
+  "900": $gray-900
+), $grays);
+// stylelint-enable
+
+$blue:    #0d6efd !default;
+$indigo:  #6610f2 !default;
+$purple:  #6f42c1 !default;
+$pink:    #d63384 !default;
+$red:     #dc3545 !default;
+$orange:  #fd7e14 !default;
+$yellow:  #ffc107 !default;
+$green:   #198754 !default;
+$teal:    #20c997 !default;
+$cyan:    #0dcaf0 !default;
+
+// stylelint-disable
+$colors: () !default;
+$colors: map-merge((
+  "blue":       $blue,
+  "indigo":     $indigo,
+  "purple":     $purple,
+  "pink":       $pink,
+  "red":        $red,
+  "orange":     $orange,
+  "yellow":     $yellow,
+  "green":      $green,
+  "teal":       $teal,
+  "cyan":       $cyan,
+  "white":      $white,
+  "gray":       $gray-600,
+  "gray-dark":  $gray-800
+), $colors);
+// stylelint-enable
+
+// Color scheme
+
+$primary:       $blue !default;
+$secondary:     $gray-600 !default;
+$success:       $green !default;
+$info:          $cyan !default;
+$warning:       $yellow !default;
+$danger:        $red !default;
+$light:         $gray-100 !default;
+$dark:          $gray-800 !default;
+
+// stylelint-disable
+$theme-colors: () !default;
+$theme-colors: map-merge((
+  "primary":    $primary,
+  "secondary":  $secondary,
+  "success":    $success,
+  "info":       $info,
+  "warning":    $warning,
+  "danger":     $danger,
+  "light":      $light,
+  "dark":       $dark
+), $theme-colors);
+// stylelint-enable
+
+// Options
+//
+// Quickly modify global styling by enabling or disabling optional features.
+
+$enable-caret:                true !default;
+$enable-rounded:              true !default;
+$enable-shadows:              true !default;
+$enable-gradients:            false !default;
+$enable-transitions:          true !default;
+$enable-reduced-motion:       true !default;
+$enable-smooth-scroll:        true !default;
+$enable-grid-classes:         true !default;
+$enable-button-pointers:      true !default;
+$enable-rfs:                  true !default;
+$enable-validation-icons:     true !default;
+$enable-negative-margins:     false !default;
+$enable-deprecation-messages: true !default;
+$enable-important-utilities:  true !default;
+
+// Prefix for :root CSS variables
+
+$variable-prefix:             bs- !default;
+
+// Body
+//
+// Settings for the `<body>` element.
+
+$body-bg:                     $white !default;
+$body-color:                  $gray-900 !default;
+$body-text-align:             null !default;
+
+// Links
+//
+// Style anchor elements.
+
+$link-color:                              $primary !default;
+$link-decoration:                         none !default;
+$link-shade-percentage:                   20% !default;
+$link-hover-color:                        shift-color($link-color, $link-shade-percentage) !default;
+$link-hover-decoration:                   null !default;
+
+$stretched-link-pseudo-element:           after !default;
+$stretched-link-z-index:                  1 !default;
+
+//

+ 41 - 0
build/scss/_brand.scss

@@ -0,0 +1,41 @@
+//
+// Core: Brand
+//
+
+// .brand-container {
+// display: inline-block;
+// }
+
+.brand-container {
+  display: flex;
+  font-size: $navbar-brand-font-size;
+  padding: $brand-link-padding-y $sidebar-padding-x;
+  white-space: nowrap;
+  border-bottom: $brand-link-border-buttom solid tint-color($dark, 10%);
+
+  &:hover {
+    color: $white;
+    text-decoration: none;
+  }
+
+  // TODO: crete utility for opacity for image
+  .brand-image {
+    float: left;
+    line-height: .8;
+    margin-left: .8rem;
+    margin-right: .5rem;
+    margin-top: -3px;
+    max-height: 33px;
+    width: auto;
+  }
+
+  .brand-text {
+    color: $sidebar-dark-color;
+  }
+
+  .sidebar-mini-icon {
+    color: $gray-400;
+    margin-left: auto;
+    order: 2;
+  }
+}

+ 88 - 0
build/scss/_layout.scss

@@ -0,0 +1,88 @@
+//
+// Core: Layout
+//
+
+.wrapper {
+  align-items: stretch;
+  display: flex;
+  width: 100%;
+  overflow: clip;
+
+  .sidebar-rtl {
+    flex-direction: row-reverse;
+  }
+
+  .layout-fixed & .sidebar {
+    // stylelint-disable-next-line
+    height: calc(100vh - (#{$main-header-height-inner} + #{$main-header-bottom-border-width}));
+  }
+  .layout-fixed.text-sm & .sidebar {
+    // stylelint-disable-next-line
+    height: calc(100vh - (#{$main-header-height-sm-inner} + #{$main-header-bottom-border-width}));
+  }
+}
+
+.content-wrapper {
+  display: flex;
+  width: 100%;
+  min-width: 0;
+  min-height: 100vh;
+  background-color: $main-bg;
+  color: $main-color;
+  flex-direction: column;
+  overflow: hidden;
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+  z-index: $zindex-content-wrapper;
+  @include transition($sidebar-transition);
+}
+
+.content {
+  flex: 1;
+  width: 100vw;
+  max-width: 100vw;
+  padding: 1rem;
+}
+
+.sidebar-close .main-sidebar {
+  margin-left: -250px;
+}
+
+.layout-fixed {
+  .main-sidebar {
+    bottom: 0;
+    float: none;
+    left: 0;
+    position: fixed;
+    top: 0;
+  }
+
+  .sidebar-close {
+    .content-wrapper {
+      margin-left: 0;
+    }
+  }
+}
+
+@include media-breakpoint-up(sm) {
+  body:not(.sidebar-close).layout-fixed {
+    .content-wrapper {
+      margin-left: $sidebar-width;
+    }
+    &.sidebar-collapse .content-wrapper {
+      margin-left: $sidebar-mini-width;
+    }
+  }
+}
+
+// @debug $sidebar-fixed;
+// @debug $sidebar-fixed;
+
+@include dark-mode() {
+  .content-wrapper {
+    background-color: $main-bg-alt;
+    color: $main-color-alt;
+  }
+}
+
+//

+ 24 - 0
build/scss/_main-footer.scss

@@ -0,0 +1,24 @@
+//
+// Core: Main Footer
+//
+
+.main-footer {
+  background-color: $main-footer-bg;
+  border-top: $main-footer-border-top;
+  color: $main-footer-color;
+  padding: $main-footer-padding;
+
+  .text-sm &,
+  &.text-sm {
+    padding: $main-footer-padding-sm;
+  }
+}
+
+@include dark-mode() {
+  .main-footer {
+    background-color: $main-footer-bg-alt;
+    border-top-color: tint-color($dark, 10%);
+  }
+}
+
+//

+ 31 - 0
build/scss/_main-header.scss

@@ -0,0 +1,31 @@
+//
+// Core: Main Header
+//
+
+.main-header {
+  background-color: $white;
+  border-bottom: $main-header-bottom-border;
+  z-index: $zindex-main-header;
+
+  .nav-link {
+    color: $dark;
+  }
+}
+
+@include dark-mode() {
+  .main-header {
+    background-color: $dark-alt;
+    border-bottom-color: tint-color($dark-alt, 10%);
+
+    .nav-link {
+      color: $gray-400-alt;
+
+      &:hover,
+      &:focus {
+        color: $white-alt;
+      }
+    }
+  }
+}
+
+//

+ 86 - 0
build/scss/_main-sidebar.scss

@@ -0,0 +1,86 @@
+//
+// Core: Main Sidebar
+//
+
+// Default Sidebar Theme
+@include sidebar-theme($sidebar-dark-bg, $sidebar-dark-color);
+
+.main-sidebar {
+  @include transition($sidebar-transition);
+  z-index: $zindex-sidebar;
+  min-width: $sidebar-width;
+  max-width: $sidebar-width;
+}
+
+@include media-breakpoint-down(sm) {
+  :not(.layout-fixed).main-sidebar {
+    margin-left: -#{$sidebar-width};
+
+    .sidebar-open & {
+      transform: translateX($sidebar-width);
+
+      .sidebar-mini-icon {
+        display: none;
+        transition: display $transition-speed;
+      }
+    }
+  }
+}
+
+.sidebar {
+  height: 100%;
+  overflow-x: hidden;
+  overflow-y: auto;
+  padding-bottom: $sidebar-padding-y;
+  padding-left: $sidebar-padding-x;
+  padding-right: $sidebar-padding-x;
+  padding-top: $sidebar-padding-y;
+  @include scrollbar-color-gray();
+  @include scrollbar-width-none();
+
+  &:hover {
+    @include scrollbar-width-thin();
+  }
+}
+
+// Sidebar navigation menu
+.nav-sidebar {
+  // All levels
+  .nav-link > .right,
+  .nav-link > span > .right {
+    position: absolute;
+    right: 1rem;
+    top: .7rem;
+  }
+
+  .nav-link {
+    position: relative;
+
+    span {
+      display: inline-block;
+      padding-left: .5rem;
+    }
+
+    .nav-icon {
+      padding-left: .3rem;
+    }
+  }
+
+  .nav-header {
+    font-size: .9rem;
+    padding: $nav-link-padding-y ($nav-link-padding-y * 1.5);
+  }
+
+  // Tree view menu
+  .nav-treeview {
+    display: none;
+    list-style: none;
+    padding: 0;
+  }
+
+  .menu-open > .nav-treeview {
+    display: block;
+  }
+}
+
+//

+ 11 - 0
build/scss/_mixins.scss

@@ -0,0 +1,11 @@
+//
+// General: Mixins
+//
+
+@import "mixins/animations";
+@import "mixins/dark-mode";
+@import "mixins/scrollbar";
+@import "mixins/sidebar-theme";
+@import "mixins/miscellaneous";
+
+//

+ 128 - 0
build/scss/_sidebar-mini.scss

@@ -0,0 +1,128 @@
+//
+// Core: Sidebar Mini
+//
+
+.sidebar-mini.sidebar-collapse {
+  .main-sidebar {
+    min-width: $sidebar-mini-width;
+    max-width: $sidebar-mini-width;
+  }
+
+  // Make the sidebar headers
+  .nav-sidebar .nav-header {
+    display: none;
+  }
+
+  .nav-sidebar .nav-link span {
+    width: 0;
+    white-space: nowrap;
+  }
+
+  .sidebar .user-panel > .info,
+  .nav-sidebar .nav-link span,
+  .brand-link {
+    margin-left: -10px;
+    animation-name: fadeOut;
+    animation-duration: $transition-speed;
+    animation-fill-mode: both;
+    visibility: hidden;
+  }
+
+  .brand-link {
+    order: 2;
+    margin-left: auto;
+  }
+
+  .sidebar-mini-icon {
+    order: 1;
+    margin-left: 1rem;
+  }
+
+  &.layout-fixed.sidebar-hover {
+    .main-sidebar {
+      min-width: $sidebar-width;
+      max-width: $sidebar-width;
+    }
+
+    .nav-sidebar .nav-header {
+      display: block;
+    }
+
+    .sidebar .user-panel > .info,
+    .nav-sidebar .nav-link span,
+    .brand-link {
+      margin-left: 0;
+      animation-name: fadeIn;
+      animation-duration: $transition-speed;
+      animation-fill-mode: both;
+      visibility: visible;
+    }
+
+    .brand-link {
+      order: 1;
+    }
+
+    .sidebar-mini-icon {
+      order: 2;
+      margin-left: auto;
+    }
+  }
+}
+
+.sidebar-mini.sidebar-collapse:not(.layout-fixed) {
+  .sidebar {
+    overflow: visible;
+
+    .nav-sidebar .nav-item:hover {
+      position: relative;
+
+      .nav-link {
+        border-top-right-radius: 0;
+        border-bottom-right-radius: 0;
+      }
+
+      span {
+        animation: none;
+        z-index: $zindex-sidebar + 12;
+        visibility: visible;
+        display: inline-block;
+        position: absolute;
+        width: $sidebar-width;
+        left: $sidebar-mini-width;
+        top: 0;
+        background-color: inherit;
+        padding: inherit;
+        padding-left: 1rem;
+        margin-left: -1rem;
+        border-top-left-radius: 0;
+        border-bottom-left-radius: 0;
+      }
+    }
+  }
+}
+
+.sidebar-is-opening {
+  .sidebar .user-panel > .info,
+  .nav-sidebar .nav-link span,
+  .brand-link {
+    margin-left: 0;
+    animation-name: fadeIn;
+    animation-duration: $transition-speed;
+    animation-fill-mode: both;
+    visibility: visible;
+  }
+}
+
+.sidebar-is-collapsing {
+  .sidebar .user-panel > .info,
+  .nav-sidebar .nav-link span,
+  .brand-link {
+    margin-left: -10px;
+    animation-name: fadeOut;
+    animation-duration: $transition-speed;
+    animation-fill-mode: both;
+    visibility: visible;
+  }
+}
+
+//

+ 22 - 0
build/scss/_utilities.scss

@@ -0,0 +1,22 @@
+// Utilities
+
+// util-opacity
+$utilities: (
+  "opacity": (
+    property: opacity,
+    values: (
+      0: 0,
+      20: .2,
+      30: .3,
+      40: .4,
+      50: .5,
+      60: .6,
+      70: .7,
+      80: .8,
+      90: .9,
+      100: 1,
+    )
+  )
+);
+
+//

+ 9 - 0
build/scss/_variables-alt.scss

@@ -0,0 +1,9 @@
+// MAIN FOOTER
+// --------------------------------------------------------
+$main-footer-bg-alt:                $dark !default;
+
+// Body background (Affects main content background only)
+$main-bg-alt:                  tint-color($dark-alt, 7.5%) !default;
+$main-color-alt:               $white !default;
+
+//

+ 119 - 0
build/scss/_variables.scss

@@ -0,0 +1,119 @@
+// Variables for AdminLTE
+
+// LAYOUT
+// --------------------------------------------------------
+
+$font-size-root:              1rem !default;
+
+// TRANSITIONS SETTINGS
+// --------------------------------------------------------
+
+// Transition global options
+$transition-speed: .3s !default;
+$transition-fn: ease-in-out !default;
+
+// Sidebar
+// --------------------------------------------------------
+$sidebar-width:               250px !default;
+$sidebar-padding-x:           .5rem !default;
+$sidebar-padding-y:           0 !default;
+$sidebar-custom-height:       4rem !default;
+$sidebar-custom-height-lg:    6rem !default;
+$sidebar-custom-height-xl:    8rem !default;
+$sidebar-custom-padding-x:    .85rem !default;
+$sidebar-custom-padding-y:    .5rem !default;
+$sidebar-transition:          min-width $transition-speed $transition-fn,
+  max-width $transition-speed $transition-fn,
+  margin-left $transition-speed $transition-fn,
+  margin-right $transition-speed $transition-fn,
+  transform $transition-speed $transition-fn;
+
+// SIDEBAR SKINS
+// --------------------------------------------------------
+
+// Dark sidebar
+$sidebar-dark-bg:                     $dark !default;
+$sidebar-dark-hover-bg:             rgba(255, 255, 255, .1) !default;
+$sidebar-dark-color:                #c2c7d0 !default;
+$sidebar-dark-hover-color:            $white !default;
+$sidebar-dark-active-color:           $white !default;
+$sidebar-dark-submenu-bg:             transparent !default;
+$sidebar-dark-submenu-color:        #c2c7d0 !default;
+$sidebar-dark-submenu-hover-color:    $white !default;
+$sidebar-dark-submenu-hover-bg:       $sidebar-dark-hover-bg !default;
+$sidebar-dark-submenu-active-color:   $sidebar-dark-bg !default;
+$sidebar-dark-submenu-active-bg:    rgba(255, 255, 255, .9) !default;
+
+// Light sidebar
+$sidebar-light-bg:                    $white !default;
+$sidebar-light-hover-bg:              rgba($black, .1) !default;
+$sidebar-light-color:                 $gray-800 !default;
+$sidebar-light-hover-color:           $gray-900 !default;
+$sidebar-light-active-color:          $black !default;
+$sidebar-light-submenu-bg:            transparent !default;
+$sidebar-light-submenu-color:        #777 !default;
+$sidebar-light-submenu-hover-color:    $black !default;
+$sidebar-light-submenu-hover-bg:       $sidebar-light-hover-bg !default;
+$sidebar-light-submenu-active-color:   $sidebar-light-hover-color !default;
+$sidebar-light-submenu-active-bg:      $sidebar-light-submenu-hover-bg !default;
+
+// SIDEBAR MINI
+// --------------------------------------------------------
+$sidebar-mini-width:          ($nav-link-padding-x + $sidebar-padding-x + .8rem) * 2 !default;
+$sidebar-nav-icon-width:      $sidebar-mini-width - (($sidebar-padding-x + $nav-link-padding-x) * 2) !default;
+$sidebar-user-image-width:    $sidebar-nav-icon-width + ($nav-link-padding-x / 2) !default;
+
+// CONTROL SIDEBAR
+// --------------------------------------------------------
+$control-sidebar-width:       $sidebar-width !default;
+
+// MAIN HEADER
+// --------------------------------------------------------
+$main-header-bottom-border-width:  $border-width !default;
+$main-header-bottom-border-color:  $gray-300 !default;
+$main-header-bottom-border:        $main-header-bottom-border-width solid $main-header-bottom-border-color !default;
+$main-header-link-padding-y:       $navbar-padding-y !default;
+$main-header-height-inner:         ($nav-link-height + ($main-header-link-padding-y * 2)) !default;
+$main-header-height:               add($main-header-height-inner, $main-header-bottom-border-width) !default;
+$nav-link-sm-padding-y:            .35rem !default;
+$nav-link-sm-height:               ($font-size-sm * $line-height-sm + $nav-link-sm-padding-y * 1.785) !default;
+$main-header-height-sm-inner:      ($nav-link-sm-height + ($main-header-link-padding-y * 2)) !default;
+$main-header-height-sm:            add($main-header-height-sm-inner, $main-header-bottom-border-width) !default;
+
+// MAIN FOOTER
+// --------------------------------------------------------
+$main-footer-padding:           1rem !default;
+$main-footer-padding-sm:        $main-footer-padding * .812 !default;
+$main-footer-border-top-width:  1px !default;
+$main-footer-border-top-color:  $gray-300 !default;
+$main-footer-border-top:        $main-footer-border-top-width solid $main-footer-border-top-color !default;
+$main-footer-height-inner:      (($font-size-root * $line-height-base) + ($main-footer-padding * 2)) !default;
+$main-footer-height:            add($main-footer-height-inner, $main-footer-border-top-width) !default;
+$main-footer-height-sm-inner:   (($font-size-sm * $line-height-base) + ($main-footer-padding-sm * 2)) !default;
+$main-footer-height-sm:         add($main-footer-height-sm-inner, $main-footer-border-top-width) !default;
+$main-footer-bg:                $white !default;
+$main-footer-color:             tint-color($gray-700, 25%) !default;
+
+// BRAND LINK
+// --------------------------------------------------------
+$brand-link-padding-y:     $navbar-brand-padding-y + $navbar-padding-y;
+$brand-link-border-buttom: 1px;
+
+// Z-INDEX
+// --------------------------------------------------------
+$zindex-main-header:      $zindex-fixed + 4 !default;
+$zindex-sidebar:          $zindex-fixed + 8 !default;
+$zindex-main-footer:      $zindex-fixed + 2 !default;
+$zindex-control-sidebar:  $zindex-fixed + 1 !default;
+$zindex-toasts:           $zindex-sidebar + 2 !default;
+$zindex-content-wrapper:  $zindex-sidebar - 2 !default;
+$zindex-preloader:        $zindex-toasts + 2 !default;
+
+// Body background (Affects main content background only)
+$main-bg:               #f4f6f9 !default;
+$main-color:              $black !default;
+
+// Dark mode
+$enable-dark-mode:        true !default;
+
+//

+ 24 - 0
build/scss/adminlte.scss

@@ -0,0 +1,24 @@
+/*!
+ *   AdminLTE v4.0.0-alpha.1
+ *   Author: Colorlib
+ *   Website: AdminLTE.io <https://adminlte.io>
+ *   License: Open source - MIT <https://opensource.org/licenses/MIT>
+ */
+
+// Bootstrap
+// ---------------------------------------------------
+@import "bootstrap/scss/functions";
+@import "bootstrap-variables";
+@import "utilities";
+@import "bootstrap/scss/bootstrap";
+
+// Variables and Mixins
+// ---------------------------------------------------
+@import "bootstrap-variables-alt";
+@import "variables";
+@import "variables-alt";
+@import "mixins";
+
+@import "parts/core";
+
+//

+ 119 - 0
build/scss/mixins/_animations.scss

@@ -0,0 +1,119 @@
+//
+// Mixins: Animation
+//
+
+
+@keyframes flipInX {
+  0% {
+    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    transition-timing-function: ease-in;
+    opacity: 0;
+  }
+
+  40% {
+    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    transition-timing-function: ease-in;
+  }
+
+  60% {
+    transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+    opacity: 1;
+  }
+
+  80% {
+    transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+  }
+
+  100% {
+    transform: perspective(400px);
+  }
+}
+
+
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+
+  to {
+    opacity: 1;
+  }
+}
+
+@keyframes fadeOut {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+  }
+}
+
+@keyframes shake {
+  0% {
+    transform: translate(2px, 1px) rotate(0deg);
+  }
+  10% {
+    transform: translate(-1px, -2px) rotate(-2deg);
+  }
+  20% {
+    transform: translate(-3px, 0) rotate(3deg);
+  }
+  30% {
+    transform: translate(0, 2px) rotate(0deg);
+  }
+  40% {
+    transform: translate(1px, -1px) rotate(1deg);
+  }
+  50% {
+    transform: translate(-1px, 2px) rotate(-1deg);
+  }
+  60% {
+    transform: translate(-3px, 1px) rotate(0deg);
+  }
+  70% {
+    transform: translate(2px, 1px) rotate(-2deg);
+  }
+  80% {
+    transform: translate(-1px, -1px) rotate(4deg);
+  }
+  90% {
+    transform: translate(2px, 2px) rotate(0deg);
+  }
+  100% {
+    transform: translate(1px, -2px) rotate(-1deg);
+  }
+}
+
+@keyframes wobble {
+  0% {
+    transform: none;
+  }
+
+  15% {
+    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+  }
+
+  30% {
+    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+  }
+
+  45% {
+    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+  }
+
+  60% {
+    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+  }
+
+  75% {
+    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+  }
+
+  100% {
+    transform: none;
+  }
+}
+
+//

+ 7 - 0
build/scss/mixins/_dark-mode.scss

@@ -0,0 +1,7 @@
+@mixin dark-mode {
+  @if $enable-dark-mode {
+    @media (prefers-color-scheme: dark) {
+      @content;
+    }
+  }
+}

+ 33 - 0
build/scss/mixins/_miscellaneous.scss

@@ -0,0 +1,33 @@
+//
+// Mixins: Miscellaneous
+//
+
+// ETC
+// @mixin translate($x, $y) {
+//   transform: translate($x, $y);
+// }
+
+// Different radius each side
+// @mixin border-radius-sides($top-left, $top-right, $bottom-left, $bottom-right) {
+//   border-radius: $top-left $top-right $bottom-left $bottom-right;
+// }
+
+// @mixin calc($property, $expression) {
+//   #{$property}: calc(#{$expression});
+// }
+
+@mixin rotate($value) {
+  transform: rotate($value);
+}
+
+// @mixin animation($animation) {
+//   animation: $animation;
+// }
+
+// Gradient background
+// @mixin gradient($color: #f5f5f5, $start: #eee, $stop: $white) {
+//   background-color: $color;
+//   background-image: gradient(linear, left bottom, left top, color-stop(0, $start), color-stop(1, $stop));
+// }
+
+//

+ 38 - 0
build/scss/mixins/_scrollbar.scss

@@ -0,0 +1,38 @@
+//
+// Mixins: Scrollbar
+//
+
+@mixin scrollbar-color-gray() {
+  scrollbar-color: #a9a9a9 transparent;
+
+  &::-webkit-scrollbar-thumb {
+    background-color: #a9a9a9;
+  }
+
+  &::-webkit-scrollbar-track {
+    background-color: transparent;
+  }
+
+  &::-webkit-scrollbar-corner {
+    background-color: transparent;
+  }
+}
+
+@mixin scrollbar-width-thin() {
+  scrollbar-width: thin;
+
+  &::-webkit-scrollbar {
+    width: .5rem;
+    height: .5rem;
+  }
+}
+
+@mixin scrollbar-width-none() {
+  scrollbar-width: none;
+
+  &::-webkit-scrollbar {
+    width: 0;
+  }
+}
+
+//

+ 45 - 0
build/scss/mixins/_sidebar-theme.scss

@@ -0,0 +1,45 @@
+//
+// Mixins: Sidebar Theme
+//
+
+@mixin sidebar-theme(
+  $sidebar-bg,
+  $sidebar-color
+) {
+
+  .wrapper {
+    background: $sidebar-bg;
+  }
+
+  .main-sidebar {
+    color: $sidebar-color;
+    background-color: $sidebar-bg;
+  }
+
+  // Sidebar navigation menu
+  .nav-sidebar {
+    // All levels
+    .nav-link {
+      color: $sidebar-color;
+
+      &:hover,
+      .active {
+        color: color-constract($sidebar-dark-color);
+      }
+    }
+  }
+
+  .sidebar-collapse:not(.layout-fixed) {
+    .sidebar {
+      .nav-sidebar .nav-item:hover {
+        .nav-link:not(.active) {
+          span {
+            background-color: $sidebar-bg;
+          }
+        }
+      }
+    }
+  }
+}
+
+//

+ 12 - 0
build/scss/parts/_core.scss

@@ -0,0 +1,12 @@
+//
+// Part: Core
+//
+
+@import "../layout";
+@import "../main-header";
+@import "../main-footer";
+@import "../main-sidebar";
+@import "../sidebar-mini";
+@import "../brand";
+
+//

+ 9 - 0
build/ts/AdminLTE.ts

@@ -0,0 +1,9 @@
+import PushMenu from './push-menu'
+import Treeview from './treeview'
+
+export {
+  PushMenu,
+  Treeview
+}
+
+//

+ 62 - 0
build/ts/Treeview.ts

@@ -0,0 +1,62 @@
+/**
+ * --------------------------------------------
+ * AdminLTE treeview.ts
+ * License MIT
+ * --------------------------------------------
+ */
+
+import {
+  windowReady
+} from './util/index'
+
+/**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+const CLASS_NAME_MENU_OPEN = 'menu-open'
+
+const SELECTOR_NAV_ITEM = '.nav-item'
+const SELECTOR_DATA_TOGGLE = '[data-widget="treeview"]'
+
+/**
+ * Class Definition
+ * ====================================================
+ */
+
+class Treeview {
+  toggle(treeviewMenu: Element): void {
+    const navItem = treeviewMenu.closest(SELECTOR_NAV_ITEM)
+    if (navItem?.classList.contains(CLASS_NAME_MENU_OPEN)) {
+      navItem.classList.remove(CLASS_NAME_MENU_OPEN)
+    } else {
+      navItem?.classList.add(CLASS_NAME_MENU_OPEN)
+    }
+  }
+}
+
+/**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+const button = document.querySelectorAll(SELECTOR_DATA_TOGGLE)
+
+windowReady(() => {
+  for (const btn of button) {
+    btn.addEventListener('click', event => {
+      event.preventDefault()
+
+      const treeviewMenu = event.target as Element
+
+      const data = new Treeview()
+      data.toggle(treeviewMenu)
+    })
+  }
+})
+
+export default Treeview
+
+//

+ 198 - 0
build/ts/push-menu.ts

@@ -0,0 +1,198 @@
+/**
+ * --------------------------------------------
+ * AdminLTE pushmenu.ts
+ * License MIT
+ * --------------------------------------------
+ */
+
+import {
+  windowReady
+} from './util/index'
+
+/**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+const CLASS_NAME_SIDEBAR_MINI = 'sidebar-mini'
+const CLASS_NAME_SIDEBAR_MINI_HAD = 'sidebar-mini-had'
+const CLASS_NAME_SIDEBAR_COLLAPSE = 'sidebar-collapse'
+const CLASS_NAME_SIDEBAR_CLOSE = 'sidebar-close'
+const CLASS_NAME_SIDEBAR_OPEN = 'sidebar-open'
+const CLASS_NAME_SIDEBAR_OPENING = 'sidebar-is-opening'
+const CLASS_NAME_SIDEBAR_COLLAPSING = 'sidebar-is-collapsing'
+const CLASS_NAME_SIDEBAR_SM = 'sidebar-sm'
+const CLASS_NAME_SIDEBAR_HOVER = 'sidebar-hover'
+
+const SELECTOR_SIDEBAR = '.sidebar'
+// const SELECTOR_MAIN_SIDEBAR = '.main-sidebar'
+// const SELECTOR_CONTENT_WRAPPER = '.content-wrapper'
+const SELECTOR_MINI_TOGGLE = '[data-pushmenu="mini"]'
+const SELECTOR_FULL_TOGGLE = '[data-pushmenu="full"]'
+const SELECTOR_SIDEBAR_SM = `.${CLASS_NAME_SIDEBAR_SM}`
+const SELECTOR_CONTENT = '.content'
+
+/**
+ * Class Definition
+ * ====================================================
+ */
+
+class PushMenu {
+  sidebarOpening(): void {
+    const bodyClass = document.body.classList
+
+    bodyClass.add(CLASS_NAME_SIDEBAR_OPENING)
+    setTimeout(() => {
+      bodyClass.remove(CLASS_NAME_SIDEBAR_OPENING)
+    }, 1000)
+  }
+
+  sidebarColllapsing(): void {
+    const bodyClass = document.body.classList
+
+    bodyClass.add(CLASS_NAME_SIDEBAR_COLLAPSING)
+    setTimeout(() => {
+      bodyClass.remove(CLASS_NAME_SIDEBAR_COLLAPSING)
+    }, 1000)
+  }
+
+  expand(): void {
+    this.sidebarOpening()
+    const bodyClass = document.body.classList
+    bodyClass.remove(CLASS_NAME_SIDEBAR_CLOSE)
+    bodyClass.remove(CLASS_NAME_SIDEBAR_COLLAPSE)
+    bodyClass.add(CLASS_NAME_SIDEBAR_OPEN)
+  }
+
+  collapse(): void {
+    this.sidebarColllapsing()
+    const bodyClass = document.body.classList
+    bodyClass.add(CLASS_NAME_SIDEBAR_COLLAPSE)
+  }
+
+  close(): void {
+    const bodyClass = document.body.classList
+    bodyClass.add(CLASS_NAME_SIDEBAR_CLOSE)
+    // if (bodyClass.contains(CLASS_NAME_SIDEBAR_SM)) {
+    bodyClass.remove(CLASS_NAME_SIDEBAR_OPEN)
+    // }
+  }
+
+  toggleFull(): void {
+    const bodyClass = document.body.classList
+
+    if (bodyClass.contains(CLASS_NAME_SIDEBAR_CLOSE)) {
+      this.expand()
+    } else {
+      this.close()
+    }
+
+    if (bodyClass.contains(CLASS_NAME_SIDEBAR_MINI)) {
+      bodyClass.remove(CLASS_NAME_SIDEBAR_MINI)
+      bodyClass.add(CLASS_NAME_SIDEBAR_MINI_HAD)
+    }
+  }
+
+  toggleMini(): void {
+    const bodyClass = document.body.classList
+
+    if (bodyClass.contains(CLASS_NAME_SIDEBAR_MINI_HAD)) {
+      bodyClass.remove(CLASS_NAME_SIDEBAR_MINI_HAD)
+      bodyClass.add(CLASS_NAME_SIDEBAR_MINI)
+    }
+
+    if (bodyClass.contains(CLASS_NAME_SIDEBAR_COLLAPSE)) {
+      this.expand()
+    } else {
+      this.collapse()
+    }
+  }
+
+  toggle(state: string): void {
+    if (state === 'full') {
+      this.toggleFull()
+    } else if (state === 'mini') {
+      this.toggleMini()
+    }
+  }
+}
+
+/**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
+
+windowReady(() => {
+  function addSidebaBreakPoint() {
+    const widthOutput: number = window.innerWidth
+    const bodyClass = document.body.classList
+    if (widthOutput >= 576) {
+      bodyClass.remove(CLASS_NAME_SIDEBAR_SM)
+    } else {
+      bodyClass.add(CLASS_NAME_SIDEBAR_SM)
+    }
+  }
+
+  addSidebaBreakPoint()
+
+  window.addEventListener('resize', addSidebaBreakPoint)
+
+  const fullBtn = document.querySelectorAll(SELECTOR_FULL_TOGGLE)
+  const miniBtn = document.querySelectorAll(SELECTOR_MINI_TOGGLE)
+
+  for (const btn of fullBtn) {
+    btn.addEventListener('click', () => {
+      const data = new PushMenu()
+      data.toggle('full')
+    })
+  }
+
+  for (const btn of miniBtn) {
+    btn.addEventListener('click', () => {
+      const data = new PushMenu()
+      data.toggle('mini')
+    })
+  }
+
+  const selSidebar = document.querySelector(SELECTOR_SIDEBAR)
+
+  selSidebar?.addEventListener('mouseover', () => {
+    const bodyClass = document.body.classList
+    bodyClass.add(CLASS_NAME_SIDEBAR_HOVER)
+  })
+
+  selSidebar?.addEventListener('mouseout', () => {
+    const bodyClass = document.body.classList
+    bodyClass.remove(CLASS_NAME_SIDEBAR_HOVER)
+  })
+
+  function removeOverlaySidebar() {
+    const bodyClass = document.body.classList
+    if (bodyClass.contains(CLASS_NAME_SIDEBAR_SM)) {
+      bodyClass.remove(CLASS_NAME_SIDEBAR_OPEN)
+      bodyClass.remove(CLASS_NAME_SIDEBAR_COLLAPSE)
+      bodyClass.add(CLASS_NAME_SIDEBAR_CLOSE)
+    }
+  }
+
+  let selSidebarSm = document.querySelector(SELECTOR_SIDEBAR_SM)
+  let selContentWrapper = selSidebarSm?.querySelector(SELECTOR_CONTENT)
+
+  window.addEventListener('resize', () => {
+    selSidebarSm = document.querySelector(SELECTOR_SIDEBAR_SM)
+    selContentWrapper = selSidebarSm?.querySelector(SELECTOR_CONTENT)
+    selContentWrapper?.addEventListener('touchstart', removeOverlaySidebar)
+    selContentWrapper?.addEventListener('click', removeOverlaySidebar)
+  })
+
+  selContentWrapper?.addEventListener('touchstart', removeOverlaySidebar)
+  selContentWrapper?.addEventListener('click', removeOverlaySidebar)
+
+  window.addEventListener('resize', removeOverlaySidebar)
+})
+
+export default PushMenu
+
+//

+ 20 - 0
build/ts/util/index.ts

@@ -0,0 +1,20 @@
+const domReady = (callBack: () => void): void => {
+  if (document.readyState === 'loading') {
+    document.addEventListener('DOMContentLoaded', callBack)
+  } else {
+    callBack()
+  }
+}
+
+const windowReady = (callBack: () => void): void => {
+  if (document.readyState === 'complete') {
+    callBack()
+  } else {
+    window.addEventListener('load', callBack)
+  }
+}
+
+export {
+  domReady,
+  windowReady
+}

BIN
dist/img/AdminLTELogo.png


+ 148 - 0
index.html

@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>AdminLTE v4</title>
+  <link rel="stylesheet" href="dist/css/adminlte.css">
+  <link rel="stylesheet" href="./node_modules/@fortawesome/fontawesome-free/css/all.min.css">
+</head>
+
+<body class="sidebar-mini">
+  <div class="wrapper">
+    <!-- Main Sidebar Container -->
+    <nav class="main-sidebar">
+      <div class="brand-container">
+        <a href="#" class="brand-link">
+          <img src="dist/img/AdminLTELogo.png" alt="AdminLTE Logo" class="brand-image opacity-80">
+          <span class="brand-text fw-light">AdminLTE 4</span>
+        </a>
+        <a class="sidebar-mini-icon" data-pushmenu="mini" href="#" role="button"><i class="fas fa-angle-double-left"></i></a>
+      </div>
+      <!-- Sidebar -->
+      <div class="sidebar">
+        <!-- Sidebar Menu -->
+        <nav class="mt-2">
+          <ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
+            <li class="nav-item">
+              <a href="#" class="nav-link active">
+                <i class="nav-icon fas fa-th"></i>
+                <span>
+                  Simple Link
+                </span>
+              </a>
+            </li>
+            <li class="nav-header">MULTI LEVEL EXAMPLE</li>
+            <li class="nav-item">
+              <a href="#" class="nav-link">
+                <i class="nav-icon fas fa-circle"></i>
+                <span>
+                  Level 1
+                  <i class="right fas fa-angle-left"></i>
+                </span>
+              </a>
+              <ul class="nav nav-treeview">
+                <li class="nav-item">
+                  <a href="#" class="nav-link">
+                    <i class="nav-icon far fa-circle"></i>
+                    <span>
+                      Level 2
+                      <i class="right fas fa-angle-left"></i>
+                    </span>
+                  </a>
+                  <ul class="nav nav-treeview">
+                    <li class="nav-item">
+                      <a href="#" class="nav-link">
+                        <i class="nav-icon far fa-dot-circle"></i>
+                        <span>
+                          Level 3
+                          <i class="right fas fa-angle-left"></i>
+                        </span>
+                      </a>
+                    </li>
+                  </ul>
+                  <a href="#" class="nav-link">
+                    <i class="nav-icon far fa-circle"></i>
+                    <span>
+                      Level 2
+                    </span>
+                  </a>
+                </li>
+              </ul>
+            </li>
+            <li class="nav-item">
+              <a href="#" class="nav-link">
+                <i class="nav-icon fas fa-th"></i>
+                <span>
+                  Simple Link
+                </span>
+              </a>
+            </li>
+          </ul>
+        </nav>
+      </div>
+      <!-- /.sidebar -->
+    </nav>
+
+    <!-- Content Wrapper. Contains page content -->
+    <div class="content-wrapper">
+      <!-- Navbar -->
+      <nav class="main-header navbar navbar-expand">
+        <div class="container-fluid">
+          <ul class="navbar-nav">
+            <li class="nav-item">
+              <a class="nav-link" data-pushmenu="full" href="#" role="button"><i class="fas fa-bars"></i></a>
+            </li>
+            <li class="nav-item">
+              <a href="index3.html" class="nav-link">Home</a>
+            </li>
+            <li class="nav-item">
+              <a href="#" class="nav-link">Contact</a>
+            </li>
+          </ul>
+        </div>
+      </nav>
+      <!-- /.navbar -->
+
+      <!-- Main content -->
+      <main class="content">
+        <div class="container-fluid">
+          <div class="container">
+            <button type="button" class="btn btn-primary">Primary</button>
+            <button type="button" class="btn btn-secondary">Secondary</button>
+            <button type="button" class="btn btn-success">Success</button>
+            <button type="button" class="btn btn-danger">Danger</button>
+            <button type="button" class="btn btn-warning">Warning</button>
+            <button type="button" class="btn btn-info">Info</button>
+            <button type="button" class="btn btn-light">Light</button>
+            <button type="button" class="btn btn-dark">Dark</button>
+            <button type="button" class="btn btn-link">Link</button>
+          </div>
+          <!-- /.row -->
+        </div><!-- /.container-fluid -->
+      </main>
+      <!-- /.content -->
+
+      <!-- Main Footer -->
+      <footer class="main-footer">
+        <!-- To the right -->
+        <div class="float-end d-none d-sm-inline">
+          Anything you want
+        </div>
+        <!-- Default to the left -->
+        <strong>Copyright &copy; 2014-2021 <a href="https://adminlte.io">AdminLTE.io</a>.</strong> All rights reserved.
+      </footer>
+    </div>
+    <!-- /.content-wrapper -->
+  </div>
+  <!-- ./wrapper -->
+
+  <!-- REQUIRED SCRIPTS -->
+
+  <!-- Bootstrap 5 -->
+  <script src="./node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
+  <!-- AdminLTE App -->
+  <script src="dist/js/adminlte.js"></script>
+</body>
+</html>

File diff suppressed because it is too large
+ 676 - 2627
package-lock.json


+ 27 - 103
package.json

@@ -1,46 +1,32 @@
 {
   "name": "admin-lte",
   "description": "Responsive open source admin dashboard and control panel.",
-  "version": "3.1.0",
+  "version": "4.0.0-alpha1",
   "license": "MIT",
   "author": "Colorlib <https://colorlib.com>",
   "main": "dist/js/adminlte.min.js",
   "scripts": {
     "bundlewatch": "bundlewatch --config .bundlewatch.config.json",
     "css": "npm-run-all css-compile css-prefix css-minify",
-    "css-splits": "npm-run-all css-compile-splits css-prefix-splits css-minify-splits",
-    "css-all": "npm-run-all --parallel css css-splits",
-    "css-compile-bash": "node-sass --importer node_modules/node-sass-package-importer/dist/cli.js --output-style expanded --source-map true --source-map-contents true --precision 6 ",
-    "css-compile": "npm run css-compile-bash -- build/scss/adminlte.scss dist/css/adminlte.css",
-    "css-compile-splits": "npm run css-compile-bash -- build/scss/parts -o dist/css/alt/",
+    "css-compile": "sass --load-path=node_modules build/scss:dist/css",
     "css-prefix": "postcss --config build/config/postcss.config.js --replace \"dist/css/*.css\" \"!dist/css/*.min.css\"",
-    "css-prefix-splits": "postcss --config build/config/postcss.config.js --replace \"dist/css/alt/*.css\" \"!dist/css/alt/*.min.css\"",
     "css-minify-bash": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output ",
     "css-minify": "npm run css-minify-bash -- dist/css/ --batch --batch-suffix \".min\" \"dist/css/*.css\" \"!dist/css/*.min.css\"",
-    "css-minify-splits": "npm run css-minify-bash -- dist/css/alt/ --batch --batch-suffix \".min\" \"dist/css/alt/*.css\" \"!dist/css/alt/*.min.css\"",
     "css-lint": "stylelint \"build/scss/**/*.scss\" --cache --cache-location .cache/.stylelintcache",
-    "compile": "npm-run-all --parallel js css-all",
     "dev": "npm-run-all --parallel watch sync",
-    "docs": "npm-run-all docs-prepare docs-compile",
-    "docs-lint": "node build/npm/vnu-jar.js",
-    "docs-compile": "cd docs/ && bundle exec jekyll build -d ../docs_html",
-    "docs-serve": "npm-run-all compile docs-prepare && cd docs/ && bundle exec jekyll serve",
-    "docs-prepare": "node build/npm/DocsPublish.js -v",
     "lockfile-lint": "lockfile-lint --allowed-hosts npm --allowed-schemes https: --empty-hostname false --type npm --path package-lock.json",
-    "postinstall": "npm run plugins",
     "js": "npm-run-all js-compile js-minify",
-    "js-compile": "rollup --config build/config/rollup.config.js --sourcemap",
-    "js-minify": "terser --compress typeofs=false --mangle --comments \"/^!/\" --source-map \"content=dist/js/adminlte.js.map,includeSources,url=adminlte.min.js.map\" --output dist/js/adminlte.min.js dist/js/adminlte.js",
-    "js-lint": "eslint --cache --cache-location .cache/.eslintcache --report-unused-disable-directives .",
+    "js-compile": "npm-run-all --parallel js-compile-esbuild js-type-check",
+    "js-compile-esbuild": "node build/config/esbuild.config.js",
+    "js-type-check": "tsc --noEmit",
+    "js-minify": "node build/config/esbuild.config-min.js",
+    "js-lint": "eslint --ext=js,ts --cache --cache-location .cache/.eslintcache --report-unused-disable-directives .",
     "lint": "npm-run-all --continue-on-error --parallel css-lint js-lint lockfile-lint",
-    "production": "npm-run-all --parallel compile plugins",
-    "prepare-release": "npm-run-all production docs",
-    "test": "npm-run-all lint production",
-    "plugins": "node build/npm/Publish.js -v",
+    "compile": "npm-run-all --parallel css js",
     "sync": "browser-sync start --server --files *.html pages/ dist/",
-    "watch": "concurrently \"npm run watch-css\" \"npm run watch-js\"",
-    "watch-css": "nodemon --watch build/scss -e scss -x \"npm-run-all css-lint css\"",
-    "watch-js": "nodemon --watch build/js -e js -x \"npm-run-all js-lint js\""
+    "watch": "concurrently \"npm:watch-*\"",
+    "watch-css": "nodemon --watch build/scss -e scss -x \"npm-run-all css-compile css-prefix\"",
+    "watch-js": "nodemon --watch build/ts -e ts -x \"npm-run-all js-compile\""
   },
   "keywords": [
     "css",
@@ -65,93 +51,31 @@
   },
   "dependencies": {
     "@fortawesome/fontawesome-free": "^5.15.3",
-    "@lgaitan/pace-progress": "^1.0.7",
-    "@sweetalert2/theme-bootstrap-4": "^4.0.3",
-    "@ttskch/select2-bootstrap4-theme": "^1.5.2",
-    "bootstrap": "^4.6.0",
-    "bootstrap-colorpicker": "^3.2.0",
-    "bootstrap-slider": "^11.0.2",
-    "bootstrap-switch": "3.3.4",
-    "bootstrap4-duallistbox": "^4.0.2",
-    "bs-custom-file-input": "^1.3.4",
-    "bs-stepper": "^1.7.0",
-    "chart.js": "^2.9.4",
-    "codemirror": "^5.60.0",
-    "datatables.net": "^1.10.24",
-    "datatables.net-autofill-bs4": "^2.3.5",
-    "datatables.net-bs4": "^1.10.24",
-    "datatables.net-buttons-bs4": "^1.7.0",
-    "datatables.net-colreorder-bs4": "^1.5.3",
-    "datatables.net-fixedcolumns-bs4": "^3.3.2",
-    "datatables.net-fixedheader-bs4": "^3.1.8",
-    "datatables.net-keytable-bs4": "^2.6.1",
-    "datatables.net-responsive-bs4": "^2.2.7",
-    "datatables.net-rowgroup-bs4": "^1.1.2",
-    "datatables.net-rowreorder-bs4": "^1.2.7",
-    "datatables.net-scroller-bs4": "^2.0.3",
-    "datatables.net-searchbuilder-bs4": "^1.0.1",
-    "datatables.net-searchpanes-bs4": "^1.2.2",
-    "datatables.net-select-bs4": "^1.3.2",
-    "daterangepicker": "^3.1.0",
-    "dropzone": "^5.8.1",
-    "ekko-lightbox": "^5.3.0",
-    "fastclick": "^1.0.6",
-    "filterizr": "^2.2.4",
-    "flag-icon-css": "^3.5.0",
-    "flot": "^4.2.2",
-    "fs-extra": "^9.1.0",
-    "fullcalendar": "^5.5.1",
-    "icheck-bootstrap": "^3.0.1",
-    "inputmask": "^5.0.5",
-    "ion-rangeslider": "^2.3.1",
-    "jquery": "^3.6.0",
-    "jquery-knob-chif": "^1.2.13",
-    "jquery-mapael": "^2.2.0",
-    "jquery-mousewheel": "^3.1.13",
-    "jquery-ui-dist": "^1.12.1",
-    "jquery-validation": "^1.19.3",
-    "jqvmap-novulnerability": "^1.5.1",
-    "jsgrid": "^1.5.3",
-    "jszip": "^3.6.0",
-    "moment": "^2.29.1",
-    "overlayscrollbars": "^1.13.1",
-    "pdfmake": "^0.1.70",
-    "popper.js": "^1.16.1",
-    "raphael": "^2.3.0",
-    "select2": "^4.0.13",
-    "sparklines": "^1.3.0",
-    "summernote": "^0.8.18",
-    "sweetalert2": "^10.15.6",
-    "tempusdominus-bootstrap-4": "^5.39.0",
-    "toastr": "^2.1.4",
-    "uplot": "^1.6.7"
+    "@popperjs/core": "^2.9.2",
+    "bootstrap": "^5.0.0"
   },
   "devDependencies": {
-    "@babel/core": "^7.13.10",
-    "@babel/preset-env": "^7.13.10",
-    "@rollup/plugin-babel": "^5.3.0",
+    "@typescript-eslint/eslint-plugin": "^4.22.1",
+    "@typescript-eslint/parser": "^4.22.1",
     "autoprefixer": "^10.2.5",
     "browser-sync": "^2.26.14",
     "bundlewatch": "^0.3.2",
-    "clean-css-cli": "^5.2.2",
-    "concurrently": "^6.0.0",
-    "eslint": "^7.22.0",
-    "eslint-config-xo": "^0.35.0",
-    "eslint-plugin-compat": "^3.9.0",
+    "clean-css-cli": "^5.3.0",
+    "concurrently": "^6.0.2",
+    "esbuild": "^0.11.18",
+    "eslint": "^7.25.0",
+    "eslint-config-xo": "^0.36.0",
+    "eslint-config-xo-typescript": "^0.40.0",
     "eslint-plugin-import": "^2.22.1",
-    "eslint-plugin-unicorn": "^29.0.0",
+    "eslint-plugin-unicorn": "^31.0.0",
     "lockfile-lint": "^4.6.2",
-    "node-sass": "^5.0.0",
-    "node-sass-package-importer": "^5.3.2",
     "nodemon": "^2.0.7",
     "npm-run-all": "^4.1.5",
-    "postcss": "^8.2.8",
+    "postcss": "^8.2.14",
     "postcss-cli": "^8.3.1",
-    "postcss-scrollbar": "^0.3.0",
-    "rollup": "^2.42.1",
-    "stylelint": "^13.12.0",
-    "stylelint-config-twbs-bootstrap": "^2.1.0",
-    "terser": "^5.6.1",
-    "vnu-jar": "^21.2.5"
+    "sass": "^1.32.12",
+    "stylelint": "^13.13.1",
+    "stylelint-config-twbs-bootstrap": "^2.2.0",
+    "typescript": "^4.2.4"
   }
 }

+ 24 - 0
tsconfig.json

@@ -0,0 +1,24 @@
+{
+  "compilerOptions": {
+    "noFallthroughCasesInSwitch": true,
+    "noUnusedParameters": true,
+    "noImplicitReturns": true,
+    "noUnusedLocals": true,
+    "noImplicitAny": true,
+    "target": "esnext",
+    "module": "esnext",
+    "strict": true,
+    "strictNullChecks": true,
+    "strictBindCallApply": true,
+    "strictFunctionTypes": true,
+    "strictPropertyInitialization": true
+  },
+  "include": [
+    "build/ts/**/*"
+  ],
+  "exclude": [
+    "dist",
+    "node_modules",
+    "plugins"
+  ]
+}

Some files were not shown because too many files changed in this diff