├── .eslintrc.json ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── app ├── [...not_found] │ └── page.tsx ├── about-section │ ├── About.tsx │ ├── SongCard.tsx │ ├── SongCarousel.tsx │ └── songDetails.ts ├── animations │ ├── AnimatedBody.tsx │ ├── AnimatedTitle.tsx │ ├── AnimatedWords.tsx │ ├── AnimatedWords2.tsx │ ├── PreLoader │ │ ├── PreLoader.tsx │ │ ├── loader.js │ │ └── preloader.css │ ├── animate.css │ └── animations.tsx ├── api │ └── hello │ │ └── route.js ├── blog-section │ ├── BlogCard.tsx │ ├── BlogGrid.tsx │ └── blogDetails.ts ├── contact-section │ └── Contact.tsx ├── fonts │ ├── Mona-Sans-BlackNarrow.woff2 │ ├── Mona-Sans-BlackNarrowItalic.woff2 │ ├── Mona-Sans-BoldNarrow.woff2 │ ├── Mona-Sans-BoldNarrowItalic.woff2 │ ├── Mona-Sans-ExtraBoldNarrow.woff2 │ ├── Mona-Sans-LightNarrow.woff2 │ ├── Mona-Sans-LightNarrowItalic.woff2 │ ├── Mona-Sans-MediumNarrow.woff2 │ ├── Mona-Sans-MediumNarrowItalic.woff2 │ ├── Mona-Sans-RegularNarrowItalic.woff2 │ ├── Mona-Sans-SemiBoldNarrow.woff2 │ ├── Mona-Sans-SemiBoldNarrowItalic.woff2 │ ├── Mona-Sans-UltraLightNarrow.woff2 │ └── monaSans.ts ├── footer │ └── Footer.tsx ├── globals.css ├── hero-section │ └── Hero.tsx ├── layout.tsx ├── navbar │ └── NavBar.tsx ├── not-found.tsx ├── page.module.css ├── page.tsx ├── reviews-section │ ├── ReviewCard.tsx │ ├── ReviewGrid.tsx │ └── reviewDetails.ts ├── utils │ └── BlobityConfig.tsx └── work-section │ ├── ProjectCard.tsx │ ├── ProjectGrid.tsx │ ├── Work.tsx │ └── projectDetails.ts ├── jsconfig.json ├── next-env.d.ts ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── alan.jpeg ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── heart icon.png ├── hero.jpg ├── hero.webp ├── hiremeoncontra-dark.webp ├── jerry.avif ├── mauro.jpeg ├── olamide.jpeg ├── profile.webp ├── projects │ ├── alpaca-flip.png │ ├── alpaca-new.webp │ ├── carpool-new.webp │ ├── crown.webp │ ├── flixify-flip.png │ ├── flixify-new.png │ ├── flixify.png │ ├── hsl.webp │ ├── interlock-flip.png │ ├── interlock-flip2.png │ ├── interlock-new-flip.png │ ├── interlock-new.png │ ├── interlock.png │ ├── mlsc.png │ ├── odunsi-flip.png │ ├── odunsi-mobile.png │ ├── odunsi.png │ ├── propellent-new-flip.png │ ├── propellent-new.png │ ├── propellent.png │ ├── rags.webp │ ├── shortener-new.webp │ ├── skywatch-flip.png │ ├── skywatch-new.webp │ ├── synthetix-flip.png │ ├── synthetix.png │ └── titi.webp ├── review-slash.svg ├── samuel.avif ├── site.webmanifest ├── songs │ ├── 22-double-0.jpg │ ├── care.jpg │ ├── floods.jpg │ ├── glitter.jpg │ ├── lemme-land.jpg │ ├── let-me-go.jpg │ ├── lie-again.jpeg │ ├── martins-sofa.jpg │ ├── nice-and-good.jpg │ └── one-up.png └── umar.jpeg ├── tailwind.config.js └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.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 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | .vercel 35 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules\\typescript\\lib", 3 | "typescript.enablePromptUseWorkspaceTsdk": true 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Personal Portfolio Website — v1 2 | 3 | My name is Victor Williams, and I’m a front-end engineer and web designer based in Lagos, Nigeria. My passion lies in creating software that solves real-world problems and positively impacts people’s lives. 4 | 5 | I created this website to showcase my work. I’m always striving to create something unique and innovative. I love experimenting with new technologies and staying up-to-date with the latest trends in the tech world. 6 | 7 | ## Tech Stack 8 | 9 | **Client:** React, Next.js, TypeScript, TailwindCSS, Framer Motion, GSAP. 10 | 11 | **Hosting:** Vercel. 12 | 13 | ## Screenshots & Demo 14 | 15 | ![App Screenshot](https://user-images.githubusercontent.com/84178696/228679118-47e63775-0635-42b2-8838-a80644ef612b.png) 16 | 17 | ![App Screenshot](https://user-images.githubusercontent.com/84178696/228673498-ad33b834-58b3-43e5-b184-b136d01c6e1a.png) 18 | 19 | ![App Screenshot](https://user-images.githubusercontent.com/84178696/228675919-70180c2c-c888-423d-ae85-409ce4645b8b.png) 20 | 21 | [View Live Demo](https://folio-v1-victorcodess.vercel.app/) 22 | 23 | ## Run Locally 24 | 25 | Clone the project 26 | 27 | ```bash 28 | git clone https://github.com/victorcodess/folio-v1 29 | ``` 30 | 31 | Go to the project directory 32 | 33 | ```bash 34 | cd folio-v1 35 | ``` 36 | 37 | Install dependencies 38 | 39 | ```bash 40 | npm install 41 | ``` 42 | 43 | Start the server 44 | 45 | ```bash 46 | npm run dev 47 | ``` 48 | 49 | ## Contributing & Usage 50 | 51 | This project is open source, and you are welcome to use the code or parts of the code for your own site. I encourage you to modify the theme and components to make it your own. However, please do not present any of the projects featured on this site as your own. The content of this portfolio is personal and represents real projects I’ve worked on. 52 | 53 | If you are using the site’s design largely unmodified, please credit me as the designer of the website. 54 | 55 | Incase you have any questions or concerns, please feel free to reach out to me on [Twitter.](https://twitter.com/victorwill__) I am always happy to help! 56 | 57 | 58 | ## Feedback 59 | 60 | While I would not be accepting contributions or pull requests at this time, I appreciate your feedback on this project. If you have any suggestions or questions, please don’t hesitate to reach out to me on [Twitter.](https://twitter.com/victorwill__) Your feedback is valuable and will help me improve. 61 | 62 | ## License 63 | 64 | [MIT](https://choosealicense.com/licenses/mit/) 65 | -------------------------------------------------------------------------------- /app/[...not_found]/page.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | import {notFound} from "next/navigation" 3 | 4 | export default function NotFoundCatchAll() { 5 | notFound() 6 | return null 7 | } -------------------------------------------------------------------------------- /app/about-section/About.tsx: -------------------------------------------------------------------------------- 1 | import SongCarousel from "./SongCarousel"; 2 | import "../animations/animate.css"; 3 | import AnimatedBody from "../animations/AnimatedBody"; 4 | import AnimatedTitle from "../animations/AnimatedTitle"; 5 | 6 | const About = () => { 7 | return ( 8 |
12 |
13 | 23 | 24 |
25 |
26 | 31 | 37 | 42 | 47 | 52 |
53 | 54 |
55 |
56 | 64 | 69 |
70 |
71 | 79 | 84 |
85 |
86 | 94 | 99 |
100 |
101 |
102 |
103 | 104 | 108 |
109 |
110 |
111 | ); 112 | }; 113 | 114 | export default About; 115 | -------------------------------------------------------------------------------- /app/about-section/SongCard.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import { SongProps } from "./songDetails"; 3 | import Link from "next/link"; 4 | 5 | const SongCard = ({ title, artist, image, link }: SongProps) => { 6 | return ( 7 | 8 |
11 | {title} 16 |
17 | 18 |
19 |

{artist}

20 |

{title}

21 |
22 |
23 | 24 | ); 25 | }; 26 | 27 | export default SongCard; 28 | -------------------------------------------------------------------------------- /app/about-section/SongCarousel.tsx: -------------------------------------------------------------------------------- 1 | import SongCard from "./SongCard"; 2 | import { songs, SongProps } from "./songDetails"; 3 | import "../animations/animate.css"; 4 | 5 | const SongCarousel = () => { 6 | return ( 7 |
8 |
9 | {songs.map((song: SongProps, index) => ( 10 | 17 | ))} 18 |
19 |
20 | {songs.map((song: SongProps, index) => ( 21 | 28 | ))} 29 |
30 |
31 | ); 32 | }; 33 | 34 | export default SongCarousel; 35 | -------------------------------------------------------------------------------- /app/about-section/songDetails.ts: -------------------------------------------------------------------------------- 1 | export type SongProps = { 2 | title: string; 3 | artist: string; 4 | image: string; 5 | link: string; 6 | }; 7 | 8 | export const songs = [ 9 | { 10 | title: "Lie Again", 11 | artist: "Giveon", 12 | image: require(".//../../public/songs/lie-again.jpeg"), 13 | link: "https://open.spotify.com/album/11q4Tt1RzwrFzF2Vddc2yO", 14 | }, 15 | { 16 | title: "Martin's Sofa", 17 | artist: "Headie One", 18 | image: require(".//../../public/songs/martins-sofa.jpg"), 19 | link: "https://open.spotify.com/album/5ywIBJnydB9IMqgg0XDU6O", 20 | }, 21 | { 22 | title: "Let Me Go", 23 | artist: "Daniel Ceasar", 24 | image: require(".//../../public/songs/let-me-go.jpg"), 25 | link: "https://open.spotify.com/track/4AwJSk491AvHk2AAJReGzZ", 26 | }, 27 | { 28 | title: "One Up", 29 | artist: "Central Cee", 30 | image: require(".//../../public/songs/one-up.png"), 31 | link: "https://open.spotify.com/album/51A9bnCs9oq6vjFZIDza97", 32 | }, 33 | { 34 | title: "Glitter", 35 | artist: "BENEE", 36 | image: require(".//../../public/songs/glitter.jpg"), 37 | link: "https://open.spotify.com/track/23TPP1eeElFfvYVznskwCY", 38 | }, 39 | { 40 | title: "Lemme Land?", 41 | artist: "Canking, Ess2Mad", 42 | image: require(".//../../public/songs/lemme-land.jpg"), 43 | link: "https://open.spotify.com/track/4Fmr4dbY1sZiX77ZbljNFC", 44 | }, 45 | { 46 | title: "Floods", 47 | artist: "Lucky Daye", 48 | image: require(".//../../public/songs/floods.jpg"), 49 | link: "https://open.spotify.com/track/4GBjdj1z74h8RVr1Us6YFc", 50 | }, 51 | { 52 | title: "Nice & Good", 53 | artist: "SL, Knucks", 54 | image: require(".//../../public/songs/nice-and-good.jpg"), 55 | link: "https://open.spotify.com/album/2nZHGm0LbyWb9SQ48RWFdO", 56 | }, 57 | { 58 | title: "Care", 59 | artist: "Sonder", 60 | image: require(".//../../public/songs/care.jpg"), 61 | link: "https://open.spotify.com/track/3tkxfORwPo2zydAf25YFOc", 62 | }, 63 | { 64 | title: "22 Double 0", 65 | artist: "Unknown T", 66 | image: require(".//../../public/songs/22-double-0.jpg"), 67 | link: "https://open.spotify.com/track/0L0sXaqVYGpvXWcikG6zlk", 68 | }, 69 | ]; 70 | -------------------------------------------------------------------------------- /app/animations/AnimatedBody.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useAnimation, motion } from "framer-motion"; 3 | import { useInView } from "react-intersection-observer"; 4 | 5 | type AnimatedBodyProps = { 6 | text: string; 7 | className?: string; 8 | wordSpace?: string; 9 | charSpace?: string; 10 | }; 11 | 12 | export default function AnimatedBody({ 13 | text, 14 | className, 15 | wordSpace, 16 | charSpace, 17 | }: AnimatedBodyProps) { 18 | // const text = "Animated Text"; // This would normally be passed into this component as a prop! 19 | 20 | const ctrls = useAnimation(); 21 | 22 | const { ref, inView } = useInView({ 23 | threshold: 0.1, 24 | triggerOnce: true, 25 | }); 26 | 27 | useEffect(() => { 28 | if (inView) { 29 | ctrls.start("visible"); 30 | } 31 | if (!inView) { 32 | ctrls.start("hidden"); 33 | } 34 | }, [ctrls, inView]); 35 | 36 | const wordAnimation = { 37 | hidden: {}, 38 | visible: {}, 39 | }; 40 | 41 | const bodyAnimation = { 42 | hidden: { 43 | opacity: 0, 44 | y: `1em`, 45 | }, 46 | visible: { 47 | opacity: 1, 48 | y: `0em`, 49 | transition: { 50 | delay: 0.1, 51 | duration: 1, 52 | ease: [0.2, 0.65, 0.3, 0.9], 53 | }, 54 | }, 55 | }; 56 | 57 | return ( 58 | 70 | ); 71 | } 72 | -------------------------------------------------------------------------------- /app/animations/AnimatedTitle.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useAnimation, motion } from "framer-motion"; 3 | import { useInView } from "react-intersection-observer"; 4 | 5 | type AnimatedTitleProps = { 6 | text: string; 7 | className: string; 8 | wordSpace: string; 9 | charSpace: string; 10 | delay?: number; 11 | }; 12 | 13 | export default function AnimatedTitle({ 14 | text, 15 | className, 16 | wordSpace, 17 | charSpace, 18 | }: AnimatedTitleProps) { 19 | // const text = "Animated Text"; // This would normally be passed into this component as a prop! 20 | 21 | const ctrls = useAnimation(); 22 | 23 | const { ref, inView } = useInView({ 24 | threshold: 0.1, 25 | triggerOnce: true, 26 | }); 27 | 28 | useEffect(() => { 29 | if (inView) { 30 | ctrls.start("visible"); 31 | } 32 | if (!inView) { 33 | ctrls.start("hidden"); 34 | } 35 | }, [ctrls, inView]); 36 | 37 | const wordAnimation = { 38 | hidden: {}, 39 | visible: {}, 40 | }; 41 | 42 | const characterAnimation = { 43 | hidden: { 44 | opacity: 0, 45 | y: `0.25em`, 46 | }, 47 | visible: { 48 | opacity: 1, 49 | y: `0em`, 50 | transition: { 51 | duration: 1, 52 | ease: [0.2, 0.65, 0.3, 0.9], 53 | }, 54 | }, 55 | }; 56 | 57 | return ( 58 |

59 | {text.split(" ").map((word, index) => { 60 | return ( 61 | 87 | ); 88 | })} 89 |

90 | ); 91 | } 92 | -------------------------------------------------------------------------------- /app/animations/AnimatedWords.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import { useEffect } from "react"; 3 | import { useAnimation } from "framer-motion"; 4 | import { useInView } from "react-intersection-observer"; 5 | 6 | type AnimatedWordsProps = { 7 | title: string; 8 | style: string; 9 | }; 10 | 11 | const AnimatedWords: React.FC = ({ title, style }) => { 12 | const ctrls = useAnimation(); 13 | 14 | const { ref, inView } = useInView({ 15 | threshold: 0.1, 16 | triggerOnce: true, 17 | }); 18 | 19 | useEffect(() => { 20 | if (inView) { 21 | ctrls.start("animate"); 22 | } 23 | if (!inView) { 24 | ctrls.start("initial"); 25 | } 26 | }, [ctrls, inView]); 27 | 28 | const wordAnimation = { 29 | initial: { 30 | opacity: 0, 31 | y: 150, 32 | // y: 100, 33 | }, 34 | animate: { 35 | opacity: 1, 36 | y: 0, 37 | transition: { 38 | delay: 6, 39 | ease: [0.2, 0.65, 0.3, 0.9], 40 | duration: 1, 41 | }, 42 | }, 43 | }; 44 | 45 | const staggerChildren = { 46 | animate: { 47 | transition: { 48 | delayChildren: 0.4, 49 | staggerChildren: 0.1, 50 | }, 51 | }, 52 | }; 53 | 54 | return ( 55 |

56 | 60 | {title.split(" ").map((word, index) => ( 61 | 72 | 73 | {word + "\u00A0"} 74 | 75 | 76 | ))} 77 | 78 |

79 | ); 80 | }; 81 | 82 | export default AnimatedWords; 83 | -------------------------------------------------------------------------------- /app/animations/AnimatedWords2.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import { useEffect } from "react"; 3 | import { useAnimation } from "framer-motion"; 4 | import { useInView } from "react-intersection-observer"; 5 | 6 | type AnimatedWords2Props = { 7 | title: string; 8 | style: string; 9 | }; 10 | 11 | const AnimatedWords2: React.FC = ({ title, style }) => { 12 | const ctrls = useAnimation(); 13 | 14 | const { ref, inView } = useInView({ 15 | threshold: 0.5, 16 | triggerOnce: true, 17 | }); 18 | 19 | useEffect(() => { 20 | if (inView) { 21 | ctrls.start("animate"); 22 | } 23 | if (!inView) { 24 | ctrls.start("initial"); 25 | } 26 | }, [ctrls, inView]); 27 | 28 | const wordAnimation2 = { 29 | initial: { 30 | opacity: 0, 31 | y: 150, 32 | }, 33 | animate: { 34 | opacity: 1, 35 | y: 0, 36 | transition: { 37 | // delay: 1, 38 | ease: [0.2, 0.65, 0.3, 0.9], 39 | duration: 0.8, 40 | }, 41 | }, 42 | }; 43 | 44 | return ( 45 |

46 | 47 | {title.split(" ").map((word, index) => ( 48 | 58 | 62 | {word + "\u00A0"} 63 | 64 | 65 | ))} 66 | 67 |

68 | ); 69 | }; 70 | 71 | export default AnimatedWords2; 72 | -------------------------------------------------------------------------------- /app/animations/PreLoader/PreLoader.tsx: -------------------------------------------------------------------------------- 1 | "use cleint"; 2 | import { useEffect } from "react"; 3 | import { preLoaderAnim } from "./loader"; 4 | import "./preloader.css"; 5 | 6 | const PreLoader = () => { 7 | useEffect(() => { 8 | preLoaderAnim(); 9 | }, []); 10 | 11 | return ( 12 |
13 |
14 | Developer, 15 | Designer, 16 | Driller. 17 |
18 |
19 |
20 | ); 21 | }; 22 | 23 | export default PreLoader; 24 | -------------------------------------------------------------------------------- /app/animations/PreLoader/loader.js: -------------------------------------------------------------------------------- 1 | import gsap from "gsap"; 2 | 3 | // Declare a general timeline to use in all the animation functions. 4 | 5 | const tl = gsap.timeline(); 6 | 7 | // Preloader Animation 8 | export const preLoaderAnim = () => { 9 | tl.to(".texts-container", { 10 | duration: 0, 11 | opacity: 1, 12 | ease: "Power3.easeOut", 13 | }) 14 | .from(".texts-container span", { 15 | duration: 1.5, 16 | delay: 1, 17 | y: 70, 18 | skewY: 10, 19 | stagger: 0.4, 20 | ease: "Power3.easeOut", 21 | }) 22 | .to(".texts-container span", { 23 | duration: 1, 24 | y: 70, 25 | skewY: -20, 26 | stagger: 0.2, 27 | ease: "Power3.easeOut", 28 | }) 29 | .to("body", { 30 | duration: 0.01, 31 | css: { overflowY: "scroll" }, 32 | ease: "power3.inOut", 33 | }) 34 | .from(".sub", { 35 | duration: 1, 36 | opacity: 0, 37 | y: 80, 38 | ease: "expo.easeOut", 39 | }) 40 | .to( 41 | ".preloader", 42 | { 43 | duration: 1.5, 44 | height: "0vh", 45 | ease: "Power3.easeOut", 46 | onComplete: mobileLanding(), 47 | }, 48 | "-=2" 49 | ) 50 | .to(".preloader", { 51 | duration: 0, 52 | css: { display: "none" }, 53 | }); 54 | }; 55 | 56 | export const mobileLanding = () => { 57 | window.innerWidth < 763 && 58 | tl.from(".landing__main2", { 59 | duration: 1, 60 | delay: 0, 61 | opacity: 0, 62 | y: 80, 63 | ease: "expo.easeOut", 64 | }); 65 | }; 66 | -------------------------------------------------------------------------------- /app/animations/PreLoader/preloader.css: -------------------------------------------------------------------------------- 1 | .preloader { 2 | height: 100vh; 3 | width: 100%; 4 | background: #0e1016; 5 | color: #e4ded7; 6 | position: fixed; 7 | bottom: 0; 8 | left: 0; 9 | right: 0; 10 | z-index: 55; 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | overflow: hidden !important; 15 | } 16 | 17 | .preloader .texts-container { 18 | height: 60px; 19 | } 20 | -------------------------------------------------------------------------------- /app/animations/animate.css: -------------------------------------------------------------------------------- 1 | @keyframes marquee { 2 | 0% { 3 | left: 0; 4 | } 5 | 100% { 6 | left: -550%; 7 | } 8 | } 9 | .animate { 10 | animation: marquee 20s linear infinite; 11 | transform: translate(0, -50%); 12 | } 13 | 14 | .animate:hover { 15 | animation-play-state: paused; 16 | } 17 | 18 | @screen sm { 19 | @keyframes marquee { 20 | 0% { 21 | left: 0; 22 | } 23 | 100% { 24 | left: -340%; 25 | } 26 | } 27 | .animate { 28 | animation: marquee 20s linear infinite; 29 | transform: translate(0, -50%); 30 | } 31 | } 32 | 33 | @screen md { 34 | @keyframes marquee { 35 | 0% { 36 | left: 0; 37 | } 38 | 100% { 39 | left: -355%; 40 | } 41 | } 42 | .animate { 43 | animation: marquee 20s linear infinite; 44 | transform: translate(0, -50%); 45 | } 46 | } 47 | 48 | @screen lg { 49 | @keyframes marquee { 50 | 0% { 51 | left: 0; 52 | } 53 | 100% { 54 | left: -300%; 55 | } 56 | } 57 | .animate { 58 | animation: marquee 20s linear infinite; 59 | transform: translate(0, -50%); 60 | } 61 | } 62 | 63 | @screen xl { 64 | @keyframes marquee { 65 | 0% { 66 | left: 0; 67 | } 68 | 100% { 69 | left: -200%; 70 | } 71 | } 72 | .animate { 73 | animation: marquee 20s linear infinite; 74 | transform: translate(0, -50%); 75 | } 76 | } 77 | 78 | .rotate { 79 | animation: rotation 1s infinite linear; 80 | } 81 | 82 | @keyframes rotation { 83 | from { 84 | transform: rotate(0deg); 85 | } 86 | to { 87 | transform: rotate(360deg); 88 | } 89 | } 90 | 91 | .rotate:hover { 92 | animation-play-state: paused; 93 | } 94 | 95 | .heartbeat { 96 | animation: beat 0.3s infinite alternate; 97 | transform-origin: center; 98 | } 99 | 100 | @keyframes beat { 101 | to { 102 | transform: scale(1.02); 103 | } 104 | } 105 | 106 | .heartbeat:hover { 107 | animation-play-state: paused; 108 | } 109 | -------------------------------------------------------------------------------- /app/animations/animations.tsx: -------------------------------------------------------------------------------- 1 | export const riseWithFade = { 2 | initial: { 3 | y: 100, 4 | opacity: 0, 5 | }, 6 | animate: { 7 | y: 0, 8 | opacity: 1, 9 | transition: { 10 | ease: [0.65, 0, 0.35, 1], 11 | duration: 0.7, 12 | }, 13 | }, 14 | }; 15 | 16 | export const imageAnimation = { 17 | initial: { 18 | y: 50, 19 | opacity: 0, 20 | scale: 0.8, 21 | }, 22 | animate: { 23 | opacity: 1, 24 | scale: 1, 25 | y: `0em`, 26 | transition: { 27 | delay: 6.5, 28 | duration: 1, 29 | ease: [0.2, 0.65, 0.3, 0.9], 30 | }, 31 | }, 32 | }; 33 | 34 | export const staggerChildren = { 35 | animate: { 36 | transition: { 37 | delayChildren: 0.4, 38 | staggerChildren: 0.1, 39 | }, 40 | }, 41 | }; 42 | 43 | export const wordAnimation = { 44 | initial: { 45 | opacity: 0, 46 | y: 150, 47 | }, 48 | animate: { 49 | opacity: 1, 50 | y: 0, 51 | transition: { 52 | delay: 1, 53 | ease: [0.2, 0.65, 0.3, 0.9], 54 | duration: 1, 55 | }, 56 | }, 57 | }; 58 | 59 | export const wordAnimation2 = { 60 | initial: { 61 | opacity: 0, 62 | y: 150, 63 | }, 64 | animate: { 65 | opacity: 1, 66 | y: 0, 67 | transition: { 68 | // delay: 1, 69 | ease: [0.2, 0.65, 0.3, 0.9], 70 | duration: 1, 71 | }, 72 | }, 73 | }; 74 | 75 | export const bodyAnimation = { 76 | initial: { 77 | opacity: 0, 78 | y: `1em`, 79 | }, 80 | animate: { 81 | opacity: 1, 82 | y: `0em`, 83 | transition: { 84 | delay: 5.5, 85 | duration: 1, 86 | ease: [0.2, 0.65, 0.3, 0.9], 87 | }, 88 | }, 89 | }; 90 | -------------------------------------------------------------------------------- /app/api/hello/route.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/api/hello/route.js -------------------------------------------------------------------------------- /app/blog-section/BlogCard.tsx: -------------------------------------------------------------------------------- 1 | import { blogProps } from "./blogDetails"; 2 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 3 | import { faArrowRight } from "@fortawesome/free-solid-svg-icons"; 4 | import Image from "next/image"; 5 | import Link from "next/link"; 6 | import { motion } from "framer-motion"; 7 | import "../globals.css"; 8 | 9 | const BlogCard = ({ title, image, url, date, available, index }: blogProps) => { 10 | return ( 11 | 28 |
29 |
30 | {title} 37 |
38 | 39 |

40 | {title} 41 |

42 |
43 | 44 |
45 | {available ? ( 46 | <> 47 | {" "} 48 |

{date}

{" "} 49 | 55 | 64 | 65 | 66 | ) : ( 67 | <> 68 |

Coming soon

69 |
70 | 71 | )} 72 |
73 |
74 | ); 75 | }; 76 | 77 | export default BlogCard; 78 | -------------------------------------------------------------------------------- /app/blog-section/BlogGrid.tsx: -------------------------------------------------------------------------------- 1 | import BlogCard from "./BlogCard"; 2 | import { blogDetails } from "./blogDetails"; 3 | import AnimatedWords2 from "../animations/AnimatedWords2"; 4 | import { monaSans } from "../fonts/monaSans"; 5 | import AnimatedBody from "../animations/AnimatedBody"; 6 | 7 | const Blog = () => { 8 | return ( 9 |
10 |
13 | {" "} 14 | 18 | 22 |
23 |
24 | {blogDetails.map((blog, index) => { 25 | return ( 26 | 35 | ); 36 | })} 37 |
38 |
39 | ); 40 | }; 41 | 42 | export default Blog; 43 | -------------------------------------------------------------------------------- /app/blog-section/blogDetails.ts: -------------------------------------------------------------------------------- 1 | export type blogProps = { 2 | title: string; 3 | image: string; 4 | date: string; 5 | url: string; 6 | available: boolean; 7 | index: number; 8 | }; 9 | 10 | export const blogDetails = [ 11 | // { 12 | // title: "Building a Text Field Component with Material UI, Formik, and Yup", 13 | // image: 14 | // "https://cdn.hashnode.com/res/hashnode/image/upload/v1628442954056/OHNFYAzz4.jpeg?w=1600&h=840&fit=crop&crop=entropy&auto=compress,format&format=webp", 15 | // date: "12/31/2022", 16 | // url: "", 17 | // available: false, 18 | // }, 19 | // { 20 | // title: 21 | // "Creating a Select Field Component with Material UI, Formik, and Yup", 22 | // image: 23 | // "https://cdn.hashnode.com/res/hashnode/image/upload/v1624616590157/N4Hvd8NfZ.png?w=1600&h=840&fit=crop&crop=entropy&auto=compress,format&format=webp", 24 | // date: "12/31/2022", 25 | // url: "", 26 | // available: false, 27 | // }, 28 | { 29 | title: "How to create exit animations with Framer Motion", 30 | image: 31 | "https://cdn.hashnode.com/res/hashnode/image/upload/v1715345723909/c71d9691-fe4c-4302-b1cb-d9dca77a99b5.png?w=1600&h=840&fit=crop&crop=entropy&auto=compress,format&format=webp", 32 | date: "MAY 2024", 33 | url: "https://blog.victorwilliams.me/how-to-create-exit-animations-with-framer-motion", 34 | available: true, 35 | }, 36 | { 37 | title: "The Importance of Collaboration in Achieving Successful Design", 38 | image: 39 | "https://github.com/victorcodess/folio-v1/assets/84178696/05656547-3206-42af-b081-83247f9a1063", 40 | date: "MAY 2024", 41 | url: "https://blog.victorwilliams.me/importance-of-collaboration-in-design", 42 | available: true, 43 | }, 44 | { 45 | title: 46 | "Step-by-Step Guide: Adding Google Maps to Your React App Using Vis.gl", 47 | image: 48 | "https://github.com/victorcodess/folio-v1/assets/84178696/c2693469-e5c6-43ad-a857-693bbbfe7b9a", 49 | date: "APR 2024", 50 | url: "https://blog.victorwilliams.me/how-to-add-google-maps-to-react-app-visgl", 51 | available: true, 52 | }, 53 | // { 54 | // title: 55 | // "2023: A Year in Review – Navigating Challenges and Embracing Growth", 56 | // image: 57 | // "https://cdn.hashnode.com/res/hashnode/image/upload/v1704146853987/5e5ffc0f-9d20-4cc8-ad94-00ec737ba0f5.jpeg", 58 | // date: "JAN 2024", 59 | // url: "https://blog.victorwilliams.me/2023-a-year-in-review", 60 | // available: true, 61 | // }, 62 | // { 63 | // title: "Reflecting on My 18th Year: A Personal Review of 2022", 64 | // image: 65 | // "https://cdn.hashnode.com/res/hashnode/image/upload/v1672494063925/1ee2925f-e529-4a8b-9dd7-6eea996a34eb.png", 66 | // date: "DEC 2022", 67 | // url: "https://blog.victorwilliams.me/reflecting-on-my-18th-year-a-personal-review-of-2022", 68 | // available: true, 69 | // }, 70 | ]; 71 | -------------------------------------------------------------------------------- /app/contact-section/Contact.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import Image from "next/image"; 3 | import { monaSans } from "../fonts/monaSans"; 4 | import "../animations/animate.css"; 5 | import AnimatedBody from "../animations/AnimatedBody"; 6 | import AnimatedTitle from "../animations/AnimatedTitle"; 7 | import AnimatedWords2 from "../animations/AnimatedWords2"; 8 | import { motion } from "framer-motion"; 9 | import heartIcon from "../../public/heart icon.png"; 10 | 11 | const Contact = () => { 12 | return ( 13 | 19 |
20 |
23 | 29 | Heart Icon 34 |
35 | 36 |
37 |
38 | 46 |
47 | 53 | 57 | 58 | 64 | 70 | 74 | 75 |
76 |
77 | 78 |
79 | 84 | 92 | 93 | 98 | 106 | 107 | 112 | 120 | 121 | 126 | 134 | 135 | 140 | 148 | 149 |
150 |
151 |
152 |
153 | ); 154 | }; 155 | 156 | export default Contact; 157 | -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-BlackNarrow.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-BlackNarrow.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-BlackNarrowItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-BlackNarrowItalic.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-BoldNarrow.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-BoldNarrow.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-BoldNarrowItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-BoldNarrowItalic.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-ExtraBoldNarrow.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-ExtraBoldNarrow.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-LightNarrow.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-LightNarrow.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-LightNarrowItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-LightNarrowItalic.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-MediumNarrow.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-MediumNarrow.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-MediumNarrowItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-MediumNarrowItalic.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-RegularNarrowItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-RegularNarrowItalic.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-SemiBoldNarrow.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-SemiBoldNarrow.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-SemiBoldNarrowItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-SemiBoldNarrowItalic.woff2 -------------------------------------------------------------------------------- /app/fonts/Mona-Sans-UltraLightNarrow.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/fonts/Mona-Sans-UltraLightNarrow.woff2 -------------------------------------------------------------------------------- /app/fonts/monaSans.ts: -------------------------------------------------------------------------------- 1 | import localFont from "next/font/local"; 2 | 3 | export const monaSans = localFont({ 4 | src: [ 5 | { 6 | path: "./Mona-Sans-BlackNarrow.woff2", 7 | weight: "900", 8 | style: "normal", 9 | }, 10 | { 11 | path: "./Mona-Sans-BlackNarrowItalic.woff2", 12 | weight: "900", 13 | style: "italic", 14 | }, 15 | { 16 | path: "./Mona-Sans-BoldNarrow.woff2", 17 | weight: "700", 18 | style: "normal", 19 | }, 20 | { 21 | path: "./Mona-Sans-BoldNarrowItalic.woff2", 22 | weight: "700", 23 | style: "italic", 24 | }, 25 | { 26 | path: "./Mona-Sans-LightNarrow.woff2", 27 | weight: "300", 28 | style: "normal", 29 | }, 30 | { 31 | path: "./Mona-Sans-LightNarrowItalic.woff2", 32 | weight: "300", 33 | style: "italic", 34 | }, 35 | { 36 | path: "./Mona-Sans-MediumNarrow.woff2", 37 | weight: "500", 38 | style: "normal", 39 | }, 40 | { 41 | path: "./Mona-Sans-MediumNarrowItalic.woff2", 42 | weight: "500", 43 | style: "italic", 44 | }, 45 | { 46 | path: "./Mona-Sans-SemiBoldNarrow.woff2", 47 | weight: "600", 48 | style: "normal", 49 | }, 50 | { 51 | path: "./Mona-Sans-SemiBoldNarrowItalic.woff2", 52 | weight: "600", 53 | style: "italic", 54 | }, 55 | { 56 | path: "./Mona-Sans-ExtraBoldNarrow.woff2", 57 | weight: "800", 58 | style: "normal", 59 | }, 60 | { 61 | path: "./Mona-Sans-UltraLightNarrow.woff2", 62 | weight: "200", 63 | style: "normal", 64 | }, 65 | { 66 | path: "./Mona-Sans-RegularNarrowItalic.woff2", 67 | weight: "400", 68 | style: "italic", 69 | }, 70 | ], 71 | }); 72 | -------------------------------------------------------------------------------- /app/footer/Footer.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import { motion } from "framer-motion"; 3 | import AnimatedBody from "../animations/AnimatedBody"; 4 | 5 | const Footer = () => { 6 | const year = new Date().getFullYear(); 7 | 8 | return ( 9 | 14 | 15 | 16 |
17 | 21 | 26 | 27 | 28 | {" "} 29 | 30 |
31 |
32 |
33 | ); 34 | }; 35 | 36 | export default Footer; 37 | -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | h1 { 7 | @apply text-4xl; 8 | @apply font-bold; 9 | } 10 | h2 { 11 | @apply text-3xl; 12 | @apply font-bold; 13 | } 14 | h3 { 15 | @apply text-2xl; 16 | @apply font-bold; 17 | } 18 | h4 { 19 | @apply text-xl; 20 | @apply font-semibold; 21 | } 22 | h5 { 23 | @apply text-lg; 24 | @apply font-semibold; 25 | } 26 | h6 { 27 | @apply text-sm; 28 | @apply font-semibold; 29 | } 30 | } 31 | 32 | html, 33 | body { 34 | overscroll-behavior: none; 35 | } 36 | 37 | body { 38 | overflow-y: hidden; 39 | } 40 | -------------------------------------------------------------------------------- /app/hero-section/Hero.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import Image from "next/image"; 3 | import { monaSans } from "../fonts/monaSans"; 4 | import { motion } from "framer-motion"; 5 | import { imageAnimation, bodyAnimation } from "../animations/animations"; 6 | import AnimatedWords from "../animations/AnimatedWords"; 7 | import profile from "../../public/profile.webp"; 8 | 9 | const Hero = () => { 10 | return ( 11 | 17 | 18 | 19 |
20 |
21 | 26 | 30 | BOOK A CALL 31 | 32 | 33 |
34 | 35 |
36 | 41 | 45 | GH 46 | 47 | 48 | 53 | 57 | LN 58 | 59 | 60 | 65 | 69 | TW 70 | 71 | 72 | 77 | 81 | CO 82 | 83 | 84 |
85 |
86 | 87 |
88 |
91 | 95 | 99 | Victor's headshot 107 | 108 |
109 |
110 | 111 |
116 | 120 |

121 | Frontend Engineer and Web Designer, prev at{" "} 122 | 128 | Kora, 129 | {" "} 130 | currently available for work. 131 |

132 |
133 | 134 | 138 |

139 | Focused on interfaces and experiences, working remotely from Lagos, 140 | Nigeria. 141 |

142 |
143 |
144 |
145 | ); 146 | }; 147 | 148 | export default Hero; 149 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import "./globals.css"; 2 | import { ReactNode } from "react"; 3 | import type { Metadata } from "next"; 4 | import { Syne } from "next/font/google"; 5 | import { Analytics } from "@vercel/analytics/react"; 6 | 7 | const syne = Syne({ 8 | subsets: ["latin"], 9 | display: "block", 10 | weight: ["400", "500", "600", "700", "800"], 11 | }); 12 | 13 | export const metadata: Metadata = { 14 | title: "Victor Williams — Frontend Engineer", 15 | description: 16 | "Frontend Engineer and Web Designer, currently at Kora. Focused on interfaces and experiences, working remotely from Lagos, Nigeria.", 17 | generator: "Next.js", 18 | applicationName: "Victor Williams", 19 | keywords: [ 20 | "freelance", 21 | "developer", 22 | "freelance developer", 23 | "frontend", 24 | "react", 25 | "frontend developer", 26 | "frontend engineer", 27 | "creative", 28 | "creative developer", 29 | "creative engineer", 30 | "tech", 31 | "nigeria", 32 | "software", 33 | "software developer", 34 | "portfolio", 35 | "frontend developer portfolio", 36 | "creative developer portfolio", 37 | ], 38 | colorScheme: "dark", 39 | openGraph: { 40 | title: "Victor Williams — Frontend Engineer", 41 | description: 42 | "Frontend Engineer and Web Designer, currently at Kora. Focused on interfaces and experiences, working remotely from Lagos, Nigeria.", 43 | url: "https://www.victorwilliams.me/", 44 | siteName: "www.victorwilliams.me", 45 | images: [ 46 | { 47 | url: "https://user-images.githubusercontent.com/84178696/228620835-e3cc5c9b-72fc-4f54-a628-407ef7b650f5.png", 48 | width: 1200, 49 | height: 630, 50 | alt: "Victor Williams — Frontend Engineer", 51 | }, 52 | ], 53 | locale: "en-US", 54 | type: "website", 55 | }, 56 | twitter: { 57 | card: "summary_large_image", 58 | title: "Victor Williams — Frontend Engineer", 59 | description: 60 | "Frontend Engineer and Web Designer, currently at Kora. Focused on interfaces and experiences, working remotely from Lagos, Nigeria.", 61 | creator: "victorwill__", 62 | creatorId: "1243720976552144897", 63 | images: [ 64 | "https://user-images.githubusercontent.com/84178696/228620835-e3cc5c9b-72fc-4f54-a628-407ef7b650f5.png", 65 | ], 66 | }, 67 | robots: { 68 | index: true, 69 | follow: true, 70 | nocache: false, 71 | googleBot: { 72 | index: true, 73 | follow: false, 74 | noimageindex: true, 75 | "max-video-preview": -1, 76 | "max-image-preview": "large", 77 | "max-snippet": -1, 78 | }, 79 | }, 80 | category: "technology", 81 | }; 82 | 83 | type RootLayoutProps = { 84 | children: ReactNode; 85 | }; 86 | 87 | export default function RootLayout({ children }: RootLayoutProps) { 88 | return ( 89 | 90 | 93 | {children} 94 | 95 | 96 | 97 | ); 98 | } 99 | -------------------------------------------------------------------------------- /app/navbar/NavBar.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import Link from "next/link"; 3 | import { faFilePdf } from "@fortawesome/free-solid-svg-icons"; 4 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 5 | 6 | const NavBar = () => { 7 | const handleScroll = (e: React.MouseEvent) => { 8 | // first prevent the default behavior 9 | e.preventDefault(); 10 | // get the href and remove everything before the hash (#) 11 | const href = e.currentTarget.href; 12 | const targetId = href.replace(/.*\#/, ""); 13 | // get the element by id and use scrollIntoView 14 | const elem = document.getElementById(targetId); 15 | elem?.scrollIntoView({ 16 | behavior: "smooth", 17 | }); 18 | }; 19 | 20 | return ( 21 | 79 | ); 80 | }; 81 | 82 | export default NavBar; 83 | -------------------------------------------------------------------------------- /app/not-found.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "next/link"; 3 | import Image from "next/image"; 4 | 5 | const NotFound = () => { 6 | return ( 7 |
8 |

Egbon, you don miss road oh!

9 | Funny Meme 16 |
17 | 18 | Head back to my{" "} 19 | Portfolio 20 | 21 |
22 |
23 | ); 24 | }; 25 | 26 | export default NotFound; 27 | -------------------------------------------------------------------------------- /app/page.module.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/app/page.module.css -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import Hero from "./hero-section/Hero"; 3 | import useBlobity from "blobity/lib/react/useBlobity"; 4 | import { useEffect } from "react"; 5 | import { ScrollerMotion } from "scroller-motion"; 6 | import PreLoader from "./animations/PreLoader/PreLoader"; 7 | import { initialBlobityOptions } from "./utils/BlobityConfig"; 8 | import NavBar from "./navbar/NavBar"; 9 | 10 | import dynamic from "next/dynamic"; 11 | import Reviews from "./reviews-section/ReviewGrid"; 12 | const Work = dynamic(() => import("./work-section/Work")); 13 | const About = dynamic(() => import("./about-section/About")); 14 | const Blog = dynamic(() => import("./blog-section/BlogGrid")); 15 | const Contact = dynamic(() => import("./contact-section/Contact")); 16 | const Footer = dynamic(() => import("./footer/Footer")); 17 | 18 | export default function Home() { 19 | const blobityInstance = useBlobity(initialBlobityOptions); 20 | 21 | useEffect(() => { 22 | if (blobityInstance.current) { 23 | // @ts-ignore for debugging purposes or playing around 24 | window.blobity = blobityInstance.current; 25 | } 26 | }, [blobityInstance]); 27 | 28 | useEffect(() => { 29 | window.scrollTo({ 30 | top: 0, 31 | left: 0, 32 | }); 33 | }, []); 34 | 35 | return ( 36 | <> 37 | 38 | 39 | 40 | 41 | {/* */} 42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 |
51 | {/*
*/} 52 | 53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /app/reviews-section/ReviewCard.tsx: -------------------------------------------------------------------------------- 1 | import { reviewProps } from "./reviewDetails"; 2 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 3 | import { faArrowRight } from "@fortawesome/free-solid-svg-icons"; 4 | import Image from "next/image"; 5 | import Link from "next/link"; 6 | import "../globals.css"; 7 | import profile from "../../public/samuel.avif"; 8 | import slash from "../../public/review-slash.svg"; 9 | import { motion } from "framer-motion"; 10 | 11 | const BlogCard = ({ 12 | name, 13 | role, 14 | company, 15 | profileImg, 16 | testimonial, 17 | index, 18 | }: reviewProps) => { 19 | const abbreviateName = (name: string): string => { 20 | const [firstName, lastName] = name.split(" "); 21 | return `${firstName} ${lastName[0]}.`; 22 | }; 23 | 24 | return ( 25 | 42 | {"title"} 47 | 48 |

49 | {testimonial} 50 |

51 | 52 |
53 | {"title"} 60 |
61 |

62 | {abbreviateName(name)} 63 |

64 |

65 | {role} @ {company} 66 |

67 |
68 |
69 |
70 | ); 71 | }; 72 | 73 | export default BlogCard; 74 | -------------------------------------------------------------------------------- /app/reviews-section/ReviewGrid.tsx: -------------------------------------------------------------------------------- 1 | import ReviewCard from "./ReviewCard"; 2 | import { reviewDetails } from "./reviewDetails"; 3 | import AnimatedWords2 from "../animations/AnimatedWords2"; 4 | import { monaSans } from "../fonts/monaSans"; 5 | import AnimatedBody from "../animations/AnimatedBody"; 6 | import { motion } from "framer-motion"; 7 | import hireMe from "../../public/hiremeoncontra-dark.webp"; 8 | import Image from "next/image"; 9 | 10 | const Reviews = () => { 11 | return ( 12 |
13 |
16 | 20 | 24 |
25 | 26 | {reviewDetails.map((review, index) => { 27 | return ( 28 | 37 | ); 38 | })} 39 | 40 | 41 | 60 | {"hire 61 | 62 | 63 | {/* 83 | */} 88 |
89 | ); 90 | }; 91 | 92 | export default Reviews; 93 | -------------------------------------------------------------------------------- /app/reviews-section/reviewDetails.ts: -------------------------------------------------------------------------------- 1 | import { StaticImageData } from "next/image"; 2 | import alex from "../../public/samuel.avif"; 3 | import jerry from "../../public/jerry.avif"; 4 | import mauro from "../../public/mauro.jpeg"; 5 | import alan from "../../public/alan.jpeg"; 6 | import olamide from "../../public/olamide.jpeg"; 7 | import umar from "../../public/umar.jpeg"; 8 | 9 | export type reviewProps = { 10 | name: string; 11 | role: string; 12 | company: string; 13 | profileImg: StaticImageData; 14 | testimonial: string; 15 | index: number; 16 | }; 17 | 18 | export const reviewDetails = [ 19 | { 20 | name: "Samuel Alex", 21 | role: "Product Designer", 22 | company: "Umoja Linn", 23 | profileImg: alex, 24 | testimonial: 25 | "Victor is seriously one of the best frontend developers I've ever worked with. He's incredibly talented, super easy to work with, and always goes above and beyond.", 26 | }, 27 | { 28 | name: "Jeremiah Oloyede", 29 | role: "Founder", 30 | company: "Crown Branding Agency", 31 | profileImg: jerry, 32 | testimonial: 33 | "Victor's work is truly outstanding, and I can't recommend him enough! He completely transformed our branding agency's website. Since launch, we've seen a significant jump in website traffic and, crucially, conversions.", 34 | }, 35 | { 36 | name: "Mauro Reis", 37 | role: "CEO", 38 | company: "Meuclone Digital", 39 | profileImg: mauro, 40 | testimonial: 41 | "Outstanding professional, developed our startup's website and delivered it in a very short time and with high quality.", 42 | }, 43 | { 44 | name: "Umar Abdullahi", 45 | role: "Head of Engineering", 46 | company: "Mono", 47 | profileImg: umar, 48 | testimonial: 49 | "Victor is hardworking and has great sense of ownership. He was able to contribute in engineering excellent user interfaces and user experiences at Mono. I’m confident he will be a great asset to any engineering team.", 50 | }, 51 | { 52 | name: "Olamide Sholanke", 53 | role: "Senior Frontend Engineer", 54 | company: "Mono", 55 | profileImg: olamide, 56 | testimonial: 57 | "I had the pleasure of working with Victor on a frontend development project at Mono, and I highly recommend him. He consistently delivered high-quality code, and brought a proactive and creative approach to problem-solving.", 58 | }, 59 | { 60 | name: "Alan Franciskovic", 61 | role: "Sales Specialist", 62 | company: "Croatia Osiguranje d.d", 63 | profileImg: alan, 64 | testimonial: 65 | "Very talented and amazing freelancer. Very easy to communicate with, pleasure to work with. Outstanding attention to detail, and works as fast as possible while also delivering amazing work.", 66 | }, 67 | 68 | ]; 69 | -------------------------------------------------------------------------------- /app/utils/BlobityConfig.tsx: -------------------------------------------------------------------------------- 1 | export const initialBlobityOptions = { 2 | licenseKey: "opensource", 3 | focusableElementsOffsetX: 5, 4 | focusableElementsOffsetY: 5, 5 | color: "#e4ded7", 6 | dotColor: "#0e1016", 7 | invert: true, 8 | focusableElements: 9 | "[data-blobity], a:not([data-no-blobity]), h4:not([data-no-blobity]), li:not([data-no-blobity]), button:not([data-no-blobity]), [data-blobity-tooltip]", 10 | font: "'Montserrat','Source Sans Pro',-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif", 11 | fontSize: 16, 12 | fontWeight: 500, 13 | opacity: 1, 14 | fontColor: "#0e1016", 15 | zIndex: 100, 16 | size: 40, 17 | radius: 4, 18 | magnetic: true, 19 | } -------------------------------------------------------------------------------- /app/work-section/ProjectCard.tsx: -------------------------------------------------------------------------------- 1 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 2 | import { faLink } from "@fortawesome/free-solid-svg-icons"; 3 | import { faGithub } from "@fortawesome/free-brands-svg-icons"; 4 | import { ProjectProps } from "./projectDetails"; 5 | import Link from "next/link"; 6 | import Image from "next/image"; 7 | import AnimatedTitle from "../animations/AnimatedTitle"; 8 | import AnimatedBody from "../animations/AnimatedBody"; 9 | import { motion } from "framer-motion"; 10 | 11 | const ProjectCard = ({ 12 | id, 13 | name, 14 | description, 15 | technologies, 16 | github, 17 | demo, 18 | image, 19 | available, 20 | }: ProjectProps) => { 21 | return ( 22 | 36 | {name} 43 |
48 | {available ? ( 49 | <> 50 | 56 | 65 | 66 | 67 | 76 | 77 | 78 | ) : ( 79 |
80 | 86 | 95 | 96 |
97 |

98 | Coming soon 99 |

100 |
101 |
102 | )} 103 |
104 |
111 | 119 | 125 |
126 | {technologies.map((tech, id) => ( 127 | 136 | ))} 137 |
138 |
139 |
140 | ); 141 | }; 142 | 143 | export default ProjectCard; 144 | -------------------------------------------------------------------------------- /app/work-section/ProjectGrid.tsx: -------------------------------------------------------------------------------- 1 | import ProjectCard from "./ProjectCard"; 2 | import { devProjects, designProjects, ProjectProps } from "./projectDetails"; 3 | import { useState } from "react"; 4 | 5 | const ProjectGrid = () => { 6 | // const [filter, setFilter] = useState(true); 7 | 8 | return ( 9 | <> 10 | {/*
11 |

setFilter(true)} 16 | > 17 | Development 18 |

{" "} 19 |

setFilter(false)} 24 | > 25 | Design 26 |

27 |
*/} 28 | 29 | {/* {filter ? ( */} 30 |
31 | {devProjects.map((project: ProjectProps) => ( 32 | 43 | ))} 44 |
45 | {/* ) : ( 46 |
47 | {designProjects.map((project: ProjectProps) => ( 48 | 60 | ))} 61 |
62 | )} */} 63 | 64 | ); 65 | }; 66 | 67 | export default ProjectGrid; 68 | -------------------------------------------------------------------------------- /app/work-section/Work.tsx: -------------------------------------------------------------------------------- 1 | import ProjectGrid from "./ProjectGrid"; 2 | 3 | const Work = () => { 4 | return ( 5 |
9 |

10 | Featured Work 11 |

12 | 13 | 14 |
15 | ); 16 | }; 17 | 18 | export default Work; 19 | -------------------------------------------------------------------------------- /app/work-section/projectDetails.ts: -------------------------------------------------------------------------------- 1 | export type ProjectProps = { 2 | id: number; 3 | name: string; 4 | description: string; 5 | technologies: string[]; 6 | github: string; 7 | demo: string; 8 | image: string; 9 | available: boolean; 10 | }; 11 | 12 | export const devProjects = [ 13 | { 14 | id: 0, 15 | name: "Odunsi", 16 | description: 17 | "Portfolio website for Michael Odunsi, an experienced UI/UX designer crafting unique, user-friendly products and web experiences for Web3 founders and projects.", 18 | technologies: ["React", "Tailwind CSS", "Framer Motion"], 19 | github: "https://github.com/victorcodess/odunsi-web3-folio", 20 | demo: "https://www.odunsi.xyz/", 21 | image: require(".//../../public/projects/odunsi.png"), 22 | available: true, 23 | }, 24 | { 25 | id: 1, 26 | name: "Interlock", 27 | description: 28 | "This is a website for a Fintech Startup to showcase their innovative solutions tailored to meet the evolving needs of their clients.", 29 | technologies: ["React", "Tailwind CSS", "Framer Motion"], 30 | github: "https://github.com/victorcodess/interlock", 31 | demo: "https://interlock-teal.vercel.app/", 32 | image: require(".//../../public/projects/interlock.png"), 33 | available: true, 34 | }, 35 | { 36 | id: 2, 37 | name: "Synthetix", 38 | description: 39 | "Built specifically for an AI startup, this website lets them present cutting-edge AI data processing solutions tailored to their customers' needs.", 40 | technologies: ["React", "Next.js", "Prismic CMS"], 41 | github: "https://github.com/victorcodess/synthetix", 42 | demo: "https://synthetix-iota.vercel.app/", 43 | image: require(".//../../public/projects/synthetix-flip.png"), 44 | available: true, 45 | }, 46 | { 47 | id: 3, 48 | name: "Propellent", 49 | description: 50 | "A website built for a software startup and small business, to showcase their services and mark their online presence.", 51 | technologies: ["React", "Tailwind CSS", "Framer Motion"], 52 | github: "https://github.com/victorcodess/propellent", 53 | demo: "https://propellent.vercel.app/", 54 | image: require(".//../../public/projects/propellent-new.png"), 55 | available: true, 56 | }, 57 | { 58 | id: 4, 59 | name: "Flixify", 60 | description: 61 | "Flixify lets you seamlessly explore movies and TV series, add bookmarks, and search across all pages. It offers user authentication along with a theme switch.", 62 | technologies: ["Next.js", "Typescript", "Prisma"], 63 | github: "https://github.com/victorcodess/flixify", 64 | demo: "https://flixify.victorwilliams.me/", 65 | image: require(".//../../public/projects/flixify.png"), 66 | available: true, 67 | }, 68 | // { 69 | // id: 4, 70 | // name: "SkyWatch", 71 | // description: 72 | // "SkyWatch is a convenient and user-friendly tool that allows you to quickly and easily check the current weather and forecast for the next 2 days in any city.", 73 | // technologies: ["React", "CSS", "Chart.js"], 74 | // github: "https://github.com/victorcodess/weather-forecast-website", 75 | // demo: "https://sky-watch.vercel.app/", 76 | // image: require(".//../../public/projects/skywatch-flip.png"), 77 | // available: true, 78 | // }, 79 | // { 80 | // id: 4, 81 | // name: "Alpaca Image Generator", 82 | // description: 83 | // "An image generator website that allows users to generate, combine, and download images.", 84 | // technologies: ["React", "CSS", "Merge Images"], 85 | // github: "https://github.com/victorcodess/alpaca-image-generator", 86 | // demo: "http://alpaca-image-generator-beta.vercel.app", 87 | // image: require(".//../../public/projects/alpaca-flip.png"), 88 | // available: true, 89 | // }, 90 | 91 | // { 92 | // id: 5, 93 | // name: "Link Shortener", 94 | // description: 95 | // "A website that reduces the length of your URL using Bit.ly's API", 96 | // technologies: ["JavaScript", "CSS", "Bit.ly's API"], 97 | // github: "https://github.com/victorcodess/url-shortener", 98 | // demo: "https://url-shortener-nine-delta.vercel.app", 99 | // image: require(".//../../public/projects/shortener-new.webp"), 100 | // available: true, 101 | // }, 102 | // { 103 | // id: 6, 104 | // name: "Carpooling Service", 105 | // description: 106 | // "TMTM helps Covenant University students find fellow students who are headed to the same location, so they can share a ride and split the cost.", 107 | // technologies: ["Material UI", "React", "Formik"], 108 | // github: "https://github.com/victorcodess/carpooling-service", 109 | // demo: "", 110 | // image: require(".//../../public/projects/carpool-new.webp"), 111 | // available: false, 112 | // }, 113 | // { 114 | // id: 7, 115 | // name: "MLSC.ng", 116 | // description: 117 | // "This is platform for Microsoft Learn Student Ambassadors to shorten links, append their sharing IDs and generate event certificates.", 118 | // technologies: ["Next.js", "Next Auth", "Tailwind CSS"], 119 | // github: "https://github.com/msp-nigeria/mlsc.ng-frontend", 120 | // demo: "", 121 | // image: require(".//../../public/projects/mlsc.png"), 122 | // available: false, 123 | // }, 124 | ]; 125 | 126 | export const designProjects = [ 127 | { 128 | id: 1, 129 | name: "Hebron Statup Lab Website", 130 | description: 131 | "SkyWatch is a convenient and user-friendly tool that allows you to quickly and easily check the current.", 132 | technologies: ["UX Research", "UI Design", "Prototyping"], 133 | github: "", 134 | demo: "", 135 | image: "/_next/image?url=%2F..%2Fpublic%2Fprojects%2Fhsl.webp&w=1920&q=75", 136 | available: false, 137 | }, 138 | { 139 | id: 2, 140 | name: "RAGS Scrubs Website", 141 | description: 142 | "An image generator website that allows users to generate, combine, and download images.", 143 | technologies: ["UX Research", "UI Design", "Prototyping"], 144 | github: "", 145 | demo: "", 146 | image: "/_next/image?url=%2F..%2Fpublic%2Fprojects%2Frags.webp&w=1920&q=75", 147 | available: false, 148 | }, 149 | { 150 | id: 3, 151 | name: "Crown Branding Agency Website", 152 | description: 153 | "A website that reduces the length of your URL using Bit.ly's API", 154 | technologies: ["UX Research", "UI Design", "Prototyping"], 155 | github: "", 156 | demo: "", 157 | image: 158 | "/_next/image?url=%2F..%2Fpublic%2Fprojects%2Fcrown.webp&w=1920&q=75", 159 | available: false, 160 | }, 161 | { 162 | id: 4, 163 | name: "Titi Mobile App", 164 | description: 165 | "TMTM helps you find people who are headed to the same location as you, so you can share a ride and split the cost with them.", 166 | technologies: ["UX Research", "UI Design", "Prototyping"], 167 | github: "", 168 | demo: "", 169 | image: "/_next/image?url=%2F..%2Fpublic%2Fprojects%2Ftiti.webp&w=1920&q=75", 170 | available: false, 171 | }, 172 | ]; 173 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | experimental: { 4 | appDir: true, 5 | }, 6 | optimizeFonts: false, 7 | images: { 8 | domains: ["user-images.githubusercontent.com", "cdn.hashnode.com", "github.com"], 9 | }, 10 | fontLoaders: [ 11 | { 12 | loader: "@next/font/google", 13 | options: { 14 | subsets: ["latin"], 15 | weight: ["400", "500", "600", "700", "800"], 16 | }, 17 | }, 18 | ], 19 | }; 20 | 21 | module.exports = nextConfig; 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "folio-v1", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@fortawesome/fontawesome-svg-core": "^6.3.0", 13 | "@fortawesome/free-brands-svg-icons": "^6.3.0", 14 | "@fortawesome/free-solid-svg-icons": "^6.3.0", 15 | "@fortawesome/react-fontawesome": "^0.2.0", 16 | "@tailwindcss/line-clamp": "^0.4.2", 17 | "@vercel/analytics": "^0.1.11", 18 | "blobity": "^0.2.3", 19 | "eslint": "8.35.0", 20 | "eslint-config-next": "13.2.3", 21 | "framer-motion": "^10.6.1", 22 | "gsap": "^3.11.5", 23 | "next": "13.2.3", 24 | "react": "^18.2.0", 25 | "react-dom": "18.2.0", 26 | "react-intersection-observer": "^9.4.3", 27 | "resize-observer-polyfill": "^1.5.1", 28 | "scroller-motion": "^1.2.3", 29 | "sharp": "^0.32.0", 30 | "touch-cli": "^0.0.1" 31 | }, 32 | "devDependencies": { 33 | "@types/node": "18.15.0", 34 | "@types/react": "18.0.28", 35 | "autoprefixer": "^10.4.13", 36 | "postcss": "^8.4.21", 37 | "prettier": "^2.8.4", 38 | "prettier-plugin-tailwindcss": "^0.2.5", 39 | "tailwind-scrollbar": "^3.0.0", 40 | "tailwindcss": "^3.2.7" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/alan.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/alan.jpeg -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/favicon.ico -------------------------------------------------------------------------------- /public/heart icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/heart icon.png -------------------------------------------------------------------------------- /public/hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/hero.jpg -------------------------------------------------------------------------------- /public/hero.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/hero.webp -------------------------------------------------------------------------------- /public/hiremeoncontra-dark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/hiremeoncontra-dark.webp -------------------------------------------------------------------------------- /public/jerry.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/jerry.avif -------------------------------------------------------------------------------- /public/mauro.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/mauro.jpeg -------------------------------------------------------------------------------- /public/olamide.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/olamide.jpeg -------------------------------------------------------------------------------- /public/profile.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/profile.webp -------------------------------------------------------------------------------- /public/projects/alpaca-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/alpaca-flip.png -------------------------------------------------------------------------------- /public/projects/alpaca-new.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/alpaca-new.webp -------------------------------------------------------------------------------- /public/projects/carpool-new.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/carpool-new.webp -------------------------------------------------------------------------------- /public/projects/crown.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/crown.webp -------------------------------------------------------------------------------- /public/projects/flixify-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/flixify-flip.png -------------------------------------------------------------------------------- /public/projects/flixify-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/flixify-new.png -------------------------------------------------------------------------------- /public/projects/flixify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/flixify.png -------------------------------------------------------------------------------- /public/projects/hsl.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/hsl.webp -------------------------------------------------------------------------------- /public/projects/interlock-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/interlock-flip.png -------------------------------------------------------------------------------- /public/projects/interlock-flip2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/interlock-flip2.png -------------------------------------------------------------------------------- /public/projects/interlock-new-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/interlock-new-flip.png -------------------------------------------------------------------------------- /public/projects/interlock-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/interlock-new.png -------------------------------------------------------------------------------- /public/projects/interlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/interlock.png -------------------------------------------------------------------------------- /public/projects/mlsc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/mlsc.png -------------------------------------------------------------------------------- /public/projects/odunsi-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/odunsi-flip.png -------------------------------------------------------------------------------- /public/projects/odunsi-mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/odunsi-mobile.png -------------------------------------------------------------------------------- /public/projects/odunsi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/odunsi.png -------------------------------------------------------------------------------- /public/projects/propellent-new-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/propellent-new-flip.png -------------------------------------------------------------------------------- /public/projects/propellent-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/propellent-new.png -------------------------------------------------------------------------------- /public/projects/propellent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/propellent.png -------------------------------------------------------------------------------- /public/projects/rags.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/rags.webp -------------------------------------------------------------------------------- /public/projects/shortener-new.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/shortener-new.webp -------------------------------------------------------------------------------- /public/projects/skywatch-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/skywatch-flip.png -------------------------------------------------------------------------------- /public/projects/skywatch-new.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/skywatch-new.webp -------------------------------------------------------------------------------- /public/projects/synthetix-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/synthetix-flip.png -------------------------------------------------------------------------------- /public/projects/synthetix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/synthetix.png -------------------------------------------------------------------------------- /public/projects/titi.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/projects/titi.webp -------------------------------------------------------------------------------- /public/review-slash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /public/samuel.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/samuel.avif -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /public/songs/22-double-0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/songs/22-double-0.jpg -------------------------------------------------------------------------------- /public/songs/care.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/songs/care.jpg -------------------------------------------------------------------------------- /public/songs/floods.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/songs/floods.jpg -------------------------------------------------------------------------------- /public/songs/glitter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/songs/glitter.jpg -------------------------------------------------------------------------------- /public/songs/lemme-land.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/songs/lemme-land.jpg -------------------------------------------------------------------------------- /public/songs/let-me-go.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/songs/let-me-go.jpg -------------------------------------------------------------------------------- /public/songs/lie-again.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/songs/lie-again.jpeg -------------------------------------------------------------------------------- /public/songs/martins-sofa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/songs/martins-sofa.jpg -------------------------------------------------------------------------------- /public/songs/nice-and-good.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/songs/nice-and-good.jpg -------------------------------------------------------------------------------- /public/songs/one-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/songs/one-up.png -------------------------------------------------------------------------------- /public/umar.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorcodess/folio-v1/e1fe2b76a6e735f4e6f875584a761d65ae3297ee/public/umar.jpeg -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./app/**/*.{js,ts,jsx,tsx}", 5 | "./pages/**/*.{js,ts,jsx,tsx}", 6 | "./components/**/*.{js,ts,jsx,tsx}", 7 | 8 | // Or if using `src` directory: 9 | "./src/**/*.{js,ts,jsx,tsx}", 10 | ], 11 | theme: { 12 | extend: { 13 | screens: { 14 | "3xl": "1600px", 15 | }, 16 | }, 17 | }, 18 | plugins: [require("tailwind-scrollbar"), require("@tailwindcss/line-clamp")], 19 | }; 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "noEmit": true, 9 | "incremental": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ] 21 | }, 22 | "include": [ 23 | "next-env.d.ts", 24 | ".next/types/**/*.ts", 25 | "**/*.ts", 26 | "**/*.tsx", 27 | "app/work-section/projectDetails.ts", 28 | "app/animations/PreLoader/loader.js" 29 | ], 30 | "exclude": ["node_modules"] 31 | } 32 | --------------------------------------------------------------------------------