initial commit

This commit is contained in:
Harivansh Rathi 2025-01-03 15:55:01 +05:30
commit fb5b992b17
35 changed files with 11573 additions and 0 deletions

42
src/app/App.css Normal file
View file

@ -0,0 +1,42 @@
@media only screen and (max-width: 991px) {
.s_c {
padding-top: 40px;
}
}
.page-enter {
transform: translateY(100%);
}
.page-enter-active {
transform: translateY(0%);
transition: all 400ms ease-out;
}
.page-exit {
transform: translateY(0%);
position: absolute;
left: 0;
right: 0;
top: 0;
}
.page-exit-active {
position: absolute;
left: 0;
right: 0;
top: 0;
transform: translateY(-130%);
transition: all 400ms ease-out;
}
@media (min-width: 1400px) {
.container,
.container-lg,
.container-md,
.container-sm,
.container-xl,
.container-xxl {
max-width: 1140px;
}
}

41
src/app/App.js Normal file
View file

@ -0,0 +1,41 @@
import React, { useEffect } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import {
BrowserRouter as Router,
useLocation,
} from "react-router-dom";
import withRouter from "../hooks/withRouter";
import AppRoutes from "./routes";
import Headermain from "../header";
import AnimatedCursor from "../hooks/AnimatedCursor";
import "./App.css";
function _ScrollToTop(props) {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return props.children;
}
const ScrollToTop = withRouter(_ScrollToTop);
export default function App() {
return (
<Router basename={process.env.PUBLIC_URL}>
<div className="cursor__dot">
<AnimatedCursor
innerSize={15}
outerSize={15}
color="255, 255 ,255"
outerAlpha={0.4}
innerScale={0.7}
outerScale={5}
/>
</div>
<ScrollToTop>
<Headermain />
<AppRoutes />
</ScrollToTop>
</Router>
);
}

42
src/app/routes.js Normal file
View file

@ -0,0 +1,42 @@
import React from "react";
import { Route, Routes} from "react-router-dom";
import withRouter from "../hooks/withRouter"
import { Home } from "../pages/home";
import { Portfolio } from "../pages/portfolio";
import { ContactUs } from "../pages/contact";
import { About } from "../pages/about";
import { Socialicons } from "../components/socialicons";
import { CSSTransition, TransitionGroup } from "react-transition-group";
const AnimatedRoutes = withRouter(({ location }) => (
<TransitionGroup>
<CSSTransition
key={location.key}
timeout={{
enter: 400,
exit: 400,
}}
classNames="page"
unmountOnExit
>
<Routes location={location}>
<Route exact path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/portfolio" element={<Portfolio />} />
<Route path="/contact" element={<ContactUs />} />
<Route path="*" element={<Home />} />
</Routes>
</CSSTransition>
</TransitionGroup>
));
function AppRoutes() {
return (
<div className="s_c">
<AnimatedRoutes />
<Socialicons />
</div>
);
}
export default AppRoutes;

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

View file

@ -0,0 +1,37 @@
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="2em"
height="2em"
x="0"
y="0"
viewBox="0 0 512 512"
>
<g>
<g xmlns="http://www.w3.org/2000/svg">
<g>
<circle
cx="256"
cy="256"
fill="#ffffff"
r="256"
data-original="#ff3333"
/>
</g>
<g>
<path
d="m374.02 119.205v155.57c0 65.08-52.94 118.02-118.02 118.02s-118.02-52.94-118.02-118.02v-155.57h58v155.57c0 33.09 26.93 60.02 60.02 60.02s60.02-26.93 60.02-60.02v-155.57z"
fill="#000000"
data-original="#f8fffb"
/>
</g>
<g>
<path
d="m374.02 119.2v155.58c0 65.08-52.94 118.02-118.02 118.02v-58c33.09 0 60.02-26.94 60.02-60.02v-155.58z"
fill="#000000"
data-original="#d8d8d8"
/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,49 @@
import React from "react";
import "./style.css";
import {
FaGithub,
FaTwitter,
FaFacebookF,
FaLinkedin,
FaYoutube,
FaTwitch,
FaInstagram,
FaSnapchatGhost,
FaTiktok,
FaFileAlt
} from "react-icons/fa";
import { socialprofils } from "../../content_option";
const ICON_MAPPING = {
default: FaFileAlt,
facebook: FaFacebookF,
github: FaGithub,
instagram: FaInstagram,
linkedin: FaLinkedin,
snapchat: FaSnapchatGhost,
tiktok: FaTiktok,
twitter: FaTwitter,
twitch: FaTwitch,
youtube: FaYoutube,
resume: FaFileAlt
};
export const Socialicons = (params) => {
return (
<div className="stick_follow_icon">
<ul>
{Object.entries(socialprofils).map(([platform, url]) => {
const IconComponent = ICON_MAPPING[platform] || ICON_MAPPING.default;
return (
<li key={platform}>
<a href={url}>
<IconComponent />
</a>
</li>
);
})}
</ul>
<p>Follow Me</p>
</div>
);
};

View file

