feat: Add ability to copy/cut cards with shortcut support

This commit is contained in:
Maksim Eltyshev
2025-12-09 14:58:01 +01:00
parent 52acc9de90
commit 9e6e38fcf7
113 changed files with 1616 additions and 259 deletions
+38 -17
View File
@@ -6,10 +6,10 @@
import React, { useCallback, useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { useSelector } from 'react-redux';
import { shallowEqual, useSelector } from 'react-redux';
import { useInView } from 'react-intersection-observer';
import { useTranslation } from 'react-i18next';
import { Button, Loader } from 'semantic-ui-react';
import { Button, Icon, Loader } from 'semantic-ui-react';
import selectors from '../../../selectors';
import { BoardMembershipRoles } from '../../../constants/Enums';
@@ -20,11 +20,18 @@ import PlusMathIcon from '../../../assets/images/plus-math-icon.svg?react';
import styles from './ListView.module.scss';
const ListView = React.memo(
({ cardIds, isCardsFetching, isAllCardsFetched, onCardsFetch, onCardCreate }) => {
const canAddCard = useSelector((state) => {
({ cardIds, isCardsFetching, isAllCardsFetched, onCardsFetch, onCardCreate, onCardPaste }) => {
const clipboard = useSelector(selectors.selectClipboard);
const { canAddCard, canPasteCard } = useSelector((state) => {
const boardMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state);
return !!boardMembership && boardMembership.role === BoardMembershipRoles.EDITOR;
});
const isEditor = !!boardMembership && boardMembership.role === BoardMembershipRoles.EDITOR;
return {
canAddCard: isEditor,
canPasteCard: isEditor,
};
}, shallowEqual);
const [t] = useTranslation();
const [isAddCardOpened, setIsAddCardOpened] = useState(false);
@@ -54,17 +61,29 @@ const ListView = React.memo(
<AddCard onCreate={onCardCreate} onClose={handleAddCardClose} />
</div>
) : (
<Button
type="button"
disabled={!onCardCreate}
className={styles.addCardButton}
onClick={handleAddCardClick}
>
<PlusMathIcon className={styles.addCardButtonIcon} />
<span className={styles.addCardButtonText}>
{onCardCreate ? t('action.addCard') : t('common.atLeastOneListMustBePresent')}
</span>
</Button>
<div className={styles.addCardButtonWrapper}>
<Button
type="button"
disabled={!onCardCreate}
className={styles.addCardButton}
onClick={handleAddCardClick}
>
<PlusMathIcon className={styles.addCardButtonIcon} />
<span className={styles.addCardButtonText}>
{onCardCreate ? t('action.addCard') : t('common.atLeastOneListMustBePresent')}
</span>
</Button>
{onCardPaste && clipboard && canPasteCard && (
<Button
type="button"
disabled={!onCardCreate}
className={classNames(styles.addCardButton, styles.paste)}
onClick={onCardPaste}
>
<Icon fitted name="paste" />
</Button>
)}
</div>
))}
{cardIds.length > 0 && (
<div className={classNames(styles.segment, styles.cards)}>
@@ -95,6 +114,7 @@ ListView.propTypes = {
isAllCardsFetched: PropTypes.bool,
onCardsFetch: PropTypes.func,
onCardCreate: PropTypes.func,
onCardPaste: PropTypes.func,
};
ListView.defaultProps = {
@@ -102,6 +122,7 @@ ListView.defaultProps = {
isAllCardsFetched: undefined,
onCardsFetch: undefined,
onCardCreate: undefined,
onCardPaste: undefined,
};
export default ListView;