imnya.ng/src/components/Contact.astro
imnyang 56af4599a2
Some checks failed
/ print-content (push) Failing after 1m53s
src/components/Contact.astro 업데이트
2026-09-03 06:57:57 +09:00

121 lines
6.2 KiB
Text
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.

---
const contacts = [
{ name: "Email", icon: "mail", action: "dialog" },
{ name: "Blog", icon: "rss", url: "https://blog.imnya.ng" },
{ name: "GitHub", icon: "github", url: "https://github.com/imnyang" },
{ name: "git.mizuki.guru", icon: "git", url: "https://git.mizuki.guru/imnyang" },
{ name: "Instagram", icon: "instagram", url: "https://instagram.com/imnya.ng" },
{ name: "𝕏", icon: "x", url: "https://x.com/imnya_ng" },
];
const emailContacts = [
{ label: "Personal", address: "me@imnya.ng" },
{ label: "Dazzle.st", address: "imnyang@dazzle.st" },
];
const icons: Record<string, string> = {
mail: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>`,
rss: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 0 1 9 9"/><path d="M4 4a16 16 0 0 1 16 16"/><circle cx="5" cy="19" r="1"/></svg>`,
github: `<img src="/icon/github.svg" width="24" height="24" alt="GitHub" class="w-6 h-6" />`,
git: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="6" x2="6" y1="3" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>`,
instagram: `<img src="/icon/instagram.svg" width="18" height="18" alt="Instagram" class="w-4 h-4" />`,
x: `<p class="text-[20px] font-bold leading-none">𝕏</p>`,
};
---
<div class="flex flex-row space-x-4 relative">
{contacts.map((c) => (
c.action === "dialog" ? (
<button
type="button"
id="email-btn"
title={c.name}
class="flex items-center space-x-2 text-foreground/80 hover:text-foreground transition-colors hover:cursor-pointer"
set:html={icons[c.icon]}
/>
) : (
<a
href={c.url}
target="_blank"
rel="noopener noreferrer"
title={c.name}
class="flex items-center space-x-2 text-foreground/80 hover:text-foreground transition-colors"
set:html={icons[c.icon]}
/>
)
))}
</div>
<!-- Email Dialog -->
<div
id="email-dialog"
class="hidden fixed inset-0 z-50 flex items-center justify-center"
role="dialog"
aria-modal="true"
aria-label="Contact Me"
>
<div id="email-dialog-backdrop" class="absolute inset-0 bg-black/50"></div>
<div class="relative z-10 bg-background border border-border rounded-xl shadow-xl p-6 w-full max-w-sm mx-4">
<h2 class="text-lg font-semibold mb-1">Contact Me</h2>
<p class="text-sm text-muted-foreground mb-4">이메일 주소를 클릭하면 복사되고, 더블클릭하면 메일 앱이 열립니다.</p>
<div class="flex flex-col gap-3">
{emailContacts.map((ec) => (
<div>
<p class="text-xs text-muted-foreground mb-1">{ec.label}</p>
<button
type="button"
data-email={ec.address}
class="email-copy-btn w-full flex items-center gap-3 border border-border rounded-lg px-4 py-2.5 hover:bg-muted transition-colors text-left active:scale-95 transition-transform"
>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0"><rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
<span class="flex-1 text-sm">{ec.address}</span>
<span class="copy-icon text-muted-foreground">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>
</span>
</button>
</div>
))}
</div>
<div class="mt-5 flex justify-end">
<button
type="button"
id="email-dialog-close"
class="px-4 py-2 rounded bg-muted text-foreground text-sm hover:bg-muted/80 transition-colors cursor-pointer"
>
Close
</button>
</div>
</div>
</div>
<script>
const dialog = document.getElementById("email-dialog")!;
const openBtn = document.getElementById("email-btn")!;
const closeBtn = document.getElementById("email-dialog-close")!;
const backdrop = document.getElementById("email-dialog-backdrop")!;
const open = () => dialog.classList.remove("hidden");
const close = () => dialog.classList.add("hidden");
openBtn.addEventListener("click", open);
closeBtn.addEventListener("click", close);
backdrop.addEventListener("click", close);
document.addEventListener("keydown", (e) => { if (e.key === "Escape") close(); });
document.querySelectorAll<HTMLButtonElement>(".email-copy-btn").forEach((btn) => {
const email = btn.dataset.email!;
const copyIcon = btn.querySelector(".copy-icon")!;
btn.addEventListener("click", async () => {
await navigator.clipboard.writeText(email);
copyIcon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>`;
setTimeout(() => {
copyIcon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>`;
}, 1200);
});
btn.addEventListener("dblclick", () => {
window.location.href = `mailto:${email}`;
});
});
</script>