├── 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 |
26 |
27 |
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 |
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 |
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 |
16 |
17 | {/* Company logo */}
18 |
19 |
Ojukwu Somkene
20 |
21 |
22 |
23 |
24 | {/* Button to open mobile menu on small screens */}
25 | setMobileMenuOpen(true)}
28 | className="-m-2.5 inline-flex items-center justify-center rounded-md p-2.5 text-gray-700"
29 | >
30 | Open main menu
31 |
32 |
33 |
34 |
35 |
36 | {/* Navigation links for large screens */}
37 | {navigation.map((item) => (
38 |
42 | {item.name}
43 |
44 | ))}
45 |
46 |
47 |
48 |
49 |
50 |
51 | Let's Work!
52 |
53 |
54 |
55 |
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 | setMobileMenuOpen(false)}
72 | className="-m-2.5 rounded-md p-2.5 text-gray-700"
73 | >
74 | Close menu
75 |
76 |
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 |
setOpen(!open)}
84 | className="h-10 w-10 rounded-full bg-gray-50 dark:bg-neutral-800 flex items-center justify-center"
85 | >
86 |
87 |
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 |
92 | {tech.logo}
93 | {tech.name}
94 |
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 |
121 | {tech.logo}
122 | {tech.name}
123 |
124 |
125 | ))}
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | );
135 | };
136 |
137 | export default About;
138 |
--------------------------------------------------------------------------------