Merge pull request #624 from dod-ccpo/toggle-sidenav

Toggle sidenav
This commit is contained in:
dandds 2019-02-12 09:26:17 -05:00 committed by GitHub
commit 3c7fe2cf24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 247 additions and 165 deletions

View File

@ -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")

View File

@ -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=/'
},
},
}

View File

@ -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
},
},
}

View File

@ -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() {

23
js/mixins/toggle.js Normal file
View File

@ -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
},
},
}

View File

@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="angle-double-left" class="svg-inline--fa fa-angle-double-left fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M223.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L319.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L393.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34zm-192 34l136 136c9.4 9.4 24.6 9.4 33.9 0l22.6-22.6c9.4-9.4 9.4-24.6 0-33.9L127.9 256l96.4-96.4c9.4-9.4 9.4-24.6 0-33.9L201.7 103c-9.4-9.4-24.6-9.4-33.9 0l-136 136c-9.5 9.4-9.5 24.6-.1 34z"></path></svg>

After

Width:  |  Height:  |  Size: 630 B

View File

@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="angle-double-right" class="svg-inline--fa fa-angle-double-right fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34zm192-34l-136-136c-9.4-9.4-24.6-9.4-33.9 0l-22.6 22.6c-9.4 9.4-9.4 24.6 0 33.9l96.4 96.4-96.4 96.4c-9.4 9.4-9.4 24.6 0 33.9l22.6 22.6c9.4 9.4 24.6 9.4 33.9 0l136-136c9.4-9.2 9.4-24.4 0-33.8z"></path></svg>

After

Width:  |  Height:  |  Size: 634 B

View File

@ -67,6 +67,10 @@
@include icon-color($color-gray);
}
&.icon--blue {
@include icon-color($color-blue-darker);
}
&.icon--medium {
@include icon-size(12);
}

View File

@ -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;
}
}

View File

@ -2,23 +2,35 @@
{% from "components/sidenav_item.html" import SidenavItem %}
<div class="global-navigation sidenav">
<div class="sidenav__title">Portfolios</div>
<ul class="sidenav__list--padded">
{% for other_portfolio in portfolios|sort(attribute='name') %}
{{ SidenavItem(other_portfolio.name,
href=url_for("portfolios.show_portfolio", portfolio_id=other_portfolio.id),
active=(other_portfolio.id | string) == request.view_args.get('portfolio_id')
) }}
{% endfor %}
</ul>
<div class="sidenav__divider--small"></div>
<a class="sidenav__link sidenav__link--add" href="{{ url_for("task_orders.get_started") }}" title="Fund a New Portfolio">
<span class="sidenav__link-label">Fund a New Portfolio</span>
{{ Icon("plus", classes="sidenav__link-icon") }}
</a>
</div>
<div class="global-navigation sidenav--minimized">
<div class="sidenav__title">Show >>></div>
<div v-cloak is="SidenavToggler" class="sidenav-container">
<template slot-scope='props'>
<div v-bind:class="{'global-navigation': true, 'sidenav': props.isVisible, 'sidenav--minimized': !props.isVisible}">
<a href="#" v-on:click="props.toggle" class="sidenav__toggle">
<template v-if="props.isVisible">
{{ Icon('angle-double-left-solid', classes="toggle-arrows icon--blue") }}
Hide
</template>
<template v-else>
Show
{{ Icon('angle-double-right-solid', classes="toggle-arrows icon--blue") }}
</template>
</a>
<div v-if="props.isVisible">
<div class="sidenav__title">Portfolios</div>
<ul class="sidenav__list--padded">
{% for other_portfolio in portfolios|sort(attribute='name') %}
{{ SidenavItem(other_portfolio.name,
href=url_for("portfolios.show_portfolio", portfolio_id=other_portfolio.id),
active=(other_portfolio.id | string) == request.view_args.get('portfolio_id')
) }}
{% endfor %}
</ul>
<div class="sidenav__divider--small"></div>
<a class="sidenav__link sidenav__link--add" href="{{ url_for("task_orders.get_started") }}" title="Fund a New Portfolio">
<span class="sidenav__link-label">Fund a New Portfolio</span>
{{ Icon("plus", classes="sidenav__link-icon") }}
</a>
</div>
</div>
</template>
</div>