├── public ├── assets │ └── images │ │ ├── ap.jpg │ │ ├── sd.jpg │ │ ├── sn.jpg │ │ ├── decor.jpg │ │ └── retweet.jpg ├── vercel.svg └── next.svg ├── postcss.config.mjs ├── lib └── utils.ts ├── constants ├── navigation.ts └── projectData.ts ├── components.json ├── next.config.mjs ├── app ├── globals.css ├── layout.tsx └── page.tsx ├── .gitignore ├── tsconfig.json ├── package.json ├── components ├── shared │ ├── SlideIn.tsx │ ├── Dock.tsx │ ├── heroSection.tsx │ ├── contact.tsx │ ├── Skills.tsx │ ├── Projects.tsx │ ├── Navbar.tsx │ └── About.tsx └── ui │ └── floating-dock.tsx ├── README.md └── tailwind.config.ts /public/assets/images/ap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somkenemuscle/Portfolio/HEAD/public/assets/images/ap.jpg -------------------------------------------------------------------------------- /public/assets/images/sd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somkenemuscle/Portfolio/HEAD/public/assets/images/sd.jpg -------------------------------------------------------------------------------- /public/assets/images/sn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somkenemuscle/Portfolio/HEAD/public/assets/images/sn.jpg -------------------------------------------------------------------------------- /public/assets/images/decor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somkenemuscle/Portfolio/HEAD/public/assets/images/decor.jpg -------------------------------------------------------------------------------- /public/assets/images/retweet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somkenemuscle/Portfolio/HEAD/public/assets/images/retweet.jpg -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /constants/navigation.ts: -------------------------------------------------------------------------------- 1 | // Define the navigation items 2 | export const navigation = [ 3 | { name: 'Projects', href: '#projects' }, 4 | { name: 'Skills', href: '#skills' }, 5 | { name: 'About', href: '#about' }, 6 | { name: 'Resume', href: 'https://utfs.io/f/rXxdhjbFRcsmqeDfzvLAg19Zkx3TWniNDhroBma8M64FO5Ie' } 7 | ]; 8 | 9 | 10 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | images: { 4 | remotePatterns: [ 5 | { 6 | protocol: 'https', 7 | hostname: 'assets.aceternity.com' 8 | }, 9 | { 10 | protocol: 'https', 11 | hostname: 'framerusercontent.com' 12 | } 13 | ], 14 | }, 15 | }; 16 | 17 | export default nextConfig; 18 | -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | /* Define the keyframes for the blinking effect */ 6 | @keyframes blink { 7 | 8 | 0%, 9 | 100% { 10 | opacity: 1; 11 | } 12 | 13 | 50% { 14 | opacity: 0; 15 | } 16 | } 17 | 18 | html { 19 | scroll-behavior: smooth; 20 | 21 | } 22 | 23 | /* Apply the animation to the blinking-dot class */ 24 | .blinking-dot { 25 | animation: blink 0.7s infinite; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Inter } from "next/font/google"; 3 | import "./globals.css"; 4 | 5 | const inter = Inter({ subsets: ["latin"] }); 6 | 7 | export const metadata: Metadata = { 8 | title: "Ojukwu Somkene", 9 | description: "Ojukwu Somkene's portfolio", 10 | }; 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: Readonly<{ 15 | children: React.ReactNode; 16 | }>) { 17 | return ( 18 | 19 | {children} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import Navbar from "@/components/shared/Navbar"; 2 | import HeroSection from "@/components/shared/heroSection"; 3 | import { Projects } from "@/components/shared/Projects"; 4 | import Skills from "@/components/shared/Skills"; 5 | import Contact from "@/components/shared/contact"; 6 | import About from "@/components/shared/About"; 7 | 8 | export default function Home() { 9 | 10 | return ( 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | ); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "portfolio", 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 | "@headlessui/react": "^2.1.3", 13 | "@heroicons/react": "^2.1.5", 14 | "@radix-ui/react-icons": "^1.3.1", 15 | "@tabler/icons-react": "^3.14.0", 16 | "class-variance-authority": "^0.7.0", 17 | "clsx": "^2.1.1", 18 | "framer-motion": "^11.3.31", 19 | "lucide-react": "^0.436.0", 20 | "next": "14.2.6", 21 | "react": "^18", 22 | "react-dom": "^18", 23 | "react-intersection-observer": "^9.13.0", 24 | "tailwind-merge": "^2.5.2", 25 | "tailwindcss-animate": "^1.0.7" 26 | }, 27 | "devDependencies": { 28 | "@types/node": "^20", 29 | "@types/react": "^18", 30 | "@types/react-dom": "^18", 31 | "postcss": "^8", 32 | "tailwindcss": "^3.4.1", 33 | "typescript": "^5" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /components/shared/SlideIn.tsx: -------------------------------------------------------------------------------- 1 | // components/SlideIn.tsx 2 | 'use client' 3 | import React from 'react'; 4 | import { motion } from 'framer-motion'; 5 | import { useInView } from 'react-intersection-observer'; 6 | 7 | interface SlideInProps { 8 | children: React.ReactNode; 9 | direction?: 'left' | 'right' | 'top' | 'bottom'; 10 | duration?: number; 11 | } 12 | 13 | const SlideIn: React.FC = ({ 14 | children, 15 | direction = 'left', 16 | duration = 0.5, 17 | }) => { 18 | const { ref, inView } = useInView({ 19 | triggerOnce: true, 20 | threshold: 0.1, 21 | }); 22 | 23 | const variants = { 24 | hidden: { 25 | opacity: 0, 26 | x: direction === 'left' ? -100 : direction === 'right' ? 100 : 0, 27 | y: direction === 'top' ? -100 : direction === 'bottom' ? 100 : 0, 28 | }, 29 | visible: { 30 | opacity: 1, 31 | x: 0, 32 | y: 0, 33 | }, 34 | }; 35 | 36 | return ( 37 | 44 | {children} 45 | 46 | ); 47 | }; 48 | 49 | export default SlideIn; 50 | -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/shared/Dock.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import React from "react"; 3 | import { FloatingDock } from "@/components/ui/floating-dock"; 4 | import { GitHubLogoIcon, LinkedInLogoIcon, TwitterLogoIcon } from "@radix-ui/react-icons" 5 | 6 | export function FloatingDockDemo() { 7 | const contactlinks = [ 8 | { 9 | title: "Linkedin", 10 | icon: ( 11 | 12 | ), 13 | href: "https://www.linkedin.com/in/somkene-ojukwu/", 14 | }, 15 | { 16 | title: "Twitter", 17 | icon: ( 18 | 19 | ), 20 | href: "https://x.com/somkeneOj", 21 | }, 22 | { 23 | title: "GitHub", 24 | icon: ( 25 | 26 | ), 27 | href: "https://github.com/somkenemuscle", 28 | }, 29 | 30 | ]; 31 | 32 | 33 | return ( 34 |
35 | 38 |
39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /components/shared/heroSection.tsx: -------------------------------------------------------------------------------- 1 | import { FloatingDockDemo } from "./Dock" 2 | import SlideIn from "./SlideIn" 3 | function HeroSection() { 4 | return ( 5 | 6 |
7 |
8 | 9 |
10 |
11 |

12 | OJUKWU SOMKENE IFECHUKWU 13 |

14 |

15 | I am a Full-Stack developer based in Nigeria, passionate about creating web applications that are both functional and visually appealing. "Coding is not just a job for me, it’s a hobby that I deeply enjoy." 16 |

17 |
18 | 19 |
20 |
21 |
22 | 28 |
29 | 30 |
31 |
32 | 33 | ) 34 | } 35 | 36 | export default HeroSection -------------------------------------------------------------------------------- /constants/projectData.ts: -------------------------------------------------------------------------------- 1 | export const projectData = [ 2 | { 3 | title: "Appvarsity", 4 | description: 5 | "A platform dedicated to bridging the gap in information and resources for Aptech students by providing them with essential tools and support tailored to their needs. ", 6 | technologies: ["React","Next.js", "MongoDB", "Tailwind", "Express.js", "Typescript"], 7 | livePreview: "https://appvarsity.vercel.app/", 8 | caseStudy: "#", 9 | sourceCode: "https://github.com/somkenemuscle/AppVarsity", 10 | image: "/assets/images/ap.jpg", 11 | }, 12 | { 13 | title: "Retweet", 14 | description: 15 | "A fun and interactive social media platform designed for sharing posts and connecting with friends, built specifically for my school or any community and friends to create our very own online hangout space! 😂", 16 | technologies: ["React","Tailwind", "Next.js", "Typescript", "Express.js", "MongoDb"], 17 | livePreview: "https://retweet-frontend.vercel.app/", 18 | caseStudy: "#", 19 | sourceCode: "https://github.com/somkenemuscle/Retweet-backend", 20 | image: "/assets/images/retweet.jpg", 21 | }, 22 | { 23 | title: "SwiftDocs", 24 | description: 25 | "A live document collaboration application that allows users worldwide to share a common space and exchange innovative ideas seamlessly.", 26 | technologies: ["React","Tailwind", "MongoDb", "Express.js", "Typescript"], 27 | livePreview: "https://swiftdocs.vercel.app/", 28 | caseStudy: "#", 29 | sourceCode: "https://github.com/somkenemuscle/Swift-Docs", 30 | image: "/assets/images/sd.jpg", 31 | }, 32 | 33 | { 34 | title: "Decorvista", 35 | description: 36 | "An e-commerce platform that allows users to shop for home design appliances and connect with interior designers, creating a collaborative space to showcase and explore innovative designs.", 37 | technologies: ["React", "Bootstrap", "Javascript", "Express.js", "MongoDb"], 38 | livePreview: "https://decorvista.vercel.app/", 39 | caseStudy: "#", 40 | sourceCode: "https://github.com/somkenemuscle/decorvista", 41 | image: "/assets/images/decor.jpg", 42 | }, 43 | 44 | ]; 45 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss" 2 | 3 | const config = { 4 | darkMode: ["class"], 5 | content: [ 6 | './pages/**/*.{ts,tsx}', 7 | './components/**/*.{ts,tsx}', 8 | './app/**/*.{ts,tsx}', 9 | './src/**/*.{ts,tsx}', 10 | ], 11 | prefix: "", 12 | theme: { 13 | container: { 14 | center: true, 15 | padding: "2rem", 16 | screens: { 17 | "2xl": "1400px", 18 | }, 19 | }, 20 | extend: { 21 | colors: { 22 | border: "hsl(var(--border))", 23 | input: "hsl(var(--input))", 24 | ring: "hsl(var(--ring))", 25 | background: "hsl(var(--background))", 26 | foreground: "hsl(var(--foreground))", 27 | primary: { 28 | DEFAULT: "hsl(var(--primary))", 29 | foreground: "hsl(var(--primary-foreground))", 30 | }, 31 | secondary: { 32 | DEFAULT: "hsl(var(--secondary))", 33 | foreground: "hsl(var(--secondary-foreground))", 34 | }, 35 | destructive: { 36 | DEFAULT: "hsl(var(--destructive))", 37 | foreground: "hsl(var(--destructive-foreground))", 38 | }, 39 | muted: { 40 | DEFAULT: "hsl(var(--muted))", 41 | foreground: "hsl(var(--muted-foreground))", 42 | }, 43 | accent: { 44 | DEFAULT: "hsl(var(--accent))", 45 | foreground: "hsl(var(--accent-foreground))", 46 | }, 47 | popover: { 48 | DEFAULT: "hsl(var(--popover))", 49 | foreground: "hsl(var(--popover-foreground))", 50 | }, 51 | card: { 52 | DEFAULT: "hsl(var(--card))", 53 | foreground: "hsl(var(--card-foreground))", 54 | }, 55 | }, 56 | borderRadius: { 57 | lg: "var(--radius)", 58 | md: "calc(var(--radius) - 2px)", 59 | sm: "calc(var(--radius) - 4px)", 60 | }, 61 | keyframes: { 62 | "accordion-down": { 63 | from: { height: "0" }, 64 | to: { height: "var(--radix-accordion-content-height)" }, 65 | }, 66 | "accordion-up": { 67 | from: { height: "var(--radix-accordion-content-height)" }, 68 | to: { height: "0" }, 69 | }, 70 | }, 71 | animation: { 72 | "accordion-down": "accordion-down 0.2s ease-out", 73 | "accordion-up": "accordion-up 0.2s ease-out", 74 | }, 75 | }, 76 | }, 77 | plugins: [require("tailwindcss-animate")], 78 | } satisfies Config 79 | 80 | export default config -------------------------------------------------------------------------------- /components/shared/contact.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | IconBrandGithub, 3 | IconBrandX, 4 | IconBrandLinkedin, 5 | IconBrandGmail, 6 | 7 | } from "@tabler/icons-react"; 8 | import Link from "next/link"; 9 | 10 | function Contact() { 11 | const contactlinks = [ 12 | { 13 | title: "Linkedin", 14 | icon: ( 15 | 16 | ), 17 | href: "https://www.linkedin.com/in/somkene-ojukwu/", 18 | }, 19 | { 20 | title: "GitHub", 21 | icon: ( 22 | 23 | ), 24 | href: "https://github.com/somkenemuscle", 25 | }, 26 | { 27 | title: "E-mail", 28 | icon: ( 29 | 30 | ), 31 | href: "mmailto:somkeneoj@gmail.com", // Replace with your actual email 32 | }, 33 | { 34 | title: "Twitter", 35 | icon: ( 36 | 37 | ), 38 | href: "https://x.com/somkeneOj", 39 | } 40 | ]; 41 | 42 | return ( 43 |
44 | {/* */} 45 |
46 |
47 | Reach out to me
48 | 49 | somkeneoj@gmail.com 50 | 51 |
52 | 53 | {/* */} 54 |
55 | {contactlinks.map((link, index) => ( 56 | 64 | {link.icon} 65 | 66 | ))} 67 |
68 |
69 | 70 |
71 |
72 |
73 | Copyright 2024 - Ojukwu Somkene. 74 | 75 |
76 |
77 | ) 78 | } 79 | 80 | export default Contact -------------------------------------------------------------------------------- /components/shared/Skills.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { 3 | IconBrandReact, 4 | IconBrandMongodb, 5 | IconBrandTypescript, 6 | IconBrandNodejs, 7 | IconBrandDocker, 8 | IconBrandTailwind, 9 | IconBrandBootstrap, 10 | IconBrandNextjs, 11 | IconBrandJavascript, 12 | IconBrandHtml5, 13 | IconBrandCss3, 14 | IconServer2, 15 | } from "@tabler/icons-react"; 16 | import { motion } from "framer-motion"; 17 | import SlideIn from "./SlideIn"; 18 | 19 | function Skills() { 20 | const skills = [ 21 | { name: "HTML5", logo: }, 22 | { name: "CSS3", logo: }, 23 | { name: "JavaScript", logo: }, 24 | { name: "TypeScript", logo: }, 25 | { name: "Bootstrap", logo: }, 26 | { name: "Tailwind", logo: }, 27 | { name: "ReactJs", logo: }, 28 | { name: "Next.js", logo: }, 29 | { name: "Node.js", logo: }, 30 | { name: "Express", logo: }, 31 | { name: "MongoDB", logo: }, 32 | { name: "Docker", logo: } 33 | ]; 34 | 35 | // Animation variants for each skill 36 | const skillVariants = { 37 | hidden: { opacity: 0, y: 50 }, // Starting state 38 | visible: { opacity: 1, y: 0 }, // Ending state 39 | }; 40 | 41 | return ( 42 |
43 | 44 |

45 | These are the technologies i specialize in, drawn from my experience as a Frontend and Backend developer 46 |

47 |
48 |
49 | {skills.map((skill, index) => ( 50 | 59 | {skill.logo} 60 | {skill.name} 61 | 62 | ))} 63 |
64 |
65 | ); 66 | } 67 | 68 | export default Skills; 69 | -------------------------------------------------------------------------------- /components/shared/Projects.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import Image from "next/image"; 3 | import Link from "next/link"; 4 | import React from "react"; 5 | import SlideIn from "./SlideIn"; 6 | import { projectData } from "@/constants/projectData"; 7 | import { GitHubLogoIcon } from "@radix-ui/react-icons" 8 | 9 | export const Projects = () => { 10 | return ( 11 | 12 |
13 |
14 |

15 | Featured Projects 16 |

17 |

18 | Check out my selected projects to see my work in action. 19 |

20 |
21 | 22 |
23 | 24 | 25 | {projectData.map((project, index) => ( 26 |
34 | {/* Text Section */} 35 |
36 |
37 |

{project.title}

38 |

{project.description}

39 |
40 | {/* 41 | Case Study - 42 | */} 43 | 44 |
45 | 46 | Source Code ... 47 |
48 | 49 | 50 |
51 |
52 | {project.technologies.map((tech) => ( 53 | 57 | {tech} 58 | 59 | ))} 60 |
61 |
62 | 67 | Live Preview 68 | 69 |
70 | 71 | {/* Image Section */} 72 |
73 | {project.title} 81 |
82 |
83 | ))} 84 |
85 |
86 |
87 | 88 | 89 | 90 | ); 91 | }; 92 | -------------------------------------------------------------------------------- /components/shared/Navbar.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; // Indicate that this is a client-side rendered component 2 | import { useState } from 'react'; // Import useState and useEffect hooks from React 3 | import { Dialog, DialogPanel } from '@headlessui/react'; // Import Dialog and DialogPanel components from Headless UI 4 | import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'; // Import icons from Heroicons 5 | import Link from 'next/link'; // Import Link from Next.js 6 | import { navigation } from '@/constants/navigation'; 7 | 8 | const Navbar = () => { 9 | // State to control the mobile menu open/close 10 | const [mobileMenuOpen, setMobileMenuOpen] = useState(false); 11 | 12 | return ( 13 |
14 |
15 | 56 | 57 | {/* Mobile menu dialog */} 58 | 59 |
60 | 61 |
62 | {/* Company logo in mobile menu */} 63 | 64 | Your Company 65 |