@ -0,0 +1,86 @@
.stick_follow_icon {
top: 50%;
left: 30px;
width: 20px;
height: 200px;
position: fixed;
margin-top: -100px;
}
.stick_follow_icon ul {
list-style: none;
padding: 0;
margin: 0;
}
.stick_follow_icon svg {
width: 1.3em;
height: 1.3em;
fill: var(--text-color)
}
.stick_follow_icon p {
top: 70px;
left: -24px;
width: 68px;
height: 20px;
color: var(--text-color);
font-size: 12px;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
position: relative;
transform: rotate( -90deg);
}
.stick_follow_icon ul li {
display: block;
font-size: 12px;
text-align: center;
margin-bottom: 10px;
transition: all .3s;
}
.stick_follow_icon p:after {
top: 9px;
right: -48px;
width: 40px;
height: 1px;
content: "";
display: block;
position: absolute;
background-color: var(--text-color);
}
@media only screen and (max-width: 991px) {
.stick_follow_icon {
width: unset;
height: unset;
position: static;
margin-top: unset;
display: flex;
flex-direction: row-reverse;
justify-content: center;
padding: 40px 0;
align-items: center;
}
.stick_follow_icon p {
top: unset;
left: unset;
width: unset;
height: unset;
white-space: nowrap;
position: relative;
transform: unset;
font-size: 17px;
margin-right: 65px;
}
.stick_follow_icon ul {
margin-bottom: 20px;
}
.stick_follow_icon ul li {
display: inline;
margin-bottom: 29px;
margin-right: 10px;
}
}

View file

@ -0,0 +1,21 @@
import React, { useEffect, useState } from "react";
import { WiMoonAltWaningCrescent4 } from "react-icons/wi";
const Themetoggle = () => {
const [theme, settheme] = useState(localStorage.getItem("theme"));
const themetoggle = () => {
settheme(theme === "dark" ? "light" : "dark");
};
useEffect(() => {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme );
}, [theme]);
return (
<div className="nav_ac" onClick={themetoggle}>
<WiMoonAltWaningCrescent4 />
</div>
);
};
export default Themetoggle;

View file

@ -0,0 +1,15 @@
.theme_toggler {
background: var(--primary-color);
z-index: 999999999;
left: 10px;
background: var(--primary-color);
display: flex;
height: 50px;
align-items: center;
padding-left: 10px;
}
.theme_toggler svg {
width: 2em;
height: 2em;
}

170
src/content_option.js Normal file
View file

@ -0,0 +1,170 @@
const logotext = "HARIVANSH";
const meta = {
title: "Harivansh Rathi",
description: "Im Harivansh Rathi, a Computer Science student at the University of Virginia.",
};
const introdata = {
title: "Hi, I'm Harivansh Rathi",
animated: {
first: "Full Stack Developer",
second: "Software Engineer",
third: "Tech Enthusiast",
},
description: "I'm passionate about building exceptional digital experiences that make a difference. With expertise in both frontend and backend development, I create scalable and efficient solutions that solve real-world problems.",
your_img_url: "https://i.imgur.com/0y00000.png",
};
const dataabout = {
title: "About Me",
aboutme: "I am a Computer Science student at the University of Virginia, with a passion for software development and AI. I enjoy building scalable applications and exploring the latest advancements in technology. I am always eager to learn and contribute to innovative projects.",
};
const worktimeline = [{
jobtitle: "Front End Development Intern",
where: "UNIKOVE TECHNOLOGIES",
date: "June 2024 - August 2024",
},
{
jobtitle: "Software Development Intern",
where: "MOGLIX",
date: "June 2023 - August 2023",
},
{
jobtitle: "Software Engineering Intern",
where: "SAN AUTO",
date: "June 2022 - August 2022",
},
];
const skills = [{
name: "Python",
value: 90,
},
{
name: "Java",
value: 85,
},
{
name: "Typescript",
value: 80,
},
{
name: "HTML",
value: 90,
},
{
name: "CSS/Tailwind",
value: 85,
},
{
name: "C/C++",
value: 70,
},
{
name: "React.js",
value: 80,
},
{
name: "Node.js",
value: 75,
},
{
name: "Express.js",
value: 75,
},
{
name: "Vite",
value: 80,
},
{
name: "Next.js 14",
value: 70,
},
{
name: "Git/Github",
value: 90,
},
{
name: "PostgreSQL",
value: 80,
},
{
name: "MySQL",
value: 80,
},
{
name: "Supabase",
value: 75,
},
{
name: "Vercel",
value: 80,
},
{
name: "OAuth 2.0",
value: 70,
},
];
const services = [{
title: "Front End Development",
description: "Utilizing JavaScript and React.js to refine UX design elements, ensuring seamless functionality and integration.",
},
{
title: "Back End Development",
description: "Developing robust and scalable backend solutions using Node.js, Express.js, and SQL databases.",
},
{
title: "AI Application Development",
description: "Building AI-powered applications with a focus on document retrieval and data analysis.",
},
];
const dataportfolio = [{
img: "https://picsum.photos/400/300/?grayscale",
description: "Built a React/TypeScript RAG AI chat application with n8n, achieving 95% query response accuracy",
link: "https://github.com/harivansh-afk/RAG-ui",
},
{
img: "https://picsum.photos/400/300/?grayscale",
description: "Co-authored a research paper on cryptocurrency market predictability with a PHD student at CMU",
link: "https://github.com/harivansh-afk/CryptoCurrencyPredictionLSTM",
},
{
img: "https://picsum.photos/400/300/?grayscale",
description: "Built a full-stack habit tracker web app with React, TypeScript, and Supabase, boosting scalability by 25%",
link: "https://github.com/harivansh-afk/Habit-Tracker",
},
{
img: "https://picsum.photos/400/300/?grayscale",
description: "Built a React/TypeScript app with Shadcn/UI and Tailwind, implementing lazy loading for 40% faster loads",
link: "https://github.com/harivansh-afk/ENGL-Final-Project",
},
];
const contactConfig = {
YOUR_EMAIL: "zng2gc@virginia.edu",
YOUR_FONE: "+1 434-310-1227",
description: "I am currently based in Charlottesville, VA. Feel free to reach out to me for any opportunities or collaborations.",
YOUR_SERVICE_ID: "service_id",
YOUR_TEMPLATE_ID: "template_id",
YOUR_USER_ID: "user_id",
};
const socialprofils = {
github: "https://github.com/harivansh-afk",
linkedin: "https://linkedin.com/in/harivansh-rathi",
resume: "https://docs.google.com/document/d/1TKbtqYinjRNFZiZNbxEwRTz5QDiZ5mOk/edit?usp=sharing&ouid=104313709347999918268&rtpof=true&sd=true"
};
export {
meta,
dataabout,
dataportfolio,
worktimeline,
skills,
services,
introdata,
contactConfig,
socialprofils,
logotext,
};

