diff --git a/package.json b/package.json index 29caf1f1..2f947b53 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/free-solid-svg-icons": "^5.15.1", "@fortawesome/react-fontawesome": "^0.1.11", + "@types/react-copy-to-clipboard": "^4.3.0", "axios": "^0.19.2", "chart.js": "^2.8.0", "codemirror": "^5.57.0", @@ -21,6 +22,7 @@ "path": "^0.12.7", "query-string": "^6.7.0", "react": "^16.13.1", + "react-copy-to-clipboard": "^5.0.2", "react-dom": "npm:@hot-loader/react-dom", "react-fast-compare": "^3.2.0", "react-ga": "^3.1.2", diff --git a/resources/scripts/components/elements/CopyOnClick.tsx b/resources/scripts/components/elements/CopyOnClick.tsx new file mode 100644 index 00000000..f1914ed5 --- /dev/null +++ b/resources/scripts/components/elements/CopyOnClick.tsx @@ -0,0 +1,63 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import CopyToClipboard from 'react-copy-to-clipboard'; +import tw from 'twin.macro'; +import styled, { keyframes } from 'styled-components/macro'; +import Fade from '@/components/elements/Fade'; +import { SwitchTransition } from 'react-transition-group'; + +const fade = keyframes` + from { opacity: 0 } + to { opacity: 1 } +`; + +const Toast = styled.div` + ${tw`fixed z-50 bottom-0 left-0 mb-4 w-full flex justify-end pr-4`}; + animation: ${fade} 250ms linear; + + & > div { + ${tw`rounded px-4 py-2 text-white bg-neutral-800 border border-neutral-900`}; + } +`; + +const CopyOnClick: React.FC<{ text: string }> = ({ text, children }) => { + const [ copied, setCopied ] = useState(false); + + useEffect(() => { + if (!copied) return; + + const timeout = setTimeout(() => { + setCopied(false); + }, 2500); + + return () => { + clearTimeout(timeout); + }; + }, [ copied ]); + + const onCopy = useCallback(() => { + setCopied(true); + }, []); + + return ( + <> + + + {copied ? + +
+

Copied "{text}" to clipboard.

+
+
+ : + <> + } +
+
+ + {children} + + + ); +}; + +export default CopyOnClick; diff --git a/resources/scripts/components/server/network/AllocationRow.tsx b/resources/scripts/components/server/network/AllocationRow.tsx index 27c2fba9..7113edab 100644 --- a/resources/scripts/components/server/network/AllocationRow.tsx +++ b/resources/scripts/components/server/network/AllocationRow.tsx @@ -14,6 +14,7 @@ import { debounce } from 'debounce'; import setServerAllocationNotes from '@/api/server/network/setServerAllocationNotes'; import useFlash from '@/plugins/useFlash'; import { ServerContext } from '@/state/server'; +import CopyOnClick from '@/components/elements/CopyOnClick'; const Code = styled.code`${tw`font-mono py-1 px-2 bg-neutral-900 rounded text-sm inline-block`}`; const Label = styled.label`${tw`uppercase text-xs mt-1 text-neutral-400 block px-1 select-none transition-colors duration-150`}`; @@ -43,11 +44,12 @@ const AllocationRow = ({ allocation, onSetPrimary, onNotesChanged }: Props) => {
- +
- {allocation.alias || allocation.ip} - + {allocation.alias ? {allocation.alias} : + {allocation.ip}} +
{allocation.port} diff --git a/yarn.lock b/yarn.lock index 897bad16..fff07b1d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1201,6 +1201,13 @@ dependencies: query-string "*" +"@types/react-copy-to-clipboard@^4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@types/react-copy-to-clipboard/-/react-copy-to-clipboard-4.3.0.tgz#8e07becb4f11cfced4bd36038cb5bdf5c2658be5" + integrity sha512-iideNPRyroENqsOFh1i2Dv3zkviYS9r/9qD9Uh3Z9NNoAAqqa2x53i7iGndGNnJFIo20wIu7Hgh77tx1io8bgw== + dependencies: + "@types/react" "*" + "@types/react-dom@^16.9.8": version "16.9.8" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" @@ -2460,6 +2467,13 @@ copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" +copy-to-clipboard@^3: + version "3.3.1" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" + integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== + dependencies: + toggle-selection "^1.0.6" + core-js-compat@^3.6.2: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" @@ -5650,7 +5664,7 @@ promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" -prop-types@^15.5.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.0, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -5802,6 +5816,14 @@ react-async-script@^1.1.1: hoist-non-react-statics "^3.3.0" prop-types "^15.5.0" +react-copy-to-clipboard@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.2.tgz#d82a437e081e68dfca3761fbd57dbf2abdda1316" + integrity sha512-/2t5mLMMPuN5GmdXo6TebFa8IoFxZ+KTDDqYhcDm0PhkgEzSxVvIX26G20s1EB02A4h2UZgwtfymZ3lGJm0OLg== + dependencies: + copy-to-clipboard "^3" + prop-types "^15.5.8" + "react-dom@npm:@hot-loader/react-dom": version "16.11.0" resolved "https://registry.yarnpkg.com/@hot-loader/react-dom/-/react-dom-16.11.0.tgz#c0b483923b289db5431516f56ee2a69448ebf9bd" @@ -7027,6 +7049,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toggle-selection@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= + toidentifier@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"