mirror of
https://github.com/kemko/nomad.git
synced 2026-01-07 02:45:42 +03:00
Merge pull request #4536 from hashicorp/f-ui-mobile-views
UI: Mobile Views
This commit is contained in:
5
ui/app/components/global-header.js
Normal file
5
ui/app/components/global-header.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
onHamburgerClick() {},
|
||||
});
|
||||
@@ -32,6 +32,8 @@ export default Component.extend({
|
||||
});
|
||||
}),
|
||||
|
||||
onHamburgerClick() {},
|
||||
|
||||
gotoJobsForNamespace(namespace) {
|
||||
if (!namespace || !namespace.get('id')) return;
|
||||
|
||||
|
||||
@@ -2,4 +2,6 @@ import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ['page-layout'],
|
||||
|
||||
isGutterOpen: false,
|
||||
});
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
@import './components/empty-message';
|
||||
@import './components/error-container';
|
||||
@import './components/gutter';
|
||||
@import './components/gutter-toggle';
|
||||
@import './components/inline-definitions';
|
||||
@import './components/job-diff';
|
||||
@import './components/json-viewer';
|
||||
@import './components/loading-spinner';
|
||||
@import './components/metrics';
|
||||
@import './components/node-status-light';
|
||||
@import './components/nomad-logo';
|
||||
@import './components/page-layout';
|
||||
@import './components/simple-list';
|
||||
@import './components/status-text';
|
||||
|
||||
19
ui/app/styles/components/gutter-toggle.scss
Normal file
19
ui/app/styles/components/gutter-toggle.scss
Normal file
@@ -0,0 +1,19 @@
|
||||
.gutter-toggle {
|
||||
display: none;
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
padding: 1.25rem 0.7rem;
|
||||
z-index: 1; // Make sure the toggle is on top of its siblings
|
||||
height: 100%;
|
||||
fill: desaturate(lighten($nomad-green, 20%), 30%);
|
||||
cursor: pointer;
|
||||
|
||||
> svg {
|
||||
width: 15px;
|
||||
}
|
||||
|
||||
@media #{$mq-hidden-gutter} {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,74 @@
|
||||
.gutter {
|
||||
height: 100%;
|
||||
border-right: 1px solid $grey-blue;
|
||||
overflow: hidden;
|
||||
|
||||
@media #{$mq-hidden-gutter} {
|
||||
border-right: none;
|
||||
|
||||
&.is-open {
|
||||
box-shadow: 0 0 30px darken($nomad-green-darker, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
.collapsed-menu {
|
||||
display: none;
|
||||
position: relative;
|
||||
height: 3.5rem;
|
||||
width: $gutter-width;
|
||||
transform: translateX($gutter-width);
|
||||
z-index: $z-gutter;
|
||||
transition: transform ease-in-out 0.2s;
|
||||
|
||||
&.is-open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.gutter-toggle {
|
||||
fill: $grey-light;
|
||||
}
|
||||
|
||||
.nomad-logo {
|
||||
fill: $grey-light;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
padding: 0.5rem 1rem;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
@media #{$mq-hidden-gutter} {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
z-index: $z-gutter;
|
||||
}
|
||||
}
|
||||
|
||||
// Treated as an element of the gutter component despite not being nested within
|
||||
// for z-index reasons.
|
||||
.gutter-backdrop {
|
||||
display: block;
|
||||
position: fixed;
|
||||
background: darken($nomad-green-darker, 10%);
|
||||
opacity: 0;
|
||||
width: calc(100vw + #{$gutter-width});
|
||||
height: 100vh;
|
||||
top: 0;
|
||||
left: 0;
|
||||
transform: translateY(-100%);
|
||||
transition: opacity ease-in-out 0.2s;
|
||||
z-index: $z-gutter-backdrop;
|
||||
|
||||
@media #{$mq-hidden-gutter} {
|
||||
&.is-open {
|
||||
transform: translateY(0);
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
9
ui/app/styles/components/nomad-logo.scss
Normal file
9
ui/app/styles/components/nomad-logo.scss
Normal file
@@ -0,0 +1,9 @@
|
||||
.nomad-logo {
|
||||
height: 26px;
|
||||
max-height: 26px;
|
||||
fill: $white;
|
||||
|
||||
.faded {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,28 @@
|
||||
bottom: 0;
|
||||
top: $header-height;
|
||||
z-index: $z-gutter;
|
||||
background: $white;
|
||||
}
|
||||
|
||||
&.is-right {
|
||||
margin-left: $gutter-width;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@media #{$mq-hidden-gutter} {
|
||||
&.is-left {
|
||||
top: 0;
|
||||
transform: translateX(-$gutter-width);
|
||||
transition: transform ease-in-out 0.2s;
|
||||
|
||||
&.is-open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-right {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
.navbar {
|
||||
display: flex;
|
||||
|
||||
&.is-primary {
|
||||
background: linear-gradient(to right, $nomad-green-darker, $nomad-green-dark);
|
||||
height: 3.5rem;
|
||||
color: $primary-invert;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
overflow: hidden;
|
||||
|
||||
.navbar-item {
|
||||
color: rgba($primary-invert, 0.8);
|
||||
@@ -35,11 +38,13 @@
|
||||
top: 1.25em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.is-logo img {
|
||||
height: 26px;
|
||||
max-height: 26px;
|
||||
}
|
||||
.navbar-end {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: flex-end;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.navbar-end > a.navbar-item {
|
||||
@@ -65,8 +70,15 @@
|
||||
}
|
||||
|
||||
.navbar-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.is-gutter {
|
||||
width: $gutter-width;
|
||||
|
||||
@media #{$mq-hidden-gutter} {
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,5 +42,9 @@
|
||||
+ * {
|
||||
margin-top: 5em;
|
||||
}
|
||||
|
||||
@media #{$mq-hidden-gutter} {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,3 +39,5 @@ $breadcrumb-item-color: $white;
|
||||
$breadcrumb-item-hover-color: $white;
|
||||
$breadcrumb-item-active-color: $white;
|
||||
$breadcrumb-item-separator-color: $primary;
|
||||
|
||||
$mq-hidden-gutter: 'only screen and (max-width : 960px)';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
$z-tooltip: 250;
|
||||
$z-header: 200;
|
||||
$z-gutter: 200;
|
||||
$z-header: 210;
|
||||
$z-gutter: 220;
|
||||
$z-gutter-backdrop: 219;
|
||||
$z-subnav: 200;
|
||||
$z-base: 100;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{{#freestyle-usage "header" title="Global Header"}}
|
||||
<nav class="navbar is-primary">
|
||||
<div class="navbar-brand">
|
||||
<span class="gutter-toggle" aria-label="menu">
|
||||
{{partial "partials/hamburger-menu"}}
|
||||
</span>
|
||||
<span class="navbar-item is-logo">
|
||||
<img src="/ui/images/nomad-logo.svg" alt="Nomad" />
|
||||
{{partial "partials/nomad-logo"}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<nav class="navbar is-primary">
|
||||
<div class="navbar-brand">
|
||||
<span data-test-header-gutter-toggle class="gutter-toggle" aria-label="menu" onclick={{action onHamburgerClick}}>
|
||||
{{partial "partials/hamburger-menu"}}
|
||||
</span>
|
||||
<span class="navbar-item is-logo">
|
||||
<img src="/ui/images/nomad-logo.svg" alt="Nomad" />
|
||||
{{partial "partials/nomad-logo"}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<div class="page-column is-left">
|
||||
<div class="gutter">
|
||||
<div data-test-gutter-menu class="page-column is-left {{if isOpen "is-open"}}">
|
||||
<div class="gutter {{if isOpen "is-open"}}">
|
||||
<header class="collapsed-menu {{if isOpen "is-open"}}">
|
||||
<span data-test-gutter-gutter-toggle class="gutter-toggle" aria-label="menu" onclick={{action onHamburgerClick}}>
|
||||
{{partial "partials/hamburger-menu"}}
|
||||
</span>
|
||||
<span class="logo-container">
|
||||
{{partial "partials/nomad-logo"}}
|
||||
</span>
|
||||
</header>
|
||||
<aside class="menu">
|
||||
<p class="menu-label">
|
||||
Workload
|
||||
@@ -42,3 +50,4 @@
|
||||
<div data-test-page-content class="page-column is-right">
|
||||
{{yield}}
|
||||
</div>
|
||||
<div data-test-gutter-backdrop class="gutter-backdrop {{if isOpen "is-open"}}" onclick={{action onHamburgerClick}}></div>
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{{#global-header class="page-header"}}
|
||||
{{#global-header
|
||||
class="page-header"
|
||||
onHamburgerClick=(action (mut isGutterOpen) true)}}
|
||||
{{app-breadcrumbs}}
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
{{#gutter-menu
|
||||
class="page-body"
|
||||
isOpen=isGutterOpen
|
||||
onHamburgerClick=(action (mut isGutterOpen) false)}}
|
||||
{{yield}}
|
||||
{{/gutter-menu}}
|
||||
|
||||
5
ui/app/templates/partials/hamburger-menu.hbs
Normal file
5
ui/app/templates/partials/hamburger-menu.hbs
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg class="hamburger-menu" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0" y="0" width="100" height="16" />
|
||||
<rect x="0" y="42" width="100" height="16" />
|
||||
<rect x="0" y="84" width="100" height="16" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 236 B |
14
ui/app/templates/partials/nomad-logo.hbs
Normal file
14
ui/app/templates/partials/nomad-logo.hbs
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg class="nomad-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 206.31 60.07">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M78.49,21.83V46.07h-5.9v-32h8.06L92.79,38.39V14.1h5.9v32H90.63Z"/>
|
||||
<path d="M113.09,46.55c-8,0-10.18-4.42-10.18-9.22V31.43c0-4.8,2.16-9.22,10.18-9.22s10.18,4.42,10.18,9.22v5.91C123.27,42.13,121.11,46.55,113.09,46.55Zm0-19.35c-3.12,0-4.32,1.39-4.32,4v6.29c0,2.64,1.2,4,4.32,4s4.32-1.39,4.32-4V31.24C117.41,28.6,116.21,27.2,113.09,27.2Z"/>
|
||||
<path d="M141.08,46.07V29.75c0-1.25-.53-1.87-1.87-1.87a16.16,16.16,0,0,0-6.1,2V46.07h-5.86V22.69h4.46l.58,2a23.43,23.43,0,0,1,9.36-2.45,4.44,4.44,0,0,1,4.42,2.5,23,23,0,0,1,9.41-2.5c3.89,0,5.28,2.74,5.28,6.91V46.07H154.9V29.75c0-1.25-.53-1.87-1.87-1.87a15.5,15.5,0,0,0-6.1,2V46.07Z"/>
|
||||
<path d="M182.88,46.07h-4.8l-.43-1.58a12.79,12.79,0,0,1-7,2.06c-4.27,0-6.1-2.93-6.1-7,0-4.75,2.06-6.58,6.82-6.58H177V30.56c0-2.59-.72-3.5-4.46-3.5a32.71,32.71,0,0,0-6.48.72l-.72-4.46a30.52,30.52,0,0,1,8-1.1c7.34,0,9.5,2.59,9.5,8.45ZM177,37.24h-4.32c-1.92,0-2.45.53-2.45,2.3s.53,2.35,2.35,2.35a9.2,9.2,0,0,0,4.42-1.2Z"/>
|
||||
<path d="M186.48,30.47c0-5.18,2.3-8.26,7.73-8.26a32.22,32.22,0,0,1,6.24.67V13.14l5.86-.82V46.07h-4.66l-.58-2a12.31,12.31,0,0,1-7.39,2.45c-4.7,0-7.2-2.79-7.2-8.11Zm14-2.64a26,26,0,0,0-5.18-.62c-2.11,0-2.93,1-2.93,3.12v8.26c0,1.92.72,3,2.88,3a8.28,8.28,0,0,0,5.23-2.11Z"/>
|
||||
<polygon class="faded" points="38.02 23.13 38.02 33.08 31.09 37.09 26.25 34.09 26.25 60.06 26.38 60.07 52.49 45.07 52.49 15.11 52.01 15.11 38.02 23.13"/>
|
||||
<polygon points="26.03 0.07 0 15.11 17.56 25.43 21.11 23.27 29.75 28.08 29.75 18.08 38.02 13.11 38.02 23.13 52.49 15.11 52.49 15.07 26.03 0.07"/>
|
||||
<polygon points="22.75 32.09 22.75 42.08 14.87 47.08 14.87 27.08 17.86 25.25 0.15 15.11 0 15.11 0 45.07 26.25 60.06 26.25 34.09 22.75 32.09"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 206.31 60.07"><defs><style>.cls-1,.cls-2{fill:#fff;}.cls-2{opacity:0.7;}</style></defs><title>Asset 1</title><g id="Layer_2" data-name="Layer 2"><g id="Logo"><path class="cls-1" d="M78.49,21.83V46.07h-5.9v-32h8.06L92.79,38.39V14.1h5.9v32H90.63Z"/><path class="cls-1" d="M113.09,46.55c-8,0-10.18-4.42-10.18-9.22V31.43c0-4.8,2.16-9.22,10.18-9.22s10.18,4.42,10.18,9.22v5.91C123.27,42.13,121.11,46.55,113.09,46.55Zm0-19.35c-3.12,0-4.32,1.39-4.32,4v6.29c0,2.64,1.2,4,4.32,4s4.32-1.39,4.32-4V31.24C117.41,28.6,116.21,27.2,113.09,27.2Z"/><path class="cls-1" d="M141.08,46.07V29.75c0-1.25-.53-1.87-1.87-1.87a16.16,16.16,0,0,0-6.1,2V46.07h-5.86V22.69h4.46l.58,2a23.43,23.43,0,0,1,9.36-2.45,4.44,4.44,0,0,1,4.42,2.5,23,23,0,0,1,9.41-2.5c3.89,0,5.28,2.74,5.28,6.91V46.07H154.9V29.75c0-1.25-.53-1.87-1.87-1.87a15.5,15.5,0,0,0-6.1,2V46.07Z"/><path class="cls-1" d="M182.88,46.07h-4.8l-.43-1.58a12.79,12.79,0,0,1-7,2.06c-4.27,0-6.1-2.93-6.1-7,0-4.75,2.06-6.58,6.82-6.58H177V30.56c0-2.59-.72-3.5-4.46-3.5a32.71,32.71,0,0,0-6.48.72l-.72-4.46a30.52,30.52,0,0,1,8-1.1c7.34,0,9.5,2.59,9.5,8.45ZM177,37.24h-4.32c-1.92,0-2.45.53-2.45,2.3s.53,2.35,2.35,2.35a9.2,9.2,0,0,0,4.42-1.2Z"/><path class="cls-1" d="M186.48,30.47c0-5.18,2.3-8.26,7.73-8.26a32.22,32.22,0,0,1,6.24.67V13.14l5.86-.82V46.07h-4.66l-.58-2a12.31,12.31,0,0,1-7.39,2.45c-4.7,0-7.2-2.79-7.2-8.11Zm14-2.64a26,26,0,0,0-5.18-.62c-2.11,0-2.93,1-2.93,3.12v8.26c0,1.92.72,3,2.88,3a8.28,8.28,0,0,0,5.23-2.11Z"/><polygon class="cls-2" points="38.02 23.13 38.02 33.08 31.09 37.09 26.25 34.09 26.25 60.06 26.38 60.07 52.49 45.07 52.49 15.11 52.01 15.11 38.02 23.13"/><polygon class="cls-1" points="26.03 0.07 0 15.11 17.56 25.43 21.11 23.27 29.75 28.08 29.75 18.08 38.02 13.11 38.02 23.13 52.49 15.11 52.49 15.07 26.03 0.07"/><polygon class="cls-1" points="22.75 32.09 22.75 42.08 14.87 47.08 14.87 27.08 17.86 25.25 0.15 15.11 0 15.11 0 45.07 26.25 60.06 26.25 34.09 22.75 32.09"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
73
ui/tests/integration/page-layout-test.js
Normal file
73
ui/tests/integration/page-layout-test.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { test, moduleForComponent } from 'ember-qunit';
|
||||
import { find, click } from 'ember-native-dom-helpers';
|
||||
import wait from 'ember-test-helpers/wait';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
|
||||
|
||||
moduleForComponent('page-layout', 'Integration | Component | page layout', {
|
||||
integration: true,
|
||||
beforeEach() {
|
||||
this.server = startMirage();
|
||||
},
|
||||
afterEach() {
|
||||
this.server.shutdown();
|
||||
},
|
||||
});
|
||||
|
||||
test('the global-header hamburger menu opens the gutter menu', function(assert) {
|
||||
this.render(hbs`{{page-layout}}`);
|
||||
|
||||
assert.notOk(
|
||||
find('[data-test-gutter-menu]').classList.contains('is-open'),
|
||||
'Gutter menu is not open'
|
||||
);
|
||||
click('[data-test-header-gutter-toggle]');
|
||||
|
||||
return wait().then(() => {
|
||||
assert.ok(find('[data-test-gutter-menu]').classList.contains('is-open'), 'Gutter menu is open');
|
||||
});
|
||||
});
|
||||
|
||||
test('the gutter-menu hamburger menu closes the gutter menu', function(assert) {
|
||||
this.render(hbs`{{page-layout}}`);
|
||||
|
||||
click('[data-test-header-gutter-toggle]');
|
||||
|
||||
return wait()
|
||||
.then(() => {
|
||||
assert.ok(
|
||||
find('[data-test-gutter-menu]').classList.contains('is-open'),
|
||||
'Gutter menu is open'
|
||||
);
|
||||
click('[data-test-gutter-gutter-toggle]');
|
||||
return wait();
|
||||
})
|
||||
.then(() => {
|
||||
assert.notOk(
|
||||
find('[data-test-gutter-menu]').classList.contains('is-open'),
|
||||
'Gutter menu is not open'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('the gutter-menu backdrop closes the gutter menu', function(assert) {
|
||||
this.render(hbs`{{page-layout}}`);
|
||||
|
||||
click('[data-test-header-gutter-toggle]');
|
||||
|
||||
return wait()
|
||||
.then(() => {
|
||||
assert.ok(
|
||||
find('[data-test-gutter-menu]').classList.contains('is-open'),
|
||||
'Gutter menu is open'
|
||||
);
|
||||
click('[data-test-gutter-backdrop]');
|
||||
return wait();
|
||||
})
|
||||
.then(() => {
|
||||
assert.notOk(
|
||||
find('[data-test-gutter-menu]').classList.contains('is-open'),
|
||||
'Gutter menu is not open'
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user