diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx
index 040955c..d80f0df 100644
--- a/src/components/ui/tooltip.tsx
+++ b/src/components/ui/tooltip.tsx
@@ -18,7 +18,7 @@ const TooltipContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
- className,
+ className
)}
{...props}
/>
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index c1f5e5c..50c109f 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -1,16 +1,78 @@
-import "@/styles/globals.css";
import type { AppProps } from "next/app";
+import Head from "next/head";
import Script from "next/script";
+import { AnimatePresence } from "framer-motion";
+
+import "@/styles/globals.css";
export default function App({ Component, pageProps }: AppProps) {
return (
<>
-
-
+
+
+
+
+
+
+
+
+ Jasper Mayone
+
+
+
+
+
+
+
+
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
>
);
}
diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx
index 29e35b1..48ea644 100644
--- a/src/pages/_document.tsx
+++ b/src/pages/_document.tsx
@@ -1,5 +1,14 @@
import { SpeedInsights } from "@vercel/speed-insights/next";
import { Head, Html, Main, NextScript } from "next/document";
+import { Metadata } from "next";
+
+export const metadata: Metadata = {
+ title: {
+ template: "%s | Jasper Mayone",
+ default: "Jasper Mayone",
+ },
+ description: "Personal Website of Jasper Mayone",
+};
export default function Document() {
return (
diff --git a/src/pages/api/email/new.tsx b/src/pages/api/email/new.tsx
index 0947c04..dc496bf 100644
--- a/src/pages/api/email/new.tsx
+++ b/src/pages/api/email/new.tsx
@@ -2,6 +2,10 @@ import arcjet, { protectSignup } from "@arcjet/next";
import { LoopsClient } from "loops";
import { NextApiRequest, NextApiResponse } from "next";
+export const config = {
+ runtime: "nodejs",
+};
+
// Arcjet setup for signup protection with multiple rules
const aj = arcjet({
key: process.env.ARCJET_KEY!,
@@ -58,7 +62,7 @@ const aj = arcjet({
export default async function handler(
req: NextApiRequest,
- res: NextApiResponse
+ res: NextApiResponse,
) {
if (req.method !== "POST") {
return res
@@ -85,7 +89,7 @@ export default async function handler(
}
// Loops client for contact creation
- const loops = new LoopsClient(process.env.LOOPS_API_KEY);
+ const loops = new LoopsClient(process.env.LOOPS_API_KEY!);
try {
const properties = {
source: "jaspermayone.com",
diff --git a/src/pages/api/friends.tsx b/src/pages/api/friends.tsx
new file mode 100644
index 0000000..c1a29e2
--- /dev/null
+++ b/src/pages/api/friends.tsx
@@ -0,0 +1,150 @@
+type Friend = {
+ name: string;
+ bio: string;
+ // image_name: string;
+ link: string;
+};
+
+/*
+ Aarya Narula - https://github.com/radioblahaj
+ Alex Deforest - https://defo.one
+ Aram Shiva - https://aram.sh/
+ Ben Dixon - https://malted.dev
+ Cisco Wallace-Hurtado - https://jaspermayone.com/404
+ Deven Jadhav - https://devenjadhav.com/
+ Ian Madden - https://github.com/YodaLightsabr
+ Kieran Klukas - https://kieranklukas.com/
+ Luke Oldenburg - https://github.com/Luke-Oldenburg
+ Manitej Boorgu - https://github.com/techpixel
+ Milo Heintz - https://www.instagram.com/milo_heintz
+ Reese Armstrong - https://reeseric.ci/
+ Rhys Panopio - https://www.linkedin.com/in/rhys-panopio/
+ Robert Goll - https://rgoll.com/
+ Ryan Di Lorenzo - https://github.com/LimesKey
+ Ryan Rudes - https://ryanrudes.com/
+ Samuel Fernandez - https://sfernandez.dev/
+ Sam Poder - https://sampoder.com/
+ Ruien Luo - https://rluo.dev/
+ Samantha Miel - https://www.instagram.com/cirque_du_samantha/
+ Théo Reid - https://www.instagram.com/theointheair/
+*/
+
+const friends: Friend[] = [
+ {
+ name: "Aarya Narula",
+ bio: "INSERT BIO SOON",
+ link: "https://github.com/radioblahaj",
+ },
+ {
+ name: "Alex Deforest",
+ bio: "INSERT BIO SOON",
+ link: "https://defo.one",
+ },
+ {
+ name: "Aram Shiva",
+ bio: "INSERT BIO SOON",
+ link: "https://aram.sh/",
+ },
+ {
+ name: "Ben Dixon",
+ bio: "INSERT BIO SOON",
+ link: "https://malted.dev",
+ },
+ {
+ name: "Cisco Wallace-Hurtado",
+ bio: "INSERT BIO SOON",
+ link: "https://jaspermayone.com/404",
+ },
+ {
+ name: "Deven Jadhav",
+ bio: "INSERT BIO SOON",
+ link: "https://devenjadhav.com/",
+ },
+ {
+ name: "Ian Madden",
+ bio: "INSERT BIO SOON",
+ link: "https://github.com/YodaLightsabr",
+ },
+ {
+ name: "Kieran Klukas",
+ bio: "INSERT BIO SOON",
+ link: "https://kieranklukas.com/",
+ },
+ {
+ name: "Luke Oldenburg",
+ bio: "INSERT BIO SOON",
+ link: "https://github.com/Luke-Oldenburg",
+ },
+ {
+ name: "Manitej Boorgu",
+ bio: "INSERT BIO SOON",
+ link: "https://github.com/techpixel",
+ },
+ {
+ name: "Milo Heintz",
+ bio: "INSERT BIO SOON",
+ link: "https://www.instagram.com/milo_heintz",
+ },
+ {
+ name: "Reese Armstrong",
+ bio: "INSERT BIO SOON",
+ link: "https://reeseric.ci/",
+ },
+ {
+ name: "Rhys Panopio",
+ bio: "INSERT BIO SOON",
+ link: "https://www.linkedin.com/in/rhys-panopio/",
+ },
+ {
+ name: "Robert Goll",
+ bio: "INSERT BIO SOON",
+ link: "https://rgoll.com/",
+ },
+ {
+ name: "Ryan Di Lorenzo",
+ bio: "INSERT BIO SOON",
+ link: "https://github.com/LimesKey",
+ },
+ {
+ name: "Ryan Rudes",
+ bio: "INSERT BIO SOON",
+ link: "https://ryanrudes.com/",
+ },
+ {
+ name: "Samuel Fernandez",
+ bio: "INSERT BIO SOON",
+ link: "https://sfernandez.dev/",
+ },
+ {
+ name: "Sam Poder",
+ bio: "INSERT BIO SOON",
+ link: "https://sampoder.com/",
+ },
+ {
+ name: "Samantha Miel",
+ bio: "INSERT BIO SOON",
+ link: "https://www.instagram.com/cirque_du_samantha/",
+ },
+ {
+ name: "Théo Reid",
+ bio: "INSERT BIO SOON",
+ link: "https://www.instagram.com/theointheair/",
+ },
+ {
+ name: "Ruien Luo",
+ bio: "INSERT BIO SOON",
+ link: "https://rluo.dev/",
+ },
+];
+
+export default function handler(req: any, res: any) {
+ let rjson = friends;
+
+ // modify the json to include a "file_name" property. this should be the name of the person with spaces replaced with underscores and all lowercase. Add .jpg to the end of the file name
+ let mjson = rjson.map((friend) => {
+ let file_name = friend.name.replace(/ /g, "_").toLowerCase() + ".png";
+ return { ...friend, file_name };
+ });
+
+ res.status(200).json(mjson);
+}
diff --git a/src/pages/api/imagecount.ts b/src/pages/api/imagecount.ts
deleted file mode 100644
index 50e88a0..0000000
--- a/src/pages/api/imagecount.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import fs from "fs";
-import path from "path";
-
-export default function handler(req, res) {
- const imagesDirectory = path.join(process.cwd(), "public/images");
- fs.readdir(imagesDirectory, (err, files) => {
- if (err) {
- return res.status(500).json({ error: "Failed to read directory" });
- }
-
- const imageCount = files.filter((file) => file.endsWith(".jpg")).length;
- res.status(200).json({ count: imageCount });
- });
-}
diff --git a/src/pages/api/photos.tsx b/src/pages/api/photos.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/pages/friends/index.tsx b/src/pages/friends/index.tsx
new file mode 100644
index 0000000..fd102a8
--- /dev/null
+++ b/src/pages/friends/index.tsx
@@ -0,0 +1,91 @@
+import { Suspense, useEffect, useMemo, useState } from "react";
+import { ParallaxScroll } from "@/components/ui/friends";
+import DotsBackground from "@/components/DotsBackground";
+
+/*
+ Ben Dixon - https://malted.dev
+ Aram Shiva - https://aram.sh/
+ Sam Poder - https://sampoder.com/
+ Deven Jadhav - https://devenjadhav.com/
+ Aarya - https://github.com/radioblahaj
+ Alex Deforest - https://defo.one
+ Manitej - https://github.com/techpixel
+ Ruien Luo - https://rluo.dev/
+ Reese Armstrong - https://reeseric.ci/
+ Rhys Panopio - https://www.linkedin.com/in/rhys-panopio/
+ Ian Madden - https://github.com/YodaLightsabr
+ Kieran - https://kieranklukas.com/
+ Ryan Di Lorenzo - https://github.com/LimesKey
+ Samuel F. - https://sfernandez.dev/
+ Luke O - https://github.com/Luke-Oldenburg
+ Ryan Rudes - https://ryanrudes.com/
+*/
+
+function shuffleArray(array: T[]): T[] {
+ let currentIndex = array.length,
+ randomIndex;
+
+ // While there remain elements to shuffle...
+ while (currentIndex !== 0) {
+ // Pick a remaining element...
+ randomIndex = Math.floor(Math.random() * currentIndex);
+ currentIndex--;
+
+ // And swap it with the current element.
+ [array[currentIndex], array[randomIndex]] = [
+ array[randomIndex],
+ array[currentIndex],
+ ];
+ }
+
+ return array;
+}
+
+// Create a fallback component for Suspense loading state
+function LoadingFallback() {
+ return
Loading...
;
+}
+
+export default function Friends() {
+ const [friends, setFriends] = useState([]);
+
+ useEffect(() => {
+ const fetchFriends = async () => {
+ const response = await fetch("/api/friends");
+ const data = await response.json();
+ setFriends(data); // Store the friends data
+ };
+
+ fetchFriends();
+ }, []);
+
+ const staticFriends = useMemo(() => {
+ const shuffledFriends = shuffleArray(
+ friends.map((friend) => ({
+ ...friend,
+ image: `/images/friends/${friend.file_name}`,
+ })),
+ );
+ return [
+ {
+ name: "I have some super cool friends, check them all out! 🌟 (btw, shoot me a message if you want to be added here, I definitely missed some people lol.)",
+ type: "text", // Define it as text to handle separately in the parallax scroll
+ },
+ ...shuffledFriends,
+ ];
+ }, [friends]);
+
+ return (
+ <>
+
+
+ {/* Friends Parallax Scroll with Suspense */}
+
+ }>
+
+
+
+
+ >
+ );
+}
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 60fca9b..d38893e 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,81 +1,269 @@
-import Email from "@/components/email";
-import Experience from "@/components/experience";
-import Header from "@/components/header";
+import { useState, useEffect } from "react";
import { motion } from "framer-motion";
-import Image from "next/image";
import Link from "next/link";
+import Email from "@/components/email";
+import DotsBackground from "@/components/DotsBackground";
+import styles from "@/styles/Home.module.css";
+import CommitHash from "@/components/helpers/commitHash";
+import {
+ SiDevdotto,
+ SiGithub,
+ SiInstagram,
+ SiLinkedin,
+ SiThreads,
+ SiX,
+} from "react-icons/si";
+import Experience from "@/components/experience";
+
+/* Reference https://nextjs.org/learn/dashboard-app/adding-metadata when adding new metadata. */
export default function Home() {
- return (
- <>
-
-
-
-
-
-
-
-
-
- Jasper Mayone{" "} (he/they) {" "}
-
- is a 17-year-old high school student from Vermont. They are a circus
- performer, a{" "}
+ const [selectedTab, setSelectedTab] = useState("Homepage");
+
+ const menuItems = [
+ "Homepage",
+ // "Portfolio",
+ "Resume",
+ "Photos",
+ "@jasperdoescircus",
+ ];
+
+ const fadeVariants = {
+ hidden: { opacity: 0 },
+ visible: { opacity: 1 },
+ exit: { opacity: 0 },
+ };
+
+ useEffect(() => {
+ console.log(
+ "%cWOWY! A real life developer or code enthusiast? I'm so glad you're here! \nI'm GitHub at @jaspermayone! \nIf you're interested in circus arts, photography, or just want to chat, feel free to reach out to me at me@jaspermayone.com. \nI can't wait to meet you!",
+ "background: #222; color: #bada55",
+ );
+ }, []);
+
+ const renderContent = () => {
+ switch (selectedTab) {
+ case "Homepage":
+ return (
+ <>
+
+ Jasper Mayone (he/they){" "}
+
+ is a 17-year-old high school student from Vermont. They are a
+ circus performer, a{" "}
coder
, and a{" "}
-
+
photographer
.
-
- A circus artist and a native Vermonter, Jasper is a high school graduate from the class of 2024!
- Graduating a full year early, they are currently taking a gap year to explore.
- Jasper tries to live by the quote “We’ve all got both light and dark inside us.
- What matters is the part we choose to act on...that’s who we really are.” from one of their favorite books, Harry Potter.
- Jasper’s hobbies include reading, being in the great outdoors, photography, computer programming, cooking,
- and running away to join the circus.
+
+ A circus artist and a native Vermonter, Jasper is a high school
+ graduate from the class of 2024! Graduating a full year early,
+ they are currently taking a gap year to explore. Jasper tries to
+ live by the quote “We’ve all got both light and dark inside us.
+ What matters is the part we choose to act on...that’s who we
+ really are.” from one of their favorite books, Harry Potter.
+ Jasper’s hobbies include reading, being in the great outdoors,
+ photography, computer programming, cooking, and running away to
+ join the circus.