diff --git a/build/config/esbuild.config.js b/build/config/esbuild.config.js index 20d51d3e0..11ce232b7 100644 --- a/build/config/esbuild.config.js +++ b/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: { diff --git a/build/scss/_brand.scss b/build/scss/_brand.scss index b8c0851b4..ecdcf4814 100644 --- a/build/scss/_brand.scss +++ b/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; diff --git a/build/scss/_layout.scss b/build/scss/_layout.scss index 8b2073a82..d8fcd40c4 100644 --- a/build/scss/_layout.scss +++ b/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; } diff --git a/build/scss/_main-footer.scss b/build/scss/_main-footer.scss index 59a6c3a3f..fd4cc6627 100644 --- a/build/scss/_main-footer.scss +++ b/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; diff --git a/build/scss/_main-header.scss b/build/scss/_main-header.scss index 1a73030f4..ee85ebda6 100644 --- a/build/scss/_main-header.scss +++ b/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; } } diff --git a/build/scss/_main-sidebar.scss b/build/scss/_main-sidebar.scss index 3c828ae99..db24f8f11 100644 --- a/build/scss/_main-sidebar.scss +++ b/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 { - display: none; - transition: display $transition-speed; - } + .sidebar-mini-icon { + visibility: hidden; + } + + .sidebar-open { + .content-wrapper { + opacity: .9; } } } .sidebar { - height: 100%; overflow-x: hidden; overflow-y: auto; padding-bottom: $sidebar-padding-y; diff --git a/build/scss/_sidebar-mini.scss b/build/scss/_sidebar-mini.scss index 1cef9f494..d1c8b68ac 100644 --- a/build/scss/_sidebar-mini.scss +++ b/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, diff --git a/build/ts/AdminLTE.ts b/build/ts/AdminLTE.ts index e6e00eadf..85003d24c 100644 --- a/build/ts/AdminLTE.ts +++ b/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 } diff --git a/build/ts/Treeview.ts b/build/ts/Treeview.ts index c1da93446..345663d47 100644 --- a/build/ts/Treeview.ts +++ b/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() diff --git a/build/ts/push-menu.ts b/build/ts/push-menu.ts index ef87d9f68..0f4642eaa 100644 --- a/build/ts/push-menu.ts +++ b/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 diff --git a/build/ts/sidebar-hover.ts b/build/ts/sidebar-hover.ts new file mode 100644 index 000000000..1d90d6f4d --- /dev/null +++ b/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 diff --git a/build/ts/sidebar-overlay.ts b/build/ts/sidebar-overlay.ts new file mode 100644 index 000000000..49fdaffd7 --- /dev/null +++ b/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 diff --git a/index.html b/index.html index 9ab45e01c..f58ead70e 100644 --- a/index.html +++ b/index.html @@ -9,10 +9,10 @@ - +
-