72
src/header/index.js Normal file
View file

@ -0,0 +1,72 @@
import React, { useState } from "react";
import "./style.css";
import { VscGrabber, VscClose } from "react-icons/vsc";
import { Link } from "react-router-dom";
import { logotext ,socialprofils } from "../content_option";
import Themetoggle from "../components/themetoggle";
const Headermain = () => {
const [isActive, setActive] = useState("false");
const handleToggle = () => {
setActive(!isActive);
document.body.classList.toggle("ovhidden");
};
return (
<>
<header className="fixed-top site__header">
<div className="d-flex align-items-center justify-content-between">
<Link className="navbar-brand nav_ac" to="/">
{logotext}
</Link>
<div className="d-flex align-items-center">
<Themetoggle />
<button className="menu__button nav_ac" onClick={handleToggle}>
{!isActive ? <VscClose /> : <VscGrabber />}
</button>
</div>
</div>
<div className={`site__navigation ${!isActive ? "menu__opend" : ""}`}>
<div className="bg__menu h-100">
<div className="menu__wrapper">
<div className="menu__container p-3">
<ul className="the_menu">
<li className="menu_item ">
<Link onClick={handleToggle} to="/" className="my-3">Home</Link>
</li>
<li className="menu_item">
<Link onClick={handleToggle} to="/portfolio" className="my-3"> Portfolio</Link>
</li>
<li className="menu_item">
<Link onClick={handleToggle} to="/about" className="my-3">About</Link>
</li>
<li className="menu_item">
<Link onClick={handleToggle} to="/contact" className="my-3"> Contact</Link>
</li>
</ul>
</div>
</div>
</div>
<div className="menu_footer d-flex flex-column flex-md-row justify-content-between align-items-md-center position-absolute w-100 p-3">
<div className="d-flex">
<a href={socialprofils.github}>Github</a>
<a href={socialprofils.linkedin}>LinkedIn</a>
<a href={socialprofils.portfolio}>Resume</a>
</div>
<p className="copyright m-0">copyright __ {logotext}</p>
</div>
</div>
</header>
<div className="br-top"></div>
<div className="br-bottom"></div>
<div className="br-left"></div>
<div className="br-right"></div>
</>
);
};
export default Headermain;

207
src/header/style.css Normal file
View file

@ -0,0 +1,207 @@
.site__header {
top: 10px;
padding-left: 10px;
padding-right: 10px;
}
.menu__button {
color: var(--text-color);
}
.menu__button:focus,
.menu__button:hover {
color: var(--text-color);
box-shadow: unset;
}
.menu__button svg {
width: 2em;
height: 2em;
fill: var(--text-color-2);
color: var(--text-color-2);
}
.nav_ac {
padding: 5px 15px;
margin: 0;
border: unset;
background: var(--primary-color);
font-size: 1.25rem;
font-family: Marcellus;
color: var(--text-color-2);
line-height: 2;
height: 50px;
font-weight: bold;
z-index: 1000;
}
.nav_ac:hover {
color: var(--text-color-2);
}
.br-top,
.br-bottom,
.br-right,
.br-left {
position: fixed;
z-index: 999999;
background: var(--primary-color);
}
.br-top {
top: 0;
height: 10px;
left: 0;
width: 100%;
}
.br-bottom {
bottom: 0;
left: 0;
height: 10px;
width: 100%;
}
.br-right {
width: 10px;
right: 0;
top: 0;
height: 100%;
}
.br-left {
width: 10px;
left: 0;
top: 0;
height: 100%;
}
.cortina__wrapper-menu {
position: relative;
width: 100%;
padding-top: 5em;
padding-bottom: 3em;
height: 100%;
overflow-y: auto;
}
.site__navigation {
height: 100%;
left: 0;
overflow: hidden;
position: fixed;
top: 0;
width: 100%;
visibility: hidden;
}
.menu__opend {
visibility: visible !important;
}
.main__menu_ul,
.menu_right {
opacity: 0;
position: relative;
transition: 0.5s;
transition-delay: 0s;
visibility: hidden;
z-index: 100;
}
.menu_right {
text-align: center;
}
.site__navigation.menu__opend .main__menu_ul,
.site__navigation.menu__opend .menu_right {
opacity: 1;
transition-delay: 0.6s;
visibility: visible;
}
.site__navigation .main__menu_ul li {
list-style: none;
margin: 10px 0;
}
.site__navigation .main__menu_ul li a {
color: var(--text-color);
display: block;
font-size: 2.5rem;
text-decoration: none;
}
.bg__menu {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
background-color: var(--primary-color);
will-change: transform;
transform: translateY(-100%);
transition: .5s ease all;
}
.menu__opend .bg__menu {
transform: translateY(0);
}
.menu__wrapper {
position: relative;
width: 100%;
height: 100%;
overflow: hidden auto;
}
.the_menu {
padding-top: 20vh;
padding-bottom: 20vh;
padding-left: 0;
}
@media (min-width: 992px) {
.menu__container {
margin-left: 33.3333%;
}
.the_menu {
padding-top: 10vh;
padding-bottom: 10vh;
}
}
.the_menu .menu_item>a {
color: var(--text-color-2);
line-height: 1;
font-size: 2rem;
display: inline-block;
position: relative;
transition: color 250ms cubic-bezier(0, 0, 0.58, 1) 0s;
padding: 4px 0px;
text-decoration: none;
font-family: Marcellus;
}
.the_menu .menu_item>a:hover {
color: var(--text-color-3);
}
@media (min-width: 768px) {
.the_menu .menu_item>a {
font-size: 4.8vw;
}
}
.menu_footer {
bottom: 0;
font-family: Marcellus;
font-size: 14px;
background: var(--primary-color);
}
.menu_footer a {
color: var(--text-color-2);
margin-right: 10px;
text-decoration: none;
}

