Skip to content

Commit 36e4853

Browse files
authored
Add a copy tags to clipboard button to item popup in the map view. (#2798)
* Add a copy tags to clipboard button to item popup in the map view. * Fix linting issues
1 parent fcedeba commit 36e4853

2 files changed

Lines changed: 61 additions & 11 deletions

File tree

src/components/EnhancedMap/PropertyList/Messages.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,9 @@ export default defineMessages({
1313
id: "PropertyList.noProperties",
1414
defaultMessage: "No Properties",
1515
},
16+
17+
copyTagsTooltip: {
18+
id: "PropertyList.copyTagsTooltip",
19+
defaultMessage: "Copy tags to clipboard",
20+
},
1621
});

src/components/EnhancedMap/PropertyList/PropertyList.jsx

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import _isEmpty from "lodash/isEmpty";
44
import _isObject from "lodash/isObject";
55
import _map from "lodash/map";
66
import _truncate from "lodash/truncate";
7-
import { FormattedMessage } from "react-intl";
7+
import { useState } from "react";
8+
import { CopyToClipboard } from "react-copy-to-clipboard";
9+
import { FormattedMessage, useIntl } from "react-intl";
810
import { valueOrExternalLink } from "../../../utils/linkUtils";
911
import SvgSymbol from "../../SvgSymbol/SvgSymbol";
1012
import messages from "./Messages";
@@ -18,18 +20,61 @@ const PropertyList = (props) => {
1820
// Default is lightMode -- only do darkMode if the value is present and false
1921
const darkMode = props.lightMode === false;
2022
const tagInfo = window.env.REACT_APP_TAGINFO_SERVER_URL;
23+
const intl = useIntl();
24+
const [copied, setCopied] = useState(false);
25+
26+
const EXCLUDED_KEYS = new Set(["@id", "osmid"]);
27+
const MAX_VALUE_LENGTH = 255;
28+
29+
const copyableTagText = () => {
30+
if (_isEmpty(props.featureProperties)) return "";
31+
return Object.entries(props.featureProperties)
32+
.filter(
33+
([key, value]) =>
34+
!_isObject(value) && !EXCLUDED_KEYS.has(key) && String(value).length <= MAX_VALUE_LENGTH,
35+
)
36+
.map(([key, value]) => `${key}=${value}`)
37+
.join("\n");
38+
};
39+
40+
const handleCopy = () => {
41+
setCopied(true);
42+
setTimeout(() => setCopied(false), 1500);
43+
};
44+
2145
const header = (
22-
<h3 className="mr-flex mr-items-center">
23-
{props.onBack && (
24-
<a onClick={props.onBack} className="mr-mr-4">
25-
<SvgSymbol
26-
sym="icon-cheveron-left"
27-
viewBox="0 0 20 20"
28-
className="mr-fill-current mr-w-6 mr-h-6"
29-
/>
30-
</a>
46+
<h3 className="mr-flex mr-items-center mr-justify-between">
47+
<span className="mr-flex mr-items-center">
48+
{props.onBack && (
49+
<a onClick={props.onBack} className="mr-mr-4">
50+
<SvgSymbol
51+
sym="icon-cheveron-left"
52+
viewBox="0 0 20 20"
53+
className="mr-fill-current mr-w-6 mr-h-6"
54+
/>
55+
</a>
56+
)}
57+
{props.header ? props.header : <FormattedMessage {...messages.title} />}
58+
</span>
59+
{!_isEmpty(props.featureProperties) && (
60+
<CopyToClipboard text={copyableTagText()} onCopy={handleCopy}>
61+
<button
62+
className={classNames(
63+
"mr-ml-2",
64+
darkMode
65+
? "mr-text-green-lighter hover:mr-text-white"
66+
: "mr-text-grey hover:mr-text-green-dark",
67+
)}
68+
title={intl.formatMessage(messages.copyTagsTooltip)}
69+
>
70+
<SvgSymbol
71+
sym={copied ? "check-icon" : "clipboard-icon"}
72+
viewBox="0 0 20 20"
73+
className="mr-fill-current mr-w-4 mr-h-4"
74+
/>
75+
</button>
76+
</CopyToClipboard>
3177
)}
32-
{props.header ? props.header : <FormattedMessage {...messages.title} />}
3378
</h3>
3479
);
3580

0 commit comments

Comments
 (0)