Merge pull request #81 from dod-ccpo/ui/global-navigation-frame
Ui/global navigation frame
This commit is contained in:
commit
e7f1762fb4
@ -16,6 +16,7 @@ from atst.home import home
|
||||
from atst.api_client import ApiClient
|
||||
from atst.sessions import RedisSessions
|
||||
from atst import ui_modules
|
||||
from atst import ui_methods
|
||||
|
||||
ENV = os.getenv("TORNADO_ENV", "dev")
|
||||
|
||||
@ -101,6 +102,7 @@ def make_app(config, deps, **kwargs):
|
||||
cookie_secret=config["default"]["COOKIE_SECRET"],
|
||||
debug=config["default"].getboolean("DEBUG"),
|
||||
ui_modules=ui_modules,
|
||||
ui_methods=ui_methods,
|
||||
**kwargs,
|
||||
)
|
||||
app.config = config
|
||||
|
2
atst/ui_methods.py
Normal file
2
atst/ui_methods.py
Normal file
@ -0,0 +1,2 @@
|
||||
def matchesPath(self, href):
|
||||
return self.request.uri.startswith(href)
|
@ -5,3 +5,12 @@ class Icon(UIModule):
|
||||
with open('static/icons/%s.svg' % name) as svg:
|
||||
return self.render_string(
|
||||
"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)
|
||||
|
@ -1,7 +1,6 @@
|
||||
@import 'core/variables';
|
||||
@import '../node_modules/uswds/src/stylesheets/uswds';
|
||||
|
||||
@import 'core/base';
|
||||
@import 'core/grid';
|
||||
@import 'core/util';
|
||||
|
||||
@ -12,12 +11,13 @@
|
||||
@import 'elements/block_lists';
|
||||
@import 'elements/tables';
|
||||
@import 'elements/icons';
|
||||
@import 'elements/sidenav';
|
||||
|
||||
@import 'components/layout';
|
||||
@import 'components/topbar';
|
||||
@import 'components/global_navigation';
|
||||
@import 'components/site_action';
|
||||
@import 'components/empty_state';
|
||||
|
||||
@import 'sections/main';
|
||||
@import 'sections/topbar';
|
||||
@import 'sections/sidenav';
|
||||
@import 'sections/footer';
|
||||
@import 'sections/login';
|
||||
|
30
scss/components/_global_navigation.scss
Normal file
30
scss/components/_global_navigation.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
31
scss/components/_layout.scss
Normal file
31
scss/components/_layout.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
71
scss/components/_topbar.scss
Normal file
71
scss/components/_topbar.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -9,12 +9,9 @@
|
||||
// We are implementing a simple flexbox row/column system
|
||||
|
||||
@mixin grid-row {
|
||||
@include media($medium-screen) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
max-width: $site-max-width;
|
||||
}
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
@mixin grid-pad {
|
||||
|
@ -1,3 +1,25 @@
|
||||
.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;
|
||||
}
|
||||
|
@ -3,9 +3,11 @@
|
||||
* ===================================================
|
||||
*/
|
||||
|
||||
$gap: .8rem; // 8px at 10px $em-base
|
||||
$gap: 0.8rem; // 8px at 10px $em-base
|
||||
$topbar-height: 4.8rem;
|
||||
$icon-bar-width: 4.0rem;
|
||||
$icon-size-small: 2.4rem;
|
||||
$hover-transition-time: 0.2s;
|
||||
|
||||
/*
|
||||
* USWDS Variables
|
||||
|
@ -1,17 +1,19 @@
|
||||
@mixin icon {
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
display: inline-flex;
|
||||
|
||||
> svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
* {
|
||||
transition: fill $hover-transition-time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin icon-size($size) {
|
||||
$icon-size: $size * .1rem;
|
||||
width: $icon-size;
|
||||
height: $icon-size;
|
||||
height: auto;
|
||||
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 {
|
||||
@include icon;
|
||||
@include icon-size(16);
|
||||
@include icon-style-default;
|
||||
|
||||
&.icon--tiny {
|
||||
@include icon-size(10);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
.sidenav {
|
||||
@include grid-pad;
|
||||
@include panel-margin;
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
@include media($large-screen) {
|
||||
width: 21rem;
|
||||
li {
|
||||
margin: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@include media($xlarge-screen) {
|
||||
width: 30rem;
|
||||
}
|
||||
|
||||
.sidenav__link {
|
||||
@ -18,10 +16,10 @@
|
||||
padding: $gap ($gap * 2);
|
||||
color: $color-black;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-white;
|
||||
color: $color-primary;
|
||||
.sidenav__link-icon {
|
||||
margin-left: - ($gap * .5);
|
||||
}
|
||||
|
||||
&.sidenav__link--disabled {
|
||||
@ -35,60 +33,42 @@
|
||||
color: $color-primary;
|
||||
box-shadow: inset .4rem 0 0 0 $color-primary;
|
||||
|
||||
.sidenav__link-icon {
|
||||
@include icon-style-active;
|
||||
}
|
||||
|
||||
+ ul {
|
||||
background-color: $color-white;
|
||||
|
||||
.sidenav__link {
|
||||
&--active {
|
||||
@include h5;
|
||||
box-shadow: none;
|
||||
color: $color-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ ul {
|
||||
padding-bottom: $gap / 2;
|
||||
|
||||
li {
|
||||
.sidenav__link {
|
||||
@include h5;
|
||||
padding: ($gap * .75) ($gap * 3);
|
||||
border: 0;
|
||||
@include h5;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
.sidenav__link {
|
||||
padding-bottom: $gap * 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
> ul {
|
||||
@include panel-margin;
|
||||
&:hover {
|
||||
color: $color-primary;
|
||||
|
||||
&:last-child {
|
||||
margin: 0;
|
||||
.sidenav__link-icon {
|
||||
@include icon-style-active;
|
||||
}
|
||||
|
||||
> li {
|
||||
&:last-child {
|
||||
> .sidenav__link {
|
||||
border-bottom: 1px solid $color-black;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,11 @@
|
||||
* @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 {
|
||||
font-family: $font-sans;
|
||||
|
||||
@ -25,12 +30,12 @@ h2 {
|
||||
|
||||
|
||||
a,
|
||||
a > span {
|
||||
a:hover {
|
||||
transition:
|
||||
background 0.2s,
|
||||
border 0.2s,
|
||||
box-shadow 0.2s,
|
||||
color 0.2s,
|
||||
background $hover-transition-time,
|
||||
border $hover-transition-time,
|
||||
box-shadow $hover-transition-time,
|
||||
color $hover-transition-time,
|
||||
}
|
||||
|
||||
dt {
|
||||
|
@ -1,3 +0,0 @@
|
||||
section {
|
||||
margin-bottom: 10rem;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
{# TODO: set this context elsewhere #}
|
||||
{# set context='workspace' #}
|
||||
{% set context='global' %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@ -10,18 +14,19 @@
|
||||
<link rel="icon" type="image/x-icon" href="/static/img/favicon.ico">
|
||||
</head>
|
||||
<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 content %}
|
||||
these are not the droids you are looking for
|
||||
{% end %}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% include 'footer.html.to' %}
|
||||
</body>
|
||||
|
@ -1,9 +1,5 @@
|
||||
{% extends "base.html.to" %}
|
||||
|
||||
{% block sidenav %}
|
||||
{% include 'nav-side.html.to' %}
|
||||
{% end %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<main class="usa-section usa-content">
|
||||
|
9
templates/navigation/_sidenav_item.html.to
Normal file
9
templates/navigation/_sidenav_item.html.to
Normal 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>
|
6
templates/navigation/global_navigation.html.to
Normal file
6
templates/navigation/global_navigation.html.to
Normal 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>
|
19
templates/navigation/topbar.html.to
Normal file
19
templates/navigation/topbar.html.to
Normal 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>
|
@ -1,9 +1,5 @@
|
||||
{% extends "base.html.to" %}
|
||||
|
||||
{% block sidenav %}
|
||||
{% include 'nav-side.html.to' %}
|
||||
{% end %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
@ -1,12 +1,8 @@
|
||||
{% extends "base.html.to" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<main class="usa-section usa-content usa-width-one-whole">
|
||||
|
||||
<h1>Workspaces</h1>
|
||||
|
||||
<table class="usa-table-borderless" width="100%">
|
||||
<div class='col'>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" width="50%">Workspace Name</th>
|
||||
@ -29,8 +25,6 @@
|
||||
{% end %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
{% end %}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user