157 lines
6.1 KiB
TypeScript
157 lines
6.1 KiB
TypeScript
"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>
|
||
);
|
||
}
|