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 */} - - Full Screen -
, - 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 ? ( - {alt} 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( +
+ + Full Screen +
, + 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 ? ( + {alt} 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