From d175ff4ce1893a0529e827e33b8462f14e456b9a Mon Sep 17 00:00:00 2001 From: onicolasz Date: Thu, 12 Sep 2024 14:52:20 -0300 Subject: [PATCH 1/4] feat: added scroll board function with mouse --- src/controllers/BoardContainer.js | 74 ++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 6 deletions(-) diff --git a/src/controllers/BoardContainer.js b/src/controllers/BoardContainer.js index 7603b894..2c46c80c 100644 --- a/src/controllers/BoardContainer.js +++ b/src/controllers/BoardContainer.js @@ -7,14 +7,19 @@ import PropTypes from 'prop-types' import pick from 'lodash/pick' import isEqual from 'lodash/isEqual' import Lane from './Lane' -import { PopoverWrapper } from 'react-popopo' +import {PopoverWrapper} from 'react-popopo' import * as boardActions from 'rt/actions/BoardActions' import * as laneActions from 'rt/actions/LaneActions' class BoardContainer extends Component { state = { - addLaneMode: false + addLaneMode: false, + isDragging: false, + startX: 0, + startY: 0, + scrollLeft: 0, + scrollTop: 0 } componentDidMount() { @@ -23,6 +28,61 @@ class BoardContainer extends Component { if (eventBusHandle) { this.wireEventBus() } + + const boardElement = document.querySelector('.react-trello-board') + if (boardElement) { + boardElement.addEventListener('mousedown', this.handleMouseDown) + boardElement.addEventListener('mousemove', this.handleMouseMove) + boardElement.addEventListener('mouseup', this.handleMouseUp) + boardElement.addEventListener('mouseleave', this.handleMouseLeave) + } + } + + componentWillUnmount() { + const boardElement = document.querySelector('.react-trello-board') + if (boardElement) { + boardElement.removeEventListener('mousedown', this.handleMouseDown) + boardElement.removeEventListener('mousemove', this.handleMouseMove) + boardElement.removeEventListener('mouseup', this.handleMouseUp) + boardElement.removeEventListener('mouseleave', this.handleMouseLeave) + } + } + + handleMouseDown = e => { + if (e.target.closest('.react-trello-card')) return + + this.setState({ + isDragging: true, + startX: e.pageX - e.currentTarget.offsetLeft, + startY: e.pageY - e.currentTarget.offsetTop, + scrollLeft: e.currentTarget.scrollLeft, + scrollTop: e.currentTarget.scrollTop + }) + } + + handleMouseMove = e => { + const {isDragging, startX, startY, scrollLeft, scrollTop} = this.state + if (!isDragging) return + + const boardElement = document.querySelector('.react-trello-board') + + e.preventDefault() + + const x = e.pageX - boardElement.offsetLeft + const y = e.pageY - boardElement.offsetTop + const walkX = (x - startX) * 1.5 + const walkY = (y - startY) * 1.5 + + boardElement.scrollLeft = scrollLeft - walkX + boardElement.scrollTop = scrollTop - walkY + } + + handleMouseUp = () => { + this.setState({isDragging: false}) + } + + handleMouseLeave = () => { + this.setState({isDragging: false}) } UNSAFE_componentWillReceiveProps(nextProps) { @@ -204,8 +264,10 @@ class BoardContainer extends Component { {canAddLanes && ( - {editable && !addLaneMode ? : ( - addLaneMode && + {editable && !addLaneMode ? ( + + ) : ( + addLaneMode && )} )} @@ -250,11 +312,11 @@ BoardContainer.propTypes = { laneDragClass: PropTypes.string, laneDropClass: PropTypes.string, onCardMoveAcrossLanes: PropTypes.func.isRequired, - t: PropTypes.func.isRequired, + t: PropTypes.func.isRequired } BoardContainer.defaultProps = { - t: v=>v, + t: v => v, onDataChange: () => {}, handleDragStart: () => {}, handleDragEnd: () => {}, From e8e0e878865743a48a66f294e7e98b3abf6b3406 Mon Sep 17 00:00:00 2001 From: Nicolas Barros Date: Wed, 15 Jan 2025 14:32:53 -0300 Subject: [PATCH 2/4] feat: add conditional to CardHeader --- src/components/Card.js | 95 ++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 37 deletions(-) diff --git a/src/components/Card.js b/src/components/Card.js index e5d2952c..b2a4d0b2 100644 --- a/src/components/Card.js +++ b/src/components/Card.js @@ -1,14 +1,7 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' -import { - MovableCardWrapper, - CardHeader, - CardRightContent, - CardTitle, - Detail, - Footer -} from 'rt/styles/Base' +import {MovableCardWrapper, CardHeader, CardRightContent, CardTitle, Detail, Footer} from 'rt/styles/Base' import InlineInput from 'rt/widgets/InlineInput' import Tag from './Card/Tag' import DeleteButton from 'rt/widgets/DeleteButton' @@ -19,7 +12,7 @@ class Card extends Component { e.stopPropagation() } - render() { + render() { const { showDeleteButton, style, @@ -38,38 +31,66 @@ class Card extends Component { t } = this.props - const updateCard = (card) => { + const updateCard = card => { onChange({...card, id}) } return ( - - - - {editable ? updateCard({title: value})} /> : title} - - - {editable ? updateCard({label: value})} /> : label} - - {showDeleteButton && } - + + {(title || label) && ( + + + {editable ? ( + updateCard({title: value})} + /> + ) : ( + title + )} + + + {editable ? ( + updateCard({label: value})} + /> + ) : ( + label + )} + + {showDeleteButton && } + + )} - {editable ? updateCard({description: value})} /> : description} + {editable ? ( + updateCard({description: value})} + /> + ) : ( + description + )} - {tags && tags.length> 0 && ( -
- {tags.map(tag => ( - - ))} -
- )} + {tags && + tags.length > 0 && ( +
+ {tags.map(tag => ( + + ))} +
+ )}
- ) + ) } } @@ -84,7 +105,7 @@ Card.propTypes = { title: PropTypes.string.isRequired, label: PropTypes.string, description: PropTypes.string, - tags: PropTypes.array, + tags: PropTypes.array } Card.defaultProps = { @@ -93,9 +114,9 @@ Card.defaultProps = { onClick: () => {}, style: {}, tagStyle: {}, - title: 'no title', + title: null, description: '', - label: '', + label: null, tags: [], className: '' } From 88f2d7bc8b41b1885868fe47307f945123fdb821 Mon Sep 17 00:00:00 2001 From: onicolasz Date: Wed, 15 Jan 2025 22:21:25 -0300 Subject: [PATCH 3/4] feat: add webkit scrollbar --- src/controllers/BoardContainer.js | 23 ++++++++++++++++++----- src/controllers/Lane.js | 21 +++++++++++++++++---- src/styles/Base.js | 18 ++++++++++++++++++ 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/controllers/BoardContainer.js b/src/controllers/BoardContainer.js index 2c46c80c..fdf5c9d0 100644 --- a/src/controllers/BoardContainer.js +++ b/src/controllers/BoardContainer.js @@ -31,6 +31,12 @@ class BoardContainer extends Component { const boardElement = document.querySelector('.react-trello-board') if (boardElement) { + // Add user-select: none to prevent text selection + boardElement.style.userSelect = 'none' + boardElement.style.WebkitUserSelect = 'none' + boardElement.style.MozUserSelect = 'none' + boardElement.style.msUserSelect = 'none' + boardElement.addEventListener('mousedown', this.handleMouseDown) boardElement.addEventListener('mousemove', this.handleMouseMove) boardElement.addEventListener('mouseup', this.handleMouseUp) @@ -49,7 +55,16 @@ class BoardContainer extends Component { } handleMouseDown = e => { - if (e.target.closest('.react-trello-card')) return + // Prevent dragging when interacting with lanes or cards + if ( + e.target.closest('.react-trello-card') || + e.target.closest('.react-trello-lane') || + e.target.closest('.draggable') + ) + return + + // Prevent text selection + e.preventDefault() this.setState({ isDragging: true, @@ -61,7 +76,7 @@ class BoardContainer extends Component { } handleMouseMove = e => { - const {isDragging, startX, startY, scrollLeft, scrollTop} = this.state + const {isDragging, startX, scrollLeft} = this.state if (!isDragging) return const boardElement = document.querySelector('.react-trello-board') @@ -69,12 +84,10 @@ class BoardContainer extends Component { e.preventDefault() const x = e.pageX - boardElement.offsetLeft - const y = e.pageY - boardElement.offsetTop const walkX = (x - startX) * 1.5 - const walkY = (y - startY) * 1.5 + // Only allow horizontal scrolling boardElement.scrollLeft = scrollLeft - walkX - boardElement.scrollTop = scrollTop - walkY } handleMouseUp = () => { diff --git a/src/controllers/Lane.js b/src/controllers/Lane.js index 3a8303a8..3e5287ed 100644 --- a/src/controllers/Lane.js +++ b/src/controllers/Lane.js @@ -47,7 +47,7 @@ class Lane extends Component { sortCards(cards, sortFunction) { if (!cards) return [] if (!sortFunction) return cards - return cards.concat().sort(function (card1, card2) { + return cards.concat().sort(function(card1, card2) { return sortFunction(card1, card2) }) } @@ -190,9 +190,10 @@ class Lane extends Component { }) return ( - + 0 return ( @@ -266,7 +274,9 @@ class Lane extends Component { key={id} onClick={() => onLaneClick && onLaneClick(id)} draggable={false} - className={allClassNames}> + className={allClassNames} + style + style={laneStyle}> {this.renderHeader({id, cards, ...otherProps})} {this.renderDragContainer(isDraggingOver)} {loading && } @@ -328,4 +338,7 @@ const mapDispatchToProps = dispatch => ({ actions: bindActionCreators(laneActions, dispatch) }) -export default connect(null, mapDispatchToProps)(Lane) +export default connect( + null, + mapDispatchToProps +)(Lane) diff --git a/src/styles/Base.js b/src/styles/Base.js index c8ab5896..8a803ce2 100644 --- a/src/styles/Base.js +++ b/src/styles/Base.js @@ -34,6 +34,24 @@ export const GlobalStyle = createGlobalStyle` line-height: 32px; width: 32px; } + + .scrollable-lane::-webkit-scrollbar { + width: 5px; + height: 8px; + } + + .scrollable-lane::-webkit-scrollbar-thumb { + background: #888; + border-radius: 10px; + } + + .scrollable-lane::-webkit-scrollbar-thumb:hover { + background: #555; + } + + .scrollable-lane::-webkit-scrollbar-track { + background: transparent; + } ` export const CustomPopoverContainer = styled(PopoverContainer)` From d5fa9ce8eef5cdf1ec327e449ebb5955945a588e Mon Sep 17 00:00:00 2001 From: onicolasz Date: Wed, 15 Jan 2025 22:36:33 -0300 Subject: [PATCH 4/4] feat: remove lane style --- src/controllers/Lane.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/controllers/Lane.js b/src/controllers/Lane.js index 3e5287ed..1ecea9e8 100644 --- a/src/controllers/Lane.js +++ b/src/controllers/Lane.js @@ -260,12 +260,6 @@ class Lane extends Component { ...otherProps } = this.props - const laneStyle = { - ...otherProps.style, - overflowY: 'auto', - maxHeight: '100vh' - } - const allClassNames = classNames('react-trello-lane', this.props.className || '') const showFooter = collapsibleLanes && cards.length > 0 return ( @@ -274,9 +268,7 @@ class Lane extends Component { key={id} onClick={() => onLaneClick && onLaneClick(id)} draggable={false} - className={allClassNames} - style - style={laneStyle}> + className={allClassNames}> {this.renderHeader({id, cards, ...otherProps})} {this.renderDragContainer(isDraggingOver)} {loading && }