diff --git a/.DS_Store b/.DS_Store index 3938252..cc3b8aa 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/assets/.DS_Store b/assets/.DS_Store index 5008ddf..18309de 100644 Binary files a/assets/.DS_Store and b/assets/.DS_Store differ diff --git a/assets/cyclops.png b/assets/cyclops.png new file mode 100644 index 0000000..fc4756f Binary files /dev/null and b/assets/cyclops.png differ diff --git a/assets/image.png b/assets/image.png new file mode 100644 index 0000000..ffceda1 Binary files /dev/null and b/assets/image.png differ diff --git a/assets/images.jpeg b/assets/images.jpeg new file mode 100644 index 0000000..9aa3bbe Binary files /dev/null and b/assets/images.jpeg differ diff --git a/assets/openpedia.png b/assets/openpedia.png index 83ca64a..2842820 100644 Binary files a/assets/openpedia.png and b/assets/openpedia.png differ diff --git a/assets/owasp.jpg b/assets/owasp.jpg new file mode 100644 index 0000000..08af74c Binary files /dev/null and b/assets/owasp.jpg differ diff --git a/assets/owasp.png b/assets/owasp.png new file mode 100644 index 0000000..63fda91 Binary files /dev/null and b/assets/owasp.png differ diff --git a/assets/sentry.jpeg b/assets/sentry.jpeg new file mode 100644 index 0000000..e19c421 Binary files /dev/null and b/assets/sentry.jpeg differ diff --git a/assets/t-mobile-icon.png b/assets/t-mobile-icon.png new file mode 100644 index 0000000..63f9afd Binary files /dev/null and b/assets/t-mobile-icon.png differ diff --git a/css/project.css b/css/project.css index 655a4d7..4b5608a 100644 --- a/css/project.css +++ b/css/project.css @@ -139,16 +139,17 @@ article .icon { .btn-container { margin-top: 1rem; display: flex; - /* justify-content: space-between; */ - align-items : space-between; + flex-wrap: wrap; /* Allows buttons to wrap to the next line */ + justify-content: center; gap: 1rem; } + .btn { font-weight: 600; transition: all 300ms ease; padding: 1rem; - width: 6rem; + width: 8rem; border-radius: 2rem; } diff --git a/css/style.css b/css/style.css index f556211..6a0f71f 100644 --- a/css/style.css +++ b/css/style.css @@ -750,7 +750,7 @@ img { align-items: center; justify-content: center; } - +/* .tabs { display: flex; position: relative; @@ -831,7 +831,123 @@ input[id="radio-4"]:checked ~ .glider { transform: scale(0.6); } } - + */ + + .container-tabs { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; +} + +.tabs { + display: flex; + position: relative; + background-color: #fff; + box-shadow: 0 0 1px 0 rgba(24, 94, 224, 0.15), 0 6px 12px 0 rgba(24, 94, 224, 0.15); + padding: 0.35rem; + border-radius: 99px; +} + +.tabs * { + z-index: 2; +} + +input[type="radio"] { + display: none; +} + +.tab { + display: flex; + align-items: center; + justify-content: center; + height: 34px; + width: 280px; + font-size: 1.25rem; + font-weight: 500; + border-radius: 99px; + cursor: pointer; + transition: color 0.15s ease-in; +} + +.glider { + position: absolute; + display: flex; + height: 34px; + width: 280px; + background-color: var(--first-color); + z-index: 1; + border-radius: 99px; + transition: 0.25s ease-out; +} + +input[type="radio"]:checked + label { + color: #fff; +} + +input[id="radio-1"]:checked ~ .glider { + transform: translateX(0); +} +input[id="radio-2"]:checked ~ .glider { + transform: translateX(100%); +} +input[id="radio-3"]:checked ~ .glider { + transform: translateX(200%); +} +input[id="radio-4"]:checked ~ .glider { + transform: translateX(300%); +} + +/* Hide Dropdown by Default */ +.dropdown { + display: none; +} + +/* Show Dropdown & Hide Tabs on Small Screens */ +@media (max-width: 1200px) { + .tabs { + display: none; + } + + .dropdown { + position: relative; + width: 300px; + margin: 0 auto; /* Center horizontally */ + display: flex; + justify-content: center; + -webkit-appearance: none; /* Disable macOS native styling */ + -moz-appearance: none; + } + + .dropdown::after { + font-size: 1rem; + color: var(--first-color); + position: absolute; + top: 50%; + right: 15px; + transform: translateY(-50%); + pointer-events: none; + } + + .dropdown select:hover, + .dropdown select:focus { + background-color: var(--first-color); + color: white; + border-color: var(--first-color); + outline: none; + } + + select { + + width: 100%; + padding: 10px; + font-size: 1.2rem; + border-radius: 10px; + border: 1px solid #ccc; + background: #fff; + } +} + /* ================================================ Contact Me ============================================= */ diff --git a/data/projects.json b/data/projects.json new file mode 100644 index 0000000..7d986cc --- /dev/null +++ b/data/projects.json @@ -0,0 +1,185 @@ +{ + "projects" : { + "web_development": [ + { + "id": 1, + "title": "Cryptocurrency Tracker", + "image": "../assets/cryptoTracker.png", + "description": "Constructed a web application using React to monitor prices and performance of 4000+ cryptocurrencies in real-time.", + "contribution": [ + "Utilized Redux Toolkit for streamlined state management and integrated 2 APIs for real-time data-driven decision-making.", + "Leveraged Chart.js features to visualize historical data using 8+ graphs, and Jest for unit testing." + ], + "links": { + "live": "https://main--cerulean-tartufo-01ec5f.netlify.app/", + "github" : "https://github.com/nipunh/cryptotracker" + } + }, + { + "id": 2, + "title": "Job Portal", + "image": "../assets/jobportal.png", + "description": "Created a full-stack user-friendly web application for job seekers, streamlining job searching and posting process.", + "contribution": [ + "Leveraged Angular for the frontend and Spring Boot with MongoDB for the backend.", + "Established JWT token-based authentication for enhanced user access control." + ], + "links": { + "github": "https://github.com/nipunh/Job-Search-Platform" + } + }, + { + "id": 3, + "title": "Ecommerce Web Application", + "image": "../assets/underconstruction.png", + "description": "Conceptualized and engineered a full-stack e-commerce web application using cutting-edge Javascript frameworks.", + "contribution": [ + "Developed REST API endpoints with Node.js, Express, and MongoDB.", + "Integrated third-party APIs, like Google Maps, Twilio, and Stripe with React to enhance functionalities." + ], + "links": { + "github": "https://github.com/nipunh/Ecommerce-Web-Application" + } + }, + { + "id": 4, + "title": "3D Tshirt Design", + "image": "../assets/underconstruction.png", + "description": "Developed an immersive and visually stunning ThreeJS-powered 3D product website with integrated artificial intelligence features.", + "contribution": [ + "Leveraged DALLE AI (OpenAI API) to generate images and employed TailwindCSS for efficient utility-first styling, ensuring a responsive design across devices." + ], + "links": { + "github": "" + } + } + ], + "mobile_development": [ + { + "id": "5", + "title": "Reselling Platform", + "image": "../assets/resseller.png", + "links": { + "github" : "https://github.com/nipunh/reseller" + }, + "description": "Led the end-to-end development of a dynamic mobile application using React Native, spearheading the creation of a comprehensive platform for streamlined item reselling.", + "contribution": [] + }, + { + "id": "6", + "title": "Expense Tracker", + "image": "../assets/expense.png", + "link": { + "github" : "https://github.com/nipunh/react-native-expense-tracker" + }, + "description": "Designed and Developed a React Native and Firebase based expense tracker with features such as expense tracking, categorization, receipt storage, and visualizations, for users to effectively manage their expenses and gain valuable insights into their spending habits." + + }, + { + "id": "7", + "title": "Restaurant App", + "image": "../assets/fooddelivery.png", + "description": "Mobile application for user to browse restaurant menus, customize orders, and place orders. Utilized device location to suggest nearby restaurants allowing users to search for restaurants by distance.", + "contribution" : [ + "Developed a real-time chat feature using Flutter Streams and firebase firestore for communication with restaurant staff.", + "Offered table reservations and utilized notifications and reminders to keep users updated on reservations.", + "Implemented the BLoC architecture to integrate the Stripe payment gateway supporting various payment methods." + ], + + "links" : {} + } + ], + "open_source": [ + { + "id": "8", + "title": "OWASP", + "image": "../assets/owasp.jpg", + "description": "OWASP Nest is a centralized platform developed by the Open Worldwide Application Security Project (OWASP) to enhance collaboration and engagement within its global community.", + "contribution": [ + "Introduced a new component to display information about entity leaders within the application.", + "Developed a new page that provides snapshots or summaries of various community activities and statistics.", + "Resolved issues related to the display of map borders on both the Chapter and Main pages, enhancing visual consistency.", + "Corrected the color of cluster markers on maps to improve readability and user experience.", + "Enhanced the layout of the project details page by adopting a two-column design for recent issues and releases, aligning it with the main page's structure." + ], + "links": { + "github" : "https://github.com/OWASP/Nest/pulls?q=is%3Apr+is%3Aclosed+author%3Anipunh", + "bug_ticket": "https://github.com/cyclops-ui/cyclops/issues/421", + "my_contribution": "https://github.com/cyclops-ui/cyclops/pull/491" + } + }, + { + "id": "9", + "title": "Sentry", + "image": "../assets/images.jpeg", + "description": "Sentry automatically detects and notifies you of critical performance issues so you can trace every slow transaction to a poor-performing API call or DB query.", + "contribution": [ + "Addressed UI issues related to the account notification settings input, enhancing user experience.", + "Fixed display issues with native stack traces, ensuring register visibility and proper button placement." + ], + "links": { + "github" : "https://github.com/getsentry/sentry/pulls?q=is+author%3Anipunh", + "bug_ticket": "https://github.com/getsentry/sentry/issues/82508", + "my_contribution_1": "https://github.com/getsentry/sentry/pull/82642", + "enhancement_ticket": "https://github.com/getsentry/sentry/issues/82371", + "my_contribution_2": "https://github.com/getsentry/sentry/pull/82641" + } + }, + { + "id": "10", + "title": "Cyclops", + "image": "../assets/cyclops.png", + "description": "Cyclops is an open-source dev tool that simplifies Kubernetes with an easy-to-use UI, making it less intimidating. Instead of creating and configuring your Kubernetes manifests with YAML, use Cyclops to painlessly configure and deploy your applications - validations included!", + "contribution": ["Improved state-management to better tackle loading state of multiple templates in Table."], + "links": { + "github" : "https://github.com/cyclops-ui/cyclops/pulls?q=is%3Apr+is%3Aclosed+author%3Anipunh", + "bug_ticket": "https://github.com/cyclops-ui/cyclops/issues/421", + "my_contribution": "https://github.com/cyclops-ui/cyclops/pull/491" + } + }, + { + "id": "11", + "title": "Openpedia", + "image": "../assets/openpedia.png", + "description": "Openpedia provides a wealth of useful resources that enable developers to become a seasoned open source contributor.", + "contribution":["Converted static component to dynamic component and resolved bug in footer & navigation."], + "links": { + "github": "https://github.com/Sriparno08/Openpedia" + } + } + ], + "ml_development": [ + { + "id": "12", + "title": "AI Face Mask", + "image": "../assets/underconstruction.png", + "description": "Trained a Convolutional Neural Network model to analyze face images and detect whether a person is wearing a mask or not, the type of mask being worn, and whether the mask is worn correctly.", + "contribution": ["Achieved 73.4% accuracy on the validation model and identified bias affecting model performance."], + "links": { + "github": "https://github.com/nipunh/MaskNet" + } + }, + { + "id": "13", + "title": "Steam Game Recommendation", + "image": "../assets/underconstruction.png", + "description": "Developed a recommendation model for personalized game suggestions based on user behavior, applying preprocessing methods and performing exploratory data analysis using PySpark.", + "contribution": ["Trained and compared between Matrix Vectorization – ALS and Item-Item Recommendation – Cosine Similarity & Pearson Coefficient, calculating RMSE to evaluate models."], + "links": { + "github": "https://github.com/VishanthSurresh/Steam-Game-Recommendation/tree/main" + } + }, + { + "id": "14", + "title": "Covid Detection using Xray", + "image": "../assets/underconstruction.png", + "description": "Developed a deep learning classification system using CNNs to detect COVID-19, pneumonia, and normal cases in chest X-rays using MobileNetV2 and custom CNN models.", + "contribution": ["Achieved an accuracy of 86.25% for the custom CNN model and 84% for MobileNetV2, assisting radiologists in COVID-19 diagnosis."], + "links": { + "github": "" + } + } + ] + } +} + \ No newline at end of file diff --git a/index.html b/index.html index c98fdbb..459c2ed 100644 --- a/index.html +++ b/index.html @@ -33,27 +33,23 @@ - + @@ -144,10 +140,10 @@

About Me

- Software Engineer with experience in developing full-stack web applications, - proven track record of collaborating with teams to develop, enhance and troubleshoot - applications. Proficient in modern Javascript frameworks such as React, Node, and Redux. - Possesses a solid foundation in algorithm design, programming, and problem-solving. + Computer Science graduate with over 2 year of experience specializing in front-end and back-end development. + Highly detail-oridented professional known for excellent communication, teamwork and collaboration skills, + coupled with a passion for problem-solving. Recognized for adhering to best practices and coding standards, + with a strong focus on delivering high-quality, scalable solutions.

@@ -264,6 +260,23 @@

Senior Secondary

+ +
+
+ +
+
+
+ +
+ +
+

Full Stack Developer

+ T-Mobile
+ Oct 2024 - Present +
+
+
@@ -271,7 +284,7 @@

Full Stack Developer

Smartrek Technologies
- 2024 - Present + Feb 2024 - June 2024
@@ -501,539 +514,22 @@

Projects

-
-
-
-
- Project 1 - -

Cryptocurrency Tracker

-
- - -
-
-
- - -
-

Cryptocurrency Tracker

-
    -
  • Constructed a web application using React to monitor prices and performance of 4000+ - cryptocurrencies in real-time.
  • -
  • Utilized Redux Toolkit for streamlined state management and integrated 2 APIs for real-time - data-driven decision-making.
  • -
  • Leveraged Chart.js features to visualize historical data using 8+ graphs, and Jest for unit - testing.
  • - -
-
-
-
-
- - -
-
-
- Project 1 - -

Job Portal

-
- - -
-
-
- -
-

Job Portal

-
    -
  • Created an full stack user-friendly web application for job seekers, streamlining job searching - and posting process.
  • -
  • Leveraged Angular for the frontend and employing Spring Boot and MongoDB for the backend to - expedite development.
  • -
  • Effectively communicated project requirements and progress in a team of 6 members and maintained - GitHub Wiki.
  • -
  • Established JWT token-based authentication and authorization for enhanced user access control. -
  • -
-
-
-
-
- - -
-
-
- Project 1 - -

Ecommerce Web App

-
- - -
-
-
- -
-

Ecommerce Web Application

-
    -
  • Conceptualized and engineered a full-stack e-commerce web application using cutting-edge - Javascript frameworks.
  • -
  • Developed REST API endpoints with Nodejs, Express, and MongoDB, increasing efficient data - management.
  • -
  • Orchestrated integration of third-party APIs, like Google Maps, twilio, and Stripe with React to - elevate the functionalities.
  • -
-
- -
-
-
- -
-
-
- Project 1 - -

3D Tshirt Design

-
- - -
-
-
- -
-

3D Tshirt Design

-
    -
  • Developed an immersive and visually stunning ThreeJS-powered 3D product website with integrated - artificial intelligence features.
  • -
  • Leveraged DALLE AI (OpenAI API) to generate and utilize images, adding a unique and dynamic - element to the websites.
  • -
  • Employed TailwindCSS for efficient utility-first CSS styling, ensuring a responsive and visually - appealing design across devices.
  • - -
-
-
-
-
+ - - - - - - -
- - - - - - -
@@ -1069,33 +565,27 @@

Location

-
+ +
Name - +
Email - +
- - -
Message - +
- - - @@ -1104,11 +594,9 @@

- -
- +
@@ -1141,17 +629,12 @@

Nipun

- - - + - - + - - \ No newline at end of file diff --git a/js/email.js b/js/email.js deleted file mode 100644 index b4e39d9..0000000 --- a/js/email.js +++ /dev/null @@ -1,60 +0,0 @@ -(function() { - // https://dashboard.emailjs.com/admin/account - emailjs.init({ - publicKey: vars.EMAILJS_PUBLICKEY, - }); -})(); - -// Getting elements -const form = document.getElementById('contact__form'); -const userName = document.getElementById('user_name'); -const userEmail = document.getElementById('user_email'); -const userMessage = document.getElementById('user_message'); -const messageContainer = document.querySelector('.message-container'); -const message = document.getElementById('message'); - -let isValid = false - -function validateForm() { - // Using Contraint API - isValid = form.checkValidity(); - // Style main message for an error - if(isValid === false) { - messageContainer.style.display = 'inline'; - message.textContent ="Please fil out all the fields"; - message.style.color = 'text-color'; - } else if(isValid === true) { - messageContainer.style.display = 'inline'; - message.textContent ="Your message is being sent"; - message.style.color = 'text-color'; - } -} - - function processFormData(e) { - e.preventDefault() - - // Validating form - validateForm(); - - // Sending the formdata - if(isValid === true) { - emailjs.send(vars.SERVICE_ID, vars.TEMPLATE_ID, { - name : "Nipun Hedaoo", - from_name: userName.value, - email: userEmail.value, - message: userMessage.value, - }) - .then(function(response){ - message.textContent ="Thank you very much we will reply to you as soon as possible"; - message.style.color = 'green'; - messageContainer.style.borderColor = 'green'; - console.log('SUCCES', response.status, response.text); - form.reset(); - }, function(error){ - console.log("FAILED", error); - }) - } - } - - // Add eventlisteners -form.addEventListener('submit', processFormData); diff --git a/js/main.js b/js/main.js index 2b428c2..1333018 100644 --- a/js/main.js +++ b/js/main.js @@ -60,22 +60,64 @@ tabs.forEach(tab => { // =================================== Portfolio ====================== -// var swiper = new Swiper(".portfolio__container", { -// cssMode: true, -// loop : true, -// navigation: { -// nextEl: ".swiper-button-next", -// prevEl: ".swiper-button-prev", -// }, -// pagination: { -// el: ".swiper-pagination", -// clickable : true -// }, - -// mousewheel : true, -// keyboard : true -// }); +async function fetchProjects() { + try { + const response = await fetch('data/projects.json'); // Ensure the correct path + const projects = await response.json(); + + Object.entries(projects["projects"]).forEach(([category, categoryProjects]) => { + Object.values(categoryProjects).forEach(project => { + createProjectCard(project, category); + }); + }); + } catch (error) { + console.error('Error fetching project data:', error); + } +} + +function createProjectCard(project, category) { + const container = document.getElementById(category); + const card = document.createElement('div'); + card.classList.add('project-card', 'color-container', 'flip-card'); + card.setAttribute('data-card', project.id); + + const flipCardInner = document.createElement('div'); + flipCardInner.classList.add('flip-card-inner'); + + const flipCardFront = document.createElement('div'); + flipCardFront.classList.add('flip-card-front'); + flipCardFront.innerHTML = ` + ${project.title} +

${project.title}

+
+ ${project.links?.live ? `` : ''} + ${project.links?.github ? `` : ''} + +
+ `; + + const flipCardBack = document.createElement('div'); + flipCardBack.classList.add('flip-card-back'); + flipCardBack.innerHTML = ` + +
+

${project.title}

+ +
+ `; + + flipCardInner.appendChild(flipCardFront); + flipCardInner.appendChild(flipCardBack); + card.appendChild(flipCardInner); + container.appendChild(card); +} +document.addEventListener('DOMContentLoaded', fetchProjects); // ================================== Skills ========================== diff --git a/perfil.png b/perfil.png deleted file mode 100644 index 1f08507..0000000 Binary files a/perfil.png and /dev/null differ diff --git a/tracking.js b/tracking.js new file mode 100644 index 0000000..80bf88e --- /dev/null +++ b/tracking.js @@ -0,0 +1,137 @@ +(document.addEventListener("DOMContentLoaded", function () { + const container = document.getElementById("location-popup-container"); + // const apiUrl = "https://counterbynipun.onrender.com/api/track"; + const apiUrl = "http://localhost:3000/api/track"; + const token = getQueryParam("token"); + + // Function to retrieve query parameter from script URL + function getQueryParam(param) { + const script = document.currentScript; + const url = new URL(script.src); + return url.searchParams.get(param); + } + + // Function to hash data (IP in this case) using SHA-256 + async function hashIP(ip) { + const encoder = new TextEncoder(); + const data = encoder.encode(ip); + const hashBuffer = await crypto.subtle.digest("SHA-256", data); + return Array.from(new Uint8Array(hashBuffer)) + .map((byte) => byte.toString(16).padStart(2, "0")) + .join(""); + } + + function getOSAndDevice() { + const userAgent = navigator.userAgent; + let os = "Unknown OS"; + if (userAgent.indexOf("Win") !== -1) os = "Windows"; + else if (userAgent.indexOf("Mac") !== -1) os = "macOS"; + else if (userAgent.indexOf("Linux") !== -1) os = "Linux"; + else if (userAgent.indexOf("Android") !== -1) os = "Android"; + else if (/iPhone|iPad|iPod/.test(userAgent)) os = "iOS"; + + let device = "Desktop"; + if (/Mobile|Android|iPhone|iPad|iPod/.test(userAgent)) device = "Mobile"; + + return { os, device }; + } + + // Function to get the user's IP + async function getUserIP() { + try { + const response = await fetch("https://api.ipify.org?format=json"); + if (!response.ok) throw new Error(`Failed to fetch IP: ${response.status}`); + const data = await response.json(); + return data.ip; + } catch (error) { + console.error("Error fetching IP:", error); + return null; + } + } + + // Function to get user's IP and location (only if consented) + async function getUserIPAndLocation() { + try { + const response = await fetch("https://ipinfo.io/json?token=4fe0c05bf130d0"); + if (!response.ok) throw new Error(`Failed to fetch location: ${response.status}`); + return await response.json(); + } catch (error) { + console.error("Error fetching location:", error); + return null; + } + } + + // Function to send tracking data + async function sendTrackingData(collectLocation) { + try { + const ip = await getUserIP(); + if (!ip) return; + + const hashedIP = await hashIP(ip); + const userAgentInfo = getOSAndDevice(); + let requestData = { + ipAddress: hashedIP, + os: userAgentInfo.os, + device: userAgentInfo.device, + }; + + if (collectLocation) { + const locationData = await getUserIPAndLocation(); + if (locationData) { + requestData.city = locationData.city; + requestData.country = locationData.country; + } + } + + await fetch(`${apiUrl}/${token}`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(requestData), + }); + } catch (error) { + console.error("Tracking failed:", error); + } + } + + // Show popup if no prior consent + if (!localStorage.getItem("locationConsent")) { + const popup = document.createElement("div"); + popup.id = "location-popup"; + popup.style.position = "fixed"; + popup.style.bottom = "20px"; + popup.style.left = "50%"; + popup.style.transform = "translateX(-50%)"; + popup.style.background = "#333"; + popup.style.color = "white"; + popup.style.padding = "15px"; + popup.style.borderRadius = "5px"; + popup.style.boxShadow = "0px 0px 10px rgba(0,0,0,0.2)"; + popup.style.display = "flex"; + popup.style.alignItems = "center"; + popup.style.justifyContent = "space-between"; + popup.style.minWidth = "300px"; + + popup.innerHTML = ` + Allow location tracking for analytics? + + + `; + + container.appendChild(popup); + + document.getElementById("accept-btn").addEventListener("click", function () { + localStorage.setItem("locationConsent", "accepted"); + popup.remove(); + sendTrackingData(true); // Collect location data + }); + + document.getElementById("decline-btn").addEventListener("click", function () { + localStorage.setItem("locationConsent", "declined"); + popup.remove(); + sendTrackingData(false); // Only collect hashed IP + }); + } else { + // Use stored consent value + sendTrackingData(localStorage.getItem("locationConsent") === "accepted"); + } +}))(); \ No newline at end of file