Implement code changes to enhance functionality and improve performance

This commit is contained in:
Daniel LaForce 2025-04-08 18:09:32 -06:00
parent 855628795c
commit e4abc52092
6 changed files with 2718 additions and 1180 deletions

View File

@ -85,9 +85,137 @@
padding: 0 1.5rem;
}
/* Navigation Bar */
.navbar {
background-color: rgba(15, 23, 42, 0.9);
backdrop-filter: var(--glass-effect);
-webkit-backdrop-filter: var(--glass-effect);
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
padding: 1rem 0;
border-bottom: 1px solid var(--border);
}
.navbar .container {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-weight: 600;
font-size: 1.5rem;
}
.logo a {
color: var(--text-primary);
text-decoration: none;
display: flex;
align-items: center;
}
.logo-text {
background: var(--accent-gradient);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.logo-dot {
color: var(--text-secondary);
}
.nav-menu {
display: flex;
gap: 2rem;
}
.nav-link {
color: var(--text-secondary);
text-decoration: none;
font-size: 0.95rem;
font-weight: 500;
transition: all var(--transition-normal);
position: relative;
}
.nav-link::after {
content: "";
position: absolute;
bottom: -5px;
left: 0;
width: 0;
height: 2px;
background: var(--accent-gradient);
transition: width var(--transition-normal);
}
.nav-link:hover {
color: var(--text-primary);
}
.nav-link:hover::after {
width: 100%;
}
.nav-link.active {
color: var(--accent);
}
.nav-link.active::after {
width: 100%;
}
.nav-buttons {
display: flex;
align-items: center;
gap: 1rem;
}
.dashboard-link {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
font-size: 0.9rem;
font-weight: 500;
color: var(--text-primary);
background-color: rgba(59, 130, 246, 0.1);
border: 1px solid rgba(59, 130, 246, 0.2);
border-radius: 0.5rem;
text-decoration: none;
transition: all var(--transition-normal);
}
.dashboard-link:hover {
background-color: rgba(59, 130, 246, 0.2);
border-color: rgba(59, 130, 246, 0.3);
}
.live-indicator {
width: 8px;
height: 8px;
background-color: var(--success);
border-radius: 50%;
animation: pulse 2s infinite;
}
.menu-toggle {
display: none;
background: none;
border: none;
color: var(--text-primary);
font-size: 1.25rem;
cursor: pointer;
}
/* Sandbox Specific Styles */
.sandbox-container {
padding: 5rem 0 2rem;
margin-top: 4rem;
}
.sandbox-header {
@ -630,31 +758,64 @@
}
/* Footer */
.sandbox-footer {
.footer {
background-color: var(--secondary-bg);
border-top: 1px solid var(--border);
padding: 3rem 0 1.5rem;
margin-top: 5rem;
}
.footer-content {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 2rem;
margin-bottom: 2rem;
}
.footer-logo {
font-weight: 600;
font-size: 1.5rem;
}
.footer-links {
display: flex;
gap: 2rem;
}
.footer-links a {
color: var(--text-secondary);
text-decoration: none;
font-size: 0.95rem;
transition: color var(--transition-normal);
}
.footer-links a:hover {
color: var(--accent);
}
.footer-social {
display: flex;
gap: 1.25rem;
}
.footer-social a {
color: var(--text-secondary);
font-size: 1.25rem;
transition: color var(--transition-normal);
}
.footer-social a:hover {
color: var(--accent);
}
.footer-bottom {
padding-top: 1.5rem;
border-top: 1px solid var(--border);
font-size: 0.85rem;
text-align: center;
font-size: 0.9rem;
color: var(--text-secondary);
}
.back-to-site {
display: flex;
align-items: center;
gap: 0.5rem;
color: var(--accent);
font-weight: 500;
transition: all var(--transition-normal);
}
.back-to-site:hover {
color: var(--accent-darker);
transform: translateX(-3px);
}
/* Animation */
@keyframes pulse {
0% {
@ -679,6 +840,29 @@
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
.nav-menu {
position: fixed;
top: 75px;
left: 0;
right: 0;
background-color: var(--primary-bg);
flex-direction: column;
align-items: center;
padding: 2rem 0;
gap: 1.5rem;
transition: transform var(--transition-normal);
transform: translateY(-150%);
border-bottom: 1px solid var(--border);
}
.nav-menu.show {
transform: translateY(0);
}
.menu-toggle {
display: block;
}
}
@media (max-width: 768px) {
@ -696,10 +880,52 @@
.preview-tabs {
display: none;
}
.footer-content {
flex-direction: column;
gap: 2rem;
align-items: flex-start;
}
.footer-links {
flex-wrap: wrap;
justify-content: center;
gap: 1.5rem;
row-gap: 1rem;
}
}
</style>
</head>
<body>
<!-- Navigation Bar -->
<nav class="navbar">
<div class="container">
<div class="logo">
<a href="index.html">
<span class="logo-text">Argobox</span>
<span class="logo-dot">.com</span>
</a>
</div>
<div class="nav-menu" id="navMenu">
<a href="index.html#home" class="nav-link">Home</a>
<a href="index.html#services" class="nav-link">Services</a>
<a href="index.html#lab" class="nav-link active">Live Lab</a>
<a href="index.html#projects" class="nav-link">Projects</a>
<a href="index.html#experience" class="nav-link">Experience</a>
<a href="index.html#contact" class="nav-link">Contact</a>
</div>
<div class="nav-buttons">
<a href="dashboard.html" class="dashboard-link" target="_blank">
<span class="live-indicator"></span>
<span>Live Dashboard</span>
</a>
<button class="menu-toggle" id="menuToggle" aria-label="Toggle menu">
<i class="fas fa-bars"></i>
</button>
</div>
</div>
</nav>
<div class="sandbox-container">
<div class="container">
<div class="sandbox-header">
@ -1233,18 +1459,59 @@
</div>
</div>
<div class="sandbox-footer">
<a href="index.html" class="back-to-site">
<i class="fas fa-arrow-left"></i>
<span>Back to Main Site</span>
</a>
<div class="footer-info">Sandbox environments automatically shut down after 30 minutes</div>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-logo">
<span class="logo-text">Argobox</span>
<span class="logo-dot">.com</span>
</div>
<div class="footer-links">
<a href="#home">Home</a>
<a href="#services">Services</a>
<a href="#lab">Live Lab</a>
<a href="#projects">Projects</a>
<a href="#contact">Contact</a>
</div>
<div class="footer-social">
<a href="https://github.com/keyargo" target="_blank" aria-label="GitHub"><i class="fab fa-github"></i></a>
<a href="https://www.linkedin.com/in/danlaforce" target="_blank" aria-label="LinkedIn"><i class="fab fa-linkedin"></i></a>
<a href="mailto:daniel.laforce@argobox.com" aria-label="Email"><i class="fas fa-envelope"></i></a>
</div>
</div>
<div class="footer-bottom">
<p>&copy; <span id="current-year"></span> All rights reserved. Inovin LLC</p>
</div>
</div>
</footer>
<!-- JavaScript -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Set current year for copyright
document.getElementById('current-year').textContent = new Date().getFullYear();
// Mobile menu toggle
const menuToggle = document.getElementById('menuToggle');
const navMenu = document.getElementById('navMenu');
menuToggle.addEventListener('click', function() {
navMenu.classList.toggle('show');
const icon = menuToggle.querySelector('i');
if (navMenu.classList.contains('show')) {
icon.classList.remove('fa-bars');
icon.classList.add('fa-times');
} else {
icon.classList.remove('fa-times');
icon.classList.add('fa-bars');
}
});
// Tab switching
const tabs = document.querySelectorAll('.preview-tab');
const tabContents = document.querySelectorAll('.tab-content');
@ -1272,6 +1539,17 @@
const playbookName = this.querySelector('.playbook-title').textContent;
previewTitle.textContent = playbookName;
// Reset status
const statusIndicator = document.querySelector('.preview-status');
statusIndicator.innerHTML = '<div class="status-dot status-ready"></div><span>Ready to deploy</span>';
// Switch back to code tab
tabs.forEach(t => t.classList.remove('active'));
tabContents.forEach(tc => tc.classList.remove('active'));
document.querySelector('[data-tab="code"]').classList.add('active');
document.getElementById('code-tab').classList.add('active');
});
});
@ -1318,6 +1596,13 @@
const timeRemainingDiv = document.querySelector('.time-remaining div');
const timeProgressBar = document.querySelector('.time-progress-bar');
// For demo purposes, we'll just set the initial values
timeRemainingDiv.textContent = "Sandbox environment active for 15 more minutes";
timeProgressBar.style.width = "100%";
// In a real implementation, you would use setInterval to update the countdown
// This is left commented out to avoid unnecessary timer in the demo
/*
const countdownInterval = setInterval(function() {
timeLeft -= 1;
const width = (timeLeft / 15) * 100;
@ -1333,11 +1618,8 @@
timeRemainingDiv.textContent = `Sandbox environment active for ${timeLeft} more minutes`;
timeProgressBar.style.width = `${width}%`;
}
}, 60000); // Update every minute (in real implementation)
// For demo purposes, we'll just set the initial values
timeRemainingDiv.textContent = "Sandbox environment active for 15 more minutes";
timeProgressBar.style.width = "100%";
}, 60000); // Update every minute
*/
}, 3000); // Simulate 3 second deployment
});

