Enhance SEO metadata, update hero section content, improve navigation highlighting, and refactor JavaScript for role switching and scroll spy functionality. Remove unused CSS styles and add new project card styles.

This commit is contained in:
Daniel LaForce 2025-04-10 01:33:57 -06:00
parent e4f6a2542f
commit 2a239fb6c8
6 changed files with 426 additions and 171 deletions

BIN
images/og-preview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 KiB

View File

@ -13,6 +13,16 @@
<meta property="og:description" content="Expert in infrastructure architecture, DevOps automation, and secure cloud migrations. View my live lab dashboard and projects.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://laforceit.com">
<meta property="og:image" content="https://laforceit.com/images/og-preview.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:site_name" content="LaForceIT.com">
<!-- Twitter Card data -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Daniel LaForce | Infrastructure & Systems Architect">
<meta name="twitter:description" content="Expert in infrastructure architecture, DevOps automation, and secure cloud migrations.">
<meta name="twitter:image" content="https://laforceit.com/images/og-preview.jpg">
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="images/favicon.ico">
@ -76,7 +86,6 @@
<div class="intro-section">
<div class="name-section">
<h2 class="name">Daniel LaForce</h2>
<span class="your-text">your</span>
</div>
<h1 class="hero-title">
@ -97,7 +106,7 @@
</h1>
<p class="hero-description" id="role-description">
Securing and optimizing your digital infrastructure with enterprise-grade solutions — from zero-trust architecture to automated security monitoring that keeps your business protected 24/7.
Helping businesses run faster, safer, and smarter—through automated infrastructure, secure architecture, and real-world engineering.
</p>
<div class="inline-terminal">
@ -132,13 +141,13 @@
</div>
<div class="cta-buttons">
<a href="#contact" class="btn btn-primary">
<a href="#contact" class="btn btn-primary btn-featured">
<span class="pulse-ring"></span>
<span class="btn-text">Hire Me</span>
<span class="btn-icon"><i class="fas fa-arrow-right"></i></span>
</a>
<a href="https://www.argobox.com" class="btn btn-outline btn-featured" target="_blank">
<span class="pulse-ring"></span>
<a href="https://www.argobox.com" class="btn btn-outline" target="_blank">
<span class="btn-text">Explore My Lab</span>
<span class="btn-icon"><i class="fas fa-server"></i></span>
</a>
@ -372,63 +381,83 @@
<span>View Live Dashboard</span>
</span>
</a>
<a href="https://argobox.com/ansible-sandbox" class="btn btn-outline" target="_blank">Try Ansible Sandbox</a>
<a href="https://argobox.com/ansible-sandbox" class="btn btn-outline btn-offline" target="_blank">
<span class="flex-center">
<span class="offline-indicator"></span>
<span>Ansible Sandbox (Offline)</span>
</span>
</a>
</div>
</div>
<div class="lab-card">
<div class="lab-card lab-metrics-card">
<h3 class="lab-card-title">Real-Time Metrics</h3>
<div class="metric">
<div class="metric-header">
<span class="metric-name">CPU Usage</span>
<span class="metric-value">42%</span>
<div class="terminal-card">
<div class="terminal-card-header">
<span class="terminal-title">System Status</span>
<span class="terminal-status online">ONLINE</span>
</div>
<div class="metric-bar">
<div class="metric-progress" style="width: 42%"></div>
</div>
</div>
<div class="metric">
<div class="metric-header">
<span class="metric-name">Memory</span>
<span class="metric-value">57%</span>
</div>
<div class="metric-bar">
<div class="metric-progress" style="width: 57%"></div>
</div>
</div>
<div class="metric">
<div class="metric-header">
<span class="metric-name">Storage</span>
<span class="metric-value">63%</span>
</div>
<div class="metric-bar">
<div class="metric-progress" style="width: 63%"></div>
</div>
</div>
<div class="metric">
<div class="metric-header">
<span class="metric-name">Network</span>
<span class="metric-value">28%</span>
</div>
<div class="metric-bar">
<div class="metric-progress" style="width: 28%"></div>
<div class="terminal-card-content">
<div class="metric">
<div class="metric-header">
<span class="metric-name">CPU Usage</span>
<span class="metric-value">42%</span>
</div>
<div class="metric-bar">
<div class="metric-progress" style="width: 42%"></div>
</div>
</div>
<div class="metric">
<div class="metric-header">
<span class="metric-name">Memory</span>
<span class="metric-value">57%</span>
</div>
<div class="metric-bar">
<div class="metric-progress" style="width: 57%"></div>
</div>
</div>
<div class="metric">
<div class="metric-header">
<span class="metric-name">Storage</span>
<span class="metric-value">63%</span>
</div>
<div class="metric-bar">
<div class="metric-progress" style="width: 63%"></div>
</div>
</div>
<div class="metric">
<div class="metric-header">
<span class="metric-name">Network</span>
<span class="metric-value">28%</span>
</div>
<div class="metric-bar">
<div class="metric-progress" style="width: 28%"></div>
</div>
</div>
</div>
</div>
<h4 class="lab-subtitle">Active Services:</h4>
<div class="services-grid-small">
<div class="service-tag"><span class="status-dot"></span>Gitea</div>
<div class="service-tag"><span class="status-dot"></span>VSCode Server</div>
<div class="service-tag"><span class="status-dot"></span>rTorrent</div>
<div class="service-tag"><span class="status-dot"></span>NAS</div>
<div class="service-tag"><span class="status-dot"></span>Traefik</div>
<div class="service-tag"><span class="status-dot"></span>K3s</div>
<div class="service-tag"><span class="status-dot"></span>Cloudflared</div>
<div class="service-tag"><span class="status-dot"></span>FileBrowser</div>
<div class="service-tag"><span class="status-dot active"></span>Gitea</div>
<div class="service-tag"><span class="status-dot active"></span>VSCode Server</div>
<div class="service-tag"><span class="status-dot active"></span>rTorrent</div>
<div class="service-tag"><span class="status-dot active"></span>NAS</div>
<div class="service-tag"><span class="status-dot active"></span>Traefik</div>
<div class="service-tag"><span class="status-dot active"></span>K3s</div>
<div class="service-tag"><span class="status-dot active"></span>Cloudflared</div>
<div class="service-tag"><span class="status-dot active"></span>FileBrowser</div>
<div class="service-tag"><span class="status-dot active"></span>OpenWebUI</div>
<div class="service-tag"><span class="status-dot active"></span>Ollama</div>
<div class="service-tag"><span class="status-dot active"></span>Obsidian Blog</div>
<div class="service-tag"><span class="status-dot active"></span>Obsidian Notes</div>
<div class="service-tag"><span class="status-dot error"></span>Ansible Sandbox</div>
<div class="service-tag"><span class="status-dot active"></span>Jellyfin</div>
<div class="service-tag"><span class="status-dot active"></span>Plex</div>
</div>
</div>
</div>
@ -597,7 +626,7 @@
<i class="fab fa-linkedin"></i>
</div>
<h3 class="contact-title">LinkedIn</h3>
<p><a href="https://www.linkedin.com/in/daniellaforce" target="_blank">linkedin.com/in/daniellaforce</a></p>
<p><a href="https://www.linkedin.com/in/danlaforce" target="_blank">linkedin.com/in/danlaforce</a></p>
</div>
<div class="contact-item">
@ -605,7 +634,7 @@
<i class="fab fa-github"></i>
</div>
<h3 class="contact-title">GitHub</h3>
<p><a href="https://github.com/daniellaforce" target="_blank">github.com/daniellaforce</a></p>
<p><a href="https://github.com/keyargo" target="_blank">github.com/danlaforce</a></p>
</div>
</div>
@ -664,10 +693,10 @@
</div>
<div class="footer-social">
<a href="https://www.linkedin.com/in/daniellaforce" target="_blank" title="LinkedIn">
<a href="https://www.linkedin.com/in/danlaforce" target="_blank" title="LinkedIn">
<i class="fab fa-linkedin"></i>
</a>
<a href="https://github.com/daniellaforce" target="_blank" title="GitHub">
<a href="https://github.com/keyargo" target="_blank" title="GitHub">
<i class="fab fa-github"></i>
</a>
<a href="mailto:daniel@laforceit.com" title="Email">

