Skip to content

Commit 8d26765

Browse files
authored
fix: harden blog share actions
1 parent 3ceb2b1 commit 8d26765

2 files changed

Lines changed: 30 additions & 9 deletions

File tree

src/components/SocialShare/SocialShare.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
width: 3.25rem;
2626
height: 3.25rem;
2727
border-radius: 999px;
28+
border: 1px solid var(--ifm-color-emphasis-300);
2829
border: 1px solid color-mix(in srgb, var(--ifm-color-primary) 18%, var(--ifm-color-emphasis-300));
2930
background: var(--ifm-background-surface-color);
3031
color: var(--ifm-font-color-base) !important;
@@ -75,6 +76,11 @@
7576
color: var(--ifm-color-primary) !important;
7677
}
7778

79+
.share-btn-circle.copy.copy-error {
80+
border-color: var(--ifm-color-danger);
81+
color: var(--ifm-color-danger) !important;
82+
}
83+
7884
@media (max-width: 576px) {
7985
.share-buttons-row {
8086
gap: 0.75rem;

src/components/SocialShare/index.tsx

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import { FaXTwitter } from "react-icons/fa6";
66
import "./SocialShare.css";
77

88
const COPY_RESET_DELAY_MS = 2000;
9+
const COPY_DEFAULT_LABEL = "Copy link";
10+
const COPY_SUCCESS_LABEL = "Link copied";
11+
const COPY_ERROR_LABEL = "Unable to copy link";
912

1013
type SocialShareProps = {
1114
permalink?: string;
@@ -17,17 +20,17 @@ export default function SocialShare({
1720
title,
1821
}: SocialShareProps): JSX.Element | null {
1922
const { siteConfig } = useDocusaurusContext();
20-
const [copied, setCopied] = useState(false);
23+
const [copyState, setCopyState] = useState<"idle" | "copied" | "error">("idle");
2124

2225
useEffect(() => {
23-
if (!copied) {
26+
if (copyState === "idle") {
2427
return undefined;
2528
}
2629

27-
const timeout = window.setTimeout(() => setCopied(false), COPY_RESET_DELAY_MS);
30+
const timeout = window.setTimeout(() => setCopyState("idle"), COPY_RESET_DELAY_MS);
2831

2932
return () => window.clearTimeout(timeout);
30-
}, [copied]);
33+
}, [copyState]);
3134

3235
if (!permalink || !title) {
3336
return null;
@@ -61,13 +64,25 @@ export default function SocialShare({
6164

6265
const handleCopyLink = async () => {
6366
if (typeof navigator === "undefined" || !navigator.clipboard) {
67+
setCopyState("error");
6468
return;
6569
}
6670

67-
await navigator.clipboard.writeText(blogUrl);
68-
setCopied(true);
71+
try {
72+
await navigator.clipboard.writeText(blogUrl);
73+
setCopyState("copied");
74+
} catch {
75+
setCopyState("error");
76+
}
6977
};
7078

79+
const copyLabel =
80+
copyState === "copied"
81+
? COPY_SUCCESS_LABEL
82+
: copyState === "error"
83+
? COPY_ERROR_LABEL
84+
: COPY_DEFAULT_LABEL;
85+
7186
return (
7287
<section className="blog-post-share-section" aria-label="Share this post">
7388
<p className="share-title">Share this post</p>
@@ -87,12 +102,12 @@ export default function SocialShare({
87102
))}
88103
<button
89104
type="button"
90-
className={`share-btn-circle copy${copied ? " copied" : ""}`}
105+
className={`share-btn-circle copy${copyState === "copied" ? " copied" : ""}${copyState === "error" ? " copy-error" : ""}`}
91106
onClick={() => {
92107
void handleCopyLink();
93108
}}
94-
title={copied ? "Link copied" : "Copy link"}
95-
aria-label={copied ? "Link copied" : "Copy link"}
109+
title={copyLabel}
110+
aria-label={copyLabel}
96111
>
97112
<FaLink aria-hidden="true" />
98113
</button>

0 commit comments

Comments
 (0)