parent
108cf60e0c
commit
58ce75b38a
114 changed files with 966 additions and 17255 deletions
122
src/components/Contact.astro
Normal file
122
src/components/Contact.astro
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
---
|
||||
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: "ADOFAI.gg", address: "imnyang@adofai.gg" },
|
||||
{ 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>
|
||||
Loading…
Reference in a new issue