Merge pull request #3127 from Icinga/feature/toggle-sidebar

Toggle sidebar
This commit is contained in:
lippserd 2017-11-21 23:16:15 +01:00 committed by GitHub
commit 97b8f1d241
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 303 additions and 178 deletions

View File

@ -14,3 +14,7 @@ if ($searchDashboard->search('dummy')->getPane('search')->hasDashlets()): ?>
</form>
<?php endif; ?>
<?= $menuRenderer->setCssClass('primary-nav')->setElementTag('nav')->setHeading(t('Navigation')); ?>
<button id="toggle-sidebar" title="<?= $this->translate('Toggle Menu') ?>">
<i id="close-sidebar" class="icon-angle-double-left"></i>
<i id="open-sidebar" class="icon-angle-double-right"></i>
</button>

View File

@ -13,19 +13,22 @@ html {
}
#header {
height: 3em;
left: 0;
position: fixed;
top: 0;
width: 100%;
padding-bottom: 3em;
position: fixed;
left: 0;
top: 0;
}
#sidebar {
width: 12em;
position: fixed;
bottom: 0;
left: 0;
position: fixed;
top: 2.25em;
width: 12em;
top: 4.5em;
}
#main {

View File

@ -37,18 +37,28 @@
}
#header-logo-container {
height: 2.667em;
margin: .1667em 0 .1667em .7em;
width: 100px;
background: inherit;
height: 6em;
padding: 1.25em;
width: 16em;
position: fixed;
left: 0;
margin-top: -3em;
}
#header-logo {
background-image: url('../img/icinga-logo.svg');
background-position: left center;
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
display: block;
height: 100%;
width: 100%;
&:focus {
outline: none;
opacity: .6;
}
}
#icinga-logo {
@ -226,3 +236,88 @@ html.no-js .controls > .tabs {
background-color: @color-notification-warning;
}
}
// Z-Index correction
#main {
z-index: 1;
}
#sidebar {
z-index: 2;
}
// Collpased sidebar
#layout.sidebar-collapsed {
#header-logo-container {
height: 3.167em;
padding: 0.25em 0.125em;
width: 4em;
}
#header-logo {
background-image: url('../img/icinga-logo-compact.svg');
}
#main {
left: 3em;
}
#sidebar {
top: 2.25em;
width: 3em;
}
#open-sidebar {
display: inline;
}
#close-sidebar {
display: none;
}
#menu {
.badge {
display: none;
}
img.icon {
margin: 0 1.25em -.25em 0.25em;
font-size: 1.5em;
}
.nav-item {
white-space: nowrap;
}
.nav-level-1 > .nav-item i {
font-size: 1.5em;
margin-right: .5em;
}
> .search-control {
height: 3.333em;
}
}
#search:focus {
background-color: @gray-lighter;
box-shadow: 0 0 .25em 0 rgba(0, 0, 0, .2);
padding-left: 3.75em;
width: 20em;
position: fixed;
}
.search-input {
font-size: 1.25em;
}
.search-reset {
display: none;
}
.skip-links {
a, button {
width: 20em;
}
}
}

View File

