Skip to content

Commit

Permalink
feat: add button to copy DevCard image to clipboard (#3943)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonroberts authored Aug 16, 2024
1 parent aa9f86f commit d15ea8c
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 1 deletion.
18 changes: 18 additions & 0 deletions lib/utils/copy-to-clipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ export const copyToClipboard = async (content: string) => {
}
};

export async function copyImageToClipboard(imageUrl: string) {
try {
await navigator.clipboard.write([
new ClipboardItem({
"image/png": new Promise(async (resolve) => {
const data = await fetch(imageUrl);
const blob = await data.blob();

resolve(new Blob([blob], { type: "image/png" }));
}),
}),
]);
return true;
} catch (err) {
return false;
}
}

/**
* Copies the content of an HTML element as an image to the clipboard.
*
Expand Down
38 changes: 37 additions & 1 deletion pages/u/[username]/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useTransition, animated } from "@react-spring/web";
import Image from "next/image";
import { usePostHog } from "posthog-js/react";
import { captureException } from "@sentry/nextjs";
import { FiCopy } from "react-icons/fi";
import Button from "components/shared/Button/button";
import HeaderLogo from "components/molecules/HeaderLogo/header-logo";
import DevCardCarousel from "components/organisms/DevCardCarousel/dev-card-carousel";
Expand All @@ -12,6 +13,9 @@ import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
import { linkedinCardShareUrl, siteUrl, twitterCardShareUrl } from "lib/utils/urls";
import FullHeightContainer from "components/atoms/FullHeightContainer/full-height-container";
import { isValidUrlSlug } from "lib/utils/url-validators";
import { copyImageToClipboard } from "lib/utils/copy-to-clipboard";
import { useToast } from "lib/hooks/useToast";
import { Spinner } from "components/atoms/SpinLoader/spin-loader";
import TwitterIcon from "../../../public/twitter-x-logo.svg";
import LinkinIcon from "../../../img/icons/social-linkedin.svg";
import BubbleBG from "../../../img/bubble-bg.svg";
Expand Down Expand Up @@ -162,6 +166,36 @@ export default function CardPage({ username, cards }: { username: string; cards:
);
}

function CopyButton({ username }: { username: string }) {
const [copying, setCopying] = useState(false);
const { toast } = useToast();
const posthog = usePostHog();

return (
<div
className="rounded-full w-10 h-10 bg-sauced-orange stroke-white cursor-pointer hover:opacity-80 transition-all
flex items-center justify-center"
onClick={async () => {
setCopying(true);
posthog.capture("DevCard image copied", { username });
copyImageToClipboard(siteUrl(`og-images/dev-card`, { username })).then((copied) => {
if (copied) {
setTimeout(() => {
toast({ description: "Copied to clipboard", variant: "success" });
setCopying(false);
}, 500);
} else {
toast({ description: "Error copying to clipboard", variant: "warning" });
setCopying(false);
}
});
}}
>
{copying ? <Spinner className="w-6 h-8" /> : <FiCopy className="w-6 h-8 stroke-white" />}
</div>
);
}

function SocialButtons({ username, summary }: { username: string; summary: string }) {
const posthog = usePostHog();
const icons = [
Expand All @@ -181,7 +215,7 @@ function SocialButtons({ username, summary }: { username: string; summary: strin

return (
<div>
<div className="text-white text-xs mb-2">Share your DevCard</div>
<div className="flex justify-center text-white text-xs mb-2">Share your DevCard</div>
<div className="flex gap-2 justify-center">
{icons.map((icon) => (
<a
Expand All @@ -200,6 +234,8 @@ function SocialButtons({ username, summary }: { username: string; summary: strin
/>
</a>
))}

<CopyButton username={username} />
</div>
</div>
);
Expand Down

0 comments on commit d15ea8c

Please sign in to comment.