Implement contact section and form functionality: Added a new contact section with a form for user inquiries, including validation and success/error message handling. Updated navigation links and styles for improved user experience.
1060
ansible-sandbox.html
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 424 KiB After Width: | Height: | Size: 190 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 833 B After Width: | Height: | Size: 757 B |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
61
index.html
|
@ -38,11 +38,11 @@
|
|||
</a>
|
||||
</div>
|
||||
<div class="nav-menu">
|
||||
<a href="#home" class="nav-link active">Home</a>
|
||||
<a href="#home" class="nav-link">Home</a>
|
||||
<a href="#technologies" class="nav-link">Technologies</a>
|
||||
<a href="#services" class="nav-link">Services</a>
|
||||
<a href="#lab" class="nav-link">Live Lab</a>
|
||||
<a href="#projects" class="nav-link">Projects</a>
|
||||
<a href="#experience" class="nav-link">Experience</a>
|
||||
<a href="#dashboards" class="nav-link">Dashboards</a>
|
||||
<a href="#contact" class="nav-link">Contact</a>
|
||||
</div>
|
||||
<div class="nav-buttons">
|
||||
|
@ -62,7 +62,7 @@
|
|||
<a href="https://laforceit.com" class="laforceit-link">
|
||||
<span class="logo-text-glow">LaForceIT</span><span class="logo-dot-glow">.com</span>
|
||||
</a>
|
||||
<a href="https://login.argobox.com" class="signin-button" target="_blank">
|
||||
<a href="construction.html" class="signin-button" target="_blank">
|
||||
<i class="fas fa-sign-in-alt"></i>
|
||||
<span>Sign In</span>
|
||||
</a>
|
||||
|
@ -827,6 +827,59 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Contact Section -->
|
||||
<section id="contact" class="contact">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Let's Connect</h2>
|
||||
<p class="section-description">
|
||||
Have a project in mind? Reach out to discuss how I can help.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="contact-grid">
|
||||
<div class="contact-info">
|
||||
<div class="contact-item">
|
||||
<div class="contact-icon">
|
||||
<i class="fas fa-envelope"></i>
|
||||
</div>
|
||||
<h3 class="contact-title">Email</h3>
|
||||
<p><a href="mailto:daniel@argobox.com">daniel@argobox.com</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="contact-form-container">
|
||||
<form id="contact-form" class="contact-form">
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" id="name" name="name" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" name="email" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="subject">Subject</label>
|
||||
<input type="text" id="subject" name="subject" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="message">Message</label>
|
||||
<textarea id="message" name="message" rows="5" required></textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-paper-plane btn-icon"></i>
|
||||
Send Message
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
|
|
67
script.js
|
@ -119,3 +119,70 @@ function updateYear() {
|
|||
yearElement.textContent = new Date().getFullYear();
|
||||
}
|
||||
}
|
||||
|
||||
// Contact Form Handler
|
||||
const contactForm = document.getElementById('contact-form');
|
||||
if (contactForm) {
|
||||
contactForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const submitButton = contactForm.querySelector('button[type="submit"]');
|
||||
const originalButtonText = submitButton.innerHTML;
|
||||
|
||||
try {
|
||||
submitButton.disabled = true;
|
||||
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
|
||||
|
||||
const formData = new FormData(contactForm);
|
||||
const data = {
|
||||
name: formData.get('name'),
|
||||
email: formData.get('email'),
|
||||
subject: formData.get('subject'),
|
||||
message: formData.get('message')
|
||||
};
|
||||
|
||||
const response = await fetch('/functions/contact', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.error || 'Failed to send email');
|
||||
}
|
||||
|
||||
// Show success message
|
||||
const successMessage = document.createElement('div');
|
||||
successMessage.className = 'alert alert-success';
|
||||
successMessage.innerHTML = '<i class="fas fa-check-circle"></i> Message sent successfully! We\'ll get back to you soon.';
|
||||
contactForm.insertBefore(successMessage, submitButton);
|
||||
contactForm.reset();
|
||||
|
||||
// Remove success message after 5 seconds
|
||||
setTimeout(() => {
|
||||
successMessage.remove();
|
||||
}, 5000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error sending email:', error);
|
||||
|
||||
// Show error message
|
||||
const errorMessage = document.createElement('div');
|
||||
errorMessage.className = 'alert alert-error';
|
||||
errorMessage.innerHTML = '<i class="fas fa-exclamation-circle"></i> ' + error.message;
|
||||
contactForm.insertBefore(errorMessage, submitButton);
|
||||
|
||||
// Remove error message after 5 seconds
|
||||
setTimeout(() => {
|
||||
errorMessage.remove();
|
||||
}, 5000);
|
||||
|
||||
} finally {
|
||||
submitButton.disabled = false;
|
||||
submitButton.innerHTML = originalButtonText;
|
||||
}
|
||||
});
|
||||
}
|
92
styles.css
|
@ -1344,10 +1344,16 @@ section {
|
|||
}
|
||||
|
||||
/* Contact Section */
|
||||
.contact {
|
||||
padding: 6rem 0;
|
||||
background: var(--secondary-bg);
|
||||
}
|
||||
|
||||
.contact-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
gap: 3rem;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.contact-info {
|
||||
|
@ -1357,45 +1363,50 @@ section {
|
|||
}
|
||||
|
||||
.contact-item {
|
||||
background-color: var(--card-bg);
|
||||
background: var(--card-bg);
|
||||
padding: 2rem;
|
||||
border-radius: 1rem;
|
||||
border: 1px solid var(--border);
|
||||
padding: 1.5rem;
|
||||
transition: all var(--transition-normal);
|
||||
box-shadow: var(--card-shadow);
|
||||
transition: var(--transition-normal);
|
||||
}
|
||||
|
||||
.contact-item:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: var(--card-shadow);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.contact-icon {
|
||||
font-size: 2rem;
|
||||
color: var(--accent);
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background: var(--accent-gradient);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.contact-icon i {
|
||||
color: var(--text-primary);
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.contact-title {
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.contact-form-container {
|
||||
background-color: var(--card-bg);
|
||||
border-radius: 1rem;
|
||||
border: 1px solid var(--border);
|
||||
background: var(--card-bg);
|
||||
padding: 2rem;
|
||||
transition: all var(--transition-normal);
|
||||
}
|
||||
|
||||
.contact-form-container:hover {
|
||||
border-radius: 1rem;
|
||||
box-shadow: var(--card-shadow);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.contact-form {
|
||||
display: grid;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
|
@ -1406,26 +1417,36 @@ section {
|
|||
}
|
||||
|
||||
.form-group label {
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group textarea {
|
||||
padding: 0.75rem;
|
||||
background-color: rgba(15, 23, 42, 0.6);
|
||||
padding: 0.8rem 1rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 0.5rem;
|
||||
background: var(--card-bg);
|
||||
color: var(--text-primary);
|
||||
font-family: 'Inter', sans-serif;
|
||||
transition: all var(--transition-normal);
|
||||
transition: var(--transition-normal);
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.3);
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
resize: vertical;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contact-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
|
@ -2501,3 +2522,30 @@ section {
|
|||
margin: 0;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
/* Contact Form Alerts */
|
||||
.alert {
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.alert i {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: rgba(16, 185, 129, 0.1);
|
||||
border: 1px solid var(--success);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: rgba(239, 68, 68, 0.1);
|
||||
border: 1px solid var(--error);
|
||||
color: var(--error);
|
||||
}
|