diff --git a/README.md b/README.md
index 5c951b7..27df2f1 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,13 @@
-## Pradumna Saraf Portfolio
+### Pradumnasaraf.github.io
-This repository contains the source code for my portfolio website. It is built using HTML and CSS. It is hosted on GitHub Pages.
+This repository contains the source code for my personal/portfolio/service website. It is built Next.js and Tailwind CSS. The Code is 100% open source and available for anyone to use.
-[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/Pradumnasaraf/Pradumnasaraf.github.io)
+![website screenshot](https://github.com/user-attachments/assets/c4e1fdf8-49fd-4e2b-a66c-bb55e84e3e01)
-![Website Demo](https://github.com/Pradumnasaraf/Pradumnasaraf.github.io/assets/51878265/0b330ade-1645-4005-b4fd-2f1aeb6a17bf)
-
-## 🌐 Website
-
-A custom domain name is used for the website. It is hosted on GitHub Pages. The website is accessible at [pradumnasaraf.dev](https://pradumnasaraf.dev/)
-
-## 🛡️ License
+### 📜 License
**Pradumnasaraf.github.io** is licensed under the GPL-3.0 License - see the [LICENSE](/LICENSE) file for details.
-## 🤝 Support
+### 🛡 Security
-Don't forget to leave a star ⭐️
+If you discover a security vulnerability within this project, please check the [SECURITY](SECURITY.md) for more information.
\ No newline at end of file
diff --git a/next.config.mjs b/next.config.mjs
index 3ef4061..e511a23 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -3,11 +3,31 @@ const nextConfig = {
async redirects() {
return [
{
- source: '/hey',
- destination: '/',
- permanent: true, // Permanent redirect (301)
+ source: '/monitoring',
+ destination: 'https://Pradumnasaraf.github.io/Monitoring',
+ permanent: true,
},
- ];
+ {
+ source: '/newsletter',
+ destination: 'https://pradumnasaa.substack.com',
+ permanent: true,
+ },
+ {
+ source: '/cv',
+ destination: 'https://www.canva.com/design/DAF_kKnj9WI/IT8NdwVQlzRK3DaMmXm18A/edit?utm_content=DAF_kKnj9WI&utm_campaign=designshare&utm_medium=link2&utm_source=sharebutton',
+ permanent: true,
+ },
+ {
+ source: '/resume',
+ destination: 'https://www.canva.com/design/DAF_kKnj9WI/IT8NdwVQlzRK3DaMmXm18A/edit?utm_content=DAF_kKnj9WI&utm_campaign=designshare&utm_medium=link2&utm_source=sharebutton',
+ permanent: true,
+ },
+ {
+ source: '/blog',
+ destination: 'https://blog.pradumnasaraf.dev',
+ permanent: true,
+ }
+ ]
},
};
diff --git a/package-lock.json b/package-lock.json
index 3bc50c6..da93301 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,7 +6,7 @@
"packages": {
"": {
"name": "pradumnasaraf.dev",
- "version": "2.13.1",
+ "version": "3.0.0",
"dependencies": {
"next": "15.1.4",
"react": "^19.0.0",
diff --git a/src/app/camera/components/FullScreenModal.js b/src/app/camera/components/FullScreenModal.js
deleted file mode 100644
index 0f49540..0000000
--- a/src/app/camera/components/FullScreenModal.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-import { createPortal } from 'react-dom';
-import '../style.css';
-
-const FullScreenModal = ({ isOpen, imageSrc, onClose }) => {
- if (!isOpen) return null;
-
- return createPortal(
-
- {/* The close button positioned at the top-right corner of the viewport */}
-
- ×
-
-
-
,
- document.body
- );
-};
-
-export default FullScreenModal;
\ No newline at end of file
diff --git a/src/app/camera/components/MasonryGrid.js b/src/app/camera/components/MasonryGrid.js
deleted file mode 100644
index 7bd37f9..0000000
--- a/src/app/camera/components/MasonryGrid.js
+++ /dev/null
@@ -1,70 +0,0 @@
-'use client';
-import React, { useState } from 'react';
-import FullScreenModal from './FullScreenModal';
-import Masonry from 'react-masonry-css';
-import '../style.css';
-
-const MasonryGrid = ({ images }) => {
- const [isModalOpen, setIsModalOpen] = useState(false);
- const [modalImageSrc, setModalImageSrc] = useState('');
-
- const openModal = (src) => {
- setModalImageSrc(src);
- setIsModalOpen(true);
- };
-
- const closeModal = () => {
- setIsModalOpen(false);
- setModalImageSrc('');
- };
-
- const breakpointColumnsObj = {
- default: 3,
- 1100: 3,
- 700: 2,
- 500: 1
- };
-
- return (
- <>
-
- {images.map((image, index) => (
- openModal(image.src)}
- />
- ))}
-
-
-
- >
- );
-};
-
-// Component to handle individual image rendering with error handling
-const ImageItem = ({ src, alt, onClick }) => {
- const [hasError, setHasError] = useState(false);
-
- return !hasError ? (
- setHasError(true)}
- loading="lazy"
- />
- ) : null;
-};
-
-export default MasonryGrid;
\ No newline at end of file
diff --git a/src/app/camera/page.js b/src/app/camera/page.js
index 316b8b9..cc43411 100644
--- a/src/app/camera/page.js
+++ b/src/app/camera/page.js
@@ -1,7 +1,8 @@
'use client';
-import MasonryGrid from './components/MasonryGrid';
-import { useEffect } from 'react';
-
+import React, { useState, useEffect } from 'react';
+import Masonry from 'react-masonry-css';
+import { createPortal } from 'react-dom';
+import './style.css';
const images = [
{ src: 'https://drive.google.com/thumbnail?id=1uu0wWGmbHC0VY7BT-n5DUpWz86_ozANg&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1G8IYlbeJUKvghC8FIlEmtyVo6fg_YxqZ&sz=w2000', alt: 'photo' },
@@ -38,52 +39,132 @@ const images = [
{ src: 'https://drive.google.com/thumbnail?id=1ISysXMTEBkqwt3-wCN0jFRNATZTWKi26&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1bifEZJm_rIx_Xs4pORmfXCCIVFuMH_DY&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=11VG8uzX2vUMSRtEnHsDxDMT3fcletqsY&sz=w2000', alt: 'photo' },
- { src: 'https://drive.google.com/thumbnail?id=1JANNc-kNawn7jUGRs4MUZc9ib0wQ8JBP&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1YbOEXGJfIOXvRW6akB1HVmaIOOF2Jk1h&sz=w2000', alt: 'photo' },
- { src: 'https://drive.google.com/thumbnail?id=1b3CqP5Hn0xI2m6d2jH9_uWrfn3z8rkI0&sz=w2000', alt: 'photo' },
+ { src: 'https://drive.google.com/thumbnail?id=1JANNc-kNawn7jUGRs4MUZc9ib0wQ8JBP&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1ko_WLnJ2SNNEO13WkKmRhpvobDQ6Q_Ko&sz=w2000', alt: 'photo' },
+ { src: 'https://drive.google.com/thumbnail?id=1b3CqP5Hn0xI2m6d2jH9_uWrfn3z8rkI0&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1ruE0RqOwTPK0AR17ap4hwfGDgWboP52p&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1O83nNCKCUZ4McHO1nlZXvo1OKqzLldyw&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1MxtU3yWE8BkSi-1gessGGaTKGKzO8SO6&sz=w2000', alt: 'photo' },
- { src: 'https://drive.google.com/thumbnail?id=1FEQMnHybHi1TDvCHweOsB7ODeC06VjIs&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1nTQlYnaHPsy-kCrlV1bJocKgwlvqmyQc&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1K_Iteo-Rqrxi0ayMMAjOgsBSocg81Wmx&sz=w2000', alt: 'photo' },
- { src: 'https://drive.google.com/thumbnail?id=16ujZfroa5zjL09-UJWPyeRK0NUu1VkBi&sz=w2000', alt: 'photo' },
+ { src: 'https://drive.google.com/thumbnail?id=1FEQMnHybHi1TDvCHweOsB7ODeC06VjIs&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1P60hz5FIkEhoyxEJOtHCVprzm8sP4tt-&sz=w2000', alt: 'photo' },
- { src: 'https://drive.google.com/thumbnail?id=1-umcEA-0sefXkCVXtpEFxvVAWqtnw2y1&sz=w2000', alt: 'photo' },
- { src: 'https://drive.google.com/thumbnail?id=1sVamXny-K2Tfb_m_PGxQEdTiV99_r8q8&sz=w2000', alt: 'photo' },
{ src: 'https://drive.google.com/thumbnail?id=1dD4-Qrc2Hk4dCFQKcBB4GRbsvrcJOt0Q&sz=w2000', alt: 'photo' },
+ { src: 'https://drive.google.com/thumbnail?id=1sVamXny-K2Tfb_m_PGxQEdTiV99_r8q8&sz=w2000', alt: 'photo' },
+ { src: 'https://drive.google.com/thumbnail?id=16ujZfroa5zjL09-UJWPyeRK0NUu1VkBi&sz=w2000', alt: 'photo' },
+ { src: 'https://drive.google.com/thumbnail?id=1-umcEA-0sefXkCVXtpEFxvVAWqtnw2y1&sz=w2000', alt: 'photo' },
]
+// FullScreenModal Component
+const FullScreenModal = ({ isOpen, imageSrc, onClose }) => {
+ if (!isOpen) return null;
+
+ return createPortal(
+
+
+ ×
+
+
+
,
+ document.body
+ );
+};
+
+// Main Home Component
export default function Home() {
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [modalImageSrc, setModalImageSrc] = useState('');
+
+ const openModal = (src) => {
+ setModalImageSrc(src);
+ setIsModalOpen(true);
+ };
+
+ const closeModal = () => {
+ setIsModalOpen(false);
+ setModalImageSrc('');
+ };
+
+ const breakpointColumnsObj = {
+ default: 3,
+ 1100: 3,
+ 700: 2,
+ 500: 1
+ };
+
useEffect(() => {
- // Google Tag Manager Script
- const scriptGTM = document.createElement('script');
- scriptGTM.innerHTML = `
- (function (w, d, s, l, i) {
- w[l] = w[l] || [];
- w[l].push({
- 'gtm.start': new Date().getTime(),
- event: 'gtm.js',
- });
- var f = d.getElementsByTagName(s)[0],
- j = d.createElement(s),
- dl = l != 'dataLayer' ? '&l=' + l : '';
- j.async = true;
- j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
- f.parentNode.insertBefore(j, f);
- })(window, document, 'script', 'dataLayer', 'GTM-WRGLMZCX');
- `;
- document.head.appendChild(scriptGTM);
- return () => {
- document.head.removeChild(scriptGTM);
- };
- }, []);
+ // Google Tag Manager Script
+ const scriptGTM = document.createElement('script');
+ scriptGTM.innerHTML = `
+ (function (w, d, s, l, i) {
+ w[l] = w[l] || [];
+ w[l].push({
+ 'gtm.start': new Date().getTime(),
+ event: 'gtm.js',
+ });
+ var f = d.getElementsByTagName(s)[0],
+ j = d.createElement(s),
+ dl = l != 'dataLayer' ? '&l=' + l : '';
+ j.async = true;
+ j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
+ f.parentNode.insertBefore(j, f);
+ })(window, document, 'script', 'dataLayer', 'GTM-WRGLMZCX');
+ `;
+ document.head.appendChild(scriptGTM);
+ return () => {
+ document.head.removeChild(scriptGTM);
+ };
+ }, []);
+
return (
-
+
+ {images.map((image, index) => (
+ openModal(image.src)}
+ />
+ ))}
+
+
+
);
-}
\ No newline at end of file
+}
+
+// ImageItem Component
+const ImageItem = ({ src, alt, onClick }) => {
+ const [hasError, setHasError] = useState(false);
+
+ return !hasError ? (
+ setHasError(true)}
+ loading="lazy"
+ />
+ ) : null;
+};
\ No newline at end of file
diff --git a/src/app/not-found.css b/src/app/not-found.css
new file mode 100644
index 0000000..1073757
--- /dev/null
+++ b/src/app/not-found.css
@@ -0,0 +1,43 @@
+.not-found-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 100vh;
+ background-color: #f8f9fa;
+ color: #333;
+ text-align: center;
+ font-family: Arial, sans-serif;
+}
+
+.not-found-title {
+ font-size: 3rem;
+ font-weight: bold;
+ color: #f57b85;
+}
+
+.not-found-description {
+ margin-top: 1rem;
+ font-size: 1.25rem;
+ color: #6c757d;
+}
+
+.not-found-description a {
+ color: #f57b85;
+ text-decoration: none;
+}
+
+.not-found-link {
+ font-size: 1.5em;
+ margin-top: 2rem;
+ padding: 0.5rem 1rem;
+ background-color: #2C3333;
+ color: white;
+ text-decoration: none;
+ border-radius: 10px;
+ transition: background-color 0.5s ease;
+}
+
+.not-found-link:hover {
+ opacity: 0.6;
+}
\ No newline at end of file
diff --git a/src/app/not-found.js b/src/app/not-found.js
new file mode 100644
index 0000000..ac0248e
--- /dev/null
+++ b/src/app/not-found.js
@@ -0,0 +1,15 @@
+import './not-found.css';
+
+export default function NotFound() {
+ return (
+
+
404 - Page Not Found :(
+
+ Sorry, the page you are looking for does not exist. If you think this is an error, please email me here .
+
+
+ Go Back to Home
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/page.js b/src/app/page.js
index 1f5eaf3..bb8b8a9 100644
--- a/src/app/page.js
+++ b/src/app/page.js
@@ -85,6 +85,9 @@ export default function Home() {
Services
+
+
+ Newsletter
Contact
diff --git a/src/app/services/page.js b/src/app/services/page.js
index 909b0d2..1f01182 100644
--- a/src/app/services/page.js
+++ b/src/app/services/page.js
@@ -2,8 +2,10 @@
import './style.css'
import Head from 'next/head';
import { useEffect } from 'react';
-import { FaTwitter, FaLinkedin, FaDev, FaGithub, FaEnvelope, FaSuitcase, FaFeather, FaMicrophone, FaTerminal, FaVideo, FaStackExchange } from 'react-icons/fa';
-import { TbArticle } from "react-icons/tb";
+import { FaTwitter, FaLinkedin, FaDev, FaGithub, FaEnvelope, FaSuitcase, FaFeather, FaMicrophone, FaTools, FaVideo, FaStackExchange } from 'react-icons/fa';
+import { FaHashnode } from "react-icons/fa6";
+import { BsPeopleFill } from "react-icons/bs";
+import { MdArticle } from "react-icons/md";
import Image from 'next/image';
const ServicesPage = () => {
@@ -120,6 +122,9 @@ const ServicesPage = () => {
Home
+
+ Newsletter
+
Contact
@@ -169,14 +174,14 @@ const ServicesPage = () => {
-
+
Build Products
Building products, tools, apps, etc for companies according to their needs.
-
+
Community
Building community around products and companies to scale up the product feedback
@@ -228,7 +233,7 @@ const ServicesPage = () => {
Draft before posting
-
+
Blog
FROM
$500
@@ -346,7 +351,7 @@ const ServicesPage = () => {
-
+
Hashnode
500+ Followers