View File

@ -76,12 +76,261 @@
radial-gradient(circle at 75% 60%, rgba(14, 165, 233, 0.1) 0%, transparent 50%);
}
a {
color: inherit;
text-decoration: none;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 0 1.5rem;
}
/* Navigation Bar */
.navbar {
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: rgba(15, 23, 42, 0.9);
backdrop-filter: var(--glass-effect);
-webkit-backdrop-filter: var(--glass-effect);
z-index: 1000;
border-bottom: 1px solid var(--border);
}
.navbar .container {
display: flex;
justify-content: space-between;
align-items: center;
height: 4rem;
}
.logo {
font-size: 1.5rem;
font-weight: 700;
}
.logo-text {
color: var(--accent);
}
.logo-dot {
color: var(--text-primary);
}
.nav-menu {
display: flex;
gap: 2rem;
}
.nav-link {
font-size: 1rem;
font-weight: 500;
color: var(--text-secondary);
transition: color var(--transition-normal);
position: relative;
}
.nav-link:hover,
.nav-link.active {
color: var(--text-primary);
}
.nav-link::after {
content: '';
position: absolute;
left: 0;
bottom: -0.5rem;
width: 0;
height: 2px;
background-color: var(--accent);
transition: width var(--transition-normal);
}
.nav-link:hover::after,
.nav-link.active::after {
width: 100%;
}
.nav-buttons {
display: flex;
align-items: center;
gap: 1rem;
}
.dashboard-link {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
background-color: rgba(59, 130, 246, 0.1);
color: var(--accent);
border-radius: 9999px;
font-weight: 500;
font-size: 0.9rem;
transition: all var(--transition-normal);
border: 1px solid rgba(59, 130, 246, 0.3);
}
.dashboard-link:hover {
background-color: rgba(59, 130, 246, 0.2);
box-shadow: var(--accent-glow);
}
.live-indicator {
width: 8px;
height: 8px;
background-color: var(--success);
border-radius: 50%;
position: relative;
}
.live-indicator::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 50%;
background-color: var(--success);
animation: pulse 2s infinite;
z-index: -1;
}
.menu-toggle {
display: none;
background: none;
border: none;
color: var(--text-primary);
font-size: 1.25rem;
cursor: pointer;
}
/* Footer */
.footer {
width: 100%;
left: 0;
right: 0;
bottom: 0;
background: var(--secondary-bg);
border-top: 1px solid var(--border);
padding: 2rem 0;
margin-top: auto;
}
.footer-content {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.footer-logo {
font-size: 1.25rem;
font-weight: 700;
}
.footer-links {
display: flex;
gap: 1.5rem;
}
.footer-links a {
color: var(--text-secondary);
transition: color var(--transition-normal);
}
.footer-links a:hover {
color: var(--text-primary);
}
.footer-social {
display: flex;
gap: 1rem;
}
.footer-social a {
color: var(--text-secondary);
font-size: 1.25rem;
transition: all var(--transition-normal);
}
.footer-social a:hover {
color: var(--accent);
transform: translateY(-3px);
}
.footer-bottom {
text-align: center;
color: var(--text-secondary);
font-size: 0.85rem;
}
@keyframes pulse {
0% {
transform: scale(1);
opacity: 0.8;
}
70% {
transform: scale(2);
opacity: 0;
}
100% {
transform: scale(1);
opacity: 0;
}
}
/* Responsive Styles */
@media (max-width: 1024px) {
.nav-menu {
gap: 1.5rem;
}
}
@media (max-width: 768px) {
.navbar .container {
height: 3.5rem;
}
.nav-menu {
position: fixed;
top: 3.5rem;
left: 0;
width: 100%;
height: calc(100vh - 3.5rem);
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2rem;
background-color: var(--primary-bg);
transform: translateX(100%);
transition: transform var(--transition-normal);
z-index: 999;
}
.nav-menu.active {
transform: translateX(0);
}
.menu-toggle {
display: block;
}
.footer-content {
flex-direction: column;
gap: 1.5rem;
}
.footer-links {
flex-wrap: wrap;
justify-content: center;
}
}
/* Dashboard Specific Styles */
.dashboard-container {
padding: 5rem 0 2rem;
@ -105,7 +354,7 @@
font-weight: 600;
}
.live-indicator {
.live-indicator-label {
display: flex;
align-items: center;
font-size: 0.9rem;
@ -743,12 +992,41 @@
</style>
</head>
<body>
<!-- Navigation Bar -->
<nav class="navbar">
<div class="container">
<div class="logo">
<a href="#home">
<span class="logo-text">Argobox</span>
<span class="logo-dot">.com</span>
</a>
</div>
<div class="nav-menu">
<a href="#home" class="nav-link active">Home</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="#contact" class="nav-link">Contact</a>
</div>
<div class="nav-buttons">
<a href="dashboard.html" class="dashboard-link" target="_blank">
<span class="live-indicator"></span>
<span>Live Dashboard</span>
</a>
<button class="menu-toggle" aria-label="Toggle menu">
<i class="fas fa-bars"></i>
</button>
</div>
</div>
</nav>
<div class="dashboard-container">
<div class="container">
<div class="dashboard-header">
<div class="dashboard-title">
<h1>Infrastructure Dashboard</h1>
<div class="live-indicator">
<div class="live-indicator-label">
<span class="live-dot"></span>
<span>Live</span>
</div>
@ -883,7 +1161,6 @@
<circle class="data-point" cx="0" cy="350" r="4" data-value="30%" data-time="00:00" />
<circle class="data-point" cx="150" cy="310" r="4" data-value="38%" data-time="03:45" />
<circle class="data-point" cx="300" cy="250" r="4" data-value="50%" data-time="07:30" />
<circle class="data-point" cx="450" cy="230" r="4" data-value
<circle class="data-point" cx="450" cy="230" r="4" data-value="54%" data-time="11:15" />
<circle class="data-point" cx="600" cy="240" r="4" data-value="52%" data-time="15:00" />
<circle class="data-point" cx="750" cy="160" r="4" data-value="68%" data-time="18:45" />
@ -1106,20 +1383,45 @@
</div>
</div>
</div>
</div>
</div>
<div class="dashboard-footer">
<a href="index.html" class="back-to-site">
<i class="fas fa-arrow-left"></i>
<span>Back to Main Site</span>
</a>
<div class="footer-info">Updated every 60 seconds • Last refresh: <span id="last-refresh">Just now</span></div>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-logo">
<span class="logo-text">Argobox</span>
<span class="logo-dot">.com</span>
</div>
<div class="footer-links">
<a href="index.html#home">Home</a>
<a href="index.html#services">Services</a>
<a href="index.html#lab">Live Lab</a>
<a href="index.html#projects">Projects</a>
<a href="index.html#experience">Experience</a>
<a href="index.html#contact">Contact</a>
</div>
<div class="footer-social">
<a href="https://www.linkedin.com/in/danlaforce" target="_blank"><i class="fab fa-linkedin"></i></a>
<a href="https://github.com/keyargo" target="_blank"><i class="fab fa-github"></i></a>
</div>
</div>
<div class="footer-bottom">
<p>&copy; <span id="current-year"></span> All rights reserved. Inovin LLC</p>
</div>
</div>
</footer>
<script>
// Initialize dashboard functionality
document.addEventListener('DOMContentLoaded', function() {
// Set current year in footer
document.getElementById('current-year').textContent = new Date().getFullYear();
// Set up data point hover tooltips
const dataPoints = document.querySelectorAll('.data-point');
const tooltip = document.getElementById('chart-tooltip');
@ -1251,6 +1553,14 @@
logsContent.insertBefore(logEntry, logsContent.firstChild);
}
// Mobile menu toggle
const menuToggle = document.querySelector('.menu-toggle');
const navMenu = document.querySelector('.nav-menu');
menuToggle.addEventListener('click', function() {
navMenu.classList.toggle('active');
});
// Auto refresh every 60 seconds
setInterval(function() {
simulateRefresh();

View File

@ -3,9 +3,16 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Daniel LaForce | Infrastructure & Systems Engineer</title>
<meta name="description" content="Expert in systems administration, network engineering, and infrastructure solutions. Specializing in virtualization, containerization, and secure cloud migrations.">
<meta name="keywords" content="system administrator, network engineer, infrastructure, virtualization, kubernetes, docker, cloud migration">
<title>Daniel LaForce | Infrastructure & Systems Architect | DevOps Engineer</title>
<meta name="description" content="Expert in systems engineering, infrastructure architecture, DevOps automation, and secure cloud migrations. Specializing in virtualization, containerization, and network security.">
<meta name="keywords" content="infrastructure architect, systems engineer, DevOps automation, network security, virtualization, kubernetes, docker, cloud migration, IT consultant">
<meta name="author" content="Daniel LaForce">
<!-- Open Graph / Social Media Meta Tags -->
<meta property="og:title" content="Daniel LaForce | Infrastructure & Systems Architect">
<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://argobox.com">
<!-- Favicon -->
<link rel="icon" href="images/favicon.ico" type="image/x-icon">
@ -19,15 +26,17 @@
<!-- Google 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=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
</head>
<body>
<!-- Navigation Bar -->
<nav class="navbar">
<div class="container">
<div class="logo">
<a href="#home">
<span class="logo-text">Argobox</span>
<span class="logo-dot">.com</span>
</a>
</div>
<div class="nav-menu">
<a href="#home" class="nav-link active">Home</a>
@ -42,7 +51,7 @@
<span class="live-indicator"></span>
<span>Live Dashboard</span>
</a>
<button class="menu-toggle">
<button class="menu-toggle" aria-label="Toggle menu">
<i class="fas fa-bars"></i>
</button>
</div>
@ -51,37 +60,56 @@
<!-- Hero Section -->
<section id="home" class="hero">
<!-- Background elements -->
<div class="particles-container" id="particles-container"></div>
<div class="floating-icons" id="floating-icons"></div>
<div class="container">
<div class="hero-content">
<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">
<span class="role-wrapper">
<span class="role active" data-role="admin" data-description="Building scalable infrastructure with optimized performance and bulletproof security — from server management to end-user support that keeps businesses running smoothly.">
<span class="highlight">System</span> <span class="highlight">Administrator</span> &amp; IT Expert
</span>
<span class="role" data-role="devops" data-description="Streamlining development workflows with CI/CD pipelines and infrastructure as code — automating deployments and improving reliability across your entire technology stack.">
<span class="highlight">DevOps</span> &amp; <span class="highlight">Automation</span> Engineer
</span>
<span class="role" data-role="architect" data-description="Designing resilient infrastructure and automation solutions — from virtualization and containerization to secure network architecture and cloud migration strategies.">
<span class="highlight">Infrastructure</span> &amp; <span class="highlight">Systems</span> Architect
</span>
</span>
</h1>
<div class="status-indicator">
<p class="hero-description" id="role-description">
Building scalable infrastructure with optimized performance and bulletproof security — from server management to end-user support that keeps businesses running smoothly.
</p>
<div class="inline-terminal">
<div id="terminal-text" class="terminal-text">> Ready for deployment...</div>
</div>
</div>
<div class="dashboard-section">
<div class="status-pill">
<div class="live-indicator"></div>
<span>Lab Status: Online</span>
</div>
<p class="hero-description">
I build resilient infrastructure and automation solutions — from virtualization and containerization to secure network architecture and cloud migration.
</p>
<div class="command-line">
<span class="typing-animation">> Ready for deployment...</span>
</div>
<div class="hero-buttons">
<a href="#contact" class="btn btn-primary">Hire Me</a>
<a href="ansible-sandbox.html" class="btn btn-outline" target="_blank">Explore My Lab</a>
<a href="resume.html" class="btn btn-outline" target="_blank">View Resume</a>
</div>
</div>
<div class="hero-visual">
<div class="tech-dashboard">
<div class="data-stream">
<div class="data-line" style="left: 10%; width: 80%; animation-duration: 3s;"></div>
<div class="data-line" style="left: 25%; width: 60%; animation-duration: 4s;"></div>
<div class="data-line" style="left: 40%; width: 40%; animation-duration: 2.5s;"></div>
<div class="data-line" style="left: 55%; width: 30%; animation-duration: 3.5s;"></div>
<div class="data-line" style="left: 70%; width: 20%; animation-duration: 4.5s;"></div>
<div class="data-line"></div>
<div class="data-line"></div>
<div class="data-line"></div>
<div class="data-line"></div>
<div class="data-line"></div>
</div>
<div class="terminal">
<div class="monitoring-terminal">
<div class="terminal-line">> Monitoring infrastructure...</div>
<div class="terminal-line success">> CPU load: Normal</div>
<div class="terminal-line success">> RAM usage: 42%</div>
@ -92,6 +120,95 @@
</div>
</div>
</div>
<div class="cta-buttons">
<a href="#contact" class="btn btn-primary">
<span class="btn-text">Hire Me</span>
<span class="btn-icon"><i class="fas fa-arrow-right"></i></span>
</a>
<a href="ansible-sandbox.html" class="btn btn-outline btn-featured" target="_blank">
<span class="pulse-ring"></span>
<span class="btn-text">Explore My Lab</span>
<span class="btn-icon"><i class="fas fa-server"></i></span>
</a>
<a href="resume.html" class="btn btn-outline" target="_blank">
<span class="btn-text">View Resume</span>
<span class="btn-icon"><i class="fas fa-file-alt"></i></span>
</a>
</div>
</div>
</div>
</section>
<!-- Solutions Showcase -->
<section class="solutions-showcase">
<div class="container">
<div class="solutions-header">
<h3 class="solutions-title">Solving Complex IT Challenges</h3>
</div>
<div class="solutions-carousel">
<div class="solution-slide active" id="solution-1">
<div class="solution-icon"><i class="fas fa-sync"></i></div>
<h4>Seamless Microsoft 365 Migrations</h4>
<p>Executed with 60% less downtime than industry average</p>
</div>
<div class="solution-slide" id="solution-2">
<div class="solution-icon"><i class="fas fa-shield-alt"></i></div>
<h4>Secure Remote Work Infrastructure</h4>
<p>Zero-trust architecture implementation for distributed teams</p>
</div>
<div class="solution-slide" id="solution-3">
<div class="solution-icon"><i class="fas fa-tachometer-alt"></i></div>
<h4>Automated DevOps Pipelines</h4>
<p>Reducing deployment times by up to 85% with CI/CD automation</p>
</div>
<div class="solution-slide" id="solution-4">
<div class="solution-icon"><i class="fas fa-cubes"></i></div>
<h4>Containerized Application Deployment</h4>
<p>Simplified scaling and maintenance with Kubernetes orchestration</p>
</div>
<div class="solution-slide" id="solution-5">
<div class="solution-icon"><i class="fas fa-users-cog"></i></div>
<h4>Enterprise-Level System Administration</h4>
<p>99.98% uptime across critical infrastructure components</p>
</div>
<div class="solution-slide" id="solution-6">
<div class="solution-icon"><i class="fas fa-network-wired"></i></div>
<h4>Network Infrastructure Optimization</h4>
<p>40% reduced latency and improved throughput for business applications</p>
</div>
<div class="solution-slide" id="solution-7">
<div class="solution-icon"><i class="fas fa-headset"></i></div>
<h4>Responsive Technical Support</h4>
<p>Average ticket resolution time reduced by 68% through process optimization</p>
</div>
<div class="solution-slide" id="solution-8">
<div class="solution-icon"><i class="fas fa-server"></i></div>
<h4>Server Consolidation & Virtualization</h4>
<p>35% cost reduction while improving redundancy and disaster recovery</p>
</div>
</div>
<div class="slider-controls">
<button class="slider-dot active" data-slide="solution-1" aria-label="Solution 1"></button>
<button class="slider-dot" data-slide="solution-2" aria-label="Solution 2"></button>
<button class="slider-dot" data-slide="solution-3" aria-label="Solution 3"></button>
<button class="slider-dot" data-slide="solution-4" aria-label="Solution 4"></button>
<button class="slider-dot" data-slide="solution-5" aria-label="Solution 5"></button>
<button class="slider-dot" data-slide="solution-6" aria-label="Solution 6"></button>
<button class="slider-dot" data-slide="solution-7" aria-label="Solution 7"></button>
<button class="slider-dot" data-slide="solution-8" aria-label="Solution 8"></button>
</div>
</div>
</section>
@ -407,7 +524,7 @@
</div>
</section>
<!-- Experience Section (Optional) -->
<!-- Experience Section -->
<section id="experience" class="experience">
<div class="container">
<div class="section-header">
@ -532,9 +649,9 @@
</div>
<div class="footer-social">
<a href="https://github.com/keyargo" target="_blank"><i class="fab fa-github"></i></a>
<a href="https://www.linkedin.com/in/danlaforce" target="_blank"><i class="fab fa-linkedin"></i></a>
<a href="mailto:daniel.laforce@argobox.com"><i class="fas fa-envelope"></i></a>
<a href="https://github.com/keyargo" target="_blank" aria-label="GitHub"><i class="fab fa-github"></i></a>
<a href="https://www.linkedin.com/in/danlaforce" target="_blank" aria-label="LinkedIn"><i class="fab fa-linkedin"></i></a>
<a href="mailto:daniel.laforce@argobox.com" aria-label="Email"><i class="fas fa-envelope"></i></a>
</div>
</div>

View File

@ -24,10 +24,19 @@
<style>
/* Resume-specific styles */
body {
margin: 0;
padding: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
}
.resume-container {
max-width: 1000px;
margin: 6rem auto 4rem;
padding: 0 1.5rem;
flex: 1;
}
.resume-header {
@ -196,6 +205,17 @@
margin-bottom: 0.5rem;
}
.resume-education-grade {
color: var(--text-secondary);
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.resume-education-skills {
margin-top: 0.5rem;
color: var(--text-secondary);
}
.resume-projects {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
@ -250,6 +270,17 @@
margin-top: 3rem;
}
.footer {
width: 100%;
left: 0;
right: 0;
bottom: 0;
background: var(--dark-bg);
border-top: 1px solid var(--border);
padding: 2rem 0;
margin-top: auto;
}
@media (max-width: 768px) {
.resume-skills, .resume-projects {
grid-template-columns: 1fr;
@ -260,15 +291,14 @@
<body>
<!-- Navigation -->
<nav class="navbar">
<div class="container nav-container">
<div class="container">
<div class="logo">
<a href="index.html">
<span class="logo-text">Argobox</span>
<span class="logo-dot">.com</span>
</a>
</div>
<div class="nav-links">
<div class="nav-menu">
<a href="index.html#home" class="nav-link">Home</a>
<a href="index.html#services" class="nav-link">Services</a>
<a href="index.html#lab" class="nav-link">Live Lab</a>
@ -276,13 +306,12 @@
<a href="index.html#experience" class="nav-link">Experience</a>
<a href="index.html#contact" class="nav-link">Contact</a>
</div>
<div class="nav-actions">
<a href="dashboard.html" class="dashboard-btn" target="_blank">
<span class="live-dot"></span>
<div class="nav-buttons">
<a href="dashboard.html" class="dashboard-link" target="_blank">
<span class="live-indicator"></span>
<span>Live Dashboard</span>
</a>
<button class="mobile-menu-btn">
<button class="menu-toggle" aria-label="Toggle menu">
<i class="fas fa-bars"></i>
</button>
</div>
@ -308,10 +337,6 @@
<i class="fas fa-envelope"></i>
<a href="mailto:daniel.laforce@argobox.com">daniel.laforce@argobox.com</a>
</div>
<div class="resume-contact-item">
<i class="fas fa-envelope-open"></i>
<a href="mailto:daniel.laforce@gmail.com">daniel.laforce@gmail.com</a>
</div>
<div class="resume-contact-item">
<i class="fab fa-linkedin"></i>
<a href="https://www.linkedin.com/in/danlaforce" target="_blank">linkedin.com/in/danlaforce</a>
@ -320,10 +345,6 @@
<i class="fab fa-github"></i>
<a href="https://github.com/keyargo" target="_blank">github.com/keyargo</a>
</div>
<div class="resume-contact-item">
<i class="fas fa-globe"></i>
<a href="https://www.argobox.com" target="_blank">argobox.com</a>
</div>
</div>
</div>
@ -621,57 +642,67 @@
<div class="resume-job-achievements">
<div class="resume-job-achievement">
<i class="fas fa-award"></i>
<span>Sigma Alpha Phi (NSLS)</span>
<span>Activities and societies: Sigma Alpha Pi Honors Society (The National Society of Leadership and Success)</span>
</div>
<div class="resume-job-achievement">
<i class="fas fa-award"></i>
<span>Academic Excellence Award</span>
</div>
<div class="resume-education-skills">
<strong>Skills:</strong> Python (Programming Language) · Project Management · Machine Learning · Team Leadership
</div>
</div>
<div class="resume-education">
<h3 class="resume-education-title">Cyber Operations Training</h3>
<h3 class="resume-education-title">Cyber Ops</h3>
<div class="resume-education-institution">Cisco Networking Academy</div>
<div class="resume-education-period">2018</div>
<div class="resume-education-skills">
<strong>Skills:</strong> Networking · Cyber-security · Cisco Technologies
</div>
</div>
<div class="resume-education">
<h3 class="resume-education-title">Computer Science and Innovation</h3>
<div class="resume-education-institution">University of Colorado Colorado Springs (UCCS)</div>
<div class="resume-education-period">January 2017 - December 2017</div>
</div>
<div class="resume-education">
<h3 class="resume-education-title">Associate's Degree, General Studies</h3>
<div class="resume-education-institution">Front Range Community College</div>
<div class="resume-education-period">January 2016 - May 2018</div>
<div class="resume-job-achievements">
<div class="resume-job-achievement">
<i class="fas fa-award"></i>
<span>Magna Cum Laude</span>
</div>
<div class="resume-job-achievement">
<i class="fas fa-award"></i>
<span>Phi Theta Kappa</span>
</div>
<div class="resume-education-grade">Grade: 4.0</div>
<div class="resume-education-skills">
<strong>Skills:</strong> C++ · Team Leadership
</div>
</div>
<div class="resume-education">
<h3 class="resume-education-title">Associate's Degree, General Studies</h3>
<div class="resume-education-institution">Pikes Peak Community College</div>
<h3 class="resume-education-title">Associate's degree, General Studies</h3>
<div class="resume-education-institution">Pikes Peak State College</div>
<div class="resume-education-period">2015 - 2018</div>
<div class="resume-education-grade">Grade: 4.0</div>
<div class="resume-job-achievements">
<div class="resume-job-achievement">
<i class="fas fa-award"></i>
<span>Magna Cum Laude</span>
<span>Activities and societies: Phi Theta Kappa Honor Society</span>
</div>
</div>
<div class="resume-education-skills">
<strong>Skills:</strong> Linux · Virtual Server · C++ · System Administration · Wireless
</div>
</div>
<div class="resume-education">
<h3 class="resume-education-title">Associate's Degree, Computer Wide Area Networks</h3>
<div class="resume-education-institution">Front Range Community College</div>
<div class="resume-education-period">2014 - 2016</div>
<div class="resume-education-grade">Grade: 3.87</div>
<div class="resume-job-achievements">
<div class="resume-job-achievement">
<i class="fas fa-award"></i>
<span>Activities and societies: Phi Theta Kappa Honor Society</span>
</div>
<div class="resume-job-achievement">
<i class="fas fa-award"></i>
<span>President's List (Spring 2014, Spring 2015)</span>
<span>Magna Cum Laude honors</span>
</div>
</div>
<div class="resume-education-skills">
<strong>Skills:</strong> Virtual Server · C++ · Networking · Wireless
</div>
</div>
</div>

576
script.js
View File

@ -1,53 +1,66 @@
/**
* Main JavaScript file for argobox.com
* Handles navigation, animations, and interactivity
* Handles animations, interactions, and dynamic content
*/
document.addEventListener('DOMContentLoaded', function() {
// Update current year in footer
const yearElement = document.getElementById('current-year');
if (yearElement) {
yearElement.textContent = new Date().getFullYear();
// Initialize all website functionality
initNavigation();
initParticlesAndIcons();
initRoleRotation();
initTerminalTyping();
initSolutionsCarousel();
initScrollReveal();
updateMetrics();
updateYear();
// Initialize form handling
const contactForm = document.getElementById('contact-form');
if (contactForm) {
initFormHandling(contactForm);
}
});
/**
* Set up navigation functionality - mobile menu and scroll spy
*/
function initNavigation() {
// Mobile menu toggle
const menuToggle = document.querySelector('.mobile-menu-btn');
const navLinks = document.querySelector('.nav-links');
const menuToggle = document.querySelector('.menu-toggle');
const navMenu = document.querySelector('.nav-menu');
if (menuToggle && navLinks) {
if (menuToggle && navMenu) {
menuToggle.addEventListener('click', function() {
navLinks.classList.toggle('active');
navMenu.classList.toggle('active');
menuToggle.setAttribute('aria-expanded',
menuToggle.getAttribute('aria-expanded') === 'true' ? 'false' : 'true');
});
}
// Set active navigation links based on scroll position
const sections = document.querySelectorAll('section');
const navItems = document.querySelectorAll('.nav-link');
// Navigation scroll spy
const sections = document.querySelectorAll('section[id]');
const navLinks = document.querySelectorAll('.nav-link');
function updateActiveLink() {
let currentSection = '';
function updateActiveNavLink() {
let scrollPosition = window.scrollY + 100;
sections.forEach(section => {
const sectionTop = section.offsetTop - 100;
const sectionTop = section.offsetTop;
const sectionHeight = section.offsetHeight;
const sectionId = section.getAttribute('id');
if (window.scrollY >= sectionTop && window.scrollY < sectionTop + sectionHeight) {
currentSection = section.getAttribute('id');
}
});
navItems.forEach(link => {
if (scrollPosition >= sectionTop && scrollPosition < sectionTop + sectionHeight) {
navLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('href') === `#${currentSection}`) {
if (link.getAttribute('href') === `#${sectionId}`) {
link.classList.add('active');
}
});
}
});
}
window.addEventListener('scroll', updateActiveLink);
updateActiveLink();
// Handle navbar style change on scroll
// Navbar style change on scroll
const navbar = document.querySelector('.navbar');
function updateNavbarStyle() {
@ -58,41 +71,352 @@ document.addEventListener('DOMContentLoaded', function() {
}
}
window.addEventListener('scroll', updateNavbarStyle);
window.addEventListener('scroll', () => {
updateActiveNavLink();
updateNavbarStyle();
});
// Form submission handling
const contactForm = document.getElementById('contact-form');
// Initial call to set correct states
updateActiveNavLink();
updateNavbarStyle();
}
if (contactForm) {
contactForm.addEventListener('submit', async function(e) {
/**
* Create background particles and floating tech icons
*/
function initParticlesAndIcons() {
createBackgroundParticles();
createFloatingIcons();
}
/**
* Create animated background particles
*/
function createBackgroundParticles() {
const particlesContainer = document.getElementById('particles-container');
if (!particlesContainer) return;
particlesContainer.innerHTML = '';
for (let i = 0; i < 40; i++) {
const particle = document.createElement('div');
particle.classList.add('particle');
// Random size, opacity, and position
const size = Math.random() * 4 + 1;
const opacity = Math.random() * 0.3 + 0.1;
particle.style.width = `${size}px`;
particle.style.height = `${size}px`;
particle.style.opacity = opacity;
// Position randomly with some clustering toward top areas
const xPos = Math.random() * 100;
const yPos = Math.random() * 100;
particle.style.left = `${xPos}%`;
particle.style.top = `${yPos}%`;
// Animation properties
particle.style.animationDuration = `${Math.random() * 20 + 10}s`;
particle.style.animationDelay = `${Math.random() * 5}s`;
// Add particle animation
particle.style.animation = `particle-float ${Math.random() * 20 + 10}s linear infinite`;
particlesContainer.appendChild(particle);
}
}
/**
* Create floating tech icons in the background
*/
function createFloatingIcons() {
const iconContainer = document.getElementById('floating-icons');
if (!iconContainer) return;
iconContainer.innerHTML = '';
// Tech-related unicode symbols and fontawesome classes
const icons = [
'⚙️', '💻', '🔒', '🔌', '🌐', '☁️', '📊',
'fa-server', 'fa-network-wired', 'fa-database',
'fa-code-branch', 'fa-cloud', 'fa-shield-alt'
];
for (let i = 0; i < 12; i++) {
const icon = document.createElement('div');
icon.classList.add('floating-icon');
const iconType = icons[Math.floor(Math.random() * icons.length)];
// Handle both unicode and font awesome
if (iconType.startsWith('fa-')) {
const faIcon = document.createElement('i');
faIcon.className = `fas ${iconType}`;
icon.appendChild(faIcon);
} else {
icon.textContent = iconType;
}
// Random size and position
const size = Math.random() * 24 + 16;
icon.style.fontSize = `${size}px`;
// Position
icon.style.left = `${Math.random() * 100}%`;
icon.style.bottom = `-50px`;
// Animation
icon.style.animationDuration = `${Math.random() * 30 + 20}s`;
icon.style.animationDelay = `${Math.random() * 10}s`;
iconContainer.appendChild(icon);
}
}
/**
* Initialize role rotation in the hero section
*/
function initRoleRotation() {
const roles = document.querySelectorAll('.role');
const descriptionElement = document.getElementById('role-description');
if (roles.length === 0 || !descriptionElement) return;
let currentRole = 0;
function rotateRoles() {
// Hide current role
roles[currentRole].classList.remove('active');
// Move to next role
currentRole = (currentRole + 1) % roles.length;
// Show new role
roles[currentRole].classList.add('active');
// Update description text
const newDescription = roles[currentRole].getAttribute('data-description');
if (newDescription) {
descriptionElement.textContent = newDescription;
// Animate the description change
descriptionElement.style.opacity = '0';
descriptionElement.style.transform = 'translateY(10px)';
setTimeout(() => {
descriptionElement.style.opacity = '1';
descriptionElement.style.transform = 'translateY(0)';
}, 50);
}
}
// Set initial role to active
roles[0].classList.add('active');
// Initialize with the first description
const initialDescription = roles[0].getAttribute('data-description');
if (initialDescription && descriptionElement) {
descriptionElement.textContent = initialDescription;
}
// Start rotation with delay
setInterval(rotateRoles, 5000);
}
/**
* Initialize terminal typing animation in the hero section
*/
function initTerminalTyping() {
const terminalText = document.getElementById('terminal-text');
if (!terminalText) return;
const terminalMessages = [
"> Ready for deployment...",
"> Reducing operational costs by 30%",
"> Improving system reliability to 99.9%",
"> Accelerating digital transformation",
"> Enhancing security compliance",
"> Streamlining IT workflows",
"> Optimizing infrastructure performance",
"> Implementing best practices",
"> Supporting business objectives"
];
let currentMessage = 0;
function typeMessage(message, index = 0) {
if (index < message.length) {
terminalText.textContent = message.substring(0, index + 1);
setTimeout(() => typeMessage(message, index + 1), 50 + Math.random() * 50);
} else {
// Wait before clearing and typing next message
setTimeout(clearAndTypeNext, 3000);
}
}
function clearAndTypeNext() {
// Clear the current text with a backspace effect
const currentText = terminalText.textContent;
function backspace(length = currentText.length) {
if (length > 0) {
terminalText.textContent = currentText.substring(0, length - 1);
setTimeout(() => backspace(length - 1), 20);
} else {
// Move to next message
currentMessage = (currentMessage + 1) % terminalMessages.length;
setTimeout(() => typeMessage(terminalMessages[currentMessage]), 500);
}
}
backspace();
}
// Start the typing animation with the first message
typeMessage(terminalMessages[0]);
}
/**
* Initialize the solutions carousel
*/
function initSolutionsCarousel() {
const slides = document.querySelectorAll('.solution-slide');
const dots = document.querySelectorAll('.slider-dot');
if (slides.length === 0 || dots.length === 0) return;
let currentSlide = 0;
let slideInterval;
function showSlide(index) {
// Hide all slides
slides.forEach(slide => slide.classList.remove('active'));
dots.forEach(dot => dot.classList.remove('active'));
// Show selected slide
slides[index].classList.add('active');
dots[index].classList.add('active');
currentSlide = index;
}
function nextSlide() {
const next = (currentSlide + 1) % slides.length;
showSlide(next);
}
// Add click events to dots
dots.forEach((dot, index) => {
dot.addEventListener('click', () => {
clearInterval(slideInterval);
showSlide(index);
// Restart automatic rotation
slideInterval = setInterval(nextSlide, 5000);
});
});
// Start automatic rotation
slideInterval = setInterval(nextSlide, 5000);
// Show first slide initially
showSlide(0);
}
/**
* Add scroll reveal animations to elements
*/
function initScrollReveal() {
const revealElements = document.querySelectorAll('.section-header, .service-card, .project-card, .lab-card, .timeline-item, .contact-item');
revealElements.forEach(element => {
element.classList.add('reveal');
});
function checkReveal() {
revealElements.forEach(element => {
const elementTop = element.getBoundingClientRect().top;
const elementVisible = 150;
if (elementTop < window.innerHeight - elementVisible) {
element.classList.add('active');
}
});
}
// Initial check
checkReveal();
// Check on scroll
window.addEventListener('scroll', checkReveal);
}
/**
* Update metrics values periodically to simulate live data
*/
function updateMetrics() {
const metrics = {
'CPU Usage': { min: 30, max: 60, element: null },
'Memory': { min: 45, max: 70, element: null },
'Storage': { min: 60, max: 75, element: null },
'Network': { min: 15, max: 40, element: null }
};
// Get all metric elements
document.querySelectorAll('.metric').forEach(metric => {
const nameElement = metric.querySelector('.metric-name');
if (nameElement && metrics[nameElement.textContent]) {
metrics[nameElement.textContent].element = metric;
}
});
function updateMetricValues() {
Object.keys(metrics).forEach(key => {
const metric = metrics[key];
if (!metric.element) return;
const valueEl = metric.element.querySelector('.metric-value');
const progressEl = metric.element.querySelector('.metric-progress');
if (valueEl && progressEl) {
const newValue = Math.floor(Math.random() * (metric.max - metric.min)) + metric.min;
valueEl.textContent = `${newValue}%`;
progressEl.style.width = `${newValue}%`;
}
});
}
// Update metrics every 5 seconds
setInterval(updateMetricValues, 5000);
}
/**
* Initialize contact form handling
*/
function initFormHandling(form) {
form.addEventListener('submit', async function(e) {
e.preventDefault();
const submitButton = contactForm.querySelector('button[type="submit"]');
const submitButton = form.querySelector('button[type="submit"]');
const originalButtonText = submitButton.innerHTML;
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
submitButton.disabled = true;
try {
const formData = new FormData(contactForm);
const formValues = Object.fromEntries(formData.entries());
// Simulated form submission - in production replace with actual API call
// const formData = new FormData(form);
// const formValues = Object.fromEntries(formData.entries());
const response = await fetch('/contact', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formValues)
});
// Simulated API response delay
await new Promise(resolve => setTimeout(resolve, 1500));
const result = await response.json();
if (response.ok) {
// Success message
alert('Thank you for your message! I will get back to you soon.');
contactForm.reset();
} else {
throw new Error(result.error || 'Failed to send message');
}
form.reset();
} catch (error) {
console.error('Error:', error);
alert('Failed to send message. Please try again or contact me directly via email.');
@ -103,141 +427,33 @@ document.addEventListener('DOMContentLoaded', function() {
});
}
// Initialize and animate the hero terminal
const typingElement = document.querySelector('.typing-effect');
if (typingElement) {
// The animation is handled by CSS, nothing to do here
console.log('Terminal typing animation initialized');
}
// Create animated data streams in the dashboard
function createDataStreamAnimation() {
const dataStreamContainer = document.querySelector('.data-stream');
if (!dataStreamContainer) {
console.log('Data stream container not found');
return;
}
// Clear existing lines
dataStreamContainer.innerHTML = '';
// Create new random lines
for (let i = 0; i < 10; i++) {
const line = document.createElement('div');
line.classList.add('data-line');
// Random positioning and animation
const left = Math.random() * 90 + 5; // 5-95%
const width = Math.random() * 40 + 10; // 10-50%
const duration = Math.random() * 3 + 2; // 2-5s duration
const delay = Math.random() * 2; // 0-2s delay
line.style.cssText = `
left: ${left}%;
width: ${width}%;
animation: datastream ${duration}s linear infinite;
animation-delay: -${delay}s;
opacity: ${Math.random() * 0.3 + 0.2};
`;
dataStreamContainer.appendChild(line);
/**
* Update copyright year in the footer
*/
function updateYear() {
const yearElement = document.getElementById('current-year');
if (yearElement) {
yearElement.textContent = new Date().getFullYear();
}
}
// Initialize the data stream animation immediately
createDataStreamAnimation();
/**
* Utility function to add particle float animation
*/
document.addEventListener('DOMContentLoaded', function() {
// Initialize all website functionality
initNavigation();
initParticlesAndIcons();
initRoleRotation(); // Updated function
initTerminalTyping(); // Updated function
initSolutionsCarousel(); // Updated function
initScrollReveal();
updateMetrics();
updateYear();
// Refresh data streams every 8 seconds
setInterval(createDataStreamAnimation, 8000);
// Update terminal output with random status messages
function updateTerminalOutput() {
const terminalOutput = document.querySelector('.terminal-output');
if (!terminalOutput) return;
const statusMessages = [
{ text: 'All systems operational', type: '' },
{ text: 'Backup completed successfully', type: 'terminal-success' },
{ text: 'Security scan in progress', type: 'terminal-info' },
{ text: 'New updates available', type: 'terminal-warning' },
{ text: 'Optimizing database performance', type: 'terminal-info' }
];
// Randomly update one of the lines
const lineIndex = Math.floor(Math.random() * 2) + 4; // Only update the last few lines
const lineToUpdate = terminalOutput.children[lineIndex];
if (lineToUpdate) {
const randomMessage = statusMessages[Math.floor(Math.random() * statusMessages.length)];
lineToUpdate.textContent = `> ${randomMessage.text}`;
lineToUpdate.className = 'terminal-line';
if (randomMessage.type) {
lineToUpdate.classList.add(randomMessage.type);
}
}
}
// Periodically update the terminal with new messages
setInterval(updateTerminalOutput, 5000);
// Simulated live metrics - randomly update values periodically
function updateMetrics() {
function updateMetricIfExists(selector, minValue, maxValue) {
const valueElement = document.querySelector(selector + ' .metric-value') ||
document.querySelector(selector + ' .metric-header .metric-value');
const barElement = document.querySelector(selector + ' .metric-progress');
if (valueElement && barElement) {
const newValue = Math.floor(Math.random() * (maxValue - minValue)) + minValue;
valueElement.textContent = `${newValue}%`;
barElement.style.width = `${newValue}%`;
return true;
}
return false;
}
// Try different selectors to find the metrics
// First attempt with nth-child
let found = updateMetricIfExists('.metric:nth-child(1)', 20, 50);
if (!found) {
// Alternative approach - try by unique class or attribute
updateMetricIfExists('[data-metric="cpu"]', 20, 50);
}
updateMetricIfExists('.metric:nth-child(2)', 45, 65) ||
updateMetricIfExists('[data-metric="memory"]', 45, 65);
updateMetricIfExists('.metric:nth-child(3)', 60, 65) ||
updateMetricIfExists('[data-metric="storage"]', 60, 65);
updateMetricIfExists('.metric:nth-child(4)', 15, 45) ||
updateMetricIfExists('[data-metric="network"]', 15, 45);
}
// Update metrics every 5 seconds
setInterval(updateMetrics, 5000);
// Trigger an initial metrics update
setTimeout(updateMetrics, 500);
// Debug info - help determine if there are any issues
console.log('Script loaded successfully');
console.log('Sections found:', sections.length);
console.log('Nav links found:', navItems.length);
// Check if dashboard elements exist
console.log('Data stream container exists:',
!!document.querySelector('.data-stream') ||
!!document.querySelector('.tech-dashboard .data-stream'));
console.log('Metrics containers exist:',
!!document.querySelector('.metric'));
// Add some diagnostic info in case we're having issues
if (!document.querySelector('.data-stream') &&
!document.querySelector('.tech-dashboard .data-stream')) {
console.warn('Data stream container not found - visualizations may not appear');
// Initialize form handling
const contactForm = document.getElementById('contact-form');
if (contactForm) {
initFormHandling(contactForm);
}
});

1256
styles.css

File diff suppressed because it is too large Load Diff