1101 lines
31 KiB
Plaintext
1101 lines
31 KiB
Plaintext
---
|
|
// HomePage.astro
|
|
// Premium homepage for LaForceIT tech blog
|
|
|
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
|
import Header from '../components/Header.astro';
|
|
import Footer from '../components/Footer.astro';
|
|
import Terminal from '../components/Terminal.astro';
|
|
import KnowledgeGraph from '../components/KnowledgeGraph.astro';
|
|
import { getCollection } from 'astro:content';
|
|
import { Image } from 'astro:assets';
|
|
import { COMMON_COMMANDS, TERMINAL_CONTENT } from '../config/terminal.js';
|
|
|
|
// Get all blog entries
|
|
const allPosts = await getCollection('posts');
|
|
|
|
// Sort by publication date
|
|
const sortedPosts = allPosts.sort((a, b) => {
|
|
const dateA = a.data.pubDate ? new Date(a.data.pubDate) : new Date(0);
|
|
const dateB = b.data.pubDate ? new Date(b.data.pubDate) : new Date(0);
|
|
return dateB.getTime() - dateA.getTime();
|
|
});
|
|
|
|
// Get recent posts (latest 4)
|
|
const recentPosts = sortedPosts.slice(0, 4);
|
|
|
|
// Prepare terminal commands - now imported from central config
|
|
const terminalCommands = COMMON_COMMANDS;
|
|
|
|
// Prepare graph data for knowledge map
|
|
// Extract categories and tags from posts
|
|
const categories = [...new Set(allPosts.map(post => post.data.category || 'Uncategorized'))];
|
|
const allTags = [...new Set(allPosts.flatMap(post => post.data.tags || []))];
|
|
|
|
// Prepare graph nodes (posts)
|
|
const graphNodes = allPosts.map(post => ({
|
|
id: post.slug,
|
|
label: post.data.title,
|
|
category: post.data.category || 'Uncategorized',
|
|
tags: post.data.tags || []
|
|
}));
|
|
|
|
// Create edges between posts with similar tags or categories
|
|
const graphEdges = [];
|
|
for (let i = 0; i < graphNodes.length; i++) {
|
|
const postA = graphNodes[i];
|
|
|
|
for (let j = i + 1; j < graphNodes.length; j++) {
|
|
const postB = graphNodes[j];
|
|
|
|
// Create edge if posts share at least one tag or same category
|
|
const sharedTags = postA.tags.filter(tag => postB.tags.includes(tag));
|
|
|
|
if (sharedTags.length > 0 || postA.category === postB.category) {
|
|
graphEdges.push({
|
|
source: postA.id,
|
|
target: postB.id,
|
|
strength: sharedTags.length + (postA.category === postB.category ? 1 : 0)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
const graphData = {
|
|
nodes: graphNodes,
|
|
edges: graphEdges
|
|
};
|
|
|
|
// Featured services
|
|
const services = [
|
|
{
|
|
title: "Kubernetes Configurations",
|
|
description: "Production-ready Kubernetes manifests for deploying applications at scale.",
|
|
icon: "server",
|
|
link: "/resources/kubernetes"
|
|
},
|
|
{
|
|
title: "Docker Compose Templates",
|
|
description: "Ready-to-use compose files for quickly deploying services in your home lab.",
|
|
icon: "box",
|
|
link: "/resources/docker-compose"
|
|
},
|
|
{
|
|
title: "Infrastructure Guides",
|
|
description: "Step-by-step tutorials for setting up enterprise-grade home infrastructure.",
|
|
icon: "layers",
|
|
link: "/resources/infrastructure"
|
|
},
|
|
{
|
|
title: "Monitoring Solutions",
|
|
description: "End-to-end monitoring stacks for keeping an eye on your systems.",
|
|
icon: "activity",
|
|
link: "/resources/monitoring"
|
|
}
|
|
];
|
|
|
|
// Tech stack items
|
|
const techStack = [
|
|
{ name: "Kubernetes", icon: "https://cdn.simpleicons.org/kubernetes/326CE5" },
|
|
{ name: "Docker", icon: "https://cdn.simpleicons.org/docker/2496ED" },
|
|
{ name: "Prometheus", icon: "https://cdn.simpleicons.org/prometheus/E6522C" },
|
|
{ name: "Ansible", icon: "https://cdn.simpleicons.org/ansible/EE0000" },
|
|
{ name: "Terraform", icon: "https://cdn.simpleicons.org/terraform/7B42BC" },
|
|
{ name: "ArgoCD", icon: "https://cdn.simpleicons.org/argo/EF7B4D" },
|
|
{ name: "GitHub", icon: "https://cdn.simpleicons.org/github/181717" },
|
|
{ name: "Grafana", icon: "https://cdn.simpleicons.org/grafana/F46800" },
|
|
];
|
|
---
|
|
|
|
<BaseLayout title="LaForceIT - Home Lab & DevOps Insights" description="Dive into enterprise-grade home lab setups, Kubernetes deployments, and DevOps best practices for the modern tech enthusiast">
|
|
<Header slot="header" />
|
|
|
|
<main>
|
|
<!-- Hero Section -->
|
|
<section class="hero-section">
|
|
<div class="hero-bg"></div>
|
|
<div class="container">
|
|
<div class="hero-content">
|
|
<div class="hero-text">
|
|
<div class="hero-subtitle">
|
|
<span class="hero-badge">Technical Articles & Guides</span>
|
|
</div>
|
|
<h1 class="hero-title">
|
|
Exploring
|
|
<span class="gradient-text">advanced</span><br>
|
|
<span class="gradient-text-alt">infrastructure</span> and
|
|
<span class="emphasis">automation</span>
|
|
</h1>
|
|
<p class="hero-description">
|
|
Dive into enterprise-grade home lab setups, Kubernetes deployments, and DevOps best practices for the modern tech enthusiast.
|
|
</p>
|
|
<div class="hero-actions">
|
|
<a href="/blog" class="primary-button">
|
|
<span>Explore Articles</span>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="5" y1="12" x2="19" y2="12"></line>
|
|
<polyline points="12 5 19 12 12 19"></polyline>
|
|
</svg>
|
|
</a>
|
|
<a href="/resources" class="secondary-button">
|
|
<span>View Resources</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="terminal-container">
|
|
<Terminal commands={terminalCommands} title="argobox:~/homelab" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tech-stack">
|
|
<div class="tech-stack-slider">
|
|
<div class="tech-stack-track">
|
|
{techStack.map((tech) => (
|
|
<div class="tech-item">
|
|
<img src={tech.icon} alt={tech.name} class="tech-icon" />
|
|
<span class="tech-name">{tech.name}</span>
|
|
</div>
|
|
))}
|
|
{/* Duplicate for infinite scrolling */}
|
|
{techStack.map((tech) => (
|
|
<div class="tech-item">
|
|
<img src={tech.icon} alt={tech.name} class="tech-icon" />
|
|
<span class="tech-name">{tech.name}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Featured Services Section -->
|
|
<section class="services-section">
|
|
<div class="container">
|
|
<div class="section-header">
|
|
<h2 class="section-title">Technical Resources</h2>
|
|
<p class="section-description">
|
|
Enterprise-grade solutions for your home lab and DevOps workflows
|
|
</p>
|
|
</div>
|
|
|
|
<div class="services-grid">
|
|
{services.map((service) => (
|
|
<a href={service.link} class="service-card">
|
|
<div class="service-icon">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
{service.icon === 'server' && (
|
|
<>
|
|
<rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect>
|
|
<rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect>
|
|
<line x1="6" y1="6" x2="6.01" y2="6"></line>
|
|
<line x1="6" y1="18" x2="6.01" y2="18"></line>
|
|
</>
|
|
)}
|
|
{service.icon === 'box' && (
|
|
<>
|
|
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
|
|
<polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline>
|
|
<line x1="12" y1="22.08" x2="12" y2="12"></line>
|
|
</>
|
|
)}
|
|
{service.icon === 'layers' && (
|
|
<>
|
|
<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
|
|
<polyline points="2 17 12 22 22 17"></polyline>
|
|
<polyline points="2 12 12 17 22 12"></polyline>
|
|
</>
|
|
)}
|
|
{service.icon === 'activity' && (
|
|
<>
|
|
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>
|
|
</>
|
|
)}
|
|
</svg>
|
|
</div>
|
|
<h3 class="service-title">{service.title}</h3>
|
|
<p class="service-description">{service.description}</p>
|
|
<div class="service-link">
|
|
<span>Explore</span>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
|
|
<polyline points="15 3 21 3 21 9"></polyline>
|
|
<line x1="10" y1="14" x2="21" y2="3"></line>
|
|
</svg>
|
|
</div>
|
|
</a>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Knowledge Graph Section -->
|
|
<section class="graph-container-section">
|
|
<div class="container">
|
|
<div class="section-header">
|
|
<h2 class="section-title">Knowledge Graph</h2>
|
|
<p class="section-description">
|
|
Explore connections between articles based on topics and categories
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="full-width-container">
|
|
<KnowledgeGraph graphData={graphData} height="600px" />
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Recent Articles Section -->
|
|
<section class="recent-articles-section">
|
|
<div class="container">
|
|
<div class="section-header">
|
|
<h2 class="section-title">Recent Articles</h2>
|
|
<p class="section-description">
|
|
Latest insights and guides from the LaForceIT blog
|
|
</p>
|
|
</div>
|
|
|
|
<div class="articles-grid">
|
|
{recentPosts.map((post) => (
|
|
<a href={`/posts/${post.slug}/`} class="article-card">
|
|
<div class="article-image-container">
|
|
<img
|
|
src={post.data.heroImage || '/images/placeholders/default.jpg'}
|
|
alt={post.data.title}
|
|
class="article-image"
|
|
width="600"
|
|
height="300"
|
|
loading="lazy"
|
|
/>
|
|
{post.data.category && (
|
|
<span class="article-category">{post.data.category}</span>
|
|
)}
|
|
</div>
|
|
<div class="article-content">
|
|
<div class="article-meta">
|
|
<time datetime={post.data.pubDate?.toISOString()}>
|
|
{post.data.pubDate ? new Date(post.data.pubDate).toLocaleDateString('en-us', {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric'
|
|
}) : 'No date'}
|
|
</time>
|
|
<span class="article-read-time">{post.data.readTime || '5 min read'}</span>
|
|
</div>
|
|
<h3 class="article-title">{post.data.title}</h3>
|
|
<p class="article-excerpt">{post.data.description || 'No description available'}</p>
|
|
<div class="article-footer">
|
|
<div class="article-tags">
|
|
{post.data.tags && post.data.tags.slice(0, 2).map((tag) => (
|
|
<span class="article-tag">{tag}</span>
|
|
))}
|
|
{post.data.tags && post.data.tags.length > 2 && (
|
|
<span class="article-tag">+{post.data.tags.length - 2}</span>
|
|
)}
|
|
</div>
|
|
<span class="read-more">Read More</span>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
))}
|
|
</div>
|
|
|
|
<div class="view-all-container">
|
|
<a href="/blog" class="view-all-button">
|
|
<span>View All Articles</span>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="5" y1="12" x2="19" y2="12"></line>
|
|
<polyline points="12 5 19 12 12 19"></polyline>
|
|
</svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- CTA Section -->
|
|
<section class="cta-section">
|
|
<div class="cta-bg"></div>
|
|
<div class="container">
|
|
<div class="cta-container">
|
|
<h2 class="cta-title">Ready to upgrade your home lab?</h2>
|
|
<p class="cta-description">
|
|
Get access to premium resources, configuration templates, and step-by-step guides to take your infrastructure to the next level.
|
|
</p>
|
|
<div class="cta-actions">
|
|
<a href="/resources" class="cta-primary-button">
|
|
<span>Explore Resources</span>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="5" y1="12" x2="19" y2="12"></line>
|
|
<polyline points="12 5 19 12 12 19"></polyline>
|
|
</svg>
|
|
</a>
|
|
<a href="/contact" class="cta-secondary-button">
|
|
<span>Get in Touch</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Terminal Section -->
|
|
<section class="terminal-section">
|
|
<div class="container">
|
|
<div class="row">
|
|
<div class="col-12 col-md-6">
|
|
<Terminal
|
|
title="argobox:~/kubernetes"
|
|
promptPrefix={TERMINAL_DEFAULTS.promptPrefix}
|
|
height="400px"
|
|
command="kubectl get pods -A | head -8"
|
|
output={`NAMESPACE NAME READY STATUS RESTARTS AGE
|
|
kube-system coredns-66bff467f8-8p7z2 1/1 Running 0 15d
|
|
kube-system coredns-66bff467f8-v68vr 1/1 Running 0 15d
|
|
kube-system etcd-control-plane 1/1 Running 0 15d
|
|
kube-system kube-apiserver-control-plane 1/1 Running 0 15d
|
|
kube-system kube-controller-manager-control-plane 1/1 Running 0 15d
|
|
kube-system kube-proxy-c84qf 1/1 Running 0 15d
|
|
kube-system kube-scheduler-control-plane 1/1 Running 0 15d`}
|
|
/>
|
|
</div>
|
|
<div class="col-12 col-md-6">
|
|
<Terminal
|
|
title="argobox:~/system"
|
|
promptPrefix={TERMINAL_DEFAULTS.promptPrefix}
|
|
height="400px"
|
|
content={SYSTEM_MONITOR_SEQUENCE.map(item => `<div class="term-blue">${item.prompt}</div><span>$</span> <span class="term-bold">${item.command}</span>\n${item.output.join('\n')}`).join('\n\n')}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<Footer slot="footer" />
|
|
</BaseLayout>
|
|
|
|
<style>
|
|
/* Hero Section */
|
|
.hero-section {
|
|
position: relative;
|
|
padding: 8rem 0 6rem;
|
|
overflow: hidden;
|
|
background: linear-gradient(to bottom, var(--bg-secondary), var(--bg-primary));
|
|
}
|
|
|
|
.hero-bg {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-image:
|
|
radial-gradient(circle at 20% 35%, rgba(6, 182, 212, 0.1) 0%, transparent 50%),
|
|
radial-gradient(circle at 75% 15%, rgba(59, 130, 246, 0.1) 0%, transparent 45%),
|
|
radial-gradient(circle at 85% 70%, rgba(139, 92, 246, 0.1) 0%, transparent 40%);
|
|
z-index: -1;
|
|
}
|
|
|
|
.hero-bg::before {
|
|
content: "";
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-image:
|
|
linear-gradient(rgba(226, 232, 240, 0.03) 1px, transparent 1px),
|
|
linear-gradient(90deg, rgba(226, 232, 240, 0.03) 1px, transparent 1px);
|
|
background-size: 30px 30px;
|
|
}
|
|
|
|
.hero-content {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 3rem;
|
|
align-items: center;
|
|
}
|
|
|
|
.hero-text {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.hero-subtitle {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.hero-badge {
|
|
background: rgba(6, 182, 212, 0.1);
|
|
color: var(--accent-primary);
|
|
padding: 0.5rem 1rem;
|
|
border-radius: 30px;
|
|
font-size: 0.85rem;
|
|
font-weight: 500;
|
|
letter-spacing: 0.05em;
|
|
font-family: var(--font-mono);
|
|
border: 1px solid rgba(6, 182, 212, 0.2);
|
|
}
|
|
|
|
.hero-title {
|
|
font-size: clamp(2.5rem, 5vw, 3.5rem);
|
|
line-height: 1.1;
|
|
margin: 0;
|
|
}
|
|
|
|
.gradient-text {
|
|
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
color: transparent;
|
|
display: inline-block;
|
|
}
|
|
|
|
.gradient-text-alt {
|
|
background: linear-gradient(90deg, var(--accent-secondary), var(--accent-tertiary));
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
color: transparent;
|
|
display: inline-block;
|
|
}
|
|
|
|
.emphasis {
|
|
position: relative;
|
|
display: inline-block;
|
|
}
|
|
|
|
.emphasis::after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: -5px;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 4px;
|
|
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.hero-description {
|
|
color: var(--text-secondary);
|
|
font-size: clamp(1rem, 2vw, 1.25rem);
|
|
line-height: 1.6;
|
|
max-width: 540px;
|
|
margin: 0;
|
|
}
|
|
|
|
.hero-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 1rem;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.primary-button {
|
|
padding: 0.8rem 1.5rem;
|
|
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
|
|
color: var(--bg-primary);
|
|
font-weight: 600;
|
|
border-radius: 8px;
|
|
border: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
text-decoration: none;
|
|
transition: all 0.3s ease;
|
|
box-shadow: 0 4px 15px rgba(6, 182, 212, 0.3);
|
|
}
|
|
|
|
.primary-button:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 8px 20px rgba(6, 182, 212, 0.4);
|
|
}
|
|
|
|
.secondary-button {
|
|
padding: 0.8rem 1.5rem;
|
|
background: rgba(226, 232, 240, 0.1);
|
|
color: var(--text-primary);
|
|
font-weight: 600;
|
|
border-radius: 8px;
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
text-decoration: none;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.secondary-button:hover {
|
|
background: rgba(226, 232, 240, 0.2);
|
|
border-color: rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.terminal-container {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* Tech Stack Slider */
|
|
.tech-stack {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
background: linear-gradient(0deg, rgba(13, 18, 30, 0.9), transparent);
|
|
padding: 1.5rem 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.tech-stack-slider {
|
|
width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.tech-stack-track {
|
|
display: flex;
|
|
animation: scroll 30s linear infinite;
|
|
}
|
|
|
|
.tech-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
margin: 0 1.5rem;
|
|
white-space: nowrap;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.tech-icon {
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
|
|
.tech-name {
|
|
font-size: 0.9rem;
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
@keyframes scroll {
|
|
0% {
|
|
transform: translateX(0);
|
|
}
|
|
100% {
|
|
transform: translateX(-50%);
|
|
}
|
|
}
|
|
|
|
/* Services Section */
|
|
.services-section {
|
|
padding: 6rem 0;
|
|
background: var(--bg-primary);
|
|
position: relative;
|
|
}
|
|
|
|
.section-header {
|
|
text-align: center;
|
|
max-width: 800px;
|
|
margin: 0 auto 4rem;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: clamp(1.75rem, 3vw, 2.5rem);
|
|
margin-bottom: 1rem;
|
|
position: relative;
|
|
display: inline-block;
|
|
}
|
|
|
|
.section-title::after {
|
|
content: '';
|
|
position: absolute;
|
|
height: 4px;
|
|
width: 60px;
|
|
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
|
|
bottom: -10px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.section-description {
|
|
color: var(--text-secondary);
|
|
max-width: 600px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.services-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
gap: 2rem;
|
|
margin-top: 2rem;
|
|
}
|
|
|
|
.service-card {
|
|
background: rgba(30, 41, 59, 0.5);
|
|
border: 1px solid var(--border-primary);
|
|
border-radius: 12px;
|
|
padding: 2rem;
|
|
transition: all 0.3s ease;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1.25rem;
|
|
text-decoration: none;
|
|
color: var(--text-primary);
|
|
position: relative;
|
|
overflow: hidden;
|
|
height: 100%;
|
|
}
|
|
|
|
.service-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background: linear-gradient(135deg, rgba(6, 182, 212, 0.05), rgba(139, 92, 246, 0.05));
|
|
z-index: -1;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.service-card:hover {
|
|
transform: translateY(-5px);
|
|
border-color: rgba(6, 182, 212, 0.3);
|
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.service-card:hover::before {
|
|
opacity: 1;
|
|
}
|
|
|
|
.service-icon {
|
|
background: rgba(6, 182, 212, 0.1);
|
|
width: 56px;
|
|
height: 56px;
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: var(--accent-primary);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.service-card:hover .service-icon {
|
|
background: var(--accent-primary);
|
|
color: var(--bg-primary);
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.service-title {
|
|
font-size: 1.25rem;
|
|
margin: 0;
|
|
}
|
|
|
|
.service-description {
|
|
color: var(--text-secondary);
|
|
font-size: 0.95rem;
|
|
margin: 0;
|
|
line-height: 1.6;
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.service-link {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
color: var(--accent-primary);
|
|
font-weight: 500;
|
|
font-size: 0.95rem;
|
|
margin-top: auto;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.service-card:hover .service-link {
|
|
transform: translateX(5px);
|
|
}
|
|
|
|
/* Knowledge Graph Section */
|
|
.graph-container-section {
|
|
padding: 4rem 0;
|
|
background: linear-gradient(180deg, var(--bg-primary), var(--bg-secondary), var(--bg-primary));
|
|
position: relative;
|
|
}
|
|
|
|
.full-width-container {
|
|
max-width: 1440px;
|
|
margin: 0 auto;
|
|
padding: 0 1rem;
|
|
}
|
|
|
|
/* Recent Articles Section */
|
|
.recent-articles-section {
|
|
padding: 6rem 0;
|
|
background: var(--bg-primary);
|
|
position: relative;
|
|
}
|
|
|
|
.articles-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: 2rem;
|
|
margin-top: 2rem;
|
|
}
|
|
|
|
.article-card {
|
|
background: var(--card-bg);
|
|
border-radius: 12px;
|
|
border: 1px solid var(--card-border);
|
|
overflow: hidden;
|
|
transition: all 0.3s ease;
|
|
position: relative;
|
|
z-index: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
text-decoration: none;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.article-card:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 10px 30px rgba(6, 182, 212, 0.1);
|
|
border-color: rgba(6, 182, 212, 0.3);
|
|
}
|
|
|
|
.article-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background: linear-gradient(135deg, rgba(6, 182, 212, 0.05), rgba(139, 92, 246, 0.05));
|
|
z-index: -1;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.article-card:hover::before {
|
|
opacity: 1;
|
|
}
|
|
|
|
.article-image-container {
|
|
position: relative;
|
|
}
|
|
|
|
.article-image {
|
|
width: 100%;
|
|
height: 200px;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.article-category {
|
|
position: absolute;
|
|
top: 15px;
|
|
right: 15px;
|
|
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
|
|
color: var(--bg-primary);
|
|
padding: 0.35rem 0.8rem;
|
|
border-radius: 20px;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
box-shadow: 0 2px 10px rgba(6, 182, 212, 0.25);
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
.article-content {
|
|
padding: 1.5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.article-meta {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 1rem;
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.article-title {
|
|
font-size: 1.25rem;
|
|
margin-bottom: 0.75rem;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.article-excerpt {
|
|
color: var(--text-secondary);
|
|
font-size: 0.9rem;
|
|
margin-bottom: 1.5rem;
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 3;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.article-footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-top: auto;
|
|
}
|
|
|
|
.article-tags {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.article-tag {
|
|
background: rgba(255, 255, 255, 0.05);
|
|
color: var(--text-secondary);
|
|
padding: 0.2rem 0.5rem;
|
|
border-radius: 4px;
|
|
font-size: 0.7rem;
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
.read-more {
|
|
color: var(--accent-primary);
|
|
font-weight: 500;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.read-more::after {
|
|
content: '→';
|
|
transition: transform 0.3s ease;
|
|
}
|
|
|
|
.article-card:hover .read-more::after {
|
|
transform: translateX(3px);
|
|
}
|
|
|
|
.view-all-container {
|
|
display: flex;
|
|
justify-content: center;
|
|
margin-top: 3rem;
|
|
}
|
|
|
|
.view-all-button {
|
|
padding: 0.8rem 1.5rem;
|
|
background: rgba(226, 232, 240, 0.05);
|
|
color: var(--text-primary);
|
|
font-weight: 600;
|
|
border-radius: 8px;
|
|
border: 1px solid var(--border-primary);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
text-decoration: none;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.view-all-button:hover {
|
|
background: rgba(226, 232, 240, 0.1);
|
|
transform: translateY(-3px);
|
|
}
|
|
|
|
/* CTA Section */
|
|
.cta-section {
|
|
padding: 6rem 0;
|
|
position: relative;
|
|
}
|
|
|
|
.cta-bg {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: linear-gradient(135deg, rgba(6, 182, 212, 0.05), rgba(139, 92, 246, 0.05));
|
|
z-index: -1;
|
|
}
|
|
|
|
.cta-bg::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-image:
|
|
linear-gradient(rgba(226, 232, 240, 0.03) 1px, transparent 1px),
|
|
linear-gradient(90deg, rgba(226, 232, 240, 0.03) 1px, transparent 1px);
|
|
background-size: 30px 30px;
|
|
}
|
|
|
|
.cta-container {
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
text-align: center;
|
|
background: rgba(30, 41, 59, 0.7);
|
|
backdrop-filter: blur(10px);
|
|
border: 1px solid var(--border-primary);
|
|
border-radius: 16px;
|
|
padding: 3rem;
|
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.cta-title {
|
|
font-size: clamp(1.5rem, 3vw, 2.25rem);
|
|
margin-bottom: 1.5rem;
|
|
background: linear-gradient(90deg, var(--accent-primary), var(--accent-tertiary));
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
color: transparent;
|
|
display: inline-block;
|
|
}
|
|
|
|
.cta-description {
|
|
color: var(--text-secondary);
|
|
font-size: clamp(1rem, 2vw, 1.1rem);
|
|
margin-bottom: 2rem;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.cta-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 1rem;
|
|
justify-content: center;
|
|
}
|
|
|
|
.cta-primary-button {
|
|
padding: 0.8rem 1.5rem;
|
|
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
|
|
color: var(--bg-primary);
|
|
font-weight: 600;
|
|
border-radius: 8px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
text-decoration: none;
|
|
transition: all 0.3s ease;
|
|
box-shadow: 0 4px 15px rgba(6, 182, 212, 0.3);
|
|
}
|
|
|
|
.cta-primary-button:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 8px 20px rgba(6, 182, 212, 0.4);
|
|
}
|
|
|
|
.cta-secondary-button {
|
|
padding: 0.8rem 1.5rem;
|
|
background: rgba(226, 232, 240, 0.1);
|
|
color: var(--text-primary);
|
|
font-weight: 600;
|
|
border-radius: 8px;
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
text-decoration: none;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.cta-secondary-button:hover {
|
|
background: rgba(226, 232, 240, 0.2);
|
|
}
|
|
|
|
/* Terminal Section */
|
|
.terminal-section {
|
|
padding: 6rem 0;
|
|
background: var(--bg-primary);
|
|
position: relative;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: clamp(1.75rem, 3vw, 2.5rem);
|
|
margin-bottom: 1rem;
|
|
position: relative;
|
|
display: inline-block;
|
|
}
|
|
|
|
.section-title::after {
|
|
content: '';
|
|
position: absolute;
|
|
height: 4px;
|
|
width: 60px;
|
|
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
|
|
bottom: -10px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
border-radius: 2px;
|
|
}
|
|
|
|
/* Responsive Design */
|
|
@media (max-width: 1024px) {
|
|
.hero-content {
|
|
grid-template-columns: 1fr;
|
|
gap: 3rem;
|
|
}
|
|
|
|
.hero-text {
|
|
text-align: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.hero-description {
|
|
max-width: 100%;
|
|
}
|
|
|
|
.cta-container {
|
|
padding: 2rem;
|
|
margin: 0 1rem;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.hero-section {
|
|
padding: 6rem 0 8rem;
|
|
}
|
|
|
|
.articles-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.hero-actions {
|
|
justify-content: center;
|
|
}
|
|
|
|
.services-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.cta-container {
|
|
padding: 2rem 1rem;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
// Animate neural nodes in hero section
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const heroSection = document.querySelector('.hero-section');
|
|
|
|
if (heroSection) {
|
|
// Create animated nodes
|
|
for (let i = 0; i < 15; i++) {
|
|
const node = document.createElement('div');
|
|
node.classList.add('neural-node');
|
|
|
|
// Set random positions
|
|
node.style.position = 'absolute';
|
|
node.style.width = `${Math.random() * 2 + 1}px`;
|
|
node.style.height = node.style.width;
|
|
node.style.background = 'rgba(226, 232, 240, 0.15)';
|
|
node.style.borderRadius = '50%';
|
|
node.style.top = `${Math.random() * 100}%`;
|
|
node.style.left = `${Math.random() * 100}%`;
|
|
node.style.boxShadow = '0 0 10px rgba(6, 182, 212, 0.5)';
|
|
node.style.zIndex = '-1';
|
|
|
|
// Set animation properties
|
|
node.style.animation = `pulse ${4 + Math.random() * 4}s infinite alternate ease-in-out`;
|
|
node.style.animationDelay = `${Math.random() * 5}s`;
|
|
|
|
heroSection.appendChild(node);
|
|
}
|
|
}
|
|
});
|
|
</script> |