└── Portfolio
└── portfolio
├── components
├── OpenSource.tsx
├── additionalhook.tsx
├── ReachOut.tsx
├── ui
│ ├── badge.tsx
│ ├── button.tsx
│ ├── card-spotlight.tsx
│ ├── tracing-beam.tsx
│ └── canvas-reveal-effect.tsx
├── magicui
│ ├── blur-fade.tsx
│ ├── icon-cloud.tsx
│ ├── bento-grid.tsx
│ ├── shimmer-button.tsx
│ ├── dock.tsx
│ └── particles.tsx
├── WorkExperience.tsx
├── connect.tsx
├── TechStack.tsx
├── ProjectCard.tsx
├── blogs.tsx
├── Aboutme.tsx
└── Projects.tsx
├── .eslintrc.json
├── app
├── favicon.ico
├── layout.tsx
├── globals.css
└── page.tsx
├── public
├── pfp.jpg
├── grid 3.avif
├── grid1.avif
├── grid2.webp
├── grid4.avif
├── grid5.avif
├── campussync.jpg
├── portfolio.jpg
├── 1--xbrainly.jpg
├── Rahul_Resume.pdf
├── Resume_rahul.pdf
├── deliverimage.jpg
├── insocialImage.jpg
├── chillguyanalyzer.png
├── vercel.svg
└── next.svg
├── next.config.mjs
├── postcss.config.mjs
├── lib
└── utils.ts
├── components.json
├── .gitignore
├── tsconfig.json
├── package.json
├── README.md
└── tailwind.config.ts
/Portfolio/portfolio/components/OpenSource.tsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/app/favicon.ico
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/pfp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/pfp.jpg
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/grid 3.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/grid 3.avif
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/grid1.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/grid1.avif
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/grid2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/grid2.webp
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/grid4.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/grid4.avif
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/grid5.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/grid5.avif
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/campussync.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/campussync.jpg
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/portfolio.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/portfolio.jpg
--------------------------------------------------------------------------------
/Portfolio/portfolio/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | export default nextConfig;
5 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/1--xbrainly.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/1--xbrainly.jpg
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/Rahul_Resume.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/Rahul_Resume.pdf
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/Resume_rahul.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/Resume_rahul.pdf
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/deliverimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/deliverimage.jpg
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/insocialImage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/insocialImage.jpg
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/chillguyanalyzer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wraith2009/Portfolio/HEAD/Portfolio/portfolio/public/chillguyanalyzer.png
--------------------------------------------------------------------------------
/Portfolio/portfolio/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 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/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 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": true,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.ts",
8 | "css": "app/globals.css",
9 | "baseColor": "zinc",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils",
16 | "ui": "@/components/ui",
17 | "magicui": "@/components/magicui"
18 | }
19 | }
--------------------------------------------------------------------------------
/Portfolio/portfolio/.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 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/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 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from "next";
2 | import { Inter } from "next/font/google";
3 | import "./globals.css";
4 | import SocialDock from "@/components/connect";
5 | import { Analytics } from "@vercel/analytics/react";
6 |
7 | const inter = Inter({ subsets: ["latin"] });
8 |
9 | export const metadata: Metadata = {
10 | title: "Rahul Bhardwaj",
11 | description: "Rahul's Portfolio",
12 | };
13 |
14 | export default function RootLayout({
15 | children,
16 | }: Readonly<{
17 | children: React.ReactNode;
18 | }>) {
19 | return (
20 |
21 |
22 |
23 | {children}
24 |
25 |
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/additionalhook.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, RefObject } from "react";
2 |
3 | export function useOnScreen(ref: RefObject): boolean {
4 | const [isIntersecting, setIntersecting] = useState(false);
5 |
6 | useEffect(() => {
7 | const observer = new IntersectionObserver(
8 | ([entry]) => setIntersecting(entry.isIntersecting),
9 | { threshold: 0.1 } // Adjust this threshold as needed
10 | );
11 |
12 | const currentRef = ref.current;
13 |
14 | if (currentRef) {
15 | observer.observe(currentRef);
16 | }
17 |
18 | return () => {
19 | if (currentRef) {
20 | observer.unobserve(currentRef);
21 | }
22 | };
23 | }, [ref]);
24 |
25 | return isIntersecting;
26 | }
27 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/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 | "@heroicons/react": "^2.2.0",
13 | "@radix-ui/react-icons": "^1.3.0",
14 | "@radix-ui/react-slot": "^1.1.0",
15 | "@react-three/fiber": "^8.17.7",
16 | "@vercel/analytics": "^1.3.1",
17 | "class-variance-authority": "^0.7.0",
18 | "clsx": "^2.1.1",
19 | "framer-motion": "^11.11.9",
20 | "next": "14.2.5",
21 | "next-themes": "^0.3.0",
22 | "react": "^18",
23 | "react-dom": "^18",
24 | "react-icon-cloud": "^4.1.4",
25 | "react-icons": "^5.4.0",
26 | "tailwind-merge": "^2.5.4",
27 | "tailwindcss-animate": "^1.0.7",
28 | "three": "^0.168.0"
29 | },
30 | "devDependencies": {
31 | "@types/node": "^20",
32 | "@types/react": "^18",
33 | "@types/react-dom": "^18",
34 | "@types/three": "^0.168.0",
35 | "eslint": "^8",
36 | "eslint-config-next": "14.2.5",
37 | "postcss": "^8",
38 | "tailwindcss": "^3.4.1",
39 | "typescript": "^5"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/ReachOut.tsx:
--------------------------------------------------------------------------------
1 |
2 |
3 | // export default function ReachOut(){
4 | // return (
5 | //
6 | //
7 | // Thank you for visiting my portfolio!
8 | //
9 | //
10 | // If you’re looking for someone to help bring your ideas to life, I’d be excited to collaborate with you. Whether you need a creative solution, technical expertise, or someone to work closely with your team, I’m here to contribute in any way I can.
11 | //
12 | //
13 | // Feel free to reach out if you’re interested in hiring me or partnering on a project.
14 | //
15 | //
16 | // You can contact me at rbh97995@gmail.com .
17 | //
18 | //
19 | // I look forward to seeing how we can create something great together!
20 | //
21 | //
22 | // )
23 | // }
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/ui/badge.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { cva, type VariantProps } from "class-variance-authority"
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const badgeVariants = cva(
7 | "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
8 | {
9 | variants: {
10 | variant: {
11 | default:
12 | "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
13 | secondary:
14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15 | destructive:
16 | "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
17 | outline: "text-foreground",
18 | },
19 | },
20 | defaultVariants: {
21 | variant: "default",
22 | },
23 | }
24 | )
25 |
26 | export interface BadgeProps
27 | extends React.HTMLAttributes,
28 | VariantProps {}
29 |
30 | function Badge({ className, variant, ...props }: BadgeProps) {
31 | return (
32 |
33 | )
34 | }
35 |
36 | export { Badge, badgeVariants }
--------------------------------------------------------------------------------
/Portfolio/portfolio/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/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 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/magicui/blur-fade.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useRef } from "react";
4 | import {
5 | AnimatePresence,
6 | motion,
7 | useInView,
8 | UseInViewOptions,
9 | Variants,
10 | } from "framer-motion";
11 |
12 | type MarginType = UseInViewOptions["margin"];
13 |
14 | interface BlurFadeProps {
15 | children: React.ReactNode;
16 | className?: string;
17 | variant?: {
18 | hidden: { y: number };
19 | visible: { y: number };
20 | };
21 | duration?: number;
22 | delay?: number;
23 | yOffset?: number;
24 | inView?: boolean;
25 | inViewMargin?: MarginType;
26 | blur?: string;
27 | }
28 |
29 | export default function BlurFade({
30 | children,
31 | className,
32 | variant,
33 | duration = 0.4,
34 | delay = 0,
35 | yOffset = 6,
36 | inView = false,
37 | inViewMargin = "-50px",
38 | blur = "6px",
39 | }: BlurFadeProps) {
40 | const ref = useRef(null);
41 | const inViewResult = useInView(ref, { once: true, margin: inViewMargin });
42 | const isInView = !inView || inViewResult;
43 | const defaultVariants: Variants = {
44 | hidden: { y: yOffset, opacity: 0, filter: `blur(${blur})` },
45 | visible: { y: -yOffset, opacity: 1, filter: `blur(0px)` },
46 | };
47 | const combinedVariants = variant || defaultVariants;
48 | return (
49 |
50 |
63 | {children}
64 |
65 |
66 | );
67 | }
68 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/WorkExperience.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { HiMiniBuildingOffice2 } from "react-icons/hi2";
3 | interface WorkExperienceProps {
4 | position: string;
5 | companyName: string;
6 | timePeriod: string;
7 | }
8 |
9 | const WorkExperience: React.FC = ({
10 | position,
11 | companyName,
12 | timePeriod,
13 | }) => {
14 | return (
15 |
16 |
17 |
{companyName}
18 |
{position}
19 |
{timePeriod}
20 |
21 |
22 | );
23 | };
24 |
25 | export default function MyWorkExperience() {
26 | return (
27 |
28 |
29 |
Work Experience
30 |
31 |
Places I have worked at
32 |
33 |
34 |
39 |
40 |
45 |
46 |
51 |
52 |
57 |
58 |
59 | );
60 | }
61 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/connect.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { FaEnvelope, FaTwitter, FaGithub, FaHome } from "react-icons/fa";
4 | import { Dock, DockIcon } from "./magicui/dock";
5 |
6 | export default function SocialDock() {
7 | return (
8 |
64 | );
65 | }
66 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | :root {
7 | --background: 0 0% 100%;
8 | --foreground: 240 10% 3.9%;
9 | --card: 0 0% 100%;
10 | --card-foreground: 240 10% 3.9%;
11 | --popover: 0 0% 100%;
12 | --popover-foreground: 240 10% 3.9%;
13 | --primary: 240 5.9% 10%;
14 | --primary-foreground: 0 0% 98%;
15 | --secondary: 240 4.8% 95.9%;
16 | --secondary-foreground: 240 5.9% 10%;
17 | --muted: 240 4.8% 95.9%;
18 | --muted-foreground: 240 3.8% 46.1%;
19 | --accent: 240 4.8% 95.9%;
20 | --accent-foreground: 240 5.9% 10%;
21 | --destructive: 0 84.2% 60.2%;
22 | --destructive-foreground: 0 0% 98%;
23 | --border: 240 5.9% 90%;
24 | --input: 240 5.9% 90%;
25 | --ring: 240 10% 3.9%;
26 | --radius: 0.5rem;
27 | --chart-1: 12 76% 61%;
28 | --chart-2: 173 58% 39%;
29 | --chart-3: 197 37% 24%;
30 | --chart-4: 43 74% 66%;
31 | --chart-5: 27 87% 67%;
32 | }
33 |
34 | .dark {
35 | --background: 240 10% 3.9%;
36 | --foreground: 0 0% 98%;
37 | --card: 240 10% 3.9%;
38 | --card-foreground: 0 0% 98%;
39 | --popover: 240 10% 3.9%;
40 | --popover-foreground: 0 0% 98%;
41 | --primary: 0 0% 98%;
42 | --primary-foreground: 240 5.9% 10%;
43 | --secondary: 240 3.7% 15.9%;
44 | --secondary-foreground: 0 0% 98%;
45 | --muted: 240 3.7% 15.9%;
46 | --muted-foreground: 240 5% 64.9%;
47 | --accent: 240 3.7% 15.9%;
48 | --accent-foreground: 0 0% 98%;
49 | --destructive: 0 62.8% 30.6%;
50 | --destructive-foreground: 0 0% 98%;
51 | --border: 240 3.7% 15.9%;
52 | --input: 240 3.7% 15.9%;
53 | --ring: 240 4.9% 83.9%;
54 | --chart-1: 220 70% 50%;
55 | --chart-2: 160 60% 45%;
56 | --chart-3: 30 80% 55%;
57 | --chart-4: 280 65% 60%;
58 | --chart-5: 340 75% 55%;
59 | }
60 | }
61 |
62 | @layer base {
63 | * {
64 | @apply border-border;
65 | }
66 | body {
67 | @apply bg-background text-foreground;
68 | }
69 | }
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Slot } from "@radix-ui/react-slot"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
9 | {
10 | variants: {
11 | variant: {
12 | default:
13 | "bg-primary text-primary-foreground shadow hover:bg-primary/90",
14 | destructive:
15 | "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
16 | outline:
17 | "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
18 | secondary:
19 | "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
20 | ghost: "hover:bg-accent hover:text-accent-foreground",
21 | link: "text-primary underline-offset-4 hover:underline",
22 | },
23 | size: {
24 | default: "h-9 px-4 py-2",
25 | sm: "h-8 rounded-md px-3 text-xs",
26 | lg: "h-10 rounded-md px-8",
27 | icon: "h-9 w-9",
28 | },
29 | },
30 | defaultVariants: {
31 | variant: "default",
32 | size: "default",
33 | },
34 | }
35 | )
36 |
37 | export interface ButtonProps
38 | extends React.ButtonHTMLAttributes,
39 | VariantProps {
40 | asChild?: boolean
41 | }
42 |
43 | const Button = React.forwardRef(
44 | ({ className, variant, size, asChild = false, ...props }, ref) => {
45 | const Comp = asChild ? Slot : "button"
46 | return (
47 |
52 | )
53 | }
54 | )
55 | Button.displayName = "Button"
56 |
57 | export { Button, buttonVariants }
58 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/TechStack.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import IconCloud from "./magicui/icon-cloud";
4 | import BlurFade from "./magicui/blur-fade"; // Use the IconCloud component you've defined
5 | import { i } from "framer-motion/client";
6 | import { Badge } from "./ui/badge";
7 |
8 | const BLUR_FADE_DELAY = 0.04;
9 | export default function TechStackSection() {
10 | const techStackIcons = [
11 | "typescript",
12 | "javascript",
13 | "dart",
14 | "java",
15 | "rust",
16 | "react",
17 | "nextdotjs",
18 | "linux",
19 | "flutter",
20 | "android",
21 | "html5",
22 | "css3",
23 | "nodedotjs",
24 | "express",
25 | "prisma",
26 | "postgresql",
27 | "docker",
28 | "firebase",
29 | "vercel",
30 | "testinglibrary",
31 | "jest",
32 | "cypress",
33 | "docker",
34 | "git",
35 | "mongodb",
36 | "mysql",
37 | "github",
38 | "visualstudiocode",
39 | "figma",
40 | ];
41 |
42 | const skills = [
43 | "React",
44 | "Next.js",
45 | "Typescript",
46 | "Node.js",
47 | "Postgres",
48 | "MongoDB",
49 | "Express",
50 | "C++",
51 | "git",
52 | "GitHub",
53 | "Javascript",
54 | ];
55 |
56 | return (
57 |
58 |
59 | My Tech Stacks
60 |
61 |
62 |
63 |
64 | Skills
65 |
66 |
67 | {skills.map((skill, id) => (
68 |
69 | {skill}
70 |
71 | ))}
72 |
73 |
74 |
75 |
76 |
77 |
78 | );
79 | }
80 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/ProjectCard.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { FiGithub, FiLink2 } from "react-icons/fi";
3 | import Image from "next/image";
4 | import { Badge } from "./ui/badge";
5 |
6 | interface FeaturedProjectComponentProps {
7 | imageSrc?: string;
8 | projectName: string;
9 | description: string;
10 | technologies: string[];
11 | github: string;
12 | live: string;
13 | }
14 |
15 | const FeaturedProjectComponent: React.FC = ({
16 | imageSrc,
17 | projectName,
18 | description,
19 | technologies,
20 | github,
21 | live,
22 | }) => {
23 | const [isExpanded, setIsExpanded] = useState(false);
24 |
25 | return (
26 |
27 |
28 |
29 | {projectName}
30 |
31 |
36 | {description}
37 |
38 |
39 |
40 | {technologies.map((tech, index) => (
41 | {tech}
42 | ))}
43 |
44 |
66 |
67 |
68 | );
69 | };
70 |
71 | export default FeaturedProjectComponent;
72 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/magicui/icon-cloud.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useEffect, useMemo, useState } from "react";
4 | import { useTheme } from "next-themes";
5 | import {
6 | Cloud,
7 | fetchSimpleIcons,
8 | ICloud,
9 | renderSimpleIcon,
10 | SimpleIcon,
11 | } from "react-icon-cloud";
12 |
13 | export const cloudProps: Omit = {
14 | containerProps: {
15 | style: {
16 | display: "flex",
17 | justifyContent: "center",
18 | alignItems: "center",
19 | width: "100%",
20 | paddingTop: 40,
21 | },
22 | },
23 | options: {
24 | reverse: true,
25 | depth: 1,
26 | wheelZoom: false,
27 | imageScale: 2,
28 | activeCursor: "default",
29 | tooltip: "native",
30 | initial: [0.1, -0.1],
31 | clickToFront: 500,
32 | tooltipDelay: 0,
33 | outlineColour: "#0000",
34 | maxSpeed: 0.04,
35 | minSpeed: 0.02,
36 | // dragControl: false,
37 | },
38 | };
39 |
40 | export const renderCustomIcon = (icon: SimpleIcon, theme: string) => {
41 | const bgHex = theme === "light" ? "#f3f2ef" : "#080510";
42 | const fallbackHex = theme === "light" ? "#6e6e73" : "#ffffff";
43 | const minContrastRatio = theme === "dark" ? 2 : 1.2;
44 |
45 | return renderSimpleIcon({
46 | icon,
47 | bgHex,
48 | fallbackHex,
49 | minContrastRatio,
50 | size: 42,
51 | aProps: {
52 | href: undefined,
53 | target: undefined,
54 | rel: undefined,
55 | onClick: (e: any) => e.preventDefault(),
56 | },
57 | });
58 | };
59 |
60 | export type DynamicCloudProps = {
61 | iconSlugs: string[];
62 | };
63 |
64 | type IconData = Awaited>;
65 |
66 | export default function IconCloud({ iconSlugs }: DynamicCloudProps) {
67 | const [data, setData] = useState(null);
68 | const { theme } = useTheme();
69 |
70 | useEffect(() => {
71 | fetchSimpleIcons({ slugs: iconSlugs }).then(setData);
72 | }, [iconSlugs]);
73 |
74 | const renderedIcons = useMemo(() => {
75 | if (!data) return null;
76 |
77 | return Object.values(data.simpleIcons).map((icon) =>
78 | renderCustomIcon(icon, theme || "light"),
79 | );
80 | }, [data, theme]);
81 |
82 | return (
83 | // @ts-ignore
84 |
85 | <>{renderedIcons}>
86 |
87 | );
88 | }
89 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/ui/card-spotlight.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useMotionValue, motion, useMotionTemplate } from "framer-motion";
4 | import React, { MouseEvent as ReactMouseEvent, useState } from "react";
5 | import { CanvasRevealEffect } from "@/components/ui/canvas-reveal-effect";
6 | import { cn } from "@/lib/utils";
7 |
8 | export const CardSpotlight = ({
9 | children,
10 | radius = 350,
11 | color = "#262626",
12 | className,
13 | ...props
14 | }: {
15 | radius?: number;
16 | color?: string;
17 | children: React.ReactNode;
18 | } & React.HTMLAttributes) => {
19 | const mouseX = useMotionValue(0);
20 | const mouseY = useMotionValue(0);
21 | function handleMouseMove({
22 | currentTarget,
23 | clientX,
24 | clientY,
25 | }: ReactMouseEvent) {
26 | let { left, top } = currentTarget.getBoundingClientRect();
27 |
28 | mouseX.set(clientX - left);
29 | mouseY.set(clientY - top);
30 | }
31 |
32 | const [isHovering, setIsHovering] = useState(false);
33 | const handleMouseEnter = () => setIsHovering(true);
34 | const handleMouseLeave = () => setIsHovering(false);
35 | return (
36 |
46 |
59 | {isHovering && (
60 |
69 | )}
70 |
71 | {children}
72 |
73 | );
74 | };
75 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/blogs.tsx:
--------------------------------------------------------------------------------
1 | export default function Blogs_section() {
2 | const blogs = [
3 | {
4 | date: "Mar 08, 2025",
5 | title: "How vector search works",
6 | link: "https://medium.com/@rbh97995/how-vector-search-works-1f965e167a63",
7 | },
8 | {
9 | date: "May 08, 2025",
10 | title: "Understanding Phantom Reads: Ghosts in Your Database",
11 | link: "https://medium.com/@rbh97995/understanding-phantom-reads-ghosts-in-your-database-2e2964caf96b",
12 | },
13 | {
14 | date: "May 25, 2025",
15 | title:
16 | "Eventual Consistency in Distributed Systems: A Real-World Perspective",
17 | link: "https://medium.com/@rbh97995/eventual-consistency-in-distributed-systems-a-real-world-perspective-1175fd0f742b",
18 | },
19 | {
20 | date: "June 2, 2025",
21 | title:
22 | "From Monolith to Microservice: Designing a Centralized Payment System for a Growing EdTech Platform",
23 | link: "https://medium.com/@rbh97995/from-monolith-to-microservice-designing-a-centralized-payment-system-for-a-growing-edtech-platform-23539a4d89ff",
24 | },
25 | {
26 | date: "June 30, 2025",
27 | title:
28 | "Understanding Processes in Operating Systems: The Beating Heart of Your Computer",
29 | link: "https://medium.com/@rbh97995/understanding-processes-in-operating-systems-the-beating-heart-of-your-computer-ae1734a57392",
30 | },
31 | {
32 | date: "July 07, 2025",
33 | title: "How Computers Talk: A Deep Dive into Host-to-Host Communication",
34 | link: "https://medium.com/@rahulbhardwaj09/how-computers-talk-a-deep-dive-into-host-to-host-communication-2210494ea0fa",
35 | },
36 | ];
37 |
38 | return (
39 |
40 |
41 |
42 |
Recent blog posts
43 |
44 |
Things I have written recently.
45 |
46 | {blogs.map((blog, index) => (
47 |
48 | •
49 |
50 | {blog.date} :
51 |
52 |
58 | {blog.title}
59 |
60 |
61 | ))}
62 |
63 |
64 |
65 | );
66 | }
67 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/magicui/bento-grid.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from "react";
2 | import { ArrowRightIcon } from "@radix-ui/react-icons";
3 |
4 | import { cn } from "@/lib/utils";
5 | import { Button } from "@/components/ui/button";
6 |
7 | const BentoGrid = ({
8 | children,
9 | className,
10 | }: {
11 | children: ReactNode;
12 | className?: string;
13 | }) => {
14 | return (
15 |
21 | {children}
22 |
23 | );
24 | };
25 |
26 | const BentoCard = ({
27 | name,
28 | className,
29 | background,
30 | Icon,
31 | description,
32 | img,
33 | imgClassName,
34 | href,
35 | cta,
36 | }: {
37 | name: string;
38 | className: string;
39 | background: ReactNode;
40 | Icon: any;
41 | description: string;
42 | img?: string;
43 | imgClassName?: string;
44 | href: string;
45 | cta: string;
46 | }) => (
47 |
58 |
59 | {img && (
60 |
65 | )}
66 |
67 |
68 |
69 |
70 | {name}
71 |
72 |
{description}
73 |
74 |
75 |
87 |
88 |
89 | );
90 |
91 | export { BentoCard, BentoGrid };
92 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/Aboutme.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { BentoGrid, BentoCard } from "./magicui/bento-grid";
4 | import { FaEnvelope, FaLink, FaUserTie, FaLaptopCode } from "react-icons/fa";
5 |
6 | const About = () => {
7 | return (
8 |
9 |
10 | About Me
11 |
12 |
13 |
14 |
19 | }
20 | Icon={FaUserTie}
21 | img="/grid4.avif"
22 | imgClassName="w-full h-full"
23 | description="A Software Developer with almost 1 year of experience. I specialize in MERN stack development and am passionate about creating innovative technologies."
24 | href="https://www.linkedin.com/in/rahulbhardwaj09/"
25 | cta="Read more"
26 | />
27 |
28 |
33 | }
34 | Icon={FaLaptopCode}
35 | img="/grid 3.avif"
36 | imgClassName="w-full h-full"
37 | description="With experience working with clients and companies, I focus on building full-stack applications that deliver seamless user experiences."
38 | href="https://github.com/wraith2009"
39 | cta="See My Work"
40 | />
41 |
42 |
47 | }
48 | Icon={FaLink}
49 | img="/grid 3.avif"
50 | imgClassName="w-full h-full"
51 | description="I am always looking to collaborate on new and exciting projects. Whether it is for technical expertise or creative solutions, I am ready to contribute."
52 | href="https://x.com/10xRahul_"
53 | cta="Contact Me"
54 | />
55 |
56 |
61 | }
62 | Icon={FaEnvelope}
63 | img="/grid5.avif"
64 | imgClassName="w-full h-full"
65 | description="Feel free to reach out via email if you want to hire me or collaborate on a project. Let us create something amazing together!"
66 | href="mailto:rbh97995@gmail.com"
67 | cta="Send Mail"
68 | />
69 |
70 |
71 | );
72 | };
73 |
74 | export default About;
75 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/magicui/shimmer-button.tsx:
--------------------------------------------------------------------------------
1 | import React, { CSSProperties } from "react";
2 |
3 | import { cn } from "@/lib/utils";
4 |
5 | export interface ShimmerButtonProps
6 | extends React.ButtonHTMLAttributes {
7 | shimmerColor?: string;
8 | shimmerSize?: string;
9 | borderRadius?: string;
10 | shimmerDuration?: string;
11 | background?: string;
12 | className?: string;
13 | children?: React.ReactNode;
14 | }
15 |
16 | const ShimmerButton = React.forwardRef(
17 | (
18 | {
19 | shimmerColor = "#ffffff",
20 | shimmerSize = "0.05em",
21 | shimmerDuration = "3s",
22 | borderRadius = "100px",
23 | background = "rgba(0, 0, 0, 1)",
24 | className,
25 | children,
26 | ...props
27 | },
28 | ref,
29 | ) => {
30 | return (
31 |
50 | {/* spark container */}
51 |
57 | {/* spark */}
58 |
59 | {/* spark before */}
60 |
61 |
62 |
63 | {children}
64 |
65 | {/* Highlight */}
66 |
82 |
83 | {/* backdrop */}
84 |
89 |
90 | );
91 | },
92 | );
93 |
94 | ShimmerButton.displayName = "ShimmerButton";
95 |
96 | export default ShimmerButton;
97 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/magicui/dock.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React, { PropsWithChildren, useRef } from "react";
4 | import { cva, type VariantProps } from "class-variance-authority";
5 | import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
6 |
7 | import { cn } from "@/lib/utils";
8 |
9 | export interface DockProps extends VariantProps {
10 | className?: string;
11 | magnification?: number;
12 | distance?: number;
13 | direction?: "top" | "middle" | "bottom";
14 | children: React.ReactNode;
15 | }
16 |
17 | const DEFAULT_MAGNIFICATION = 60;
18 | const DEFAULT_DISTANCE = 140;
19 |
20 | const dockVariants = cva(
21 | "mx-auto w-max mt-8 h-[58px] p-2 flex gap-2 rounded-2xl border supports-backdrop-blur:bg-white/10 supports-backdrop-blur:dark:bg-black/10 backdrop-blur-md",
22 | );
23 |
24 | const Dock = React.forwardRef(
25 | (
26 | {
27 | className,
28 | children,
29 | magnification = DEFAULT_MAGNIFICATION,
30 | distance = DEFAULT_DISTANCE,
31 | direction = "bottom",
32 | ...props
33 | },
34 | ref,
35 | ) => {
36 | const mousex = useMotionValue(Infinity);
37 |
38 | const renderChildren = () => {
39 | return React.Children.map(children, (child: any) => {
40 | return React.cloneElement(child, {
41 | mousex: mousex,
42 | magnification: magnification,
43 | distance: distance,
44 | });
45 | });
46 | };
47 |
48 | return (
49 | mousex.set(e.pageX)}
52 | onMouseLeave={() => mousex.set(Infinity)}
53 | {...props}
54 | className={cn(dockVariants({ className }), {
55 | "items-start": direction === "top",
56 | "items-center": direction === "middle",
57 | "items-end": direction === "bottom",
58 | })}
59 | >
60 | {renderChildren()}
61 |
62 | );
63 | },
64 | );
65 |
66 | Dock.displayName = "Dock";
67 |
68 | export interface DockIconProps {
69 | size?: number;
70 | magnification?: number;
71 | distance?: number;
72 | mousex?: any;
73 | className?: string;
74 | children?: React.ReactNode;
75 | props?: PropsWithChildren;
76 | }
77 |
78 | const DockIcon = ({
79 | size,
80 | magnification = DEFAULT_MAGNIFICATION,
81 | distance = DEFAULT_DISTANCE,
82 | mousex,
83 | className,
84 | children,
85 | ...props
86 | }: DockIconProps) => {
87 | const ref = useRef(null);
88 |
89 | const distanceCalc = useTransform(mousex, (val: number) => {
90 | const bounds = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 };
91 |
92 | return val - bounds.x - bounds.width / 2;
93 | });
94 |
95 | let widthSync = useTransform(
96 | distanceCalc,
97 | [-distance, 0, distance],
98 | [40, magnification, 40],
99 | );
100 |
101 | let width = useSpring(widthSync, {
102 | mass: 0.1,
103 | stiffness: 150,
104 | damping: 12,
105 | });
106 |
107 | return (
108 |
117 | {children}
118 |
119 | );
120 | };
121 |
122 | DockIcon.displayName = "DockIcon";
123 |
124 | export { Dock, DockIcon, dockVariants };
125 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/Projects.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React, { useRef } from "react";
4 | import ProjectComponent from "./ProjectCard";
5 | import { useOnScreen } from "./additionalhook";
6 |
7 | const Projects: React.FC = () => {
8 | const projectsRef = useRef(null);
9 | const isVisible = useOnScreen(projectsRef);
10 |
11 | const projectData = [
12 | {
13 | projectName: "w-Monitor",
14 | description:
15 | "Currently in the building phase, A modern website and API monitoring platform with alerting.",
16 | technologies: [
17 | "React.js",
18 | "TypeScript",
19 | "Tailwind CSS",
20 | "SQS",
21 | "AWS Lambda",
22 | ],
23 | github: "https://github.com/wraith2009/w-monitor-backend",
24 | live: "#", // In building phase
25 | },
26 | {
27 | projectName: "ts-orm",
28 | description:
29 | " Currently in active development . A TypeScript-first ORM designed for fun.",
30 | technologies: ["TypeScript", "Node.js", "PostgreSQL", "Zod"],
31 | github: "https://github.com/wraith2009/ts-orm",
32 | live: "#", // In building phase
33 | },
34 | {
35 | projectName: "100xBrainly",
36 | description:
37 | "A personal Secound Brain with AI feature to communicate with your secound brain.",
38 | technologies: [
39 | "React.js",
40 | "TypeScript",
41 | "Tailwind CSS",
42 | "ExpressJs",
43 | "Node.js",
44 | "Recoil",
45 | ],
46 | github: "https://github.com/wraith2009/brainlyFrontend",
47 | live: "https://brainly-frontend-sable.vercel.app/",
48 | },
49 |
50 | {
51 | projectName: "inSocial",
52 | description: "A social media platform with real time messaging.",
53 | technologies: [
54 | "Node.js",
55 | "Express",
56 | "React.js",
57 | "Tailwind CSS",
58 | "WebSockets",
59 | "MongoDB",
60 | "Google Gemini",
61 | ],
62 | github: "https://github.com/mayank2153/inSocial",
63 | live: "#",
64 | },
65 | {
66 | projectName: "ChillGuyAnalyzer",
67 | description:
68 | "A fun project that i worked on . It measure the chillness of a person using AI based on their Github profile.",
69 | technologies: [
70 | "React.js",
71 | "TypeScript",
72 | "Tailwind CSS",
73 | "Honojs",
74 | "OpenAI",
75 | ],
76 | github: "https://github.com/wraith2009/ChillGuyAnalyzer",
77 | live: "https://chillguyanalyzer.onrender.com/",
78 | },
79 | ];
80 |
81 | return (
82 |
89 |
90 | Projects
91 |
92 |
93 | {projectData.map((project, index) => (
94 |
102 | ))}
103 |
104 |
105 | );
106 | };
107 |
108 | export default Projects;
109 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/ui/tracing-beam.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import React, { useEffect, useRef, useState } from "react";
3 | import {
4 | motion,
5 | useTransform,
6 | useScroll,
7 | useVelocity,
8 | useSpring,
9 | } from "framer-motion";
10 | import { cn } from "@/lib/utils";
11 |
12 | export const TracingBeam = ({
13 | children,
14 | className,
15 | }: {
16 | children: React.ReactNode;
17 | className?: string;
18 | }) => {
19 | const ref = useRef(null);
20 | const { scrollYProgress } = useScroll({
21 | target: ref,
22 | offset: ["start start", "end start"],
23 | });
24 |
25 | const contentRef = useRef(null);
26 | const [svgHeight, setSvgHeight] = useState(0);
27 |
28 | useEffect(() => {
29 | if (contentRef.current) {
30 | setSvgHeight(contentRef.current.offsetHeight);
31 | }
32 | }, []);
33 |
34 | const y1 = useSpring(
35 | useTransform(scrollYProgress, [0, 0.8], [50, svgHeight]),
36 | {
37 | stiffness: 500,
38 | damping: 90,
39 | }
40 | );
41 | const y2 = useSpring(
42 | useTransform(scrollYProgress, [0, 1], [50, svgHeight - 200]),
43 | {
44 | stiffness: 500,
45 | damping: 90,
46 | }
47 | );
48 |
49 | return (
50 |
54 |
55 | 0
63 | ? "none"
64 | : "rgba(0, 0, 0, 0.24) 0px 3px 8px",
65 | }}
66 | className="ml-[27px] h-4 w-4 rounded-full border border-netural-200 shadow-sm flex items-center justify-center"
67 | >
68 | 0 ? "white" : "var(--emerald-500)",
76 | borderColor:
77 | scrollYProgress.get() > 0 ? "white" : "var(--emerald-600)",
78 | }}
79 | className="h-2 w-2 rounded-full border border-neutral-300 bg-white"
80 | />
81 |
82 |
89 |
98 |
108 |
109 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | {children}
126 |
127 | );
128 | };
129 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/app/page.tsx:
--------------------------------------------------------------------------------
1 | "use client"; // <-- This ensures everything runs on the client-side
2 |
3 | import { motion } from "framer-motion";
4 | import ShimmerButton from "@/components/magicui/shimmer-button";
5 | import TechStackSection from "@/components/TechStack";
6 | import MyProjects from "@/components/Projects";
7 | import MyWorkExperience from "@/components/WorkExperience";
8 | import AboutMe from "@/components/Aboutme";
9 | import Blogs_section from "@/components/blogs";
10 |
11 | const fadeInUp = {
12 | hidden: { opacity: 0, y: 50 },
13 | visible: { opacity: 1, y: 0, transition: { duration: 0.8 } },
14 | };
15 |
16 | export default function Home() {
17 | return (
18 |
19 |
26 | Hi, my name is
27 |
28 | Rahul Bhardwaj.
29 |
30 |
31 | I build things for the web.
32 |
33 |
34 | I’m a full-stack developer from India. I specialize in turning ideas
35 | into fully functional web applications. Whether you’re building a
36 | product from the ground up or improving an existing one, I can help
37 | bring your vision to life with clean, efficient code.
38 |
39 |
46 |
51 |
52 | Resume
53 |
54 |
55 |
56 |
57 |
58 |
65 |
66 |
67 |
68 |
75 |
76 |
77 |
78 |
85 |
86 |
87 | {/*
88 |
94 |
95 |
96 |
97 |
104 |
105 | */}
106 |
112 |
113 | © 2024 Rahul Bhardwaj. All rights reserved.
114 | Made with ❤️ by Rahul Bhardwaj
115 |
116 |
117 |
118 | );
119 | }
120 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss"
2 | const defaultTheme = require("tailwindcss/defaultTheme");
3 | const colors = require("tailwindcss/colors");
4 | const {
5 | default: flattenColorPalette,
6 | } = require("tailwindcss/lib/util/flattenColorPalette");
7 |
8 | const config = {
9 | darkMode: ["class"],
10 | content: [
11 | './pages/**/*.{ts,tsx}',
12 | './components/**/*.{ts,tsx}',
13 | './app/**/*.{ts,tsx}',
14 | './src/**/*.{ts,tsx}',
15 | ],
16 | prefix: "",
17 | theme: {
18 | container: {
19 | center: true,
20 | padding: "2rem",
21 | screens: {
22 | "2xl": "1400px",
23 | },
24 | },
25 | extend: {
26 | fontFamily: {
27 | montserrat: ['Montserrat', 'sans-serif'],
28 | },
29 | colors: {
30 | border: "hsl(var(--border))",
31 | input: "hsl(var(--input))",
32 | ring: "hsl(var(--ring))",
33 | background: "hsl(var(--background))",
34 | foreground: "hsl(var(--foreground))",
35 | primary: {
36 | DEFAULT: "hsl(var(--primary))",
37 | foreground: "hsl(var(--primary-foreground))",
38 | },
39 | secondary: {
40 | DEFAULT: "hsl(var(--secondary))",
41 | foreground: "hsl(var(--secondary-foreground))",
42 | },
43 | destructive: {
44 | DEFAULT: "hsl(var(--destructive))",
45 | foreground: "hsl(var(--destructive-foreground))",
46 | },
47 | muted: {
48 | DEFAULT: "hsl(var(--muted))",
49 | foreground: "hsl(var(--muted-foreground))",
50 | },
51 | accent: {
52 | DEFAULT: "hsl(var(--accent))",
53 | foreground: "hsl(var(--accent-foreground))",
54 | },
55 | popover: {
56 | DEFAULT: "hsl(var(--popover))",
57 | foreground: "hsl(var(--popover-foreground))",
58 | },
59 | card: {
60 | DEFAULT: "hsl(var(--card))",
61 | foreground: "hsl(var(--card-foreground))",
62 | },
63 | },
64 | borderRadius: {
65 | lg: "var(--radius)",
66 | md: "calc(var(--radius) - 2px)",
67 | sm: "calc(var(--radius) - 4px)",
68 | },
69 | keyframes: {
70 | "accordion-down": {
71 | from: { height: "0" },
72 | to: { height: "var(--radix-accordion-content-height)" },
73 | },
74 | "accordion-up": {
75 | from: { height: "var(--radix-accordion-content-height)" },
76 | to: { height: "0" },
77 | },
78 | "shine-pulse": {
79 | "0%": {
80 | "background-position": "0% 0%",
81 | },
82 | "50%": {
83 | "background-position": "100% 100%",
84 | },
85 | to: {
86 | "background-position": "0% 0%",
87 | },
88 | },
89 | "spin-around": {
90 | "0%": {
91 | transform: "translateZ(0) rotate(0)",
92 | },
93 | "15%, 35%": {
94 | transform: "translateZ(0) rotate(90deg)",
95 | },
96 | "65%, 85%": {
97 | transform: "translateZ(0) rotate(270deg)",
98 | },
99 | "100%": {
100 | transform: "translateZ(0) rotate(360deg)",
101 | },
102 | },
103 | slide: {
104 | to: {
105 | transform: "translate(calc(100cqw - 100%), 0)",
106 | },
107 | },
108 | },
109 | animation: {
110 | "accordion-down": "accordion-down 0.2s ease-out",
111 | "accordion-up": "accordion-up 0.2s ease-out",
112 | "spin-around": "spin-around calc(var(--speed) * 2) infinite linear",
113 | slide: "slide var(--speed) ease-in-out infinite alternate",
114 | },
115 | },
116 | },
117 | plugins: [
118 | require("tailwindcss-animate"),
119 | addVariablesForColors,
120 | ],
121 | } satisfies Config
122 |
123 | // This plugin adds each Tailwind color as a global CSS variable, e.g. var(--gray-200).
124 | function addVariablesForColors({ addBase, theme }: any) {
125 | let allColors = flattenColorPalette(theme("colors"));
126 | let newVars = Object.fromEntries(
127 | Object.entries(allColors).map(([key, val]) => [`--${key}`, val])
128 | );
129 | addBase({
130 | ":root": newVars,
131 | });
132 | }
133 |
134 | export default config
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/magicui/particles.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React, { useEffect, useRef, useState } from "react";
4 |
5 | interface MousePosition {
6 | x: number;
7 | y: number;
8 | }
9 |
10 | function MousePosition(): MousePosition {
11 | const [mousePosition, setMousePosition] = useState({
12 | x: 0,
13 | y: 0,
14 | });
15 |
16 | useEffect(() => {
17 | const handleMouseMove = (event: MouseEvent) => {
18 | setMousePosition({ x: event.clientX, y: event.clientY });
19 | };
20 |
21 | window.addEventListener("mousemove", handleMouseMove);
22 |
23 | return () => {
24 | window.removeEventListener("mousemove", handleMouseMove);
25 | };
26 | }, []);
27 |
28 | return mousePosition;
29 | }
30 |
31 | interface ParticlesProps {
32 | className?: string;
33 | quantity?: number;
34 | staticity?: number;
35 | ease?: number;
36 | size?: number;
37 | refresh?: boolean;
38 | color?: string;
39 | vx?: number;
40 | vy?: number;
41 | }
42 | function hexToRgb(hex: string): number[] {
43 | hex = hex.replace("#", "");
44 |
45 | if (hex.length === 3) {
46 | hex = hex
47 | .split("")
48 | .map((char) => char + char)
49 | .join("");
50 | }
51 |
52 | const hexInt = parseInt(hex, 16);
53 | const red = (hexInt >> 16) & 255;
54 | const green = (hexInt >> 8) & 255;
55 | const blue = hexInt & 255;
56 | return [red, green, blue];
57 | }
58 |
59 | const Particles: React.FC = ({
60 | className = "",
61 | quantity = 100,
62 | staticity = 50,
63 | ease = 50,
64 | size = 0.4,
65 | refresh = false,
66 | color = "#ffffff",
67 | vx = 0,
68 | vy = 0,
69 | }) => {
70 | const canvasRef = useRef(null);
71 | const canvasContainerRef = useRef(null);
72 | const context = useRef(null);
73 | const circles = useRef([]);
74 | const mousePosition = MousePosition();
75 | const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
76 | const canvasSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 });
77 | const dpr = typeof window !== "undefined" ? window.devicePixelRatio : 1;
78 |
79 | useEffect(() => {
80 | if (canvasRef.current) {
81 | context.current = canvasRef.current.getContext("2d");
82 | }
83 | initCanvas();
84 | animate();
85 | window.addEventListener("resize", initCanvas);
86 |
87 | return () => {
88 | window.removeEventListener("resize", initCanvas);
89 | };
90 | }, [color]);
91 |
92 | useEffect(() => {
93 | onMouseMove();
94 | }, [mousePosition.x, mousePosition.y]);
95 |
96 | useEffect(() => {
97 | initCanvas();
98 | }, [refresh]);
99 |
100 | const initCanvas = () => {
101 | resizeCanvas();
102 | drawParticles();
103 | };
104 |
105 | const onMouseMove = () => {
106 | if (canvasRef.current) {
107 | const rect = canvasRef.current.getBoundingClientRect();
108 | const { w, h } = canvasSize.current;
109 | const x = mousePosition.x - rect.left - w / 2;
110 | const y = mousePosition.y - rect.top - h / 2;
111 | const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2;
112 | if (inside) {
113 | mouse.current.x = x;
114 | mouse.current.y = y;
115 | }
116 | }
117 | };
118 |
119 | type Circle = {
120 | x: number;
121 | y: number;
122 | translateX: number;
123 | translateY: number;
124 | size: number;
125 | alpha: number;
126 | targetAlpha: number;
127 | dx: number;
128 | dy: number;
129 | magnetism: number;
130 | };
131 |
132 | const resizeCanvas = () => {
133 | if (canvasContainerRef.current && canvasRef.current && context.current) {
134 | circles.current.length = 0;
135 | canvasSize.current.w = canvasContainerRef.current.offsetWidth;
136 | canvasSize.current.h = canvasContainerRef.current.offsetHeight;
137 | canvasRef.current.width = canvasSize.current.w * dpr;
138 | canvasRef.current.height = canvasSize.current.h * dpr;
139 | canvasRef.current.style.width = `${canvasSize.current.w}px`;
140 | canvasRef.current.style.height = `${canvasSize.current.h}px`;
141 | context.current.scale(dpr, dpr);
142 | }
143 | };
144 |
145 | const circleParams = (): Circle => {
146 | const x = Math.floor(Math.random() * canvasSize.current.w);
147 | const y = Math.floor(Math.random() * canvasSize.current.h);
148 | const translateX = 0;
149 | const translateY = 0;
150 | const pSize = Math.floor(Math.random() * 2) + size;
151 | const alpha = 0;
152 | const targetAlpha = parseFloat((Math.random() * 0.6 + 0.1).toFixed(1));
153 | const dx = (Math.random() - 0.5) * 0.1;
154 | const dy = (Math.random() - 0.5) * 0.1;
155 | const magnetism = 0.1 + Math.random() * 4;
156 | return {
157 | x,
158 | y,
159 | translateX,
160 | translateY,
161 | size: pSize,
162 | alpha,
163 | targetAlpha,
164 | dx,
165 | dy,
166 | magnetism,
167 | };
168 | };
169 |
170 | const rgb = hexToRgb(color);
171 |
172 | const drawCircle = (circle: Circle, update = false) => {
173 | if (context.current) {
174 | const { x, y, translateX, translateY, size, alpha } = circle;
175 | context.current.translate(translateX, translateY);
176 | context.current.beginPath();
177 | context.current.arc(x, y, size, 0, 2 * Math.PI);
178 | context.current.fillStyle = `rgba(${rgb.join(", ")}, ${alpha})`;
179 | context.current.fill();
180 | context.current.setTransform(dpr, 0, 0, dpr, 0, 0);
181 |
182 | if (!update) {
183 | circles.current.push(circle);
184 | }
185 | }
186 | };
187 |
188 | const clearContext = () => {
189 | if (context.current) {
190 | context.current.clearRect(
191 | 0,
192 | 0,
193 | canvasSize.current.w,
194 | canvasSize.current.h,
195 | );
196 | }
197 | };
198 |
199 | const drawParticles = () => {
200 | clearContext();
201 | const particleCount = quantity;
202 | for (let i = 0; i < particleCount; i++) {
203 | const circle = circleParams();
204 | drawCircle(circle);
205 | }
206 | };
207 |
208 | const remapValue = (
209 | value: number,
210 | start1: number,
211 | end1: number,
212 | start2: number,
213 | end2: number,
214 | ): number => {
215 | const remapped =
216 | ((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
217 | return remapped > 0 ? remapped : 0;
218 | };
219 |
220 | const animate = () => {
221 | clearContext();
222 | circles.current.forEach((circle: Circle, i: number) => {
223 | // Handle the alpha value
224 | const edge = [
225 | circle.x + circle.translateX - circle.size, // distance from left edge
226 | canvasSize.current.w - circle.x - circle.translateX - circle.size, // distance from right edge
227 | circle.y + circle.translateY - circle.size, // distance from top edge
228 | canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge
229 | ];
230 | const closestEdge = edge.reduce((a, b) => Math.min(a, b));
231 | const remapClosestEdge = parseFloat(
232 | remapValue(closestEdge, 0, 20, 0, 1).toFixed(2),
233 | );
234 | if (remapClosestEdge > 1) {
235 | circle.alpha += 0.02;
236 | if (circle.alpha > circle.targetAlpha) {
237 | circle.alpha = circle.targetAlpha;
238 | }
239 | } else {
240 | circle.alpha = circle.targetAlpha * remapClosestEdge;
241 | }
242 | circle.x += circle.dx + vx;
243 | circle.y += circle.dy + vy;
244 | circle.translateX +=
245 | (mouse.current.x / (staticity / circle.magnetism) - circle.translateX) /
246 | ease;
247 | circle.translateY +=
248 | (mouse.current.y / (staticity / circle.magnetism) - circle.translateY) /
249 | ease;
250 |
251 | drawCircle(circle, true);
252 |
253 | // circle gets out of the canvas
254 | if (
255 | circle.x < -circle.size ||
256 | circle.x > canvasSize.current.w + circle.size ||
257 | circle.y < -circle.size ||
258 | circle.y > canvasSize.current.h + circle.size
259 | ) {
260 | // remove the circle from the array
261 | circles.current.splice(i, 1);
262 | // create a new circle
263 | const newCircle = circleParams();
264 | drawCircle(newCircle);
265 | // update the circle position
266 | }
267 | });
268 | window.requestAnimationFrame(animate);
269 | };
270 |
271 | return (
272 |
273 |
274 |
275 | );
276 | };
277 |
278 | export default Particles;
279 |
--------------------------------------------------------------------------------
/Portfolio/portfolio/components/ui/canvas-reveal-effect.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { cn } from "@/lib/utils";
3 | import { Canvas, useFrame, useThree } from "@react-three/fiber";
4 | import React, { useMemo, useRef } from "react";
5 | import * as THREE from "three";
6 |
7 | export const CanvasRevealEffect = ({
8 | animationSpeed = 0.4,
9 | opacities = [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1],
10 | colors = [[0, 255, 255]],
11 | containerClassName,
12 | dotSize,
13 | showGradient = true,
14 | }: {
15 | /**
16 | * 0.1 - slower
17 | * 1.0 - faster
18 | */
19 | animationSpeed?: number;
20 | opacities?: number[];
21 | colors?: number[][];
22 | containerClassName?: string;
23 | dotSize?: number;
24 | showGradient?: boolean;
25 | }) => {
26 | return (
27 |
28 |
29 |
43 |
44 | {showGradient && (
45 |
46 | )}
47 |
48 | );
49 | };
50 |
51 | interface DotMatrixProps {
52 | colors?: number[][];
53 | opacities?: number[];
54 | totalSize?: number;
55 | dotSize?: number;
56 | shader?: string;
57 | center?: ("x" | "y")[];
58 | }
59 |
60 | const DotMatrix: React.FC = ({
61 | colors = [[0, 0, 0]],
62 | opacities = [0.04, 0.04, 0.04, 0.04, 0.04, 0.08, 0.08, 0.08, 0.08, 0.14],
63 | totalSize = 4,
64 | dotSize = 2,
65 | shader = "",
66 | center = ["x", "y"],
67 | }) => {
68 | const uniforms = React.useMemo(() => {
69 | let colorsArray = [
70 | colors[0],
71 | colors[0],
72 | colors[0],
73 | colors[0],
74 | colors[0],
75 | colors[0],
76 | ];
77 | if (colors.length === 2) {
78 | colorsArray = [
79 | colors[0],
80 | colors[0],
81 | colors[0],
82 | colors[1],
83 | colors[1],
84 | colors[1],
85 | ];
86 | } else if (colors.length === 3) {
87 | colorsArray = [
88 | colors[0],
89 | colors[0],
90 | colors[1],
91 | colors[1],
92 | colors[2],
93 | colors[2],
94 | ];
95 | }
96 |
97 | return {
98 | u_colors: {
99 | value: colorsArray.map((color) => [
100 | color[0] / 255,
101 | color[1] / 255,
102 | color[2] / 255,
103 | ]),
104 | type: "uniform3fv",
105 | },
106 | u_opacities: {
107 | value: opacities,
108 | type: "uniform1fv",
109 | },
110 | u_total_size: {
111 | value: totalSize,
112 | type: "uniform1f",
113 | },
114 | u_dot_size: {
115 | value: dotSize,
116 | type: "uniform1f",
117 | },
118 | };
119 | }, [colors, opacities, totalSize, dotSize]);
120 |
121 | return (
122 |
175 | );
176 | };
177 |
178 | type Uniforms = {
179 | [key: string]: {
180 | value: number[] | number[][] | number;
181 | type: string;
182 | };
183 | };
184 | const ShaderMaterial = ({
185 | source,
186 | uniforms,
187 | maxFps = 60,
188 | }: {
189 | source: string;
190 | hovered?: boolean;
191 | maxFps?: number;
192 | uniforms: Uniforms;
193 | }) => {
194 | const { size } = useThree();
195 | const ref = useRef();
196 | let lastFrameTime = 0;
197 |
198 | useFrame(({ clock }) => {
199 | if (!ref.current) return;
200 | const timestamp = clock.getElapsedTime();
201 | if (timestamp - lastFrameTime < 1 / maxFps) {
202 | return;
203 | }
204 | lastFrameTime = timestamp;
205 |
206 | const material: any = ref.current.material;
207 | const timeLocation = material.uniforms.u_time;
208 | timeLocation.value = timestamp;
209 | });
210 |
211 | const getUniforms = () => {
212 | const preparedUniforms: any = {};
213 |
214 | for (const uniformName in uniforms) {
215 | const uniform: any = uniforms[uniformName];
216 |
217 | switch (uniform.type) {
218 | case "uniform1f":
219 | preparedUniforms[uniformName] = { value: uniform.value, type: "1f" };
220 | break;
221 | case "uniform3f":
222 | preparedUniforms[uniformName] = {
223 | value: new THREE.Vector3().fromArray(uniform.value),
224 | type: "3f",
225 | };
226 | break;
227 | case "uniform1fv":
228 | preparedUniforms[uniformName] = { value: uniform.value, type: "1fv" };
229 | break;
230 | case "uniform3fv":
231 | preparedUniforms[uniformName] = {
232 | value: uniform.value.map((v: number[]) =>
233 | new THREE.Vector3().fromArray(v)
234 | ),
235 | type: "3fv",
236 | };
237 | break;
238 | case "uniform2f":
239 | preparedUniforms[uniformName] = {
240 | value: new THREE.Vector2().fromArray(uniform.value),
241 | type: "2f",
242 | };
243 | break;
244 | default:
245 | console.error(`Invalid uniform type for '${uniformName}'.`);
246 | break;
247 | }
248 | }
249 |
250 | preparedUniforms["u_time"] = { value: 0, type: "1f" };
251 | preparedUniforms["u_resolution"] = {
252 | value: new THREE.Vector2(size.width * 2, size.height * 2),
253 | }; // Initialize u_resolution
254 | return preparedUniforms;
255 | };
256 |
257 | // Shader material
258 | const material = useMemo(() => {
259 | const materialObject = new THREE.ShaderMaterial({
260 | vertexShader: `
261 | precision mediump float;
262 | in vec2 coordinates;
263 | uniform vec2 u_resolution;
264 | out vec2 fragCoord;
265 | void main(){
266 | float x = position.x;
267 | float y = position.y;
268 | gl_Position = vec4(x, y, 0.0, 1.0);
269 | fragCoord = (position.xy + vec2(1.0)) * 0.5 * u_resolution;
270 | fragCoord.y = u_resolution.y - fragCoord.y;
271 | }
272 | `,
273 | fragmentShader: source,
274 | uniforms: getUniforms(),
275 | glslVersion: THREE.GLSL3,
276 | blending: THREE.CustomBlending,
277 | blendSrc: THREE.SrcAlphaFactor,
278 | blendDst: THREE.OneFactor,
279 | });
280 |
281 | return materialObject;
282 | }, [size.width, size.height, source]);
283 |
284 | return (
285 |
286 |
287 |
288 |
289 | );
290 | };
291 |
292 | const Shader: React.FC = ({ source, uniforms, maxFps = 60 }) => {
293 | return (
294 |
295 |
296 |
297 | );
298 | };
299 | interface ShaderProps {
300 | source: string;
301 | uniforms: {
302 | [key: string]: {
303 | value: number[] | number[][] | number;
304 | type: string;
305 | };
306 | };
307 | maxFps?: number;
308 | }
309 |
--------------------------------------------------------------------------------