<!
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My Portfolio</title>
<style>
@import url('https://fonts.googleapis.com/css2?
family=Poppins:wght@400;600;800&display=swap');
:root {
--color-bg: #ffffff;
--color-text-primary: #111827;
--color-text-secondary: #6b7280;
--color-accent: #2563eb;
--color-accent-hover: #1e40af;
--border-radius: 0.75rem;
--shadow-light: rgba(0, 0, 0, 0.1);
--max-width: 1200px;
--transition-speed: 0.3s;
}
/* Global Reset */
* {
box-sizing: border-box;
}
body {
margin: 0; padding: 0;
background-color: var(--color-bg);
color: var(--color-text-primary);
font-family: 'Poppins', sans-serif;
line-height: 1.6;
font-size: 18px;
font-weight: 400;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
color: var(--color-accent);
text-decoration: none;
transition: color var(--transition-speed);
}
a:hover,
a:focus {
color: var(--color-accent-hover);
outline: none;
}
img {
max-width: 100%;
height: auto;
border-radius: var(--border-radius);
}
h1, h2, h3, h4 {
margin: 0;
font-weight: 800;
color: var(--color-text-primary);
}
h1 {
font-size: 3rem;
line-height: 1.2;
margin-bottom: 0.5rem;
}
h2 {
font-size: 2rem;
margin-bottom: 1rem;
}
h3 {
font-size: 1.25rem;
margin-bottom: 0.5rem;
}
/* Container */
.container {
max-width: var(--max-width);
margin-left: auto;
margin-right: auto;
padding-left: 1rem;
padding-right: 1rem;
}
/* Header & Nav */
header {
position: sticky;
top: 0;
background: var(--color-bg);
box-shadow: 0 1px 4px var(--shadow-light);
z-index: 1000;
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
max-width: var(--max-width);
margin: 0 auto;
padding: 1rem 1rem;
}
.logo {
font-size: 1.5rem;
font-weight: 800;
color: var(--color-accent);
user-select: none;
}
.nav-links {
display: flex;
gap: 2rem;
}
.nav-links a {
font-weight: 600;
padding: 0.25rem 0.5rem;
border-radius: var(--border-radius);
transition: background-color var(--transition-speed), color var(--
transition-speed);
}
.nav-links a:hover,
.nav-links a:focus {
background-color: var(--color-accent);
color: #fff;
outline: none;
}
/* Hero Section */
#hero {
padding: 6rem 1rem 6rem;
background: linear-gradient(135deg, #e0f2fe 0%, #bae6fd 100%);
text-align: center;
border-radius: var(--border-radius);
box-shadow: 0 8px 16px rgba(37, 99, 235, 0.25);
}
#hero h1 {
font-size: 3.5rem;
margin-bottom: 0.75rem;
}
#hero p {
font-size: 1.25rem;
color: var(--color-text-secondary);
margin-bottom: 2rem;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
#hero .cta-button {
background-color: var(--color-accent);
color: white;
font-weight: 700;
padding: 1rem 2.5rem;
border: none;
border-radius: var(--border-radius);
font-size: 1.125rem;
cursor: pointer;
box-shadow: 0 4px 8px rgba(37, 99, 235, 0.5);
transition: background-color var(--transition-speed), transform
var(--transition-speed);
}
#hero .cta-button:hover,
#hero .cta-button:focus {
background-color: var(--color-accent-hover);
transform: scale(1.05);
outline: none;
}
/* Sections */
section {
padding-top: 5rem;
padding-bottom: 5rem;
max-width: var(--max-width);
margin-left: auto;
margin-right: auto;
}
/* About */
#about .content {
max-width: 900px;
margin-left: auto;
margin-right: auto;
color: var(--color-text-secondary);
font-size: 1.125rem;
line-height: 1.8;
text-align: center;
}
/* Skills */
#skills .skills-grid {
display: grid;
grid-template-columns: repeat(auto-fit,minmax(140px,1fr));
gap: 2rem;
max-width: 900px;
margin: 0 auto;
}
.skill-card {
background: #f9fafe;
border-radius: var(--border-radius);
padding: 1.5rem;
text-align: center;
font-weight: 600;
font-size: 1rem;
color: var(--color-text-primary);
box-shadow: 0 2px 6px var(--shadow-light);
transition: transform var(--transition-speed);
cursor: default;
user-select: none;
}
.skill-card:hover {
transform: translateY(-6px);
}
/* Projects */
#projects .projects-grid {
display: grid;
grid-template-columns: repeat(auto-fit,minmax(280px,1fr));
gap: 2.5rem;
max-width: 1200px;
margin: 0 auto;
}
.project-card {
background: #fefefe;
box-shadow: 0 4px 12px var(--shadow-light);
border-radius: var(--border-radius);
overflow: hidden;
display: flex;
flex-direction: column;
transition: transform var(--transition-speed);
cursor: pointer;
}
.project-card:hover {
transform: translateY(-8px);
}
.project-image {
width: 100%;
height: 180px;
object-fit: cover;
border-bottom: 1px solid #e5e7eb;
}
.project-content {
padding: 1rem 1.25rem 1.5rem;
flex-grow: 1;
display: flex;
flex-direction: column;
}
.project-title {
font-weight: 700;
margin-bottom: 0.5rem;
color: var(--color-text-primary);
}
.project-description {
flex-grow: 1;
color: var(--color-text-secondary);
font-size: 0.95rem;
}
.project-links {
margin-top: 1rem;
display: flex;
gap: 1rem;
}
.project-link {
color: var(--color-accent);
font-weight: 700;
font-size: 0.9rem;
transition: color var(--transition-speed);
}
.project-link:hover,
.project-link:focus {
color: var(--color-accent-hover);
outline: none;
}
/* Contact */
#contact {
background: #f9fafe;
border-radius: var(--border-radius);
padding: 2rem 1rem 3rem;
max-width: 600px;
margin: 0 auto 5rem;
box-shadow: 0 2px 10px var(--shadow-light);
}
#contact h2 {
text-align: center;
margin-bottom: 2rem;
}
form {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
label {
font-weight: 600;
color: var(--color-text-primary);
}
input[type="text"],
input[type="email"],
textarea {
font-family: 'Poppins', sans-serif;
font-size: 1rem;
padding: 0.75rem 1rem;
border: 1.5px solid #d1d5db;
border-radius: var(--border-radius);
transition: border-color var(--transition-speed);
resize: vertical;
}
input[type="text"]:focus,
input[type="email"]:focus,
textarea:focus {
outline: none;
border-color: var(--color-accent);
box-shadow: 0 0 8px rgba(37, 99, 235, 0.4);
}
button[type="submit"] {
background-color: var(--color-accent);
color: white;
font-weight: 700;
padding: 1rem 1.5rem;
border: none;
border-radius: var(--border-radius);
font-size: 1.125rem;
cursor: pointer;
box-shadow: 0 4px 8px rgba(37, 99, 235, 0.5);
transition: background-color var(--transition-speed), transform
var(--transition-speed);
}
button[type="submit"]:hover,
button[type="submit"]:focus {
background-color: var(--color-accent-hover);
transform: scale(1.05);
outline: none;
}
.form-status {
font-weight: 600;
font-size: 1rem;
text-align: center;
margin-top: 1rem;
}
.form-status.success {
color: #16a34a;
}
.form-status.error {
color: #dc2626;
}
/* Footer */
footer {
text-align: center;
color: var(--color-text-secondary);
padding: 2rem 1rem;
font-size: 0.9rem;
}
/* Responsive */
@media (max-width: 640px) {
#hero h1 {
font-size: 2.7rem;
}
#hero p {
font-size: 1rem;
}
.nav-links {
gap: 1rem;
}
}
</style>
</head>
<body>
<header>
<nav class="container" role="navigation" aria-label="Primary
Navigation">
<div class="logo" tabindex="0">HolarTech_Pulse</div>
<div class="nav-links">
<a href="#about">About</a>
<a href="#skills">Skills</a>
<a href="#projects">Projects</a>
<a href="#contact">Contact</a>
</div>
</nav>
</header>
<main>
<section id="hero" role="banner" aria-label="Introduction">
<div class="container">
<h1>Crafting Modern Web Experiences</h1>
<p>Hi, I'm a passionate developer crafting responsive, elegant
websites and applications with clean code and awesome UX design.</p>
<button class="cta-button"
onclick="document.getElementById('contact').scrollIntoView({behavior:'smo
oth'})">Contact Me</button>
</div>
</section>
<section id="about" aria-labelledby="about-title" class="container">
<h2 id="about-title">About Me</h2>
<div class="content">
<p>Hello! I'm a full-stack web developer with a love for creating
beautiful, user-friendly, and performant web experiences. I specialize in
modern JavaScript frameworks, responsive design, and accessible
interfaces.</p>
</div>
</section>
<section id="skills" aria-labelledby="skills-title" class="container">
<h2 id="skills-title">Skills</h2>
<div class="skills-grid" role="list" aria-label="List of skills">
<div class="skill-card" role="listitem" tabindex="0">HTML5</div>
<div class="skill-card" role="listitem" tabindex="0">CSS3</div>
<div class="skill-card" role="listitem" tabindex="0">JavaScript
(ES6+)</div>
<div class="skill-card" role="listitem" tabindex="0">React</div>
<div class="skill-card" role="listitem" tabindex="0">Node.js</div>
<div class="skill-card" role="listitem" tabindex="0">Express</div>
<div class="skill-card" role="listitem" tabindex="0">SQLite</div>
<div class="skill-card" role="listitem" tabindex="0">REST
APIs</div>
<div class="skill-card" role="listitem" tabindex="0">Git &
GitHub</div>
</div>
</section>
<section id="projects" aria-labelledby="projects-title"
class="container">
<h2 id="projects-title">Projects</h2>
<div class="projects-grid" aria-label="List of projects">
<article class="project-card" tabindex="0">
<img src="https://images.unsplash.com/photo-1522202176988-
66273c2fd55f?auto=format&fit=crop&w=600&q=80" alt="Project 1 screenshot"
class="project-image" />
<div class="project-content">
<h3 class="project-title">Portfolio Website</h3>
<p class="project-description">A modern, responsive portfolio
website built with React and TailwindCSS showcasing web projects and
skills.</p>
<div class="project-links">
<a class="project-link"
href="https://github.com/yourusername/portfolio" target="_blank"
rel="noopener noreferrer">GitHub</a>
<a class="project-link" href="https://yourportfolio.com"
target="_blank" rel="noopener noreferrer">Live Site</a>
</div>
</div>
</article>
<article class="project-card" tabindex="0">
<img src="https://images.unsplash.com/photo-1519389950473-
47ba0277781c?auto=format&fit=crop&w=600&q=80" alt="Project 2 screenshot"
class="project-image" />
<div class="project-content">
<h3 class="project-title">Task Manager API</h3>
<p class="project-description">A RESTful API built with Node.js
and Express, featuring user authentication and task management with
MongoDB.</p>
<div class="project-links">
<a class="project-link"
href="https://github.com/yourusername/task-manager-api" target="_blank"
rel="noopener noreferrer">GitHub</a>
<a class="project-link" href="#" tabindex="-1" aria-
disabled="true" style="color:gray;cursor:default;">Live Site</a>
</div>
</div>
</article>
<article class="project-card" tabindex="0">
<img src="https://images.unsplash.com/photo-1498050108023-
c5249f4df085?auto=format&fit=crop&w=600&q=80" alt="Project 3 screenshot"
class="project-image" />
<div class="project-content">
<h3 class="project-title">E-Commerce Store</h3>
<p class="project-description">A full-stack e-commerce store
developed with React, Node.js and Stripe for seamless payments.</p>
<div class="project-links">
<a class="project-link"
href="https://github.com/yourusername/ecommerce-store" target="_blank"
rel="noopener noreferrer">GitHub</a>
<a class="project-link" href="https://store.example.com"
target="_blank" rel="noopener noreferrer">Live Site</a>
</div>
</div>
</article>
</div>
</section>
<section id="contact" aria-labelledby="contact-title" tabindex="-1">
<h2 id="contact-title">Contact Me</h2>
<form id="contact-form" novalidate aria-describedby="form-status"
aria-live="polite">
<label for="name">Name</label>
<input type="text" id="name" name="name" required minlength="2"
autocomplete="name" aria-required="true" aria-describedby="name-error"/>
<span id="name-error" class="error-message" role="alert"
style="display:none;color:#dc2626;font-size:0.9rem;">Please enter your
name (at least 2 characters).</span>
<label for="email">Email</label>
<input type="email" id="email" name="email" required
autocomplete="email" aria-required="true" aria-describedby="email-
error"/>
<span id="email-error" class="error-message" role="alert"
style="display:none;color:#dc2626;font-size:0.9rem;">Please enter a valid
email address.</span>
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required
minlength="10" aria-required="true" aria-describedby="message-
error"></textarea>
<span id="message-error" class="error-message" role="alert"
style="display:none;color:#dc2626;font-size:0.9rem;">Please enter a
message (at least 10 characters).</span>
<button type="submit">Send Message</button>
<div id="form-status" class="form-status" role="status" aria-
live="polite"></div>
</form>
</section>
</main>
<footer>
<p>© 2024 MyPortfolio — Built with ❤️</p>
</footer>
<script>
(() => {
const form = document.getElementById('contact-form');
const statusEl = document.getElementById('form-status');
const showError = (id, message) => {
const el = document.getElementById(id);
el.style.display = 'block';
el.textContent = message;
};
const hideError = (id) => {
const el = document.getElementById(id);
el.style.display = 'none';
el.textContent = '';
};
const validate = () => {
let valid = true;
const name = form.name.value.trim();
if(name.length < 2) {
showError('name-error', 'Please enter your name (at least 2
characters).');
valid = false;
} else {
hideError('name-error');
}
const email = form.email.value.trim();
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if(!emailRegex.test(email)) {
showError('email-error', 'Please enter a valid email address.');
valid = false;
} else {
hideError('email-error');
}
const message = form.message.value.trim();
if(message.length < 10) {
showError('message-error', 'Please enter a message (at least 10
characters).');
valid = false;
} else {
hideError('message-error');
}
return valid;
};
form.addEventListener('submit', async (e) => {
e.preventDefault();
statusEl.textContent = '';
statusEl.className = 'form-status';
if(!validate()) {
statusEl.textContent = 'Please fix the errors above and try
again.';
statusEl.classList.add('error');
return;
}
const formData = {
name: form.name.value.trim(),
email: form.email.value.trim(),
message: form.message.value.trim()
};
try {
statusEl.textContent = 'Sending message...';
const res = await fetch('/api/contact', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData)
});
if(res.ok) {
statusEl.textContent = 'Thank you for your message! I will get
back to you soon.';
statusEl.classList.add('success');
form.reset();
} else {
const data = await res.json();
statusEl.textContent = data.error || 'Something went wrong.
Please try again later.';
statusEl.classList.add('error');
}
} catch (err) {
statusEl.textContent = 'Failed to send message. Please check your
network and try again.';
statusEl.classList.add('error');
}
});
})();
</script>
</body>
</html>