Merge pull request #81 from dod-ccpo/ui/global-navigation-frame

Ui/global navigation frame
This commit is contained in:
andrewdds 2018-07-20 11:35:28 -04:00 committed by GitHub
commit e7f1762fb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 285 additions and 197 deletions

View File

@ -16,6 +16,7 @@ from atst.home import home
from atst.api_client import ApiClient from atst.api_client import ApiClient
from atst.sessions import RedisSessions from atst.sessions import RedisSessions
from atst import ui_modules from atst import ui_modules
from atst import ui_methods
ENV = os.getenv("TORNADO_ENV", "dev") ENV = os.getenv("TORNADO_ENV", "dev")
@ -101,6 +102,7 @@ def make_app(config, deps, **kwargs):
cookie_secret=config["default"]["COOKIE_SECRET"], cookie_secret=config["default"]["COOKIE_SECRET"],
debug=config["default"].getboolean("DEBUG"), debug=config["default"].getboolean("DEBUG"),
ui_modules=ui_modules, ui_modules=ui_modules,
ui_methods=ui_methods,
**kwargs, **kwargs,
) )
app.config = config app.config = config

2
atst/ui_methods.py Normal file
View File

@ -0,0 +1,2 @@
def matchesPath(self, href):
return self.request.uri.startswith(href)

View File

@ -5,3 +5,12 @@ class Icon(UIModule):
with open('static/icons/%s.svg' % name) as svg: with open('static/icons/%s.svg' % name) as svg:
return self.render_string( return self.render_string(
"components/icon.html.to", svg=svg.read(), name=name, classes=classes) "components/icon.html.to", svg=svg.read(), name=name, classes=classes)
class SidenavItem(UIModule):
def render(self, label, href, active=False, icon=None):
return self.render_string(
"navigation/_sidenav_item.html.to",
label=label,
href=href,
active=active,
icon=icon)

View File

@ -1,7 +1,6 @@
@import 'core/variables'; @import 'core/variables';
@import '../node_modules/uswds/src/stylesheets/uswds'; @import '../node_modules/uswds/src/stylesheets/uswds';
@import 'core/base';
@import 'core/grid'; @import 'core/grid';
@import 'core/util'; @import 'core/util';
@ -12,12 +11,13 @@
@import 'elements/block_lists'; @import 'elements/block_lists';
@import 'elements/tables'; @import 'elements/tables';
@import 'elements/icons'; @import 'elements/icons';
@import 'elements/sidenav';
@import 'components/layout';
@import 'components/topbar';
@import 'components/global_navigation';
@import 'components/site_action'; @import 'components/site_action';
@import 'components/empty_state'; @import 'components/empty_state';
@import 'sections/main';
@import 'sections/topbar';
@import 'sections/sidenav';
@import 'sections/footer'; @import 'sections/footer';
@import 'sections/login'; @import 'sections/login';

View File

@ -0,0 +1,30 @@
.global-navigation {
background-color: $color-white;
.sidenav__link {
padding-right: $gap;
@include media($medium-screen) {
padding-right: $gap * 2;
}
}
.sidenav__link-label {
@include hide;
@include media($medium-screen) {
@include unhide;
padding-left: $gap;
}
}
&.global-navigation__context--workspace {
.sidenav__link {
padding-right: $gap;
}
.sidenav__link-label {
@include hide;
}
}
}

View File

@ -0,0 +1,31 @@
body {
background-color: $color-gray-lightest;
display: flex;
flex-direction: column;
justify-content: flex-start;
min-height: 100vh;
> footer {
margin-top: auto;
}
}
.global-layout {
display: flex;
flex-wrap: nowrap;
flex-grow: 1;
.global-navigation {
margin-top: -1px;
}
.global-panel-container {
margin: $gap;
max-width: $site-max-width;
overflow: auto;
@include media($medium-screen) {
margin: $gap * 2;
}
}
}

View File

@ -0,0 +1,71 @@
.topbar {
background-color: $color-white;
border-bottom: 1px solid $color-black;
.topbar__navigation {
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: space-between;
.topbar__link {
color: $color-black;
display: inline-flex;
align-items: center;
height: $topbar-height;
padding: 0 ($gap * 2);
text-decoration: none;
.topbar__link-label {
@include h5;
}
.topbar__link-icon {
margin-left: $gap;
}
&.topbar__link--shield {
width: $icon-bar-width;
justify-content: center;
padding: 0;
.topbar__link-icon {
margin: 0;
}
}
&:hover {
background-color: $color-primary-darker;
color: $color-white;
.topbar__link-icon {
@include icon-style-inverted;
}
}
}
.topbar__context {
display: flex;
flex-grow: 1;
flex-direction: row;
align-items: stretch;
justify-content: space-between;
&.topbar__context--workspace {
background-color: $color-primary;
.topbar__link {
color: $color-white;
.topbar__link-icon {
@include icon-style-inverted;
}
&:hover {
background-color: $color-primary-darker;
}
}
}
}
}
}

View File

