Skip to content

Commit 07b3c7e

Browse files
committed
feat(Add and Delete Lanes): Ability to delete lanes when canAddLanes prop is set to true
#163
1 parent 5a33c31 commit 07b3c7e

File tree

11 files changed

+10665
-10305
lines changed

11 files changed

+10665
-10305
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
},
4040
"homepage": "https://github.com/rcdexta/react-trello",
4141
"dependencies": {
42+
"@terebentina/react-popover": "^2.0.0",
4243
"immutability-helper": "^2.8.1",
4344
"lodash": "^4.17.11",
4445
"prop-types": "^15.6.2",

src/actions/LaneActions.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export const updateCards = createAction('UPDATE_CARDS')
77
export const updateLanes = createAction('UPDATE_LANES')
88
export const paginateLane = createAction('PAGINATE_LANE')
99
export const moveLane = createAction('MOVE_LANE')
10+
export const removeLane = createAction('REMOVE_LANE')

src/components/BoardContainer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {BoardDiv, LaneSection} from '../styles/Base'
1010
import {NewLaneButton} from '../styles/Elements'
1111
import Lane from './Lane'
1212
import NewLane from './NewLane'
13+
import { PopoverWrapper } from '@terebentina/react-popover'
1314

1415
import * as boardActions from '../actions/BoardActions'
1516
import * as laneActions from '../actions/LaneActions'
@@ -150,6 +151,7 @@ class BoardContainer extends Component {
150151

151152
return (
152153
<BoardDiv style={style} {...otherProps} draggable={false}>
154+
<PopoverWrapper>
153155
<Container
154156
orientation="horizontal"
155157
onDragStart={this.onDragStart}
@@ -176,6 +178,7 @@ class BoardContainer extends Component {
176178
return draggable && laneDraggable ? <Draggable key={lane.id}>{laneToRender}</Draggable> : <span key={lane.id}>{laneToRender}</span>
177179
})}
178180
</Container>
181+
</PopoverWrapper>
179182
{canAddLanes && (
180183
<Container orientation="horizontal">
181184
{editable && !addLaneMode ? (

src/components/Lane.js

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,25 @@ import isEqual from 'lodash/isEqual'
66
import Container from '../dnd/Container'
77
import Draggable from '../dnd/Draggable'
88
import uuidv1 from 'uuid/v1'
9+
import Popover from '@terebentina/react-popover'
910

1011
import Loader from './Loader'
1112
import Card from './Card'
1213
import NewCard from './NewCard'
1314
import {AddCardLink, LaneFooter, LaneHeader, RightContent, ScrollableLane, Section, Title} from '../styles/Base'
1415

1516
import * as laneActions from '../actions/LaneActions'
16-
import {CollapseBtn, ExpandBtn} from '../styles/Elements'
17+
import {
18+
CollapseBtn,
19+
DeleteWrapper,
20+
ExpandBtn,
21+
GenDelButton,
22+
LaneMenuContent,
23+
LaneMenuHeader,
24+
LaneMenuItem,
25+
LaneMenuTitle,
26+
MenuButton
27+
} from '../styles/Elements'
1728

1829
class Lane extends Component {
1930
state = {
@@ -195,8 +206,29 @@ class Lane extends Component {
195206
)
196207
}
197208

209+
removeLane = () => {
210+
const {id} = this.props
211+
this.props.actions.removeLane({laneId: id})
212+
}
213+
214+
laneMenu = () => {
215+
return (
216+
<Popover className="menu" position="bottom" trigger={<MenuButton></MenuButton>}>
217+
<LaneMenuHeader>
218+
<LaneMenuTitle>Lane actions</LaneMenuTitle>
219+
<DeleteWrapper>
220+
<GenDelButton>&#10006;</GenDelButton>
221+
</DeleteWrapper>
222+
</LaneMenuHeader>
223+
<LaneMenuContent>
224+
<LaneMenuItem onClick={this.removeLane}>Delete Lane...</LaneMenuItem>
225+
</LaneMenuContent>
226+
</Popover>
227+
)
228+
}
229+
198230
renderHeader = () => {
199-
const {customLaneHeader} = this.props
231+
const {customLaneHeader, canAddLanes} = this.props
200232
if (customLaneHeader) {
201233
const customLaneElement = React.cloneElement(customLaneHeader, {...this.props})
202234
return <span>{customLaneElement}</span>
@@ -210,6 +242,7 @@ class Lane extends Component {
210242
<span style={labelStyle}>{label}</span>
211243
</RightContent>
212244
)}
245+
{canAddLanes && this.laneMenu()}
213246
</LaneHeader>
214247
)
215248
}
@@ -272,7 +305,8 @@ Lane.propTypes = {
272305
addCardTitle: PropTypes.string,
273306
editable: PropTypes.bool,
274307
cardDraggable: PropTypes.bool,
275-
cardDragClass: PropTypes.string
308+
cardDragClass: PropTypes.string,
309+
canAddLanes: PropTypes.bool
276310
}
277311

278312
Lane.defaultProps = {

src/components/widgets/DeleteButton.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {DeleteWrapper, DelButton} from '../../styles/Elements'
44
const DeleteButton = props => {
55
return (
66
<DeleteWrapper {...props}>
7-
<DelButton>x</DelButton>
7+
<DelButton>&#10006;</DelButton>
88
</DeleteWrapper>
99
)
1010
}

src/helpers/LaneHelper.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ const LaneHelper = {
9292
const laneToMove = state.lanes[oldIndex]
9393
const tempState = update(state, {lanes: {$splice: [[oldIndex, 1]]}});
9494
return update(tempState, {lanes: {$splice: [[newIndex, 0, laneToMove]]}})
95+
},
96+
97+
removeLane: (state, {laneId}) => {
98+
const updatedLanes = state.lanes.filter(lane => lane.id !== laneId)
99+
return update(state, {lanes: {$set: updatedLanes}})
95100
}
96101
}
97102

src/reducers/BoardReducer.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const boardReducer = (state = {lanes: []}, action) => {
1919
return Lh.paginateLane(state, payload)
2020
case 'MOVE_LANE':
2121
return Lh.moveLane(state, payload)
22+
case 'REMOVE_LANE':
23+
return Lh.removeLane(state, payload)
2224
case 'ADD_LANE':
2325
return Lh.addLane(state, payload)
2426
default:

src/styles/Base.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,57 @@
11
import styled, {createGlobalStyle} from 'styled-components'
22

33
export const GlobalStyle = createGlobalStyle`
4+
5+
.popover {
6+
position: absolute;
7+
right: 10px;
8+
}
9+
.popover .popover__content {
10+
visibility: hidden;
11+
margin-top: -5px;
12+
opacity: 0;
13+
position: absolute;
14+
z-index: 10;
15+
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3);
16+
transition: all 0.3s ease 0ms;
17+
border-radius: 3px;
18+
min-width: 7em;
19+
flex-flow: column nowrap;
20+
background-color: #fff;
21+
color: #000;
22+
padding: 5px; }
23+
.popover .popover__content::before {
24+
content: "";
25+
position: absolute;
26+
background: transparent none repeat scroll 0 0;
27+
border: 6px solid transparent;
28+
transition: all 0.3s ease 0ms; }
29+
left: 50%; }
30+
.popover.popover--bottom {
31+
flex-flow: column nowrap; }
32+
.popover.popover--bottom .popover__content {
33+
left: 50%;
34+
transform: translateX(-50%); }
35+
36+
.popover.popover--active .popover__content {
37+
visibility: visible;
38+
opacity: 1;
39+
transition-delay: 100ms; }
40+
.popover[class*="menu"] .popover__content {
41+
border-radius: 3px;
42+
min-width: 7em;
43+
flex-flow: column nowrap;
44+
color: #000; }
45+
.popover[class*="menu"] .popover__content a {
46+
color: rgba(255, 255, 255, 0.56);
47+
padding: .5em 1em;
48+
margin: 0;
49+
text-decoration: none; }
50+
.popover[class*="menu"] .popover__content a:hover {
51+
background-color: #00bcd4 !important;
52+
color: #37474F; }
53+
54+
455
.comPlainTextContentEditable {
556
-webkit-user-modify: read-write-plaintext-only;
657
}
@@ -19,6 +70,19 @@ export const GlobalStyle = createGlobalStyle`
1970
.react_trello_dragLaneClass {
2071
transform: rotate(3deg);
2172
}
73+
74+
.icon-overflow-menu-horizontal:before {
75+
content: "\\E91F";
76+
}
77+
.icon-lg, .icon-sm {
78+
color: #798d99;
79+
}
80+
.icon-lg {
81+
height: 32px;
82+
font-size: 16px;
83+
line-height: 32px;
84+
width: 32px;
85+
}
2286
`
2387

2488
export const BoardDiv = styled.div`

src/styles/Elements.js

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,28 @@ export const DeleteWrapper = styled.div`
66
position: absolute;
77
top: -1px;
88
right: 2px;
9+
cursor: pointer;
910
`
1011

11-
export const DelButton = styled.button`
12-
font-weight: bold;
12+
export const GenDelButton = styled.button`
13+
transition: all 0.5s ease;
14+
display: inline-block;
1315
border: none;
16+
font-size: 15px;
17+
height: 15px;
18+
padding: 0;
19+
margin-top: 5px;
20+
text-align: center;
21+
width: 15px;
22+
background: inherit;
23+
cursor: pointer;
24+
`
25+
26+
export const DelButton = styled.button`
27+
transition: all 0.5s ease;
1428
display: inline-block;
29+
border: none;
1530
font-size: 8px;
16-
opacity: 0;
1731
height: 15px;
1832
line-height: 1px;
1933
margin: 0 0 8px;
@@ -22,12 +36,71 @@ export const DelButton = styled.button`
2236
width: 15px;
2337
background: inherit;
2438
cursor: pointer;
25-
39+
opacity: 0;
2640
${MovableCardWrapper}:hover & {
2741
opacity: 1;
2842
}
2943
`
3044

45+
export const MenuButton = styled.button`
46+
transition: all 0.5s ease;
47+
display: inline-block;
48+
border: none;
49+
outline: none;
50+
font-size: 16px;
51+
font-weight: bold;
52+
height: 15px;
53+
line-height: 1px;
54+
margin: 0 0 8px;
55+
padding: 0;
56+
text-align: center;
57+
width: 15px;
58+
background: inherit;
59+
cursor: pointer;
60+
`
61+
62+
export const LaneMenuHeader = styled.div`
63+
position: relative;
64+
margin-bottom: 4px;
65+
text-align: center;
66+
`
67+
68+
export const LaneMenuContent = styled.div`
69+
overflow-x: hidden;
70+
overflow-y: auto;
71+
padding: 0 12px 12px;
72+
`
73+
74+
export const LaneMenuItem = styled.div`
75+
cursor: pointer;
76+
display: block;
77+
font-weight: 700;
78+
padding: 6px 12px;
79+
position: relative;
80+
margin: 0 -12px;
81+
text-decoration: none;
82+
83+
&:hover {
84+
background-color: #3179BA;
85+
color: #fff;
86+
}
87+
`
88+
89+
export const LaneMenuTitle = styled.span`
90+
box-sizing: border-box;
91+
color: #6b808c;
92+
display: block;
93+
line-height: 30px;
94+
border-bottom: 1px solid rgba(9,45,66,.13);
95+
margin: 0 6px;
96+
overflow: hidden;
97+
padding: 0 32px;
98+
position: relative;
99+
text-overflow: ellipsis;
100+
white-space: nowrap;
101+
z-index: 1;
102+
`
103+
31104
export const DeleteIcon = styled.span`
32105
position: relative;
33106
display: inline-block;

0 commit comments

Comments
 (0)