Browse Source

improve treeview

Daniel 3 years ago
parent
commit
7c8e175f23

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

@@ -14,6 +14,7 @@ const banner = `/*!
 esbuild.build({
   entryPoints: ['build/ts/adminlte.ts'],
   bundle: true,
+  format: 'iife',
   minify: false,
   sourcemap: true,
   banner: {

+ 0 - 5
build/scss/_brand.scss

@@ -2,10 +2,6 @@
 // Core: Brand
 //
 
-// .brand-container {
-// display: inline-block;
-// }
-
 .brand-container {
   display: flex;
   font-size: $navbar-brand-font-size;
@@ -18,7 +14,6 @@
     text-decoration: none;
   }
 
-  // TODO: crete utility for opacity for image
   .brand-image {
     float: left;
     line-height: .8;

+ 1 - 2
build/scss/_layout.scss

@@ -6,7 +6,6 @@
   align-items: stretch;
   display: flex;
   width: 100%;
-  overflow: clip;
 
   .sidebar-rtl {
     flex-direction: row-reverse;
@@ -39,7 +38,7 @@
 
 .content {
   flex: 1;
-  width: 100vw;
+  width: 100%;
   max-width: 100vw;
   padding: 1rem;
 }

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

@@ -7,6 +7,7 @@
   border-top: $main-footer-border-top;
   color: $main-footer-color;
   padding: $main-footer-padding;
+  width: inherit;
 
   .text-sm &,
   &.text-sm {
@@ -14,6 +15,17 @@
   }
 }
 
+.layout-footer-fixed {
+  .main-footer {
+    position: fixed;
+    bottom: 0;
+  }
+
+  .content {
+    margin-bottom: $main-footer-height;
+  }
+}
+
 @include dark-mode() {
   .main-footer {
     background-color: $main-footer-bg-alt;

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

@@ -5,10 +5,26 @@
 .main-header {
   background-color: $white;
   border-bottom: $main-header-bottom-border;
+  width: inherit;
   z-index: $zindex-main-header;
 
   .nav-link {
     color: $dark;
+
+    &:hover,
+    &:focus {
+      color: $black;
+    }
+  }
+}
+
+.layout-navbar-fixed {
+  .main-header {
+    position: fixed;
+  }
+
+  .content {
+    margin-top: $main-header-height;
   }
 }
 

+ 10 - 6
build/scss/_main-sidebar.scss

@@ -13,22 +13,26 @@
 }
 
 @include media-breakpoint-down(sm) {
-  :not(.layout-fixed).main-sidebar {
+  .main-sidebar {
     margin-left: -#{$sidebar-width};
 
     .sidebar-open & {
       transform: translateX($sidebar-width);
+    }
+  }
+
+  .sidebar-mini-icon {
+    visibility: hidden;
+  }
 
-      .sidebar-mini-icon {
-        display: none;
-        transition: display $transition-speed;
-      }
+  .sidebar-open {
+    .content-wrapper {
+      opacity: .9;
     }
   }
 }
 
 .sidebar {
-  height: 100%;
   overflow-x: hidden;
   overflow-y: auto;
   padding-bottom: $sidebar-padding-y;

+ 8 - 1
build/scss/_sidebar-mini.scss

@@ -2,6 +2,13 @@
 // Core: Sidebar Mini
 //
 
+// A fix for text overflow while transitioning from sidebar mini to full sidebar
+.nav-sidebar,
+.nav-sidebar > .nav-header,
+.nav-sidebar .nav-link {
+  white-space: nowrap;
+}
+
 .sidebar-mini.sidebar-collapse {
   .main-sidebar {
     min-width: $sidebar-mini-width;
@@ -45,7 +52,7 @@
     }
 
     .nav-sidebar .nav-header {
-      display: block;
+      display: inline-block;
     }
 
     .sidebar .user-panel > .info,

+ 4 - 0
build/ts/AdminLTE.ts

@@ -1,8 +1,12 @@
 import PushMenu from './push-menu'
+import SidebarHover from './sidebar-hover'
+import SidebarOverlay from './sidebar-overlay'
 import Treeview from './treeview'
 
 export {
   PushMenu,
+  SidebarHover,
+  SidebarOverlay,
   Treeview
 }
 

+ 54 - 5
build/ts/Treeview.ts

@@ -1,3 +1,4 @@
+/* eslint-disable no-console */
 /**
  * --------------------------------------------
  * AdminLTE treeview.ts
@@ -6,7 +7,7 @@
  */
 
 import {
-  windowReady
+  domReady
 } from './util/index'
 
 /**
@@ -20,18 +21,66 @@ const CLASS_NAME_MENU_OPEN = 'menu-open'
 const SELECTOR_NAV_ITEM = '.nav-item'
 const SELECTOR_DATA_TOGGLE = '[data-widget="treeview"]'
 
+const Defaults = {
+  transitionDuration: 300
+}
+
 /**
  * Class Definition
  * ====================================================
  */
 
 class Treeview {
+  open(navItem: Element | null, childNavItem: HTMLElement | null | undefined): void {
+    console.log('🚀 ~ file: treeview.ts ~ line 31 ~ Treeview ~ open ~ childNavItem', childNavItem)
+
+    navItem?.classList.add(CLASS_NAME_MENU_OPEN)
+
+    const height: number = childNavItem?.scrollHeight ?? 0
+
+    childNavItem?.style.setProperty('transition', `height ${Defaults.transitionDuration}ms`)
+    childNavItem?.style.setProperty('overflow', 'hidden')
+    childNavItem?.style.setProperty('display', 'block')
+    childNavItem?.style.setProperty('height', '0px')
+
+    setTimeout(() => {
+      childNavItem?.style.setProperty('height', `${height}px`)
+    }, 1)
+
+    setTimeout(() => {
+      childNavItem?.style.removeProperty('overflow')
+      childNavItem?.style.setProperty('height', 'auto')
+    }, Defaults.transitionDuration)
+  }
+
+  close(navItem: Element, childNavItem: HTMLElement | null | undefined): void {
+    navItem.classList.remove(CLASS_NAME_MENU_OPEN)
+
+    const height: number = childNavItem?.scrollHeight ?? 0
+    childNavItem?.style.setProperty('transition', `height ${Defaults.transitionDuration}ms`)
+
+    childNavItem?.style.setProperty('overflow', 'hidden')
+    childNavItem?.style.setProperty('height', `${height}px`)
+
+    setTimeout(() => {
+      childNavItem?.style.setProperty('height', '0px')
+    }, 1)
+
+    setTimeout(() => {
+      // childNavItem?.style.removeProperty('height')
+      childNavItem?.style.removeProperty('display')
+      childNavItem?.style.removeProperty('overflow')
+    }, Defaults.transitionDuration)
+  }
+
   toggle(treeviewMenu: Element): void {
-    const navItem = treeviewMenu.closest(SELECTOR_NAV_ITEM)
+    const navItem: HTMLElement | null = treeviewMenu.closest(SELECTOR_NAV_ITEM)
+    const childNavItem: HTMLElement | null | undefined = navItem?.querySelector('.nav-treeview')
+
     if (navItem?.classList.contains(CLASS_NAME_MENU_OPEN)) {
-      navItem.classList.remove(CLASS_NAME_MENU_OPEN)
+      this.close(navItem, childNavItem)
     } else {
-      navItem?.classList.add(CLASS_NAME_MENU_OPEN)
+      this.open(navItem, childNavItem)
     }
   }
 }
@@ -44,7 +93,7 @@ class Treeview {
 
 const button = document.querySelectorAll(SELECTOR_DATA_TOGGLE)
 
-windowReady(() => {
+domReady(() => {
   for (const btn of button) {
     btn.addEventListener('click', event => {
       event.preventDefault()

+ 2 - 59
build/ts/push-menu.ts

@@ -6,7 +6,7 @@
  */
 
 import {
-  windowReady
+  domReady
 } from './util/index'
 
 /**
@@ -22,16 +22,9 @@ 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
@@ -124,21 +117,7 @@ class PushMenu {
  * ------------------------------------------------------------------------
  */
 
-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)
-
+domReady(() => {
   const fullBtn = document.querySelectorAll(SELECTOR_FULL_TOGGLE)
   const miniBtn = document.querySelectorAll(SELECTOR_MINI_TOGGLE)
 
@@ -155,42 +134,6 @@ windowReady(() => {
       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

+ 50 - 0
build/ts/sidebar-hover.ts

@@ -0,0 +1,50 @@
+/**
+ * --------------------------------------------
+ * AdminLTE treeview.ts
+ * License MIT
+ * --------------------------------------------
+ */
+
+import {
+  domReady
+} from './util/index'
+
+/**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+const CLASS_NAME_SIDEBAR_HOVER = 'sidebar-hover'
+
+const SELECTOR_SIDEBAR = '.sidebar'
+
+class SidebarHover {
+  onHover(): void {
+    const bodyClass = document.body.classList
+    bodyClass.add(CLASS_NAME_SIDEBAR_HOVER)
+  }
+
+  notHover(): void {
+    const bodyClass = document.body.classList
+    bodyClass.remove(CLASS_NAME_SIDEBAR_HOVER)
+  }
+
+  init(): void {
+    const selSidebar = document.querySelector(SELECTOR_SIDEBAR)
+    selSidebar?.addEventListener('mouseover', () => {
+      this.onHover()
+    })
+
+    selSidebar?.addEventListener('mouseout', () => {
+      this.notHover()
+    })
+  }
+}
+
+domReady(() => {
+  const data = new SidebarHover()
+  data.init()
+})
+
+export default SidebarHover

+ 67 - 0
build/ts/sidebar-overlay.ts

@@ -0,0 +1,67 @@
+/**
+ * --------------------------------------------
+ * AdminLTE treeview.ts
+ * License MIT
+ * --------------------------------------------
+ */
+
+import {
+  domReady
+} from './util/index'
+
+/**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+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_SM = 'sidebar-sm'
+
+const SELECTOR_SIDEBAR_SM = `.${CLASS_NAME_SIDEBAR_SM}`
+const SELECTOR_CONTENT = '.content'
+
+class SidebarOverlay {
+  addSidebaBreakPoint(): void {
+    const bodyClass = document.body.classList
+    const widthOutput: number = window.innerWidth
+    if (widthOutput > 576) {
+      bodyClass.remove(CLASS_NAME_SIDEBAR_SM)
+    } else {
+      bodyClass.add(CLASS_NAME_SIDEBAR_SM)
+    }
+  }
+
+  removeOverlaySidebar(): void {
+    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)
+    }
+  }
+
+  init(): void {
+    const selSidebarSm = document.querySelector(SELECTOR_SIDEBAR_SM)
+    const selContentWrapper = selSidebarSm?.querySelector(SELECTOR_CONTENT)
+
+    selContentWrapper?.addEventListener('touchstart', this.removeOverlaySidebar)
+    selContentWrapper?.addEventListener('click', this.removeOverlaySidebar)
+  }
+}
+
+domReady(() => {
+  const data = new SidebarOverlay()
+
+  data.addSidebaBreakPoint()
+  data.init()
+
+  window.addEventListener('resize', () => {
+    data.addSidebaBreakPoint()
+    data.init()
+  })
+})
+
+export default SidebarOverlay

+ 12 - 15
index.html

@@ -9,10 +9,10 @@
   <link rel="stylesheet" href="./node_modules/@fortawesome/fontawesome-free/css/all.min.css">
 </head>
 
-<body class="sidebar-mini">
+<body class="sidebar-mini layout-fixed">
   <div class="wrapper">
     <!-- Main Sidebar Container -->
-    <nav class="main-sidebar">
+    <nav class="main-sidebar shadow">
       <div class="brand-container">
         <a href="#" class="brand-link">
           <img src="dist/img/AdminLTELogo.png" alt="AdminLTE Logo" class="brand-image opacity-80">
@@ -57,7 +57,6 @@
                         <i class="nav-icon far fa-dot-circle"></i>
                         <span>
                           Level 3
-                          <i class="right fas fa-angle-left"></i>
                         </span>
                       </a>
                     </li>
@@ -95,7 +94,7 @@
               <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>
+              <a href="#" class="nav-link">Home</a>
             </li>
             <li class="nav-item">
               <a href="#" class="nav-link">Contact</a>
@@ -108,17 +107,15 @@
       <!-- 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>
+          <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>
           <!-- /.row -->
         </div><!-- /.container-fluid -->
       </main>

+ 16 - 16
package-lock.json

@@ -360,9 +360,9 @@
       }
     },
     "@eslint/eslintrc": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
-      "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz",
+      "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==",
       "dev": true,
       "requires": {
         "ajv": "^6.12.4",
@@ -1362,9 +1362,9 @@
       "dev": true
     },
     "concurrently": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.0.2.tgz",
-      "integrity": "sha512-u+1Q0dJG5BidgUTpz9CU16yoHTt/oApFDQ3mbvHwSDgMjU7aGqy0q8ZQyaZyaNxdwRKTD872Ux3Twc6//sWA+Q==",
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.1.0.tgz",
+      "integrity": "sha512-jy+xj49pvqeKjc2TAVXRIhrgPG51eBKDZti0kZ41kaWk9iLbyWBjH6KMFpW7peOLkEymD+ZM83Lx6UEy3N/M9g==",
       "dev": true,
       "requires": {
         "chalk": "^4.1.0",
@@ -1556,9 +1556,9 @@
       "dev": true
     },
     "date-fns": {
-      "version": "2.21.1",
-      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.21.1.tgz",
-      "integrity": "sha512-m1WR0xGiC6j6jNFAyW4Nvh4WxAi4JF4w9jRJwSI8nBmNcyZXPcP9VUQG+6gHQXAmqaGEKDKhOqAtENDC941UkA==",
+      "version": "2.21.3",
+      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.21.3.tgz",
+      "integrity": "sha512-HeYdzCaFflc1i4tGbj7JKMjM4cKGYoyxwcIIkHzNgCkX8xXDNJDZXgDDVchIWpN4eQc3lH37WarduXFZJOtxfw==",
       "dev": true
     },
     "debug": {
@@ -1933,9 +1933,9 @@
       }
     },
     "esbuild": {
-      "version": "0.11.18",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.11.18.tgz",
-      "integrity": "sha512-KD7v4N9b5B8bxPUNn/3GA9r0HWo4nJk3iwjZ+2zG1ffg+r8ig+wqj7sW6zgI6Sn4/B2FnbzqWxcAokAGGM5zwQ==",
+      "version": "0.11.20",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.11.20.tgz",
+      "integrity": "sha512-QOZrVpN/Yz74xfat0H6euSgn3RnwLevY1mJTEXneukz1ln9qB+ieaerRMzSeETpz/UJWsBMzRVR/andBht5WKw==",
       "dev": true
     },
     "escalade": {
@@ -1963,13 +1963,13 @@
       "dev": true
     },
     "eslint": {
-      "version": "7.25.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz",
-      "integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==",
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz",
+      "integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "7.12.11",
-        "@eslint/eslintrc": "^0.4.0",
+        "@eslint/eslintrc": "^0.4.1",
         "ajv": "^6.10.0",
         "chalk": "^4.0.0",
         "cross-spawn": "^7.0.2",

+ 3 - 3
package.json

@@ -61,9 +61,9 @@
     "browser-sync": "^2.26.14",
     "bundlewatch": "^0.3.2",
     "clean-css-cli": "^5.3.0",
-    "concurrently": "^6.0.2",
-    "esbuild": "^0.11.18",
-    "eslint": "^7.25.0",
+    "concurrently": "^6.1.0",
+    "esbuild": "^0.11.20",
+    "eslint": "^7.26.0",
     "eslint-config-xo": "^0.36.0",
     "eslint-config-xo-typescript": "^0.40.0",
     "eslint-plugin-import": "^2.22.1",