Enhance SEO metadata, update hero section content, improve navigation highlighting, and refactor JavaScript for role switching and scroll spy functionality. Remove unused CSS styles and add new project card styles.
This commit is contained in:
parent
e4f6a2542f
commit
2a239fb6c8
Binary file not shown.
After Width: | Height: | Size: 898 KiB |
139
index.html
139
index.html
|
@ -13,6 +13,16 @@
|
|||
<meta property="og:description" content="Expert in infrastructure architecture, DevOps automation, and secure cloud migrations. View my live lab dashboard and projects.">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://laforceit.com">
|
||||
<meta property="og:image" content="https://laforceit.com/images/og-preview.jpg">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:site_name" content="LaForceIT.com">
|
||||
|
||||
<!-- Twitter Card data -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Daniel LaForce | Infrastructure & Systems Architect">
|
||||
<meta name="twitter:description" content="Expert in infrastructure architecture, DevOps automation, and secure cloud migrations.">
|
||||
<meta name="twitter:image" content="https://laforceit.com/images/og-preview.jpg">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/x-icon" href="images/favicon.ico">
|
||||
|
@ -76,7 +86,6 @@
|
|||
<div class="intro-section">
|
||||
<div class="name-section">
|
||||
<h2 class="name">Daniel LaForce</h2>
|
||||
<span class="your-text">your</span>
|
||||
</div>
|
||||
|
||||
<h1 class="hero-title">
|
||||
|
@ -97,7 +106,7 @@
|
|||
</h1>
|
||||
|
||||
<p class="hero-description" id="role-description">
|
||||
Securing and optimizing your digital infrastructure with enterprise-grade solutions — from zero-trust architecture to automated security monitoring that keeps your business protected 24/7.
|
||||
Helping businesses run faster, safer, and smarter—through automated infrastructure, secure architecture, and real-world engineering.
|
||||
</p>
|
||||
|
||||
<div class="inline-terminal">
|
||||
|
@ -132,13 +141,13 @@
|
|||
</div>
|
||||
|
||||
<div class="cta-buttons">
|
||||
<a href="#contact" class="btn btn-primary">
|
||||
<a href="#contact" class="btn btn-primary btn-featured">
|
||||
<span class="pulse-ring"></span>
|
||||
<span class="btn-text">Hire Me</span>
|
||||
<span class="btn-icon"><i class="fas fa-arrow-right"></i></span>
|
||||
</a>
|
||||
|
||||
<a href="https://www.argobox.com" class="btn btn-outline btn-featured" target="_blank">
|
||||
<span class="pulse-ring"></span>
|
||||
<a href="https://www.argobox.com" class="btn btn-outline" target="_blank">
|
||||
<span class="btn-text">Explore My Lab</span>
|
||||
<span class="btn-icon"><i class="fas fa-server"></i></span>
|
||||
</a>
|
||||
|
@ -372,63 +381,83 @@
|
|||
<span>View Live Dashboard</span>
|
||||
</span>
|
||||
</a>
|
||||
<a href="https://argobox.com/ansible-sandbox" class="btn btn-outline" target="_blank">Try Ansible Sandbox</a>
|
||||
<a href="https://argobox.com/ansible-sandbox" class="btn btn-outline btn-offline" target="_blank">
|
||||
<span class="flex-center">
|
||||
<span class="offline-indicator"></span>
|
||||
<span>Ansible Sandbox (Offline)</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lab-card">
|
||||
<div class="lab-card lab-metrics-card">
|
||||
<h3 class="lab-card-title">Real-Time Metrics</h3>
|
||||
|
||||
<div class="metric">
|
||||
<div class="metric-header">
|
||||
<span class="metric-name">CPU Usage</span>
|
||||
<span class="metric-value">42%</span>
|
||||
<div class="terminal-card">
|
||||
<div class="terminal-card-header">
|
||||
<span class="terminal-title">System Status</span>
|
||||
<span class="terminal-status online">ONLINE</span>
|
||||
</div>
|
||||
<div class="metric-bar">
|
||||
<div class="metric-progress" style="width: 42%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metric">
|
||||
<div class="metric-header">
|
||||
<span class="metric-name">Memory</span>
|
||||
<span class="metric-value">57%</span>
|
||||
</div>
|
||||
<div class="metric-bar">
|
||||
<div class="metric-progress" style="width: 57%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metric">
|
||||
<div class="metric-header">
|
||||
<span class="metric-name">Storage</span>
|
||||
<span class="metric-value">63%</span>
|
||||
</div>
|
||||
<div class="metric-bar">
|
||||
<div class="metric-progress" style="width: 63%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metric">
|
||||
<div class="metric-header">
|
||||
<span class="metric-name">Network</span>
|
||||
<span class="metric-value">28%</span>
|
||||
</div>
|
||||
<div class="metric-bar">
|
||||
<div class="metric-progress" style="width: 28%"></div>
|
||||
<div class="terminal-card-content">
|
||||
<div class="metric">
|
||||
<div class="metric-header">
|
||||
<span class="metric-name">CPU Usage</span>
|
||||
<span class="metric-value">42%</span>
|
||||
</div>
|
||||
<div class="metric-bar">
|
||||
<div class="metric-progress" style="width: 42%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metric">
|
||||
<div class="metric-header">
|
||||
<span class="metric-name">Memory</span>
|
||||
<span class="metric-value">57%</span>
|
||||
</div>
|
||||
<div class="metric-bar">
|
||||
<div class="metric-progress" style="width: 57%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metric">
|
||||
<div class="metric-header">
|
||||
<span class="metric-name">Storage</span>
|
||||
<span class="metric-value">63%</span>
|
||||
</div>
|
||||
<div class="metric-bar">
|
||||
<div class="metric-progress" style="width: 63%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metric">
|
||||
<div class="metric-header">
|
||||
<span class="metric-name">Network</span>
|
||||
<span class="metric-value">28%</span>
|
||||
</div>
|
||||
<div class="metric-bar">
|
||||
<div class="metric-progress" style="width: 28%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="lab-subtitle">Active Services:</h4>
|
||||
<div class="services-grid-small">
|
||||
<div class="service-tag"><span class="status-dot"></span>Gitea</div>
|
||||
<div class="service-tag"><span class="status-dot"></span>VSCode Server</div>
|
||||
<div class="service-tag"><span class="status-dot"></span>rTorrent</div>
|
||||
<div class="service-tag"><span class="status-dot"></span>NAS</div>
|
||||
<div class="service-tag"><span class="status-dot"></span>Traefik</div>
|
||||
<div class="service-tag"><span class="status-dot"></span>K3s</div>
|
||||
<div class="service-tag"><span class="status-dot"></span>Cloudflared</div>
|
||||
<div class="service-tag"><span class="status-dot"></span>FileBrowser</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>Gitea</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>VSCode Server</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>rTorrent</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>NAS</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>Traefik</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>K3s</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>Cloudflared</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>FileBrowser</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>OpenWebUI</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>Ollama</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>Obsidian Blog</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>Obsidian Notes</div>
|
||||
<div class="service-tag"><span class="status-dot error"></span>Ansible Sandbox</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>Jellyfin</div>
|
||||
<div class="service-tag"><span class="status-dot active"></span>Plex</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -597,7 +626,7 @@
|
|||
<i class="fab fa-linkedin"></i>
|
||||
</div>
|
||||
<h3 class="contact-title">LinkedIn</h3>
|
||||
<p><a href="https://www.linkedin.com/in/daniellaforce" target="_blank">linkedin.com/in/daniellaforce</a></p>
|
||||
<p><a href="https://www.linkedin.com/in/danlaforce" target="_blank">linkedin.com/in/danlaforce</a></p>
|
||||
</div>
|
||||
|
||||
<div class="contact-item">
|
||||
|
@ -605,7 +634,7 @@
|
|||
<i class="fab fa-github"></i>
|
||||
</div>
|
||||
<h3 class="contact-title">GitHub</h3>
|
||||
<p><a href="https://github.com/daniellaforce" target="_blank">github.com/daniellaforce</a></p>
|
||||
<p><a href="https://github.com/keyargo" target="_blank">github.com/danlaforce</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -664,10 +693,10 @@
|
|||
</div>
|
||||
|
||||
<div class="footer-social">
|
||||
<a href="https://www.linkedin.com/in/daniellaforce" target="_blank" title="LinkedIn">
|
||||
<a href="https://www.linkedin.com/in/danlaforce" target="_blank" title="LinkedIn">
|
||||
<i class="fab fa-linkedin"></i>
|
||||
</a>
|
||||
<a href="https://github.com/daniellaforce" target="_blank" title="GitHub">
|
||||
<a href="https://github.com/keyargo" target="_blank" title="GitHub">
|
||||
<i class="fab fa-github"></i>
|
||||
</a>
|
||||
<a href="mailto:daniel@laforceit.com" title="Email">
|
||||
|
|
|
@ -508,9 +508,9 @@
|
|||
<i class="fas fa-phone"></i>
|
||||
<a href="tel:7203100064">720-310-0064</a>
|
||||
</div>
|
||||
<a href="mailto:daniel.laforce@laforceit.com" class="resume-contact-item">
|
||||
<a href="mailto:daniel@laforceit.com" class="resume-contact-item">
|
||||
<i class="fas fa-envelope"></i>
|
||||
daniel.laforce@laforceit.com
|
||||
daniel@laforceit.com
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/in/danlaforce" class="resume-contact-item" target="_blank">
|
||||
<i class="fab fa-linkedin"></i>
|
||||
|
@ -987,10 +987,10 @@
|
|||
</div>
|
||||
|
||||
<div class="footer-social">
|
||||
<a href="https://www.linkedin.com/in/daniellaforce" target="_blank" title="LinkedIn">
|
||||
<a href="https://www.linkedin.com/in/danlaforce" target="_blank" title="LinkedIn">
|
||||
<i class="fab fa-linkedin"></i>
|
||||
</a>
|
||||
<a href="https://github.com/daniellaforce" target="_blank" title="GitHub">
|
||||
<a href="https://github.com/keyargo" target="_blank" title="GitHub">
|
||||
<i class="fab fa-github"></i>
|
||||
</a>
|
||||
<a href="mailto:daniel@laforceit.com" title="Email">
|
||||
|
|
139
script.js
139
script.js
|
@ -19,6 +19,37 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
if (contactForm) {
|
||||
initFormHandling(contactForm);
|
||||
}
|
||||
|
||||
// Highlight navigation on scroll
|
||||
setupScrollSpy();
|
||||
|
||||
// Setup role switching with improved timing
|
||||
setupRoleSwitching();
|
||||
|
||||
// Other initializations...
|
||||
setupFloatingIcons();
|
||||
setupParticles();
|
||||
setupRevealAnimations();
|
||||
initializeSlider();
|
||||
|
||||
// Contact form handling
|
||||
setupContactForm();
|
||||
|
||||
// Mobile menu toggle
|
||||
document.querySelector('.menu-toggle').addEventListener('click', function() {
|
||||
document.querySelector('.nav-menu').classList.toggle('active');
|
||||
});
|
||||
|
||||
// Navbar effects on scroll
|
||||
window.addEventListener('scroll', function() {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
|
||||
if (window.scrollY > 50) {
|
||||
navbar.classList.add('scrolled');
|
||||
} else {
|
||||
navbar.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -460,4 +491,110 @@ function updateYear() {
|
|||
if (yearElement) {
|
||||
yearElement.textContent = new Date().getFullYear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up scroll spy functionality to highlight nav links
|
||||
* as the user scrolls through different sections
|
||||
*/
|
||||
function setupScrollSpy() {
|
||||
const sections = document.querySelectorAll('section[id]');
|
||||
const navLinks = document.querySelectorAll('.nav-link');
|
||||
|
||||
window.addEventListener('scroll', function() {
|
||||
let current = '';
|
||||
|
||||
sections.forEach(section => {
|
||||
const sectionTop = section.offsetTop - 100;
|
||||
const sectionHeight = section.offsetHeight;
|
||||
|
||||
if (window.scrollY >= sectionTop && window.scrollY < sectionTop + sectionHeight) {
|
||||
current = section.getAttribute('id');
|
||||
}
|
||||
});
|
||||
|
||||
navLinks.forEach(link => {
|
||||
link.classList.remove('active');
|
||||
if (link.getAttribute('href') === `#${current}`) {
|
||||
link.classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up automated role switching with better timing and transitions
|
||||
*/
|
||||
function setupRoleSwitching() {
|
||||
const roles = document.querySelectorAll('.role');
|
||||
const roleDescription = document.getElementById('role-description');
|
||||
let currentRoleIndex = 0;
|
||||
|
||||
// Initial role description
|
||||
if (roles.length > 0 && roleDescription) {
|
||||
roleDescription.textContent = roles[0].getAttribute('data-description');
|
||||
roles[0].classList.add('active');
|
||||
}
|
||||
|
||||
// Switch roles every 5 seconds with fade transition
|
||||
setInterval(() => {
|
||||
// Remove active class from current role
|
||||
roles[currentRoleIndex].classList.remove('active');
|
||||
|
||||
// Move to the next role or back to the first
|
||||
currentRoleIndex = (currentRoleIndex + 1) % roles.length;
|
||||
|
||||
// Add active class to new role
|
||||
roles[currentRoleIndex].classList.add('active');
|
||||
|
||||
// Update the role description with fade effect
|
||||
if (roleDescription) {
|
||||
roleDescription.style.opacity = '0';
|
||||
|
||||
setTimeout(() => {
|
||||
roleDescription.textContent = roles[currentRoleIndex].getAttribute('data-description');
|
||||
roleDescription.style.opacity = '1';
|
||||
}, 300);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// Replace the existing setupFloatingIcons with this improved version
|
||||
function setupFloatingIcons() {
|
||||
const container = document.getElementById('floating-icons');
|
||||
if (!container) return;
|
||||
|
||||
// Clear existing icons
|
||||
container.innerHTML = '';
|
||||
|
||||
// Tech icons to display
|
||||
const icons = [
|
||||
'fa-server', 'fa-network-wired', 'fa-shield-alt',
|
||||
'fa-cloud', 'fa-code-branch', 'fa-database',
|
||||
'fa-laptop-code', 'fa-lock', 'fa-terminal'
|
||||
];
|
||||
|
||||
// Create floating icons
|
||||
icons.forEach(icon => {
|
||||
const iconElement = document.createElement('div');
|
||||
iconElement.className = 'floating-icon';
|
||||
iconElement.innerHTML = `<i class="fas ${icon}"></i>`;
|
||||
|
||||
// Random starting position
|
||||
const randomX = Math.floor(Math.random() * 100);
|
||||
const randomY = Math.floor(Math.random() * 100);
|
||||
const randomDelay = Math.random() * 5;
|
||||
const randomDuration = 20 + Math.random() * 10;
|
||||
|
||||
// Apply styles
|
||||
iconElement.style.left = `${randomX}%`;
|
||||
iconElement.style.top = `${randomY}%`;
|
||||
iconElement.style.animationDelay = `${randomDelay}s`;
|
||||
iconElement.style.animationDuration = `${randomDuration}s`;
|
||||
|
||||
// Add to container
|
||||
container.appendChild(iconElement);
|
||||
});
|
||||
}
|
||||
|
||||
// More existing code...
|
101
style.css
101
style.css
|
@ -1,101 +0,0 @@
|
|||
.form-notification {
|
||||
margin-top: 1rem;
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
animation: slideIn 0.3s ease-out;
|
||||
font-weight: 500;
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.form-notification.success {
|
||||
background-color: var(--success);
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.form-notification.error {
|
||||
background-color: var(--error);
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.form-notification i {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideOut {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.form-notification.hiding {
|
||||
animation: slideOut 0.3s ease-in forwards;
|
||||
}
|
||||
|
||||
@keyframes float-particle {
|
||||
0% {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
transform: translate(20px, -20px);
|
||||
}
|
||||
50% {
|
||||
transform: translate(40px, 0);
|
||||
}
|
||||
75% {
|
||||
transform: translate(20px, 20px);
|
||||
}
|
||||
100% {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
:root {
|
||||
--success: #10b981;
|
||||
--error: #ef4444;
|
||||
}
|
||||
|
||||
.logo-text-glow {
|
||||
font-weight: 800;
|
||||
font-size: 1.6rem;
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-darker));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
text-shadow: 0 0 6px rgba(59, 130, 246, 0.5);
|
||||
transition: all 0.3s ease-in-out;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.logo-dot-glow {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 1.6rem;
|
||||
margin-left: -1px;
|
||||
text-shadow: 0 0 3px rgba(255, 255, 255, 0.3);
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
210
styles.css
210
styles.css
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
* Main stylesheet for argobox.com
|
||||
* Modern tech portfolio design with animation effects
|
||||
* Main stylesheet for laforceit.com
|
||||
*/
|
||||
|
||||
:root {
|
||||
|
@ -198,7 +197,6 @@ section {
|
|||
|
||||
.navbar.scrolled {
|
||||
background-color: rgba(15, 23, 42, 0.95);
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.navbar .container {
|
||||
|
@ -443,13 +441,14 @@ background-clip: text;
|
|||
}
|
||||
|
||||
.hero-description {
|
||||
font-size: 1.2rem;
|
||||
font-size: 1.1rem;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 1.5rem; /* Add explicit top margin */
|
||||
margin-bottom: 2rem;
|
||||
max-width: 550px;
|
||||
position: relative; /* Make it position relative */
|
||||
z-index: 1; /* Ensure it's above the role titles */
|
||||
max-width: 90%;
|
||||
line-height: 1.6;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
/* Terminal text that appears directly on the page */
|
||||
|
@ -1153,8 +1152,6 @@ background-clip: text;
|
|||
padding: 2rem;
|
||||
transition: all var(--transition-normal);
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.project-card:hover {
|
||||
|
@ -1874,4 +1871,197 @@ body::before {
|
|||
}
|
||||
}
|
||||
|
||||
/* Highlight navigation links on scroll */
|
||||
.nav-link.active {
|
||||
color: var(--accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.nav-link.active::after {
|
||||
width: 100%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Terminal Card Styles for Lab Section */
|
||||
.terminal-card {
|
||||
background-color: rgba(15, 23, 42, 0.95);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 1.5rem;
|
||||
box-shadow: var(--card-shadow);
|
||||
transition: all var(--transition-normal);
|
||||
}
|
||||
|
||||
.terminal-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 15px 30px -10px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.terminal-card-header {
|
||||
background-color: rgba(30, 41, 59, 0.95);
|
||||
padding: 0.75rem 1rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.terminal-title {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.terminal-status {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(15, 23, 42, 0.7);
|
||||
}
|
||||
|
||||
.terminal-status.online {
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.terminal-card-content {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* Service tags with active indicators */
|
||||
.status-dot.active {
|
||||
background-color: var(--success);
|
||||
box-shadow: 0 0 5px var(--success);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
/* Service tags with error indicators */
|
||||
.status-dot.error {
|
||||
background-color: var(--error);
|
||||
box-shadow: 0 0 5px var(--error);
|
||||
}
|
||||
|
||||
/* Project Cards with Images */
|
||||
.project-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--card-bg);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
transition: all var(--transition-normal);
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: var(--card-shadow);
|
||||
}
|
||||
|
||||
.project-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 15px 30px -10px rgba(0, 0, 0, 0.4);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.project-image {
|
||||
position: relative;
|
||||
height: 180px;
|
||||
overflow: hidden;
|
||||
background-color: rgba(15, 23, 42, 0.8);
|
||||
}
|
||||
|
||||
.project-thumbnail {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.project-card:hover .project-thumbnail {
|
||||
transform: scale(1.05);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.project-icon {
|
||||
position: absolute;
|
||||
bottom: -25px;
|
||||
right: 20px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent-gradient);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 1.5rem;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
border: 3px solid var(--primary-bg);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.project-content {
|
||||
padding: 1.5rem;
|
||||
padding-top: 1rem;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.project-links {
|
||||
margin-top: auto;
|
||||
padding-top: 1rem;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.project-link {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
color: var(--accent);
|
||||
transition: all var(--transition-normal);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.project-link:hover {
|
||||
color: var(--accent-darker);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.project-card {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.project-image {
|
||||
height: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-offline {
|
||||
border-color: var(--error);
|
||||
color: var(--error);
|
||||
cursor: not-allowed;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.btn-offline:hover {
|
||||
background-color: rgba(239, 68, 68, 0.1);
|
||||
color: var(--error);
|
||||
box-shadow: 0 0 10px rgba(239, 68, 68, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.offline-indicator {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: var(--error);
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue