Skip to content

Commit d13a661

Browse files
committed
Hey
1 parent 5b6a734 commit d13a661

File tree

8 files changed

+280
-12
lines changed

8 files changed

+280
-12
lines changed

package-lock.json

Lines changed: 85 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12+
"clsx": "^2.1.1",
13+
"motion": "^12.23.12",
14+
"next": "15.4.5",
1215
"react": "19.1.0",
1316
"react-dom": "19.1.0",
14-
"next": "15.4.5"
17+
"tailwind-merge": "^3.3.1"
1518
},
1619
"devDependencies": {
20+
"@eslint/eslintrc": "^3",
1721
"@tailwindcss/postcss": "^4",
18-
"tailwindcss": "^4",
1922
"eslint": "^9",
2023
"eslint-config-next": "15.4.5",
21-
"@eslint/eslintrc": "^3"
24+
"tailwindcss": "^4"
2225
}
2326
}

public/logo.png

9.23 KB
Loading

src/app/globals.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,13 @@
11
@import "tailwindcss";
2+
3+
4+
5+
.font-space-grotesk {
6+
font-family: var(--font-space-grotesk) , 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
7+
}
8+
.font-space-mono {
9+
font-family: var(--font-space-mono) , 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
10+
}
11+
.font-borel {
12+
font-family: var(--font-borel) , 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
13+
}

src/app/layout.js

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,42 @@
11
import "./globals.css";
2+
import { Space_Grotesk, Space_Mono, Borel } from "next/font/google";
3+
4+
const spaceGrotesk = Space_Grotesk({
5+
subsets: ["latin"],
6+
variable: "--font-space-grotesk",
7+
weight: ["300", "400", "500", "700"], // adjust as needed
8+
});
9+
10+
const spaceMono = Space_Mono({
11+
subsets: ["latin"],
12+
variable: "--font-space-mono",
13+
weight: ["400", "700"],
14+
});
15+
16+
const borel = Borel({
17+
subsets: ["latin"],
18+
variable: "--font-borel",
19+
weight: ["400"],
20+
});
221

322
export const metadata = {
4-
title:
5-
"Vspcoderz Portfolio - Hi, I am Vspcoderz a 10th Student Passionate In Code ",
23+
title: "Vspcoderz Portfolio ",
624
description:
725
"Hey I am Vedant Pakwane AKA Vspcoderz I am In 10th In 2025 I am Intrested In Java , DSA , Javascript , Python , AI/ML , Next.js , React & More.... ",
26+
icons: {
27+
icon: "/logo.png",
28+
apple: "/logo.png",
29+
},
830
};
931

1032
export default function RootLayout({ children }) {
1133
return (
1234
<html lang="en">
13-
<body className="bg-zinc-900 text-zinc-100">{children}</body>
35+
<body
36+
className={`bg-zinc-900 text-zinc-100 ${spaceGrotesk.variable} ${spaceMono.variable}`}
37+
>
38+
{children}
39+
</body>
1440
</html>
1541
);
1642
}

src/components/HeroSection.jsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
1-
import React from 'react'
1+
import React from "react";
2+
import { TextHoverEffect } from "@/components/ui/text-hover-effect";
23

34
const HeroSection = () => {
45
return (
5-
<section className="w-full h-screen ">HeroSection</section>
6-
)
7-
}
6+
<>
7+
<section className="w-full h-screen flex justify-center items-center">
8+
<div className="absolute top-24 left-1/4 w-1/2 h-96 flex items-center justify-center z-0">
9+
<TextHoverEffect text="Hello!" />
10+
</div>
811

