improve treeview

pull/3698/head
Daniel 2021-05-08 22:13:00 +05:30
parent 74baa01504
commit 7c8e175f23
15 changed files with 256 additions and 112 deletions

View File

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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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 {
display: none;
transition: display $transition-speed;
visibility: hidden;
}
.sidebar-open {
.content-wrapper {
opacity: .9;
}
}
}
.sidebar {
height: 100%;
overflow-x: hidden;
overflow-y: auto;
padding-bottom: $sidebar-padding-y;

View File

@ -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,

View File

@ -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
}

View File

@ -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 {
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 {
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: HTMLElement | null = treeviewMenu.closest(SELECTOR_NAV_ITEM)
const childNavItem: HTMLElement | null | undefined = navItem?.querySelector('.nav-treeview')
if (navItem?.classList.contains(CLASS_NAME_MENU_OPEN)) {
this.close(navItem, childNavItem)
} else {
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()

View File

@ -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
build/ts/sidebar-hover.ts Normal file
View File

@ -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

View File

@ -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

View File

@ -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,7 +107,6 @@
<!-- 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>
@ -118,7 +116,6 @@
<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>

32
package-lock.json generated
View File

@ -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",

View File

@ -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",