diff --git a/awx/ui/static/fonts/ubuntu-r-webfont.woff b/awx/ui/static/fonts/ubuntu-r-webfont.woff
new file mode 100644
index 0000000000..96cc74f9b2
Binary files /dev/null and b/awx/ui/static/fonts/ubuntu-r-webfont.woff differ
diff --git a/awx/ui/static/fonts/ubuntu.woff2 b/awx/ui/static/fonts/ubuntu.woff2
new file mode 100644
index 0000000000..2701e3f6cc
Binary files /dev/null and b/awx/ui/static/fonts/ubuntu.woff2 differ
diff --git a/awx/ui/static/img/CloudSync.svg b/awx/ui/static/img/CloudSync.svg
new file mode 100644
index 0000000000..d9fac6d652
--- /dev/null
+++ b/awx/ui/static/img/CloudSync.svg
@@ -0,0 +1,18 @@
+
+
diff --git a/awx/ui/static/img/Credentials.svg b/awx/ui/static/img/Credentials.svg
new file mode 100644
index 0000000000..d15344cd86
--- /dev/null
+++ b/awx/ui/static/img/Credentials.svg
@@ -0,0 +1,12 @@
+
+
diff --git a/awx/ui/static/img/JobTemplates.svg b/awx/ui/static/img/JobTemplates.svg
new file mode 100644
index 0000000000..720bf11493
--- /dev/null
+++ b/awx/ui/static/img/JobTemplates.svg
@@ -0,0 +1,16 @@
+
+
diff --git a/awx/ui/static/img/Jobs.svg b/awx/ui/static/img/Jobs.svg
new file mode 100644
index 0000000000..ec37085ba3
--- /dev/null
+++ b/awx/ui/static/img/Jobs.svg
@@ -0,0 +1,13 @@
+
+
diff --git a/awx/ui/static/img/PortalMode.svg b/awx/ui/static/img/PortalMode.svg
new file mode 100644
index 0000000000..d1a3cf102e
--- /dev/null
+++ b/awx/ui/static/img/PortalMode.svg
@@ -0,0 +1,12 @@
+
+
diff --git a/awx/ui/static/img/Projects.svg b/awx/ui/static/img/Projects.svg
new file mode 100644
index 0000000000..3e7149867b
--- /dev/null
+++ b/awx/ui/static/img/Projects.svg
@@ -0,0 +1,13 @@
+
+
diff --git a/awx/ui/static/img/Setup.svg b/awx/ui/static/img/Setup.svg
new file mode 100644
index 0000000000..5b4d23a410
--- /dev/null
+++ b/awx/ui/static/img/Setup.svg
@@ -0,0 +1,12 @@
+
+
diff --git a/awx/ui/static/img/Signout.svg b/awx/ui/static/img/Signout.svg
new file mode 100644
index 0000000000..2ba8a576f8
--- /dev/null
+++ b/awx/ui/static/img/Signout.svg
@@ -0,0 +1,18 @@
+
+
diff --git a/awx/ui/static/img/Teams.svg b/awx/ui/static/img/Teams.svg
new file mode 100644
index 0000000000..d5d0b4562b
--- /dev/null
+++ b/awx/ui/static/img/Teams.svg
@@ -0,0 +1,15 @@
+
+
diff --git a/awx/ui/static/img/TowerLogo.svg b/awx/ui/static/img/TowerLogo.svg
new file mode 100644
index 0000000000..df6e470282
--- /dev/null
+++ b/awx/ui/static/img/TowerLogo.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/awx/ui/static/img/Users.svg b/awx/ui/static/img/Users.svg
new file mode 100644
index 0000000000..c7e4feac21
--- /dev/null
+++ b/awx/ui/static/img/Users.svg
@@ -0,0 +1,13 @@
+
+
diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js
index 133ac2e52a..1bddad24fc 100644
--- a/awx/ui/static/js/app.js
+++ b/awx/ui/static/js/app.js
@@ -937,7 +937,7 @@ var tower = angular.module('Tower', [
LoadConfig, Store, ShowSocketHelp, AboutAnsibleHelp, ConfigureTower, CreateCustomInventory) {
- var e, html, sock;
+ var html, e, sock;
function activateTab() {
// Make the correct tab active
diff --git a/awx/ui/static/js/main-menu/main-menu.directive.js b/awx/ui/static/js/main-menu/main-menu.directive.js
new file mode 100644
index 0000000000..2272e4c102
--- /dev/null
+++ b/awx/ui/static/js/main-menu/main-menu.directive.js
@@ -0,0 +1,28 @@
+function getMenuStylePartialUrl(style) {
+
+ if (style !== 'default' && style !== 'minimal') {
+ console.warn('main-menu: "', style, 'is not a valid menu style. Please use "default" or "minimal".');
+ style = 'default';
+ }
+
+ return '/static/js/main-menu/menu-' + style + '.partial.html';
+}
+
+function link(scope, element, attrs) {
+ scope.$watch(function(scope) {
+ return scope.$eval(scope.style);
+ }, function(value) {
+ scope.menuStylePartialUrl = getMenuStylePartialUrl(value);
+ });
+}
+
+export default function() {
+ return {
+ restrict: 'E',
+ template: '',
+ scope: {
+ style: '&menuStyle'
+ },
+ link: link
+ };
+}
diff --git a/awx/ui/static/js/main-menu/main.js b/awx/ui/static/js/main-menu/main.js
new file mode 100644
index 0000000000..722c6dd62d
--- /dev/null
+++ b/awx/ui/static/js/main-menu/main.js
@@ -0,0 +1,7 @@
+import mainMenu from './main-menu.directive';
+import menuItem from './menu-item.directive';
+
+export default
+ angular.module('mainMenu', [])
+ .directive('menuItem', menuItem)
+ .directive('mainMenu', mainMenu);
diff --git a/awx/ui/static/js/main-menu/menu-default.partial.html b/awx/ui/static/js/main-menu/menu-default.partial.html
new file mode 100644
index 0000000000..ad551cb1ed
--- /dev/null
+++ b/awx/ui/static/js/main-menu/menu-default.partial.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/awx/ui/static/js/main-menu/menu-item.directive.js b/awx/ui/static/js/main-menu/menu-item.directive.js
new file mode 100644
index 0000000000..fde1fd9049
--- /dev/null
+++ b/awx/ui/static/js/main-menu/menu-item.directive.js
@@ -0,0 +1,18 @@
+export default ['$location', function($location) {
+ return {
+ link: function(scope, element, attrs) {
+ var itemPath = attrs.href.replace(/^#/, '');
+
+ scope.$watch(function() {
+ return $location.path();
+ }, function(currentPath) {
+ console.log(itemPath, currentPath);
+ if (currentPath === itemPath) {
+ element.addClass('MenuItem--active');
+ } else {
+ element.removeClass('MenuItem--active');
+ }
+ });
+ }
+ };
+}];
diff --git a/awx/ui/static/js/main-menu/menu-minimal.partial.html b/awx/ui/static/js/main-menu/menu-minimal.partial.html
new file mode 100644
index 0000000000..c79ad8a59e
--- /dev/null
+++ b/awx/ui/static/js/main-menu/menu-minimal.partial.html
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/awx/ui/static/js/shared/menu/menu-item.block.less b/awx/ui/static/js/shared/menu/menu-item.block.less
new file mode 100644
index 0000000000..d6b393d049
--- /dev/null
+++ b/awx/ui/static/js/shared/menu/menu-item.block.less
@@ -0,0 +1,100 @@
+/** @define MenuItem */
+
+@import (reference) "shared/utilities/icons.less";
+
+.MenuItem {
+ display: flex;
+ flex: none;
+ padding: 2.8rem 0;
+ min-height: 5.8rem;
+ min-width: 9.2rem;
+
+ &--fixed {
+ flex: none;
+ min-width: 0;
+ margin-right: 0 !important;
+ }
+
+ &--logo {
+ width: 202px;
+ }
+
+ &--active {
+ flex-direction: column !important;
+ justify-content: center !important;
+ background-color: rgba(255,255,255,0.35);
+ .MenuItem-hover-icon {
+ display: flex;
+ opacity: 1 !important;
+ height: 22px !important;
+ }
+ }
+
+ &--hoverable {
+ transition: background-color 0.3s;
+ flex-direction: column;
+ justify-content: center;
+ .MenuItem-hover-icon {
+ display: flex;
+ opacity: 0;
+ height: 0;
+ width: auto;
+ transition: opacity 0.3s ease-out, height 0.2s ease-out;
+ }
+ &:hover {
+ background-color: rgba(255,255,255,0.35);
+ .MenuItem-hover-icon {
+ display: flex;
+ opacity: 1;
+ height: 22px;
+ }
+ }
+ }
+ &--context {
+ // Push this and all following elements to the right
+ margin-left: auto;
+ flex-direction: column;
+ justify-content: center;
+
+ .MenuItem {
+ // Make sure items in this container are aligned to
+ // the right-hand side (on rtl platforms)
+ align-self: flex-end;
+ }
+ }
+
+ &--right {
+ margin-left: auto;
+ }
+
+ &--setup {
+ &:before {
+ .icon(@fa-var-cogs);
+ padding-right: 0.25rem;
+ }
+ }
+
+ &--popup {
+ // Make pseudo button
+ background: transparent;
+ border: 0;
+ padding: 8px 0;
+
+ outline: none;
+
+ &:after {
+ .icon(@fa-var-angle-down);
+ }
+ }
+
+ &-logo {
+ height: 34px;
+ width: auto;
+ }
+
+ &-icon {
+ height: 13px;
+ width: auto;
+ }
+
+}
diff --git a/awx/ui/static/js/shared/menu/menu.block.less b/awx/ui/static/js/shared/menu/menu.block.less
new file mode 100644
index 0000000000..00ae1f40f9
--- /dev/null
+++ b/awx/ui/static/js/shared/menu/menu.block.less
@@ -0,0 +1,51 @@
+/** @define Menu */
+
+.Menu {
+ display: flex;
+ align-items: center;
+ background-color: white;
+
+ &--main {
+ background-color: white;
+ padding: 0 1rem;
+ margin: 0;
+ .MenuItem {
+ color: black;
+ margin-right: 2rem;
+ padding: 0 1rem;
+ align-items: center;
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+
+ &--popup {
+ display: block;
+ position: absolute;
+ top: 60px;
+ right: 19px;
+ width: 160px;
+
+ .MenuItem {
+ padding: 0.5rem;
+ border: solid 1px #7A7A7A;
+ border-bottom: none;
+ text-align: center;
+ margin-right: 0;
+ &:last-child {
+ border-bottom: solid 1px #7A7A7A;
+ }
+ }
+ }
+
+ &--fixed-top {
+ width: 100%;
+ z-index: 1040;
+ position: fixed;
+ right: 0;
+ left: 0;
+ top: 0;
+ }
+
+}
diff --git a/awx/ui/static/js/shared/utilities/icons.less b/awx/ui/static/js/shared/utilities/icons.less
new file mode 100644
index 0000000000..805c2ec335
--- /dev/null
+++ b/awx/ui/static/js/shared/utilities/icons.less
@@ -0,0 +1,16 @@
+@import "components-font-awesome/less/variables.less";
+
+/* not bem */
+
+.icon(@icon-var) {
+ display: flex;
+ align-self: center;
+ font-family: FontAwesome;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+
+ content: @icon-var;
+}
diff --git a/awx/ui/static/js/shared/utilities/layer.less b/awx/ui/static/js/shared/utilities/layer.less
new file mode 100644
index 0000000000..e5af025d5b
--- /dev/null
+++ b/awx/ui/static/js/shared/utilities/layer.less
@@ -0,0 +1,4 @@
+.u-layer {
+ position: relative;
+ z-index: 10000;
+}
diff --git a/awx/ui/static/js/tmp.less b/awx/ui/static/js/tmp.less
deleted file mode 100644
index 621cf94742..0000000000
--- a/awx/ui/static/js/tmp.less
+++ /dev/null
@@ -1,11 +0,0 @@
-/** @define Component */
-
-.Component {
- &-title {
- diddy: doo;
- }
- .diddy {
- dah: doody;
- }
- doo: dah;
-}
diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html
index 1e65dc521a..b6f3dc647a 100644
--- a/awx/ui/templates/ui/index.html
+++ b/awx/ui/templates/ui/index.html
@@ -28,100 +28,10 @@
-
-
-
@@ -273,7 +183,7 @@
Please enter a valid number.
Please enter a non-negative number.
Please enter a number smaller than 9999.
-
+
-
-