If you’re trying to get your first dev job, design role, or freelance client, your portfolio often gets more attention than your resume.
And the best portfolio? One you actually built yourself.
In this guide, we’ll build a clean, responsive portfolio website from scratch using plain HTML, CSS, and JavaScript. No frameworks. No heavy setup. Just core web skills you can explain confidently in an interview.
By the end, you’ll have a multi-page site with:
- Dark/light theme toggle
- Mobile-friendly navigation
- About-page image carousel
- Projects grid
- Resume viewer and download
- Contact form with client-side feedback
It is practical, polished, and ready to customize for your own work.
What We’re Building
- Home page: Hero section with your photo, short intro, and call-to-action buttons
- About page: Your background, experience timeline, and image carousel
- Projects page: Responsive project cards with hover overlays and tags
- Resume page: Embedded PDF plus download button
- Contact page: Contact info and a clean form
- Theme support: Dark/light mode saved with
localStorage - Responsive layout: Works on mobile, tablet, and desktop
- Footer social links: GitHub, LinkedIn, Twitter/X, Instagram
Why Build It Yourself?
Templates are fast, but building your own portfolio gives you real advantages:
- You understand every part of it. If someone asks, “Did you build this?” you can confidently say yes.
- It proves your skills directly. Your portfolio itself becomes a project sample.
- You get full control. No fighting against a template’s limits.
- You practice useful JavaScript. Theme toggles, nav menus, carousel logic, and form handling all show up in real projects.
Let’s get started.
Project Setup
Create a new folder (for example, portfolio).
We’ll use the Outfit font from Google Fonts. Add it with a <link> tag in the <head> of each HTML file.
If you want to follow along quickly, download the project assets ZIP file, which includes the images folder. Extract it and place the files in the same paths used in this tutorial (especially assets/images/) before you start. This lets you test the layout, carousel behavior, and resume embed right away.
Step 1: Build the HTML Pages
We’ll create five HTML pages. They all share the same navbar and footer, so navigation stays consistent.
index.html (Home)
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Alex Rivera | Full-Stack Developer & UX Designer</title>
<!-- SEO -->
<meta name="description" content="Alex Rivera is a full-stack developer and UX designer crafting clean, performant web experiences. Available for freelance and full-time opportunities." />
<meta name="author" content="Alex Rivera" />
<meta name="robots" content="index, follow" />
<link rel="canonical" href="https://your-username.github.io/portfolio/" />
<!-- Open Graph -->
<meta property="og:title" content="Alex Rivera | Full-Stack Developer & UX Designer" />
<meta property="og:description" content="Full-stack developer and UX designer building clean, performant web experiences." />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://your-username.github.io/portfolio/" />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
<!-- Stylesheet -->
<link rel="stylesheet" href="assets/css/styles.css" />
</head>
<body>
<nav class="navbar" id="navbar">
<div class="nav-container">
<a href="index.html" class="nav-brand">AR.</a>
<div class="nav-links" id="nav-links">
<a href="index.html" class="active">Home</a>
<a href="about.html">About</a>
<a href="projects.html">Projects</a>
<a href="resume.html">Resume</a>
<a href="contact.html">Contact</a>
</div>
<div class="nav-controls">
<button class="theme-toggle" id="theme-toggle" aria-label="Toggle Theme">
<svg id="theme-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M12 2.25a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM7.5 12a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM18.894 6.166a.75.75 0 0 0-1.06-1.06l-1.591 1.59a.75.75 0 1 0 1.06 1.061l1.591-1.59ZM21.75 12a.75.75 0 0 1-.75.75h-2.25a.75.75 0 0 1 0-1.5H21a.75.75 0 0 1 .75.75ZM17.834 18.894a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 1 0-1.061 1.06l1.59 1.591ZM12 18.75a.75.75 0 0 1 .75.75V21a.75.75 0 0 1-1.5 0v-1.5a.75.75 0 0 1 .75-.75ZM6.166 18.894a.75.75 0 0 1-1.06-1.06l1.59-1.591a.75.75 0 1 1 1.061 1.06l-1.59 1.591ZM2.25 12a.75.75 0 0 1 .75-.75H5.25a.75.75 0 0 1 0 1.5H3a.75.75 0 0 1-.75-.75ZM6.166 6.166a.75.75 0 0 1 1.06-1.06l1.59 1.591a.75.75 0 1 1-1.061 1.06l-1.59-1.591Z"
/>
</svg>
</button>
<button class="mobile-toggle" id="mobile-toggle" aria-label="Toggle Menu">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16m-7 6h7" />
</svg>
</button>
</div>
</div>
</nav>
<main>
<section class="hero">
<div class="hero-content">
<span class="hero-subtitle">Development | Design | Strategy</span>
<h1 class="hero-title">Hi, I'm Alex Rivera.</h1>
<p class="hero-desc">A full-stack developer and UX designer passionate about building fast, accessible, and beautiful digital products. Welcome to my portfolio.</p>
<div class="hero-actions">
<a href="resume.html" class="btn-primary">
View Resume
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="5" y1="12" x2="19" y2="12"></line>
<polyline points="12 5 19 12 12 19"></polyline>
</svg>
</a>
<a href="contact.html" class="btn-secondary">Let's Talk</a>
</div>
</div>
<div class="hero-image-wrapper">
<img src="assets/images/profile.jpg" alt="Alex Rivera Profile" class="hero-image" />
</div>
</section>
</main>
<footer>
<div class="footer-left">© <span id="year">2026</span> Alex Rivera. All rights reserved.</div>
<div class="socials">
<a href="https://github.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
/>
</svg>
</a>
<a href="https://www.linkedin.com/in/your-username/" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" /></svg>
</a>
<a href="https://twitter.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="Twitter / X">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.741l7.73-8.835L1.254 2.25H8.08l4.259 5.622 5.905-5.622Zm-1.161 17.52h1.833L7.084 4.126H5.117z" /></svg>
</a>
<a href="https://instagram.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="Instagram">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z"
/>
</svg>
</a>
</div>
</footer>
<script src="assets/js/scripts.js"></script>
</body>
</html>
Keep this page simple: a two-column hero with your photo on one side and your name, short tagline, and CTA buttons on the other.
about.html (About)
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>About | Alex Rivera</title>
<!-- SEO -->
<meta name="description" content="Learn about Alex Rivera — a full-stack developer and UX designer with a background in computer science, user experience, and product development." />
<meta name="author" content="Alex Rivera" />
<meta name="robots" content="index, follow" />
<link rel="canonical" href="https://your-username.github.io/portfolio/about.html" />
<!-- Open Graph -->
<meta property="og:title" content="About | Alex Rivera" />
<meta property="og:description" content="Learn about Alex Rivera — a full-stack developer and UX designer with a background in computer science and product development." />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://your-username.github.io/portfolio/about.html" />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
<!-- Stylesheet -->
<link rel="stylesheet" href="assets/css/styles.css" />
</head>
<body>
<nav class="navbar" id="navbar">
<div class="nav-container">
<a href="index.html" class="nav-brand">AR.</a>
<div class="nav-links" id="nav-links">
<a href="index.html" class="active">Home</a>
<a href="about.html">About</a>
<a href="projects.html">Projects</a>
<a href="resume.html">Resume</a>
<a href="contact.html">Contact</a>
</div>
<div class="nav-controls">
<button class="theme-toggle" id="theme-toggle" aria-label="Toggle Theme">
<svg id="theme-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M12 2.25a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM7.5 12a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM18.894 6.166a.75.75 0 0 0-1.06-1.06l-1.591 1.59a.75.75 0 1 0 1.06 1.061l1.591-1.59ZM21.75 12a.75.75 0 0 1-.75.75h-2.25a.75.75 0 0 1 0-1.5H21a.75.75 0 0 1 .75.75ZM17.834 18.894a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 1 0-1.061 1.06l1.59 1.591ZM12 18.75a.75.75 0 0 1 .75.75V21a.75.75 0 0 1-1.5 0v-1.5a.75.75 0 0 1 .75-.75ZM6.166 18.894a.75.75 0 0 1-1.06-1.06l1.59-1.591a.75.75 0 1 1 1.061 1.06l-1.59 1.591ZM2.25 12a.75.75 0 0 1 .75-.75H5.25a.75.75 0 0 1 0 1.5H3a.75.75 0 0 1-.75-.75ZM6.166 6.166a.75.75 0 0 1 1.06-1.06l1.59 1.591a.75.75 0 1 1-1.061 1.06l-1.59-1.591Z"
/>
</svg>
</button>
<button class="mobile-toggle" id="mobile-toggle" aria-label="Toggle Menu">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16m-7 6h7" />
</svg>
</button>
</div>
</div>
</nav>
<main class="page-main">
<div class="page-container">
<h1 class="page-title">About Me.</h1>
<div class="about-grid">
<div class="about-image-col">
<div class="image-stack">
<img src="assets/images/profile.jpg" alt="Alex Rivera" class="stack-img main-img" loading="lazy" />
</div>
</div>
<div class="about-text-col">
<h2 class="section-heading">My Journey</h2>
<p class="section-text">I'm a full-stack developer and UX designer with a passion for building products that are both technically solid and genuinely enjoyable to use. I'm currently open to full-time roles and freelance collaborations in software engineering, front-end development, and product design.</p>
<p class="section-text">I grew up in a multicultural household and spent several years living and studying abroad, which gave me an appreciation for diverse perspectives and human-centered design. Outside of work, I enjoy hiking, photography, and contributing to open-source projects on GitHub.</p>
<h2 class="section-heading mt-2">Experience & Education</h2>
<p class="section-text">I hold a Master's in Human-Computer Interaction from State University (2024) and a Bachelor's in Computer Science with a concentration in Software Engineering (2022). My academic and professional background spans frontend development, UX research, API design, and agile project management. I hold the AWS Certified Developer certification.</p>
<div class="carousel" id="carousel">
<div class="carousel-slides" id="carousel-slides">
<img src="assets/images/workspace.jpg" alt="Modern tech office workspace" class="carousel-slide" loading="lazy" />
<img src="assets/images/team-collaboration.jpg" alt="Team collaboration and brainstorming" class="carousel-slide" loading="lazy" />
<img src="assets/images/tech-conference.jpg" alt="Tech conference and professional development" class="carousel-slide" loading="lazy" />
</div>
<div class="carousel-controls">
<button class="carousel-btn" id="prev" aria-label="Previous Slide">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="chevron-left" aria-hidden="true" style="width: 18px; height: 18px" class="lucide lucide-chevron-left"><path d="m15 18-6-6 6-6"></path></svg>
</button>
<button class="carousel-btn" id="next" aria-label="Next Slide">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="chevron-right" aria-hidden="true" style="width: 18px; height: 18px" class="lucide lucide-chevron-right"><path d="m9 18 6-6-6-6"></path></svg>
</button>
</div>
</div>
<div class="experience-list">
<div class="exp-item">
<span class="exp-year">2022 - 2024</span>
<div class="exp-details">
<h3>Master's in Human-Computer Interaction</h3>
<p>State University</p>
</div>
</div>
<div class="exp-item">
<span class="exp-year">2018 - 2022</span>
<div class="exp-details">
<h3>Bachelor's in Computer Science</h3>
<p>Software Engineering Concentration — State University</p>
</div>
</div>
</div>
<h2 class="section-heading mt-2">Community & Leadership</h2>
<p class="section-text">I'm an active contributor to open-source communities and local tech meetups focused on making technology more accessible. I've served as a mentor for early-career developers through a regional coding bootcamp program.</p>
<p class="section-text">I also volunteer as a workshop facilitator at community coding events, helping students from underrepresented backgrounds get started with web development and design fundamentals.</p>
</div>
</div>
</div>
</main>
<footer>
<div class="footer-left">© <span id="year">2026</span> Alex Rivera. All rights reserved.</div>
<div class="socials">
<a href="https://github.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
/>
</svg>
</a>
<a href="https://www.linkedin.com/in/your-username/" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" /></svg>
</a>
<a href="https://twitter.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="Twitter / X">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.741l7.73-8.835L1.254 2.25H8.08l4.259 5.622 5.905-5.622Zm-1.161 17.52h1.833L7.084 4.126H5.117z" /></svg>
</a>
<a href="https://instagram.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="Instagram">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z"
/>
</svg>
</a>
</div>
</footer>
<script src="assets/js/scripts.js"></script>
</body>
</html>
Use a two-column layout for your image and bio. Add your experience timeline and an image carousel to show work, events, or campus highlights without clutter.
projects.html (Projects)
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Projects | Alex Rivera</title>
<!-- SEO -->
<meta name="description" content="Browse Alex Rivera's portfolio of development and design projects, including web applications, UI redesigns, and open-source contributions." />
<meta name="author" content="Alex Rivera" />
<meta name="robots" content="index, follow" />
<link rel="canonical" href="https://your-username.github.io/portfolio/projects.html" />
<!-- Open Graph -->
<meta property="og:title" content="Projects | Alex Rivera" />
<meta property="og:description" content="Browse Alex Rivera's portfolio of development and design projects, including web applications, UI redesigns, and open-source contributions." />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://your-username.github.io/portfolio/projects.html" />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
<!-- Stylesheet -->
<link rel="stylesheet" href="assets/css/styles.css" />
</head>
<body>
<nav class="navbar" id="navbar">
<div class="nav-container">
<a href="index.html" class="nav-brand">AR.</a>
<div class="nav-links" id="nav-links">
<a href="index.html" class="active">Home</a>
<a href="about.html">About</a>
<a href="projects.html">Projects</a>
<a href="resume.html">Resume</a>
<a href="contact.html">Contact</a>
</div>
<div class="nav-controls">
<button class="theme-toggle" id="theme-toggle" aria-label="Toggle Theme">
<svg id="theme-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M12 2.25a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM7.5 12a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM18.894 6.166a.75.75 0 0 0-1.06-1.06l-1.591 1.59a.75.75 0 1 0 1.06 1.061l1.591-1.59ZM21.75 12a.75.75 0 0 1-.75.75h-2.25a.75.75 0 0 1 0-1.5H21a.75.75 0 0 1 .75.75ZM17.834 18.894a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 1 0-1.061 1.06l1.59 1.591ZM12 18.75a.75.75 0 0 1 .75.75V21a.75.75 0 0 1-1.5 0v-1.5a.75.75 0 0 1 .75-.75ZM6.166 18.894a.75.75 0 0 1-1.06-1.06l1.59-1.591a.75.75 0 1 1 1.061 1.06l-1.59 1.591ZM2.25 12a.75.75 0 0 1 .75-.75H5.25a.75.75 0 0 1 0 1.5H3a.75.75 0 0 1-.75-.75ZM6.166 6.166a.75.75 0 0 1 1.06-1.06l1.59 1.591a.75.75 0 1 1-1.061 1.06l-1.59-1.591Z"
/>
</svg>
</button>
<button class="mobile-toggle" id="mobile-toggle" aria-label="Toggle Menu">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16m-7 6h7" />
</svg>
</button>
</div>
</div>
</nav>
<main class="page-main">
<div class="page-container">
<h1 class="page-title">Selected Works.</h1>
<div class="projects-grid">
<!-- Project 1: E-commerce Platform Redesign -->
<div class="project-card">
<div class="project-img-wrapper">
<img src="assets/images/project-ecommerce.jpg" alt="E-commerce Platform Redesign" class="project-img" loading="lazy" />
<div class="project-overlay">
<a href="#" target="_blank" rel="noopener noreferrer" class="overlay-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
</svg>
View Project
</a>
</div>
</div>
<div class="project-info">
<h2 class="project-title">E-Commerce Platform Redesign</h2>
<p class="project-desc">Led a full UX audit and front-end rebuild of an e-commerce platform. Improved checkout conversion by 30% through streamlined user flows and a modernized component library.</p>
<div class="project-tags">
<span class="tag">UX Design</span>
<span class="tag">React</span>
</div>
</div>
</div>
<!-- Project 2: Task Management App -->
<div class="project-card">
<div class="project-img-wrapper">
<img src="assets/images/project-task-app.jpg" alt="Task Management Mobile App" class="project-img" loading="lazy" />
<div class="project-overlay">
<a href="#" target="_blank" rel="noopener noreferrer" class="overlay-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
</svg>
View Project
</a>
</div>
</div>
<div class="project-info">
<h2 class="project-title">Task Management App</h2>
<p class="project-desc">Designed and built a cross-platform task management app with real-time sync, drag-and-drop Kanban boards, and team collaboration features using React Native and Firebase.</p>
<div class="project-tags">
<span class="tag">React Native</span>
<span class="tag">Firebase</span>
</div>
</div>
</div>
<!-- Project 3: Analytics Dashboard -->
<div class="project-card">
<div class="project-img-wrapper">
<img src="assets/images/project-dashboard.jpg" alt="Analytics Dashboard" class="project-img" loading="lazy" />
<div class="project-overlay">
<a href="#" target="_blank" rel="noopener noreferrer" class="overlay-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
</svg>
View Project
</a>
</div>
</div>
<div class="project-info">
<h2 class="project-title">Analytics Dashboard</h2>
<p class="project-desc">Built an interactive data analytics dashboard for a SaaS product, featuring live charts, filterable KPI cards, and CSV export — reducing manual reporting time by 60%.</p>
<div class="project-tags">
<span class="tag">Data Viz</span>
<span class="tag">Node.js</span>
</div>
</div>
</div>
</div>
</div>
</main>
<footer>
<div class="footer-left">© <span id="year">2026</span> Alex Rivera. All rights reserved.</div>
<div class="socials">
<a href="https://github.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
/>
</svg>
</a>
<a href="https://www.linkedin.com/in/your-username/" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" /></svg>
</a>
<a href="https://twitter.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="Twitter / X">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.741l7.73-8.835L1.254 2.25H8.08l4.259 5.622 5.905-5.622Zm-1.161 17.52h1.833L7.084 4.126H5.117z" /></svg>
</a>
<a href="https://instagram.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="Instagram">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z"
/>
</svg>
</a>
</div>
</footer>
<script src="assets/js/scripts.js"></script>
</body>
</html>
Create a responsive grid of project cards. Each card should include:
- Cover image
- Hover overlay with a “View Project” button
- Project title
- Short description
- Tech or category tags (
React,UX Design,Node.js, etc.)
resume.html (Resume)
Keep this page minimal: an embedded PDF and a clear download button. Replace the <iframe> src with your real resume path.
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Resume | Alex Rivera</title>
<!-- SEO -->
<meta name="description" content="View and download Alex Rivera's resume. Full-stack developer and UX designer with a Master's in HCI and AWS Developer certification." />
<meta name="author" content="Alex Rivera" />
<meta name="robots" content="index, follow" />
<link rel="canonical" href="https://your-username.github.io/portfolio/resume.html" />
<!-- Open Graph -->
<meta property="og:title" content="Resume | Alex Rivera" />
<meta property="og:description" content="Full-stack developer and UX designer with a Master's in HCI and AWS Developer certification." />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://your-username.github.io/portfolio/resume.html" />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
<!-- Stylesheet -->
<link rel="stylesheet" href="assets/css/styles.css" />
</head>
<body>
<nav class="navbar" id="navbar">
<div class="nav-container">
<a href="index.html" class="nav-brand">AR.</a>
<div class="nav-links" id="nav-links">
<a href="index.html" class="active">Home</a>
<a href="about.html">About</a>
<a href="projects.html">Projects</a>
<a href="resume.html">Resume</a>
<a href="contact.html">Contact</a>
</div>
<div class="nav-controls">
<button class="theme-toggle" id="theme-toggle" aria-label="Toggle Theme">
<svg id="theme-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M12 2.25a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM7.5 12a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM18.894 6.166a.75.75 0 0 0-1.06-1.06l-1.591 1.59a.75.75 0 1 0 1.06 1.061l1.591-1.59ZM21.75 12a.75.75 0 0 1-.75.75h-2.25a.75.75 0 0 1 0-1.5H21a.75.75 0 0 1 .75.75ZM17.834 18.894a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 1 0-1.061 1.06l1.59 1.591ZM12 18.75a.75.75 0 0 1 .75.75V21a.75.75 0 0 1-1.5 0v-1.5a.75.75 0 0 1 .75-.75ZM6.166 18.894a.75.75 0 0 1-1.06-1.06l1.59-1.591a.75.75 0 1 1 1.061 1.06l-1.59 1.591ZM2.25 12a.75.75 0 0 1 .75-.75H5.25a.75.75 0 0 1 0 1.5H3a.75.75 0 0 1-.75-.75ZM6.166 6.166a.75.75 0 0 1 1.06-1.06l1.59 1.591a.75.75 0 1 1-1.061 1.06l-1.59-1.591Z"
/>
</svg>
</button>
<button class="mobile-toggle" id="mobile-toggle" aria-label="Toggle Menu">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16m-7 6h7" />
</svg>
</button>
</div>
</div>
</nav>
<main class="page-main">
<div class="page-container" style="max-width: 800px; text-align: center">
<h1 class="page-title" style="margin-bottom: 1.5rem">My Resume.</h1>
<p class="section-text" style="max-width: 600px; margin: 0 auto 2.5rem">Take a look at my qualifications and experience. You can also download a copy for your records.</p>
<div class="resume-actions" style="margin-bottom: 3rem">
<!-- TODO: Replace the href with the path to your actual resume PDF -->
<a href="assets/documents/resume.pdf" class="btn-primary" download>
Download PDF
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
<polyline points="7 10 12 15 17 10"></polyline>
<line x1="12" y1="15" x2="12" y2="3"></line>
</svg>
</a>
</div>
<div class="resume-container">
<!-- TODO: Replace the src with the path to your actual resume PDF -->
<iframe src="assets/images/resume.pdf" class="resume-frame" title="Alex Rivera Resume" allowfullscreen></iframe>
</div>
<p class="updated-note">Last updated: January 2026</p>
</div>
</main>
<footer>
<div class="footer-left">© <span id="year">2026</span> Alex Rivera. All rights reserved.</div>
<div class="socials">
<a href="https://github.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
/>
</svg>
</a>
<a href="https://www.linkedin.com/in/your-username/" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" /></svg>
</a>
<a href="https://twitter.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="Twitter / X">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.741l7.73-8.835L1.254 2.25H8.08l4.259 5.622 5.905-5.622Zm-1.161 17.52h1.833L7.084 4.126H5.117z" /></svg>
</a>
<a href="https://instagram.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="Instagram">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z"
/>
</svg>
</a>
</div>
</footer>
<script src="assets/js/scripts.js"></script>
</body>
</html>
contact.html (Contact)
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Resume | Alex Rivera</title>
<!-- SEO -->
<meta name="description" content="View and download Alex Rivera's resume. Full-stack developer and UX designer with a Master's in HCI and AWS Developer certification." />
<meta name="author" content="Alex Rivera" />
<meta name="robots" content="index, follow" />
<link rel="canonical" href="https://your-username.github.io/portfolio/resume.html" />
<!-- Open Graph -->
<meta property="og:title" content="Resume | Alex Rivera" />
<meta property="og:description" content="Full-stack developer and UX designer with a Master's in HCI and AWS Developer certification." />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://your-username.github.io/portfolio/resume.html" />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
<!-- Stylesheet -->
<link rel="stylesheet" href="assets/css/styles.css" />
</head>
<body>
<nav class="navbar" id="navbar">
<div class="nav-container">
<a href="index.html" class="nav-brand">AR.</a>
<div class="nav-links" id="nav-links">
<a href="index.html" class="active">Home</a>
<a href="about.html">About</a>
<a href="projects.html">Projects</a>
<a href="resume.html">Resume</a>
<a href="contact.html">Contact</a>
</div>
<div class="nav-controls">
<button class="theme-toggle" id="theme-toggle" aria-label="Toggle Theme">
<svg id="theme-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M12 2.25a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM7.5 12a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM18.894 6.166a.75.75 0 0 0-1.06-1.06l-1.591 1.59a.75.75 0 1 0 1.06 1.061l1.591-1.59ZM21.75 12a.75.75 0 0 1-.75.75h-2.25a.75.75 0 0 1 0-1.5H21a.75.75 0 0 1 .75.75ZM17.834 18.894a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 1 0-1.061 1.06l1.59 1.591ZM12 18.75a.75.75 0 0 1 .75.75V21a.75.75 0 0 1-1.5 0v-1.5a.75.75 0 0 1 .75-.75ZM6.166 18.894a.75.75 0 0 1-1.06-1.06l1.59-1.591a.75.75 0 1 1 1.061 1.06l-1.59 1.591ZM2.25 12a.75.75 0 0 1 .75-.75H5.25a.75.75 0 0 1 0 1.5H3a.75.75 0 0 1-.75-.75ZM6.166 6.166a.75.75 0 0 1 1.06-1.06l1.59 1.591a.75.75 0 1 1-1.061 1.06l-1.59-1.591Z"
/>
</svg>
</button>
<button class="mobile-toggle" id="mobile-toggle" aria-label="Toggle Menu">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16m-7 6h7" />
</svg>
</button>
</div>
</div>
</nav>
<main class="page-main">
<div class="page-container" style="max-width: 800px; text-align: center">
<h1 class="page-title" style="margin-bottom: 1.5rem">My Resume.</h1>
<p class="section-text" style="max-width: 600px; margin: 0 auto 2.5rem">Take a look at my qualifications and experience. You can also download a copy for your records.</p>
<div class="resume-actions" style="margin-bottom: 3rem">
<!-- TODO: Replace the href with the path to your actual resume PDF -->
<a href="assets/documents/resume.pdf" class="btn-primary" download>
Download PDF
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
<polyline points="7 10 12 15 17 10"></polyline>
<line x1="12" y1="15" x2="12" y2="3"></line>
</svg>
</a>
</div>
<div class="resume-container">
<!-- TODO: Replace the src with the path to your actual resume PDF -->
<iframe src="assets/documents/resume.pdf" class="resume-frame" title="Alex Rivera Resume" allowfullscreen></iframe>
</div>
<p class="updated-note">Last updated: January 2026</p>
</div>
</main>
<footer>
<div class="footer-left">© <span id="year">2026</span> Alex Rivera. All rights reserved.</div>
<div class="socials">
<a href="https://github.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
/>
</svg>
</a>
<a href="https://www.linkedin.com/in/your-username/" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" /></svg>
</a>
<a href="https://twitter.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="Twitter / X">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.741l7.73-8.835L1.254 2.25H8.08l4.259 5.622 5.905-5.622Zm-1.161 17.52h1.833L7.084 4.126H5.117z" /></svg>
</a>
<a href="https://instagram.com/your-username" target="_blank" rel="noopener noreferrer" aria-label="Instagram">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z"
/>
</svg>
</a>
</div>
</footer>
<script src="assets/js/scripts.js"></script>
</body>
</html>
Use two columns:
- Left: email, LinkedIn, location
- Right: message form
This tutorial uses frontend-only form behavior (no backend). You can connect EmailJS, Formspree, or your own API later.
Step 2: Style with CSS
All pages share one stylesheet: assets/css/styles.css.
:root {
/* Light Theme */
--bg-color: #fcfcfc;
--text-main: #1a1a1a;
--text-muted: #666666;
--accent: #2563eb;
--nav-bg: rgba(252, 252, 252, 0.85);
--nav-border: rgba(0, 0, 0, 0.08);
--card-bg: #fff;
--btn-bg: #1a1a1a;
--btn-text: #ffffff;
--btn-hover: #333333;
--btn-sec-bg: transparent;
--btn-sec-text: #1a1a1a;
--btn-sec-border: #e5e5e5;
--btn-sec-hover: #f5f5f5;
}
[data-theme="dark"] {
/* Dark Theme */
--bg-color: #0d0d0d;
--text-main: #f2f2f2;
--text-muted: #a1a1aa;
--accent: #60a5fa;
--nav-bg: rgba(13, 13, 13, 0.85);
--nav-border: rgba(255, 255, 255, 0.08);
--card-bg: #161616;
--btn-bg: #f2f2f2;
--btn-text: #0d0d0d;
--btn-hover: #d4d4d4;
--btn-sec-bg: transparent;
--btn-sec-text: #f2f2f2;
--btn-sec-border: #333333;
--btn-sec-hover: #1a1a1a;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Outfit", sans-serif;
background-color: var(--bg-color);
color: var(--text-main);
line-height: 1.6;
transition:
background-color 0.4s ease,
color 0.4s ease;
min-height: 100vh;
display: flex;
flex-direction: column;
}
::selection {
background: var(--accent);
color: #fff;
}
/* Navigation */
.navbar {
position: sticky;
top: 0;
width: 100%;
background: var(--nav-bg);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-bottom: 1px solid var(--nav-border);
z-index: 1000;
transition:
background 0.4s ease,
border-color 0.4s ease,
padding 0.3s ease;
}
.nav-container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 1.2rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-brand {
font-size: 1.5rem;
font-weight: 800;
letter-spacing: -0.5px;
text-decoration: none;
color: var(--text-main);
}
.nav-links {
display: flex;
gap: 2.5rem;
align-items: center;
}
.nav-links a {
text-decoration: none;
color: var(--text-muted);
font-weight: 500;
font-size: 0.95rem;
transition: color 0.3s ease;
position: relative;
}
.nav-links a:hover,
.nav-links a.active {
color: var(--text-main);
}
.nav-controls {
display: flex;
align-items: center;
gap: 1rem;
}
/* Theme Toggle */
.theme-toggle {
background: none;
border: none;
color: var(--text-main);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 0.5rem;
border-radius: 50%;
transition:
background-color 0.3s ease,
transform 0.3s ease;
}
.theme-toggle:hover {
background-color: var(--nav-border);
transform: scale(1.05);
}
.theme-toggle svg {
width: 22px;
height: 22px;
fill: currentColor;
}
.mobile-toggle {
display: none;
background: none;
border: none;
color: var(--text-main);
cursor: pointer;
padding: 0.5rem;
}
/* Main Content (Hero) */
main {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.hero {
max-width: 1200px;
padding: 1.2rem 2rem;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 4rem;
text-align: left;
animation: fadeUp 1s cubic-bezier(0.16, 1, 0.3, 1) forwards;
opacity: 0;
transform: translateY(30px);
}
.hero-content {
flex: 1;
max-width: 600px;
}
.hero-image-wrapper {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.hero-image {
width: 100%;
max-width: 400px;
height: 400px;
object-fit: cover;
border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
border: 4px solid var(--btn-sec-border);
animation: blob-morph 12s ease-in-out infinite;
transition:
transform 0.4s ease,
border-color 0.4s ease;
}
.hero-image:hover {
transform: translateY(-10px) scale(1.02);
border-color: var(--accent);
}
@keyframes blob-morph {
0%,
100% {
border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
}
33% {
border-radius: 30% 60% 70% 40% / 50% 60% 30% 60%;
}
66% {
border-radius: 73% 27% 41% 59% / 40% 58% 42% 50%;
}
}
.hero-subtitle {
font-size: 0.9rem;
font-weight: 600;
color: var(--accent);
margin-bottom: 1rem;
letter-spacing: 2px;
text-transform: uppercase;
display: block;
}
.hero-title {
font-size: 4.5rem;
font-weight: 700;
line-height: 1.1;
margin-bottom: 1.5rem;
letter-spacing: -1.5px;
color: var(--text-main);
}
.hero-desc {
font-size: 1.25rem;
color: var(--text-muted);
max-width: 650px;
margin-bottom: 2.5rem;
line-height: 1.7;
}
.hero-actions {
display: flex;
gap: 1rem;
align-items: center;
}
.btn-primary,
.btn-secondary {
display: inline-flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
padding: 0.85rem 2rem;
border-radius: 50px;
text-decoration: none;
font-weight: 600;
font-size: 1rem;
transition: all 0.3s ease;
}
.btn-primary {
background-color: var(--btn-bg);
color: var(--btn-text);
border: 1px solid var(--btn-bg);
}
.btn-primary:hover {
background-color: var(--btn-hover);
border-color: var(--btn-hover);
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.btn-primary svg {
transition: transform 0.3s ease;
}
.btn-primary:hover svg {
transform: translateX(5px);
}
.btn-secondary {
background-color: var(--btn-sec-bg);
color: var(--btn-sec-text);
border: 1px solid var(--btn-sec-border);
}
.btn-secondary:hover {
background-color: var(--btn-sec-hover);
border-color: var(--text-muted);
transform: translateY(-2px);
}
/* Footer */
footer {
padding: 1.2rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid var(--nav-border);
font-size: 0.9rem;
color: var(--text-muted);
}
.socials {
display: flex;
gap: 1.25rem;
}
.socials a {
color: var(--text-muted);
transition:
color 0.3s ease,
transform 0.3s ease;
display: flex;
}
.socials a:hover {
color: var(--text-main);
transform: translateY(-2px);
}
/* Page Shared Layout */
.page-main {
padding: 1rem 0;
}
.page-container {
max-width: 1200px;
width: 100%;
margin: 0 auto;
padding: 1.2rem 2rem;
animation: fadeUp 1s cubic-bezier(0.16, 1, 0.3, 1) forwards;
opacity: 0;
transform: translateY(30px);
}
.page-title {
font-size: 3.5rem;
font-weight: 800;
margin-bottom: 3rem;
letter-spacing: -1px;
}
.section-heading {
font-size: 1.8rem;
font-weight: 700;
margin-bottom: 1rem;
color: var(--text-main);
position: relative;
display: inline-block;
}
.section-heading.mt-2 {
margin-top: 2rem;
}
.section-text {
font-size: 1.1rem;
color: var(--text-muted);
margin-bottom: 1.5rem;
line-height: 1.7;
}
.text-link {
color: var(--accent);
text-decoration: none;
font-weight: 500;
transition: color 0.3s ease;
}
.text-link:hover {
color: var(--text-main);
text-decoration: underline;
}
/* About Page Specific Layout */
.about-grid {
display: flex;
gap: 4rem;
align-items: flex-start;
}
.about-image-col {
flex: 0 0 35%;
position: sticky;
top: 8rem;
}
.about-text-col {
flex: 1;
}
.image-stack {
position: relative;
width: 100%;
aspect-ratio: 3/4;
}
.stack-img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
border: 4px solid var(--btn-sec-border);
transition: transform 0.3s ease;
}
.stack-img:hover {
transform: scale(1.02);
}
.experience-list {
display: flex;
flex-direction: column;
gap: 1.5rem;
margin-top: 1rem;
margin-bottom: 2rem;
}
.exp-item {
display: flex;
gap: 1.5rem;
padding: 1.5rem;
background-color: var(--nav-bg);
border: 1px solid var(--nav-border);
border-radius: 12px;
transition:
transform 0.3s ease,
box-shadow 0.3s ease;
}
.exp-item:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
border-color: var(--nav-border);
}
.exp-year {
font-weight: 700;
color: var(--accent);
font-size: 0.9rem;
white-space: nowrap;
}
.exp-details h3 {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 0.2rem;
margin-top: -0.3rem;
color: var(--text-main);
}
.exp-details p {
color: var(--text-muted);
font-size: 0.95rem;
}
/* Projects Page Layout */
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 2.5rem;
margin-top: 1rem;
}
.project-card {
background: var(--card-bg);
border: 1px solid var(--nav-border);
border-radius: 20px;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
transition:
transform 0.4s ease,
box-shadow 0.4s ease,
border-color 0.4s ease;
}
.project-card:hover {
transform: translateY(-8px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
border-color: var(--accent);
}
.project-img-wrapper {
position: relative;
width: 100%;
aspect-ratio: 16/10;
overflow: hidden;
}
.project-img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.6s ease;
}
.project-card:hover .project-img {
transform: scale(1.05);
}
.project-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.65);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease;
backdrop-filter: blur(2px);
-webkit-backdrop-filter: blur(2px);
}
.project-card:hover .project-overlay {
opacity: 1;
}
.overlay-btn {
background: var(--bg-color);
color: var(--text-main);
padding: 0.75rem 1.5rem;
border-radius: 30px;
font-weight: 600;
display: flex;
align-items: center;
gap: 0.5rem;
transform: translateY(20px);
transition:
transform 0.3s ease,
background 0.3s ease,
color 0.3s ease;
text-decoration: none;
}
.project-card:hover .overlay-btn {
transform: translateY(0);
}
.overlay-btn:hover {
background: var(--accent);
color: #fff;
}
.project-status-overlay {
background: rgba(0, 0, 0, 0.5);
color: #fff;
padding: 0.75rem 1.5rem;
border-radius: 30px;
font-weight: 600;
transform: translateY(20px);
transition: transform 0.3s ease;
display: inline-block;
}
.project-card:hover .project-status-overlay {
transform: translateY(0);
}
.project-info {
padding: 1.5rem;
display: flex;
flex-direction: column;
flex: 1;
}
.project-title {
font-size: 1.4rem;
font-weight: 700;
margin-bottom: 0.8rem;
color: var(--text-main);
line-height: 1.3;
}
.project-desc {
font-size: 1rem;
color: var(--text-muted);
margin-bottom: 1.5rem;
flex: 1;
}
.project-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: auto;
}
.tag {
background: var(--btn-sec-border);
border: 1px solid var(--nav-border);
padding: 0.25rem 0.75rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 500;
color: var(--text-main);
}
/* Carousel */
.carousel {
position: relative;
width: 100%;
max-width: 500px;
height: 300px;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
margin-bottom: 2rem;
border: 1px solid var(--nav-border);
}
.carousel-slides {
position: relative;
width: 100%;
height: 100%;
}
.carousel-slide {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
transition: opacity 0.5s ease;
pointer-events: none;
}
.carousel-slide.active {
opacity: 1;
pointer-events: auto;
}
.carousel-controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 5px;
z-index: 10;
background: rgba(0, 0, 0, 0.5);
padding: 5px;
border-radius: 50px;
backdrop-filter: blur(10px);
}
.carousel-btn {
background: none;
border: none;
color: white;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
border-radius: 50%;
transition: all 0.3s ease;
}
.carousel-btn:hover {
background: rgba(255, 255, 255, 0.2);
}
/* Resume Layout */
.resume-container {
width: 100%;
aspect-ratio: 8.5/11;
max-width: 800px;
background: var(--nav-bg);
border: 1px solid var(--nav-border);
border-radius: 20px;
overflow: hidden;
margin: 0 auto 1.5rem;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
}
.resume-frame {
width: 100%;
height: 100%;
border: none;
}
.updated-note {
font-size: 0.9rem;
color: var(--text-muted);
}
/* Contact Layout */
.contact-page .page-title {
margin-bottom: 0;
}
.contact-page .section-text {
margin-bottom: 3rem;
}
.contact-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
align-items: flex-start;
}
.contact-info {
display: flex;
flex-direction: column;
}
.info-items {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.info-item {
display: flex;
align-items: center;
gap: 1.5rem;
padding: 1.5rem;
background: var(--nav-bg);
border: 1px solid var(--nav-border);
border-radius: 16px;
text-decoration: none;
transition:
transform 0.3s cubic-bezier(0.16, 1, 0.3, 1),
box-shadow 0.3s ease,
border-color 0.3s ease;
}
.text-link-card.info-item:hover {
transform: translateY(-5px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
border-color: var(--accent);
}
.text-link-card.info-item:hover .info-icon {
background: var(--accent);
color: #fff;
}
.info-icon {
width: 55px;
height: 55px;
border-radius: 50%;
background: var(--btn-sec-border);
display: flex;
align-items: center;
justify-content: center;
color: var(--accent);
flex-shrink: 0;
transition:
background 0.3s ease,
color 0.3s ease;
}
.info-details h3 {
font-size: 1.1rem;
font-weight: 700;
margin-bottom: 0.2rem;
color: var(--text-main);
}
.info-details p {
color: var(--text-muted);
font-size: 0.95rem;
}
.contact-card {
background: var(--card-bg);
border: 1px solid var(--nav-border);
border-radius: 20px;
padding: 2.5rem;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
text-align: left;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: var(--text-main);
}
.form-control {
width: 100%;
padding: 1rem;
border-radius: 12px;
border: 1px solid var(--nav-border);
background: var(--bg-color);
color: var(--text-main);
font-family: inherit;
font-size: 1rem;
transition:
border-color 0.3s ease,
box-shadow 0.3s ease;
}
.form-control:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
}
.w-100 {
width: 100%;
justify-content: center;
}
.form-status {
margin-top: 1rem;
text-align: center;
font-size: 0.95rem;
font-weight: 500;
}
.form-status.success {
color: #10b981;
}
.form-status.error {
color: #ef4444;
}
/* Animations */
@keyframes fadeUp {
to {
opacity: 1;
transform: translateY(0);
}
}
/* Responsive */
@media (max-width: 992px) {
.hero {
flex-direction: column-reverse;
text-align: center;
gap: 3rem;
padding-block: 4rem;
}
.hero-content {
display: flex;
flex-direction: column;
align-items: center;
}
.hero-actions {
align-items: center;
}
.contact-grid {
grid-template-columns: 1fr;
gap: 2.5rem;
}
}
@media (max-width: 768px) {
.navbar .nav-container {
padding: 1rem 5%;
}
.nav-links {
display: flex;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: rgba(252, 252, 252, 1);
flex-direction: column;
justify-content: center;
align-items: center;
padding: 0;
border: none;
gap: 2.5rem;
opacity: 0;
pointer-events: none;
transition: opacity 0.4s ease;
z-index: 900;
}
[data-theme="dark"] .nav-links {
background: rgba(13, 13, 13, 1);
}
.nav-links.active {
opacity: 1;
pointer-events: auto;
}
.nav-links a {
font-size: 2rem;
font-weight: 700;
font-family: inherit;
color: var(--text-muted);
transition:
color 0.3s ease,
transform 0.3s ease;
}
.nav-links a:hover,
.nav-links a.active {
color: var(--text-main);
transform: translateX(10px);
}
.mobile-toggle {
display: block;
z-index: 999;
}
.hero-title {
font-size: 3rem;
}
.hero-desc {
font-size: 1.1rem;
}
.hero-actions {
flex-direction: column;
align-items: center;
}
.hero-image {
max-width: 250px;
height: 250px;
}
footer {
flex-direction: column-reverse;
gap: 1.5rem;
text-align: center;
}
.about-grid {
flex-direction: column;
gap: 2rem;
}
.about-image-col {
position: static;
max-width: 400px;
margin: 0 auto;
}
.exp-item {
flex-direction: column;
gap: 0.5rem;
}
.projects-grid {
grid-template-columns: 1fr;
gap: 1.5rem;
}
}
Key styling decisions:
Theme variables
Define light theme variables in :root and dark theme variables in [data-theme="dark"]. Switching themes becomes simple and maintainable.
Navbar
Use a subtle blur (backdrop-filter) for a polished effect. On mobile, turn links into a full-screen menu with a smooth slide-in.
Hero layout
Two columns on desktop, stacked on smaller screens. A circular profile image with light shadow helps it feel finished.
Project cards
Set overflow: hidden on the image wrapper so overlay animations stay clean.
Carousel
Show one slide at a time. Active slides use full opacity; inactive slides fade out.
Responsive breakpoints
Use media queries around 768px and 480px to adjust grids, spacing, and text for smaller screens.
Step 3: Add JavaScript Interactivity
Place all behavior in assets/js/scripts.js and include it at the bottom of each page.
const themeToggleBtn = document.getElementById("theme-toggle");
const mobileToggleBtn = document.getElementById("mobile-toggle");
const navLinks = document.getElementById("nav-links");
const themeIcon = document.getElementById("theme-icon");
// Theme Management
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
const savedTheme = localStorage.getItem("theme") || systemTheme;
document.documentElement.setAttribute("data-theme", savedTheme);
updateThemeIcon(savedTheme);
themeToggleBtn.addEventListener("click", () => {
const currentTheme = document.documentElement.getAttribute("data-theme");
const newTheme = currentTheme === "dark" ? "light" : "dark";
document.documentElement.setAttribute("data-theme", newTheme);
localStorage.setItem("theme", newTheme);
updateThemeIcon(newTheme);
});
function updateThemeIcon(theme) {
if (theme === "dark") {
// Sun Icon
themeIcon.innerHTML =
'<path d="M12 2.25a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM7.5 12a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM18.894 6.166a.75.75 0 0 0-1.06-1.06l-1.591 1.59a.75.75 0 1 0 1.06 1.061l1.591-1.59ZM21.75 12a.75.75 0 0 1-.75.75h-2.25a.75.75 0 0 1 0-1.5H21a.75.75 0 0 1 .75.75ZM17.834 18.894a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 1 0-1.061 1.06l1.59 1.591ZM12 18.75a.75.75 0 0 1 .75.75V21a.75.75 0 0 1-1.5 0v-1.5a.75.75 0 0 1 .75-.75ZM6.166 18.894a.75.75 0 0 1-1.06-1.06l1.59-1.591a.75.75 0 1 1 1.061 1.06l-1.59 1.591ZM2.25 12a.75.75 0 0 1 .75-.75H5.25a.75.75 0 0 1 0 1.5H3a.75.75 0 0 1-.75-.75ZM6.166 6.166a.75.75 0 0 1 1.06-1.06l1.59 1.591a.75.75 0 1 1-1.061 1.06l-1.59-1.591Z" />';
} else {
// Moon Icon
themeIcon.innerHTML = '<path fill-rule="evenodd" clip-rule="evenodd" d="M9.528 1.718a.75.75 0 0 1 .162.819A8.97 8.97 0 0 0 9 6a9 9 0 0 0 9 9 8.97 8.97 0 0 0 3.463-.69.75.75 0 0 1 .981.98 10.503 10.503 0 0 1-9.694 6.46c-5.799 0-10.5-4.7-10.5-10.5 0-4.368 2.667-8.112 6.46-9.694a.75.75 0 0 1 .818.162Z" />';
}
}
// Mobile Navigation Toggle
mobileToggleBtn.addEventListener("click", () => {
const isActive = navLinks.classList.toggle("active");
document.body.style.overflow = isActive ? "hidden" : "";
// Toggle icon between hamburger and close (X)
if (isActive) {
mobileToggleBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>`;
} else {
mobileToggleBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16m-7 6h7" />
</svg>`;
}
});
// Close mobile menu when a navigation link is clicked
navLinks.querySelectorAll("a").forEach((link) => {
link.addEventListener("click", () => {
navLinks.classList.remove("active");
document.body.style.overflow = "";
mobileToggleBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16m-7 6h7" />
</svg>`;
});
});
// Update Year in Footer
const yearEl = document.getElementById("year");
if (yearEl) yearEl.textContent = new Date().getFullYear();
// Active Nav Link
const currentPage = location.pathname.split("/").pop() || "index.html";
document.querySelectorAll(".nav-links a").forEach((link) => {
link.classList.remove("active");
const linkPage = link.getAttribute("href").split("/").pop();
if (linkPage === currentPage) link.classList.add("active");
});
// Carousel Logic (About Page)
const slideEls = document.querySelectorAll(".carousel-slide");
const prevBtn = document.getElementById("prev");
const nextBtn = document.getElementById("next");
if (slideEls.length && prevBtn && nextBtn) {
let index = 0;
slideEls[index].classList.add("active");
function goTo(i) {
slideEls[index].classList.remove("active");
index = (i + slideEls.length) % slideEls.length;
slideEls[index].classList.add("active");
}
prevBtn.addEventListener("click", () => goTo(index - 1));
nextBtn.addEventListener("click", () => goTo(index + 1));
}
// Contact Form Logic (Contact Page)
// This form is frontend-only. To enable email sending, integrate a service
// such as EmailJS, Formspree, or a custom backend endpoint.
const contactForm = document.getElementById("contactForm");
const formStatus = document.getElementById("formStatus");
const submitBtn = document.getElementById("submitBtn");
if (contactForm) {
contactForm.addEventListener("submit", function (event) {
event.preventDefault();
if (!contactForm.checkValidity()) {
contactForm.reportValidity();
return;
}
// Simulate submission feedback (no actual sending occurs)
const btnSpan = submitBtn.querySelector("span");
const originalText = btnSpan.textContent;
btnSpan.textContent = "Sending...";
submitBtn.disabled = true;
formStatus.textContent = "";
formStatus.className = "form-status";
setTimeout(() => {
formStatus.textContent = "Thanks for your message! I'll get back to you soon.";
formStatus.className = "form-status success";
contactForm.reset();
btnSpan.textContent = originalText;
submitBtn.disabled = false;
}, 800);
});
}
What this script handles:
Theme toggle
- Read the saved theme from
localStorage - Fallback to OS preference (
window.matchMedia) if nothing is saved - Toggle
data-themeon<html> - Save user choice
Mobile menu
- Toggle nav visibility from a hamburger button
- Lock page scroll while the menu is open
- Close the menu when a nav link is clicked
Active nav state
- Compare
location.pathnamewith nav linkhref - Highlight the current page link automatically
Carousel controls
- Track current slide index
- Move with prev/next buttons
- Wrap around using modulo logic
Contact form feedback
- Prevent default submit
- Validate with
checkValidity() - Show a success message with a short simulated delay
- Reset form fields
Step 4: Customize for Your Brand
Before you publish, go through each page and replace the placeholder identity details with your own. Update your name in all five HTML files, especially in the page title, hero section, and footer. You should also change the brand initials in the .nav-brand link across every navbar so the site feels consistent.
Next, swap in your own visuals and content. Replace `assets/images/profile.jpg` (or update image `src` values), edit the hero intro text in index.html, and rewrite the about copy in about.html. While you’re there, update the experience timeline section and replace the carousel <img> elements with photos that represent your work or journey.
Then move on to project and resume details. Refresh the project cards in projects.html with your real work, and update the resume link and embed source in `resume.html` (href and src) so visitors can view and download the correct file.
Finally, review your contact and social links. Replace the email link in contact.html, update footer social URLs on each page, and search the project for any remaining your-username placeholders so nothing generic is left behind.
If you want a different accent color, change --accent in both the light and dark theme variable blocks.
Deploy Your Portfolio
When you’re ready to publish:
GitHub Pages
Push your repo, open Settings > Pages, select your branch, and publish.
Netlify
Drag and drop the project folder into Netlify for a quick deploy.
Vercel
Connect your GitHub repo for automatic deploys on every push.
Custom domain
Buy a domain and connect it to GitHub Pages, Netlify, or Vercel.
Final Thoughts
Building from scratch takes a little more effort than using a template, but it pays off quickly. You get a portfolio that feels like yours, and you understand how every piece works.
This project gives you practice with multi-page structure, responsive CSS, DOM scripting, localStorage, and small UX details that matter.
Customize it with your own work, ship it, and keep iterating as you grow.
If you encounter any issues while building your Portfolio website or if your code isn’t behaving as expected, don’t stress! You can download the source code for this Portfolio website project for free by clicking the download button below. Alternatively, you can check out a live demo of the Portfolio website by clicking the “View Live” button.