Ojukwu Somkene

66 | 67 | 68 | {/* Button to close mobile menu */} 69 | 77 |
78 |
79 |
80 | {/* Navigation links in mobile menu */} 81 |
82 | {navigation.map((item) => ( 83 | 87 | {item.name} 88 | 89 | ))} 90 |
91 | {/* Log in link in mobile menu */} 92 | 93 |
94 | Let's Work! 95 |
96 | 97 | 98 |
99 |
100 |
101 |
102 |
103 |
104 | ); 105 | }; 106 | 107 | export default Navbar; 108 | -------------------------------------------------------------------------------- /components/ui/floating-dock.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Note: Use position fixed according to your needs 3 | * Desktop navbar is better positioned at the bottom 4 | * Mobile navbar is better positioned at bottom right. 5 | **/ 6 | 7 | import { cn } from "@/lib/utils"; 8 | import { IconLayoutNavbarCollapse } from "@tabler/icons-react"; 9 | import { 10 | AnimatePresence, 11 | MotionValue, 12 | motion, 13 | useMotionValue, 14 | useSpring, 15 | useTransform, 16 | } from "framer-motion"; 17 | import Link from "next/link"; 18 | import { useRef, useState } from "react"; 19 | 20 | export const FloatingDock = ({ 21 | items, 22 | desktopClassName, 23 | mobileClassName, 24 | }: { 25 | items: { title: string; icon: React.ReactNode; href: string }[]; 26 | desktopClassName?: string; 27 | mobileClassName?: string; 28 | }) => { 29 | return ( 30 | <> 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | const FloatingDockMobile = ({ 38 | items, 39 | className, 40 | }: { 41 | items: { title: string; icon: React.ReactNode; href: string }[]; 42 | className?: string; 43 | }) => { 44 | const [open, setOpen] = useState(false); 45 | return ( 46 |
47 | 48 | {open && ( 49 | 53 | {items.map((item, idx) => ( 54 | 70 | 75 |
{item.icon}
76 | 77 |
78 | ))} 79 |
80 | )} 81 |
82 | 88 |
89 | ); 90 | }; 91 | 92 | const FloatingDockDesktop = ({ 93 | items, 94 | className, 95 | }: { 96 | items: { title: string; icon: React.ReactNode; href: string }[]; 97 | className?: string; 98 | }) => { 99 | let mouseX = useMotionValue(Infinity); 100 | return ( 101 | mouseX.set(e.pageX)} 103 | onMouseLeave={() => mouseX.set(Infinity)} 104 | className={cn( 105 | "mx-auto hidden md:flex h-16 gap-4 items-end rounded-2xl bg-gray-50 dark:bg-neutral-900 px-4 pb-3", 106 | className 107 | )} 108 | > 109 | {items.map((item) => ( 110 | 111 | ))} 112 | 113 | ); 114 | }; 115 | 116 | function IconContainer({ 117 | mouseX, 118 | title, 119 | icon, 120 | href, 121 | }: { 122 | mouseX: MotionValue; 123 | title: string; 124 | icon: React.ReactNode; 125 | href: string; 126 | }) { 127 | let ref = useRef(null); 128 | 129 | let distance = useTransform(mouseX, (val) => { 130 | let bounds = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 }; 131 | 132 | return val - bounds.x - bounds.width / 2; 133 | }); 134 | 135 | let widthTransform = useTransform(distance, [-150, 0, 150], [40, 80, 40]); 136 | let heightTransform = useTransform(distance, [-150, 0, 150], [40, 80, 40]); 137 | 138 | let widthTransformIcon = useTransform(distance, [-150, 0, 150], [20, 40, 20]); 139 | let heightTransformIcon = useTransform( 140 | distance, 141 | [-150, 0, 150], 142 | [20, 40, 20] 143 | ); 144 | 145 | let width = useSpring(widthTransform, { 146 | mass: 0.1, 147 | stiffness: 150, 148 | damping: 12, 149 | }); 150 | let height = useSpring(heightTransform, { 151 | mass: 0.1, 152 | stiffness: 150, 153 | damping: 12, 154 | }); 155 | 156 | let widthIcon = useSpring(widthTransformIcon, { 157 | mass: 0.1, 158 | stiffness: 150, 159 | damping: 12, 160 | }); 161 | let heightIcon = useSpring(heightTransformIcon, { 162 | mass: 0.1, 163 | stiffness: 150, 164 | damping: 12, 165 | }); 166 | 167 | const [hovered, setHovered] = useState(false); 168 | 169 | return ( 170 | 171 | setHovered(true)} 175 | onMouseLeave={() => setHovered(false)} 176 | className="aspect-square rounded-full bg-gray-200 dark:bg-neutral-800 flex items-center justify-center relative" 177 | > 178 | 179 | {hovered && ( 180 | 186 | {title} 187 | 188 | )} 189 | 190 | 194 | {icon} 195 | 196 | 197 | 198 | ); 199 | } 200 | -------------------------------------------------------------------------------- /components/shared/About.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { 3 | IconBrandReact, 4 | IconBrandMongodb, 5 | IconBrandTypescript, 6 | IconBrandTailwind, 7 | IconBrandNextjs, 8 | IconBrandGit, 9 | IconServer2 10 | 11 | 12 | } from "@tabler/icons-react"; 13 | import SlideIn from "./SlideIn"; 14 | import { motion } from "framer-motion"; 15 | 16 | const About = () => { 17 | const technologies = [ 18 | { logo: , name: "React" }, 19 | { logo: , name: "Next.js" }, 20 | { logo: , name: "TypeScript" }, 21 | { logo: , name: "Express" }, 22 | { logo: , name: "MongoDB" }, 23 | ]; 24 | const technologies2 = [ 25 | { logo: , name: "React" }, 26 | { logo: , name: "Next.js" }, 27 | { logo: , name: "TypeScript" }, 28 | { logo: , name: "Tailwind" }, 29 | { logo: , name: "Git" }, 30 | 31 | ]; 32 | // Animation variants for each skill 33 | const skillVariants = { 34 | hidden: { opacity: 0, y: 50 }, // Starting state 35 | visible: { opacity: 1, y: 0 }, // Ending state 36 | }; 37 | 38 | 39 | return ( 40 | 41 |
42 |
43 | {/* Description */} 44 |
45 |

About Me

46 |

47 | With over 4 years of experience as a Full-stack developer , I have had a deep passion for creating and building things. My journey into 48 | software engineering was driven by my love for creation, which began with drawing and making music. This creative inclination naturally 49 | led me to explore the world of technology and software development. 50 |

51 |

52 | I specialize in both Frontend and Backend development, having worked extensively in both areas. I thrive on the continuous learning 53 | process that coding offers and relish the opportunity to apply new knowledge to solve real-world problems. Coding, for me, is more 54 | than just a profession, it is a hobby and a source of joy. 55 |

56 |

57 | In addition to my technical skills, I am a highly social person and have always found myself in leadership roles, guiding teams and 58 | fostering collaboration. One of the projects I am most proud of is Appvarsity, a platform I and my team developed 59 | to provide essential information and resources to Aptech students, helping them navigate their academic careers more effectively. 60 |

61 |

62 | I am always excited to take on new challenges and build innovative solutions that make a difference. Let's connect and see how we can 63 | create something amazing together! 64 |

65 | 66 | {/* Experience */} 67 |
68 |

Work Experience

69 |
    70 |
  • 71 |

    Founder & Full-Stack Developer, Appvarsity

    72 | Jan 2024 - Present 73 |

    74 | I Founded and led the development of Appvarsity, A platform designed to support Aptech students. I am responsible for overseeing both front-end and back-end development, managing the team, and ensuring we give valuable tools and essential resources to enhance students educational needs. 75 | Technologies Used 76 |

    77 |
    78 | {technologies.map((tech, index) => ( 79 | 88 | 95 | 96 | ))} 97 |
    98 |
  • 99 |
  • 100 |

    Frontend Developer Intern, Mindera

    101 | Jan 2023 - Jul 2023 102 |

    103 | I Focused on creating responsive user interfaces with a strong emphasis on performance and accessibility. I Leveraged agile methodologies to enhance teamwork and foster effective communication, contributing to a more cohesive and productive development process. 104 | Technologies Used 105 |

    106 |
    107 | {technologies2.map((tech, index) => ( 108 | 117 | 124 | 125 | ))} 126 |
    127 |
  • 128 |
129 |
130 |
131 |
132 |
133 |
134 | ); 135 | }; 136 | 137 | export default About; 138 | --------------------------------------------------------------------------------