Merge pull request #7723 from cjcenizal/7467/pin-sidebar-functionality

[7467] Add "Collapse/Expand" button to sidebar.
This commit is contained in:
CJ Cenizal 2016-08-18 12:52:35 -07:00 committed by GitHub
commit 962f036f42
24 changed files with 381 additions and 250 deletions

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
<path d="M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-1 2l3 2-3 2v-4z" />
</svg>

After

Width:  |  Height:  |  Size: 176 B

View file

@ -100,6 +100,7 @@ app.directive('dashboardGrid', function ($compile, Notifier) {
safeLayout();
$window.on('resize', safeLayout);
$scope.$on('ready:vis', safeLayout);
$scope.$on('globalNav:update', safeLayout);
}
// return the panel object for an element.

View file

@ -1,45 +0,0 @@
<div class="content" chrome-context >
<!-- TODO: These config dropdowns shouldn't be hard coded -->
<nav class="app-links-wrapper" ng-show="chrome.getVisible()">
<li
ng-if="!chrome.getBrand('logo') && !chrome.getBrand('smallLogo')"
aria-label="{{ chrome.getAppTitle() }} Logo"
class="logo kibana"
></li>
<li
ng-if="chrome.getBrand('logo')"
ng-style="{ 'background': chrome.getBrand('logo') }"
aria-label="{{ chrome.getAppTitle() }} Logo"
class="logo hidden-sm"
></li>
<li
ng-if="chrome.getBrand('smallLogo')"
ng-style="{ 'background': chrome.getBrand('smallLogo') }"
aria-label="{{ chrome.getAppTitle() }} Logo"
class="logo-small visible-sm hidden-xs"
></li>
<app-switcher>
</app-switcher>
<div class="bottom-apps">
<div class="chrome-actions" kbn-chrome-append-nav-controls></div>
</div>
</nav>
<div class="app-wrapper" ng-class="{ 'hidden-chrome': !chrome.getVisible() }">
<div class="app-wrapper-panel">
<kbn-notifications list="notifList"></kbn-notifications>
<kbn-loading-indicator></kbn-loading-indicator>
<div
class="application"
ng-class="'tab-' + chrome.getFirstPathSegment() + ' ' + chrome.getApplicationClasses()"
ng-view
></div>
</div>
</div>
</div>

View file

@ -10,8 +10,10 @@ import 'ui/timefilter';
import 'ui/notify';
import 'ui/private';
import 'ui/promises';
import 'ui/storage';
import 'ui/directives/kbn_src';
import 'ui/watch_multi';
import './services';
let chrome = {};
let internals = _.defaults(

View file

@ -1,11 +0,0 @@
<app-switcher-link
ng-repeat="link in switcher.shownNavLinks"
app-switcher-link-is-active="link.active"
app-switcher-link-is-disabled="!switcher.isNavLinkEnabled(link)"
app-switcher-link-tooltip="link.tooltip"
app-switcher-link-on-click="switcher.ensureNavigation($event, link)"
app-switcher-link-href="link.active ? link.url : (link.lastSubUrl || link.url)"
app-switcher-link-icon="link.icon"
app-switcher-link-title="link.title"
></app-switcher-link>

View file

@ -1,72 +0,0 @@
@import (reference) "~ui/styles/mixins";
@import (reference) "~ui/styles/variables";
body { overflow-x: hidden; }
.app-links-wrapper {
width: @as-open-width;
position: fixed;
left: 0;
top: 0;
bottom: 0;
z-index: 0;
background-color: @app-links-wrapper-background;
overflow: hidden;
transition: width @transition-time;
transition-delay: @transition-delay;
&:hover {
.app-title {
display: inline-block;
}
+ .app-wrapper {
transform: translateX(@as-open-width - @as-closed-width);
}
}
.logo-small,
.logo {
height: 70px;
width: @as-open-width;
list-style-type: none;
&.kibana {
background-image: url("~ui/images/kibana.svg");
background-position: 6px 10px;
background-size: 140px 50px;
background-repeat: no-repeat;
background-color: #e8488b;
}
}
.bottom-apps {
position: absolute;
bottom: 0;
}
}
.app-wrapper {
.real-flex-parent();
position: absolute;
transition: transform @transition-time;
transition-delay: @transition-delay;
left: @as-closed-width;
top: 0;
right: 0;
bottom: 0;
z-index: 1;
margin: 0 auto;
background-color: #fff;
&.hidden-chrome {
left: 0;
}
.navbar-right {
margin-right: 0;
}
}
.app-wrapper-panel {
.flex-parent(@shrink: 0);
box-shadow: -4px 0px 3px rgba(0,0,0,0.2);
}

View file

@ -1,35 +0,0 @@
import appSwitcherLinkTemplate from './app_switcher_link.html';
import './app_switcher_link.less';
import uiModules from 'ui/modules';
const module = uiModules.get('kibana');
module.directive('appSwitcherLink', chrome => {
return {
restrict: 'E',
replace: true,
scope: {
isActive: '=appSwitcherLinkIsActive',
isDisabled: '=appSwitcherLinkIsDisabled',
tooltip: '=appSwitcherLinkTooltip',
onClick: '&appSwitcherLinkOnClick',
href: '=appSwitcherLinkHref',
kbnRoute: '=appSwitcherLinkKbnRoute',
icon: '=appSwitcherLinkIcon',
title: '=appSwitcherLinkTitle'
},
template: appSwitcherLinkTemplate,
link: scope => {
scope.getHref = () => {
if (scope.href) {
return scope.href;
}
if (scope.kbnRoute) {
return chrome.addBasePath(scope.kbnRoute);
}
};
}
};
});

View file

@ -26,7 +26,7 @@ describe('appSwitcher directive', function () {
env = {
$scope: $rootScope,
$el: $compile($('<app-switcher>'))($rootScope),
$el: $compile($('<app-switcher chrome="chrome">'))($rootScope),
currentHref: href,
location: domLocation
};

View file

@ -0,0 +1,11 @@
<global-nav-link
ng-repeat="link in switcher.shownNavLinks"
is-active="link.active"
is-disabled="!switcher.isNavLinkEnabled(link)"
tooltip-content="switcher.getTooltip(link)"
on-click="switcher.ensureNavigation($event, link)"
href="link.active ? link.url : (link.lastSubUrl || link.url)"
icon="link.icon"
title="link.title"
></global-nav-link>

View file

@ -1,7 +1,6 @@
import DomLocationProvider from 'ui/dom_location';
import { parse } from 'url';
import { bindKey } from 'lodash';
import './app_switcher.less';
import uiModules from 'ui/modules';
import appSwitcherTemplate from './app_switcher.html';
@ -55,11 +54,12 @@ uiModules
.directive('appSwitcher', function () {
return {
restrict: 'E',
scope: {
chrome: '=',
},
template: appSwitcherTemplate,
controllerAs: 'switcher',
controller($scope, appSwitcherEnsureNavigation) {
// since we render this in an isolate scope we can't "require: ^chrome", but
// rather than remove all helpfull checks we can just check here.
controller($scope, appSwitcherEnsureNavigation, globalNavState) {
if (!$scope.chrome || !$scope.chrome.getNavLinks) {
throw new TypeError('appSwitcher directive requires the "chrome" config-object');
}
@ -72,6 +72,15 @@ uiModules
// links don't cause full-navigation events in certain scenarios
// so we force them when needed
this.ensureNavigation = appSwitcherEnsureNavigation;
this.getTooltip = link => {
// If the sidebar is open then we don't need to show the title because
// it will already be visible.
if (globalNavState.isOpen()) {
return link.tooltip;
}
return link.tooltip ? link.title + ' - ' + link.tooltip : link.title;
};
}
};
});

View file

@ -0,0 +1,46 @@
<nav
class="global-nav"
ng-class="{'is-global-nav-open': isGlobalNavOpen}"
ng-show="isVisible"
>
<!-- Logo -->
<li
ng-if="!logoBrand && !smallLogoBrand"
aria-label="{{ appTitle }} Logo"
class="logo kibana"
></li>
<li
ng-if="logoBrand"
ng-style="{ 'background': logoBrand }"
aria-label="{{ appTitle }} Logo"
class="logo hidden-sm"
></li>
<li
ng-if="smallLogoBrand"
ng-style="{ 'background': smallLogoBrand }"
aria-label="{{ appTitle }} Logo"
class="logo-small visible-sm hidden-xs"
></li>
<!-- Main apps -->
<app-switcher
chrome="chrome"
></app-switcher>
<!-- Bottom button -->
<div class="gloal-nav__bottom-links">
<div class="chrome-actions" kbn-chrome-append-nav-controls></div>
<!-- Open/close sidebar -->
<global-nav-link
class="{{ globalNavToggleButton.classes }}"
tooltip-content="globalNavToggleButton.tooltipContent"
on-click="toggleGlobalNav($event)"
icon="'/plugins/kibana/assets/play-circle.svg'"
title="globalNavToggleButton.title"
></global-nav-link>
</div>
</nav>

View file

@ -0,0 +1,51 @@
import './app_switcher';
import './global_nav_link';
import globalNavTemplate from './global_nav.html';
import './global_nav.less';
import uiModules from 'ui/modules';
const module = uiModules.get('kibana');
module.directive('globalNav', globalNavState => {
return {
restrict: 'E',
replace: true,
scope: {
chrome: '=',
isVisible: '=',
logoBrand: '=',
smallLogoBrand: '=',
appTitle: '=',
},
template: globalNavTemplate,
link: scope => {
// App switcher functionality.
function updateGlobalNav() {
const isOpen = globalNavState.isOpen();
scope.isGlobalNavOpen = isOpen;
scope.globalNavToggleButton = {
classes: isOpen ? 'global-nav-link--close' : undefined,
title: isOpen ? 'Collapse' : 'Expand',
tooltipContent: isOpen ? 'Collapse side bar' : 'Expand side bar',
};
// Notify visualizations, e.g. the dashboard, that they should re-render.
scope.$root.$broadcast('globalNav:update');
}
updateGlobalNav();
scope.$root.$on('globalNavState:change', () => {
updateGlobalNav();
});
scope.toggleGlobalNav = event => {
event.preventDefault();
globalNavState.setOpen(!globalNavState.isOpen());
};
}
};
});

View file

@ -0,0 +1,44 @@
@import (reference) "~ui/styles/variables";
.global-nav {
width: @as-closed-width;
position: fixed;
left: 0;
top: 0;
bottom: 0;
z-index: 0;
background-color: @app-links-wrapper-background;
overflow: hidden;
&.is-global-nav-open {
width: @as-open-width;
.app-title {
display: inline-block;
}
+ .app-wrapper {
left: @as-open-width;
}
}
.logo-small,
.logo {
height: 70px;
width: @as-open-width;
list-style-type: none;
&.kibana {
background-image: url("~ui/images/kibana.svg");
background-position: 6px 10px;
background-size: 140px 50px;
background-repeat: no-repeat;
background-color: #e8488b;
}
}
}
.gloal-nav__bottom-links {
position: absolute;
bottom: 0;
}

View file

@ -2,9 +2,9 @@ import sinon from 'auto-release-sinon';
import ngMock from 'ng_mock';
import expect from 'expect.js';
import '../app_switcher_link';
import '../global_nav_link';
describe('appSwitcherLink directive', () => {
describe('globalNavLink directive', () => {
let scope;
let $compile;
@ -19,15 +19,15 @@ describe('appSwitcherLink directive', () => {
function create(attrs) {
const template = `
<app-switcher-link
app-switcher-link-is-active="appSwitcherLinkIsActive"
app-switcher-link-is-disabled="appSwitcherLinkIsDisabled"
app-switcher-link-tooltip="appSwitcherLinkTooltip"
app-switcher-link-on-click="appSwitcherLinkOnClick()"
app-switcher-link-href="appSwitcherLinkHref"
app-switcher-link-kbn-route="appSwitcherLinkKbnRoute"
app-switcher-link-icon="appSwitcherLinkIcon"
app-switcher-link-title="appSwitcherLinkTitle"
<global-nav-link
is-active="isActive"
is-disabled="isDisabled"
tooltip-content="tooltipContent"
on-click="onClick()"
href="href"
kbn-route="kbnRoute"
icon="icon"
title="title"
/>
`;
@ -42,96 +42,96 @@ describe('appSwitcherLink directive', () => {
describe('interface', () => {
describe('appSwitcherLinkIsActive attribute', () => {
describe('isActive attribute', () => {
it(`doesn't apply the active class when false`, () => {
const element = create({
appSwitcherLinkIsActive: false,
isActive: false,
});
expect(element.hasClass('active')).to.be(false);
});
it('applies the active class when true', () => {
const element = create({
appSwitcherLinkIsActive: true,
isActive: true,
});
expect(element.hasClass('active')).to.be(true);
});
});
describe('appSwitcherLinkIsDisabled attribute', () => {
it(`doesn't apply the is-app-switcher-link-disabled class when false`, () => {
describe('isDisabled attribute', () => {
it(`doesn't apply the is-global-nav-link-disabled class when false`, () => {
const element = create({
appSwitcherLinkIsDisabled: false,
isDisabled: false,
});
expect(element.hasClass('is-app-switcher-link-disabled')).to.be(false);
expect(element.hasClass('is-global-nav-link-disabled')).to.be(false);
});
it('applies the is-app-switcher-link-disabled class when true', () => {
it('applies the is-global-nav-link-disabled class when true', () => {
const element = create({
appSwitcherLinkIsDisabled: true,
isDisabled: true,
});
expect(element.hasClass('is-app-switcher-link-disabled')).to.be(true);
expect(element.hasClass('is-global-nav-link-disabled')).to.be(true);
});
});
describe('appSwitcherLinkTooltip attribute', () => {
describe('tooltipContent attribute', () => {
it('is applied to the tooltip directive', () => {
const attrs = {
appSwitcherLinkTooltip: 'hello i am a tooltip',
tooltipContent: 'hello i am a tooltip',
};
const element = create(attrs);
expect(element.attr('tooltip')).to.be(attrs.appSwitcherLinkTooltip);
expect(element.attr('tooltip')).to.be(attrs.tooltipContent);
});
});
describe('appSwitcherLinkOnClick attribute', () => {
describe('onClick attribute', () => {
it('is called when the link is clicked', () => {
const attrs = {
appSwitcherLinkOnClick: sinon.spy(),
onClick: sinon.spy(),
};
const element = create(attrs);
element.find('[data-test-subj=appLink]').click();
sinon.assert.called(attrs.appSwitcherLinkOnClick);
sinon.assert.called(attrs.onClick);
});
});
describe('appSwitcherLinkHref attribute', () => {
describe('href attribute', () => {
it('is applied to the link', () => {
const attrs = {
appSwitcherLinkHref: 'link to a website',
href: 'link to a website',
};
const element = create(attrs);
const link = element.find('[data-test-subj=appLink]');
expect(link.attr('href')).to.be(attrs.appSwitcherLinkHref);
expect(link.attr('href')).to.be(attrs.href);
});
});
describe('appSwitcherLinkKbnRoute attribute', () => {
describe('kbnRoute attribute', () => {
it(`is applied to the link when href isn't defined`, () => {
const attrs = {
appSwitcherLinkKbnRoute: '#test',
kbnRoute: '#test',
};
const element = create(attrs);
const link = element.find('[data-test-subj=appLink]');
expect(link.attr('href')).to.be(attrs.appSwitcherLinkKbnRoute);
expect(link.attr('href')).to.be(attrs.kbnRoute);
});
it(`isn't applied to the link when href is defined`, () => {
const attrs = {
appSwitcherLinkHref: 'link to a website',
appSwitcherLinkKbnRoute: '#test',
href: 'link to a website',
kbnRoute: '#test',
};
const element = create(attrs);
const link = element.find('[data-test-subj=appLink]');
expect(link.attr('href')).not.to.be(attrs.appSwitcherLinkKbnRoute);
expect(link.attr('href')).not.to.be(attrs.kbnRoute);
});
});
describe('appSwitcherLinkIcon attribute', () => {
describe('icon attribute', () => {
describe('when present', () => {
it('displays the img element', () => {
const attrs = {
appSwitcherLinkIcon: 'icon url',
icon: 'icon url',
};
const element = create(attrs);
const img = element.find('img');
@ -140,7 +140,7 @@ describe('appSwitcherLink directive', () => {
it('hides the placeholder', () => {
const attrs = {
appSwitcherLinkIcon: 'icon url',
icon: 'icon url',
};
const element = create(attrs);
const placeholder = element.find('[data-test-subj=appLinkIconPlaceholder]');
@ -149,18 +149,18 @@ describe('appSwitcherLink directive', () => {
it(`is set as the img src`, () => {
const attrs = {
appSwitcherLinkIcon: 'icon url',
icon: 'icon url',
};
const element = create(attrs);
const img = element.find('img');
expect(img.attr('src')).to.contain(encodeURI(attrs.appSwitcherLinkIcon));
expect(img.attr('src')).to.contain(encodeURI(attrs.icon));
});
});
describe('when not present', () => {
it('hides the img element', () => {
const attrs = {
appSwitcherLinkIcon: undefined,
icon: undefined,
};
const element = create(attrs);
const img = element.find('img');
@ -169,7 +169,7 @@ describe('appSwitcherLink directive', () => {
it('displays the placeholder', () => {
const attrs = {
appSwitcherLinkIcon: undefined,
icon: undefined,
};
const element = create(attrs);
const placeholder = element.find('[data-test-subj=appLinkIconPlaceholder]');
@ -178,33 +178,33 @@ describe('appSwitcherLink directive', () => {
it(`uses the title's first letter as the placeholder`, () => {
const attrs = {
appSwitcherLinkIcon: undefined,
appSwitcherLinkTitle: 'Xyz',
icon: undefined,
title: 'Xyz',
};
const element = create(attrs);
const placeholder = element.find('[data-test-subj=appLinkIconPlaceholder]');
expect(placeholder.text()).to.contain(attrs.appSwitcherLinkTitle[0]);
expect(placeholder.text()).to.contain(attrs.title[0]);
});
});
});
describe('appSwitcherLinkTitle attribute', () => {
describe('title attribute', () => {
it('is displayed', () => {
const attrs = {
appSwitcherLinkTitle: 'demo title',
title: 'demo title',
};
const element = create(attrs);
const title = element.find('.app-switcher-link__title');
expect(title.text().trim()).to.be(attrs.appSwitcherLinkTitle);
const title = element.find('.global-nav-link__title');
expect(title.text().trim()).to.be(attrs.title);
});
it('is set as a title attribute on the anchor tag', () => {
const attrs = {
appSwitcherLinkTitle: 'demo title',
title: 'demo title',
};
const element = create(attrs);
const link = element.find('[data-test-subj=appLink]');
expect(link.attr('title')).to.be(attrs.appSwitcherLinkTitle);
expect(link.attr('title')).to.be(attrs.title);
});
});
});

View file

@ -1,35 +1,35 @@
<div
class="app-switcher-link"
ng-class="{ active: isActive, 'is-app-switcher-link-disabled': isDisabled }"
tooltip="{{ tooltip }}"
class="global-nav-link {{classes}}"
ng-class="{ active: isActive, 'is-global-nav-link-disabled': isDisabled }"
tooltip="{{ tooltipContent }}"
tooltip-placement="right"
tooltip-popup-delay="400"
tooltip-popup-delay="0"
tooltip-append-to-body="1"
>
<a
class="app-switcher-link__anchor"
class="global-nav-link__anchor"
href="{{ getHref() }}"
ng-click="onClick({ $event: $event })"
data-test-subj="appLink"
title="{{ title }}"
>
<div class="app-switcher-link__icon">
<div class="global-nav-link__icon">
<img
ng-if="icon"
class="app-switcher-link__icon-image"
class="global-nav-link__icon-image"
kbn-src="{{ '/' + icon }}"
>
<span
ng-if="!icon"
class="app-switcher-link__icon-placeholder"
class="global-nav-link__icon-placeholder"
data-test-subj="appLinkIconPlaceholder"
>
{{ title[0] }}
</span>
</div>
<div class="app-switcher-link__title">
<div class="global-nav-link__title">
{{ title }}
</div>
</a>

View file

@ -0,0 +1,35 @@
import globalNavLinkTemplate from './global_nav_link.html';
import './global_nav_link.less';
import uiModules from 'ui/modules';
const module = uiModules.get('kibana');
module.directive('globalNavLink', chrome => {
return {
restrict: 'E',
replace: true,
scope: {
isActive: '=',
isDisabled: '=',
tooltipContent: '=',
onClick: '&',
href: '=',
kbnRoute: '=',
icon: '=',
title: '=',
},
template: globalNavLinkTemplate,
link: scope => {
scope.getHref = () => {
if (scope.href) {
return scope.href;
}
if (scope.kbnRoute) {
return chrome.addBasePath(scope.kbnRoute);
}
};
}
};
});

View file

@ -1,14 +1,15 @@
@import (reference) "~ui/styles/variables";
.app-switcher-link {
width: @as-open-width;
.global-nav-link {
position: relative;
width: @as-closed-width;
height: @app-icon-height;
line-height: @app-line-height;
&.is-app-switcher-link-disabled {
&.is-global-nav-link-disabled {
opacity: 0.5;
.app-switcher-link__anchor {
.global-nav-link__anchor {
cursor: default;
}
}
@ -17,27 +18,30 @@
&.active {
background-color: @app-links-active-background;
.app-switcher-link__anchor {
.global-nav-link__anchor {
color: @white;
text-decoration: none;
}
}
}
.app-switcher-link__anchor {
.is-global-nav-open {
.global-nav-link {
width: @as-open-width;
}
}
.global-nav-link__anchor {
display: block;
height: 100%;
color: #ebf7fa;
/**
* 1. TODO: Override anchor styles. Fix this by removing a tag styles.
*/
&:focus {
color: #ebf7fa; /* 1 */
color: @white;
}
}
.app-switcher-link__icon {
.global-nav-link__icon {
display: inline-block;
width: @as-closed-width;
height: @app-icon-height;
@ -49,7 +53,7 @@
/**
* This imgae is used to display the icon.
*/
.app-switcher-link__icon-image {
.global-nav-link__icon-image {
height: 18px;
margin-top: 8px;
filter: invert(100%);
@ -58,20 +62,33 @@
/**
* This placeholder text gets shown if there is no specified icon.
*/
.app-switcher-link__icon-placeholder {
.global-nav-link__icon-placeholder {
line-height: @app-icon-height;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
}
.app-switcher-link__title {
.global-nav-link__title {
display: none;
width: calc(@as-open-width - @as-closed-width);
display: inline-block;
float: right;
font-size: 0.9em;
text-align: left;
padding-left: 3px;
line-height: @app-icon-height;
white-space: nowrap;
.is-global-nav-open & {
display: inline-block;
}
}
.global-nav-link--close {
/**
* 1. Translation accounts for the icon image being slightly off-center.
*/
.global-nav-link__icon {
transform: translateX(1px) scaleX(-1); /* 1 */
}
}

View file

@ -1,5 +1,6 @@
import './app_switcher';
import './app_switcher_link';
import './global_nav';
import kbnChromeProv from './kbn_chrome';
import kbnChromeNavControlsProv from './append_nav_controls';
import './kbn_loading_indicator';

View file

@ -0,0 +1,21 @@
<div class="content" chrome-context >
<global-nav
chrome="chrome"
is-visible="chrome.getVisible()"
logo-brand="chrome.getBrand('logo')"
small-logo-brand="chrome.getBrand('smallLogo')"
app-title="chrome.getAppTitle()"
></global-nav>
<div class="app-wrapper" ng-class="{ 'hidden-chrome': !chrome.getVisible() }">
<div class="app-wrapper-panel">
<kbn-notifications list="notifList"></kbn-notifications>
<kbn-loading-indicator></kbn-loading-indicator>
<div
class="application"
ng-class="'tab-' + chrome.getFirstPathSegment() + ' ' + chrome.getApplicationClasses()"
ng-view
></div>
</div>
</div>
</div>

View file

@ -1,15 +1,16 @@
import $ from 'jquery';
import './kbn_chrome.less';
import UiModules from 'ui/modules';
export default function (chrome, internals) {
UiModules
.get('kibana')
.directive('kbnChrome', function ($rootScope) {
.directive('kbnChrome', $rootScope => {
return {
template($el) {
const $content = $(require('ui/chrome/chrome.html'));
const $content = $(require('./kbn_chrome.html'));
const $app = $content.find('.application');
if (internals.rootController) {
@ -43,6 +44,7 @@ export default function (chrome, internals) {
// and some local values
chrome.httpActive = $http.pendingRequests;
$scope.notifList = require('ui/notify')._notifs;
return chrome;
}
};

View file

@ -0,0 +1,34 @@
@import (reference) "~ui/styles/mixins";
@import (reference) "~ui/styles/variables";
body { overflow-x: hidden; }
.app-wrapper {
.real-flex-parent();
position: absolute;
left: @as-closed-width;
top: 0;
right: 0;
bottom: 0;
z-index: 1;
margin: 0 auto;
background-color: #fff;
/**
* 1. Dirty, but we need to override the .is-global-nav-open state
* when we're looking at the log-in screen.
*/
&.hidden-chrome {
left: 0 !important; /* 1 */
}
.navbar-right {
margin-right: 0;
}
}
.app-wrapper-panel {
.flex-parent(@shrink: 0);
box-shadow: -4px 0px 3px rgba(0,0,0,0.2);
}

View file

@ -0,0 +1,18 @@
import modules from 'ui/modules';
import angular from 'angular';
modules.get('kibana')
.service('globalNavState', (localStorage, $rootScope) => {
return {
isOpen: () => {
return localStorage.get('kibana.isGlobalNavOpen');
},
setOpen: isOpen => {
localStorage.set('kibana.isGlobalNavOpen', isOpen);
$rootScope.$broadcast('globalNavState:change');
return isOpen;
}
};
});

View file

@ -0,0 +1 @@
import './global_nav_state';

View file

@ -342,7 +342,5 @@
@as-closed-width: 53px;
@app-icon-height: 38px;
@app-line-height: 24px;
@transition-time: .35s;
@transition-delay: .25s;
@app-links-wrapper-background: #3caed2;
@app-links-active-background: #2f99c1;