diff --git a/atst/app.py b/atst/app.py
index 07f40411..625e2a74 100644
--- a/atst/app.py
+++ b/atst/app.py
@@ -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
diff --git a/atst/ui_methods.py b/atst/ui_methods.py
new file mode 100644
index 00000000..d5c5bf78
--- /dev/null
+++ b/atst/ui_methods.py
@@ -0,0 +1,2 @@
+def matchesPath(self, href):
+ return self.request.uri.startswith(href)
diff --git a/atst/ui_modules.py b/atst/ui_modules.py
index ec197bcd..77671339 100644
--- a/atst/ui_modules.py
+++ b/atst/ui_modules.py
@@ -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)
diff --git a/scss/atat.scss b/scss/atat.scss
index 532330bb..01d4e9b6 100644
--- a/scss/atat.scss
+++ b/scss/atat.scss
@@ -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';
diff --git a/scss/components/_global_navigation.scss b/scss/components/_global_navigation.scss
new file mode 100644
index 00000000..203fba9f
--- /dev/null
+++ b/scss/components/_global_navigation.scss
@@ -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;
+ }
+ }
+}
diff --git a/scss/components/_layout.scss b/scss/components/_layout.scss
new file mode 100644
index 00000000..ee8308af
--- /dev/null
+++ b/scss/components/_layout.scss
@@ -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;
+ }
+ }
+}
diff --git a/scss/components/_topbar.scss b/scss/components/_topbar.scss
new file mode 100644
index 00000000..e56a95fa
--- /dev/null
+++ b/scss/components/_topbar.scss
@@ -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;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/scss/core/_base.scss b/scss/core/_base.scss
deleted file mode 100644
index 57513b32..00000000
--- a/scss/core/_base.scss
+++ /dev/null
@@ -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;
- }
-}
diff --git a/scss/core/_grid.scss b/scss/core/_grid.scss
index a18f6b44..b24327c3 100644
--- a/scss/core/_grid.scss
+++ b/scss/core/_grid.scss
@@ -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;
- }
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
}
@mixin grid-pad {
diff --git a/scss/core/_util.scss b/scss/core/_util.scss
index 101ddcf4..505b4ed5 100644
--- a/scss/core/_util.scss
+++ b/scss/core/_util.scss
@@ -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;
+}
diff --git a/scss/core/_variables.scss b/scss/core/_variables.scss
index 266065e8..4380ac69 100644
--- a/scss/core/_variables.scss
+++ b/scss/core/_variables.scss
@@ -3,9 +3,11 @@
* ===================================================
*/
-$gap: .8rem; // 8px at 10px $em-base
-$topbar-height: 4.8rem;
-$icon-size-small: 2.4rem;
+$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
diff --git a/scss/elements/_icons.scss b/scss/elements/_icons.scss
index 95f7fb46..0379154d 100644
--- a/scss/elements/_icons.scss
+++ b/scss/elements/_icons.scss
@@ -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);
+ }
}
diff --git a/scss/elements/_panels.scss b/scss/elements/_panels.scss
index f52914b2..5b0c1220 100644
--- a/scss/elements/_panels.scss
+++ b/scss/elements/_panels.scss
@@ -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;
- }
-
-
-}
diff --git a/scss/sections/_sidenav.scss b/scss/elements/_sidenav.scss
similarity index 63%
rename from scss/sections/_sidenav.scss
rename to scss/elements/_sidenav.scss
index 4415c3ae..7fa92cf6 100644
--- a/scss/sections/_sidenav.scss
+++ b/scss/elements/_sidenav.scss
@@ -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;
- }
-
- @include media($xlarge-screen) {
- width: 30rem;
+ li {
+ margin: 0;
+ display: block;
+ }
}
.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;
+ &:hover {
+ color: $color-primary;
- li {
- margin: 0;
- display: block;
- }
- }
-
- > ul {
- @include panel-margin;
-
- &:last-child {
- margin: 0;
- }
-
- > li {
- &:last-child {
- > .sidenav__link {
- border-bottom: 1px solid $color-black;
- }
+ .sidenav__link-icon {
+ @include icon-style-active;
}
+
}
}
}
diff --git a/scss/elements/_typography.scss b/scss/elements/_typography.scss
index 87022e95..9096af9d 100644
--- a/scss/elements/_typography.scss
+++ b/scss/elements/_typography.scss
@@ -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,15 +30,15 @@ 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 {
display: inline;
font-weight: bold;
-}
\ No newline at end of file
+}
diff --git a/scss/sections/_main.scss b/scss/sections/_main.scss
deleted file mode 100644
index 063b70e7..00000000
--- a/scss/sections/_main.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-section {
- margin-bottom: 10rem;
-}
diff --git a/scss/sections/_topbar.scss b/scss/sections/_topbar.scss
deleted file mode 100644
index 37114a6c..00000000
--- a/scss/sections/_topbar.scss
+++ /dev/null
@@ -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;
- }
- }
- }
- }
- }
-}
diff --git a/templates/base.html.to b/templates/base.html.to
index f271513d..f3412da9 100644
--- a/templates/base.html.to
+++ b/templates/base.html.to
@@ -1,3 +1,7 @@
+{# TODO: set this context elsewhere #}
+{# set context='workspace' #}
+{% set context='global' %}
+
@@ -10,19 +14,20 @@
+ {% include 'navigation/topbar.html.to' %}
- {% include 'header.html.to' %}
+
+ {% include 'navigation/global_navigation.html.to' %}
-
- {% block sidenav %}{% end %}
+
+ {% block sidenav %}{% end %}
- {% block content %}
- these are not the droids you are looking for
- {% end %}
+ {% block content %}
+ these are not the droids you are looking for
+ {% end %}
+
-
-
{% include 'footer.html.to' %}
diff --git a/templates/home.html.to b/templates/home.html.to
index e5f7c8f7..eb789f28 100644
--- a/templates/home.html.to
+++ b/templates/home.html.to
@@ -1,9 +1,5 @@
{% extends "base.html.to" %}
-{% block sidenav %}
-{% include 'nav-side.html.to' %}
-{% end %}
-
{% block content %}
diff --git a/templates/navigation/_sidenav_item.html.to b/templates/navigation/_sidenav_item.html.to
new file mode 100644
index 00000000..a41b7726
--- /dev/null
+++ b/templates/navigation/_sidenav_item.html.to
@@ -0,0 +1,9 @@
+
+
+ {% if icon %}
+ {% module Icon(icon, classes="sidenav__link-icon") %}
+ {% end %}
+
+ {{label}}
+
+
diff --git a/templates/navigation/global_navigation.html.to b/templates/navigation/global_navigation.html.to
new file mode 100644
index 00000000..742ddaf7
--- /dev/null
+++ b/templates/navigation/global_navigation.html.to
@@ -0,0 +1,6 @@
+
+
+ {% module SidenavItem("Requests", href="/requests", icon="document", active=matchesPath('/requests')) %}
+ {% module SidenavItem("Workspaces", href="/workspaces", icon="cloud", active=matchesPath('/workspaces')) %}
+
+
diff --git a/templates/navigation/topbar.html.to b/templates/navigation/topbar.html.to
new file mode 100644
index 00000000..9c6ef28c
--- /dev/null
+++ b/templates/navigation/topbar.html.to
@@ -0,0 +1,19 @@
+
diff --git a/templates/requests.html.to b/templates/requests.html.to
index ff1835ce..653c01b3 100644
--- a/templates/requests.html.to
+++ b/templates/requests.html.to
@@ -1,9 +1,5 @@
{% extends "base.html.to" %}
-{% block sidenav %}
-{% include 'nav-side.html.to' %}
-{% end %}
-
{% block content %}
diff --git a/templates/workspaces.html.to b/templates/workspaces.html.to
index c768708c..9f87a99a 100644
--- a/templates/workspaces.html.to
+++ b/templates/workspaces.html.to
@@ -1,12 +1,8 @@
{% extends "base.html.to" %}
{% block content %}
-
-
-
- Workspaces
-
-
+
+
Workspace Name
@@ -29,8 +25,6 @@
{% end %}
-
-
-
+
{% end %}