329
src/hooks/AnimatedCursor.js Normal file
View file

@ -0,0 +1,329 @@
import React, {useEffect,useRef,useState,useCallback} from "react"
const IsDevice = (() => {
if (typeof navigator == 'undefined') return
let ua = navigator.userAgent
return {
info: ua,
Android() {
return ua.match(/Android/i)
},
BlackBerry() {
return ua.match(/BlackBerry/i)
},
IEMobile() {
return ua.match(/IEMobile/i)
},
iOS() {
return ua.match(/iPhone|iPad|iPod/i)
},
iPad() {
return (
ua.match(/Mac/) &&
navigator.maxTouchPoints &&
navigator.maxTouchPoints > 2
)
},
OperaMini() {
return ua.match(/Opera Mini/i)
},
/**
* Any Device
*/
any() {
return (
IsDevice.Android() ||
IsDevice.BlackBerry() ||
IsDevice.iOS() ||
IsDevice.iPad() ||
IsDevice.OperaMini() ||
IsDevice.IEMobile()
)
}
}
})()
function useEventListener(eventName, handler, element = document) {
const savedHandler = useRef()
useEffect(() => {
savedHandler.current = handler
}, [handler])
useEffect(() => {
const isSupported = element && element.addEventListener
if (!isSupported) return
const eventListener = (event) => savedHandler.current(event)
element.addEventListener(eventName, eventListener)
return () => {
element.removeEventListener(eventName, eventListener)
}
}, [eventName, element])
}
/**
* Cursor Core
* Replaces the native cursor with a custom animated cursor, consisting
* of an inner and outer dot that scale inversely based on hover or click.
*
* @author Stephen Scaff (github.com/stephenscaff)
*
* @param {string} color - rgb color value
* @param {number} outerAlpha - level of alpha transparency for color
* @param {number} innerSize - inner cursor size in px
* @param {number} innerScale - inner cursor scale amount
* @param {number} outerSize - outer cursor size in px
* @param {number} outerScale - outer cursor scale amount
* @param {object} outerStyle - style object for outer cursor
* @param {object} innerStyle - style object for inner cursor
* @param {array} clickables - array of clickable selectors
*
*/
function CursorCore({
outerStyle,
innerStyle,
color = '220, 90, 90',
outerAlpha = 0.3,
innerSize = 8,
outerSize = 8,
outerScale = 6,
innerScale = 0.6,
trailingSpeed = 8,
clickables = [
'a',
'input[type="text"]',
'input[type="email"]',
'input[type="number"]',
'input[type="submit"]',
'input[type="image"]',
'label[for]',
'select',
'textarea',
'button',
'.link'
]
}) {
const cursorOuterRef = useRef()
const cursorInnerRef = useRef()
const requestRef = useRef()
const previousTimeRef = useRef()
const [coords, setCoords] = useState({ x: 0, y: 0 })
const [isVisible, setIsVisible] = useState(false)
const [isActive, setIsActive] = useState(false)
const [isActiveClickable, setIsActiveClickable] = useState(false)
let endX = useRef(0)
let endY = useRef(0)
/**
* Primary Mouse move event
* @param {number} clientX - MouseEvent.clientx
* @param {number} clientY - MouseEvent.clienty
*/
const onMouseMove = useCallback(({ clientX, clientY }) => {
setCoords({ x: clientX, y: clientY })
cursorInnerRef.current.style.top = `${clientY}px`
cursorInnerRef.current.style.left = `${clientX}px`
endX.current = clientX
endY.current = clientY
}, [])
// Outer Cursor Animation Delay
const animateOuterCursor = useCallback(
(time) => {
if (previousTimeRef.current !== undefined) {
coords.x += (endX.current - coords.x) / trailingSpeed
coords.y += (endY.current - coords.y) / trailingSpeed
cursorOuterRef.current.style.top = `${coords.y}px`
cursorOuterRef.current.style.left = `${coords.x}px`
}
previousTimeRef.current = time
requestRef.current = requestAnimationFrame(animateOuterCursor)
},
[requestRef] // eslint-disable-line
)
// RAF for animateOuterCursor
useEffect(() => {
requestRef.current = requestAnimationFrame(animateOuterCursor)
return () => cancelAnimationFrame(requestRef.current)
}, [animateOuterCursor])
// Mouse Events State updates
const onMouseDown = useCallback(() => setIsActive(true), [])
const onMouseUp = useCallback(() => setIsActive(false), [])
const onMouseEnterViewport = useCallback(() => setIsVisible(true), [])
const onMouseLeaveViewport = useCallback(() => setIsVisible(false), [])
useEventListener('mousemove', onMouseMove)
useEventListener('mousedown', onMouseDown)
useEventListener('mouseup', onMouseUp)
useEventListener('mouseover', onMouseEnterViewport)
useEventListener('mouseout', onMouseLeaveViewport)
// Cursors Hover/Active State
useEffect(() => {
if (isActive) {
cursorInnerRef.current.style.transform = `translate(-50%, -50%) scale(${innerScale})`
cursorOuterRef.current.style.transform = `translate(-50%, -50%) scale(${outerScale})`
} else {
cursorInnerRef.current.style.transform = 'translate(-50%, -50%) scale(1)'
cursorOuterRef.current.style.transform = 'translate(-50%, -50%) scale(1)'
}
}, [innerScale, outerScale, isActive])
// Cursors Click States
useEffect(() => {
if (isActiveClickable) {
cursorInnerRef.current.style.transform = `translate(-50%, -50%) scale(${
innerScale * 1.2
})`
cursorOuterRef.current.style.transform = `translate(-50%, -50%) scale(${
outerScale * 1.4
})`
}
}, [innerScale, outerScale, isActiveClickable])
// Cursor Visibility State
useEffect(() => {
if (isVisible) {
cursorInnerRef.current.style.opacity = 1
cursorOuterRef.current.style.opacity = 1
} else {
cursorInnerRef.current.style.opacity = 0
cursorOuterRef.current.style.opacity = 0
}
}, [isVisible])
useEffect(() => {
const clickableEls = document.querySelectorAll(clickables.join(','))
clickableEls.forEach((el) => {
el.style.cursor = 'none'
el.addEventListener('mouseover', () => {
setIsActive(true)
})
el.addEventListener('click', () => {
setIsActive(true)
setIsActiveClickable(false)
})
el.addEventListener('mousedown', () => {
setIsActiveClickable(true)
})
el.addEventListener('mouseup', () => {
setIsActive(true)
})
el.addEventListener('mouseout', () => {
setIsActive(false)
setIsActiveClickable(false)
})
})
return () => {
clickableEls.forEach((el) => {
el.removeEventListener('mouseover', () => {
setIsActive(true)
})
el.removeEventListener('click', () => {
setIsActive(true)
setIsActiveClickable(false)
})
el.removeEventListener('mousedown', () => {
setIsActiveClickable(true)
})
el.removeEventListener('mouseup', () => {
setIsActive(true)
})
el.removeEventListener('mouseout', () => {
setIsActive(false)
setIsActiveClickable(false)
})
})
}
}, [isActive, clickables])
// Cursor Styles
const styles = {
cursorInner: {
zIndex: 999,
display: 'block',
position: 'fixed',
borderRadius: '50%',
width: innerSize,
height: innerSize,
pointerEvents: 'none',
backgroundColor: `rgba(${color}, 1)`,
...(innerStyle && innerStyle),
transition: 'opacity 0.15s ease-in-out, transform 0.25s ease-in-out'
},
cursorOuter: {
zIndex: 999,
display: 'block',
position: 'fixed',
borderRadius: '50%',
pointerEvents: 'none',
width: outerSize,
height: outerSize,
backgroundColor: `rgba(${color}, ${outerAlpha})`,
transition: 'opacity 0.15s ease-in-out, transform 0.15s ease-in-out',
willChange: 'transform',
...(outerStyle && outerStyle)
}
}
// Hide / Show global cursor
document.body.style.cursor = 'none'
return (
<React.Fragment>
<div ref={cursorOuterRef} style={styles.cursorOuter} />
<div ref={cursorInnerRef} style={styles.cursorInner} />
</React.Fragment>
)
}
/**
* AnimatedCursor
* Calls and passes props to CursorCore if not a touch/mobile device.
*/
function AnimatedCursor({
outerStyle,
innerStyle,
color,
outerAlpha,
innerSize,
innerScale,
outerSize,
outerScale,
trailingSpeed,
clickables
}) {
if (typeof navigator !== 'undefined' && IsDevice.any()) {
return <React.Fragment></React.Fragment>
}
return (
<CursorCore
outerStyle={outerStyle}
innerStyle={innerStyle}
color={color}
outerAlpha={outerAlpha}
innerSize={innerSize}
innerScale={innerScale}
outerSize={outerSize}
outerScale={outerScale}
trailingSpeed={trailingSpeed}
clickables={clickables}
/>
)
}
export default AnimatedCursor

