Skip to content
This repository was archived by the owner on Jun 16, 2026. It is now read-only.

Commit 058bc97

Browse files
committed
Make it possible to copy the email to the clipboard
1 parent c0af876 commit 058bc97

7 files changed

Lines changed: 115 additions & 3 deletions

File tree

components/Email/index.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { useCallback, useEffect, useState } from "react";
2+
import { FaRegCopy } from "react-icons/fa";
3+
import { Tooltip } from "react-tooltip";
4+
5+
type EmailProps = {
6+
children: string;
7+
onCopyTooltip: string;
8+
};
9+
10+
export function Email({ children, onCopyTooltip }: EmailProps) {
11+
const [copied, setCopied] = useState(false);
12+
const [id, setId] = useState("");
13+
14+
const handleCopy = useCallback(() => {
15+
navigator.clipboard.writeText(children);
16+
17+
setCopied(true);
18+
}, [children]);
19+
20+
useEffect(() => {
21+
if (!copied) return;
22+
23+
const timeout = setTimeout(() => setCopied(false), 2000);
24+
25+
return () => clearTimeout(timeout);
26+
}, [copied]);
27+
28+
useEffect(() => {
29+
setId(Math.random().toString(36).substring(7));
30+
}, []);
31+
32+
return (
33+
<button className="Email" onClick={handleCopy} id={id}>
34+
{children}
35+
36+
<span className="Email__Icon">
37+
<FaRegCopy />
38+
</span>
39+
40+
<Tooltip anchorId={id} isOpen={copied} place="bottom" className="Email__Tooltip">
41+
{onCopyTooltip}
42+
</Tooltip>
43+
</button>
44+
);
45+
}

components/Email/style.css

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.Email {
2+
align-items: baseline;
3+
border: 1px dashed var(--gray7);
4+
display: inline-flex;
5+
font-size: 1em;
6+
padding: 0 0.15rem;
7+
8+
color: var(--gray11);
9+
cursor: pointer;
10+
background-color: transparent;
11+
border-radius: 0.25rem;
12+
font-family: inherit;
13+
font-weight: 700;
14+
15+
appearance: none;
16+
17+
transition: border-color 250ms ease-in-out, color 250ms ease-in-out;
18+
}
19+
20+
.Email:hover {
21+
border-color: var(--gray8);
22+
color: var(--gray12);
23+
}
24+
25+
.Email__Icon {
26+
font-size: 0.65em;
27+
margin-left: 0.25rem;
28+
}
29+
30+
.Email .Email__Tooltip {
31+
font-size: 0.65em;
32+
33+
background-color: var(--gray3);
34+
color: var(--gray12);
35+
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"react": "18.2.0",
1212
"react-dom": "18.2.0",
1313
"react-icons": "4.4.0",
14+
"react-tooltip": "5.7.4",
1415
"yup": "0.32.11"
1516
},
1617
"devDependencies": {

pages/en/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { FaGithub, FaLinkedin, FaTwitter } from "react-icons/fa";
2+
import { Email } from "../../components/Email";
23
import { Figure } from "../../components/Figure";
34
import { Link } from "../../components/Link";
45
import { List } from "../../components/List";
@@ -138,7 +139,8 @@ export default function Homepage() {
138139

139140
<Page.Text>
140141
Would you like to hire this technical training? Please drop me a line at{" "}
141-
<strong>hola@codecoolture.com</strong> and tell me about your team and the projects you are working on!
142+
<Email onCopyTooltip="Email copied to clipboard">hola@codecoolture.com</Email> and tell me about your team
143+
and the projects you are working on!
142144
</Page.Text>
143145

144146
<Page.Subheading>Published material</Page.Subheading>

pages/es/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { FaGithub, FaLink, FaTwitter } from "react-icons/fa";
2+
import { Email } from "../../components/Email";
23
import { Figure } from "../../components/Figure";
34
import { Link } from "../../components/Link";
45
import { List } from "../../components/List";
@@ -144,8 +145,8 @@ export default function Homepage() {
144145

145146
<Page.Text>
146147
Si quieres contratar esta formación para tu empresa, escríbeme un mensaje a{" "}
147-
<strong>hola@codecoolture.com</strong> y cuéntame un poco sobre tu equipo y los proyectos en los que estáis
148-
trabajando.
148+
<Email onCopyTooltip="Email copiado al portapapeles">hola@codecoolture.com</Email> y cuéntame un poco sobre
149+
tu equipo y los proyectos en los que estáis trabajando.
149150
</Page.Text>
150151

151152
<Page.Subheading>Material publicado</Page.Subheading>

styles/index.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import "react-tooltip/dist/react-tooltip.css";
2+
13
@import "@radix-ui/colors/grayDark.css";
24
@import "@radix-ui/colors/indigoDark.css";
35
@import "@radix-ui/colors/redDark.css";
@@ -7,6 +9,7 @@
79
@import "../components/Button/style.css";
810
@import "../components/Blockquote/style.css";
911
@import "../components/Code/style.css";
12+
@import "../components/Email/style.css";
1013
@import "../components/Figure/style.css";
1114
@import "../components/Link/style.css";
1215
@import "../components/List/style.css";

yarn.lock

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,18 @@
556556
minimatch "^3.1.2"
557557
strip-json-comments "^3.1.1"
558558

559+
"@floating-ui/core@^1.2.0":
560+
version "1.2.0"
561+
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.0.tgz#ae7ae7923d41f3d84cb2fd88740a89436610bbec"
562+
integrity sha512-GHUXPEhMEmTpnpIfesFA2KAoMJPb1SPQw964tToQwt+BbGXdhqTCWT1rOb0VURGylsxsYxiGMnseJ3IlclVpVA==
563+
564+
"@floating-ui/dom@^1.0.4":
565+
version "1.2.0"
566+
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.0.tgz#a60212069cc58961c478037c30eba4b191c75316"
567+
integrity sha512-QXzg57o1cjLz3cGETzKXjI3kx1xyS49DW9l7kV2jw2c8Yftd434t2hllX0sVGn2Q8MtcW/4pNm8bfE1/4n6mng==
568+
dependencies:
569+
"@floating-ui/core" "^1.2.0"
570+
559571
"@hapi/hoek@^9.0.0":
560572
version "9.2.1"
561573
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17"
@@ -1584,6 +1596,11 @@ cjs-module-lexer@^1.0.0:
15841596
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40"
15851597
integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==
15861598

1599+
classnames@^2.3.2:
1600+
version "2.3.2"
1601+
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
1602+
integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==
1603+
15871604
clean-stack@^2.0.0:
15881605
version "2.2.0"
15891606
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
@@ -3889,6 +3906,14 @@ react-refresh@0.8.3:
38893906
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
38903907
integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==
38913908

3909+
react-tooltip@5.7.4:
3910+
version "5.7.4"
3911+
resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-5.7.4.tgz#246269b89f55de031e3c964125443e41d3799500"
3912+
integrity sha512-Eocnm5Dl6numT52CXLVecX5p93W4ifU3TIbhGqrNfFw2KY7ES2tZDPQHH5yQ1OSWhAcxWZImuFRcUwe+W/vTig==
3913+
dependencies:
3914+
"@floating-ui/dom" "^1.0.4"
3915+
classnames "^2.3.2"
3916+
38923917
react@18.2.0:
38933918
version "18.2.0"
38943919
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"

0 commit comments

Comments
 (0)