mirror of
https://github.com/plankanban/planka.git
synced 2025-07-19 05:09:43 +02:00
feat: Add copy-to-clipboard for custom fields
This commit is contained in:
parent
99a06ce1ae
commit
3126a40bba
2 changed files with 68 additions and 10 deletions
|
@ -3,9 +3,10 @@
|
|||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import entryActions from '../../../entry-actions';
|
||||
|
@ -48,6 +49,7 @@ const CustomField = React.memo(({ id, customFieldGroupId }) => {
|
|||
});
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
|
||||
const handleValueUpdate = useCallback(
|
||||
(content) => {
|
||||
|
@ -64,18 +66,40 @@ const CustomField = React.memo(({ id, customFieldGroupId }) => {
|
|||
[id, customFieldGroupId, cardId, dispatch],
|
||||
);
|
||||
|
||||
const handleCopyClick = useCallback(() => {
|
||||
if (isCopied) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText(customFieldValue.content);
|
||||
|
||||
setIsCopied(true);
|
||||
setTimeout(() => {
|
||||
setIsCopied(false);
|
||||
}, 1000);
|
||||
}, [customFieldValue, isCopied]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.name}>{customField.name}</div>
|
||||
{canEdit ? (
|
||||
<ValueField
|
||||
defaultValue={customFieldValue && customFieldValue.content}
|
||||
disabled={!customField.isPersisted}
|
||||
onUpdate={handleValueUpdate}
|
||||
/>
|
||||
) : (
|
||||
<div className={styles.value}>{customFieldValue ? customFieldValue.content : '\u00A0'}</div>
|
||||
)}
|
||||
<div className={styles.valueWrapper}>
|
||||
{canEdit ? (
|
||||
<ValueField
|
||||
defaultValue={customFieldValue && customFieldValue.content}
|
||||
disabled={!customField.isPersisted}
|
||||
onUpdate={handleValueUpdate}
|
||||
/>
|
||||
) : (
|
||||
<div className={styles.value}>
|
||||
{customFieldValue ? customFieldValue.content : '\u00A0'}
|
||||
</div>
|
||||
)}
|
||||
{customFieldValue && customFieldValue.content && (
|
||||
<Button className={styles.copyButton} onClick={handleCopyClick}>
|
||||
<Icon fitted name={isCopied ? 'check' : 'copy'} />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -4,6 +4,30 @@
|
|||
*/
|
||||
|
||||
:global(#app) {
|
||||
.copyButton {
|
||||
background: #ebeef0;
|
||||
box-shadow: none;
|
||||
border-radius: 3px;
|
||||
box-sizing: content-box;
|
||||
color: #516b7a;
|
||||
display: none;
|
||||
height: 30px;
|
||||
margin: 0;
|
||||
min-height: auto;
|
||||
outline: none;
|
||||
padding: 4px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transition: background 85ms ease;
|
||||
width: 20px;
|
||||
|
||||
&:hover {
|
||||
background: #dfe3e6;
|
||||
color: #4c4c4c;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
color: #6b808c;
|
||||
font-size: 13px;
|
||||
|
@ -25,4 +49,14 @@
|
|||
padding: 8px 12px;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.valueWrapper {
|
||||
position: relative;
|
||||
|
||||
&:hover:not(:has(input:focus)) {
|
||||
.copyButton {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue