Add contact form with Cloudflare Functions
This commit is contained in:
parent
6436562a66
commit
11adc676f6
|
@ -0,0 +1,49 @@
|
|||
export async function onRequestPost(context) {
|
||||
try {
|
||||
const { name, email, subject, message } = await context.request.json();
|
||||
|
||||
// Validate inputs
|
||||
if (!name || !email || !subject || !message) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'All fields are required' }),
|
||||
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
}
|
||||
|
||||
// Send email using Resend
|
||||
const response = await fetch('https://api.resend.com/emails', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${context.env.RESEND_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
from: 'contact@argobox.com',
|
||||
to: 'daniel.laforce@gmail.com',
|
||||
subject: `Contact Form: ${subject}`,
|
||||
html: `
|
||||
<h3>New Contact Form Submission</h3>
|
||||
<p><strong>Name:</strong> ${name}</p>
|
||||
<p><strong>Email:</strong> ${email}</p>
|
||||
<p><strong>Subject:</strong> ${subject}</p>
|
||||
<h4>Message:</h4>
|
||||
<p>${message}</p>
|
||||
`
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to send email');
|
||||
}
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({ message: 'Message sent successfully!' }),
|
||||
{ status: 200, headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
} catch (error) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Failed to send message' }),
|
||||
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
}
|
||||
}
|
61
index.html
61
index.html
|
@ -69,27 +69,27 @@
|
|||
<div class="hero-buttons">
|
||||
<a href="#contact" class="btn btn-primary">Hire Me</a>
|
||||
<a href="#lab" class="btn btn-outline">Explore My Lab</a>
|
||||
<a href="resume.pdf" class="btn btn-outline" target="_blank">View Resume</a>
|
||||
<a href="resume.html" class="btn btn-outline" target="_blank">View Resume</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-visual">
|
||||
<div class="data-stream">
|
||||
<div class="data-line" style="left: 10%; width: 80%; animation-duration: 3s;"></div>
|
||||
<div class="data-line" style="left: 15%; width: 60%; animation-duration: 4s;"></div>
|
||||
<div class="data-line" style="left: 25%; width: 30%; animation-duration: 2.5s;"></div>
|
||||
<div class="data-line" style="left: 40%; width: 50%; animation-duration: 3.5s;"></div>
|
||||
<div class="data-line" style="left: 55%; width: 35%; animation-duration: 4.5s;"></div>
|
||||
<div class="data-line" style="left: 70%; width: 25%; animation-duration: 2s;"></div>
|
||||
<div class="data-line" style="left: 85%; width: 10%; animation-duration: 3.8s;"></div>
|
||||
</div>
|
||||
<div class="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>
|
||||
<div class="terminal-line success"> > Network: Stable </div>
|
||||
<div class="terminal-line info"> > Containers: 16 running </div>
|
||||
<div class="terminal-line warning"> > Backing up critical data... </div>
|
||||
<div class="terminal-line"> > Status: All systems operational </div>
|
||||
<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>
|
||||
<div class="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>
|
||||
<div class="terminal-line success">> Network: Stable</div>
|
||||
<div class="terminal-line info">> Containers: 16 running</div>
|
||||
<div class="terminal-line warning">> Backing up critical data...</div>
|
||||
<div class="terminal-line">> Status: All systems operational</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -461,24 +461,24 @@
|
|||
<div class="contact-icon">
|
||||
<i class="fas fa-envelope"></i>
|
||||
</div>
|
||||
<h3 class="contact-item-title">Email</h3>
|
||||
<p><a href="mailto:contact@argobox.com">contact@argobox.com</a></p>
|
||||
<h3 class="contact-title">Email</h3>
|
||||
<p><a href="mailto:daniel.laforce@argobox.com">daniel.laforce@argobox.com</a></p>
|
||||
</div>
|
||||
|
||||
<div class="contact-item">
|
||||
<div class="contact-icon">
|
||||
<i class="fab fa-linkedin"></i>
|
||||
</div>
|
||||
<h3 class="contact-item-title">LinkedIn</h3>
|
||||
<p><a href="https://linkedin.com/in/yourprofile" target="_blank">Connect on LinkedIn</a></p>
|
||||
<h3 class="contact-title">LinkedIn</h3>
|
||||
<p><a href="https://www.linkedin.com/in/danlaforce" target="_blank">linkedin.com/in/danlaforce</a></p>
|
||||
</div>
|
||||
|
||||
<div class="contact-item">
|
||||
<div class="contact-icon">
|
||||
<i class="fab fa-github"></i>
|
||||
</div>
|
||||
<h3 class="contact-item-title">GitHub</h3>
|
||||
<p><a href="https://github.com/yourusername" target="_blank">View My Projects</a></p>
|
||||
<h3 class="contact-title">GitHub</h3>
|
||||
<p><a href="https://github.com/keyargo" target="_blank">github.com/keyargo</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -504,7 +504,10 @@
|
|||
<textarea id="message" name="message" rows="5" required></textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Send Message</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-paper-plane btn-icon"></i>
|
||||
Send Message
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -525,18 +528,18 @@
|
|||
<a href="#services">Services</a>
|
||||
<a href="#lab">Live Lab</a>
|
||||
<a href="#projects">Projects</a>
|
||||
<a href="#experience">Experience</a>
|
||||
<a href="#contact">Contact</a>
|
||||
</div>
|
||||
|
||||
<div class="footer-social">
|
||||
<a href="https://linkedin.com/in/yourprofile" target="_blank"><i class="fab fa-linkedin"></i></a>
|
||||
<a href="https://github.com/yourusername" target="_blank"><i class="fab fa-github"></i></a>
|
||||
<a href="https://github.com/keyargo" target="_blank"><i class="fab fa-github"></i></a>
|
||||
<a href="https://www.linkedin.com/in/danllaforce" target="_blank"><i class="fab fa-linkedin"></i></a>
|
||||
<a href="mailto:daniel.laforce@argobox.com"><i class="fas fa-envelope"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<p>© <span id="current-year">2025</span> Argobox.com. All rights reserved.</p>
|
||||
<p>© <span id="current-year"></span> All rights reserved. Inovin LLC</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "argobox-portfolio",
|
||||
"version": "1.0.0",
|
||||
"description": "Portfolio website with contact form functionality",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"dev": "nodemon server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"nodemailer": "^6.9.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.0.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,710 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Daniel LaForce | Resume</title>
|
||||
|
||||
<!-- SEO Meta Tags -->
|
||||
<meta name="description" content="Professional resume of Daniel LaForce - Systems & Infrastructure Engineer specializing in virtualization, containerization, and secure network architecture.">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%22256%22 height=%22256%22 viewBox=%220 0 100 100%22><rect width=%22100%22 height=%22100%22 rx=%2220%22 fill=%22%230f172a%22></rect><path fill=%22%233b82f6%22 d=%22M30 40L50 20L70 40L50 60L30 40Z%22></path><path fill=%22%233b82f6%22 d=%22M50 60L70 40L70 70L50 90L30 70L30 40L50 60Z%22 fill-opacity=%220.6%22></path></svg>">
|
||||
|
||||
<!-- 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&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- FontAwesome -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
|
||||
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<style>
|
||||
/* Resume-specific styles */
|
||||
.resume-container {
|
||||
max-width: 1000px;
|
||||
margin: 6rem auto 4rem;
|
||||
padding: 0 1.5rem;
|
||||
}
|
||||
|
||||
.resume-header {
|
||||
text-align: center;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.resume-name {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.resume-title {
|
||||
font-size: 1.5rem;
|
||||
color: var(--accent);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.resume-contact {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.resume-contact-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.resume-contact-item i {
|
||||
margin-right: 0.5rem;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.resume-section {
|
||||
margin-bottom: 2.5rem;
|
||||
background-color: var(--card-bg);
|
||||
border-radius: 1rem;
|
||||
padding: 2rem;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.resume-section-title {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
color: var(--accent);
|
||||
position: relative;
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.resume-section-title::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 50px;
|
||||
height: 3px;
|
||||
background: var(--accent-gradient);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.resume-job {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.resume-job:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.resume-job-header {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.resume-job-title {
|
||||
font-size: 1.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.resume-job-company {
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.resume-job-period {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.resume-job-description {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.resume-job-achievements {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.resume-job-achievement {
|
||||
display: flex;
|
||||
margin-bottom: 0.75rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.resume-job-achievement i {
|
||||
color: var(--accent);
|
||||
margin-right: 0.75rem;
|
||||
margin-top: 0.25rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.resume-skills {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.resume-skill-category {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.resume-skill-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.resume-skill-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.resume-skill {
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
border: 1px solid rgba(59, 130, 246, 0.3);
|
||||
color: var(--accent);
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.resume-education {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.resume-education-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.resume-education-institution {
|
||||
color: var(--accent);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.resume-education-period {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.resume-projects {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.resume-project {
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.resume-project-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.resume-project-tech {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.resume-project-tech-item {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-secondary);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
padding: 0.15rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.resume-awards {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.resume-award {
|
||||
display: flex;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.resume-award i {
|
||||
color: var(--accent);
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
|
||||
.resume-download {
|
||||
text-align: center;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.resume-skills, .resume-projects {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar">
|
||||
<div class="container nav-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">
|
||||
<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>
|
||||
<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-actions">
|
||||
<a href="https://dashboard.argobox.com" class="dashboard-btn" target="_blank">
|
||||
<span class="live-dot"></span>
|
||||
<span>Live Dashboard</span>
|
||||
</a>
|
||||
<button class="mobile-menu-btn">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Resume Content -->
|
||||
<div class="resume-container">
|
||||
<div class="resume-header">
|
||||
<h1 class="resume-name">Daniel LaForce</h1>
|
||||
<h2 class="resume-title">Infrastructure & Systems Engineer</h2>
|
||||
|
||||
<div class="resume-contact">
|
||||
<div class="resume-contact-item">
|
||||
<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="fab fa-linkedin"></i>
|
||||
<a href="https://www.linkedin.com/in/danllaforce" target="_blank">linkedin.com/in/danllaforce</a>
|
||||
</div>
|
||||
<div class="resume-contact-item">
|
||||
<i class="fab fa-github"></i>
|
||||
<a href="https://github.com/keyargo" target="_blank">github.com/keyargo</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Experience Section -->
|
||||
<div class="resume-section">
|
||||
<h2 class="resume-section-title">Professional Experience</h2>
|
||||
|
||||
<div class="resume-job">
|
||||
<div class="resume-job-header">
|
||||
<h3 class="resume-job-title">Freelance Consultant – GIS, Infrastructure & Security Solutions</h3>
|
||||
<div class="resume-job-company">Inovin LLC</div>
|
||||
<div class="resume-job-period">April 2023 – Present | Colorado Springs, CO</div>
|
||||
</div>
|
||||
<div class="resume-job-achievements">
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Developed TerraTracer, a GIS mapping platform used by independent mining claim prospectors to automate boundary plotting, terrain-informed site selection, and BLM/state compliance, reducing manual research by 85%.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Consulted on virtualization and DevOps projects for SMB clients, implementing Proxmox/VMware solutions, containerizing legacy apps with Docker, and orchestrating microservices with Kubernetes.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Built secure cloud environments integrating Azure AD, SSO, and VPN/firewall solutions, increasing operational resilience while aligning with HIPAA and zero-trust principles.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Automated infrastructure tasks via PowerShell, Python, and Bash, optimizing system deployment, backup routines, and monitoring pipelines.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-job">
|
||||
<div class="resume-job-header">
|
||||
<h3 class="resume-job-title">Project Engineer</h3>
|
||||
<div class="resume-job-company">Anchor Point IT Solutions</div>
|
||||
<div class="resume-job-period">December 2023 - June 2024</div>
|
||||
</div>
|
||||
<div class="resume-job-achievements">
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Executed 5 Microsoft 365 and SharePoint migrations with downtime reduced by 60%.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Implemented comprehensive security stack including BlueMira & DUO (Identity), SentinelOne (Endpoint), ConnectSecure (Network), and Email Mesh Security.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Reduced security incidents by 83% through security implementations and improved system updates by 60%.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Managed approximately 235 clients with environment sizes ranging from 30 to 1000 people.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-job">
|
||||
<div class="resume-job-header">
|
||||
<h3 class="resume-job-title">Interim Virtual Chief Security Officer</h3>
|
||||
<div class="resume-job-company">Technology Response Team, LLC</div>
|
||||
<div class="resume-job-period">August 2023 - September 2023</div>
|
||||
</div>
|
||||
<div class="resume-job-achievements">
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Served as temporary VCSO for ~120 clients, conducting penetration testing using BURP Professional.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Managed enterprise security stack deployment including Blackpoint & Webroot (Endpoint), DNSFilter (Network), and ThreatLocker (Application Control).</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Administered Azure AD security policies and MFA enforcement, reducing monthly vulnerabilities by at least 20%.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-job">
|
||||
<div class="resume-job-header">
|
||||
<h3 class="resume-job-title">Network Engineer II</h3>
|
||||
<div class="resume-job-company">NOVUS Professional Services, Inc.</div>
|
||||
<div class="resume-job-period">August 2022 - March 2023</div>
|
||||
</div>
|
||||
<div class="resume-job-achievements">
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Designed and implemented a WiFi testing cage for remote firmware testing of router models (Wave2, WiFi6).</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Developed Python automation for Plume device registration and Ansible scripts for network tasks.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Managed RF testing and signal verification across 9 headends and maintained network connectivity for ~100 routers across two sites.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-job">
|
||||
<div class="resume-job-header">
|
||||
<h3 class="resume-job-title">Field Engineer</h3>
|
||||
<div class="resume-job-company">COMPUTEK Dental Systems</div>
|
||||
<div class="resume-job-period">December 2021 - August 2022</div>
|
||||
</div>
|
||||
<div class="resume-job-achievements">
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Managed IT infrastructure for 300+ dental practices (3700+ workstations, ~300 Windows Servers).</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Developed VSA Deployer application (Kaseya VSA RMM) for agent installation, reducing deployment time by 80%.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Maintained server, Hyper-V VM, and MySQL/MSSQL backups using N-Able Backups, Windows Server Backups and AIS.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-job">
|
||||
<div class="resume-job-header">
|
||||
<h3 class="resume-job-title">End-to-End Systems Engineer</h3>
|
||||
<div class="resume-job-company">Lockheed Martin</div>
|
||||
<div class="resume-job-period">June 2018 - December 2019</div>
|
||||
</div>
|
||||
<div class="resume-job-achievements">
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Maintained 2 IRON databases (AIMS and RAPID) with ~1800 configurations each, ensuring 100% database accuracy.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Collaborated with engineering team to implement Remote Tracking Station (RTS) configurations.</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>Identified and documented an average of 27 critical defects every month.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Skills Section -->
|
||||
<div class="resume-section">
|
||||
<h2 class="resume-section-title">Technical Skills</h2>
|
||||
|
||||
<div class="resume-skills">
|
||||
<div class="resume-skill-category">
|
||||
<h3 class="resume-skill-title">Cloud & Infrastructure</h3>
|
||||
<div class="resume-skill-list">
|
||||
<span class="resume-skill">Microsoft Azure</span>
|
||||
<span class="resume-skill">AWS</span>
|
||||
<span class="resume-skill">GCP</span>
|
||||
<span class="resume-skill">VMware ESXi/vSphere</span>
|
||||
<span class="resume-skill">Hyper-V</span>
|
||||
<span class="resume-skill">Docker</span>
|
||||
<span class="resume-skill">Kubernetes (K3s)</span>
|
||||
<span class="resume-skill">ProxMox</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-skill-category">
|
||||
<h3 class="resume-skill-title">Networking</h3>
|
||||
<div class="resume-skill-list">
|
||||
<span class="resume-skill">LAN/WAN</span>
|
||||
<span class="resume-skill">VPN</span>
|
||||
<span class="resume-skill">OSPF</span>
|
||||
<span class="resume-skill">EIGRP</span>
|
||||
<span class="resume-skill">STP</span>
|
||||
<span class="resume-skill">IPv4/IPv6</span>
|
||||
<span class="resume-skill">DNS/DHCP</span>
|
||||
<span class="resume-skill">VLANs</span>
|
||||
<span class="resume-skill">QoS</span>
|
||||
<span class="resume-skill">Cisco Routers</span>
|
||||
<span class="resume-skill">Catalyst Switches</span>
|
||||
<span class="resume-skill">ASA Firewalls</span>
|
||||
<span class="resume-skill">UniFi Systems</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-skill-category">
|
||||
<h3 class="resume-skill-title">Programming/Scripting</h3>
|
||||
<div class="resume-skill-list">
|
||||
<span class="resume-skill">Python</span>
|
||||
<span class="resume-skill">JavaScript (Node.js)</span>
|
||||
<span class="resume-skill">PowerShell</span>
|
||||
<span class="resume-skill">Bash</span>
|
||||
<span class="resume-skill">C/C++</span>
|
||||
<span class="resume-skill">SQL</span>
|
||||
<span class="resume-skill">AutoHotkey</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-skill-category">
|
||||
<h3 class="resume-skill-title">Security</h3>
|
||||
<div class="resume-skill-list">
|
||||
<span class="resume-skill">Penetration Testing</span>
|
||||
<span class="resume-skill">BURP Professional</span>
|
||||
<span class="resume-skill">SentinelOne</span>
|
||||
<span class="resume-skill">Blackpoint</span>
|
||||
<span class="resume-skill">Webroot</span>
|
||||
<span class="resume-skill">ThreatLocker</span>
|
||||
<span class="resume-skill">Zero-Trust Architecture</span>
|
||||
<span class="resume-skill">HIPAA Compliance</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-skill-category">
|
||||
<h3 class="resume-skill-title">Operating Systems</h3>
|
||||
<div class="resume-skill-list">
|
||||
<span class="resume-skill">Windows Server</span>
|
||||
<span class="resume-skill">Active Directory</span>
|
||||
<span class="resume-skill">Group Policy</span>
|
||||
<span class="resume-skill">Linux (Ubuntu, CentOS)</span>
|
||||
<span class="resume-skill">Cisco IOS</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-skill-category">
|
||||
<h3 class="resume-skill-title">GIS & Data</h3>
|
||||
<div class="resume-skill-list">
|
||||
<span class="resume-skill">Geospatial Mapping</span>
|
||||
<span class="resume-skill">GeoPandas</span>
|
||||
<span class="resume-skill">GDAL/OGR</span>
|
||||
<span class="resume-skill">KML Generation</span>
|
||||
<span class="resume-skill">Data Visualization</span>
|
||||
<span class="resume-skill">Machine Learning</span>
|
||||
<span class="resume-skill">Pandas</span>
|
||||
<span class="resume-skill">NumPy</span>
|
||||
<span class="resume-skill">Scikit-learn</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Education Section -->
|
||||
<div class="resume-section">
|
||||
<h2 class="resume-section-title">Education</h2>
|
||||
|
||||
<div class="resume-education">
|
||||
<h3 class="resume-education-title">Bachelor of Science, Computer Science</h3>
|
||||
<div class="resume-education-institution">Western Governors University</div>
|
||||
<div class="resume-education-period">June 2019 - April 2023</div>
|
||||
<div class="resume-job-achievements">
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-award"></i>
|
||||
<span>Sigma Alpha Phi (NSLS)</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-award"></i>
|
||||
<span>Academic Excellence Award</span>
|
||||
</div>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Certifications Section -->
|
||||
<div class="resume-section">
|
||||
<h2 class="resume-section-title">Certifications</h2>
|
||||
|
||||
<div class="resume-job-achievements">
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-certificate"></i>
|
||||
<span>Project+ (CompTIA)</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-certificate"></i>
|
||||
<span>Network+ (FRCC)</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-certificate"></i>
|
||||
<span>A+ (FRCC)</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-certificate"></i>
|
||||
<span>CCNA Cyber Ops (2021)</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-certificate"></i>
|
||||
<span>CCNA Routing & Switching (2021)</span>
|
||||
</div>
|
||||
<div class="resume-job-achievement">
|
||||
<i class="fas fa-certificate"></i>
|
||||
<span>Virtual Cyber Security Officer Training (vCSO Advanced)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Projects Section -->
|
||||
<div class="resume-section">
|
||||
<h2 class="resume-section-title">Notable Projects</h2>
|
||||
|
||||
<div class="resume-projects">
|
||||
<div class="resume-project">
|
||||
<h3 class="resume-project-title">TerraTracer</h3>
|
||||
<p>A GIS mapping platform used by mining claim prospectors to automate boundary plotting and compliance verification, reducing manual research by 85%.</p>
|
||||
<div class="resume-project-tech">
|
||||
<span class="resume-project-tech-item">Python</span>
|
||||
<span class="resume-project-tech-item">Node.js</span>
|
||||
<span class="resume-project-tech-item">GeoPandas</span>
|
||||
<span class="resume-project-tech-item">KML</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-project">
|
||||
<h3 class="resume-project-title">Wi-Fi Testing Cage</h3>
|
||||
<p>Designed and implemented a full-access Wi-Fi testing facility for remote firmware testing of router models, supporting Wave2 and WiFi6 capabilities.</p>
|
||||
<div class="resume-project-tech">
|
||||
<span class="resume-project-tech-item">RF Engineering</span>
|
||||
<span class="resume-project-tech-item">Network Testing</span>
|
||||
<span class="resume-project-tech-item">CAD Prototyping</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-project">
|
||||
<h3 class="resume-project-title">VSA Deployer</h3>
|
||||
<p>Custom application for streamlining Kaseya VSA RMM agent installation, reducing deployment time by 80% across dental practice environments.</p>
|
||||
<div class="resume-project-tech">
|
||||
<span class="resume-project-tech-item">PowerShell</span>
|
||||
<span class="resume-project-tech-item">AutoHotkey</span>
|
||||
<span class="resume-project-tech-item">RMM</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-project">
|
||||
<h3 class="resume-project-title">Argo Cloudflare DDNS</h3>
|
||||
<p>Bash script for automating DNS updates with Cloudflare, featuring user input validation, API integration, and cron scheduling.</p>
|
||||
<div class="resume-project-tech">
|
||||
<span class="resume-project-tech-item">Bash</span>
|
||||
<span class="resume-project-tech-item">API Integration</span>
|
||||
<span class="resume-project-tech-item">DNS</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resume-download">
|
||||
<a href="resume/daniel-laforce-resume.pdf" class="btn btn-primary" download>
|
||||
<i class="fas fa-download btn-icon"></i>
|
||||
Download Full Resume (PDF)
|
||||
</a>
|
||||
</div>
|
||||
</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/danllaforce" 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>© <span id="current-year"></span> All rights reserved. Inovin LLC</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- JavaScript -->
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
81
script.js
81
script.js
|
@ -65,22 +65,41 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
const contactForm = document.getElementById('contact-form');
|
||||
|
||||
if (contactForm) {
|
||||
contactForm.addEventListener('submit', function(e) {
|
||||
contactForm.addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// In a real implementation, you would send the form data to a backend service
|
||||
// For now, we'll just simulate a successful submission
|
||||
const submitButton = contactForm.querySelector('button[type="submit"]');
|
||||
const originalButtonText = submitButton.innerHTML;
|
||||
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
|
||||
submitButton.disabled = true;
|
||||
|
||||
const formData = new FormData(contactForm);
|
||||
const formValues = Object.fromEntries(formData.entries());
|
||||
|
||||
console.log('Form submission:', formValues);
|
||||
|
||||
// Show success message
|
||||
alert('Thank you for your message! I will get back to you soon.');
|
||||
|
||||
// Reset form
|
||||
contactForm.reset();
|
||||
try {
|
||||
const formData = new FormData(contactForm);
|
||||
const formValues = Object.fromEntries(formData.entries());
|
||||
|
||||
const response = await fetch('/contact', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(formValues)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
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');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Failed to send message. Please try again or contact me directly via email.');
|
||||
} finally {
|
||||
submitButton.innerHTML = originalButtonText;
|
||||
submitButton.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -93,17 +112,15 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
|
||||
// Create animated data streams in the dashboard
|
||||
function createDataStreamAnimation() {
|
||||
// Look for either class name that might be in the HTML
|
||||
const dataStreamContainer = document.querySelector('.data-stream') ||
|
||||
document.querySelector('.hero-visual .tech-dashboard .data-stream');
|
||||
|
||||
console.log('Data stream container found:', !!dataStreamContainer);
|
||||
|
||||
if (!dataStreamContainer) return;
|
||||
const dataStreamContainer = document.querySelector('.data-stream');
|
||||
|
||||
if (!dataStreamContainer) {
|
||||
console.log('Data stream container not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear existing lines
|
||||
const existingLines = dataStreamContainer.querySelectorAll('.data-line');
|
||||
existingLines.forEach(line => line.remove());
|
||||
dataStreamContainer.innerHTML = '';
|
||||
|
||||
// Create new random lines
|
||||
for (let i = 0; i < 10; i++) {
|
||||
|
@ -113,21 +130,25 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
// 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
|
||||
const duration = Math.random() * 3 + 2; // 2-5s duration
|
||||
const delay = Math.random() * 2; // 0-2s delay
|
||||
|
||||
line.style.left = `${left}%`;
|
||||
line.style.width = `${width}%`;
|
||||
line.style.animationDuration = `${duration}s`;
|
||||
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);
|
||||
console.log('Added data line:', i);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to initialize the data stream animation (with retry for race conditions)
|
||||
setTimeout(createDataStreamAnimation, 100);
|
||||
// Initialize the data stream animation immediately
|
||||
createDataStreamAnimation();
|
||||
|
||||
// Refresh data streams periodically
|
||||
// Refresh data streams every 8 seconds
|
||||
setInterval(createDataStreamAnimation, 8000);
|
||||
|
||||
// Update terminal output with random status messages
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
const express = require('express');
|
||||
const nodemailer = require('nodemailer');
|
||||
const cors = require('cors');
|
||||
require('dotenv').config();
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
// Middleware
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
app.use(express.static('public'));
|
||||
|
||||
// Email transporter
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: 'gmail',
|
||||
auth: {
|
||||
user: process.env.EMAIL_USER,
|
||||
pass: process.env.EMAIL_PASS
|
||||
}
|
||||
});
|
||||
|
||||
// Contact form endpoint
|
||||
app.post('/api/contact', async (req, res) => {
|
||||
try {
|
||||
const { name, email, subject, message } = req.body;
|
||||
|
||||
// Email options
|
||||
const mailOptions = {
|
||||
from: process.env.EMAIL_USER,
|
||||
to: 'daniel.laforce@argobox.com',
|
||||
subject: `Contact Form: ${subject}`,
|
||||
text: `
|
||||
Name: ${name}
|
||||
Email: ${email}
|
||||
Subject: ${subject}
|
||||
|
||||
Message:
|
||||
${message}
|
||||
`,
|
||||
html: `
|
||||
<h3>New Contact Form Submission</h3>
|
||||
<p><strong>Name:</strong> ${name}</p>
|
||||
<p><strong>Email:</strong> ${email}</p>
|
||||
<p><strong>Subject:</strong> ${subject}</p>
|
||||
<h4>Message:</h4>
|
||||
<p>${message}</p>
|
||||
`
|
||||
};
|
||||
|
||||
// Send email
|
||||
await transporter.sendMail(mailOptions);
|
||||
|
||||
res.status(200).json({ message: 'Message sent successfully!' });
|
||||
} catch (error) {
|
||||
console.error('Error sending email:', error);
|
||||
res.status(500).json({ message: 'Failed to send message. Please try again.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server running on port ${port}`);
|
||||
});
|
50
styles.css
50
styles.css
|
@ -297,45 +297,69 @@ ul {
|
|||
|
||||
.hero-visual {
|
||||
flex: 1;
|
||||
min-width: 300px;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.tech-dashboard {
|
||||
background-color: var(--secondary);
|
||||
border-radius: 1rem;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
|
||||
transform: perspective(1000px) rotateY(-5deg) rotateX(5deg);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tech-dashboard:hover {
|
||||
transform: perspective(1000px) rotateY(0deg) rotateX(0deg);
|
||||
}
|
||||
|
||||
/* Data Stream Animation */
|
||||
.data-stream {
|
||||
height: 200px;
|
||||
background-color: var(--secondary);
|
||||
border-radius: 0.5rem;
|
||||
background-color: rgba(15, 23, 42, 0.95);
|
||||
border-radius: 0.5rem 0.5rem 0 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin-bottom: 0.5rem;
|
||||
background-image:
|
||||
linear-gradient(rgba(59, 130, 246, 0.05) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(59, 130, 246, 0.05) 1px, transparent 1px);
|
||||
background-size: 20px 20px;
|
||||
}
|
||||
|
||||
.data-line {
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
background-color: var(--accent);
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, var(--accent), transparent);
|
||||
opacity: 0.5;
|
||||
animation-name: datastream;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
transform: translateY(-100%);
|
||||
will-change: transform;
|
||||
animation: datastream 3s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes datastream {
|
||||
0% { transform: translateY(-100%); }
|
||||
100% { transform: translateY(500%); }
|
||||
from { transform: translateY(-100%); }
|
||||
to { transform: translateY(1000%); }
|
||||
}
|
||||
|
||||
.terminal {
|
||||
background-color: var(--primary);
|
||||
border-radius: 0.5rem;
|
||||
background-color: rgba(15, 23, 42, 0.98);
|
||||
border-radius: 0 0 0.5rem 0.5rem;
|
||||
padding: 1rem;
|
||||
font-family: monospace;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.terminal-line {
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.terminal-line.success { color: var(--success); }
|
||||
.terminal-line.warning { color: var(--warning); }
|
||||
.terminal-line.info { color: var(--info); }
|
||||
|
||||
.success {
|
||||
color: var(--success);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue