├── .eslintignore ├── .dockerignore ├── public ├── favicon.ico ├── static │ └── homepage.png ├── images │ ├── heroProfile.png │ └── projects │ │ ├── 3DView.webp │ │ ├── kanbanDark.webp │ │ ├── covidTracker.webp │ │ ├── jsontreeDark.webp │ │ ├── kanbanLight.webp │ │ ├── logos │ │ ├── kanban.ico │ │ ├── jsontree.ico │ │ ├── manygames.ico │ │ ├── covidtracker.ico │ │ └── stockpredictor.ico │ │ ├── covidTrackerMap.webp │ │ ├── jsontreeLight.webp │ │ ├── kanbanCardLight.webp │ │ ├── manyGames2048.webp │ │ ├── manyGamesDark.webp │ │ ├── manyGamesLight.webp │ │ ├── manyGamesPuzzle.webp │ │ ├── manyGamesWordle.webp │ │ ├── portfolioDark.webp │ │ ├── portfolioLight.webp │ │ ├── stockPredictor.webp │ │ ├── covidTrackerTable.webp │ │ ├── stockPredictorCandleChart.webp │ │ ├── stockPredictorLineChart.webp │ │ └── stockPredictorCompareChart.webp └── icons │ ├── fram.svg │ ├── prisma.svg │ ├── mui.svg │ ├── javascript.svg │ ├── typescript.svg │ ├── html.svg │ ├── css.svg │ ├── git.svg │ ├── vite.svg │ ├── solidjs.svg │ ├── tailwindcss.svg │ ├── react-router-color.svg │ ├── aws.svg │ ├── mongodb.svg │ ├── reactjs.svg │ ├── redux.svg │ ├── docker.svg │ ├── python.svg │ ├── postman.svg │ ├── nodejs.svg │ ├── graphql.svg │ ├── github.svg │ ├── vscode.svg │ ├── sass.svg │ └── postgresql.svg ├── .prettierignore ├── .husky └── pre-commit ├── postcss.config.js ├── .env.example ├── src ├── utility │ ├── classNames.ts │ ├── verifyEmail.ts │ ├── types.ts │ ├── sendMail.ts │ ├── rate-limiter.ts │ └── cursor-trail.ts ├── data │ ├── navigationRoutes.ts │ ├── siteMetaData.mjs │ ├── experience.ts │ ├── education.ts │ ├── skills.ts │ └── projects.ts ├── pages │ ├── _document.tsx │ ├── 404.tsx │ ├── _app.tsx │ ├── about.tsx │ ├── index.tsx │ ├── projects.tsx │ └── api │ │ └── sendmail.ts ├── hooks │ ├── useAutoSizeTextarea.ts │ ├── useScreenBreakpoint.ts │ └── useDebounceValue.ts ├── components │ ├── skills │ │ ├── skills-pill.tsx │ │ └── skills-showcase.tsx │ ├── utility │ │ ├── custom-input.tsx │ │ ├── custom-textarea.tsx │ │ ├── custom-toast.tsx │ │ ├── menu-button.tsx │ │ ├── theme-switch.tsx │ │ ├── mobile-menu.tsx │ │ └── corosel.tsx │ ├── cursor-trail-canvas.tsx │ ├── contact-form │ │ ├── floating-mail-button.tsx │ │ ├── contact-mail-toast.tsx │ │ ├── contact-button.tsx │ │ ├── contact-form-modal.tsx │ │ └── contact-form.tsx │ ├── experience │ │ ├── experience-showcase-list.tsx │ │ └── experience-showcase-list-item.tsx │ ├── page-transition-animation.tsx │ ├── projects │ │ ├── project-card.tsx │ │ ├── project-showcase-list.tsx │ │ └── project-showcase.tsx │ ├── landing-hero.tsx │ ├── about-hero.tsx │ ├── duotone-image.tsx │ └── icons.tsx ├── layout │ ├── main-layout.tsx │ ├── footer.tsx │ └── navbar.tsx ├── animation │ ├── fade-up.tsx │ ├── fade-right.tsx │ └── animated-logo.tsx ├── styles │ ├── globals.css │ └── theme-expamples.css └── scripts │ └── generateSitemap.mjs ├── .eslintrc.json ├── prettier.config.js ├── .gitignore ├── tsconfig.json ├── next.config.js ├── Dockerfile ├── tailwind.config.js ├── package.json └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | .next -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .next 3 | .vscode 4 | .husky -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | yarn.lock 2 | package-lock.json 3 | node_modules 4 | .next 5 | .vscode 6 | public -------------------------------------------------------------------------------- /public/static/homepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/static/homepage.png -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no-install lint-staged 5 | -------------------------------------------------------------------------------- /public/images/heroProfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/heroProfile.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/images/projects/3DView.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/3DView.webp -------------------------------------------------------------------------------- /public/images/projects/kanbanDark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/kanbanDark.webp -------------------------------------------------------------------------------- /public/images/projects/covidTracker.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/covidTracker.webp -------------------------------------------------------------------------------- /public/images/projects/jsontreeDark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/jsontreeDark.webp -------------------------------------------------------------------------------- /public/images/projects/kanbanLight.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/kanbanLight.webp -------------------------------------------------------------------------------- /public/images/projects/logos/kanban.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/logos/kanban.ico -------------------------------------------------------------------------------- /public/images/projects/covidTrackerMap.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/covidTrackerMap.webp -------------------------------------------------------------------------------- /public/images/projects/jsontreeLight.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/jsontreeLight.webp -------------------------------------------------------------------------------- /public/images/projects/kanbanCardLight.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/kanbanCardLight.webp -------------------------------------------------------------------------------- /public/images/projects/logos/jsontree.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/logos/jsontree.ico -------------------------------------------------------------------------------- /public/images/projects/logos/manygames.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/logos/manygames.ico -------------------------------------------------------------------------------- /public/images/projects/manyGames2048.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/manyGames2048.webp -------------------------------------------------------------------------------- /public/images/projects/manyGamesDark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/manyGamesDark.webp -------------------------------------------------------------------------------- /public/images/projects/manyGamesLight.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/manyGamesLight.webp -------------------------------------------------------------------------------- /public/images/projects/manyGamesPuzzle.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/manyGamesPuzzle.webp -------------------------------------------------------------------------------- /public/images/projects/manyGamesWordle.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/manyGamesWordle.webp -------------------------------------------------------------------------------- /public/images/projects/portfolioDark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/portfolioDark.webp -------------------------------------------------------------------------------- /public/images/projects/portfolioLight.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/portfolioLight.webp -------------------------------------------------------------------------------- /public/images/projects/stockPredictor.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/stockPredictor.webp -------------------------------------------------------------------------------- /public/images/projects/covidTrackerTable.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/covidTrackerTable.webp -------------------------------------------------------------------------------- /public/images/projects/logos/covidtracker.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/logos/covidtracker.ico -------------------------------------------------------------------------------- /public/images/projects/logos/stockpredictor.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/logos/stockpredictor.ico -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Create your pass for nodemailer. Follow the steps from README.md 2 | 3 | NODEMAILER_USER=xxxxxxxxx@gmail.com 4 | NODEMAILER_PASS=zxxxxxxxxxxxxxxxxxx -------------------------------------------------------------------------------- /public/images/projects/stockPredictorCandleChart.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/stockPredictorCandleChart.webp -------------------------------------------------------------------------------- /public/images/projects/stockPredictorLineChart.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/stockPredictorLineChart.webp -------------------------------------------------------------------------------- /public/images/projects/stockPredictorCompareChart.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUMBAIYA/portfolio-v2/HEAD/public/images/projects/stockPredictorCompareChart.webp -------------------------------------------------------------------------------- /public/icons/fram.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utility/classNames.ts: -------------------------------------------------------------------------------- 1 | export function classNames( 2 | ...classes: Array 3 | ): string { 4 | return classes.filter(Boolean).join(" "); 5 | } 6 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["eslint:recommended", "next/core-web-vitals", "prettier"], 3 | "plugins": ["prettier"], 4 | "rules": { 5 | "prettier/prettier": ["error", { "endOfLine": "auto" }] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: true, 3 | semi: true, 4 | singleQuote: false, 5 | trailingComma: "all", 6 | printWidth: 80, 7 | tabWidth: 2, 8 | plugins: [require("prettier-plugin-tailwindcss")], 9 | }; 10 | -------------------------------------------------------------------------------- /src/data/navigationRoutes.ts: -------------------------------------------------------------------------------- 1 | import { NavbarRoutes } from "@/layout/navbar"; 2 | 3 | export const routes: NavbarRoutes = [ 4 | { title: "Home", href: "/" }, 5 | { title: "About", href: "/about" }, 6 | { title: "Projects", href: "/projects" }, 7 | ]; 8 | -------------------------------------------------------------------------------- /src/utility/verifyEmail.ts: -------------------------------------------------------------------------------- 1 | export function verifyEmailAddress(email: string) { 2 | // This regex is not up to the standard of Google's RFC200 email regex this is a soft verification 3 | let regex = /^[^@]+@[a-zA-Z0-9._-]+\.[a-zA-Z]{1,}$/; 4 | return regex.test(email); 5 | } 6 | -------------------------------------------------------------------------------- /src/utility/types.ts: -------------------------------------------------------------------------------- 1 | import { FieldInputProps, FieldMetaProps } from "formik"; 2 | 3 | export type FormiKInputFieldProps = { 4 | field: FieldInputProps; 5 | meta: FieldMetaProps; 6 | }; 7 | 8 | export type FormikSubmitHandler = { 9 | resetForm: () => void; 10 | }; 11 | -------------------------------------------------------------------------------- /src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from "next/document"; 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | export default function PageNotFound() { 2 | return ( 3 |
4 |
5 |

404

6 | : 7 | Page not found 8 |
9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/hooks/useAutoSizeTextarea.ts: -------------------------------------------------------------------------------- 1 | import { RefObject, useEffect } from "react"; 2 | 3 | export function useAutosizeTextArea( 4 | ref: RefObject, 5 | value: string, 6 | defaultHeight: string = "auto", 7 | ) { 8 | useEffect(() => { 9 | if (ref.current) { 10 | ref.current.style.height = defaultHeight; 11 | const scrollHeight = ref.current.scrollHeight; 12 | ref.current.style.height = scrollHeight + "px"; 13 | } 14 | }, [ref, value, defaultHeight]); 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env* 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | 37 | #editor 38 | .vscode 39 | 40 | public/sitemap.xml 41 | public/robots.txt -------------------------------------------------------------------------------- /src/hooks/useScreenBreakpoint.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useState } from "react"; 2 | 3 | export function useScreenBreakpoint(breakpoint: number) { 4 | const [width, setWidth] = useState(true); 5 | 6 | const handleResize = useCallback(() => { 7 | setWidth(window.innerWidth < breakpoint); 8 | }, [breakpoint]); 9 | 10 | useEffect(() => { 11 | handleResize(); 12 | window.addEventListener("resize", handleResize); 13 | return () => { 14 | window.removeEventListener("resize", handleResize); 15 | }; 16 | }, [handleResize]); 17 | 18 | return width; 19 | } 20 | -------------------------------------------------------------------------------- /public/icons/prisma.svg: -------------------------------------------------------------------------------- 1 | 2 | file_type_light_prisma -------------------------------------------------------------------------------- /src/components/skills/skills-pill.tsx: -------------------------------------------------------------------------------- 1 | import { FC, SVGProps } from "react"; 2 | 3 | export type SkillPillProps = { 4 | name: string; 5 | icon: FC>; 6 | }; 7 | 8 | export default function SkillPill(props: SkillPillProps) { 9 | const { name, icon: Icon } = props; 10 | return ( 11 |
12 | 13 | {name} 14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/hooks/useDebounceValue.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useState } from "react"; 2 | 3 | export function useDebounceValue(value: T, wait: number) { 4 | const [_value, setValue] = useState(value); 5 | const refMounted = useRef(false); 6 | const refTimeout = useRef(); 7 | 8 | const cancel = () => window.clearTimeout(refTimeout.current); 9 | 10 | useEffect(() => { 11 | if (refMounted.current) { 12 | cancel(); 13 | refTimeout.current = window.setTimeout(() => { 14 | setValue(value); 15 | }, wait); 16 | } 17 | }, [value, wait]); 18 | 19 | useEffect(() => { 20 | refMounted.current = true; 21 | return cancel; 22 | }, []); 23 | 24 | return _value; 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "paths": { 18 | "@/*": ["./src/*"], 19 | "@/public/*": ["./public/*"] 20 | } 21 | }, 22 | "include": [ 23 | "next-env.d.ts", 24 | "**/*.ts", 25 | "**/*.tsx", 26 | "src/data/siteMetaData.mjs" 27 | ], 28 | "exclude": ["node_modules"] 29 | } 30 | -------------------------------------------------------------------------------- /src/layout/main-layout.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | 3 | import { Montserrat } from "next/font/google"; 4 | 5 | import Navbar from "@/layout/navbar"; 6 | import Footer from "@/layout/footer"; 7 | import { routes } from "@/data/navigationRoutes"; 8 | import { classNames } from "@/utility/classNames"; 9 | 10 | const montserrat = Montserrat({ 11 | subsets: ["latin"], 12 | }); 13 | 14 | export interface MainLayoutProps { 15 | children: ReactNode; 16 | } 17 | 18 | export default function MainLayout(props: MainLayoutProps) { 19 | return ( 20 | <> 21 |
22 | 23 |
{props.children}
24 |
25 |