diff --git a/index.html b/index.html index 79addea92..6d30812ef 100644 --- a/index.html +++ b/index.html @@ -13,14 +13,14 @@ - +
@@ -40,8 +51,8 @@
- +
@@ -54,44 +65,44 @@ diff --git a/package-lock.json b/package-lock.json index e4ea6377f..9a6902646 100644 --- a/package-lock.json +++ b/package-lock.json @@ -867,9 +867,9 @@ "dev": true }, "bootstrap": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.0.tgz", - "integrity": "sha512-tmhPET9B9qCl8dCofvHeiIhi49iBt0EehmIsziZib65k1erBW1rHhj2s/2JsuQh5Pq+xz2E9bEbzp9B7xHG+VA==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.1.tgz", + "integrity": "sha512-Fl79+wsLOZKoiU345KeEaWD0ik8WKRI5zm0YSPj2oF1Qr+BO7z0fco6GbUtqjoG1h4VI89PeKJnMsMMVQdKKTw==" }, "boxen": { "version": "4.2.0", @@ -5601,9 +5601,9 @@ "dev": true }, "sass": { - "version": "1.32.12", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.12.tgz", - "integrity": "sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA==", + "version": "1.32.13", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.13.tgz", + "integrity": "sha512-dEgI9nShraqP7cXQH+lEXVf73WOPCse0QlFzSD8k+1TcOxCMwVXfQlr0jtoluZysQOyJGnfr21dLvYKDJq8HkA==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0" diff --git a/package.json b/package.json index c2bf639dc..ece7dc52d 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "dependencies": { "@fortawesome/fontawesome-free": "^5.15.3", "@popperjs/core": "^2.9.2", - "bootstrap": "^5.0.0" + "bootstrap": "^5.0.1" }, "devDependencies": { "@typescript-eslint/eslint-plugin": "^4.23.0", @@ -86,7 +86,7 @@ "postcss": "^8.2.15", "postcss-cli": "^8.3.1", "rtlcss": "^3.1.2", - "sass": "^1.32.12", + "sass": "^1.32.13", "stylelint": "^13.13.1", "stylelint-config-twbs-bootstrap": "^2.2.0", "typescript": "^4.2.4" diff --git a/scss/_custom-variables.scss b/scss/_custom-variables.scss index a6e197bb9..365479d71 100644 --- a/scss/_custom-variables.scss +++ b/scss/_custom-variables.scss @@ -86,6 +86,21 @@ $nav-link-sm-height: ($font-size-sm * $line-height-sm + $nav-link- $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; +// HEADER SKINS +// -------------------------------------------------------- + +// Dark sidebar +$header-dark-bg: $dark; +$header-dark-color: $white; +$header-mobile-dark-bg: $dark; +$header-mobile-dark-color: $white; + +// Light sidebar +$header-light-bg: $white; +$header-light-color: $dark; +$header-mobile-light-bg: $light; +$header-mobile-light-color: $dark; + // Content padding $content-padding-y: 0 !default; $content-padding-x: .5rem !default; @@ -113,8 +128,10 @@ $brand-link-border-buttom: 1px; // -------------------------------------------------------- $zindex-main-header: $zindex-fixed + 4 !default; $zindex-sidebar: $zindex-fixed + 8 !default; +$zindex-main-brand: $zindex-main-header !default; $zindex-main-footer: $zindex-fixed + 2 !default; $zindex-sidebar-horizontal: $zindex-main-header - 2 !default; +$zindex-header-mobile: $zindex-main-brand + 2 !default; $zindex-control-sidebar: $zindex-fixed + 1 !default; $zindex-toasts: $zindex-sidebar + 2 !default; $zindex-content-wrapper: $zindex-sidebar - 2 !default; diff --git a/scss/_layout.scss b/scss/_layout.scss index 2181240ac..7d555d8c6 100644 --- a/scss/_layout.scss +++ b/scss/_layout.scss @@ -4,9 +4,9 @@ @import "layout/main-sidebar"; @import "layout/sidebar"; @import "layout/nav-sidebar"; +@import "layout/sidebar-collapse"; +// @import "layout/sidebar-horizontal"; @import "layout/sidebar-close"; -@import "layout/sidebar-mini"; -@import "layout/sidebar-horizontal"; @import "layout/content-wrapper"; @import "layout/content-header"; @import "layout/content"; diff --git a/scss/_mixins.scss b/scss/_mixins.scss index 540977446..71ca09224 100644 --- a/scss/_mixins.scss +++ b/scss/_mixins.scss @@ -5,5 +5,6 @@ @import "mixins/animations"; @import "mixins/scrollbar"; @import "mixins/brand-variant"; +@import "mixins/header-variant"; @import "mixins/sidebar-variant"; @import "mixins/miscellaneous"; diff --git a/scss/layout/_layout-fixed.scss b/scss/layout/_layout-fixed.scss index 9364ebc8a..74c6a1f5e 100644 --- a/scss/layout/_layout-fixed.scss +++ b/scss/layout/_layout-fixed.scss @@ -14,6 +14,10 @@ left: 0; position: fixed; top: auto; + + .sidebar { + height: subtract(100vh, add($main-header-height-inner, $main-header-bottom-border-width / 2)); + } } .main-header, @@ -40,10 +44,6 @@ } } - .layout-fixed .wrapper .sidebar { - // stylelint-disable-next-line - height: calc(100vh - #{$main-header-height-inner}); - } // .layout-fixed.text-sm .wrapper .sidebar { // // stylelint-disable-next-line // height: calc(100vh - (#{$main-header-height-sm-inner} + #{$main-header-bottom-border-width})); diff --git a/scss/layout/_layout-mobile.scss b/scss/layout/_layout-mobile.scss index b17137c12..4976d5453 100644 --- a/scss/layout/_layout-mobile.scss +++ b/scss/layout/_layout-mobile.scss @@ -4,7 +4,7 @@ "main-sidebar main-brand main-header" "main-sidebar content-wrapper main-header" "main-sidebar main-footer main-header"; - grid-template-columns: auto auto auto; + grid-template-columns: auto 1fr auto; .main-sidebar { position: fixed; @@ -20,7 +20,23 @@ } .main-header { - display: none; + position: fixed; + top: 0; + bottom: 0; + min-height: 100vh; + z-index: $zindex-header-mobile; + width: $sidebar-width; + margin-left: -#{$sidebar-width}; + align-items: baseline; + @include transition($sidebar-transition); + + .navbar-nav { + flex-direction: column; + } + + .sidebar-full-icon { + display: none; + } } .brand-link { @@ -38,4 +54,12 @@ margin-left: 0; } } + + @include media-breakpoint-down(md) { + .header-mobile-open { + .main-header { + margin-left: 0; + } + } + } } diff --git a/scss/layout/_main-brand.scss b/scss/layout/_main-brand.scss index ad04218a5..726ece22d 100644 --- a/scss/layout/_main-brand.scss +++ b/scss/layout/_main-brand.scss @@ -18,7 +18,7 @@ max-width: $sidebar-width; height: min-content; @include transition($sidebar-transition); - z-index: $zindex-sidebar; + z-index: $zindex-main-brand; .brand-link { grid-area: brand-link; diff --git a/scss/layout/_main-header.scss b/scss/layout/_main-header.scss index a38cea569..7841d098d 100644 --- a/scss/layout/_main-header.scss +++ b/scss/layout/_main-header.scss @@ -2,21 +2,18 @@ // Core: Main Header // +@include header-variant( + $header-light-bg, + $header-light-color, + $header-mobile-light-bg, + $header-mobile-light-color +); + .main-header { grid-area: 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 { diff --git a/scss/layout/_main-sidebar.scss b/scss/layout/_main-sidebar.scss index 15eedd028..3539629da 100644 --- a/scss/layout/_main-sidebar.scss +++ b/scss/layout/_main-sidebar.scss @@ -2,8 +2,20 @@ // Core: Main Sidebar // -// Default Sidebar Theme -@include sidebar-variant($sidebar-dark-bg, $sidebar-dark-color); +// Default Sidebar Variant +@include sidebar-variant( + $sidebar-dark-bg, + $sidebar-dark-hover-bg, + $sidebar-dark-color, + $sidebar-dark-hover-color, + $sidebar-dark-active-color, + $sidebar-dark-submenu-bg, + $sidebar-dark-submenu-color, + $sidebar-dark-submenu-hover-color, + $sidebar-dark-submenu-hover-bg, + $sidebar-dark-submenu-active-color, + $sidebar-dark-submenu-active-bg +); .main-sidebar { grid-area: main-sidebar; @@ -12,28 +24,3 @@ min-width: $sidebar-width; max-width: $sidebar-width; } - -@include media-breakpoint-down(md) { - // .main-sidebar { - // display: block; - // position: fixed; - // } - // .main-sidebar { - // margin-left: -#{$sidebar-width}; - - // .sidebar-open & { - // transform: translateX($sidebar-width); - // } - // } - - // .sidebar-mini-icon { - // visibility: hidden; - // } - - // .sidebar-open { - // .content-wrapper { - // opacity: .9; - // } - // } -} - diff --git a/scss/layout/_nav-sidebar.scss b/scss/layout/_nav-sidebar.scss index dc417f295..093aaf551 100644 --- a/scss/layout/_nav-sidebar.scss +++ b/scss/layout/_nav-sidebar.scss @@ -2,7 +2,7 @@ .nav-sidebar { // All levels .nav-link > .right, - .nav-link > span > .right { + .nav-link > p > .right { position: absolute; right: 1rem; top: .7rem; @@ -10,10 +10,12 @@ .nav-link { position: relative; + width: 100%; - span { - display: inline-block; + p { + display: inline; padding-left: .5rem; + margin: 0; } .nav-icon { @@ -28,12 +30,16 @@ // Tree view menu .nav-treeview { - display: none; + // display: none; list-style: none; padding: 0; } - .menu-open > .nav-treeview { - display: block; + .nav-item { + width: 100%; + + &:not(.menu-open) .nav-treeview { + display: none; + } } } diff --git a/scss/layout/_sidebar-mini.scss b/scss/layout/_sidebar-collapse.scss similarity index 91% rename from scss/layout/_sidebar-mini.scss rename to scss/layout/_sidebar-collapse.scss index 9a3b5ace1..8e985a7b4 100644 --- a/scss/layout/_sidebar-mini.scss +++ b/scss/layout/_sidebar-collapse.scss @@ -9,7 +9,7 @@ white-space: nowrap; } -.sidebar-mini.sidebar-collapse:not(.sidebar-horizontal) { +.sidebar-collapse:not(.sidebar-horizontal) { .main-sidebar { min-width: $sidebar-mini-width; max-width: $sidebar-mini-width; @@ -20,13 +20,13 @@ display: none; } - .nav-sidebar .nav-link span { + .nav-sidebar .nav-link p { width: 0; white-space: nowrap; } .sidebar .user-panel > .info, - .nav-sidebar .nav-link span, + .nav-sidebar .nav-link p, .brand-link { margin-left: -10px; animation-name: fadeOut; @@ -46,7 +46,7 @@ } .sidebar .user-panel > .info, - .nav-sidebar .nav-link span, + .nav-sidebar .nav-link p, .brand-link { margin-left: 0; animation-name: fadeIn; @@ -91,7 +91,7 @@ .sidebar-is-opening { .sidebar .user-panel > .info, - .nav-sidebar .nav-link span, + .nav-sidebar .nav-link p, .brand-link { margin-left: 0; animation-name: fadeIn; @@ -103,7 +103,7 @@ .sidebar-is-collapsing { .sidebar .user-panel > .info, - .nav-sidebar .nav-link span, + .nav-sidebar .nav-link p, .brand-link { margin-left: -10px; animation-name: fadeOut; diff --git a/scss/layout/_sidebar-horizontal.scss b/scss/layout/_sidebar-horizontal.scss index 0a72b2c62..f8a1b143a 100644 --- a/scss/layout/_sidebar-horizontal.scss +++ b/scss/layout/_sidebar-horizontal.scss @@ -51,7 +51,7 @@ padding-left: 0; } - span { + p { padding-left: 0; } } diff --git a/scss/layout/_sidebar.scss b/scss/layout/_sidebar.scss index 7054b11b7..dff3a4dd0 100644 --- a/scss/layout/_sidebar.scss +++ b/scss/layout/_sidebar.scss @@ -1,4 +1,5 @@ .sidebar { + min-height: 100%; overflow-x: hidden; overflow-y: auto; padding-bottom: $sidebar-padding-y; diff --git a/scss/mixins/_header-variant.scss b/scss/mixins/_header-variant.scss new file mode 100644 index 000000000..6191c6e84 --- /dev/null +++ b/scss/mixins/_header-variant.scss @@ -0,0 +1,31 @@ +// +// Mixins: Sidebar Variant +// + +@mixin header-variant( + $header-bg, + $header-color, + $header-mobile-bg, + $header-mobile-color +) { + .main-header { + background-color: $header-bg; + color: $header-color; + + .nav-link { + color: $dark; + + &:hover, + &:focus { + color: $black; + } + } + } + + @include media-breakpoint-down(md) { + .main-header { + background-color: $header-mobile-bg; + color: $header-mobile-color; + } + } +} diff --git a/scss/mixins/_miscellaneous.scss b/scss/mixins/_miscellaneous.scss index 722230948..4b96dd837 100644 --- a/scss/mixins/_miscellaneous.scss +++ b/scss/mixins/_miscellaneous.scss @@ -16,9 +16,9 @@ // #{$property}: calc(#{$expression}); // } -@mixin rotate($value) { - transform: rotate($value); -} +// @mixin rotate($value) { +// transform: rotate($value); +// } // @mixin animation($animation) { // animation: $animation; diff --git a/scss/mixins/_sidebar-variant.scss b/scss/mixins/_sidebar-variant.scss index 355de6e24..00efbf88d 100644 --- a/scss/mixins/_sidebar-variant.scss +++ b/scss/mixins/_sidebar-variant.scss @@ -1,19 +1,23 @@ // -// Mixins: Sidebar Theme +// Mixins: Sidebar Variant // @mixin sidebar-variant( $sidebar-bg, - $sidebar-color + $sidebar-hover-bg, + $sidebar-color, + $sidebar-hover-color, + $sidebar-active-color, + $sidebar-submenu-bg, + $sidebar-submenu-color, + $sidebar-submenu-hover-color, + $sidebar-submenu-hover-bg, + $sidebar-submenu-active-color, + $sidebar-submenu-active-bg ) { - - // .wrapper { - // background: $sidebar-bg; - // } - .main-sidebar { - color: $sidebar-color; background-color: $sidebar-bg; + color: $sidebar-color; } // Sidebar navigation menu @@ -23,8 +27,12 @@ color: $sidebar-color; &:hover, + &:focus { + color: $sidebar-hover-color; + } + .active { - color: color-constract($sidebar-color); + color: $sidebar-active-color; } } @@ -37,7 +45,7 @@ // .sidebar { // .nav-sidebar .nav-item:hover { // .nav-link:not(.active) { - // span { + // p { // background-color: $sidebar-bg; // } // } diff --git a/ts/push-menu.ts b/ts/push-menu.ts index 655b12a7f..952167cd2 100644 --- a/ts/push-menu.ts +++ b/ts/push-menu.ts @@ -24,12 +24,14 @@ 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_MENU_OPEN = 'menu-open' +const CLASS_NAME_HEADER_MOBILE_OPEN = 'header-mobile-open' const SELECTOR_NAV_SIDEBAR = '.nav-sidebar' const SELECTOR_NAV_ITEM = '.nav-item' const SELECTOR_NAV_TREEVIEW = '.nav-treeview' const SELECTOR_MINI_TOGGLE = '[data-pushmenu="mini"]' const SELECTOR_FULL_TOGGLE = '[data-pushmenu="full"]' +const SELECTOR_FULL_HEADER = '[data-pushmenu="header"]' /** * Class Definition @@ -129,11 +131,33 @@ class PushMenu { } } + toggleHeader(): void { + this.close() + const bodyClass = document.body.classList + if (bodyClass.contains(CLASS_NAME_HEADER_MOBILE_OPEN)) { + bodyClass.remove(CLASS_NAME_HEADER_MOBILE_OPEN) + } else { + bodyClass.add(CLASS_NAME_HEADER_MOBILE_OPEN) + } + } + toggle(state: string): void { - if (state === 'full') { - this.toggleFull() - } else if (state === 'mini') { - this.toggleMini() + switch (state) { + case 'full': { + this.toggleFull() + break + } + + case 'mini': { + this.toggleMini() + break + } + + case 'header': { + this.toggleHeader() + break + } + // No default } } } @@ -147,6 +171,7 @@ class PushMenu { domReady(() => { const fullBtn = document.querySelectorAll(SELECTOR_FULL_TOGGLE) const miniBtn = document.querySelectorAll(SELECTOR_MINI_TOGGLE) + const headerBtn = document.querySelectorAll(SELECTOR_FULL_HEADER) for (const btn of fullBtn) { btn.addEventListener('click', () => { @@ -161,6 +186,13 @@ domReady(() => { data.toggle('mini') }) } + + for (const btn of headerBtn) { + btn.addEventListener('click', () => { + const data = new PushMenu() + data.toggle('header') + }) + } }) export default PushMenu diff --git a/ts/sidebar-overlay.ts b/ts/sidebar-overlay.ts index 7797c80dd..6bbb94fba 100644 --- a/ts/sidebar-overlay.ts +++ b/ts/sidebar-overlay.ts @@ -19,6 +19,7 @@ const CLASS_NAME_SIDEBAR_COLLAPSE = 'sidebar-collapse' const CLASS_NAME_SIDEBAR_CLOSE = 'sidebar-close' const CLASS_NAME_SIDEBAR_OPEN = 'sidebar-open' const CLASS_NAME_LAYOUT_MOBILE = 'layout-mobile' +const CLASS_NAME_HEADER_MOBILE_OPEN = 'header-mobile-open' const SELECTOR_SIDEBAR_SM = `.${CLASS_NAME_LAYOUT_MOBILE}` const SELECTOR_CONTENT_WRAPPER = '.content-wrapper' @@ -43,6 +44,7 @@ class SidebarOverlay { if (bodyClass.contains(CLASS_NAME_LAYOUT_MOBILE)) { bodyClass.remove(CLASS_NAME_SIDEBAR_OPEN) bodyClass.remove(CLASS_NAME_SIDEBAR_COLLAPSE) + bodyClass.remove(CLASS_NAME_HEADER_MOBILE_OPEN) bodyClass.add(CLASS_NAME_SIDEBAR_CLOSE) } } diff --git a/ts/treeview.ts b/ts/treeview.ts index 345663d47..d68211cd0 100644 --- a/ts/treeview.ts +++ b/ts/treeview.ts @@ -22,7 +22,8 @@ const SELECTOR_NAV_ITEM = '.nav-item' const SELECTOR_DATA_TOGGLE = '[data-widget="treeview"]' const Defaults = { - transitionDuration: 300 + transitionDuration: 300, + transitionTimingFuntion: 'linear' } /** @@ -38,9 +39,7 @@ class Treeview { 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(() => { @@ -50,14 +49,12 @@ class Treeview { setTimeout(() => { childNavItem?.style.removeProperty('overflow') childNavItem?.style.setProperty('height', 'auto') + childNavItem?.style.removeProperty('height') }, 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`) @@ -67,21 +64,23 @@ class Treeview { }, 1) setTimeout(() => { - // childNavItem?.style.removeProperty('height') - childNavItem?.style.removeProperty('display') childNavItem?.style.removeProperty('overflow') + childNavItem?.style.removeProperty('height') + navItem.classList.remove(CLASS_NAME_MENU_OPEN) }, 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) - } + childNavItem?.style.setProperty('transition', `height ${Defaults.transitionDuration}ms ${Defaults.transitionTimingFuntion}`) + setTimeout(() => { + if (navItem?.classList.contains(CLASS_NAME_MENU_OPEN)) { + this.close(navItem, childNavItem) + } else { + this.open(navItem, childNavItem) + } + }, 1) } } @@ -91,9 +90,8 @@ class Treeview { * ------------------------------------------------------------------------ */ -const button = document.querySelectorAll(SELECTOR_DATA_TOGGLE) - domReady(() => { + const button = document.querySelectorAll(SELECTOR_DATA_TOGGLE) for (const btn of button) { btn.addEventListener('click', event => { event.preventDefault()