diff --git a/app/actions/ui.js b/app/actions/ui.js index 8d2f7ad..3f75d0b 100644 --- a/app/actions/ui.js +++ b/app/actions/ui.js @@ -44,4 +44,14 @@ UIActions.hideTaskDetailsSidebar = () => { } }; +UIActions.toggleSwimlane = (id, collapsed) => { + return { + type: 'TOGGLE_SWIMLANE', + payload: { + id: id, + swimlaneCollapsed: collapsed + } + } +}; + export default UIActions; diff --git a/app/components/Swimlane/header.jsx b/app/components/Swimlane/header.jsx index 790df79..930fad1 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, this.props.collapsed); + }, + 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..8132380 100644 --- a/app/components/Swimlane/index.jsx +++ b/app/components/Swimlane/index.jsx @@ -75,17 +75,20 @@ const Swimlane = React.createClass({ onCardMoved, onTaskUpdated, onSectionUpdated, + onSwimlaneToggle, isStatic, 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', { @@ -97,6 +100,8 @@ const Swimlane = React.createClass({ title: name, placeholder: headerPlaceholder, onSectionUpdated: onSectionUpdated, + onSwimlaneToggle: onSwimlaneToggle, + collapsed, isPlaceholder: isPlaceholder }; diff --git a/app/components/Swimlane/style.scss b/app/components/Swimlane/style.scss index 1ef7583..017a396 100644 --- a/app/components/Swimlane/style.scss +++ b/app/components/Swimlane/style.scss @@ -32,6 +32,43 @@ $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; + + &__update-form { + transform: rotate(90deg); + } + + &__update-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 +80,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..746fb6b 100644 --- a/app/components/TaskDetailsSidebar/style.scss +++ b/app/components/TaskDetailsSidebar/style.scss @@ -71,6 +71,9 @@ $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..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 } }; @@ -78,6 +79,9 @@ const mapDispatchToProps = (dispatch) => { dispatch(Actions.deleteTask(options)); EventActions.deleteTask(id); + }, + onSwimlaneToggle: (id, collapsed) => { + dispatch(UIActions.toggleSwimlane(id, collapsed)) } } }; @@ -111,6 +115,9 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { }, onTaskUpdated: (task, updateAsana) => { dispatchProps.onTaskUpdated(task, id, currentProjectId, updateAsana); + }, + onSwimlaneToggle: (id, collapsed) => { + dispatchProps.onSwimlaneToggle(id, collapsed); } }; diff --git a/app/reducers/ui.js b/app/reducers/ui.js index cf591fa..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) { @@ -35,6 +36,13 @@ export default function auth(state = initialState, action) { case 'FETCHING_UPDATED_TASK_INFORMATION_SUCCESS': { return Object.assign({}, state, { showTaskDetailsSidebarLoading: false }); } + case 'TOGGLE_SWIMLANE': { + if (action.payload.swimlaneCollapsed) { + return Object.assign({}, state, { swimlaneCollapsed: false }); + } else { + return Object.assign({}, state, { swimlaneCollapsed: true }); + } + } default: { return state; }