diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index 9726c8b8..4f0e91cb 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -1,5 +1,14 @@ import urllib.parse as url -from flask import Blueprint, render_template, g, redirect, session, url_for, request +from flask import ( + Blueprint, + render_template, + g, + redirect, + session, + url_for, + request, + make_response, +) from flask import current_app as app from jinja2.exceptions import TemplateNotFound @@ -131,7 +140,9 @@ def login_redirect(): @bp.route("/logout") def logout(): _logout() - return redirect(url_for(".root")) + response = make_response(redirect(url_for(".root"))) + response.set_cookie("expandSidenav", "", expires=0) + return response @bp.route("/activity-history") diff --git a/js/components/sidenav_toggler.js b/js/components/sidenav_toggler.js new file mode 100644 index 00000000..faba4c3b --- /dev/null +++ b/js/components/sidenav_toggler.js @@ -0,0 +1,30 @@ +import ToggleMixin from '../mixins/toggle' + +const cookieName = 'expandSidenav' + +export default { + name: 'sidenav-toggler', + + mixins: [ToggleMixin], + + props: { + defaultVisible: { + type: Boolean, + default: function() { + if (document.cookie.match(cookieName)) { + return !!document.cookie.match(cookieName + ' *= *true') + } else { + return true + } + }, + }, + }, + + methods: { + toggle: function(e) { + e.preventDefault() + this.isVisible = !this.isVisible + document.cookie = cookieName + '=' + this.isVisible + '; path=/' + }, + }, +} diff --git a/js/components/toggler.js b/js/components/toggler.js index 0cd18dc8..a3e1ece5 100644 --- a/js/components/toggler.js +++ b/js/components/toggler.js @@ -1,32 +1,14 @@ +import ToggleMixin from '../mixins/toggle' + export default { name: 'toggler', + mixins: [ToggleMixin], + props: { defaultVisible: { type: Boolean, default: () => false, }, }, - - data: function() { - return { - isVisible: this.defaultVisible, - } - }, - - render: function(createElement) { - return createElement(this.$vnode.data.tag, [ - this.$scopedSlots.default({ - isVisible: this.isVisible, - toggle: this.toggle, - }), - ]) - }, - - methods: { - toggle: function(e) { - e.preventDefault() - this.isVisible = !this.isVisible - }, - }, } diff --git a/js/index.js b/js/index.js index f2f82bc9..7495c51c 100644 --- a/js/index.js +++ b/js/index.js @@ -33,6 +33,7 @@ import RequestsList from './components/requests_list' import ConfirmationPopover from './components/confirmation_popover' import { isNotInVerticalViewport } from './lib/viewport' import DateSelector from './components/date_selector' +import SidenavToggler from './components/sidenav_toggler' Vue.config.productionTip = false @@ -68,6 +69,7 @@ const app = new Vue({ uploadinput, DateSelector, EditOfficerForm, + SidenavToggler, }, mounted: function() { diff --git a/js/mixins/toggle.js b/js/mixins/toggle.js new file mode 100644 index 00000000..d891eb02 --- /dev/null +++ b/js/mixins/toggle.js @@ -0,0 +1,23 @@ +export default { + data: function() { + return { + isVisible: this.defaultVisible, + } + }, + + render: function(createElement) { + return createElement(this.$vnode.data.tag, [ + this.$scopedSlots.default({ + isVisible: this.isVisible, + toggle: this.toggle, + }), + ]) + }, + + methods: { + toggle: function(e) { + e.preventDefault() + this.isVisible = !this.isVisible + }, + }, +} diff --git a/static/icons/angle-double-left-solid.svg b/static/icons/angle-double-left-solid.svg new file mode 100644 index 00000000..95887a19 --- /dev/null +++ b/static/icons/angle-double-left-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/icons/angle-double-right-solid.svg b/static/icons/angle-double-right-solid.svg new file mode 100644 index 00000000..998f8595 --- /dev/null +++ b/static/icons/angle-double-right-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/styles/elements/_icons.scss b/styles/elements/_icons.scss index df42642c..fa3f54f6 100644 --- a/styles/elements/_icons.scss +++ b/styles/elements/_icons.scss @@ -67,6 +67,10 @@ @include icon-color($color-gray); } + &.icon--blue { + @include icon-color($color-blue-darker); + } + &.icon--medium { @include icon-size(12); } diff --git a/styles/elements/_sidenav.scss b/styles/elements/_sidenav.scss index dcfcfe10..57e4d1f1 100644 --- a/styles/elements/_sidenav.scss +++ b/styles/elements/_sidenav.scss @@ -1,160 +1,176 @@ -.sidenav { - @include hide; +@mixin sidenav__header { + padding: $gap ($gap * 2); + font-size: $small-font-size; + font-weight: bold; +} - @include media($large-screen) { - @include unhide; - width: 25rem; - margin: 0px; +.sidenav-container { + position: relative; + + .global-navigation.sidenav { + height: 100%; } - box-shadow: 0 6px 18px 0 rgba(48,58,65,0.15); - - .sidenav__title { - color: $color-gray-dark; - padding: $gap ($gap * 2); - text-transform: uppercase; - opacity: 0.54; - font-size: $small-font-size; - font-weight: bold; - } - - ul { - &.sidenav__list--padded { - margin: 4 * $gap 0; + .sidenav { + @include media($large-screen) { + width: 25rem; + margin: 0px; } - list-style: none; - padding: 0; + box-shadow: 0 6px 18px 0 rgba(48,58,65,0.15); - li { - margin: 0; - display: block; + .sidenav__title { + @include sidenav__header; + text-transform: uppercase; + width: 50%; + color: $color-gray-dark; + opacity: 0.54; } - } + .sidenav__toggle { + @include sidenav__header; + float: right; + color: $color-blue-darker; - .sidenav__divider--small { - display: block; - width: 4 * $gap; - border: 1px solid #D6D7D9; - margin-left: 2 * $gap; - margin-bottom: $gap; - } - - .sidenav__link { - display: block; - padding: $gap ($gap * 2); - color: $color-black; - text-decoration: none; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - .sidenav__link-icon { - margin-left: - ($gap * .5); + .toggle-arrows { + vertical-align: middle; + } } - &.sidenav__link--disabled { - color: $color-shadow; - pointer-events: none; - } + ul { + &.sidenav__list--padded { + margin: 4 * $gap 0; + } - &.sidenav__link--add { - color: $color-blue; - font-size: $small-font-size; - .icon { - @include icon-color($color-blue); - @include icon-size(14); + list-style: none; + padding: 0; + + li { + margin: 0; + display: block; } } - &.sidenav__link--active { - @include h4; - color: $color-primary; - background-color: $color-aqua-lightest; - box-shadow: inset ($gap / 2) 0 0 0 $color-primary; + .sidenav__divider--small { + display: block; + width: 4 * $gap; + border: 1px solid #D6D7D9; + margin-left: 2 * $gap; + margin-bottom: $gap; + } + + .sidenav__link { + display: block; + padding: $gap ($gap * 2); + color: $color-black; + text-decoration: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; .sidenav__link-icon { - @include icon-style-active; + margin-left: - ($gap * .5); } - position: relative; - .sidenav__link-active_indicator .icon { - @include icon-color($color-primary); - position: absolute; - right: 0; + &.sidenav__link--disabled { + color: $color-shadow; + pointer-events: none; + } + + &.sidenav__link--add { + color: $color-blue; + font-size: $small-font-size; + .icon { + @include icon-color($color-blue); + @include icon-size(14); + } + + } + + &.sidenav__link--active { + @include h4; + color: $color-primary; + background-color: $color-aqua-lightest; + box-shadow: inset ($gap / 2) 0 0 0 $color-primary; + + .sidenav__link-icon { + @include icon-style-active; + } + + position: relative; + .sidenav__link-active_indicator .icon { + @include icon-color($color-primary); + position: absolute; + right: 0; + } + + + ul { + background-color: $color-primary; + + .sidenav__link { + color: $color-white; + background-color: $color-primary; + + &:hover { + background-color: $color-blue-darker; + } + + &--active { + @include h5; + color: $color-white; + background-color: $color-primary; + box-shadow: none; + } + + .icon { + @include icon-color($color-white); + } + } + } } + ul { - background-color: $color-primary; + // padding-bottom: $gap / 2; - .sidenav__link { - color: $color-white; - background-color: $color-primary; - - &:hover { - background-color: $color-blue-darker; - } - - &--active { + li { + .sidenav__link { @include h5; - color: $color-white; - background-color: $color-primary; - box-shadow: none; - } + padding: $gap * .75; + padding-left: 4.5rem; + border: 0; + font-weight: normal; - .icon { - @include icon-color($color-white); + .sidenav__link-icon { + @include icon-size(12); + flex-shrink: 0; + margin-right: 1.5rem; + margin-left: -3rem + } + + .sidenav__link-label { + padding-left: 0; + } } } } - } - + ul { - // padding-bottom: $gap / 2; + &:hover { + color: $color-primary; + background-color: $color-aqua-lightest; - li { - .sidenav__link { - @include h5; - padding: $gap * .75; - padding-left: 4.5rem; - border: 0; - font-weight: normal; - - .sidenav__link-icon { - @include icon-size(12); - flex-shrink: 0; - margin-right: 1.5rem; - margin-left: -3rem - } - - .sidenav__link-label { - padding-left: 0; - } + .sidenav__link-icon { + @include icon-style-active; } + } } + } - &:hover { - color: $color-primary; - background-color: $color-aqua-lightest; + .sidenav--minimized { + @extend .sidenav; - .sidenav__link-icon { - @include icon-style-active; - } - - } - } -} - -.sidenav--minimized { - @extend .sidenav; - - @include unhide; - margin: 0px; - - @include media($large-screen) { - @include hide; + width: auto; + margin: 0px; } } diff --git a/templates/navigation/global_sidenav.html b/templates/navigation/global_sidenav.html index 00783943..98248ea9 100644 --- a/templates/navigation/global_sidenav.html +++ b/templates/navigation/global_sidenav.html @@ -2,23 +2,35 @@ {% from "components/sidenav_item.html" import SidenavItem %} -
- -