laforceit-blog/src/components/Footer.astro

649 lines
17 KiB
Plaintext

---
// src/components/Footer.astro
// High-quality footer with navigation, social links and additional elements
const currentYear = new Date().getFullYear();
// Define categories for footer links
const categories = [
{
title: 'Technology',
links: [
{ name: 'Kubernetes', path: '/categories/kubernetes' },
{ name: 'Docker', path: '/categories/docker' },
{ name: 'DevOps', path: '/categories/devops' },
{ name: 'Networking', path: '/categories/networking' },
{ name: 'Storage', path: '/categories/storage' }
]
},
{
title: 'Resources',
links: [
{ name: 'K8s Configurations', path: '/resources/kubernetes' },
{ name: 'Docker Compose', path: '/resources/docker-compose' },
{ name: 'Configuration Files', path: '/resources/config-files' },
{ name: 'Infrastructure Code', path: '/resources/iac' },
{ name: 'Tutorials', path: '/resources/tutorials' }
]
},
{
title: 'Projects',
links: [
{ name: 'HomeLab Setup', url: 'https://argobox.com' },
{ name: 'Tech Stack', url: 'https://argobox.com/#services' },
{ name: 'Github Repos', path: '/projects/github' },
{ name: 'Live Services', path: '/projects/services' },
{ name: 'Obsidian Templates', path: '/projects/obsidian' }
]
}
];
// Social links
const socialLinks = [
{
name: 'GitHub',
url: 'https://github.com/KeyArgo/',
icon: '<path fill-rule="evenodd" clip-rule="evenodd" d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385c.6.105.825-.255.825-.57c0-.285-.015-1.23-.015-2.235c-3.015.555-3.795-.735-4.035-1.41c-.135-.345-.72-1.41-1.23-1.695c-.42-.225-1.02-.78-.015-.795c.945-.015 1.62.87 1.845 1.23c1.08 1.815 2.805 1.305 3.495.99c.105-.78.42-1.305.765-1.605c-2.67-.3-5.46-1.335-5.46-5.925c0-1.305.465-2.385 1.23-3.225c-.12-.3-.54-1.53.12-3.18c0 0 1.005-.315 3.3 1.23c.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23c.66 1.65.24 2.88.12 3.18c.765.84 1.23 1.905 1.23 3.225c0 4.605-2.805 5.625-5.475 5.925c.435.375.81 1.095.81 2.22c0 1.605-.015 2.895-.015 3.3c0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />'
},
{
name: 'Twitter',
url: 'https://twitter.com/yourusername',
icon: '<path d="M23.643 4.937c-.835.37-1.732.62-2.675.733a4.67 4.67 0 0 0 2.048-2.578 9.3 9.3 0 0 1-2.958 1.13 4.66 4.66 0 0 0-7.938 4.25 13.229 13.229 0 0 1-9.602-4.868c-.4.69-.63 1.49-.63 2.342A4.66 4.66 0 0 0 3.96 9.824a4.647 4.647 0 0 1-2.11-.583v.06a4.66 4.66 0 0 0 3.737 4.568 4.692 4.692 0 0 1-2.104.08 4.661 4.661 0 0 0 4.352 3.234 9.348 9.348 0 0 1-5.786 1.995 9.5 9.5 0 0 1-1.112-.065 13.175 13.175 0 0 0 7.14 2.093c8.57 0 13.255-7.098 13.255-13.254 0-.2-.005-.402-.014-.602a9.47 9.47 0 0 0 2.323-2.41l.002-.003z" />'
},
{
name: 'LinkedIn',
url: 'https://linkedin.com/in/yourusername',
icon: '<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.225 0z" />'
},
{
name: 'RSS Feed',
url: '/rss.xml',
icon: '<path d="M4 11a9 9 0 0 1 9 9M4 4a16 16 0 0 1 16 16M6 19a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"></path>'
}
];
// Server status for homelab services
const services = [
{ name: 'ArgoBox', status: 'active' },
{ name: 'Git Server', status: 'active' },
{ name: 'Kubernetes', status: 'active' },
{ name: 'Media Server', status: 'active' }
];
---
<footer class="site-footer">
<!-- Network Lines Animation -->
<div class="network-lines"></div>
<!-- Floating Gradient Elements -->
<div class="footer-gradients">
<div class="gradient-circle circle-1"></div>
<div class="gradient-circle circle-2"></div>
</div>
<div class="container">
<!-- Main Footer Content -->
<div class="footer-content">
<!-- Brand Section -->
<div class="footer-brand">
<div class="footer-logo">
<div class="logo-symbol">
<span class="logo-text">LF</span>
<div class="logo-glow"></div>
</div>
<span class="footer-brand-name">LaForceIT</span>
</div>
<p class="footer-tagline">
Enterprise-grade home lab infrastructure, Kubernetes deployments, and DevOps automation for the modern tech enthusiast.
</p>
<!-- Homelab Services Status -->
<div class="service-status">
<h4 class="status-title">Services Status</h4>
<div class="status-grid">
{services.map(service => (
<div class="status-item">
<span class={`status-indicator ${service.status}`}></span>
<span class="status-name">{service.name}</span>
</div>
))}
</div>
</div>
<!-- Social Links -->
<div class="social-links">
{socialLinks.map(social => (
<a href={social.url} class="social-link" aria-label={social.name} target="_blank" rel="noopener">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<Fragment set:html={social.icon} />
</svg>
</a>
))}
</div>
</div>
<!-- Category Links -->
<div class="footer-links-container">
{categories.map(category => (
<div class="footer-col">
<h4 class="footer-col-title">{category.title}</h4>
<ul class="footer-links">
{category.links.map(link => (
<li>
<a
href={link.url || link.path}
class="footer-link"
target={link.url ? "_blank" : undefined}
rel={link.url ? "noopener noreferrer" : undefined}
>
{link.name}
</a>
</li>
))}
</ul>
</div>
))}
<!-- Newsletter Signup -->
<div class="footer-col">
<h4 class="footer-col-title">Newsletter</h4>
<p class="footer-newsletter-text">
Subscribe to get updates on new articles, resources, and projects.
</p>
<form class="newsletter-form">
<div class="newsletter-input-group">
<input type="email" placeholder="Enter your email" class="newsletter-input" required />
<button type="submit" class="newsletter-button">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="22" y1="2" x2="11" y2="13"></line>
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
</svg>
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Footer Bottom -->
<div class="footer-bottom">
<div class="copyright">
&copy; {currentYear} LaForceIT by Daniel LaForce. All rights reserved.
</div>
<div class="footer-meta-links">
<a href="/privacy" class="meta-link">Privacy Policy</a>
<span class="link-divider">|</span>
<a href="/terms" class="meta-link">Terms of Use</a>
<span class="link-divider">|</span>
<a href="/sitemap.xml" class="meta-link">Sitemap</a>
</div>
</div>
</div>
</footer>
<style>
.site-footer {
background: linear-gradient(0deg, var(--bg-secondary), var(--bg-primary));
padding: 5rem 0 2rem;
position: relative;
border-top: 1px solid var(--border-primary);
overflow: hidden;
}
/* Network Lines Animation */
.network-lines {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 1px;
overflow: hidden;
opacity: 0.5;
}
.network-lines::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent 0%, var(--accent-primary) 50%, transparent 100%);
animation: network-scan 8s infinite linear;
}
@keyframes network-scan {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
/* Floating Gradient Elements */
.footer-gradients {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
pointer-events: none;
}
.gradient-circle {
position: absolute;
border-radius: 50%;
filter: blur(70px);
opacity: 0.08;
}
.circle-1 {
width: 400px;
height: 400px;
background: var(--accent-primary);
top: -100px;
left: -150px;
}
.circle-2 {
width: 300px;
height: 300px;
background: var(--accent-tertiary);
bottom: -50px;
right: -100px;
}
/* Main Footer Content */
.footer-content {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 3rem;
position: relative;
z-index: 1;
}
/* Brand Section */
.footer-brand {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.footer-logo {
display: flex;
align-items: center;
gap: 0.75rem;
}
.logo-symbol {
width: 2.5rem;
height: 2.5rem;
border-radius: 8px;
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.logo-text {
font-family: var(--font-mono);
font-weight: bold;
font-size: 1.1rem;
color: var(--bg-primary);
z-index: 2;
}
.logo-glow {
position: absolute;
width: 150%;
height: 150%;
background: radial-gradient(circle, var(--accent-primary) 0%, transparent 70%);
opacity: 0.5;
filter: blur(15px);
z-index: 1;
animation: pulse 4s infinite alternate ease-in-out;
}
.footer-brand-name {
font-weight: 600;
font-size: 1.3rem;
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
letter-spacing: 0.02em;
}
.footer-tagline {
color: var(--text-secondary);
font-size: 0.95rem;
line-height: 1.6;
max-width: 350px;
}
/* Service Status */
.service-status {
background: rgba(15, 23, 42, 0.4);
border: 1px solid var(--border-secondary);
border-radius: 8px;
padding: 1rem;
margin-top: 1rem;
}
.status-title {
font-size: 0.9rem;
color: var(--text-secondary);
margin-bottom: 0.75rem;
font-family: var(--font-mono);
letter-spacing: 0.05em;
}
.status-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.75rem;
}
.status-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
.status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
position: relative;
}
.status-indicator.active {
background: #10b981; /* Green */
}
.status-indicator.active::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
background: #10b981;
opacity: 0.5;
animation: pulse 2s infinite;
}
.status-indicator.warning {
background: #f59e0b; /* Amber */
}
.status-indicator.offline {
background: #ef4444; /* Red */
}
.status-name {
font-size: 0.85rem;
color: var(--text-secondary);
}
/* Social Links */
.social-links {
display: flex;
gap: 1rem;
margin-top: 1rem;
}
.social-link {
width: 36px;
height: 36px;
border-radius: 50%;
background: rgba(226, 232, 240, 0.05);
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
transition: all 0.3s ease;
}
.social-link:hover {
background: var(--accent-primary);
color: var(--bg-primary);
transform: translateY(-3px);
box-shadow: 0 5px 15px var(--glow-primary);
}
/* Footer Links */
.footer-links-container {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 2rem;
}
.footer-col-title {
color: var(--text-primary);
font-size: 1.1rem;
margin-bottom: 1.5rem;
position: relative;
}
.footer-col-title::after {
content: '';
position: absolute;
left: 0;
bottom: -0.5rem;
width: 30px;
height: 2px;
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
}
.footer-links {
list-style: none;
padding: 0;
margin: 0;
}
.footer-links li {
margin-bottom: 0.75rem;
}
.footer-link {
color: var(--text-secondary);
transition: all 0.3s ease;
position: relative;
display: inline-block;
}
.footer-link:hover {
color: var(--accent-primary);
transform: translateX(3px);
}
.footer-link::before {
content: '→';
position: absolute;
left: -18px;
opacity: 0;
transition: all 0.3s ease;
color: var(--accent-primary);
}
.footer-link:hover::before {
opacity: 1;
left: -15px;
}
/* Newsletter */
.footer-newsletter-text {
color: var(--text-secondary);
font-size: 0.9rem;
margin-bottom: 1rem;
}
.newsletter-input-group {
display: flex;
position: relative;
}
.newsletter-input {
width: 100%;
background: rgba(15, 23, 42, 0.6);
border: 1px solid var(--border-secondary);
padding: 0.75rem 1rem;
border-radius: 8px;
color: var(--text-primary);
font-size: 0.9rem;
outline: none;
transition: all 0.3s ease;
}
.newsletter-input:focus {
border-color: var(--accent-primary);
box-shadow: 0 0 0 2px var(--glow-primary);
}
.newsletter-button {
position: absolute;
right: 5px;
top: 50%;
transform: translateY(-50%);
background: var(--accent-primary);
border: none;
color: var(--bg-primary);
width: 36px;
height: 36px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
}
.newsletter-button:hover {
background: var(--accent-secondary);
transform: translateY(-50%) scale(1.05);
}
/* Footer Bottom */
.footer-bottom {
margin-top: 4rem;
padding-top: 2rem;
border-top: 1px solid var(--border-secondary);
display: flex;
justify-content: space-between;
align-items: center;
color: var(--text-tertiary);
font-size: 0.9rem;
}
.footer-meta-links {
display: flex;
align-items: center;
gap: 0.5rem;
}
.meta-link {
color: var(--text-tertiary);
transition: color 0.3s ease;
}
.meta-link:hover {
color: var(--text-secondary);
}
.link-divider {
color: var(--text-tertiary);
opacity: 0.5;
}
@keyframes pulse {
0% {
opacity: 0.3;
transform: scale(0.8);
}
100% {
opacity: 0.6;
transform: scale(1.2);
}
}
/* Responsive Adjustments */
@media (max-width: 1024px) {
.footer-content {
grid-template-columns: 1fr;
gap: 3rem;
}
.footer-links-container {
grid-template-columns: repeat(2, 1fr);
}
.footer-tagline {
max-width: 100%;
}
}
@media (max-width: 768px) {
.site-footer {
padding: 3rem 0 2rem;
}
.footer-links-container {
grid-template-columns: 1fr;
gap: 2rem;
}
.status-grid {
grid-template-columns: 1fr;
}
.footer-bottom {
flex-direction: column;
gap: 1rem;
text-align: center;
}
}
</style>
<script>
// Create animated nodes in footer
document.addEventListener('DOMContentLoaded', () => {
const footer = document.querySelector('.site-footer');
if (footer) {
// Add network node animations
for (let i = 0; i < 8; i++) {
const node = document.createElement('div');
node.className = 'footer-node';
node.style.cssText = `
position: absolute;
width: 2px;
height: 2px;
background: rgba(226, 232, 240, 0.2);
border-radius: 50%;
left: ${Math.random() * 100}%;
top: ${Math.random() * 100}%;
animation: pulse ${4 + Math.random() * 4}s infinite alternate ease-in-out;
animation-delay: ${Math.random() * 5}s;
`;
footer.appendChild(node);
}
// Newsletter Form Submission
const newsletterForm = document.querySelector('.newsletter-form');
if (newsletterForm) {
newsletterForm.addEventListener('submit', (e) => {
e.preventDefault();
const emailInput = newsletterForm.querySelector('input[type="email"]');
if (emailInput && emailInput.value) {
alert(`Thank you for subscribing with ${emailInput.value}! We'll send you updates soon.`);
emailInput.value = '';
}
});
}
}
});
</script>