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.

This commit is contained in:
Daniel LaForce 2025-04-09 21:54:16 -06:00
parent ca41764594
commit 35b2ba2113
10 changed files with 715 additions and 573 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 424 KiB

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 833 B

After

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -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">

View File

@ -118,4 +118,71 @@ function updateYear() {
if (yearElement) {
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;
}
});
}

View File

@ -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 */
@ -2500,4 +2521,31 @@ section {
color: #94a3b8;
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);
}