diff --git a/index.html b/index.html
index 79addea92..6d30812ef 100644
--- a/index.html
+++ b/index.html
@@ -13,14 +13,14 @@
-
+
@@ -54,44 +65,44 @@
-
+
Simple Link
-
+
-
+
Level 1
-
+
@@ -99,9 +110,9 @@
-
+
Simple Link
-
+
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()