21
src/hooks/withRouter.js Normal file
View file

@ -0,0 +1,21 @@
import { useLocation, useNavigate, useParams } from 'react-router-dom';
function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return (
<Component
{...props}
location={location}
params={params}
navigate={navigate}
/>
);
}
return ComponentWithRouterProp;
}
export default withRouter;

96
src/index.css Normal file
View file

@ -0,0 +1,96 @@
:root {
--bg-color: #0c0c0c;
--primary-color: #0d0d0d;
--secondary-color: #fff;
--text-color: #fff;
--text-color-2: #fff;
--text-color-3: rgb(204, 0, 0);
--overlay-color: rgb(12 12 12 / 63%);
}
[data-theme="light"] {
--bg-color: #ffffff;
--primary-color: #ffffff;
--secondary-color: #000;
--text-color: #000;
--text-color-2: #000;
--text-color-3: rgb(204, 0, 0);
--overlay-color: rgb(255 255 255 / 70%);
}
html,
body {
height: 100%;
}
body {
margin: 0;
height: 100%;
overflow-x: hidden;
overflow-y: visible;
background-color: var(--bg-color);
color: var(--text-color);
font-family: 'Raleway', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding-top: 60px;
border-left: 10px solid var(--primary-color);
border-right: 10px solid var(--primary-color);
}
ul {
list-style: none;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: Marcellus;
}
a,
a:hover {
color: var(--text-color);
}
p {
word-break: break-word;
hyphens: auto;
}
.ovhidden {
overflow: hidden;
}
.text_2,
.text_2:hover {
color: var(--text-color-2);
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}
.cursor__dot div {
z-index: 999999 !important;
}
.cursor__dot div:last-child {
background-color: var(--text-color-3) !important;
}
.cursor__dot div:first-child {
filter: invert(1);
background-color: var(--overlay-color) !important;
}
.color_pr {
color: var(--primary-color) !important;
}
.color_sec {
color: var(--secondary-color);
}

9
src/index.js Normal file
View file

@ -0,0 +1,9 @@
import React from 'react';
import ReactDOM from "react-dom/client";
import App from './app/App';
import './index.css';
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<App />
);

107
src/pages/about/index.js Normal file
View file

