diff --git a/README.md b/README.md index 98fdafc9..9c4ed67b 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,71 @@ -# Portfolio Responsive Complete -## [Watch it on youtube](https://youtu.be/AKNvTxWOdKw) -### Portfolio Responsive Complete +# Halimat Aminu - Cybersecurity Portfolio -- Responsive Personal Portfolio Website HTML CSS & JavaScript. -- Contains animations when scrolling. -- Smooth scrolling in each section. -- Developed first with the Mobile First methodology, then for desktop. -- Compatible with all mobile devices and with a beautiful and pleasant user interface. +A professional portfolio website for Halimat Aminu, Cybersecurity Engineer & Chief Technology Officer. This website showcases cybersecurity expertise, professional experience, projects, and thought leadership. -💙 Join the channel to see more videos like this. [Bedimcode](https://www.youtube.com/@Bedimcode) +## Features - +- 🛡️ **Cybersecurity-Focused Design**: Dark theme with security-inspired elements +- 📱 **Fully Responsive**: Works perfectly on all devices +- ⚡ **High Performance**: Optimized for fast loading +- ♿ **Accessibility**: WCAG 2.1 AA compliant with keyboard navigation and screen reader support +- 🎨 **Modern UI/UX**: Clean, professional interface with smooth animations +- 📊 **Interactive Elements**: + - Skills radar chart (Chart.js) + - Typing animation for professions + - Project case studies + - Blog with filtering functionality +- 🔐 **Security Features**: + - Secure contact form with validation + - HTTPS-ready structure + - Form submission protection +- 🌓 **Dark/Light Theme**: User preference detection with persistent settings +## Pages + +1. **Home** (`index.html`) - Landing page with hero section, stats, and overview +2. **About** - Professional background and technical expertise +3. **Experience** - Detailed work history with achievements and skills +4. **Projects** (`projects.html`) - Detailed case studies with technical implementations +5. **Blog** (`blog.html`) - Cybersecurity articles and insights with filtering +6. **Contact** - Secure contact form with email, GitHub, and LinkedIn links + +## Technologies Used + +- **HTML5**: Semantic markup with ARIA labels +- **CSS3**: Modern features with CSS Grid and Flexbox +- **JavaScript (ES6+)**: Interactive features and animations +- **Chart.js**: Skills visualization +- **Boxicons**: Icon library +- **Google Fonts**: Space Grotesk (headings) and Inter (body) + +## File Structure +portfolio/ +├── index.html # Main homepage +├── blog.html # Blog page +├── projects.html # Projects page +├── assets/ +│ ├── css/ +│ │ ├── styles.css # Main styles +│ │ ├── blog.css # Blog-specific styles +│ │ └── projects.css # Projects-specific styles +│ ├── js/ +│ │ ├── main.js # Main JavaScript +│ │ ├── blog.js # Blog-specific JavaScript +│ │ └── projects.js # Projects-specific JavaScript +│ └── img/ # All images +├── README.md # This file +└── favicon.ico # Website icon + +## Getting Started + +### Prerequisites +- A modern web browser (Chrome, Firefox, Safari, Edge) +- Basic text editor (VS Code recommended) +- Git (for version control) + +### Installation + +1. Clone the repository: +```bash +git clone https://github.com/Halimatcd/halimataminu-portfolio.git +cd halimataminu-portfolio \ No newline at end of file diff --git a/assets/css/styles.css b/assets/css/styles.css index c83e8125..59300694 100644 --- a/assets/css/styles.css +++ b/assets/css/styles.css @@ -1,486 +1,1560 @@ -/*===== GOOGLE FONTS =====*/ -@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap"); -/*===== VARIABLES CSS =====*/ +/* ===== GOOGLE FONTS ===== */ +@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600&display=swap'); + +/* ===== VARIABLES ===== */ :root { - --header-height: 3rem; - --font-semi: 600; - /*===== Colores =====*/ - /*Purple 260 - Red 355 - Blue 224 - Pink 340*/ - /* HSL color mode */ - --hue-color: 224; - --first-color: hsl(var(--hue-color), 89%, 60%); - --second-color: hsl(var(--hue-color), 56%, 12%); - /*===== Fuente y tipografia =====*/ - --body-font: "Poppins", sans-serif; - --big-font-size: 2rem; - --h2-font-size: 1.25rem; - --normal-font-size: .938rem; - --smaller-font-size: .75rem; - /*===== Margenes =====*/ - --mb-2: 1rem; - --mb-4: 2rem; - --mb-5: 2.5rem; - --mb-6: 3rem; - /*===== z index =====*/ - --z-back: -10; - --z-fixed: 100; -} -@media screen and (min-width: 968px) { - :root { - --big-font-size: 3.5rem; - --h2-font-size: 2rem; - --normal-font-size: 1rem; - --smaller-font-size: .875rem; - } -} - -/*===== BASE =====*/ -*, ::before, ::after { + /* Cybersecurity Color Scheme */ + --primary-color: #30f907; + --primary-color-alt: #27c205; + --secondary-color: #9d4edd; + --dark-color: #000059; + --dark-color-alt: #13182a; + --light-color: #f8f9fa; + --gray-color: #6c757d; + --success-color: #00ff88; + --warning-color: #ffaa00; + --danger-color: #ff375f; + + /* Typography */ + --body-font: 'Inter', sans-serif; + --title-font: 'Space Grotesk', sans-serif; + + /* Other */ + --border-radius: 12px; + --box-shadow: 0 10px 30px rgba(0, 212, 255, 0.1); + --transition: all 0.3s ease; +} + +/* Dark theme variables */ +.dark-theme { + --dark-color: #0a0a0f; + --dark-color-alt: #121218; + --light-color: #f8f9fa; +} + +/* ===== BASE ===== */ +* { + margin: 0; + padding: 0; box-sizing: border-box; } -html { - scroll-behavior: smooth; +html { + scroll-behavior: smooth; + scroll-padding-top: 5rem; +} + +body { + font-family: var(--body-font); + background-color: var(--dark-color); + color: var(--light-color); + line-height: 1.6; + overflow-x: hidden; + margin: 0; + padding: 0; + transition: background-color 0.3s ease; +} + +h1, h2, h3, h4 { + font-family: var(--title-font); + font-weight: 600; +} + +a { + text-decoration: none; + color: inherit; +} + +ul { + list-style: none; +} + +img { + max-width: 100%; + height: auto; + display: block; +} + +/* ===== REUSABLE CLASSES ===== */ +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 1.5rem; +} + +.section { + padding: 6rem 0 4rem; + scroll-margin-top: 5rem; +} + +.section__title { + font-size: 2.5rem; + text-align: center; + margin-bottom: 3rem; + position: relative; +} + +.section__title span { + color: var(--primary-color); + position: relative; +} + +.section__title::after { + content: ''; + position: absolute; + width: 60px; + height: 3px; + background: var(--primary-color); + bottom: -10px; + left: 50%; + transform: translateX(-50%); + border-radius: 2px; +} + +.grid { + display: grid; + gap: 2rem; +} + +.button { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.875rem 2rem; + background: var(--primary-color); + color: var(--dark-color); + border-radius: var(--border-radius); + font-weight: 500; + transition: var(--transition); + border: 2px solid transparent; + cursor: pointer; + font-family: var(--body-font); + font-size: 1rem; + text-decoration: none; +} + +.button:hover { + background: transparent; + color: var(--primary-color); + border-color: var(--primary-color); + transform: translateY(-3px); + box-shadow: 0 10px 20px rgba(48, 249, 7, 0.2); +} + +.button--ghost { + background: transparent; + color: var(--primary-color); + border: 2px solid var(--primary-color); +} + +.button--ghost:hover { + background: var(--primary-color); + color: var(--dark-color); +} + +/* ===== HEADER ===== */ +.header { + position: fixed; + top: 0; + left: 0; + width: 100%; + background-color: rgba(10, 14, 23, 0.95); + backdrop-filter: blur(10px); + z-index: 1000; + border-bottom: 1px solid rgba(48, 249, 7, 0.1); + transition: var(--transition); +} + +.nav { + display: flex; + justify-content: space-between; + align-items: center; + height: 4.5rem; + padding: 0 1.5rem; +} + +.nav__logo { + display: flex; + align-items: center; + gap: 0.75rem; + font-weight: 600; + font-size: 1.25rem; + color: var(--light-color); + text-decoration: none; +} + +.nav__logo-circle { + display: flex; + align-items: center; + justify-content: center; + width: 2.5rem; + height: 2.5rem; + background: var(--primary-color); + color: var(--dark-color); + border-radius: 50%; + font-weight: 700; +} + +.nav__list { + display: flex; + gap: 2.5rem; +} + +.nav__link { + position: relative; + font-weight: 500; + transition: var(--transition); + color: var(--light-color); + text-decoration: none; +} + +.nav__link::after { + content: ''; + position: absolute; + width: 0; + height: 2px; + background: var(--primary-color); + bottom: -5px; + left: 0; + transition: var(--transition); +} + +.nav__link:hover, +.nav__link.active-link { + color: var(--primary-color); +} + +.nav__link:hover::after, +.nav__link.active-link::after { + width: 100%; +} + +.nav__buttons { + display: flex; + align-items: center; + gap: 1rem; +} + +.change-theme, +.nav__toggle { + font-size: 1.5rem; + cursor: pointer; + transition: var(--transition); + color: var(--light-color); + background: none; + border: none; +} + +.change-theme:hover, +.nav__toggle:hover { + color: var(--primary-color); +} + +.nav__close { + display: none; + font-size: 1.5rem; + cursor: pointer; + color: var(--light-color); + background: none; + border: none; +} + +/* Mobile menu */ +.nav__menu { + display: flex; + align-items: center; +} + +@media screen and (max-width: 768px) { + .nav__menu { + position: fixed; + top: 0; + right: -100%; + width: 80%; + height: 100%; + background: var(--dark-color-alt); + padding: 6rem 3rem; + transition: var(--transition); + box-shadow: -5px 0 20px rgba(0, 0, 0, 0.2); + z-index: 999; + display: block; + } + + .nav__menu.show-menu { + right: 0; + } + + .nav__list { + flex-direction: column; + gap: 2rem; + } + + .nav__close { + display: block; + position: absolute; + top: 1.5rem; + right: 1.5rem; + } +} + +/* ===== HOME ===== */ +.home { + position: relative; + padding-top: 8rem; + overflow: hidden; + min-height: 100vh; + display: flex; + align-items: center; + background: url('../assets/img/hero23.png') center/cover no-repeat; + background-position: center; + background-repeat: no-repeat; + background-size: cover; +} + +.home::before { + content: ''; + position: absolute; + inset: 0; + background: rgba(2, 11, 40, 0.72); + z-index: 1; + pointer-events: none; +} + +.home__container { + position: relative; + display: grid; + grid-template-columns: 1fr 1fr; + align-items: center; + gap: 4rem; + z-index: 3; +} + +.home__data { + z-index: 4; +} + +.home__title { + font-size: 3.5rem; + line-height: 1.2; + margin-bottom: 1rem; + color: var(--light-color); +} + +.home__title-gradient { + background: linear-gradient(90deg, var(--primary-color), var(--secondary-color)); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + display: inline-block; +} + +.typing-container { + margin-top: 0.5rem; + height: 3rem; + display: flex; + align-items: center; +} + +.typing-text { + font-size: 2rem; + color: var(--primary-color); + position: relative; + font-family: var(--title-font); + font-weight: 600; + min-height: 3rem; + display: inline-block; +} + +.typing-text::after { + content: '|'; + position: absolute; + right: -8px; + animation: blink 1s infinite; +} + +@keyframes blink { + 0%, 100% { opacity: 1; } + 50% { opacity: 0; } +} + +.home__description { + font-size: 1.125rem; + margin-bottom: 2rem; + max-width: 600px; + color: rgba(248, 249, 250, 0.9); + line-height: 1.8; +} + +.home__buttons { + display: flex; + gap: 1rem; + margin-bottom: 3rem; + flex-wrap: wrap; +} + +.home__stats { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 2rem; + margin-top: 3rem; +} + +.home__stat { + text-align: center; +} + +.home__stat-number { + display: block; + font-size: 2.5rem; + font-weight: 700; + color: var(--primary-color); + margin-bottom: 0.25rem; + font-family: var(--title-font); +} + +.home__stat-text { + font-size: 0.875rem; + color: var(--gray-color); + text-transform: uppercase; + letter-spacing: 1px; +} + +.home__image { + position: relative; + justify-self: center; +} + +.home__blob { + width: 620px; + height: 620px; + position: relative; + display: flex; + align-items: center; + justify-content: center; +} + +.home__blob-img { + width: 500px; + height: auto; + border-radius: 50%; + object-fit: cover; + position: relative; + z-index: 2; + border: 4px solid rgba(48, 249, 7, 0.3); + box-shadow: 0 0 50px rgba(48, 249, 7, 0.2); +} + +.home__blob svg { + position: absolute; + width: 100%; + height: 100%; + fill: var(--primary-color); + opacity: 0.1; + z-index: 1; +} + +.home__scroll { + position: absolute; + bottom: 2rem; + left: 50%; + transform: translateX(-50%); + animation: bounce 2s infinite; + z-index: 4; +} + +.home__scroll-link { + display: flex; + align-items: center; + gap: 0.5rem; + color: var(--primary-color); + font-weight: 500; + text-decoration: none; + background: rgba(10, 14, 23, 0.7); + padding: 0.75rem 1.5rem; + border-radius: var(--border-radius); + border: 1px solid rgba(48, 249, 7, 0.3); +} + +@keyframes bounce { + 0%, 100% { transform: translateX(-50%) translateY(0); } + 50% { transform: translateX(-50%) translateY(-10px); } +} + +/* ===== ABOUT ===== */ +.about__container { + display: grid; + grid-template-columns: 1fr 1fr; + align-items: center; + gap: 4rem; +} + +.about__description { + margin-bottom: 2rem; + color: rgba(248, 249, 250, 0.9); + font-size: 1.125rem; + line-height: 1.8; +} + +.about__details { + margin-bottom: 2rem; +} + +.about__detail { + display: flex; + align-items: flex-start; + gap: 1rem; + margin-bottom: 1.5rem; +} + +.about__detail i { + font-size: 1.5rem; + color: var(--primary-color); + margin-top: 0.25rem; + flex-shrink: 0; +} + +.about__detail h3 { + margin-bottom: 0.5rem; + color: var(--light-color); + font-size: 1.25rem; +} + +.about__detail p { + color: rgba(248, 249, 250, 0.8); + font-size: 0.95rem; +} + +.about__image { + position: relative; + overflow: visible; +} + +.about__blob { + width: 520px; + height: 520px; + background: linear-gradient(45deg, var(--primary-color), var(--secondary-color)); + opacity: 0.08; + border-radius: 50%; + position: relative; + margin: 0 auto; +} + +.about__tech-stack { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 2rem; + width: 90%; +} + +.tech-icon { + width: 140px; + height: 140px; + background: var(--dark-color-alt); + border-radius: 18px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: 4rem; + transition: var(--transition); + cursor: pointer; + position: relative; + color: var(--light-color); + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.35); + text-decoration: none; +} + +.tech-icon:hover { + background: var(--primary-color); + color: var(--dark-color); + transform: translateY(-8px); + box-shadow: 0 14px 35px rgba(48, 249, 7, 0.35); +} + +.tech-icon .tech-level { + display: block; + font-size: 1rem; + font-weight: 600; + color: rgba(248, 249, 250, 0.95); + margin-top: 0.75rem; +} + +.tech-icon:hover .tech-level { + color: var(--dark-color); +} + +.tech-icon::after { + content: attr(data-tooltip); + position: absolute; + bottom: -52px; + left: 50%; + transform: translateX(-50%); + background: var(--dark-color); + color: var(--light-color); + padding: 0.6rem 1rem; + border-radius: 4px; + font-size: 0.875rem; + white-space: nowrap; + opacity: 0; + visibility: hidden; + transition: var(--transition); + z-index: 10; + border: 1px solid rgba(48, 249, 7, 0.2); +} + +.tech-icon:hover::after { + opacity: 1; + visibility: visible; + bottom: -46px; +} + +/* ===== EXPERIENCE ===== */ +.experience__container { + max-width: 1200px; + margin: 0 auto; +} + +.experience__timeline { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); + gap: 2rem; +} + +.experience__item { + position: relative; + background: var(--dark-color-alt); + border-radius: var(--border-radius); + border: 1px solid rgba(255, 255, 255, 0.05); + padding: 2rem; + transition: var(--transition); +} + +.experience__item:hover { + border-color: var(--primary-color); + transform: translateY(-5px); + box-shadow: var(--box-shadow); +} + +.experience__header { + display: flex; + align-items: center; + gap: 1rem; + margin-bottom: 1rem; +} + +.experience__icon { + width: 48px; + height: 48px; + background: var(--primary-color); + color: var(--dark-color); + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.25rem; + flex-shrink: 0; +} + +.experience__date { + font-size: 0.875rem; + color: var(--primary-color); + font-weight: 500; + background: rgba(48, 249, 7, 0.1); + padding: 0.25rem 0.75rem; + border-radius: 20px; + border: 1px solid rgba(48, 249, 7, 0.3); +} + +.experience__company { + display: flex; + align-items: center; + gap: 1rem; + margin-bottom: 1.5rem; +} + +.experience__logo { + width: 60px; + height: 60px; + background: var(--dark-color); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; + font-size: 1.25rem; + color: var(--primary-color); + flex-shrink: 0; + border: 2px solid var(--primary-color); +} + +.experience__title { + font-size: 1.25rem; + margin-bottom: 0.25rem; + color: var(--light-color); +} + +.experience__company-name { + color: var(--gray-color); + font-size: 0.875rem; +} + +.experience__details { + margin-bottom: 1.5rem; + padding-left: 0; +} + +.experience__details li { + display: flex; + align-items: flex-start; + gap: 0.75rem; + margin-bottom: 0.75rem; + color: rgba(248, 249, 250, 0.9); + line-height: 1.6; +} + +.experience__details li:last-child { + margin-bottom: 0; +} + +.experience__details i { + color: var(--primary-color); + margin-top: 0.25rem; + font-size: 0.875rem; + flex-shrink: 0; +} + +.experience__skills { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-top: 1rem; +} + +.skill-tag { + padding: 0.375rem 0.875rem; + background: rgba(48, 249, 7, 0.1); + border: 1px solid var(--primary-color); + border-radius: 20px; + font-size: 0.75rem; + color: var(--primary-color); + transition: var(--transition); +} + +.skill-tag:hover { + background: var(--primary-color); + color: var(--dark-color); + transform: translateY(-2px); +} + +/* ===== PROJECTS ===== */ +.projects__container { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); + gap: 3rem; +} + +.project__card { + background: var(--dark-color-alt); + border-radius: var(--border-radius); + overflow: hidden; + transition: var(--transition); + border: 1px solid rgba(48, 249, 7, 0.1); + height: 100%; + display: flex; + flex-direction: column; +} + +.project__card:hover { + transform: translateY(-10px); + box-shadow: var(--box-shadow); + border-color: var(--primary-color); +} + +.project__image { + position: relative; + height: 220px; + overflow: hidden; +} + +.project__image img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s ease; +} + +.project__card:hover .project__image img { + transform: scale(1.1); +} + +.project__overlay { + position: absolute; + top: 1rem; + left: 1rem; + display: flex; + gap: 0.5rem; +} + +.project__tag { + padding: 0.375rem 0.875rem; + background: var(--dark-color); + color: var(--primary-color); + border-radius: 20px; + font-size: 0.75rem; + font-weight: 500; + border: 1px solid rgba(48, 249, 7, 0.3); } -body { - margin: var(--header-height) 0 0 0; - font-family: var(--body-font); - font-size: var(--normal-font-size); - color: var(--second-color); +.project__content { + padding: 1.5rem; + flex-grow: 1; + display: flex; + flex-direction: column; } -h1, h2, p { - margin: 0; +.project__title { + font-size: 1.5rem; + margin-bottom: 0.75rem; + color: var(--light-color); } -ul { - margin: 0; - padding: 0; - list-style: none; +.project__description { + color: rgba(248, 249, 250, 0.9); + margin-bottom: 1.5rem; + line-height: 1.6; + flex-grow: 1; } -a { +.project__tech { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-bottom: 1.5rem; +} + +.project__tech span { + padding: 0.375rem 0.75rem; + background: rgba(48, 249, 7, 0.1); + border-radius: 4px; + font-size: 0.75rem; + color: var(--primary-color); + border: 1px solid rgba(48, 249, 7, 0.2); +} + +.project__link { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--primary-color); + font-weight: 500; + font-size: 0.875rem; + transition: var(--transition); + margin-top: auto; text-decoration: none; } -img { - max-width: 100%; - height: auto; - display: block; +.project__link:hover { + gap: 0.75rem; + color: var(--secondary-color); } -/*===== CLASS CSS ===== */ -.section-title { - position: relative; - font-size: var(--h2-font-size); - color: var(--first-color); - margin-top: var(--mb-2); - margin-bottom: var(--mb-4); - text-align: center; +/* ===== SKILLS ===== */ +.skills__container { + display: grid; + grid-template-columns: 1fr 2fr; + gap: 4rem; + align-items: center; } -.section-title::after { - position: absolute; - content: ""; - width: 64px; - height: 0.18rem; - left: 0; - right: 0; - margin: auto; - top: 2rem; - background-color: var(--first-color); + +.skills__radar { + width: 100%; + max-width: 300px; + margin: 0 auto; + height: 300px; } -.section { - padding-top: 3rem; - padding-bottom: 2rem; +.skills__radar canvas { + width: 100% !important; + height: 100% !important; +} + +.skills__content { + width: 100%; } -/*===== LAYOUT =====*/ -.bd-grid { - max-width: 1024px; +.skills__groups { display: grid; - margin-left: var(--mb-2); - margin-right: var(--mb-2); + gap: 2rem; +} + +.skills__group { + background: var(--dark-color-alt); + padding: 1.5rem; + border-radius: var(--border-radius); + border: 1px solid rgba(48, 249, 7, 0.1); +} + +.skills__group-title { + display: flex; + align-items: center; + gap: 0.75rem; + font-size: 1.25rem; + margin-bottom: 1rem; + color: var(--primary-color); + font-family: var(--title-font); + font-weight: 600; +} + +.skills__group-title i { + font-size: 1.5rem; +} + +.skills__list { + display: flex; + flex-direction: column; + gap: 1.25rem; } -.l-header { +.skill__item { width: 100%; - position: fixed; - top: 0; - left: 0; - z-index: var(--z-fixed); - background-color: #fff; - box-shadow: 0 1px 4px rgba(146, 161, 176, 0.15); } -/*===== NAV =====*/ -.nav { - height: var(--header-height); +.skill__info { display: flex; justify-content: space-between; align-items: center; - font-weight: var(--font-semi); + margin-bottom: 0.5rem; } -@media screen and (max-width: 767px) { - .nav__menu { - position: fixed; - top: var(--header-height); - right: -100%; - width: 80%; - height: 100%; - padding: 2rem; - background-color: var(--second-color); - transition: 0.5s; - } + +.skill__info span { + font-weight: 500; + color: var(--light-color); } -.nav__item { - margin-bottom: var(--mb-4); + +.skill__info span:last-child { + color: var(--primary-color); + font-weight: 600; } -.nav__link { + +.skill__bar { + height: 8px; + background: var(--dark-color); + border-radius: 4px; + overflow: hidden; position: relative; - color: #fff; } -.nav__link:hover { + +.skill__percentage { + height: 100%; + background: linear-gradient(90deg, var(--primary-color), var(--secondary-color)); + border-radius: 4px; position: relative; + width: 0; + transition: width 1.5s ease-out; } -.nav__link:hover::after { - position: absolute; - content: ""; - width: 100%; - height: 0.18rem; - left: 0; - top: 2rem; - background-color: var(--first-color); + +/* ===== CERTIFICATIONS ===== */ +.certifications__container { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem; } -.nav__logo { - color: var(--second-color); + +.certification__card { + background: var(--dark-color-alt); + padding: 2rem; + border-radius: var(--border-radius); + text-align: center; + transition: var(--transition); + border: 1px solid rgba(48, 249, 7, 0.1); + display: flex; + flex-direction: column; + align-items: center; + text-decoration: none; } -.nav__toggle { - color: var(--second-color); - font-size: 1.5rem; - cursor: pointer; + +.certification__card:hover { + transform: translateY(-5px); + border-color: var(--primary-color); + box-shadow: var(--box-shadow); } -/*Active menu*/ -.active-link::after { - position: absolute; - content: ""; - width: 100%; - height: 0.18rem; - left: 0; - top: 2rem; - background-color: var(--first-color); +.certification__icon { + font-size: 3rem; + color: var(--primary-color); + width: 80px; + height: 80px; + display: flex; + align-items: center; + justify-content: center; + background: rgba(48, 249, 7, 0.08); + border-radius: 50%; + margin-bottom: 1.5rem; } -/*=== Show menu ===*/ -.show { - right: 0; +.certification__title { + font-size: 1.125rem; + margin-bottom: 0.5rem; + color: var(--light-color); + line-height: 1.4; } -/*===== HOME =====*/ -.home { - position: relative; - row-gap: 5rem; - padding: 4rem 0 5rem; +.certification__issuer { + color: var(--gray-color); + font-size: 0.875rem; + margin-bottom: 0.5rem; } -.home__data { - align-self: center; + +.certification__date { + color: var(--primary-color); + font-size: 0.875rem; + font-weight: 500; + margin-top: auto; + padding-top: 1rem; + border-top: 1px solid rgba(48, 249, 7, 0.1); + width: 100%; } -.home__title { - font-size: var(--big-font-size); - margin-bottom: var(--mb-5); + +/* ===== CONTACT ===== */ +.contact__container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4rem; } -.home__title-color { - color: var(--first-color); + +.contact__title { + font-size: 1.75rem; + margin-bottom: 1rem; + color: var(--light-color); +} + +.contact__description { + color: rgba(248, 249, 250, 0.9); + margin-bottom: 2rem; + line-height: 1.7; +} + +.contact__info { + margin-bottom: 2rem; } -.home__social { + +.contact__detail { display: flex; - flex-direction: column; + align-items: flex-start; + gap: 1rem; + margin-bottom: 1.5rem; + padding: 1rem; + background: var(--dark-color-alt); + border-radius: var(--border-radius); + border-left: 3px solid var(--primary-color); + text-decoration: none; + transition: var(--transition); +} + +.contact__detail:hover { + transform: translateX(5px); + border-color: var(--secondary-color); } -.home__social-icon { - width: max-content; - margin-bottom: var(--mb-2); + +.contact__detail i { font-size: 1.5rem; - color: var(--second-color); + color: var(--primary-color); + margin-top: 0.25rem; + flex-shrink: 0; } -.home__social-icon:hover { - color: var(--first-color); + +.contact__detail-title { + display: block; + font-size: 0.875rem; + color: var(--gray-color); + margin-bottom: 0.25rem; + text-transform: uppercase; + letter-spacing: 1px; } -.home__img { - position: absolute; - right: 0; - bottom: 0; - width: 260px; + +.contact__detail-data { + color: var(--light-color); + transition: var(--transition); + font-weight: 500; + text-decoration: none; } -.home__blob { - fill: var(--first-color); + +.contact__detail:hover .contact__detail-data { + color: var(--primary-color); } -.home__blob-img { - width: 360px; + +.contact__form { + background: var(--dark-color-alt); + padding: 2rem; + border-radius: var(--border-radius); + border: 1px solid rgba(48, 249, 7, 0.1); } -/*BUTTONS*/ -.button { - display: inline-block; - background-color: var(--first-color); - color: #fff; - padding: 0.75rem 2.5rem; - font-weight: var(--font-semi); - border-radius: 0.5rem; - transition: 0.3s; +.contact__inputs { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; + margin-bottom: 1rem; } -.button:hover { - box-shadow: 0px 10px 36px rgba(0, 0, 0, 0.15); + +.contact__content { + position: relative; + margin-bottom: 1.5rem; } -/* ===== ABOUT =====*/ -.about__container { - row-gap: 2rem; - text-align: center; +.contact__input { + width: 100%; + padding: 1rem; + background: var(--dark-color); + border: 1px solid rgba(48, 249, 7, 0.2); + border-radius: var(--border-radius); + color: var(--light-color); + outline: none; + transition: var(--transition); + font-family: var(--body-font); + font-size: 1rem; } -.about__subtitle { - margin-bottom: var(--mb-2); + +.contact__input:focus { + border-color: var(--primary-color); + box-shadow: 0 0 0 3px rgba(48, 249, 7, 0.1); } -.about__img { - justify-self: center; + +.contact__label { + position: absolute; + top: 1rem; + left: 1rem; + color: var(--gray-color); + transition: var(--transition); + pointer-events: none; + font-size: 1rem; + background: transparent; + padding: 0 0.25rem; } -.about__img img { - width: 200px; - border-radius: 0.5rem; + +.contact__input:focus + .contact__label, +.contact__input:not(:placeholder-shown) + .contact__label { + top: -0.75rem; + left: 0.75rem; + font-size: 0.75rem; + background: var(--dark-color-alt); + color: var(--primary-color); } -/* ===== SKILLS =====*/ -.skills__container { - row-gap: 2rem; - text-align: center; +.contact__textarea { + min-height: 150px; + resize: vertical; + font-family: var(--body-font); +} + +.contact__button { + width: 100%; + justify-content: center; + margin-top: 1rem; +} + +/* ===== FOOTER ===== */ +.footer { + background: var(--dark-color-alt); + padding-top: 4rem; + border-top: 1px solid rgba(48, 249, 7, 0.1); + margin-top: 4rem; } -.skills__subtitle { - margin-bottom: var(--mb-2); + +.footer__container { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 3rem; + padding: 0 1.5rem; } -.skills__text { - margin-bottom: var(--mb-4); + +.footer__content { + grid-column: span 1; } -.skills__data { + +.footer__logo { display: flex; - justify-content: space-between; align-items: center; - position: relative; - font-weight: var(--font-semi); - padding: 0.5rem 1rem; - margin-bottom: var(--mb-4); - border-radius: 0.5rem; - box-shadow: 0px 4px 25px rgba(14, 36, 49, 0.15); -} -.skills__icon { - font-size: 2rem; - margin-right: var(--mb-2); - color: var(--first-color); + gap: 0.75rem; + font-weight: 600; + font-size: 1.25rem; + color: var(--light-color); + margin-bottom: 1rem; + text-decoration: none; } -.skills__names { + +.footer__logo-circle { display: flex; align-items: center; + justify-content: center; + width: 2.5rem; + height: 2.5rem; + background: var(--primary-color); + color: var(--dark-color); + border-radius: 50%; + font-weight: 700; } -.skills__bar { - position: absolute; - left: 0; - bottom: 0; - background-color: var(--first-color); - height: 0.25rem; - border-radius: 0.5rem; - z-index: var(--z-back); + +.footer__description { + color: rgba(248, 249, 250, 0.9); + margin-bottom: 1.5rem; + line-height: 1.6; +} + +.footer__social { + display: flex; + gap: 1rem; } -.skills__html { - width: 95%; + +.footer__social-link { + width: 40px; + height: 40px; + background: var(--dark-color); + color: var(--light-color); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: var(--transition); + font-size: 1.25rem; + text-decoration: none; } -.skills__css { - width: 85%; + +.footer__social-link:hover { + background: var(--primary-color); + color: var(--dark-color); + transform: translateY(-3px); } -.skills__js { - width: 65%; + +.footer__title { + font-size: 1.125rem; + margin-bottom: 1rem; + color: var(--light-color); + font-family: var(--title-font); } -.skills__ux { - width: 85%; + +.footer__list { + display: flex; + flex-direction: column; + gap: 0.75rem; } -.skills__img { - border-radius: 0.5rem; + +.footer__link { + color: rgba(248, 249, 250, 0.9); + transition: var(--transition); + text-decoration: none; + font-size: 0.95rem; } -/* ===== WORK =====*/ -.work__container { - row-gap: 2rem; +.footer__link:hover { + color: var(--primary-color); + padding-left: 0.25rem; } -.work__img { - box-shadow: 0px 4px 25px rgba(14, 36, 49, 0.15); - border-radius: 0.5rem; - overflow: hidden; + +.footer__newsletter { + grid-column: span 1; } -.work__img img { - transition: 1s; + +.footer__newsletter-description { + color: rgba(248, 249, 250, 0.9); + margin-bottom: 1rem; + font-size: 0.95rem; + line-height: 1.6; } -.work__img img:hover { - transform: scale(1.1); + +.footer__newsletter-form { + display: flex; + gap: 0.5rem; + margin-top: 1rem; } -/* ===== CONTACT =====*/ -.contact__input { - width: 100%; - font-size: var(--normal-font-size); - font-weight: var(--font-semi); - padding: 1rem; - border-radius: 0.5rem; - border: 1.5px solid var(--second-color); +.footer__newsletter-input { + flex: 1; + padding: 0.75rem; + background: var(--dark-color); + border: 1px solid rgba(48, 249, 7, 0.2); + border-radius: var(--border-radius); + color: var(--light-color); outline: none; - margin-bottom: var(--mb-4); + font-family: var(--body-font); } -.contact__button { - display: block; + +.footer__newsletter-input:focus { + border-color: var(--primary-color); +} + +.footer__newsletter-button { + width: 45px; + background: var(--primary-color); + color: var(--dark-color); border: none; - outline: none; - font-size: var(--normal-font-size); + border-radius: var(--border-radius); cursor: pointer; - margin-left: auto; + transition: var(--transition); + font-size: 1.25rem; + display: flex; + align-items: center; + justify-content: center; } -/* ===== FOOTER =====*/ -.footer { - background-color: var(--second-color); - color: #fff; +.footer__newsletter-button:hover { + background: var(--primary-color-alt); +} + +.footer__bottom { + margin-top: 4rem; + padding: 1.5rem 0; + border-top: 1px solid rgba(48, 249, 7, 0.1); text-align: center; - font-weight: var(--font-semi); - padding: 2rem 0; } -.footer__title { - font-size: 2rem; - margin-bottom: var(--mb-4); + +.footer__copy { + color: rgba(248, 249, 250, 0.9); + font-size: 0.875rem; } -.footer__social { - margin-bottom: var(--mb-4); + +.footer__security { + color: var(--primary-color); + margin-left: 1rem; + display: inline-flex; + align-items: center; + gap: 0.5rem; } -.footer__icon { + +/* ===== SCROLL UP ===== */ +.scrollup { + position: fixed; + right: 2rem; + bottom: -30%; + background: var(--primary-color); + color: var(--dark-color); + width: 45px; + height: 45px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; font-size: 1.5rem; - color: #fff; - margin: 0 var(--mb-2); + transition: var(--transition); + z-index: 100; + opacity: 0.8; + text-decoration: none; + box-shadow: 0 5px 15px rgba(48, 249, 7, 0.3); } -.footer__copy { - font-size: var(--smaller-font-size); + +.scrollup:hover { + opacity: 1; + transform: translateY(-0.5rem); + box-shadow: 0 10px 20px rgba(48, 249, 7, 0.4); } -/* ===== MEDIA QUERIES=====*/ -@media screen and (max-width: 320px) { - .home { - row-gap: 2rem; - } - .home__img { - width: 200px; +.scrollup.show-scroll { + bottom: 2rem; +} + +/* ===== RESPONSIVE DESIGN ===== */ +@media screen and (max-width: 1200px) { + .container { + max-width: 960px; } } -@media screen and (min-width: 576px) { - .home { - padding: 4rem 0 2rem; + +@media screen and (max-width: 992px) { + .container { + max-width: 720px; + } + + .section { + padding: 5rem 0 3rem; } - .home__social { - padding-top: 0; - padding-bottom: 2.5rem; - flex-direction: row; - align-self: flex-end; + + .section__title { + font-size: 2.25rem; } - .home__social-icon { - margin-bottom: 0; - margin-right: var(--mb-4); + + .home__title { + font-size: 3rem; } - .home__img { - width: 300px; - bottom: 25%; + + .home__container { + gap: 3rem; } + .about__container { - grid-template-columns: repeat(2, 1fr); - align-items: center; - text-align: initial; + grid-template-columns: 1fr; + gap: 3rem; } + .skills__container { - grid-template-columns: 0.7fr; - justify-content: center; - column-gap: 1rem; - } - .work__container { - grid-template-columns: repeat(2, 1fr); - column-gap: 2rem; - padding-top: 2rem; + grid-template-columns: 1fr; + gap: 3rem; } - .contact__form { - width: 360px; - padding-top: 2rem; + + .skills__radar { + max-width: 400px; } + .contact__container { - justify-items: center; + grid-template-columns: 1fr; + gap: 3rem; + } + + .footer__container { + grid-template-columns: repeat(2, 1fr); } } -@media screen and (min-width: 768px) { - body { - margin: 0; + +@media screen and (max-width: 768px) { + .container { + padding: 0 1.5rem; } - .section { - padding-top: 4rem; - padding-bottom: 3rem; + + .home__container { + grid-template-columns: 1fr; + text-align: center; + gap: 3rem; + } + + .home__title { + font-size: 2.5rem; + } + + .home__description { + margin: 0 auto 2rem; + } + + .home__buttons { + justify-content: center; + } + + .home__stats { + grid-template-columns: repeat(3, 1fr); + gap: 1.5rem; + } + + .home__blob { + width: 300px; + height: 300px; + } + + .home__blob-img { + width: 250px; + } + + .about__blob { + width: 300px; + height: 300px; } - .section-title { - margin-bottom: var(--mb-6); + + .about__tech-stack { + grid-template-columns: repeat(3, 1fr); + gap: 1rem; } - .section-title::after { + + .tech-icon { width: 80px; - top: 3rem; + height: 80px; + font-size: 2rem; } - .nav { - height: calc(var(--header-height) + 1.5rem); + + .tech-icon .tech-level { + font-size: 0.75rem; } - .nav__list { - display: flex; - padding-top: 0; + + .projects__container { + grid-template-columns: 1fr; + gap: 2rem; + } + + .project__card { + max-width: 400px; + margin: 0 auto; + } + + .contact__inputs { + grid-template-columns: 1fr; } - .nav__item { - margin-left: var(--mb-6); - margin-bottom: 0; + + .footer__container { + grid-template-columns: 1fr; + text-align: center; + gap: 2rem; } - .nav__toggle { - display: none; + + .footer__social { + justify-content: center; } - .nav__link { - color: var(--second-color); + + .footer__newsletter-form { + justify-content: center; } - .home { - padding: 8rem 0 2rem; + + .scrollup { + right: 1.5rem; } - .home__img { - width: 400px; - bottom: 10%; +} + +@media screen and (max-width: 576px) { + .section__title { + font-size: 2rem; } - .about__container { - padding-top: 2rem; + + .home__title { + font-size: 2rem; } - .about__img img { - width: 300px; + + .home__buttons { + flex-direction: column; + align-items: center; } - .skills__container { + + .home__stats { + grid-template-columns: 1fr; + gap: 1.5rem; + } + + .home__stat-number { + font-size: 2rem; + } + + .typing-text { + font-size: 1.5rem; + } + + .about__tech-stack { grid-template-columns: repeat(2, 1fr); - column-gap: 2rem; - align-items: center; - text-align: initial; + gap: 1rem; } - .work__container { - grid-template-columns: repeat(3, 1fr); - column-gap: 2rem; + + .tech-icon { + width: 80px; + height: 80px; + font-size: 1.9rem; } -} -@media screen and (min-width: 992px) { - .bd-grid { - margin-left: auto; - margin-right: auto; + + .experience__timeline { + grid-template-columns: 1fr; + } + + .skills__radar { + max-width: 250px; + height: 250px; } - .home { - padding: 10rem 0 2rem; + + .certifications__container { + grid-template-columns: 1fr; + gap: 1.5rem; } - .home__img { - width: 450px; + + .scrollup { + right: 1rem; + bottom: 1rem; + width: 40px; + height: 40px; + font-size: 1.25rem; } } \ No newline at end of file diff --git a/assets/img/Hal2p.png b/assets/img/Hal2p.png new file mode 100644 index 00000000..1f0b05d0 Binary files /dev/null and b/assets/img/Hal2p.png differ diff --git a/assets/img/Sec_Cloud1.jpg b/assets/img/Sec_Cloud1.jpg new file mode 100644 index 00000000..7bfbcedf Binary files /dev/null and b/assets/img/Sec_Cloud1.jpg differ diff --git a/assets/img/Sec_cloud2.jpg b/assets/img/Sec_cloud2.jpg new file mode 100644 index 00000000..98c54fb7 Binary files /dev/null and b/assets/img/Sec_cloud2.jpg differ diff --git a/assets/img/devsec_pipeline2.jpg b/assets/img/devsec_pipeline2.jpg new file mode 100644 index 00000000..6740dfff Binary files /dev/null and b/assets/img/devsec_pipeline2.jpg differ diff --git a/assets/img/experience-bg.jpg b/assets/img/experience-bg.jpg new file mode 100644 index 00000000..84b7c3ab Binary files /dev/null and b/assets/img/experience-bg.jpg differ diff --git a/assets/img/hero-bg.jpg b/assets/img/hero-bg.jpg new file mode 100644 index 00000000..7b502214 Binary files /dev/null and b/assets/img/hero-bg.jpg differ diff --git a/assets/img/hero23.jpg b/assets/img/hero23.jpg new file mode 100644 index 00000000..ec4bd6a8 Binary files /dev/null and b/assets/img/hero23.jpg differ diff --git a/assets/img/hero_img2.jpg b/assets/img/hero_img2.jpg new file mode 100644 index 00000000..4b652c96 Binary files /dev/null and b/assets/img/hero_img2.jpg differ diff --git a/assets/img/zero_trust.jpg b/assets/img/zero_trust.jpg new file mode 100644 index 00000000..d5a347a7 Binary files /dev/null and b/assets/img/zero_trust.jpg differ diff --git a/assets/js/main.js b/assets/js/main.js index e5365138..b424fadd 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,57 +1,505 @@ -/*===== MENU SHOW =====*/ -const showMenu = (toggleId, navId) =>{ - const toggle = document.getElementById(toggleId), - nav = document.getElementById(navId) +// ===== MAIN JS FILE ===== - if(toggle && nav){ - toggle.addEventListener('click', ()=>{ - nav.classList.toggle('show') - }) - } +// ===== DOM ELEMENTS ===== +const navMenu = document.getElementById('nav-menu'); +const navToggle = document.getElementById('nav-toggle'); +const navClose = document.getElementById('nav-close'); +const themeButton = document.getElementById('theme-button'); +const scrollUp = document.getElementById('scroll-up'); + +// ===== MENU SHOW/HIDE ===== +if (navToggle) { + navToggle.addEventListener('click', () => { + navMenu.classList.add('show-menu'); + document.body.style.overflow = 'hidden'; + }); +} + +if (navClose) { + navClose.addEventListener('click', () => { + navMenu.classList.remove('show-menu'); + document.body.style.overflow = ''; + }); } -showMenu('nav-toggle','nav-menu') -/*==================== REMOVE MENU MOBILE ====================*/ -const navLink = document.querySelectorAll('.nav__link') +// ===== REMOVE MENU ON CLICK ===== +const navLinks = document.querySelectorAll('.nav__link'); +const linkAction = () => { + navMenu.classList.remove('show-menu'); + document.body.style.overflow = ''; +}; +navLinks.forEach(link => link.addEventListener('click', linkAction)); + +// ===== DARK/LIGHT THEME ===== +const darkTheme = 'dark-theme'; +const iconTheme = 'bx-sun'; + +// Check for saved theme preference or use dark theme as default +const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)'); +const savedTheme = localStorage.getItem('selected-theme'); +const savedIcon = localStorage.getItem('selected-icon'); + +// Get current theme +const getCurrentTheme = () => document.body.classList.contains(darkTheme) ? 'dark' : 'light'; +const getCurrentIcon = () => themeButton.classList.contains(iconTheme) ? 'bx-moon' : 'bx-sun'; -function linkAction(){ - const navMenu = document.getElementById('nav-menu') - // When we click on each nav__link, we remove the show-menu class - navMenu.classList.remove('show') +// Set initial theme +if (savedTheme) { + document.body.classList[savedTheme === 'dark' ? 'add' : 'remove'](darkTheme); + themeButton.classList[savedIcon === 'bx-moon' ? 'add' : 'remove'](iconTheme); +} else { + // Default to dark theme if no preference saved + document.body.classList.add(darkTheme); + themeButton.classList.remove(iconTheme); } -navLink.forEach(n => n.addEventListener('click', linkAction)) - -/*==================== SCROLL SECTIONS ACTIVE LINK ====================*/ -const sections = document.querySelectorAll('section[id]') - -const scrollActive = () =>{ - const scrollDown = window.scrollY - - sections.forEach(current =>{ - const sectionHeight = current.offsetHeight, - sectionTop = current.offsetTop - 58, - sectionId = current.getAttribute('id'), - sectionsClass = document.querySelector('.nav__menu a[href*=' + sectionId + ']') - - if(scrollDown > sectionTop && scrollDown <= sectionTop + sectionHeight){ - sectionsClass.classList.add('active-link') - }else{ - sectionsClass.classList.remove('active-link') - } - }) + +// Toggle theme +if (themeButton) { + themeButton.addEventListener('click', () => { + document.body.classList.toggle(darkTheme); + themeButton.classList.toggle(iconTheme); + + localStorage.setItem('selected-theme', getCurrentTheme()); + localStorage.setItem('selected-icon', getCurrentIcon()); + }); } -window.addEventListener('scroll', scrollActive) - -/*===== SCROLL REVEAL ANIMATION =====*/ -const sr = ScrollReveal({ - origin: 'top', - distance: '60px', - duration: 2000, - delay: 200, -// reset: true + +// ===== SCROLL SECTIONS ACTIVE LINK ===== +const sections = document.querySelectorAll('section[id]'); +const scrollActive = () => { + const scrollY = window.pageYOffset; + + sections.forEach(section => { + const sectionHeight = section.offsetHeight; + const sectionTop = section.offsetTop - 100; + const sectionId = section.getAttribute('id'); + const navLink = document.querySelector(`.nav__menu a[href*="#${sectionId}"]`); + + if (navLink) { + if (scrollY > sectionTop && scrollY <= sectionTop + sectionHeight) { + navLink.classList.add('active-link'); + } else { + navLink.classList.remove('active-link'); + } + } + }); +}; + +// Throttle scroll event for performance +let scrollTimeout; +window.addEventListener('scroll', () => { + if (!scrollTimeout) { + scrollTimeout = setTimeout(() => { + scrollActive(); + scrollTimeout = null; + }, 100); + } +}); + +// ===== SHOW SCROLL UP ===== +const scrollUpShow = () => { + if (window.scrollY >= 350) { + scrollUp.classList.add('show-scroll'); + } else { + scrollUp.classList.remove('show-scroll'); + } +}; + +window.addEventListener('scroll', scrollUpShow); + +// ===== TYPING ANIMATION ===== +const typingText = document.querySelector('.typing-text'); +if (typingText) { + const professions = ['Cybersecurity Engineer', 'DevSecOps Specialist', 'Cloud Security Architect', 'Chief Technology Officer']; + let professionIndex = 0; + let charIndex = 0; + let isDeleting = false; + let typingSpeed = 100; + + const typeEffect = () => { + const currentProfession = professions[professionIndex]; + + if (!isDeleting && charIndex <= currentProfession.length) { + typingText.textContent = currentProfession.substring(0, charIndex); + charIndex++; + typingSpeed = 100; + } else if (isDeleting && charIndex >= 0) { + typingText.textContent = currentProfession.substring(0, charIndex); + charIndex--; + typingSpeed = 50; + } else { + isDeleting = !isDeleting; + if (!isDeleting) { + professionIndex = (professionIndex + 1) % professions.length; + } + typingSpeed = isDeleting ? 50 : 1200; + } + + setTimeout(typeEffect, typingSpeed); + }; + + // Start typing animation after page load + setTimeout(typeEffect, 1000); +} + +// ===== SKILLS RADAR CHART ===== +const initSkillsChart = () => { + const ctx = document.getElementById('skillsRadar'); + + if (!ctx) return; + + // Check if Chart.js is loaded + if (typeof Chart === 'undefined') { + console.warn('Chart.js not loaded. Skills chart disabled.'); + return; + } + + try { + const skillsChart = new Chart(ctx.getContext('2d'), { + type: 'radar', + data: { + labels: ['Cloud Security', 'DevSecOps', 'Network Security', 'Threat Intelligence', 'Incident Response', 'Compliance'], + datasets: [{ + label: 'Expertise Level', + data: [95, 92, 88, 85, 90, 87], + backgroundColor: 'rgba(48, 249, 7, 0.2)', + borderColor: 'rgba(48, 249, 7, 1)', + borderWidth: 2, + pointBackgroundColor: 'rgba(48, 249, 7, 1)', + pointBorderColor: '#fff', + pointBorderWidth: 2, + pointRadius: 4, + pointHoverRadius: 6 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + r: { + angleLines: { + color: 'rgba(255, 255, 255, 0.1)' + }, + grid: { + color: 'rgba(255, 255, 255, 0.1)' + }, + pointLabels: { + color: '#fff', + font: { + family: 'Inter, sans-serif', + size: 12 + }, + padding: 10 + }, + ticks: { + display: false, + maxTicksLimit: 5, + backdropColor: 'transparent' + }, + suggestedMin: 0, + suggestedMax: 100 + } + }, + plugins: { + legend: { + display: false + }, + tooltip: { + backgroundColor: 'rgba(10, 14, 23, 0.9)', + titleColor: 'rgba(48, 249, 7, 1)', + bodyColor: '#fff', + borderColor: 'rgba(48, 249, 7, 0.3)', + borderWidth: 1 + } + } + } + }); + + // Store chart instance for potential updates + window.skillsChart = skillsChart; + + } catch (error) { + console.error('Error creating skills chart:', error); + // Fallback: Hide canvas and show message + ctx.parentElement.innerHTML = '
Skills visualization not available
'; + } +}; + +// ===== ANIMATE SKILL BARS ===== +const animateSkillBars = () => { + const skillItems = document.querySelectorAll('.skill__item'); + + if (!skillItems.length) return; + + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const skillBar = entry.target.querySelector('.skill__percentage'); + const width = skillBar.style.width || skillBar.getAttribute('data-width'); + + if (width) { + // Reset to 0 then animate to target width + skillBar.style.width = '0'; + + setTimeout(() => { + skillBar.style.width = width; + }, 300); + + observer.unobserve(entry.target); + } + } + }); + }, { + threshold: 0.1, + rootMargin: '50px' + }); + + skillItems.forEach(item => { + const skillBar = item.querySelector('.skill__percentage'); + if (skillBar) { + const width = skillBar.style.width; + if (width) { + skillBar.setAttribute('data-width', width); + skillBar.style.width = '0'; + observer.observe(item); + } + } + }); +}; + +// ===== FORM VALIDATION ===== +const initFormValidation = () => { + const contactForm = document.querySelector('.contact__form'); + + if (!contactForm) return; + + // Real-time validation + const inputs = contactForm.querySelectorAll('.contact__input, .contact__textarea'); + inputs.forEach(input => { + // Add placeholder for floating labels + if (!input.hasAttribute('placeholder')) { + input.setAttribute('placeholder', ' '); + } + + input.addEventListener('blur', () => { + validateInput(input); + }); + + input.addEventListener('input', () => { + if (input.value.trim()) { + input.style.borderColor = 'var(--primary-color)'; + } + }); + }); + + const validateInput = (input) => { + if (!input.value.trim()) { + input.style.borderColor = 'var(--danger-color)'; + return false; + } + + if (input.type === 'email') { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(input.value.trim())) { + input.style.borderColor = 'var(--warning-color)'; + return false; + } + } + + input.style.borderColor = 'var(--primary-color)'; + return true; + }; + + contactForm.addEventListener('submit', (e) => { + e.preventDefault(); + + const inputs = contactForm.querySelectorAll('.contact__input, .contact__textarea'); + let isValid = true; + + inputs.forEach(input => { + if (!validateInput(input)) { + isValid = false; + } + }); + + if (isValid) { + // Show success message + const submitButton = contactForm.querySelector('.contact__button'); + const originalText = submitButton.innerHTML; + const originalBg = submitButton.style.background; + + submitButton.innerHTML = ' Message Sent Successfully'; + submitButton.style.background = 'var(--success-color)'; + submitButton.disabled = true; + + // In a real application, you would send the form data to a server here + console.log('Form submitted:', { + name: contactForm.querySelector('[placeholder=" "]').value, + email: contactForm.querySelector('[type="email"]').value, + subject: contactForm.querySelectorAll('[placeholder=" "]')[2]?.value, + message: contactForm.querySelector('textarea').value + }); + + setTimeout(() => { + submitButton.innerHTML = originalText; + submitButton.style.background = originalBg; + submitButton.disabled = false; + contactForm.reset(); + + // Reset labels + const labels = contactForm.querySelectorAll('.contact__label'); + labels.forEach(label => { + label.style.top = '1rem'; + label.style.left = '1rem'; + label.style.fontSize = '1rem'; + label.style.background = ''; + label.style.padding = ''; + label.style.color = ''; + }); + }, 3000); + } + }); +}; + +// ===== SMOOTH SCROLL ===== +const initSmoothScroll = () => { + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function (e) { + const href = this.getAttribute('href'); + + if (href === '#' || href === '#!') return; + + const targetElement = document.querySelector(href); + if (targetElement) { + e.preventDefault(); + + // Close mobile menu if open + if (navMenu.classList.contains('show-menu')) { + navMenu.classList.remove('show-menu'); + document.body.style.overflow = ''; + } + + window.scrollTo({ + top: targetElement.offsetTop - 80, + behavior: 'smooth' + }); + } + }); + }); +}; + +// ===== REVEAL ON SCROLL ===== +const initRevealOnScroll = () => { + const revealElements = document.querySelectorAll('.experience__item, .project__card, .certification__card, .skills__group, .about__detail'); + + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('revealed'); + observer.unobserve(entry.target); + } + }); + }, { + threshold: 0.1, + rootMargin: '50px' + }); + + revealElements.forEach(element => { + element.style.opacity = '0'; + element.style.transform = 'translateY(30px)'; + element.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; + observer.observe(element); + }); +}; + +// Add CSS for reveal animation +const revealStyle = document.createElement('style'); +revealStyle.textContent = ` + .experience__item.revealed, + .project__card.revealed, + .certification__card.revealed, + .skills__group.revealed, + .about__detail.revealed { + opacity: 1 !important; + transform: translateY(0) !important; + } +`; +document.head.appendChild(revealStyle); + +// ===== DEBOUNCE FUNCTION ===== +function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +} + +// ===== INITIALIZE EVERYTHING ===== +document.addEventListener('DOMContentLoaded', () => { + // Initialize all functions + initSmoothScroll(); + initFormValidation(); + initRevealOnScroll(); + + // Initialize skills chart + if (typeof Chart !== 'undefined') { + initSkillsChart(); + } else { + console.warn('Chart.js not loaded. Loading now...'); + // Dynamically load Chart.js if not loaded + const script = document.createElement('script'); + script.src = 'https://cdn.jsdelivr.net/npm/chart.js'; + script.onload = initSkillsChart; + document.head.appendChild(script); + } + + // Scroll to top on page refresh + window.scrollTo(0, 0); + + // Set initial active nav link + scrollActive(); + + // Set initial scroll up button state + scrollUpShow(); +}); + +// ===== WINDOW LOAD EVENT ===== +window.addEventListener('load', () => { + // Animate skill bars + animateSkillBars(); +}); + +// ===== RESIZE HANDLER ===== +const handleResize = debounce(() => { + // Close mobile menu on resize to desktop + if (window.innerWidth > 768 && navMenu.classList.contains('show-menu')) { + navMenu.classList.remove('show-menu'); + document.body.style.overflow = ''; + } + + // Reinitialize charts if needed + if (window.skillsChart && typeof window.skillsChart.resize === 'function') { + window.skillsChart.resize(); + } +}, 250); + +window.addEventListener('resize', handleResize); + +// ===== ERROR HANDLING ===== +window.addEventListener('error', (e) => { + console.error('Script error:', e.error); }); -sr.reveal('.home__data, .about__img, .skills__subtitle, .skills__text',{}); -sr.reveal('.home__img, .about__subtitle, .about__text, .skills__img',{delay: 400}); -sr.reveal('.home__social-icon',{ interval: 200}); -sr.reveal('.skills__data, .work__img, .contact__input',{interval: 200}); +// ===== EXPORT FOR MODULES (if needed) ===== +if (typeof module !== 'undefined' && module.exports) { + module.exports = { + initSkillsChart, + animateSkillBars, + initFormValidation + }; +} \ No newline at end of file diff --git a/assets/scss/styles.scss b/assets/scss/styles.scss deleted file mode 100644 index 241e4d30..00000000 --- a/assets/scss/styles.scss +++ /dev/null @@ -1,525 +0,0 @@ -/*===== GOOGLE FONTS =====*/ -@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap'); - -/*===== VARIABLES CSS =====*/ -:root{ - --header-height: 3rem; - --font-semi: 600; - - /*===== Colores =====*/ - /*Purple 260 - Red 355 - Blue 224 - Pink 340*/ - /* HSL color mode */ - --hue-color: 224; - --first-color: hsl(var(--hue-color), 89%, 60%); - --second-color: hsl(var(--hue-color), 56%, 12%); - - /*===== Fuente y tipografia =====*/ - --body-font: 'Poppins', sans-serif; - - --big-font-size: 2rem; - --h2-font-size: 1.25rem; - --normal-font-size: .938rem; - --smaller-font-size: .75rem; - - /*===== Margenes =====*/ - --mb-2: 1rem; - --mb-4: 2rem; - --mb-5: 2.5rem; - --mb-6: 3rem; - - /*===== z index =====*/ - --z-back: -10; - --z-fixed: 100; - - @media screen and (min-width: 968px){ - --big-font-size: 3.5rem; - --h2-font-size: 2rem; - --normal-font-size: 1rem; - --smaller-font-size: .875rem; - } -} - -/*===== BASE =====*/ -*,::before,::after{ - box-sizing: border-box; -} -html{ - scroll-behavior: smooth; -} -body{ - margin: var(--header-height) 0 0 0; - font-family: var(--body-font); - font-size: var(--normal-font-size); - color: var(--second-color); -} -h1,h2,p{ - margin: 0; -} -ul{ - margin: 0; - padding: 0; - list-style: none; -} -a{ - text-decoration: none; -} -img{ - max-width: 100%; - height: auto; - display: block; -} - -/*===== CLASS CSS ===== */ -.section-title{ - position: relative; - font-size: var(--h2-font-size); - color: var(--first-color); - margin-top: var(--mb-2); - margin-bottom: var(--mb-4); - text-align: center; - - &::after{ - position: absolute; - content: ''; - width: 64px; - height: 0.18rem; - left: 0; - right: 0; - margin: auto; - top: 2rem; - background-color: var(--first-color); - } -} -.section{ - padding-top: 3rem; - padding-bottom: 2rem; -} - -/*===== LAYOUT =====*/ -.bd-grid{ - max-width: 1024px; - display: grid; - margin-left: var(--mb-2); - margin-right: var(--mb-2); -} -.l-header{ - width: 100%; - position: fixed; - top: 0; - left: 0; - z-index: var(--z-fixed); - background-color: #fff; - box-shadow: 0 1px 4px rgba(146,161,176,.15); -} - -/*===== NAV =====*/ -.nav{ - height: var(--header-height); - display: flex; - justify-content: space-between; - align-items: center; - font-weight: var(--font-semi); - - &__menu{ - @media screen and (max-width: 767px){ - position: fixed; - top: var(--header-height); - right: -100%; - width: 80%; - height: 100%; - padding: 2rem; - background-color: var(--second-color); - transition: .5s; - } - } - &__item{ - margin-bottom: var(--mb-4); - } - &__link{ - position: relative; - color: #fff; - - &:hover{ - position: relative; - - &::after{ - position: absolute; - content: ''; - width: 100%; - height: 0.18rem; - left: 0; - top: 2rem; - background-color: var(--first-color); - } - } - } - &__logo{ - color: var(--second-color); - } - &__toggle{ - color: var(--second-color); - font-size: 1.5rem; - cursor: pointer; - } -} -/*Active menu*/ -.active-link::after{ - position: absolute; - content: ''; - width: 100%; - height: 0.18rem; - left: 0; - top: 2rem; - background-color: var(--first-color); -} - -/*=== Show menu ===*/ -.show{ - right: 0; -} - -/*===== HOME =====*/ -.home{ - position: relative; - row-gap: 5rem; - padding: 4rem 0 5rem; - - &__data{ - align-self: center; - } - &__title{ - font-size: var(--big-font-size); - margin-bottom: var(--mb-5); - - &-color{ - color: var(--first-color); - } - } - &__social{ - display: flex; - flex-direction: column; - &-icon{ - width: max-content; - margin-bottom: var(--mb-2); - font-size: 1.5rem; - color: var(--second-color); - - &:hover{ - color: var(--first-color); - } - } - } - - &__img{ - position: absolute; - right: 0; - bottom: 0; - width: 260px; - } - &__blob{ - fill: var(--first-color); - - &-img{ - width: 360px; - } - } -} - -/*BUTTONS*/ -.button{ - display: inline-block; - background-color: var(--first-color); - color: #fff; - padding: .75rem 2.5rem; - font-weight: var(--font-semi); - border-radius: .5rem; - transition: .3s; - - &:hover{ - box-shadow: 0px 10px 36px rgba(0,0,0,.15); - } -} - -/* ===== ABOUT =====*/ -.about{ - &__container{ - row-gap: 2rem; - text-align: center; - } - &__subtitle{ - margin-bottom: var(--mb-2); - } - - &__img{ - justify-self: center; - - & img{ - width: 200px; - border-radius: .5rem; - } - } -} - -/* ===== SKILLS =====*/ -.skills{ - &__container{ - row-gap: 2rem; - text-align: center; - } - &__subtitle{ - margin-bottom: var(--mb-2); - } - &__text{ - margin-bottom: var(--mb-4); - } - &__data{ - display: flex; - justify-content: space-between; - align-items: center; - position: relative; - font-weight: var(--font-semi); - padding: .5rem 1rem; - margin-bottom: var(--mb-4); - border-radius: .5rem; - box-shadow: 0px 4px 25px rgba(14, 36, 49, 0.15); - } - &__icon{ - font-size: 2rem; - margin-right: var(--mb-2); - color: var(--first-color); - } - &__names{ - display: flex; - align-items: center; - } - &__bar{ - position: absolute; - left: 0; - bottom: 0; - background-color: var(--first-color); - height: .25rem; - border-radius: .5rem; - z-index: var(--z-back); - } - &__html{ - width: 95%; - } - &__css{ - width: 85%; - } - &__js{ - width: 65%; - } - &__ux{ - width: 85%; - } - &__img{ - border-radius: .5rem; - } -} -/* ===== WORK =====*/ -.work{ - &__container{ - row-gap: 2rem; - } - &__img{ - box-shadow: 0px 4px 25px rgba(14, 36, 49, 0.15); - border-radius: .5rem; - overflow: hidden; - - & img{ - transition: 1s; - - &:hover{ - transform: scale(1.1); - } - } - } -} - -/* ===== CONTACT =====*/ -.contact{ - &__input{ - width: 100%; - font-size: var(--normal-font-size); - font-weight: var(--font-semi); - padding: 1rem; - border-radius: .5rem; - border: 1.5px solid var(--second-color); - outline: none; - margin-bottom: var(--mb-4); - } - &__button{ - display: block; - border: none; - outline: none; - font-size: var(--normal-font-size); - cursor: pointer; - margin-left: auto; - } -} - -/* ===== FOOTER =====*/ -.footer{ - background-color: var(--second-color); - color: #fff; - text-align: center; - font-weight: var(--font-semi); - padding: 2rem 0; - - &__title{ - font-size: 2rem; - margin-bottom: var(--mb-4); - } - &__social{ - margin-bottom: var(--mb-4); - } - &__icon{ - font-size: 1.5rem; - color: #fff; - margin: 0 var(--mb-2); - } - &__copy{ - font-size: var(--smaller-font-size); - } -} - -/* ===== MEDIA QUERIES=====*/ -@media screen and (max-width: 320px){ - .home{ - row-gap: 2rem; - - &__img{ - width: 200px; - } - } -} - -@media screen and (min-width: 576px){ - .home{ - padding: 4rem 0 2rem; - &__social{ - padding-top: 0; - padding-bottom: 2.5rem; - flex-direction: row; - align-self: flex-end; - - &-icon{ - margin-bottom: 0; - margin-right: var(--mb-4); - } - } - &__img{ - width: 300px; - bottom: 25%; - } - } - - .about__container{ - grid-template-columns: repeat(2,1fr); - align-items: center; - text-align: initial; - } - - .skills__container{ - grid-template-columns: .7fr; - justify-content: center; - column-gap: 1rem; - } - - .work__container{ - grid-template-columns: repeat(2,1fr); - column-gap: 2rem; - padding-top: 2rem; - } - - .contact{ - &__form{ - width: 360px; - padding-top: 2rem ; - } - &__container{ - justify-items: center; - } - } -} - -@media screen and (min-width: 768px){ - body{ - margin: 0; - } - .section{ - padding-top: 4rem; - padding-bottom: 3rem; - } - - .section-title{ - margin-bottom: var(--mb-6); - - &::after{ - width: 80px; - top: 3rem; - } - } - - .nav{ - height: calc(var(--header-height) + 1.5rem); - &__list{ - display: flex; - padding-top: 0; - } - &__item{ - margin-left: var(--mb-6); - margin-bottom: 0; - } - &__toggle{ - display: none; - } - &__link{ - color: var(--second-color); - } - } - .home{ - padding: 8rem 0 2rem; - - &__img{ - width: 400px; - bottom: 10%; - } - } - - .about{ - &__container{ - padding-top: 2rem; - } - &__img{ - & img{ - width: 300px; - } - } - } - .skills__container{ - grid-template-columns: repeat(2,1fr); - column-gap: 2rem; - align-items: center; - text-align: initial; - } - .work__container{ - grid-template-columns: repeat(3,1fr); - column-gap: 2rem; - } -} - -@media screen and (min-width: 992px){ - .bd-grid{ - margin-left: auto; - margin-right: auto; - } - .home{ - padding: 10rem 0 2rem; - - &__img{ - width: 450px; - } - } -} diff --git a/index.html b/index.html index a9d35eca..525d3b60 100644 --- a/index.html +++ b/index.html @@ -1,205 +1,849 @@ - - - - - - - - - - -