@ -14,20 +14,43 @@
overflow: auto;
}
#menu a {
&:focus {
color: @icinga-blue;
outline-offset: -3px;
#layout:not(.minimal-layout) #menu {
padding-bottom: 2.25em;
}
#menu .nav-item {
vertical-align: middle;
> a {
&:focus {
color: @icinga-blue;
outline: none;
}
&:hover {
color: @icinga-blue;
text-decoration: none;
}
}
&:hover {
color: @icinga-blue;
text-decoration: none;
&.active {
> a {
color: @icinga-blue;
}
}
}
#menu .active > a {
color: @icinga-blue;
#layout:not(.sidebar-collapsed) #menu .nav-item > a {
// Respect overflowing content
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#layout.sidebar-collapsed #menu .nav-level-1 > .nav-item > a {
// Clip overflowing content
overflow: hidden;
width: 4em;
}
#menu .nav-level-1 > .nav-item {
@ -39,11 +62,6 @@
display: none;
}
.nav-level-2 > li {
// Expand menu if active
display: block;
}
background-color: @body-bg-color;
border-color: @icinga-blue;
}
@ -78,9 +96,20 @@
display: block;
}
#layout:not(.sidebar-collapsed) {
#menu .nav-level-1 > .nav-item {
&.active {
.nav-level-2 > li {
// Expand menu if active
display: block;
}
}
}
}
#menu img.icon {
line-height: 1;
margin: 0 0.2em;
margin: 0 0.5em -.05em 0.25em;
width: 1em;
}
@ -104,7 +133,6 @@
}
// Badge offset correction
#menu > nav > .nav-level-1 > .badge-nav-item > a > .badge {
margin-top: 0.2em;
}
@ -114,26 +142,23 @@
}
// Hovered menu
#menu .nav-level-1 > .nav-item.hover {
position: relative;
&:before {
border: 0.5em solid rgba(0, 0, 0, 0);
border-right-color: @text-color;
content: "";
position: absolute;
right: 0;
top: 30%;
}
#layout:not(.minimal-layout).sidebar-collapsed #menu .nav-level-1 > .nav-item:hover,
#layout:not(.minimal-layout) #menu .nav-level-1 > .nav-item:not(.active):hover {
> .nav-level-2 {
&:before {
border: 0.5em solid rgba(0, 0, 0, 0);
border-right-color: @text-color;
content: "";
width: 1em;
position: fixed;
margin-left: -1em;
margin-top: 0.5em;
}
background-color: @text-color;
color: @text-color-inverted;
left: 100%;
padding: @vertical-padding 0;
position: absolute;
top: 0;
position: fixed;
width: 14em;
> .nav-item {
@ -150,19 +175,25 @@
> a > .badge {
display: none;
}
img.icon {
opacity: .6;
}
}
#layout.hoveredmenu {
#main {
z-index: 2;
#layout:not(.minimal-layout) #menu .nav-level-1 > .nav-item:not(.active):hover {
> .nav-level-2 {
// Position relative to parent
margin-left: 15.583em;
margin-top: -3.167em;
}
}
#sidebar {
z-index: 3;
}
#menu {
overflow: visible;
#layout:not(.minimal-layout).sidebar-collapsed #menu .nav-level-1 > .nav-item:hover {
> .nav-level-2 {
// Position relative to parent
margin-left: 3.583em;
margin-top: -3.333em;
}
}
@ -267,3 +298,42 @@ input[type=text].search-input {
transform: none;
}
}
// Toggle sidebar button
#toggle-sidebar {
// Reset button styles
background: none;
border: none;
padding: 0;
color: @gray-light;
position: absolute;
bottom: 0;
right: 0;
i {
background: @body-bg-color;
border-radius: .25em 0 0 .25em;
font-size: 1.5em;
width: 2em;
}
&:focus {
outline: none;
}
&:hover, &:focus {
i {
color: @icinga-blue;
}
}
}
#layout.minimal-layout #toggle-sidebar {
display: none;
}
#open-sidebar {
display: none;
}

View File

