From 5bbec2e932da91592946c521a31d28316550df1c Mon Sep 17 00:00:00 2001 From: Tatianna Wiegand-Stuart Date: Tue, 19 Jul 2016 14:13:20 -0400 Subject: [PATCH 1/3] Added ability to toggle/minimize lanes --- app/actions/ui.js | 9 ++++ app/components/Swimlane/header.jsx | 5 ++ app/components/Swimlane/index.jsx | 2 + app/components/Swimlane/style.scss | 51 ++++++++++++++++++++ app/components/TaskDetailsSidebar/style.scss | 1 + app/containers/SwimlaneContainer.js | 9 +++- app/reducers/ui.js | 4 ++ 7 files changed, 80 insertions(+), 1 deletion(-) diff --git a/app/actions/ui.js b/app/actions/ui.js index 8d2f7ad..9d0da87 100644 --- a/app/actions/ui.js +++ b/app/actions/ui.js @@ -44,4 +44,13 @@ UIActions.hideTaskDetailsSidebar = () => { } }; +UIActions.toggleSwimlane = (id) => { + return { + type: 'TOGGLE_SWIMLANE', + payload: { + id: id + } + } +}; + export default UIActions; diff --git a/app/components/Swimlane/header.jsx b/app/components/Swimlane/header.jsx index 790df79..95c28f5 100644 --- a/app/components/Swimlane/header.jsx +++ b/app/components/Swimlane/header.jsx @@ -1,6 +1,10 @@ import React from 'react'; const SwimlaneHeader = React.createClass({ + handleSwimlaneToggle() { + this.props.onSwimlaneToggle(this.props.id); + }, + handleTextUpdate(updateAsana = false) { const { sectionInput } = this.refs; @@ -59,6 +63,7 @@ const SwimlaneHeader = React.createClass({ render() { return (
+ { this.renderInput() }
); diff --git a/app/components/Swimlane/index.jsx b/app/components/Swimlane/index.jsx index a5d951a..a1ba722 100644 --- a/app/components/Swimlane/index.jsx +++ b/app/components/Swimlane/index.jsx @@ -75,6 +75,7 @@ const Swimlane = React.createClass({ onCardMoved, onTaskUpdated, onSectionUpdated, + onSwimlaneToggle, isStatic, isFullWidth, fullHeight, @@ -97,6 +98,7 @@ const Swimlane = React.createClass({ title: name, placeholder: headerPlaceholder, onSectionUpdated: onSectionUpdated, + onSwimlaneToggle: onSwimlaneToggle, isPlaceholder: isPlaceholder }; diff --git a/app/components/Swimlane/style.scss b/app/components/Swimlane/style.scss index 1ef7583..6c43c2e 100644 --- a/app/components/Swimlane/style.scss +++ b/app/components/Swimlane/style.scss @@ -32,6 +32,41 @@ $swimlane-height-small: 250px; margin-left: 0; } + &--collapsed { + border-bottom-left-radius: $swimlane-border-radius; + border-bottom-right-radius: $swimlane-border-radius; + flex: none; + height: $swimlane-width; + overflow-y: visible; + width: $swimlane-header-height; + + .swimlane { + &__cards {display: none;} + + &__header { + border-bottom-left-radius: $swimlane-border-radius; + border-bottom-right-radius: $swimlane-border-radius; + height: $swimlane-width; + width: $swimlane-header-height; + + form { + transform: rotate(90deg); + + input { + width: $swimlane-width - 35px; + } + } + + &__button { + border-bottom-right-radius: $swimlane-border-radius; + border-top-right-radius: 0; + bottom: 0; + top: auto; + } + } + } + } + &__header { width: 100%; height: $swimlane-header-height; @@ -43,6 +78,22 @@ $swimlane-height-small: 250px; border-left: $swimlane-border; background-color: #F9FAFB; + &__button { + background: transparent; + border: $swimlane-border; + border-top-right-radius: $swimlane-border-radius; + border-bottom-left-radius: $swimlane-border-radius; + font-size: .75em; + outline: none; + position: absolute; + right: 0; + top: 0; + &:hover { + border-color: $brand-blue; + color: $brand-blue; + } + } + &__text { width: $swimlane-width - 1px; padding-top: $swimlane-header-horizontal-padding; diff --git a/app/components/TaskDetailsSidebar/style.scss b/app/components/TaskDetailsSidebar/style.scss index ed95575..e111015 100644 --- a/app/components/TaskDetailsSidebar/style.scss +++ b/app/components/TaskDetailsSidebar/style.scss @@ -71,6 +71,7 @@ $sidebar-components-vertical-padding: 25px; &__sub-tasks { padding-bottom: $sidebar-components-vertical-padding; + .swimlane__header__button {display: none;} } &__user-name { diff --git a/app/containers/SwimlaneContainer.js b/app/containers/SwimlaneContainer.js index 6a4f181..b38ad90 100644 --- a/app/containers/SwimlaneContainer.js +++ b/app/containers/SwimlaneContainer.js @@ -11,7 +11,8 @@ const mapStateToProps = (state) => { cardEntities: state.entities.cards.records, currentProjectId: state.entities.projects.conditions.currentId, projectEntities: state.entities.projects.records, - currentTaskId: state.entities.cards.conditions.currentId + currentTaskId: state.entities.cards.conditions.currentId, + swimlaneCollapsed: state.ui.swimlaneCollapsed } }; @@ -78,6 +79,9 @@ const mapDispatchToProps = (dispatch) => { dispatch(Actions.deleteTask(options)); EventActions.deleteTask(id); + }, + onSwimlaneToggle: (id) => { + dispatch(UIActions.toggleSwimlane(id)) } } }; @@ -111,6 +115,9 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { }, onTaskUpdated: (task, updateAsana) => { dispatchProps.onTaskUpdated(task, id, currentProjectId, updateAsana); + }, + onSwimlaneToggle: (id) => { + dispatchProps.onSwimlaneToggle(id); } }; diff --git a/app/reducers/ui.js b/app/reducers/ui.js index cf591fa..5d0b04f 100644 --- a/app/reducers/ui.js +++ b/app/reducers/ui.js @@ -1,4 +1,5 @@ const initialState = { + collapsedLanes: [], showSidebar: false, showSidebarLoading: false, showProjectLoading: false, @@ -35,6 +36,9 @@ export default function auth(state = initialState, action) { case 'FETCHING_UPDATED_TASK_INFORMATION_SUCCESS': { return Object.assign({}, state, { showTaskDetailsSidebarLoading: false }); } + case 'TOGGLE_SWIMLANE': { + return document.querySelector('section[data-reactid*="'+action.payload.id+'"]').classList.toggle('swimlane--collapsed'); + } default: { return state; } From d462992a3b4cd6e7d3b2941ac7cd2ca6066a103d Mon Sep 17 00:00:00 2001 From: Tatianna Wiegand-Stuart Date: Tue, 19 Jul 2016 14:19:06 -0400 Subject: [PATCH 2/3] Code cleanup - removed unused lines --- app/containers/SwimlaneContainer.js | 3 +-- app/reducers/ui.js | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/containers/SwimlaneContainer.js b/app/containers/SwimlaneContainer.js index b38ad90..44014ee 100644 --- a/app/containers/SwimlaneContainer.js +++ b/app/containers/SwimlaneContainer.js @@ -11,8 +11,7 @@ const mapStateToProps = (state) => { cardEntities: state.entities.cards.records, currentProjectId: state.entities.projects.conditions.currentId, projectEntities: state.entities.projects.records, - currentTaskId: state.entities.cards.conditions.currentId, - swimlaneCollapsed: state.ui.swimlaneCollapsed + currentTaskId: state.entities.cards.conditions.currentId } }; diff --git a/app/reducers/ui.js b/app/reducers/ui.js index 5d0b04f..b84c9ab 100644 --- a/app/reducers/ui.js +++ b/app/reducers/ui.js @@ -1,5 +1,4 @@ const initialState = { - collapsedLanes: [], showSidebar: false, showSidebarLoading: false, showProjectLoading: false, From a69757bb705c7c4ee59b11487154d7ac0786b01a Mon Sep 17 00:00:00 2001 From: Tatianna Wiegand-Stuart Date: Wed, 20 Jul 2016 14:48:45 -0400 Subject: [PATCH 3/3] Swimlane toggle with 'collapsed' property --- app/actions/ui.js | 5 +++-- app/components/Swimlane/header.jsx | 4 ++-- app/components/Swimlane/index.jsx | 5 ++++- app/components/Swimlane/style.scss | 10 ++++++---- app/components/TaskDetailsSidebar/style.scss | 4 +++- app/containers/SwimlaneContainer.js | 11 ++++++----- app/reducers/ui.js | 9 +++++++-- 7 files changed, 31 insertions(+), 17 deletions(-) diff --git a/app/actions/ui.js b/app/actions/ui.js index 9d0da87..3f75d0b 100644 --- a/app/actions/ui.js +++ b/app/actions/ui.js @@ -44,11 +44,12 @@ UIActions.hideTaskDetailsSidebar = () => { } }; -UIActions.toggleSwimlane = (id) => { +UIActions.toggleSwimlane = (id, collapsed) => { return { type: 'TOGGLE_SWIMLANE', payload: { - id: id + id: id, + swimlaneCollapsed: collapsed } } }; diff --git a/app/components/Swimlane/header.jsx b/app/components/Swimlane/header.jsx index 95c28f5..930fad1 100644 --- a/app/components/Swimlane/header.jsx +++ b/app/components/Swimlane/header.jsx @@ -2,7 +2,7 @@ import React from 'react'; const SwimlaneHeader = React.createClass({ handleSwimlaneToggle() { - this.props.onSwimlaneToggle(this.props.id); + this.props.onSwimlaneToggle(this.props.id, this.props.collapsed); }, handleTextUpdate(updateAsana = false) { @@ -63,7 +63,7 @@ const SwimlaneHeader = React.createClass({ render() { return (
- + { this.renderInput() }
); diff --git a/app/components/Swimlane/index.jsx b/app/components/Swimlane/index.jsx index a1ba722..8132380 100644 --- a/app/components/Swimlane/index.jsx +++ b/app/components/Swimlane/index.jsx @@ -80,13 +80,15 @@ const Swimlane = React.createClass({ isFullWidth, fullHeight, hasGutter, + collapsed, headerPlaceholder, isPlaceholder } = this.props; const sectionClasses = classNames('swimlane', { 'swimlane--full-width': isFullWidth, - 'swimlane--no-gutter': !hasGutter + 'swimlane--no-gutter': !hasGutter, + 'swimlane--collapsed': collapsed }); const cardClasses = classNames('swimlane__cards', { @@ -99,6 +101,7 @@ const Swimlane = React.createClass({ placeholder: headerPlaceholder, onSectionUpdated: onSectionUpdated, onSwimlaneToggle: onSwimlaneToggle, + collapsed, isPlaceholder: isPlaceholder }; diff --git a/app/components/Swimlane/style.scss b/app/components/Swimlane/style.scss index 6c43c2e..017a396 100644 --- a/app/components/Swimlane/style.scss +++ b/app/components/Swimlane/style.scss @@ -41,7 +41,9 @@ $swimlane-height-small: 250px; width: $swimlane-header-height; .swimlane { - &__cards {display: none;} + &__cards { + display: none; + } &__header { border-bottom-left-radius: $swimlane-border-radius; @@ -49,12 +51,12 @@ $swimlane-height-small: 250px; height: $swimlane-width; width: $swimlane-header-height; - form { + &__update-form { transform: rotate(90deg); + } - input { + &__update-input { width: $swimlane-width - 35px; - } } &__button { diff --git a/app/components/TaskDetailsSidebar/style.scss b/app/components/TaskDetailsSidebar/style.scss index e111015..746fb6b 100644 --- a/app/components/TaskDetailsSidebar/style.scss +++ b/app/components/TaskDetailsSidebar/style.scss @@ -71,7 +71,9 @@ $sidebar-components-vertical-padding: 25px; &__sub-tasks { padding-bottom: $sidebar-components-vertical-padding; - .swimlane__header__button {display: none;} + .swimlane__header__button { + display: none; + } } &__user-name { diff --git a/app/containers/SwimlaneContainer.js b/app/containers/SwimlaneContainer.js index 44014ee..05cf771 100644 --- a/app/containers/SwimlaneContainer.js +++ b/app/containers/SwimlaneContainer.js @@ -11,7 +11,8 @@ const mapStateToProps = (state) => { cardEntities: state.entities.cards.records, currentProjectId: state.entities.projects.conditions.currentId, projectEntities: state.entities.projects.records, - currentTaskId: state.entities.cards.conditions.currentId + currentTaskId: state.entities.cards.conditions.currentId, + collapsed: state.ui.swimlaneCollapsed } }; @@ -79,8 +80,8 @@ const mapDispatchToProps = (dispatch) => { dispatch(Actions.deleteTask(options)); EventActions.deleteTask(id); }, - onSwimlaneToggle: (id) => { - dispatch(UIActions.toggleSwimlane(id)) + onSwimlaneToggle: (id, collapsed) => { + dispatch(UIActions.toggleSwimlane(id, collapsed)) } } }; @@ -115,8 +116,8 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { onTaskUpdated: (task, updateAsana) => { dispatchProps.onTaskUpdated(task, id, currentProjectId, updateAsana); }, - onSwimlaneToggle: (id) => { - dispatchProps.onSwimlaneToggle(id); + onSwimlaneToggle: (id, collapsed) => { + dispatchProps.onSwimlaneToggle(id, collapsed); } }; diff --git a/app/reducers/ui.js b/app/reducers/ui.js index b84c9ab..c1d23df 100644 --- a/app/reducers/ui.js +++ b/app/reducers/ui.js @@ -3,7 +3,8 @@ const initialState = { showSidebarLoading: false, showProjectLoading: false, showTaskDetailsSidebar: false, - showTaskDetailsSidebarLoading: false + showTaskDetailsSidebarLoading: false, + swimlaneCollapsed: false }; export default function auth(state = initialState, action) { @@ -36,7 +37,11 @@ export default function auth(state = initialState, action) { return Object.assign({}, state, { showTaskDetailsSidebarLoading: false }); } case 'TOGGLE_SWIMLANE': { - return document.querySelector('section[data-reactid*="'+action.payload.id+'"]').classList.toggle('swimlane--collapsed'); + if (action.payload.swimlaneCollapsed) { + return Object.assign({}, state, { swimlaneCollapsed: false }); + } else { + return Object.assign({}, state, { swimlaneCollapsed: true }); + } } default: { return state;