9-
export default HeroSection
12+
<div className="relative z-10 flex flex-col gap-2 items-center">
13+
<h1 className="text-8xl font-space-mono">Hi I am Vspcoderz.</h1>
14+
<span className="text-8xl font-space-grotesk">Coder. Minecraft</span>
15+
</div>
16+
</section>
17+
</>
18+
);
19+
};
20+
21+
export default HeroSection;
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"use client";
2+
import React, { useRef, useEffect, useState } from "react";
3+
import { motion } from "motion/react";
4+
5+
export const TextHoverEffect = ({ text, duration }) => {
6+
const svgRef = useRef(null);
7+
const [cursor, setCursor] = useState({ x: 0, y: 0 });
8+
const [hovered, setHovered] = useState(false);
9+
const [maskPosition, setMaskPosition] = useState({ cx: "50%", cy: "50%" });
10+
11+
useEffect(() => {
12+
if (svgRef.current && cursor.x !== null && cursor.y !== null) {
13+
const svgRect = svgRef.current.getBoundingClientRect();
14+
const cxPercentage = ((cursor.x - svgRect.left) / svgRect.width) * 100;
15+
const cyPercentage = ((cursor.y - svgRect.top) / svgRect.height) * 100;
16+
setMaskPosition({
17+
cx: `${cxPercentage}%`,
18+
cy: `${cyPercentage}%`,
19+
});
20+
}
21+
}, [cursor]);
22+
23+
return (
24+
<svg
25+
ref={svgRef}
26+
width="100%"
27+
height="100%"
28+
viewBox="0 0 300 100"
29+
xmlns="http://www.w3.org/2000/svg"
30+
onMouseEnter={() => setHovered(true)}
31+
onMouseLeave={() => setHovered(false)}
32+
onMouseMove={(e) => setCursor({ x: e.clientX, y: e.clientY })}
33+
className="select-none"
34+
>
35+
<defs>
36+
<linearGradient
37+
id="textGradient"
38+
gradientUnits="userSpaceOnUse"
39+
cx="50%"
40+
cy="50%"
41+
r="25%"
42+
>
43+
{hovered && (
44+
<>
45+
<stop offset="0%" stopColor="#eab308" />
46+
<stop offset="25%" stopColor="#ef4444" />
47+
<stop offset="50%" stopColor="#3b82f6" />
48+
<stop offset="75%" stopColor="#06b6d4" />
49+
<stop offset="100%" stopColor="#8b5cf6" />
50+
</>
51+
)}
52+
</linearGradient>
53+
54+
<motion.radialGradient
55+
id="revealMask"
56+
gradientUnits="userSpaceOnUse"
57+
r="20%"
58+
initial={{ cx: "50%", cy: "50%" }}
59+
animate={maskPosition}
60+
// example for a smoother animation below
61+
// transition={{
62+
// type: "spring",
63+
// stiffness: 300,
64+
// damping: 50,
65+
// }}
66+
transition={{ duration: duration ?? 0, ease: "easeOut" }}
67+
>
68+
<stop offset="0%" stopColor="white" />
69+
<stop offset="100%" stopColor="black" />
70+
</motion.radialGradient>
71+
<mask id="textMask">
72+
<rect
73+
x="0"
74+
y="0"
75+
width="100%"
76+
height="100%"
77+
fill="url(#revealMask)"
78+
/>
79+
</mask>
80+
</defs>
81+
<text
82+
x="50%"
83+
y="50%"
84+
textAnchor="middle"
85+
dominantBaseline="middle"
86+
strokeWidth="0.3"
87+
className="fill-transparent stroke-neutral-200 font-[helvetica] text-7xl font-bold dark:stroke-neutral-800"
88+
style={{ opacity: hovered ? 0.7 : 0 }}
89+
>
90+
{text}
91+
</text>
92+
<motion.text
93+
x="50%"
94+
y="50%"
95+
textAnchor="middle"
96+
dominantBaseline="middle"
97+
strokeWidth="0.3"
98+
className="fill-transparent stroke-neutral-200 font-[helvetica] text-7xl font-bold dark:stroke-neutral-800"
99+
initial={{ strokeDashoffset: 1000, strokeDasharray: 1000 }}
100+
animate={{
101+
strokeDashoffset: 0,
102+
strokeDasharray: 1000,
103+
}}
104+
transition={{
105+
duration: 4,
106+
ease: "easeInOut",
107+
}}
108+
>
109+
{text}
110+
</motion.text>
111+
<text
112+
x="50%"
113+
y="50%"
114+
textAnchor="middle"
115+
dominantBaseline="middle"
116+
stroke="url(#textGradient)"
117+
strokeWidth="0.3"
118+
mask="url(#textMask)"
119+
className="fill-transparent font-[helvetica] text-7xl font-bold"
120+
>
121+
{text}
122+
</text>
123+
</svg>
124+
);
125+
};

src/lib/utils.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { clsx } from "clsx";
2+
import { twMerge } from "tailwind-merge";
3+
4+
export function cn(...inputs) {
5+
return twMerge(clsx(inputs));
6+
}

0 commit comments

Comments
 (0)