Skip to content

Commit

Permalink
FEAT: Work experience section, disbale movements based on user prefer…
Browse files Browse the repository at this point in the history
…ence (#6)

* chore: added scroll snap on home page

* chore: added error page and updated copy on not-found page

* chore: use constants for internal links instead of hard coded values

* chore: added fade in effect for hero section

* replace blog with about

* fix: back to home link in not found page

* chore: improve fade in effect and bounce effect

* chore: disable animation if prefers-reduced-motion is set to reduce

* chore: added experice cards and replaced inter with rethink-sans

* chore: updated layout of work section, improved animation on work section

* chore: updated package version to 0.1.3

* chore: removed blog link from sitemap

---------

Co-authored-by: ArjunGTX <[email protected]>
  • Loading branch information
ArjunGTX and arjun-findr authored Dec 22, 2024
1 parent ab86378 commit bdfe528
Show file tree
Hide file tree
Showing 24 changed files with 658 additions and 238 deletions.
Binary file added images/orgs/findr.webp
Binary file not shown.
Binary file added images/orgs/patr.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 39 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "thebatproject",
"version": "0.1.2",
"version": "0.1.3",
"private": true,
"type": "module",
"scripts": {
Expand All @@ -20,6 +20,7 @@
"@tsparticles/all": "^3.7.1",
"@tsparticles/engine": "^3.7.1",
"@tsparticles/react": "^3.0.0",
"framer-motion": "^11.15.0",
"next": "15.1.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
Expand Down
27 changes: 23 additions & 4 deletions src/app/_components/BatLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
"use client";

import React, { useEffect, useState } from "react";
import React, { useEffect, useMemo, useState } from "react";
import Particles, { initParticlesEngine } from "@tsparticles/react";
import { loadAll } from "@tsparticles/all";
import { batLogoOptions } from "@/lib/tsparticles";
import { motion, useReducedMotion } from "framer-motion";
import { getBatLogoOptions } from "@/lib/tsparticles";

export const BatLogo = () => {
const [hasInitialized, setHasInitialized] = useState(false);

const reduceMotion = useReducedMotion();

const batLogoOptions = useMemo(() => {
return getBatLogoOptions(!!reduceMotion);
}, [reduceMotion]);

useEffect(() => {
(async () => {
try {
Expand All @@ -24,11 +31,23 @@ export const BatLogo = () => {

return (
hasInitialized && (
<div className="w-full flex justify-center self-center">
<motion.div
initial={{
opacity: 0,
}}
animate={{
opacity: 1,
}}
transition={{
delay: 1.5,
duration: 2.75,
}}
className="w-full flex justify-center self-center"
>
<div className="w-full">
<Particles id="tsparticles" options={batLogoOptions} />
</div>
</div>
</motion.div>
)
);
};
96 changes: 96 additions & 0 deletions src/app/_components/ExperienceCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"use client";

import { Experience } from "@/utils/experiences";
import Image from "next/image";
import React from "react";
import { motion } from "framer-motion";
import { ExperienceDescription } from "./ExperienceDescription";
import { CustomLink } from "@/components/CustomLink";

type Props = {
experience: Experience;
};

const container = {
hidden: { opacity: 0, y: 100 },
show: {
opacity: 1,
y: 0,
transition: {
staggerChildren: 0.1,
},
},
};

const item = {
hidden: { opacity: 0, y: 100 },
show: { opacity: 1, y: 0 },
};

export const ExperienceCard: React.FC<Props> = ({ experience }) => {
return (
<div className="w-full grid grid-cols-1 gap-6 md:gap-20 min-h-[66vh]">
<motion.div
variants={container}
viewport={{ once: true }}
initial="hidden"
whileInView="show"
className="flex flex-col justify-start items-start"
>
<motion.h3
viewport={{ once: true }}
variants={item}
className="text-xl lg:text-2xl xl:text-3xl mb-1 uppercase"
>
{experience.title}
</motion.h3>
<motion.p
variants={item}
viewport={{ once: true }}
className="flex text-xs lg:text-base text-secondary justify-start items-center"
>
<CustomLink
href={experience.companyLink}
target="_blank"
className="text-xs lg:text-base text-secondary hover:text-primary hover:underline"
>
{experience.company}
</CustomLink>
&nbsp;• {experience.date}
</motion.p>
<CustomLink
href={experience.imageLink}
target="_blank"
className="w-full md:w-3/4 xl:w-[80%]"
>
<motion.div
variants={item}
viewport={{ once: true }}
className="relative overflow-hidden rounded-lg aspect-[2.2/1] w-full my-2"
>
<Image
className="object-cover"
alt={experience.imageAlt}
src={experience.image}
fill
/>
</motion.div>
</CustomLink>
<motion.p
variants={item}
viewport={{ once: true }}
className="text-xs md:text-sm lg:text-lg text-secondary font-medium mt-1"
>
{experience.subheading}
</motion.p>
<ul className="w-full flex flex-col p-0 gap-2 mt-2">
{experience.descriptions.map((description, index) => (
<li className="flex" key={index}>
<ExperienceDescription description={description} index={index} />
</li>
))}
</ul>
</motion.div>
</div>
);
};
58 changes: 58 additions & 0 deletions src/app/_components/ExperienceDescription.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use client";

import {
animate,
useInView,
useMotionValue,
useTransform,
} from "framer-motion";
import React, { useEffect, useRef } from "react";
import { motion } from "framer-motion";

type Props = {
description: string;
index: number;
};

export const ExperienceDescription: React.FC<Props> = ({
description,
index,
}) => {
const descriptionRef = useRef<HTMLParagraphElement>(null);

const duration = 4;
const delay = 0.75 + duration * index;

const count = useMotionValue(0);
const rounded = useTransform(count, (latest) => Math.round(latest));
const displayText = useTransform(rounded, (latest) =>
description.slice(0, latest),
);

const isInView = useInView(descriptionRef);

useEffect(() => {
const controls = animate(count, description.length, {
type: "tween",
duration,
ease: "linear",
autoplay: false,
delay,
});
if (isInView) {
controls.play();
} else {
controls.stop();
}
return controls.stop;
}, [description.length, isInView, count, delay, duration]);

return (
<motion.p
ref={descriptionRef}
className="text-tertiary text-xs md:text-sm lg:text-base xl:text-lg leading-normal"
>
{displayText}
</motion.p>
);
};
58 changes: 44 additions & 14 deletions src/app/_components/HeroCopy.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,63 @@
"use client";

import React from "react";
import { CustomLink } from "@/components/CustomLink";
import { ExternalLinks } from "@/utils/constants";
import { motion } from "framer-motion";

const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: {
delay: 0.5,
duration: 2.5,
staggerChildren: 0.3,
},
},
};

const item = {
hidden: { opacity: 0 },
show: { opacity: 1 },
};

export const HeroCopy = () => {
return (
<div className="flex flex-col justify-start gap-6 md:gap-8 items-center text-center order-1 self-start lg:self-center lg:-order-1 lg:text-left lg:items-start">
<h1 className="text-5xl text-primary xs:text-6xl font-bebas-neue sm:text-7xl lg:text-9xl xl:text-10xl leading-none font-bold tracking-normal lg:tracking-[0.02em]">
<motion.div
variants={container}
initial="hidden"
animate="show"
className="flex flex-col justify-start gap-6 md:gap-8 items-center text-center order-1 self-start lg:self-center lg:-order-1 lg:text-left lg:items-start"
>
<motion.h1
variants={item}
className="text-5xl text-primary xs:text-6xl font-bebas-neue sm:text-7xl lg:text-9xl xl:text-10xl leading-none font-bold tracking-normal lg:tracking-[0.015em]"
>
Developer by day, <br /> Vigilante by night
</h1>
<p className="text-base text-secondary sm:text-lg xl:text-xl leading-snug">
</motion.h1>
<motion.p
variants={item}
className="text-base text-secondary sm:text-lg xl:text-xl leading-snug"
>
<i>
&ldquo;If I can&apos;t change things here,{" "}
<br className="md:hidden" /> if I can&apos;t have an effect, <br />I
don&apos;t care what happens to me.&rdquo;
</i>
</p>
<div className="flex justify-center flex-wrap items-center gap-4">
</motion.p>
<motion.div
variants={item}
className="flex justify-center flex-wrap items-center gap-4"
>
<CustomLink
variant="primary"
className="flex text-sm md:text-base flex-col justify-center items-center group w-64"
href={ExternalLinks.meeting}
target="_blank"
>
SUMMON THE KNIGHT
<small className="text-tertiary group-hover:text-secondary group-focus-visible:text-secondary">
(Schedule a call)
</small>
<small className="text-tertiary normal-case">(Schedule a call)</small>
</CustomLink>
<CustomLink
variant="primary"
Expand All @@ -34,11 +66,9 @@ export const HeroCopy = () => {
target="_blank"
>
VIGILANTE PROFILE
<small className="text-tertiary group-hover:text-secondary group-focus-visible:text-secondary">
(Download resume)
</small>
<small className="text-tertiary normal-case">(Download resume)</small>
</CustomLink>
</div>
</div>
</motion.div>
</motion.div>
);
};
5 changes: 3 additions & 2 deletions src/app/_components/HeroSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import dynamic from "next/dynamic";
import { HeroCopy } from "./HeroCopy";
import { PageSection } from "./PageSection";
import { HomePageSections } from "@/utils/constants";

const BatLogo = dynamic(
() => import("./BatLogo").then((module) => module.BatLogo),
Expand All @@ -13,8 +14,8 @@ const BatLogo = dynamic(
export const HeroSection = () => {
return (
<PageSection
id="main"
className="w-full h-svh grid grid-cols-1 overflow-x-clip pt-32 xs:pt-32 sm:pt-36 lg:pt-16 lg:grid-cols-[1fr_1.2fr] items-center gap-10 xl:gap-20"
id={HomePageSections.main}
className="w-full snap-center h-svh grid grid-cols-1 overflow-x-clip pt-32 xs:pt-32 sm:pt-36 lg:pt-16 lg:grid-cols-[1fr_1.2fr] items-center gap-10 xl:gap-20"
>
<HeroCopy />
<div className="w-full min-h-[20vh]">
Expand Down
Loading

0 comments on commit bdfe528

Please sign in to comment.