View File

@ -508,9 +508,9 @@
<i class="fas fa-phone"></i>
<a href="tel:7203100064">720-310-0064</a>
</div>
<a href="mailto:daniel.laforce@laforceit.com" class="resume-contact-item">
<a href="mailto:daniel@laforceit.com" class="resume-contact-item">
<i class="fas fa-envelope"></i>
daniel.laforce@laforceit.com
daniel@laforceit.com
</a>
<a href="https://www.linkedin.com/in/danlaforce" class="resume-contact-item" target="_blank">
<i class="fab fa-linkedin"></i>
@ -987,10 +987,10 @@
</div>
<div class="footer-social">
<a href="https://www.linkedin.com/in/daniellaforce" target="_blank" title="LinkedIn">
<a href="https://www.linkedin.com/in/danlaforce" target="_blank" title="LinkedIn">
<i class="fab fa-linkedin"></i>
</a>
<a href="https://github.com/daniellaforce" target="_blank" title="GitHub">
<a href="https://github.com/keyargo" target="_blank" title="GitHub">
<i class="fab fa-github"></i>
</a>
<a href="mailto:daniel@laforceit.com" title="Email">

139
script.js
View File

@ -19,6 +19,37 @@ document.addEventListener('DOMContentLoaded', function() {
if (contactForm) {
initFormHandling(contactForm);
}
// Highlight navigation on scroll
setupScrollSpy();
// Setup role switching with improved timing
setupRoleSwitching();
// Other initializations...
setupFloatingIcons();
setupParticles();
setupRevealAnimations();
initializeSlider();
// Contact form handling
setupContactForm();
// Mobile menu toggle
document.querySelector('.menu-toggle').addEventListener('click', function() {
document.querySelector('.nav-menu').classList.toggle('active');
});
// Navbar effects on scroll
window.addEventListener('scroll', function() {
const navbar = document.querySelector('.navbar');
if (window.scrollY > 50) {
navbar.classList.add('scrolled');
} else {
navbar.classList.remove('scrolled');
}
});
});
/**
@ -460,4 +491,110 @@ function updateYear() {
if (yearElement) {
yearElement.textContent = new Date().getFullYear();
}
}
}
/**
* Sets up scroll spy functionality to highlight nav links
* as the user scrolls through different sections
*/
function setupScrollSpy() {
const sections = document.querySelectorAll('section[id]');
const navLinks = document.querySelectorAll('.nav-link');
window.addEventListener('scroll', function() {
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop - 100;
const sectionHeight = section.offsetHeight;
if (window.scrollY >= sectionTop && window.scrollY < sectionTop + sectionHeight) {
current = section.getAttribute('id');
}
});
navLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('href') === `#${current}`) {
link.classList.add('active');
}
});
});
}
/**
* Sets up automated role switching with better timing and transitions
*/
function setupRoleSwitching() {
const roles = document.querySelectorAll('.role');
const roleDescription = document.getElementById('role-description');
let currentRoleIndex = 0;
// Initial role description
if (roles.length > 0 && roleDescription) {
roleDescription.textContent = roles[0].getAttribute('data-description');
roles[0].classList.add('active');
}
// Switch roles every 5 seconds with fade transition
setInterval(() => {
// Remove active class from current role
roles[currentRoleIndex].classList.remove('active');
// Move to the next role or back to the first
currentRoleIndex = (currentRoleIndex + 1) % roles.length;
// Add active class to new role
roles[currentRoleIndex].classList.add('active');
// Update the role description with fade effect
if (roleDescription) {
roleDescription.style.opacity = '0';
setTimeout(() => {
roleDescription.textContent = roles[currentRoleIndex].getAttribute('data-description');
roleDescription.style.opacity = '1';
}, 300);
}
}, 5000);
}
// Replace the existing setupFloatingIcons with this improved version
function setupFloatingIcons() {
const container = document.getElementById('floating-icons');
if (!container) return;
// Clear existing icons
container.innerHTML = '';
// Tech icons to display
const icons = [
'fa-server', 'fa-network-wired', 'fa-shield-alt',
'fa-cloud', 'fa-code-branch', 'fa-database',
'fa-laptop-code', 'fa-lock', 'fa-terminal'
];
// Create floating icons
icons.forEach(icon => {
const iconElement = document.createElement('div');
iconElement.className = 'floating-icon';
iconElement.innerHTML = `<i class="fas ${icon}"></i>`;
// Random starting position
const randomX = Math.floor(Math.random() * 100);
const randomY = Math.floor(Math.random() * 100);
const randomDelay = Math.random() * 5;
const randomDuration = 20 + Math.random() * 10;
// Apply styles
iconElement.style.left = `${randomX}%`;
iconElement.style.top = `${randomY}%`;
iconElement.style.animationDelay = `${randomDelay}s`;
iconElement.style.animationDuration = `${randomDuration}s`;
// Add to container
container.appendChild(iconElement);
});
}
// More existing code...

