abhishek-portfolio-template 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -0
- package/bin/cli.js +54 -0
- package/package.json +27 -0
- package/template/components.json +22 -0
- package/template/next.config.ts +79 -0
- package/template/package.json +43 -0
- package/template/postcss.config.js +6 -0
- package/template/public/BoliviaSignature-ZpWnz.ttf +0 -0
- package/template/public/Gemini_Generated_Image_xc97toxc97toxc97.png +0 -0
- package/template/public/Hendrigo.otf +0 -0
- package/template/public/audiomass-output.mp3 +0 -0
- package/template/public/file.svg +1 -0
- package/template/public/globe.svg +1 -0
- package/template/public/googlec77e59474f5a09cb.html +1 -0
- package/template/public/icon-192x192.png +0 -0
- package/template/public/icon-512x512.png +0 -0
- package/template/public/next.svg +1 -0
- package/template/public/paper sound .mpeg +0 -0
- package/template/public/removebg.png +0 -0
- package/template/public/resume.pdf +0 -0
- package/template/public/sw.js +1 -0
- package/template/public/swe-worker-5c72df51bb1f6ee0.js +1 -0
- package/template/public/vercel.svg +1 -0
- package/template/public/window.svg +1 -0
- package/template/public/workbox-f1770938.js +1 -0
- package/template/src/app/about/page.tsx +91 -0
- package/template/src/app/actions/optimize-text.ts +54 -0
- package/template/src/app/gaming/page.tsx +308 -0
- package/template/src/app/github/[username]/page.tsx +97 -0
- package/template/src/app/globals.css +321 -0
- package/template/src/app/layout.tsx +39 -0
- package/template/src/app/manifest.ts +25 -0
- package/template/src/app/not-found.tsx +16 -0
- package/template/src/app/page.tsx +28 -0
- package/template/src/app/robots.ts +12 -0
- package/template/src/app/sitemap.ts +38 -0
- package/template/src/app/template.tsx +5 -0
- package/template/src/app/works/[slug]/page.tsx +50 -0
- package/template/src/app/works/client.tsx +44 -0
- package/template/src/app/works/page.tsx +24 -0
- package/template/src/components/about/about-client.tsx +259 -0
- package/template/src/components/home/bento-gallery.tsx +52 -0
- package/template/src/components/home/contact-section.tsx +34 -0
- package/template/src/components/home/craft-card.tsx +18 -0
- package/template/src/components/home/featured-projects.tsx +186 -0
- package/template/src/components/home/focus-card.tsx +171 -0
- package/template/src/components/home/identity-card.tsx +45 -0
- package/template/src/components/home/philosophy-card.tsx +104 -0
- package/template/src/components/home/skills-in-motion.tsx +109 -0
- package/template/src/components/home/tech-stack-marquee.tsx +56 -0
- package/template/src/components/ui/3d-folder.tsx +569 -0
- package/template/src/components/ui/avatar.tsx +50 -0
- package/template/src/components/ui/badge.tsx +36 -0
- package/template/src/components/ui/basic-avatar.tsx +12 -0
- package/template/src/components/ui/button.tsx +117 -0
- package/template/src/components/ui/clipboard-secret.tsx +39 -0
- package/template/src/components/ui/command-menu.tsx +519 -0
- package/template/src/components/ui/command-palette.tsx +152 -0
- package/template/src/components/ui/consciousness-mode.tsx +200 -0
- package/template/src/components/ui/copy-code-button.tsx +135 -0
- package/template/src/components/ui/display-cards.tsx +70 -0
- package/template/src/components/ui/dotted-map.tsx +128 -0
- package/template/src/components/ui/dropdown-menu.tsx +200 -0
- package/template/src/components/ui/emoji-rating.tsx +123 -0
- package/template/src/components/ui/exit-message.tsx +50 -0
- package/template/src/components/ui/image-zoom-overlay.tsx +178 -0
- package/template/src/components/ui/input-otp.tsx +71 -0
- package/template/src/components/ui/kbd.tsx +87 -0
- package/template/src/components/ui/location-tag.tsx +232 -0
- package/template/src/components/ui/minimal-testimonial.tsx +97 -0
- package/template/src/components/ui/mobile-menu.tsx +191 -0
- package/template/src/components/ui/navbar.tsx +148 -0
- package/template/src/components/ui/page-transition.tsx +24 -0
- package/template/src/components/ui/pixeleted-404-not-found.tsx +110 -0
- package/template/src/components/ui/preloader-wrapper.tsx +102 -0
- package/template/src/components/ui/preloader.tsx +104 -0
- package/template/src/components/ui/project-contributors.tsx +57 -0
- package/template/src/components/ui/scroll-area.tsx +117 -0
- package/template/src/components/ui/signature.tsx +173 -0
- package/template/src/components/ui/smooth-scroll.tsx +31 -0
- package/template/src/components/ui/social-icons.tsx +103 -0
- package/template/src/components/ui/social-stories.tsx +394 -0
- package/template/src/components/ui/sound-constants.ts +1 -0
- package/template/src/components/ui/text-explode.tsx +188 -0
- package/template/src/components/ui/toast.tsx +80 -0
- package/template/src/components/ui/tooltip.tsx +30 -0
- package/template/src/components/ui/user-location.tsx +151 -0
- package/template/src/components/ui/vertical-image-stack.tsx +345 -0
- package/template/src/components/works/changelog-overlay.tsx +212 -0
- package/template/src/components/works/currently-working-card.tsx +130 -0
- package/template/src/components/works/project-details-view.tsx +464 -0
- package/template/src/components/works/project-grid.tsx +81 -0
- package/template/src/fonts/BoliviaSignature-ZpWnz.ttf +0 -0
- package/template/src/fonts/Hendrigo.otf +0 -0
- package/template/src/lib/data.ts +61 -0
- package/template/src/lib/fonts.ts +14 -0
- package/template/src/lib/github.ts +15 -0
- package/template/src/lib/supabase.ts +11 -0
- package/template/src/lib/utils.ts +6 -0
- package/template/tailwind.config.ts +31 -0
- package/template/tsconfig.json +34 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect, useRef } from "react";
|
|
4
|
+
import { motion, AnimatePresence } from "framer-motion";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
import { sacramento } from "@/lib/fonts";
|
|
7
|
+
|
|
8
|
+
export function Signature() {
|
|
9
|
+
const [clickCount, setClickCount] = useState(0);
|
|
10
|
+
const [isTriggered, setIsTriggered] = useState(false);
|
|
11
|
+
const lastClickTime = useRef<number>(0);
|
|
12
|
+
const timerRef = useRef<NodeJS.Timeout | null>(null);
|
|
13
|
+
|
|
14
|
+
// USER: Provide your Cloudinary or video URL here.
|
|
15
|
+
const VIDEO_SRC = "https://res.cloudinary.com/dap0u41dz/video/upload/v1767179570/james_doakes_dexter_meme_720P_HD_bgahqk.mp4";
|
|
16
|
+
|
|
17
|
+
const handleClick = () => {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
const diff = now - lastClickTime.current;
|
|
20
|
+
|
|
21
|
+
if (diff < 500) { // Rapid click window
|
|
22
|
+
setClickCount(prev => {
|
|
23
|
+
const newCount = prev + 1;
|
|
24
|
+
if (newCount >= 3) {
|
|
25
|
+
setIsTriggered(true);
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
return newCount;
|
|
29
|
+
});
|
|
30
|
+
} else {
|
|
31
|
+
setClickCount(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
lastClickTime.current = now;
|
|
35
|
+
|
|
36
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
37
|
+
timerRef.current = setTimeout(() => {
|
|
38
|
+
setClickCount(0);
|
|
39
|
+
}, 1000);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (isTriggered) {
|
|
44
|
+
document.body.style.overflow = "hidden";
|
|
45
|
+
} else {
|
|
46
|
+
document.body.style.overflow = "";
|
|
47
|
+
}
|
|
48
|
+
return () => { document.body.style.overflow = ""; };
|
|
49
|
+
}, [isTriggered]);
|
|
50
|
+
|
|
51
|
+
// Buttery smooth GSAP-level extreme easing
|
|
52
|
+
const wipeTransition = {
|
|
53
|
+
duration: 1.4,
|
|
54
|
+
ease: [0.22, 1, 0.36, 1] as const
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<>
|
|
59
|
+
<div
|
|
60
|
+
onClick={handleClick}
|
|
61
|
+
className="absolute right-4 bottom-4 md:right-10 md:bottom-10 opacity-30 select-none transition-opacity z-50 mix-blend-overlay cursor-default"
|
|
62
|
+
style={{ WebkitTapHighlightColor: 'transparent' }}
|
|
63
|
+
>
|
|
64
|
+
{/* Signature */}
|
|
65
|
+
<span className={cn(sacramento.className, "text-4xl md:text-5xl text-white/80")}>
|
|
66
|
+
Abhishek Singh
|
|
67
|
+
</span>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<AnimatePresence mode="wait">
|
|
71
|
+
{isTriggered && (
|
|
72
|
+
<div className="fixed inset-0 z-[100000] flex items-center justify-center pointer-events-auto">
|
|
73
|
+
{/* Global Fade Backdrop for richness */}
|
|
74
|
+
<motion.div
|
|
75
|
+
initial={{ opacity: 0 }}
|
|
76
|
+
animate={{ opacity: 1 }}
|
|
77
|
+
exit={{ opacity: 0, transition: { delay: 1.2, duration: 1.5 } }}
|
|
78
|
+
transition={{ duration: 1 }}
|
|
79
|
+
className="fixed inset-0 bg-black/60 backdrop-blur-md"
|
|
80
|
+
/>
|
|
81
|
+
|
|
82
|
+
{/* 4 Corners Wipe Panels */}
|
|
83
|
+
<motion.div
|
|
84
|
+
initial={{ x: "-100%", y: "-100%" }}
|
|
85
|
+
animate={{ x: "0%", y: "0%" }}
|
|
86
|
+
exit={{ x: "-100%", y: "-100%", transition: { delay: 0.8, duration: 1.4, ease: [0.76, 0, 0.24, 1] } }}
|
|
87
|
+
transition={wipeTransition}
|
|
88
|
+
className="fixed top-0 left-0 w-1/2 h-1/2 bg-black origin-top-left z-20"
|
|
89
|
+
/>
|
|
90
|
+
<motion.div
|
|
91
|
+
initial={{ x: "100%", y: "-100%" }}
|
|
92
|
+
animate={{ x: "0%", y: "0%" }}
|
|
93
|
+
exit={{ x: "100%", y: "-100%", transition: { delay: 0.8, duration: 1.4, ease: [0.76, 0, 0.24, 1] } }}
|
|
94
|
+
transition={wipeTransition}
|
|
95
|
+
className="fixed top-0 right-0 w-1/2 h-1/2 bg-black origin-top-right z-20"
|
|
96
|
+
/>
|
|
97
|
+
<motion.div
|
|
98
|
+
initial={{ x: "-100%", y: "100%" }}
|
|
99
|
+
animate={{ x: "0%", y: "0%" }}
|
|
100
|
+
exit={{ x: "-100%", y: "100%", transition: { delay: 0.8, duration: 1.4, ease: [0.76, 0, 0.24, 1] } }}
|
|
101
|
+
transition={wipeTransition}
|
|
102
|
+
className="fixed bottom-0 left-0 w-1/2 h-1/2 bg-black origin-bottom-left z-20"
|
|
103
|
+
/>
|
|
104
|
+
<motion.div
|
|
105
|
+
initial={{ x: "100%", y: "100%" }}
|
|
106
|
+
animate={{ x: "0%", y: "0%" }}
|
|
107
|
+
exit={{ x: "100%", y: "100%", transition: { delay: 0.8, duration: 1.4, ease: [0.76, 0, 0.24, 1] } }}
|
|
108
|
+
transition={wipeTransition}
|
|
109
|
+
className="fixed bottom-0 right-0 w-1/2 h-1/2 bg-black origin-bottom-right z-20"
|
|
110
|
+
/>
|
|
111
|
+
|
|
112
|
+
{/* Dynamic Video Content */}
|
|
113
|
+
<motion.div
|
|
114
|
+
initial={{ opacity: 0, scale: 0.8, filter: "blur(10px)" }}
|
|
115
|
+
animate={{ opacity: 1, scale: 1, filter: "blur(0px)" }}
|
|
116
|
+
exit={{
|
|
117
|
+
opacity: 0,
|
|
118
|
+
scale: 1.1,
|
|
119
|
+
filter: "blur(20px)",
|
|
120
|
+
transition: { duration: 0.8, ease: [0.4, 0, 0.2, 1] }
|
|
121
|
+
}}
|
|
122
|
+
transition={{ delay: 0.9, duration: 1.2, ease: [0.22, 1, 0.36, 1] as const }}
|
|
123
|
+
className="relative z-30 flex items-center justify-center max-w-[90vw] max-h-[85vh] p-2 sm:p-4"
|
|
124
|
+
>
|
|
125
|
+
<div className="relative rounded-[32px] overflow-hidden shadow-[0_0_150px_rgba(0,0,0,1)] bg-black/20 ring-1 ring-white/10 group">
|
|
126
|
+
{VIDEO_SRC ? (
|
|
127
|
+
<video
|
|
128
|
+
autoPlay
|
|
129
|
+
playsInline
|
|
130
|
+
className="max-w-full max-h-[80vh] w-auto h-auto object-contain rounded-[24px]"
|
|
131
|
+
onEnded={() => setIsTriggered(false)}
|
|
132
|
+
src={VIDEO_SRC}
|
|
133
|
+
>
|
|
134
|
+
Your browser does not support the video tag.
|
|
135
|
+
</video>
|
|
136
|
+
) : (
|
|
137
|
+
<div className="w-[300px] h-[300px] flex flex-col items-center justify-center text-center space-y-4">
|
|
138
|
+
<div className="w-16 h-16 rounded-full border-2 border-white/5 border-t-white/40 animate-spin" />
|
|
139
|
+
<p className="text-white/20 text-xs font-mono uppercase tracking-widest">Awaiting Secret...</p>
|
|
140
|
+
</div>
|
|
141
|
+
)}
|
|
142
|
+
|
|
143
|
+
{/* Dynamic Terminate Action */}
|
|
144
|
+
<button
|
|
145
|
+
onClick={() => setIsTriggered(false)}
|
|
146
|
+
className="absolute top-4 right-4 sm:top-6 sm:right-6 opacity-0 group-hover:opacity-100 transition-all duration-700 text-white/40 hover:text-red-500 text-[9px] sm:text-xs uppercase tracking-[0.2em] sm:tracking-[0.3em] border border-white/10 px-4 py-2 sm:px-6 sm:py-2.5 rounded-full backdrop-blur-2xl bg-black/40 hover:bg-black/90 shadow-2xl translate-y-1 group-hover:translate-y-0 font-mono z-50"
|
|
147
|
+
>
|
|
148
|
+
[ ABORT_SEQUENCE ]
|
|
149
|
+
</button>
|
|
150
|
+
</div>
|
|
151
|
+
</motion.div>
|
|
152
|
+
|
|
153
|
+
{/* Restricted Zone Status HUD - Top Positioned */}
|
|
154
|
+
<motion.div
|
|
155
|
+
initial={{ opacity: 0, y: -20 }}
|
|
156
|
+
animate={{ opacity: 1, y: 0 }}
|
|
157
|
+
exit={{ opacity: 0, y: -20, transition: { delay: 0.1 } }}
|
|
158
|
+
transition={{ delay: 1.2, duration: 1 }}
|
|
159
|
+
className="absolute top-8 sm:top-12 left-1/2 -translate-x-1/2 z-30 flex flex-col items-center space-y-1 sm:space-y-2 w-full px-4 text-center"
|
|
160
|
+
>
|
|
161
|
+
<span className="text-red-500/60 text-[8px] sm:text-[10px] font-mono tracking-[0.3em] sm:tracking-[0.8em] uppercase whitespace-nowrap animate-pulse">
|
|
162
|
+
Restricted Zone Accessed
|
|
163
|
+
</span>
|
|
164
|
+
<span className="text-white/30 text-[7px] sm:text-[9px] font-mono tracking-[0.2em] sm:tracking-[0.4em] uppercase whitespace-nowrap">
|
|
165
|
+
Easter Egg Unlocked • Enjoy the Secret
|
|
166
|
+
</span>
|
|
167
|
+
</motion.div>
|
|
168
|
+
</div>
|
|
169
|
+
)}
|
|
170
|
+
</AnimatePresence>
|
|
171
|
+
</>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import Lenis from "lenis";
|
|
5
|
+
|
|
6
|
+
export const SmoothScroll = ({ children }: { children: React.ReactNode }) => {
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const lenis = new Lenis({
|
|
9
|
+
duration: 1.2,
|
|
10
|
+
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), // https://www.desmos.com/calculator/brs54l4xou
|
|
11
|
+
// direction: "vertical", // Removed as it caused type error and is default
|
|
12
|
+
// gestureDirection: "vertical", // Removed as it caused type error
|
|
13
|
+
smoothWheel: true,
|
|
14
|
+
wheelMultiplier: 1,
|
|
15
|
+
touchMultiplier: 2,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
function raf(time: number) {
|
|
19
|
+
lenis.raf(time);
|
|
20
|
+
requestAnimationFrame(raf);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
requestAnimationFrame(raf);
|
|
24
|
+
|
|
25
|
+
return () => {
|
|
26
|
+
lenis.destroy();
|
|
27
|
+
};
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
return <>{children}</>;
|
|
31
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useState } from "react"
|
|
4
|
+
|
|
5
|
+
const defaultLinks = {
|
|
6
|
+
github: "https://github.com",
|
|
7
|
+
x: "https://x.com",
|
|
8
|
+
linkedin: "https://linkedin.com",
|
|
9
|
+
dribbble: "https://dribbble.com"
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function SocialIcons({ links }: { links?: { github?: string, x?: string, linkedin?: string, dribbble?: string } }) {
|
|
13
|
+
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
|
|
14
|
+
|
|
15
|
+
const activeLinks = links || defaultLinks;
|
|
16
|
+
|
|
17
|
+
const socialItems = [
|
|
18
|
+
{
|
|
19
|
+
name: "GitHub",
|
|
20
|
+
href: activeLinks.github,
|
|
21
|
+
show: !!activeLinks.github,
|
|
22
|
+
icon: (
|
|
23
|
+
<svg viewBox="0 0 24 24" fill="currentColor" className="size-[18px]">
|
|
24
|
+
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
|
|
25
|
+
</svg>
|
|
26
|
+
),
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "X",
|
|
30
|
+
href: activeLinks.x,
|
|
31
|
+
show: !!activeLinks.x,
|
|
32
|
+
icon: (
|
|
33
|
+
<svg viewBox="0 0 24 24" fill="currentColor" className="size-[18px]">
|
|
34
|
+
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
|
|
35
|
+
</svg>
|
|
36
|
+
),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "LinkedIn",
|
|
40
|
+
href: activeLinks.linkedin,
|
|
41
|
+
show: !!activeLinks.linkedin,
|
|
42
|
+
icon: (
|
|
43
|
+
<svg viewBox="0 0 24 24" fill="currentColor" className="size-[18px]">
|
|
44
|
+
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
|
|
45
|
+
</svg>
|
|
46
|
+
),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "Dribbble",
|
|
50
|
+
href: activeLinks.dribbble,
|
|
51
|
+
show: !!activeLinks.dribbble,
|
|
52
|
+
icon: (
|
|
53
|
+
<svg viewBox="0 0 24 24" fill="currentColor" className="size-[18px]">
|
|
54
|
+
<path d="M12 24C5.385 24 0 18.615 0 12S5.385 0 12 0s12 5.385 12 12-5.385 12-12 12zm10.12-10.358c-.35-.11-3.17-.953-6.384-.438 1.34 3.684 1.887 6.684 1.992 7.308 2.3-1.555 3.936-4.02 4.395-6.87zm-6.115 7.808c-.153-.9-.75-4.032-2.19-7.77l-.066.02c-5.79 2.015-7.86 6.025-8.04 6.4 1.73 1.358 3.92 2.166 6.29 2.166 1.42 0 2.77-.29 4-.814zm-11.62-2.58c.232-.4 3.045-5.055 8.332-6.765.135-.045.27-.084.405-.12-.26-.585-.54-1.167-.832-1.74C7.17 11.775 2.206 11.71 1.756 11.7l-.004.312c0 2.633.998 5.037 2.634 6.855zm-2.42-8.955c.46.008 4.683.026 9.477-1.248-1.698-3.018-3.53-5.558-3.8-5.928-2.868 1.35-5.01 3.99-5.676 7.17zM9.6 2.052c.282.38 2.145 2.914 3.822 6 3.645-1.365 5.19-3.44 5.373-3.702-1.81-1.61-4.19-2.586-6.795-2.586-.825 0-1.63.1-2.4.285zm10.335 3.483c-.218.29-1.935 2.493-5.724 4.04.24.49.47.985.68 1.486.08.18.15.36.22.53 3.41-.43 6.8.26 7.14.33-.02-2.42-.88-4.64-2.31-6.38z" />
|
|
55
|
+
</svg>
|
|
56
|
+
),
|
|
57
|
+
},
|
|
58
|
+
].filter(item => item.show);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div className="relative flex items-center gap-0.5 px-1.5 py-1.5 rounded-2xl bg-neutral-950 border border-white/[0.08]">
|
|
62
|
+
<div className="absolute inset-0 rounded-2xl bg-gradient-to-b from-white/[0.03] to-transparent pointer-events-none" />
|
|
63
|
+
|
|
64
|
+
{socialItems.map((social, index) => (
|
|
65
|
+
<a
|
|
66
|
+
key={social.name}
|
|
67
|
+
href={social.href}
|
|
68
|
+
target="_blank"
|
|
69
|
+
rel="noopener noreferrer"
|
|
70
|
+
className="group relative flex items-center justify-center size-10 rounded-xl transition-colors duration-200"
|
|
71
|
+
onMouseEnter={() => setHoveredIndex(index)}
|
|
72
|
+
onMouseLeave={() => setHoveredIndex(null)}
|
|
73
|
+
aria-label={social.name}
|
|
74
|
+
>
|
|
75
|
+
<span
|
|
76
|
+
className={`absolute inset-1 rounded-lg bg-white/[0.08] transition-all duration-300 ease-out ${hoveredIndex === index ? "opacity-100 scale-100" : "opacity-0 scale-90"
|
|
77
|
+
}`}
|
|
78
|
+
/>
|
|
79
|
+
|
|
80
|
+
<span
|
|
81
|
+
className={`relative z-10 transition-all duration-300 ease-out ${hoveredIndex === index ? "text-white scale-110" : "text-neutral-500"
|
|
82
|
+
}`}
|
|
83
|
+
>
|
|
84
|
+
{social.icon}
|
|
85
|
+
</span>
|
|
86
|
+
|
|
87
|
+
<span
|
|
88
|
+
className={`absolute bottom-1.5 left-1/2 -translate-x-1/2 h-[2px] rounded-full bg-white transition-all duration-300 ease-out ${hoveredIndex === index ? "w-3 opacity-100" : "w-0 opacity-0"
|
|
89
|
+
}`}
|
|
90
|
+
/>
|
|
91
|
+
|
|
92
|
+
<span
|
|
93
|
+
className={`absolute -top-10 left-1/2 -translate-x-1/2 px-2.5 py-1 rounded-lg bg-white text-neutral-950 text-[11px] font-medium whitespace-nowrap transition-all duration-300 ease-out ${hoveredIndex === index ? "opacity-100 translate-y-0" : "opacity-0 translate-y-1 pointer-events-none"
|
|
94
|
+
}`}
|
|
95
|
+
>
|
|
96
|
+
{social.name}
|
|
97
|
+
<span className="absolute -bottom-1 left-1/2 -translate-x-1/2 size-2 rotate-45 bg-white" />
|
|
98
|
+
</span>
|
|
99
|
+
</a>
|
|
100
|
+
))}
|
|
101
|
+
</div>
|
|
102
|
+
)
|
|
103
|
+
}
|