1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-08-09 15:35:29 +02:00
This commit is contained in:
Rafly Maulana 2022-11-30 16:41:25 +05:00 committed by GitHub
commit 0eed55a20c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 288 additions and 55 deletions

View file

@ -7,6 +7,7 @@
"name": "planka-client",
"dependencies": {
"@juggle/resize-observer": "^3.4.0",
"@szhsin/react-menu": "^3.2.1",
"classnames": "^2.3.2",
"date-fns": "^2.29.3",
"dequal": "^2.0.3",
@ -4277,6 +4278,19 @@
"url": "https://github.com/sponsors/gregberge"
}
},
"node_modules/@szhsin/react-menu": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-3.2.1.tgz",
"integrity": "sha512-HEStuXNYHxLcGByiWaxFcE+ZaZ5BPQd/NtwBcxmUvHdvAaCZngmZ2ZddWuDAYZval94Kpahi1ZH0/WSv3oFnFg==",
"dependencies": {
"prop-types": "^15.7.2",
"react-transition-state": "^1.1.5"
},
"peerDependencies": {
"react": ">=16.14.0",
"react-dom": ">=16.14.0"
}
},
"node_modules/@testing-library/dom": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.19.0.tgz",
@ -19768,6 +19782,15 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-transition-state": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/react-transition-state/-/react-transition-state-1.1.5.tgz",
"integrity": "sha512-ITY2mZqc2dWG2eitJkYNdcSFW8aKeOlkL2A/vowRrLL8GH3J6Re/SpD/BLvQzrVOTqjsP0b5S9N10vgNNzwMUQ==",
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@ -26499,6 +26522,15 @@
"loader-utils": "^2.0.0"
}
},
"@szhsin/react-menu": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-3.2.1.tgz",
"integrity": "sha512-HEStuXNYHxLcGByiWaxFcE+ZaZ5BPQd/NtwBcxmUvHdvAaCZngmZ2ZddWuDAYZval94Kpahi1ZH0/WSv3oFnFg==",
"requires": {
"prop-types": "^15.7.2",
"react-transition-state": "^1.1.5"
}
},
"@testing-library/dom": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.19.0.tgz",
@ -37710,6 +37742,12 @@
"use-latest": "^1.2.1"
}
},
"react-transition-state": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/react-transition-state/-/react-transition-state-1.1.5.tgz",
"integrity": "sha512-ITY2mZqc2dWG2eitJkYNdcSFW8aKeOlkL2A/vowRrLL8GH3J6Re/SpD/BLvQzrVOTqjsP0b5S9N10vgNNzwMUQ==",
"requires": {}
},
"read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",

View file