@ -106,6 +106,16 @@
#layout.twocols #col2 {
border-left: 1px solid @gray-lighter;
display: block;
> .controls > .tabs:before {
background-color: @icinga-blue;
content: "";
display: block;
height: 3em;
margin-left: -1px;
width: 1px;
position: fixed;
}
}
#layout.twocols > #main > .container {

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="41px" height="35px" viewBox="0 82.75 41 35" enable-background="new 0 82.75 41 35" xml:space="preserve">
<g>
<path fill="none" stroke="#FFFFFF" stroke-width="0.75" d="M17.444,98.987l-7.967,11.424 M17.444,98.987l16.513-4.073
M17.757,99.322l4.624,7.724 M15.795,97.074L9.01,91.52 M18.425,95.846l3.994-8.297"/>
<defs>
<filter id="Adobe_OpacityMaskFilter" filterUnits="userSpaceOnUse" x="5.224" y="107.062" width="7.272" height="7.272">
<feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"/>
</filter>
</defs>
<mask maskUnits="userSpaceOnUse" x="5.224" y="107.062" width="7.272" height="7.272" id="f_1_">
<g filter="url(#Adobe_OpacityMaskFilter)">
<polygon id="e_1_" fill="#FFFFFF" points="5.224,107.062 5.224,114.335 12.497,114.335 12.497,107.062 "/>
</g>
</mask>
<path mask="url(#f_1_)" fill="#FFFFFF" d="M5.234,110.971c-0.151-2.002,1.351-3.747,3.354-3.897
c2.003-0.153,3.749,1.351,3.898,3.353c0.15,2.002-1.35,3.748-3.353,3.898C7.13,114.476,5.384,112.974,5.234,110.971"/>
<path fill="#FFFFFF" d="M21.246,107.127c0.071-0.621,0.632-1.065,1.254-0.994c0.621,0.072,1.065,0.634,0.994,1.254
c-0.074,0.621-0.634,1.065-1.254,0.994C21.619,108.31,21.174,107.748,21.246,107.127 M7.546,92.354
c-0.391-0.799-0.06-1.765,0.74-2.155c0.799-0.392,1.764-0.06,2.156,0.739c0.39,0.799,0.06,1.765-0.74,2.155
C8.902,93.484,7.938,93.152,7.546,92.354 M31.367,94.786c-0.092-1.215,0.819-2.274,2.036-2.367c1.215-0.091,2.275,0.82,2.367,2.036
c0.091,1.216-0.82,2.275-2.037,2.367C32.518,96.913,31.458,96.002,31.367,94.786 M21.386,83.381
c1.202-0.979,2.973-0.799,3.954,0.403c0.98,1.202,0.799,2.974-0.403,3.954c-1.203,0.979-2.974,0.798-3.953-0.404
C20.002,86.131,20.184,84.361,21.386,83.381 M13.79,94.311c2.309-1.882,5.709-1.536,7.594,0.773c1.88,2.31,1.534,5.709-0.774,7.594
c-2.312,1.88-5.711,1.535-7.592-0.776C11.132,99.593,11.481,96.192,13.79,94.311"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -10,9 +10,9 @@
Icinga.EventListener.call(this, icinga);
this.on('click', '#menu a', this.linkClicked, this);
this.on('click', '#menu tr[href]', this.linkClicked, this);
this.on('mouseenter', '#menu > nav > ul > li', this.menuTitleHovered, this);
this.on('mouseleave', '#sidebar', this.leaveSidebar, this);
this.on('rendered', '#menu', this.onRendered, this);
this.on('mouseenter', '#menu .nav-level-1 > .nav-item', this.fixFlyoutPosition, this);
this.on('click', '#toggle-sidebar', this.toggleSidebar, this);
/**
* The DOM-Path of the active item
@ -23,15 +23,6 @@
*/
this.active = null;
/**
* The DOM-Path of the hovered item
*
* @see getDomPath
*
* @type {null|Array}
*/
this.hovered = null;
/**
* The menu
*
@ -39,6 +30,7 @@
*/
this.$menu = null;
};
Navigation.prototype = new Icinga.EventListener();
/**
@ -71,7 +63,7 @@
};
/**
* Re-render the menu selection and menu hovering according to the current state
* Re-render the menu selection according to the current state
*/
Navigation.prototype.refresh = function() {
// restore selection to current active element
@ -89,14 +81,6 @@
$el.html($el.html());
}
}
// restore hovered menu to current hovered element
if (this.hovered) {
var hovered = this.icinga.utils.getElementByDomPath(this.hovered);
if (hovered) {
this.hoverElement($(hovered));
}
}
};
/**
@ -107,26 +91,13 @@
Navigation.prototype.linkClicked = function(event) {
var $a = $(this);
var href = $a.attr('href');
var $li;
var _this = event.data.self;
var icinga = _this.icinga;
_this.hovered = null;
if (href.match(/#/)) {
// ...it may be a menu section without a dedicated link.
// Switch the active menu item:
_this.setActive($a);
$li = $a.closest('li');
if ($li.hasClass('hover')) {
$li.removeClass('hover');
}
if (href === '#') {
// Allow to access dropdown menu by keyboard
if ($a.hasClass('dropdown-toggle')) {
$a.closest('li').toggleClass('hover');
}
return;
}
} else {
_this.setActive($(event.target));
}
@ -233,6 +204,32 @@
this.active = null;
};
/**
* Fix top position of the flyout menu
*
* @param e
*/
Navigation.prototype.fixFlyoutPosition = function(e) {
var $target = $(this);
var $flyout = $target.find('.nav-level-2');
if ($flyout.length) {
$flyout.css({
top: $target.offset().top + $target.outerHeight()
});
}
};
/**
* Collapse or expand sidebar
*
* @param {Object} e Event
*/
Navigation.prototype.toggleSidebar = function(e) {
$('#layout').toggleClass('sidebar-collapsed');
$(window).trigger('resize');
};
/**
* Called when the history changes
*
@ -267,87 +264,6 @@
return this.active;
};
Navigation.prototype.menuTitleHovered = function(event) {
if ($('#layout').hasClass('minimal-layout')) {
return;
}
var $li = $(this),
delay = 800,
_this = event.data.self;
_this.hovered = null;
if ($li.hasClass('active')) {
$li.siblings().removeClass('hover');
return;
}
if ($li.children('ul').children('li').length === 0) {
return;
}
if ($('#menu').scrollTop() > 0) {
return;
}
if ($('#layout').hasClass('hoveredmenu')) {
delay = 0;
}
setTimeout(function () {
try {
if (!$li.is('li:hover')) {
return;
}
if ($li.hasClass('active')) {
return;
}
} catch(e) { /* Bypass because if IE8 */ }
$li.siblings().each(function () {
var $sibling = $(this);
try {
if ($sibling.is('li:hover')) {
return;
}
} catch(e) { /* Bypass because if IE8 */ };
if ($sibling.hasClass('hover')) {
$sibling.removeClass('hover');
}
});
_this.hoverElement($li);
}, delay);
};
Navigation.prototype.leaveSidebar = function (event) {
var $sidebar = $(this),
$li = $sidebar.find('li.hover'),
_this = event.data.self;
if (! $li.length) {
$('#layout').removeClass('hoveredmenu');
return;
}
setTimeout(function () {
try {
if ($li.is('li:hover') || $sidebar.is('sidebar:hover')) {
return;
}
} catch(e) { /* Bypass because if IE8 */ };
$li.removeClass('hover');
$('#layout').removeClass('hoveredmenu');
}, 500);
_this.hovered = null;
};
Navigation.prototype.hoverElement = function ($li) {
$('#layout').addClass('hoveredmenu');
$li.addClass('hover');
if ($li[0]) {
this.hovered = this.icinga.utils.getDomPath($li[0]);
} else {
this.hovered = null;
}
};
Icinga.Behaviors.Navigation = Navigation;
}) (Icinga, jQuery);
})(Icinga, jQuery);

View File

@ -579,7 +579,7 @@
if (typeof $container === 'undefined') {
var $header = $('#header');
var $headerLogo = $('#header-logo');
var $headerLogo = $('#header-logo-container');
var $main = $('#main');
var $search = $('#search');
var $sidebar = $('#sidebar');
@ -595,8 +595,7 @@
display: 'none'
});
$main.css({
top: $header.height() + $sidebar.outerHeight(),
zIndex: 2
top: $header.outerHeight() + $sidebar.outerHeight()
});
$sidebar
.on(
@ -611,16 +610,14 @@
this.mobileMenu = true;
}
} else {
$headerLogo.css({
top: $header.css('height')
});
$main.css({
top: $header.css('height'),
zIndex: ''
top: $header.css('height')
});
$sidebar.css({
top: $header.css('height'),
zIndex: ''
});
$header.css({
height: $header.height() + 'px'
top: $headerLogo.offset().top + $headerLogo.outerHeight()
});
if (this.mobileMenu) {
@ -657,7 +654,7 @@
var $controls = $(this);
var $fakeControls = $controls.next('.fake-controls');
$controls.css({
top: $container.offset().top,
top: $container.offsetParent().position().top,
width: $fakeControls.outerWidth()
});
$fakeControls.height($controls.height());