Second version of my personal website.
luccaromaniello.com/
css
personal-website
bun
tailwindcss
portflio
design
typescript
code
ux-ui
astro
javascript
1---
2import { SOCIAL_ICONS } from "@constants";
3
4interface Props {
5 icon?: keyof typeof SOCIAL_ICONS;
6 label: string;
7 href: string;
8 external?: boolean;
9 theme?: "dark" | "light";
10 track?: boolean;
11 trackEvent?: string;
12 copyToClipboard?: string;
13}
14
15const {
16 icon,
17 label,
18 href,
19 external = true,
20 theme = "light",
21 track = false,
22 trackEvent,
23 copyToClipboard,
24} = Astro.props;
25const IconComponent = icon ? SOCIAL_ICONS[icon].icon : null;
26
27const themeClasses = {
28 dark: "border-white text-white hover:bg-white hover:text-black",
29 light: "border-black text-black hover:bg-black hover:text-white",
30};
31
32const sharedClasses = [
33 "w-full md:w-auto inline-flex flex-row items-center justify-center gap-2 py-2 md:py-3 px-4 md:py-2 border-2 rounded-sm shadow-[3px_3px_0_0_#AE1E5F] text-sm text-center uppercase font-semibold cursor-pointer",
34 themeClasses[theme],
35];
36---
37
38{
39 copyToClipboard ? (
40 <button
41 data-copy={copyToClipboard}
42 aria-label={label}
43 data-umami-event={trackEvent}
44 class:list={["copy-btn", ...sharedClasses]}
45 >
46 {IconComponent && <IconComponent class="w-4 h-4" />}
47 <span data-copy-label>{label}</span>
48 </button>
49 ) : (
50 <a
51 href={href}
52 aria-label={label}
53 rel={track ? undefined : "noopener noreferrer"}
54 target={external ? "_blank" : "_self"}
55 data-umami-event={trackEvent}
56 class:list={sharedClasses}
57 >
58 {IconComponent && <IconComponent class="w-4 h-4" />}
59 {label}
60 </a>
61 )
62}
63
64<script>
65 document.querySelectorAll(".copy-btn").forEach((btn) => {
66 let timeout: ReturnType<typeof setTimeout> | null = null;
67
68 btn.addEventListener("click", () => {
69 const value = btn.getAttribute("data-copy");
70 const label = btn.querySelector("[data-copy-label]") as HTMLElement;
71 if (!value || !label) return;
72
73 const original =
74 btn.getAttribute("data-original-label") ?? label.innerText;
75 if (!btn.getAttribute("data-original-label")) {
76 btn.setAttribute("data-original-label", label.innerText);
77 label.style.minWidth = `${label.offsetWidth}px`;
78 }
79
80 navigator.clipboard.writeText(value);
81
82 if (timeout) clearTimeout(timeout);
83 label.innerText = "Copied!";
84 timeout = setTimeout(() => {
85 label.innerText = original;
86 timeout = null;
87 }, 1500);
88 });
89 });
90</script>