@ -1,16 +0,0 @@
/*
* Base Styles
* @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/core/_base.scss
*/
body {
background-color: $color-gray-lightest;
display: flex;
flex-direction: column;
justify-content: flex-start;
min-height: 100vh;
> footer {
margin-top: auto;
}
}

View File

@ -9,12 +9,9 @@
// We are implementing a simple flexbox row/column system // We are implementing a simple flexbox row/column system
@mixin grid-row { @mixin grid-row {
@include media($medium-screen) { display: flex;
display: flex; flex-direction: row;
flex-direction: row; flex-wrap: nowrap;
flex-wrap: wrap;
max-width: $site-max-width;
}
} }
@mixin grid-pad { @mixin grid-pad {

View File

@ -1,3 +1,25 @@
.nowrap { .nowrap {
white-space: nowrap; white-space: nowrap;
} }
@mixin hide {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
@mixin unhide {
border: unset;
clip: unset;
height: unset;
margin: unset;
overflow: unset;
padding: unset;
position: unset;
width: unset;
}

View File

@ -3,9 +3,11 @@
* =================================================== * ===================================================
*/ */
$gap: .8rem; // 8px at 10px $em-base $gap: 0.8rem; // 8px at 10px $em-base
$topbar-height: 4.8rem; $topbar-height: 4.8rem;
$icon-size-small: 2.4rem; $icon-bar-width: 4.0rem;
$icon-size-small: 2.4rem;
$hover-transition-time: 0.2s;
/* /*
* USWDS Variables * USWDS Variables

View File

@ -1,17 +1,19 @@
@mixin icon { @mixin icon {
display: inline-block; display: inline-flex;
vertical-align: bottom;
> svg { > svg {
width: 100%; width: 100%;
height: 100%; height: 100%;
* {
transition: fill $hover-transition-time;
}
} }
} }
@mixin icon-size($size) { @mixin icon-size($size) {
$icon-size: $size * .1rem; $icon-size: $size * .1rem;
width: $icon-size; width: $icon-size;
height: $icon-size; height: auto;
margin: $icon-size / 4; margin: $icon-size / 4;
} }
@ -21,8 +23,24 @@
} }
} }
@mixin icon-style-active {
> svg * {
fill: $color-primary;
}
}
@mixin icon-style-inverted {
> svg * {
fill: $color-white;
}
}
.icon { .icon {
@include icon; @include icon;
@include icon-size(16); @include icon-size(16);
@include icon-style-default; @include icon-style-default;
&.icon--tiny {
@include icon-size(10);
}
} }

View File

@ -44,36 +44,3 @@
} }
} }
} }
/*
* Panel Container
* Grid container for panel blocks
*/
.panel-container {
@include grid-row;
@include grid-pad;
@include margin(($site-margins-mobile * 2) null);
@include media($medium-screen) {
@include margin(($site-margins * 2) null);
}
@include media($large-screen) {
flex-wrap: nowrap;
}
> .col {
@include grid-pad;
}
h1 {
margin-bottom: 0;
}
h2 {
color: $color-gray;
}
}

View File

@ -1,15 +1,13 @@
.sidenav { .sidenav {
@include grid-pad; ul {
@include panel-margin; list-style: none;
width: 100%; margin: 0;
flex-shrink: 0; padding: 0;
@include media($large-screen) { li {
width: 21rem; margin: 0;
} display: block;
}
@include media($xlarge-screen) {
width: 30rem;
} }
.sidenav__link { .sidenav__link {
@ -18,10 +16,10 @@
padding: $gap ($gap * 2); padding: $gap ($gap * 2);
color: $color-black; color: $color-black;
text-decoration: none; text-decoration: none;
white-space: nowrap;
&:hover { .sidenav__link-icon {
background-color: $color-white; margin-left: - ($gap * .5);
color: $color-primary;
} }
&.sidenav__link--disabled { &.sidenav__link--disabled {
@ -35,60 +33,42 @@
color: $color-primary; color: $color-primary;
box-shadow: inset .4rem 0 0 0 $color-primary; box-shadow: inset .4rem 0 0 0 $color-primary;
.sidenav__link-icon {
@include icon-style-active;
}
+ ul { + ul {
background-color: $color-white; background-color: $color-white;
.sidenav__link { .sidenav__link {
&--active { &--active {
@include h5; @include h5;
box-shadow: none; color: $color-primary;
} }
} }
} }
} }
+ ul { + ul {
padding-bottom: $gap / 2;
li { li {
.sidenav__link { .sidenav__link {
@include h5;
padding: ($gap * .75) ($gap * 3); padding: ($gap * .75) ($gap * 3);
border: 0; border: 0;
@include h5;
font-weight: normal; font-weight: normal;
} }
&:last-child {
.sidenav__link {
padding-bottom: $gap * 1.5;
}
}
} }
} }
}
ul { &:hover {
list-style: none; color: $color-primary;
margin: 0;
padding: 0;
li { .sidenav__link-icon {
margin: 0; @include icon-style-active;
display: block;
}
}
> ul {
@include panel-margin;
&:last-child {
margin: 0;
}
> li {
&:last-child {
> .sidenav__link {
border-bottom: 1px solid $color-black;
}
} }
} }
} }
} }

View File

@ -4,6 +4,11 @@
* @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_typography.scss * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_typography.scss
*/ */
* {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
font-family: $font-sans; font-family: $font-sans;
@ -25,15 +30,15 @@ h2 {
a, a,
a > span { a:hover {
transition: transition:
background 0.2s, background $hover-transition-time,
border 0.2s, border $hover-transition-time,
box-shadow 0.2s, box-shadow $hover-transition-time,
color 0.2s, color $hover-transition-time,
} }
dt { dt {
display: inline; display: inline;
font-weight: bold; font-weight: bold;
} }

View File

@ -1,3 +0,0 @@
section {
margin-bottom: 10rem;
}

View File

@ -1,54 +0,0 @@
.topbar {
background-color: $color-white;
height: $topbar-height;
border-bottom: 1px solid $color-black;
.topbar__navigation {
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: flex-end;
> .topbar__link {
@include h5;
color: $color-primary;
display: inline-block;
height: $topbar-height;
line-height: $topbar-height;
padding: 0 ($gap * 2);
text-decoration: none;
> span {
display: inline-block;
height: $topbar-height;
line-height: $topbar-height;
}
&.topbar__link--primary {
margin-right: auto;
> span {
@include nav-border;
}
&:hover {
color: $color-white;
background-color: $color-primary-darkest;
}
}
&.topbar__link--secondary {
font-weight: normal;
> span {
@include nav-border;
border-bottom-width: 0;
}
&:hover {
> span {
@include nav-border;
}
}
}
}
}
}

View File

@ -1,3 +1,7 @@
{# TODO: set this context elsewhere #}
{# set context='workspace' #}
{% set context='global' %}
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
@ -10,19 +14,20 @@
<link rel="icon" type="image/x-icon" href="/static/img/favicon.ico"> <link rel="icon" type="image/x-icon" href="/static/img/favicon.ico">
</head> </head>
<body> <body>
{% include 'navigation/topbar.html.to' %}
{% include 'header.html.to' %} <div class='global-layout'>
{% include 'navigation/global_navigation.html.to' %}
<div class='panel-container'> <div class='global-panel-container'>
{% block sidenav %}{% end %} {% block sidenav %}{% end %}
{% block content %} {% block content %}
these are not the droids you are looking for these are not the droids you are looking for
{% end %} {% end %}
</div>
</div> </div>
{% include 'footer.html.to' %} {% include 'footer.html.to' %}
</body> </body>
</html> </html>

View File

@ -1,9 +1,5 @@
{% extends "base.html.to" %} {% extends "base.html.to" %}
{% block sidenav %}
{% include 'nav-side.html.to' %}
{% end %}
{% block content %} {% block content %}
<main class="usa-section usa-content"> <main class="usa-section usa-content">

View File

@ -0,0 +1,9 @@
<li>
<a class="sidenav__link {% if active %}sidenav__link--active{% end %}" href="{{href}}" title="{{label}}">
{% if icon %}
{% module Icon(icon, classes="sidenav__link-icon") %}
{% end %}
<span class="sidenav__link-label">{{label}}</span>
</a>
</li>

View File

@ -0,0 +1,6 @@
<div class="global-navigation sidenav global-navigation__context--{{context}}">
<ul>
{% module SidenavItem("Requests", href="/requests", icon="document", active=matchesPath('/requests')) %}
{% module SidenavItem("Workspaces", href="/workspaces", icon="cloud", active=matchesPath('/workspaces')) %}
</ul>
</div>

View File

@ -0,0 +1,19 @@
<header class="topbar">
<nav class="topbar__navigation">
<a href="/home" class="topbar__link topbar__link--shield" title="JEDI Home">
{% module Icon('shield', classes='topbar__link-icon') %}
</a>
<div class="topbar__context topbar__context--{{context}}">
<a href="/" class="topbar__link">
<span class="topbar__link-label">JEDI</span>
{% module Icon('caret_down', classes='topbar__link-icon icon--tiny') %}
</a>
<a href="/" class="topbar__link">
<span class="topbar__link-label">Sam Seeceepio</span>
{% module Icon('avatar', classes='topbar__link-icon') %}
</a>
</div>
</nav>
</header>

View File

@ -1,9 +1,5 @@
{% extends "base.html.to" %} {% extends "base.html.to" %}
{% block sidenav %}
{% include 'nav-side.html.to' %}
{% end %}
{% block content %} {% block content %}

View File

@ -1,12 +1,8 @@
{% extends "base.html.to" %} {% extends "base.html.to" %}
{% block content %} {% block content %}
<div class='col'>
<main class="usa-section usa-content usa-width-one-whole"> <table>
<h1>Workspaces</h1>
<table class="usa-table-borderless" width="100%">
<thead> <thead>
<tr> <tr>
<th scope="col" width="50%">Workspace Name</th> <th scope="col" width="50%">Workspace Name</th>
@ -29,8 +25,6 @@
{% end %} {% end %}
</tbody> </tbody>
</table> </table>
</div>
</main>
{% end %} {% end %}