imnya.ng/src/components/Contact.tsx

157 lines
6.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { MailIcon, Rss, GitBranch, Copy, Check } from "lucide-react";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import Image from "next/image";
import { Dialog, DialogContent, DialogHeader, DialogDescription, DialogFooter, DialogClose, DialogTitle } from "./ui/dialog";
import React from "react";
import { Button } from "./ui/button";
import {
Item,
ItemActions,
ItemContent,
ItemMedia,
ItemTitle,
} from "@/components/ui/item"
type ContactMethod = {
name: string;
icon: React.ReactNode;
url?: string;
onClick?: () => void;
};
type EmailContact = {
label: string;
address: string;
};
export default function Contact() {
const [isDialogOpen, setIsDialogOpen] = React.useState(false);
const [copiedEmail, setCopiedEmail] = React.useState<string | null>(null);
const emailContacts: EmailContact[] = [
{ label: "Personal", address: "me@imnya.ng" },
{ label: "ADOFAI.gg", address: "imnyang@adofai.gg" },
{ label: "Dazzle.st", address: "imnyang@dazzle.st" },
];
const contact: ContactMethod[] = [
{
"name": "Email",
"onClick": () => setIsDialogOpen(true),
"icon": <MailIcon className="w-5 h-5" />,
},
{
"name": "Blog",
"url": "https://blog.imnya.ng",
"icon": <Rss className="w-5 h-5" />
},
{
"name": "GitHub",
"url": "https://github.com/imnyang",
"icon": <Image src="/icon/github.svg" width={24} height={24} alt="GitHub" className="w-6 h-6" />
},
{
"name": "git.mizuki.guru",
"url": "https://git.mizuki.guru/imnyang",
"icon": <GitBranch className="w-5 h-5" />
},
{
"name": "Instagram",
"url": "https://instagram.com/imnya.ng",
"icon": <Image src="/icon/instagram.svg" width={18} height={18} alt="Instagram" className="w-4 h-4" />
},
{
"name": "𝕏",
"url": "https://x.com/imnya_ng",
"icon": <p className="text-[20px] font-bold">𝕏</p>
}
]
const handleClick = (method: ContactMethod) => {
if (method.onClick) {
method.onClick();
} else if (method.url) {
window.open(method.url, "_blank", "noopener,noreferrer");
}
};
const copyEmail = (email: string) => {
void navigator.clipboard.writeText(email);
setCopiedEmail(email);
setTimeout(() => {
setCopiedEmail((currentEmail) => (currentEmail === email ? null : currentEmail));
}, 1200);
};
const openMailTo = (email: string) => {
window.location.href = `mailto:${email}`;
};
return (
<div className="flex flex-row space-x-4">
{contact.map((method) => (
<Tooltip key={method.name}>
<TooltipTrigger asChild>
<button
type="button"
onClick={() => handleClick(method)}
className="flex items-center space-x-2 text-foreground/80 hover:text-foreground transition-colors hover:cursor-pointer"
>
{method.icon}
</button>
</TooltipTrigger>
<TooltipContent>
<p>{method.name}</p>
</TooltipContent>
</Tooltip>
))}
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Contact Me</DialogTitle>
<DialogDescription asChild>
<div className="flex flex-col gap-4">
{emailContacts.map((emailContact) => (
<div key={emailContact.address}>
<p>{emailContact.label} : </p>
<Item variant="outline" size="sm" asChild>
<button
type="button"
onClick={() => copyEmail(emailContact.address)}
onDoubleClick={() => openMailTo(emailContact.address)}
className="active:scale-95 transition-transform"
>
<ItemMedia>
<MailIcon className="size-5" />
</ItemMedia>
<ItemContent>
<ItemTitle>{emailContact.address}</ItemTitle>
</ItemContent>
<ItemActions>
{copiedEmail === emailContact.address ? (
<Check className="size-4" />
) : (
<Copy className="size-4" />
)}
</ItemActions>
</button>
</Item>
</div>
))}
</div>
</DialogDescription>
</DialogHeader>
<DialogFooter className="sm:justify-end">
<DialogClose asChild>
<Button type="button">Close</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
);
}