@ -0,0 +1,107 @@
import React from "react";
import "./style.css";
import { Helmet, HelmetProvider } from "react-helmet-async";
import { Container, Row, Col } from "react-bootstrap";
import {
dataabout,
meta,
worktimeline,
skills,
} from "../../content_option";
export const About = () => {
return (
<HelmetProvider>
<Container className="About-header">
<Helmet>
<meta charSet="utf-8" />
<title> About | {meta.title}</title>
<meta name="description" content={meta.description} />
</Helmet>
<Row className="mb-5 mt-3 pt-md-3">
<Col lg="8">
<h1 className="display-4 mb-4">About me</h1>
<hr className="t_border my-4 ml-0 text-left" />
</Col>
</Row>
<Row className="sec_sp">
<Col lg="5">
<h3 className="color_sec py-4">{dataabout.title}</h3>
</Col>
<Col lg="7" className="d-flex align-items-center">
<div>
<p>{dataabout.aboutme}</p>
</div>
</Col>
</Row>
<Row className=" sec_sp">
<Col lg="5">
<h3 className="color_sec py-4">Work Timline</h3>
</Col>
<Col lg="7">
<table className="table caption-top">
<tbody>
{worktimeline.map((data, i) => {
return (
<tr key={i}>
<th scope="row">{data.jobtitle}</th>
<td>{data.where}</td>
<td>{data.date}</td>
</tr>
);
})}
</tbody>
</table>
</Col>
</Row>
<Row className="sec_sp">
<Col lg="5">
<h3 className="color_sec py-4">Skills</h3>
</Col>
<Col lg="7">
{skills.map((data, i) => {
return (
<div key={i}>
<h3 className="progress-title">{data.name}</h3>
<div className="progress">
<div
className="progress-bar"
style={{
width: `${data.value}%`,
}}
>
<div className="progress-value">{data.value}%</div>
</div>
</div>
</div>
);
})}
</Col>
</Row>
<Row className="sec_sp">
<Col lg="5">
<h3 className="color_sec py-4">Education</h3>
</Col>
<Col lg="7">
<div>
<p>
<strong>University of Virginia, Charlottesville, VA</strong>
<br />
Bachelor of Arts, Computer Science
<br />
Expected May 2026
<br />
Cumulative GPA: 3.55/4.0
<br />
Relevant Coursework:
<br />
Data structures and algo, Computer systems and organization,
Software dev essentials
</p>
</div>
</Col>
</Row>
</Container>
</HelmetProvider>
);
};

100
src/pages/about/style.css Normal file
View file

@ -0,0 +1,100 @@
.sec_sp {
margin-bottom: calc(3rem + 5.128vw)
}
.table td,
.table th {
color: var(--text-color);
}
.t_border {
border-color: var(--text-color) !important;
}
.progress-title {
font-size: 16px;
font-weight: 700;
margin: 15px 0 20px;
font-family: 'Raleway';
}
.progress {
height: 5px;
background: var(--secondary);
border-radius: 0;
box-shadow: none;
margin-bottom: 30px;
overflow: visible;
}
.progress .progress-bar {
position: relative;
background: var(--text-color);
animation: animate-positive 2s;
overflow: visible;
opacity: 0.9;
}
.progress .progress-value {
position: absolute;
top: -30px;
right: 8px;
font-size: 17px;
font-weight: bold;
font-style: italic;
color: var(--text-color);
}
@-webkit-keyframes animate-positive {
0% {
width: 0%;
}
}
@keyframes animate-positive {
0% {
width: 0%;
}
}
.section-title {
font-size: 45px;
}
.service__title {
padding: 8px 0;
border-bottom: solid 2px var(--secondary-color);
}
.service-section .service-category-title {
padding-bottom: 4px;
}
/*! CSS Used keyframes */
@-webkit-keyframes fadeInUp {
0% {
opacity: 0;
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
}
to {
opacity: 1;
-webkit-transform: translateZ(0);
transform: translateZ(0);
}
}
@keyframes fadeInUp {
0% {
opacity: 0;
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
}
to {
opacity: 1;
-webkit-transform: translateZ(0);
transform: translateZ(0);
}
}

167
src/pages/contact/index.js Normal file
View file