@ -54,6 +54,7 @@
},
"dependencies": {
"@juggle/resize-observer": "^3.4.0",
"@szhsin/react-menu": "^3.2.1",
"classnames": "^2.3.2",
"date-fns": "^2.29.3",
"dequal": "^2.0.3",

View file

@ -245,4 +245,6 @@ ActionsStep.propTypes = {
onClose: PropTypes.func.isRequired,
};
export { ActionsStep };
export default withPopup(ActionsStep);

View file

@ -5,17 +5,20 @@ import { Button, Icon } from 'semantic-ui-react';
import { Link } from 'react-router-dom';
import { Draggable } from 'react-beautiful-dnd';
import BoardMembershipsStep from '../BoardMembershipsStep';
import usePopupMenu from '../../lib/hooks/use-popup-menu';
import { startTimer, stopTimer } from '../../utils/timer';
import Paths from '../../constants/Paths';
import Tasks from './Tasks';
import NameEdit from './NameEdit';
import ActionsPopup from './ActionsPopup';
import User from '../User';
import Label from '../Label';
import DueDate from '../DueDate';
import Timer from '../Timer';
import styles from './Card.module.scss';
import '@szhsin/react-menu/dist/index.css';
const Card = React.memo(
({
@ -82,6 +85,34 @@ const Card = React.memo(
nameEdit.current.open();
}, []);
const {
handleContextMenu,
element: popupElement,
setElement,
toggleMenu,
} = usePopupMenu('test', [
{
title: 'Edit Title',
onClick: () => {
handleNameEdit();
toggleMenu(false);
},
},
{
title: 'Edit Members',
onClick: () => {
setElement(
<BoardMembershipsStep
items={allBoardMemberships}
currentUserIds={users.map((user) => user.id)}
onUserSelect={onUserAdd}
onUserDeselect={onUserRemove}
/>,
);
},
},
]);
const contentNode = (
<>
{coverUrl && <img src={coverUrl} alt="" className={styles.cover} />}
@ -150,8 +181,15 @@ const Card = React.memo(
return (
<Draggable draggableId={`card:${id}`} index={index} isDragDisabled={!isPersisted || !canEdit}>
{({ innerRef, draggableProps, dragHandleProps }) => (
// eslint-disable-next-line react/jsx-props-no-spreading
<div {...draggableProps} {...dragHandleProps} ref={innerRef} className={styles.wrapper}>
<div
// eslint-disable-next-line react/jsx-props-no-spreading
{...draggableProps}
// eslint-disable-next-line react/jsx-props-no-spreading
{...dragHandleProps}
ref={innerRef}
className={styles.wrapper}
onContextMenu={handleContextMenu}
>
<NameEdit ref={nameEdit} defaultValue={name} onUpdate={handleNameUpdate}>
<div className={styles.card}>
{isPersisted ? (
@ -163,39 +201,15 @@ const Card = React.memo(
>
{contentNode}
</Link>
{canEdit && (
<ActionsPopup
card={{
dueDate,
timer,
boardId,
listId,
projectId,
}}
projectsToLists={allProjectsToLists}
boardMemberships={allBoardMemberships}
currentUserIds={users.map((user) => user.id)}
labels={allLabels}
currentLabelIds={labels.map((label) => label.id)}
onNameEdit={handleNameEdit}
onUpdate={onUpdate}
onMove={onMove}
onTransfer={onTransfer}
onDelete={onDelete}
onUserAdd={onUserAdd}
onUserRemove={onUserRemove}
onBoardFetch={onBoardFetch}
onLabelAdd={onLabelAdd}
onLabelRemove={onLabelRemove}
onLabelCreate={onLabelCreate}
onLabelUpdate={onLabelUpdate}
onLabelDelete={onLabelDelete}
>
<Button className={classNames(styles.actionsButton, styles.target)}>
<Icon fitted name="pencil" size="small" />
</Button>
</ActionsPopup>
)}
<Button
className={classNames(styles.actionsButton, styles.target)}
onClick={handleContextMenu}
>
<Icon fitted name="pencil" size="small" />
</Button>
{canEdit && popupElement}
</>
) : (
<span className={styles.content}>{contentNode}</span>

View file

@ -0,0 +1,68 @@
import React, { useState, useCallback } from 'react';
import { ControlledMenu, useMenuState } from '@szhsin/react-menu';
import { Menu } from 'semantic-ui-react';
import { Popup } from '../custom-ui';
import '@szhsin/react-menu/dist/index.css';
/**
* hooks for popup menu
*
* @param {string} title Title of the popup
* @param {{
* title: string,
* onClick: () => void,
* }[]} list Menu list to shown
*/
export default function usePopupMenu(title, list) {
const [menuProps, toggleMenu] = useMenuState();
const [anchorPoint, setAnchorPoint] = useState({ x: 0, y: 0 });
const [customElement, setElement] = useState(null);
const handleContextMenu = useCallback(
(e) => {
e.preventDefault();
setAnchorPoint({ x: e.clientX, y: e.clientY });
toggleMenu(true);
},
[toggleMenu],
);
const handleClose = useCallback(() => {
toggleMenu(false);
setElement(null);
}, [toggleMenu]);
const element = (
<ControlledMenu
// eslint-disable-next-line react/jsx-props-no-spreading
{...menuProps}
anchorPoint={anchorPoint}
direction="right"
onClose={handleClose}
>
{customElement || (
<>
<Popup.Header>{title}</Popup.Header>
<Popup.Content>
<Menu secondary vertical>
{list.map(({ title: itemTitle, onClick }) => (
<Menu.Item key={itemTitle} onClick={onClick}>
{itemTitle}
</Menu.Item>
))}
</Menu>
</Popup.Content>
</>
)}
</ControlledMenu>
);
return {
handleContextMenu,
toggleMenu,
element,
setElement,
};
}

0
client/src/redux-history-context.js Executable file → Normal file
View file

View file

@ -2,11 +2,15 @@
#app {
background: #22252a;
.szh-menu-container {
position: fixed !important;
}
.react-datepicker {
border: 0;
color: #444444;
font-size: 14px;
font-family: "Museo Sans", "Helvetica Neue", Arial, Helvetica, sans-serif;
font-family: 'Museo Sans', 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-weight: 400;
width: 100%;
padding-bottom: 8px;
@ -261,11 +265,28 @@
}
.backgroundBlueDanube {
background: radial-gradient(circle, rgba(9, 9, 121, 1) 0%, rgba(2, 0, 36, 1) 0%, rgba(2, 29, 66, 1) 0%, rgba(2, 41, 78, 1) 0%, rgba(2, 57, 95, 1) 0%, rgba(1, 105, 144, 1) 100%, rgba(1, 151, 192, 1) 100%, rgba(0, 212, 255, 1) 100%) !important;
background: radial-gradient(
circle,
rgba(9, 9, 121, 1) 0%,
rgba(2, 0, 36, 1) 0%,
rgba(2, 29, 66, 1) 0%,
rgba(2, 41, 78, 1) 0%,
rgba(2, 57, 95, 1) 0%,
rgba(1, 105, 144, 1) 100%,
rgba(1, 151, 192, 1) 100%,
rgba(0, 212, 255, 1) 100%
) !important;
}
.backgroundSundownStripe {
background: linear-gradient(22deg, rgba(31, 30, 30, 1) 0%, rgba(255, 128, 0, 1) 10%, rgba(255, 128, 0, 1) 41%, rgba(0, 0, 0, 1) 41%, rgba(0, 102, 204, 1) 89%) !important;
background: linear-gradient(
22deg,
rgba(31, 30, 30, 1) 0%,
rgba(255, 128, 0, 1) 10%,
rgba(255, 128, 0, 1) 41%,
rgba(0, 0, 0, 1) 41%,
rgba(0, 102, 204, 1) 89%
) !important;
}
.backgroundMagicalDawn {
@ -273,15 +294,27 @@
}
.backgroundStrawberryDust {
background: linear-gradient(180deg, rgba(172, 79, 115, 1) 0%, rgba(254, 158, 150, 1) 66%) !important;
background: linear-gradient(
180deg,
rgba(172, 79, 115, 1) 0%,
rgba(254, 158, 150, 1) 66%
) !important;
}
.backgroundPurpleRose {
background: linear-gradient(128deg, rgba(116, 43, 62, 1) 19%, rgba(192, 71, 103, 1) 90%) !important;
background: linear-gradient(
128deg,
rgba(116, 43, 62, 1) 19%,
rgba(192, 71, 103, 1) 90%
) !important;
}
.backgroundSunScream {
background: linear-gradient(112deg, rgba(251, 221, 19, 1) 19%, rgba(255, 153, 1, 1) 62%) !important;
background: linear-gradient(
112deg,
rgba(251, 221, 19, 1) 19%,
rgba(255, 153, 1, 1) 62%
) !important;
}
.backgroundWarmRust {
@ -293,7 +326,11 @@
}
.backgroundGreenEyes {
background: linear-gradient(138deg, rgba(19, 170, 82, 1) 0%, rgba(0, 102, 43, 1) 90%) !important;
background: linear-gradient(
138deg,
rgba(19, 170, 82, 1) 0%,
rgba(0, 102, 43, 1) 90%
) !important;
}
.backgroundBlueXchange {
@ -321,15 +358,28 @@
}
.backgroundAlgaeGreen {
background: radial-gradient(circle farthest-corner at 10% 20%, rgba(0, 95, 104, 1) 0%, rgba(15, 156, 168, 1) 90%) !important;
background: radial-gradient(
circle farthest-corner at 10% 20%,
rgba(0, 95, 104, 1) 0%,
rgba(15, 156, 168, 1) 90%
) !important;
}
.backgroundCoralReef {
background: linear-gradient(110.3deg, rgba(238, 179, 123, 1) 8.7%, rgba(216, 103, 77, 1) 47.5%, rgba(114, 43, 54, 1) 89.1%) !important;
background: linear-gradient(
110.3deg,
rgba(238, 179, 123, 1) 8.7%,
rgba(216, 103, 77, 1) 47.5%,
rgba(114, 43, 54, 1) 89.1%
) !important;
}
.backgroundSteelGrey {
background: radial-gradient(circle farthest-corner at -4% -12.9%, rgba(74, 98, 110, 1) 0.3%, rgba(30, 33, 48, 1) 90.2%) !important;
background: radial-gradient(
circle farthest-corner at -4% -12.9%,
rgba(74, 98, 110, 1) 0.3%,
rgba(30, 33, 48, 1) 90.2%
) !important;
}
.backgroundHeatWaves {
@ -337,19 +387,35 @@
}
.backgroundWowBlue {
background: linear-gradient(111.8deg, rgba(0, 104, 155, 1) 19.8%, rgba(0, 173, 239, 1) 92.1%) !important;
background: linear-gradient(
111.8deg,
rgba(0, 104, 155, 1) 19.8%,
rgba(0, 173, 239, 1) 92.1%
) !important;
}
.backgroundVelvetLounge {
background: radial-gradient(circle farthest-corner at 10% 20%, rgba(151, 10, 130, 1) 0%, rgba(33, 33, 33, 1) 100.2%) !important;
background: radial-gradient(
circle farthest-corner at 10% 20%,
rgba(151, 10, 130, 1) 0%,
rgba(33, 33, 33, 1) 100.2%
) !important;
}
.backgroundLagoon {
background: radial-gradient(circle farthest-corner at 10% 20%, rgba(0, 107, 141, 1) 0%, rgba(0, 69, 91, 1) 90%) !important;
background: radial-gradient(
circle farthest-corner at 10% 20%,
rgba(0, 107, 141, 1) 0%,
rgba(0, 69, 91, 1) 90%
) !important;
}
.backgroundPurpleRain {
background: linear-gradient(91.7deg, rgba(50, 25, 79, 1) -4.3%, rgba(122, 101, 149, 1) 101.8%) !important;
background: linear-gradient(
91.7deg,
rgba(50, 25, 79, 1) -4.3%,
rgba(122, 101, 149, 1) 101.8%
) !important;
}
.backgroundBlueSteel {
@ -357,22 +423,49 @@
}
.backgroundBlueishCurve {
background: linear-gradient(171.8deg, rgba(5, 111, 146, 1) 13.5%, rgba(6, 57, 84, 1) 78.6%) !important;
background: linear-gradient(
171.8deg,
rgba(5, 111, 146, 1) 13.5%,
rgba(6, 57, 84, 1) 78.6%
) !important;
}
.backgroundPrismLight {
background: linear-gradient(111.7deg, rgba(251, 198, 6, 1) 2.4%, rgba(224, 82, 95, 1) 28.3%, rgba(194, 78, 154, 1) 46.2%, rgba(32, 173, 190, 1) 79.4%, rgba(22, 158, 95, 1) 100.2%) !important;
background: linear-gradient(
111.7deg,
rgba(251, 198, 6, 1) 2.4%,
rgba(224, 82, 95, 1) 28.3%,
rgba(194, 78, 154, 1) 46.2%,
rgba(32, 173, 190, 1) 79.4%,
rgba(22, 158, 95, 1) 100.2%
) !important;
}
.backgroundTheBow {
background: radial-gradient(circle farthest-corner at -8.9% 51.2%, rgba(255, 124, 0, 1) 0%, rgba(255, 124, 0, 1) 15.9%, rgba(255, 163, 77, 1) 15.9%, rgba(255, 163, 77, 1) 24.4%, rgba(19, 30, 37, 1) 24.5%, rgba(19, 30, 37, 1) 66%) !important;
background: radial-gradient(
circle farthest-corner at -8.9% 51.2%,
rgba(255, 124, 0, 1) 0%,
rgba(255, 124, 0, 1) 15.9%,
rgba(255, 163, 77, 1) 15.9%,
rgba(255, 163, 77, 1) 24.4%,
rgba(19, 30, 37, 1) 24.5%,
rgba(19, 30, 37, 1) 66%
) !important;
}
.backgroundGreenMist {
background: linear-gradient(180.5deg, rgba(0, 128, 128, 1) 8.5%, rgba(174, 206, 100, 1) 118.2%) !important;
background: linear-gradient(
180.5deg,
rgba(0, 128, 128, 1) 8.5%,
rgba(174, 206, 100, 1) 118.2%
) !important;
}
.backgroundRedCurtain {
background: radial-gradient(circle 371px at 2.9% 14.3%, rgba(255, 0, 102, 1) 0%, rgba(80, 5, 35, 1) 100.7%) !important;
background: radial-gradient(
circle 371px at 2.9% 14.3%,
rgba(255, 0, 102, 1) 0%,
rgba(80, 5, 35, 1) 100.7%
) !important;
}
}

View file

@ -40,6 +40,23 @@
"node": "^12.10"
}
},
"..": {
"version": "1.8.5",
"extraneous": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"concurrently": "^7.3.0",
"husky": "^8.0.1",
"lint-staged": "^13.0.3"
},
"devDependencies": {
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.7.1"
}
},
"node_modules/@colors/colors": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",