101
style.css
View File

@ -1,101 +0,0 @@
.form-notification {
margin-top: 1rem;
padding: 1rem 1.5rem;
border-radius: 0.5rem;
display: none;
align-items: center;
gap: 0.75rem;
animation: slideIn 0.3s ease-out;
font-weight: 500;
position: fixed;
bottom: 2rem;
right: 2rem;
z-index: 1000;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.form-notification.success {
background-color: var(--success);
color: white;
border: none;
}
.form-notification.error {
background-color: var(--error);
color: white;
border: none;
}
.form-notification i {
font-size: 1.25rem;
}
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOut {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
.form-notification.hiding {
animation: slideOut 0.3s ease-in forwards;
}
@keyframes float-particle {
0% {
transform: translate(0, 0);
}
25% {
transform: translate(20px, -20px);
}
50% {
transform: translate(40px, 0);
}
75% {
transform: translate(20px, 20px);
}
100% {
transform: translate(0, 0);
}
}
:root {
--success: #10b981;
--error: #ef4444;
}
.logo-text-glow {
font-weight: 800;
font-size: 1.6rem;
background: linear-gradient(90deg, var(--accent), var(--accent-darker));
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 6px rgba(59, 130, 246, 0.5);
transition: all 0.3s ease-in-out;
letter-spacing: -0.02em;
}
.logo-dot-glow {
color: white;
font-weight: 600;
font-size: 1.6rem;
margin-left: -1px;
text-shadow: 0 0 3px rgba(255, 255, 255, 0.3);
transition: all 0.3s ease-in-out;
}

View File

@ -1,6 +1,5 @@
/*
* Main stylesheet for argobox.com
* Modern tech portfolio design with animation effects
* Main stylesheet for laforceit.com
*/
:root {
@ -198,7 +197,6 @@ section {
.navbar.scrolled {
background-color: rgba(15, 23, 42, 0.95);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}
.navbar .container {
@ -443,13 +441,14 @@ background-clip: text;
}
.hero-description {
font-size: 1.2rem;
font-size: 1.1rem;
color: var(--text-secondary);
margin-top: 1.5rem; /* Add explicit top margin */
margin-bottom: 2rem;
max-width: 550px;
position: relative; /* Make it position relative */
z-index: 1; /* Ensure it's above the role titles */
max-width: 90%;
line-height: 1.6;
position: relative;
z-index: 10;
transition: opacity 0.3s ease;
}
/* Terminal text that appears directly on the page */
@ -1153,8 +1152,6 @@ background-clip: text;
padding: 2rem;
transition: all var(--transition-normal);
height: 100%;
display: flex;
flex-direction: column;
}
.project-card:hover {
@ -1874,4 +1871,197 @@ body::before {
}
}
/* Highlight navigation links on scroll */
.nav-link.active {
color: var(--accent);
font-weight: 600;
}
.nav-link.active::after {
width: 100%;
opacity: 1;
}
/* Terminal Card Styles for Lab Section */
.terminal-card {
background-color: rgba(15, 23, 42, 0.95);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
margin-bottom: 1.5rem;
box-shadow: var(--card-shadow);
transition: all var(--transition-normal);
}
.terminal-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 30px -10px rgba(0, 0, 0, 0.4);
}
.terminal-card-header {
background-color: rgba(30, 41, 59, 0.95);
padding: 0.75rem 1rem;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--border);
}
.terminal-title {
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
font-weight: 500;
color: var(--text-primary);
}
.terminal-status {
font-family: 'JetBrains Mono', monospace;
font-size: 0.75rem;
font-weight: 700;
padding: 0.25rem 0.5rem;
border-radius: 4px;
background-color: rgba(15, 23, 42, 0.7);
}
.terminal-status.online {
color: var(--success);
}
.terminal-card-content {
padding: 1rem;
}
/* Service tags with active indicators */
.status-dot.active {
background-color: var(--success);
box-shadow: 0 0 5px var(--success);
animation: pulse 2s infinite;
}
/* Service tags with error indicators */
.status-dot.error {
background-color: var(--error);
box-shadow: 0 0 5px var(--error);
}
/* Project Cards with Images */
.project-card {
display: flex;
flex-direction: column;
background-color: var(--card-bg);
border-radius: 12px;
overflow: hidden;
transition: all var(--transition-normal);
border: 1px solid var(--border);
box-shadow: var(--card-shadow);
}
.project-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 30px -10px rgba(0, 0, 0, 0.4);
border-color: var(--accent);
}
.project-image {
position: relative;
height: 180px;
overflow: hidden;
background-color: rgba(15, 23, 42, 0.8);
}
.project-thumbnail {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
opacity: 0.7;
}
.project-card:hover .project-thumbnail {
transform: scale(1.05);
opacity: 0.9;
}
.project-icon {
position: absolute;
bottom: -25px;
right: 20px;
width: 50px;
height: 50px;
border-radius: 50%;
background: var(--accent-gradient);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 1.5rem;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
border: 3px solid var(--primary-bg);
z-index: 1;
}
.project-content {
padding: 1.5rem;
padding-top: 1rem;
flex: 1;
display: flex;
flex-direction: column;
}
.project-links {
margin-top: auto;
padding-top: 1rem;
display: flex;
gap: 1rem;
}
.project-link {
font-size: 0.85rem;
font-weight: 500;
color: var(--accent);
transition: all var(--transition-normal);
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.project-link:hover {
color: var(--accent-darker);
text-decoration: underline;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.project-card {
flex-direction: column;
}
.project-image {
height: 160px;
}
}
.btn-offline {
border-color: var(--error);
color: var(--error);
cursor: not-allowed;
opacity: 0.8;
}
.btn-offline:hover {
background-color: rgba(239, 68, 68, 0.1);
color: var(--error);
box-shadow: 0 0 10px rgba(239, 68, 68, 0.3);
transform: translateY(-2px);
}
.offline-indicator {
width: 10px;
height: 10px;
background-color: var(--error);
border-radius: 50%;
display: inline-block;
margin-right: 0.5rem;
}