@ -0,0 +1,167 @@
import React, { useState } from "react";
import * as emailjs from "emailjs-com";
import "./style.css";
import { Helmet, HelmetProvider } from "react-helmet-async";
import { meta } from "../../content_option";
import { Container, Row, Col, Alert } from "react-bootstrap";
import { contactConfig } from "../../content_option";
export const ContactUs = () => {
const [formData, setFormdata] = useState({
email: "",
name: "",
message: "",
loading: false,
show: false,
alertmessage: "",
variant: "",
});
const handleSubmit = (e) => {
e.preventDefault();
setFormdata({ loading: true });
const templateParams = {
from_name: formData.email,
user_name: formData.name,
to_name: contactConfig.YOUR_EMAIL,
message: formData.message,
};
emailjs
.send(
contactConfig.YOUR_SERVICE_ID,
contactConfig.YOUR_TEMPLATE_ID,
templateParams,
contactConfig.YOUR_USER_ID
)
.then(
(result) => {
console.log(result.text);
setFormdata({
loading: false,
alertmessage: "SUCCESS! ,Thankyou for your messege",
variant: "success",
show: true,
});
},
(error) => {
console.log(error.text);
setFormdata({
alertmessage: `Faild to send!,${error.text}`,
variant: "danger",
show: true,
});
document.getElementsByClassName("co_alert")[0].scrollIntoView();
}
);
};
const handleChange = (e) => {
setFormdata({
...formData,
[e.target.name]: e.target.value,
});
};
return (
<HelmetProvider>
<Container>
<Helmet>
<meta charSet="utf-8" />
<title>{meta.title} | Contact</title>
<meta name="description" content={meta.description} />
</Helmet>
<Row className="mb-5 mt-3 pt-md-3">
<Col lg="8">
<h1 className="display-4 mb-4">Contact Me</h1>
<hr className="t_border my-4 ml-0 text-left" />
</Col>
</Row>
<Row className="sec_sp">
<Col lg="12">
<Alert
//show={formData.show}
variant={formData.variant}
className={`rounded-0 co_alert ${
formData.show ? "d-block" : "d-none"
}`}
onClose={() => setFormdata({ show: false })}
dismissible
>
<p className="my-0">{formData.alertmessage}</p>
</Alert>
</Col>
<Col lg="5" className="mb-5">
<h3 className="color_sec py-4">Get in touch</h3>
<address>
<strong>Email:</strong>{" "}
<a href={`mailto:${contactConfig.YOUR_EMAIL}`}>
{contactConfig.YOUR_EMAIL}
</a>
<br />
<br />
{contactConfig.hasOwnProperty("YOUR_FONE") ? (
<p>
<strong>Phone:</strong> {contactConfig.YOUR_FONE}
</p>
) : (
""
)}
</address>
<p>{contactConfig.description}</p>
</Col>
<Col lg="7" className="d-flex align-items-center">
<form onSubmit={handleSubmit} className="contact__form w-100">
<Row>
<Col lg="6" className="form-group">
<input
className="form-control"
id="name"
name="name"
placeholder="Name"
value={formData.name || ""}
type="text"
required
onChange={handleChange}
/>
</Col>
<Col lg="6" className="form-group">
<input
className="form-control rounded-0"
id="email"
name="email"
placeholder="Email"
type="email"
value={formData.email || ""}
required
onChange={handleChange}
/>
</Col>
</Row>
<textarea
className="form-control rounded-0"
id="message"
name="message"
placeholder="Message"
rows="5"
value={formData.message}
onChange={handleChange}
required
></textarea>
<br />
<Row>
<Col lg="12" className="form-group">
<button className="btn ac_btn" type="submit">
{formData.loading ? "Sending..." : "Send"}
</button>
</Col>
</Row>
</form>
</Col>
</Row>
</Container>
<div className={formData.loading ? "loading-bar" : "d-none"}></div>
</HelmetProvider>
);
};

View file

@ -0,0 +1,45 @@
.contact__form .form-control {
padding: 1.375rem .75rem;
line-height: 1.5;
color: var(--text-color);
background-color: var(--bg-color);
border-radius: 0 !important;
border: 1px solid var(--secondary-color);
}
.contact__form input.form-control {
margin-bottom: 2em;
height: calc(2.5em + .75rem + 2px);
}
button.btn.ac_btn:hover {
color: var(--secondary-color);
}
.loading-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 10px;
z-index: 999999999;
background: var(--text-color);
transform: translateX(100%);
animation: shift-rightwards 1s ease-in-out infinite;
animation-delay: .3s;
}
@keyframes shift-rightwards {
0% {
transform: translateX(-100%);
}
40% {
transform: translateX(0%);
}
60% {
transform: translateX(0%);
}
100% {
transform: translateX(100%);
}
}

66
src/pages/home/index.js Normal file
View file

@ -0,0 +1,66 @@
import React from "react";
import "./style.css";
import { Helmet, HelmetProvider } from "react-helmet-async";
import Typewriter from "typewriter-effect";
import { introdata, meta } from "../../content_option";
import { Link } from "react-router-dom";
export const Home = () => {
return (
<HelmetProvider>
<section id="home" className="home">
<Helmet>
<meta charSet="utf-8" />
<title> {meta.title}</title>
<meta name="description" content={meta.description} />
</Helmet>
<div className="intro_sec d-block d-lg-flex align-items-center ">
<div
className="h_bg-image order-1 order-lg-2 h-100 "
style={{ backgroundImage: `url(/assets/images/Image%20with%20Background%20Removed.png)` }}
></div>
<div className="text order-2 order-lg-1 h-100 d-lg-flex justify-content-center">
<div className="align-self-center ">
<div className="intro mx-auto">
<h2 className="mb-1x">{introdata.title}</h2>
<h1 className="fluidz-48 mb-1x">
<Typewriter
options={{
strings: [
introdata.animated.first,
introdata.animated.second,
introdata.animated.third,
],
autoStart: true,
loop: true,
deleteSpeed: 10,
}}
/>
</h1>
<p className="mb-1x">{introdata.description}</p>
<div className="intro_btn-action pb-5">
<Link to="/portfolio" className="text_2">
<div id="button_p" className="ac_btn btn ">
My Portfolio
<div className="ring one"></div>
<div className="ring two"></div>
<div className="ring three"></div>
</div>
</Link>
<Link to="/contact">
<div id="button_h" className="ac_btn btn">
Contact Me
<div className="ring one"></div>
<div className="ring two"></div>
<div className="ring three"></div>
</div>
</Link>
</div>
</div>
</div>
</div>
</div>
</section>
</HelmetProvider>
);
};

208
src/pages/home/style.css Normal file
View file

@ -0,0 +1,208 @@
section {
flex: 1 0 auto;
position: relative;
width: 100%;
-webkit-transition: all 0.5s ease-in;
-o-transition: all 0.5s ease-in;
transition: all 0.5s ease-in;
}
.who_am_I {
font-family: Cinzel;
}
.has-first-color {
color: var(--primary-color);
}
.btn-portfolio {
background: var(--primary-color);
border-radius: 0;
}
.btn-portfolio a {
color: #000;
text-decoration: none;
}
.btn-about a {
color: var(--text-color);
text-decoration: none;
}
.intro_sec {
height: calc(100vh - 60px);
min-height: 700px;
height: 100vh;
margin-top: -60px;
}
@media (max-width: 991.98px) {
.intro_sec {
display: block;
height: auto !important;
}
}
.intro_sec .text,
.intro_sec .h_bg-image {
width: 50%;
}
@media (max-width: 991.98px) {
.intro_sec .text,
.intro_sec .h_bg-image {
width: 100%;
}
}
.intro_sec .intro {
max-width: 450px;
margin: 0 auto;
}
@media (max-width: 991.98px) {
.intro_sec .intro {
max-width: 700px;
padding-left: 20px;
padding-right: 20px;
}
}
.intro_sec .intro .feature .wrap-icon {
background: 0 0 !important;
width: auto;
height: auto;
margin-bottom: 0;
}
.intro_sec .intro .feature .wrap-icon svg {
color: #5cccc9;
}
.intro_sec .text h1 {
font-size: 30px;
margin-bottom: 50px;
font-weight: 700;
}
.intro_sec .text h3 {
font-size: 16px;
font-weight: 700;
}
.intro_sec .h_bg-image {
background-size: cover;
background-position: center 30%;
min-height: 700px;
position: relative;
max-width: 600px;
max-height: 600px;
border-radius: 20px;
overflow: hidden;
margin: 0 auto;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.ac_btn {
padding: 4px 19px;
color: var(--secondary-color);
position: relative;
border: var(--secondary-color) 2px solid;
overflow: hidden;
transition: all 0.6s cubic-bezier(0.55, 0, 0.1, 1);
cursor: pointer;
border-radius: 0;
margin-right: 20px;
}
.ac_btn a {
text-decoration: none;
}
.ac_btn:hover {
box-shadow: 8px 8px 0px var(--text-color), -8px -8px 0px var(--text-color);
}
.ac_btn:hover .one {
opacity: 1;
transform: translate3d(0px, 0px, 0px);
}
.ac_btn:hover .two {
transform: translate3d(0px, 0px, 0px);
}
.ac_btn:hover .three {
transform: translate3d(0px, 0px, 0px);
}
.ac_btn:hover .four {
transform: translate3d(0px, 0px, 0px);
}
.ac_btn .ring {
width: 100%;
height: 100%;
position: absolute;
background: transparent;
top: 0;
left: 0;
transform: translate3d(0px, 90px, 0px);
}
.ac_btn .one {
background-color: #000;
transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1);
z-index: -3;
z-index: -4;
}
.ac_btn .two {
background-color: var(--primary-color);
transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);
z-index: -3;
}
.ac_btn .three {
background-color: var(--secondary-color);
z-index: -2;
transition: all 0.7s cubic-bezier(0.55, 0, 0.1, 1);
z-index: -3;
}
#button_p {
background: var(--secondary-color);
color: var(--primary-color);
}
#button_h:hover {
color: var(--primary-color);
}
.intro_sec .h_bg-image .resume-icon {
position: absolute;
bottom: 20px;
left: 20px;
width: 50px;
height: 50px;
color: var(--text-color);
cursor: pointer;
transition: transform 0.2s ease;
}
.intro_sec .h_bg-image .resume-icon:hover {
transform: scale(1.1);
}
@media (max-width: 991.98px) {
.intro_sec .h_bg-image .resume-icon {
bottom: 10px;
left: 50%;
transform: translateX(-50%);
}
}
.intro_sec .h_bg-image {
filter: saturate(0.5);
}

View file

@ -0,0 +1,38 @@
import React from "react";
import "./style.css";
import { Helmet, HelmetProvider } from "react-helmet-async";
import { Container, Row, Col } from "react-bootstrap";
import { dataportfolio, meta } from "../../content_option";
export const Portfolio = () => {
return (
<HelmetProvider>
<Container className="About-header">
<Helmet>
<meta charSet="utf-8" />
<title> Projects | {meta.title} </title>
<meta name="description" content={meta.description} />
</Helmet>
<Row className="mb-5 mt-3 pt-md-3">
<Col lg="8">
<h1 className="display-4 mb-4"> Projects </h1>
<hr className="t_border my-4 ml-0 text-left" />
</Col>
</Row>
<div className="mb-5 project_items_ho">
{dataportfolio.map((data, i) => {
return (
<div key={i} className="project_item">
<img src={data.img} alt="" />
<div className="content">
<p>{data.description}</p>
<a href={data.link} target="_blank" rel="noopener noreferrer">View Project</a>
</div>
</div>
);
})}
</div>
</Container>
</HelmetProvider>
);
};

View file

@ -0,0 +1,82 @@
.project_items_ho {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 2rem;
}
.project_item {
width: calc(33% - 2rem);
text-align: center;
margin: 0.5rem;
position: relative;
background: var(--secondary-color);
padding: 6px;
border: 1px solid var(--secondary-color);
transition: 0.3s ease;
font-size: 0;
min-height: 300px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
@media (max-width: 768px) {
.project_item {
width: calc(50% - 2rem);
}
}
@media (max-width: 576px) {
.project_item {
width: calc(100% - 2rem);
}
}
.project_item img {
max-width: 100%;
max-height: 200px;
object-fit: cover;
}
.project_item .content {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: var(--overlay-color);
opacity: 0;
transition: opacity 0.3s ease-in-out;
padding: 10px;
box-sizing: border-box;
}
.project_item:hover .content {
opacity: 1;
}
.project_item .content p {
color: var(--text-color);
font-size: 1rem;
margin-bottom: 10px;
}
.project_item .content a {
background: var(--bg-color);
border: solid 1px var(--text-color);
padding: 4px 8px;
text-align: center;
font-size: 1rem;
color: var(--text-color);
text-decoration: none;
}
.project_item .content a:hover {
text-decoration: none;
}

13
src/reportWebVitals.js Normal file
View file

@ -0,0 +1,13 @@
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;