refactor: Rebrand site from LaForceIT to ArgoBox

This commit is contained in:
Daniel LaForce 2025-04-27 16:52:01 -06:00
parent 2415775ba5
commit fcf2166676
30 changed files with 72 additions and 717 deletions

View File

@ -7,7 +7,7 @@ import tailwind from '@astrojs/tailwind';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
site: 'https://laforceit-blog.pages.dev', // Your current Cloudflare site site: 'https://argobox.com', // Updated site URL for ArgoBox
output: 'static', output: 'static',
// adapter: cloudflare(), // Commented out for local development // adapter: cloudflare(), // Commented out for local development
integrations: [ integrations: [

View File

@ -126,7 +126,7 @@
</div> </div>
<div class="footer-bottom"> <div class="footer-bottom">
<p>© All rights reserved. LaForceIT.com</p> <p>© All rights reserved. ArgoBox.com</p>
<p class="disclaimer">Custom-built with HTML, CSS, and JavaScript.</p> <p class="disclaimer">Custom-built with HTML, CSS, and JavaScript.</p>
</div> </div>
</div> </div>

View File

@ -9,12 +9,12 @@ import Terminal from '../components/Terminal.astro';
const terminalCommands = [ const terminalCommands = [
{ {
prompt: "[system@argobox]$ ", prompt: "[system@argobox]$ ",
command: "find /var/www/laforceit -name \"requested-page\"", command: "find /var/www/ArgoBox -name \"requested-page\"",
output: ["find: No matches found"] output: ["find: No matches found"]
}, },
{ {
prompt: "[system@argobox]$ ", prompt: "[system@argobox]$ ",
command: "grep -r \"requested-page\" /var/www/laforceit", command: "grep -r \"requested-page\" /var/www/ArgoBox",
output: ["No matches found in site content"] output: ["No matches found in site content"]
}, },
{ {
@ -53,7 +53,7 @@ const errorMessages = [
const randomError = errorMessages[Math.floor(Math.random() * errorMessages.length)]; const randomError = errorMessages[Math.floor(Math.random() * errorMessages.length)];
--- ---
<BaseLayout title="404 - Page Not Found | LaForceIT" description="The requested page was not found on the LaForceIT tech blog."> <BaseLayout title="404 - Page Not Found | ArgoBox" description="The requested page was not found on the ArgoBox tech blog.">
<Header slot="header" /> <Header slot="header" />
<main class="error-container"> <main class="error-container">

View File

@ -91,7 +91,7 @@ const services = [
<span class="logo-text">LF</span> <span class="logo-text">LF</span>
<div class="logo-glow"></div> <div class="logo-glow"></div>
</div> </div>
<span class="footer-brand-name">LaForceIT</span> <span class="footer-brand-name">ArgoBox</span>
</div> </div>
<p class="footer-tagline"> <p class="footer-tagline">
Enterprise-grade home lab infrastructure, Kubernetes deployments, and DevOps automation for the modern tech enthusiast. Enterprise-grade home lab infrastructure, Kubernetes deployments, and DevOps automation for the modern tech enthusiast.
@ -168,7 +168,7 @@ const services = [
<!-- Footer Bottom --> <!-- Footer Bottom -->
<div class="footer-bottom"> <div class="footer-bottom">
<div class="copyright"> <div class="copyright">
&copy; {currentYear} LaForceIT by Daniel LaForce. All rights reserved. &copy; {currentYear} ArgoBox by Daniel LaForce. All rights reserved.
</div> </div>
<div class="footer-meta-links"> <div class="footer-meta-links">
<a href="/privacy" class="meta-link">Privacy Policy</a> <a href="/privacy" class="meta-link">Privacy Policy</a>

View File

@ -10,8 +10,8 @@ const navItems = [
{ name: 'Tech Stack', url: '/tech-stack' }, { name: 'Tech Stack', url: '/tech-stack' },
{ name: 'Home Lab', url: 'https://argobox.com' }, { name: 'Home Lab', url: 'https://argobox.com' },
{ name: 'Resources', url: '/resources' }, { name: 'Resources', url: '/resources' },
{ name: 'About', url: 'https://laforceit.com' }, { name: 'About', url: 'https://ArgoBox.com' },
{ name: 'Contact', url: 'https://laforceit.com/index.html#contact' } { name: 'Contact', url: 'https://ArgoBox.com/index.html#contact' }
]; ];
// Get current URL path for active nav item highlighting // Get current URL path for active nav item highlighting
@ -24,7 +24,7 @@ const currentPath = Astro.url.pathname;
<a href="/" class="logo-link"> <a href="/" class="logo-link">
<div class="logo">LF</div> <div class="logo">LF</div>
<div class="site-name"> <div class="site-name">
<span class="site-title">LaForceIT</span> <span class="site-title">ArgoBox</span>
<span class="site-subtitle">Infrastructure & Automation</span> <span class="site-subtitle">Infrastructure & Automation</span>
</div> </div>
</a> </a>

View File

@ -1,6 +1,6 @@
--- ---
// HomePage.astro // HomePage.astro
// Premium homepage for LaForceIT tech blog // Premium homepage for ArgoBox tech blog
import BaseLayout from '../layouts/BaseLayout.astro'; import BaseLayout from '../layouts/BaseLayout.astro';
import Header from '../components/Header.astro'; import Header from '../components/Header.astro';
@ -107,7 +107,7 @@ const techStack = [
]; ];
--- ---
<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"> <BaseLayout title="ArgoBox - 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" /> <Header slot="header" />
<main> <main>
@ -251,7 +251,7 @@ const techStack = [
<div class="section-header"> <div class="section-header">
<h2 class="section-title">Recent Articles</h2> <h2 class="section-title">Recent Articles</h2>
<p class="section-description"> <p class="section-description">
Latest insights and guides from the LaForceIT blog Latest insights and guides from the ArgoBox blog
</p> </p>
</div> </div>

View File

@ -5,7 +5,7 @@
// Default terminal prompt settings // Default terminal prompt settings
export const TERMINAL_DEFAULTS = { export const TERMINAL_DEFAULTS = {
promptPrefix: "[laforceit@argobox]", promptPrefix: "[user@argobox]",
title: "argobox:~/blog", title: "argobox:~/blog",
theme: "dark", // Default theme (dark or light) theme: "dark", // Default theme (dark or light)
height: "auto", height: "auto",
@ -20,11 +20,11 @@ export const COMMON_COMMANDS = [
command: "ls -la ./infrastructure", command: "ls -la ./infrastructure",
output: [ output: [
"total 20", "total 20",
"drwxr-xr-x 5 laforceit users 4096 Apr 23 09:15 <span class='highlight'>kubernetes/</span>", "drwxr-xr-x 5 ArgoBox users 4096 Apr 23 09:15 <span class='highlight'>kubernetes/</span>",
"drwxr-xr-x 3 laforceit users 4096 Apr 20 17:22 <span class='highlight'>docker/</span>", "drwxr-xr-x 3 ArgoBox users 4096 Apr 20 17:22 <span class='highlight'>docker/</span>",
"drwxr-xr-x 2 laforceit users 4096 Apr 19 14:30 <span class='highlight'>networking/</span>", "drwxr-xr-x 2 ArgoBox users 4096 Apr 19 14:30 <span class='highlight'>networking/</span>",
"drwxr-xr-x 4 laforceit users 4096 Apr 22 21:10 <span class='highlight'>monitoring/</span>", "drwxr-xr-x 4 ArgoBox users 4096 Apr 22 21:10 <span class='highlight'>monitoring/</span>",
"drwxr-xr-x 3 laforceit users 4096 Apr 21 16:45 <span class='highlight'>storage/</span>", "drwxr-xr-x 3 ArgoBox users 4096 Apr 21 16:45 <span class='highlight'>storage/</span>",
] ]
}, },
{ {
@ -158,7 +158,7 @@ export const BLOG_DEPLOYMENT_SEQUENCE = [
"<span class='term-green'>✓</span> Upload complete", "<span class='term-green'>✓</span> Upload complete",
"<span class='term-green'>✓</span> CDN cache invalidated", "<span class='term-green'>✓</span> CDN cache invalidated",
"<span class='term-green'>✓</span> DNS configuration verified", "<span class='term-green'>✓</span> DNS configuration verified",
"<span class='term-green'>✓</span> Blog is live at https://laforceit.com!" "<span class='term-green'>✓</span> Blog is live at https://ArgoBox.com!"
] ]
} }
]; ];
@ -197,7 +197,7 @@ export const K8S_OPERATION_SEQUENCE = [
command: "kubectl get ingress -n blog-prod", command: "kubectl get ingress -n blog-prod",
output: [ output: [
"NAME CLASS HOSTS ADDRESS PORTS AGE", "NAME CLASS HOSTS ADDRESS PORTS AGE",
"blog-ingress <none> blog.laforceit.com 192.168.1.50 80, 443 42s" "blog-ingress <none> blog.ArgoBox.com 192.168.1.50 80, 443 42s"
] ]
} }
]; ];
@ -207,14 +207,14 @@ export const TERMINAL_CONTENT = {
fileExplorer: `<div class="term-blue">${TERMINAL_DEFAULTS.promptPrefix}</div><span>$</span> <span class="term-bold">ls -la</span> fileExplorer: `<div class="term-blue">${TERMINAL_DEFAULTS.promptPrefix}</div><span>$</span> <span class="term-bold">ls -la</span>
total 42 total 42
drwxr-xr-x 6 laforceit users 4096 Nov 7 22:15 . drwxr-xr-x 6 ArgoBox users 4096 Nov 7 22:15 .
drwxr-xr-x 12 laforceit users 4096 Nov 7 20:32 .. drwxr-xr-x 12 ArgoBox users 4096 Nov 7 20:32 ..
-rw-r--r-- 1 laforceit users 182 Nov 7 22:15 .astro -rw-r--r-- 1 ArgoBox users 182 Nov 7 22:15 .astro
drwxr-xr-x 2 laforceit users 4096 Nov 7 21:03 components drwxr-xr-x 2 ArgoBox users 4096 Nov 7 21:03 components
drwxr-xr-x 3 laforceit users 4096 Nov 7 21:14 content drwxr-xr-x 3 ArgoBox users 4096 Nov 7 21:14 content
drwxr-xr-x 4 laforceit users 4096 Nov 7 21:42 layouts drwxr-xr-x 4 ArgoBox users 4096 Nov 7 21:42 layouts
drwxr-xr-x 5 laforceit users 4096 Nov 7 22:10 pages drwxr-xr-x 5 ArgoBox users 4096 Nov 7 22:10 pages
-rw-r--r-- 1 laforceit users 1325 Nov 7 22:12 package.json`, -rw-r--r-- 1 ArgoBox users 1325 Nov 7 22:12 package.json`,
tags: `<div class="term-blue">${TERMINAL_DEFAULTS.promptPrefix}</div><span>$</span> <span class="term-bold">cat ./content/tags.txt</span> tags: `<div class="term-blue">${TERMINAL_DEFAULTS.promptPrefix}</div><span>$</span> <span class="term-bold">cat ./content/tags.txt</span>
@ -270,7 +270,7 @@ Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 2.12 KiB | 2.12 MiB/s, done. Writing objects: 100% (5/5), 2.12 KiB | 2.12 MiB/s, done.
Total 5 (delta 3), reused 0 (delta 0), pack-reused 0 Total 5 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (3/3), completed with 3 local objects. remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
<span class="term-green"></span> Deployed to https://laforceit.com <span class="term-green"></span> Deployed to https://ArgoBox.com
<span class="term-green"></span> Article published successfully`, <span class="term-green"></span> Article published successfully`,
k8sInstall: `<div class="term-blue">${TERMINAL_DEFAULTS.promptPrefix}</div><span>$</span> <span class="term-bold">curl -sfL https://get.k3s.io | sh -</span> k8sInstall: `<div class="term-blue">${TERMINAL_DEFAULTS.promptPrefix}</div><span>$</span> <span class="term-bold">curl -sfL https://get.k3s.io | sh -</span>
@ -334,12 +334,12 @@ volumes:
postgres_data: postgres_data:
<div class="term-blue">${TERMINAL_DEFAULTS.promptPrefix}</div><span>$</span> <span class="term-bold">docker-compose up -d</span> <div class="term-blue">${TERMINAL_DEFAULTS.promptPrefix}</div><span>$</span> <span class="term-bold">docker-compose up -d</span>
Creating network "laforceit-blog_default" with the default driver Creating network "ArgoBox-blog_default" with the default driver
Creating volume "laforceit-blog_postgres_data" with default driver Creating volume "ArgoBox-blog_postgres_data" with default driver
Pulling blog (node:18-alpine)... Pulling blog (node:18-alpine)...
Pulling db (postgres:14-alpine)... Pulling db (postgres:14-alpine)...
Creating laforceit-blog_db_1 ... done Creating ArgoBox-blog_db_1 ... done
Creating laforceit-blog_blog_1 ... done` Creating ArgoBox-blog_blog_1 ... done`
}; };
// Helper function to create terminal presets // Helper function to create terminal presets
@ -407,8 +407,8 @@ a834fa3ede06 redis:6 "docker-entrypoint.s…" Up 2 days
default: default:
return { return {
title: TERMINAL_DEFAULTS.title, title: TERMINAL_DEFAULTS.title,
command: "echo 'Hello from LaForceIT Terminal'", command: "echo 'Hello from ArgoBox Terminal'",
output: "Hello from LaForceIT Terminal" output: "Hello from ArgoBox Terminal"
}; };
} }
} }

View File

@ -46,7 +46,7 @@ graph TD
### Blog Repository Structure ### Blog Repository Structure
``` ```
laforceit-blog/ ArgoBox-blog/
├── src/content/ ├── src/content/
│ ├── posts -> /mnt/synology/obsidian/Public/Blog/posts │ ├── posts -> /mnt/synology/obsidian/Public/Blog/posts
│ ├── projects -> /mnt/synology/obsidian/Public/Blog/projects │ ├── projects -> /mnt/synology/obsidian/Public/Blog/projects
@ -63,8 +63,8 @@ laforceit-blog/
1. Clone the Blog Repository 1. Clone the Blog Repository
```bash ```bash
git clone https://git.argobox.com/KeyArgo/laforceit-blog.git git clone https://git.argobox.com/KeyArgo/ArgoBox-blog.git
cd laforceit-blog cd ArgoBox-blog
``` ```
2. Create the Scripts Directory 2. Create the Scripts Directory

View File

@ -7,7 +7,7 @@ draft: true
# Blog Posts Collection # Blog Posts Collection
This directory contains blog posts for the LaForceIT digital garden. This directory contains blog posts for the ArgoBox digital garden.
## Content Guidelines ## Content Guidelines

View File

@ -128,7 +128,7 @@ You can customize FileBrowser by modifying the configuration file. Here's what m
"header": "" "header": ""
}, },
"branding": { "branding": {
"name": "LaForceIT Files", "name": "ArgoBox Files",
"disableExternal": false, "disableExternal": false,
"files": "", "files": "",
"theme": "dark" "theme": "dark"

View File

@ -170,7 +170,7 @@ After installation, you'll be greeted with Gitea's setup page. Here are the sett
1. **Database Settings**: If you followed the Docker Compose example, your database is already configured. 1. **Database Settings**: If you followed the Docker Compose example, your database is already configured.
2. **General Settings**: 2. **General Settings**:
- Set your site title (e.g., "LaForceIT Git") - Set your site title (e.g., "ArgoBox Git")
- Disable user registration unless you're hosting for multiple people - Disable user registration unless you're hosting for multiple people
- Enable caching to improve performance - Enable caching to improve performance

View File

@ -64,13 +64,13 @@ Once installed, you can customize your Quartz configuration in the `quartz.confi
// quartz.config.ts // quartz.config.ts
const config: QuartzConfig = { const config: QuartzConfig = {
configuration: { configuration: {
pageTitle: "LaForceIT Digital Garden", pageTitle: "ArgoBox Digital Garden",
enableSPA: true, enableSPA: true,
enablePopovers: true, enablePopovers: true,
analytics: { analytics: {
provider: "plausible", provider: "plausible",
}, },
baseUrl: "blog.laforceit.com", baseUrl: "blog.ArgoBox.com",
ignorePatterns: ["private", "templates", ".obsidian"], ignorePatterns: ["private", "templates", ".obsidian"],
theme: { theme: {
typography: { typography: {

View File

@ -284,7 +284,7 @@ I created a simple HTML page that lists all my projects for quick access:
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>LaForceIT Workspace Launcher</title> <title>ArgoBox Workspace Launcher</title>
<style> <style>
body { body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
@ -319,7 +319,7 @@ I created a simple HTML page that lists all my projects for quick access:
</style> </style>
</head> </head>
<body> <body>
<h1>LaForceIT Workspace Launcher</h1> <h1>ArgoBox Workspace Launcher</h1>
<div class="project-list"> <div class="project-list">
<div class="project-card"> <div class="project-card">
<h2>ArgoBox</h2> <h2>ArgoBox</h2>
@ -328,7 +328,7 @@ I created a simple HTML page that lists all my projects for quick access:
</div> </div>
<div class="project-card"> <div class="project-card">
<h2>Blog</h2> <h2>Blog</h2>
<p>LaForceIT blog and digital garden</p> <p>ArgoBox blog and digital garden</p>
<a href="/projects/blog">Open Workspace</a> <a href="/projects/blog">Open Workspace</a>
</div> </div>
<!-- Add more projects as needed --> <!-- Add more projects as needed -->

View File

@ -10,7 +10,7 @@ interface Props {
const { const {
title, title,
description = "LaForceIT Blog - Home Lab & DevOps Insights", description = "ArgoBox Blog - Home Lab & DevOps Insights",
image = "/images/og-image.jpg" // Make sure this image exists in public/images/ image = "/images/og-image.jpg" // Make sure this image exists in public/images/
} = Astro.props; } = Astro.props;
--- ---
@ -67,7 +67,7 @@ const {
{ {
"@context": "https://schema.org", "@context": "https://schema.org",
"@type": "WebSite", "@type": "WebSite",
"name": "LaForceIT Blog", "name": "ArgoBox Blog",
"url": Astro.site ? new URL(Astro.url.pathname, Astro.site).href : Astro.url.href, // Use absolute URL "url": Astro.site ? new URL(Astro.url.pathname, Astro.site).href : Astro.url.href, // Use absolute URL
"description": description, "description": description,
"author": { "author": {

View File

@ -192,10 +192,10 @@ const fallbackCurrentPost = currentPost || {
{/* Author Card Updated */} {/* Author Card Updated */}
<div class="sidebar-card author-card"> <div class="sidebar-card author-card">
<div class="author-avatar"> <div class="author-avatar">
<img src="/images/avatar.jpg" alt="LaForceIT Tech Blogs" /> <img src="/images/avatar.jpg" alt="ArgoBox Tech Blogs" />
</div> </div>
<div class="author-info"> <div class="author-info">
<h3>LaForceIT.com Tech Blogs</h3> <h3>ArgoBox.com Tech Blogs</h3>
<p>For Home Labbers, Technologists & Engineers</p> <p>For Home Labbers, Technologists & Engineers</p>
</div> </div>
<p class="author-bio"> <p class="author-bio">

View File

@ -1,645 +0,0 @@
---
import BaseLayout from './BaseLayout.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
// import MiniKnowledgeGraph from '../components/MiniKnowledgeGraph.astro'; // Keep if needed elsewhere, but remove from main content
import MiniGraph from '../components/MiniGraph.astro'; // Add import for MiniGraph
import { getCollection } from 'astro:content';
interface Props {
frontmatter: {
title: string;
description?: string;
pubDate: Date;
updatedDate?: Date;
heroImage?: string;
category?: string;
tags?: string[];
readTime?: string;
draft?: boolean;
author?: string;
// Field for explicitly related posts
related_posts?: string[];
},
slug: string // Add slug to props
}
const { frontmatter, slug } = Astro.props;
// Get all posts for finding related content
const allPosts = await getCollection('posts');
// Create a currentPost object that matches the structure expected by MiniKnowledgeGraph
const currentPost = {
slug: slug,
data: frontmatter
};
// Find related posts - first from explicitly defined related_posts
const explicitRelatedPosts = frontmatter.related_posts
? allPosts.filter(post =>
frontmatter.related_posts?.includes(post.slug) &&
post.slug !== slug
)
: [];
// Then find posts with shared tags (if we need more related posts)
const MAX_RELATED_POSTS = 3;
let relatedPostsByTags = [];
if (explicitRelatedPosts.length < MAX_RELATED_POSTS && frontmatter.tags && frontmatter.tags.length > 0) {
// Create a map of posts by tags for efficient lookup
const postsByTag = new Map();
frontmatter.tags.forEach(tag => {
postsByTag.set(tag, allPosts.filter(post =>
post.slug !== slug &&
post.data.tags?.includes(tag) &&
!explicitRelatedPosts.some(p => p.slug === post.slug)
));
});
// Score posts by number of shared tags
const scoredPosts = new Map();
postsByTag.forEach((posts, tag) => {
posts.forEach(post => {
const currentScore = scoredPosts.get(post.slug) || 0;
scoredPosts.set(post.slug, currentScore + 1);
});
});
// Convert to array, sort by score, and take what we need
relatedPostsByTags = Array.from(scoredPosts.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, MAX_RELATED_POSTS - explicitRelatedPosts.length)
.map(([slug]) => allPosts.find(post => post.slug === slug))
.filter(Boolean); // Remove any undefined entries
}
// Combine explicit and tag-based related posts
const relatedPosts = [...explicitRelatedPosts, ...relatedPostsByTags];
// Format date
const formattedPubDate = frontmatter.pubDate ? new Date(frontmatter.pubDate).toLocaleDateString('en-us', {
year: 'numeric',
month: 'long',
day: 'numeric',
}) : 'N/A';
const formattedUpdatedDate = frontmatter.updatedDate ? new Date(frontmatter.updatedDate).toLocaleDateString('en-us', {
year: 'numeric',
month: 'long',
day: 'numeric',
}) : null;
// Default image if heroImage is missing
const displayImage = frontmatter.heroImage || '/images/placeholders/default.jpg';
---
<BaseLayout title={frontmatter.title} description={frontmatter.description} image={displayImage}>
<Header slot="header" />
<div class="blog-post-container">
<article class="blog-post">
<header class="blog-post-header">
{/* Display Draft Badge if needed */}
{frontmatter.draft && <span class="draft-badge mb-4">DRAFT</span>}
{/* Title */}
<h1 class="blog-post-title mb-2">{frontmatter.title}</h1>
{/* Description */}
{frontmatter.description && <p class="blog-post-description mb-4">{frontmatter.description}</p>}
{/* Metadata (Date, Read Time) */}
<div class="blog-post-meta mb-4">
<span class="blog-post-date">Published {formattedPubDate}</span>
{formattedUpdatedDate && (
<span class="blog-post-updated">(Updated {formattedUpdatedDate})</span>
)}
{frontmatter.readTime && <span class="blog-post-read-time">{frontmatter.readTime}</span>}
{frontmatter.category && <span class="blog-post-category">{frontmatter.category}</span>}
</div>
{/* Tags */}
{frontmatter.tags && frontmatter.tags.length > 0 && (
<div class="blog-post-tags">
{frontmatter.tags.map((tag) => (
<a href={`/tag/${tag}`} class="blog-post-tag">#{tag}</a>
))}
</div>
)}
</header>
{/* Display Hero Image */}
{displayImage && (
<div class="blog-post-hero">
<img src={displayImage.startsWith('/') ? displayImage : `/${displayImage}`} alt={frontmatter.title} width="1024" height="512" loading="lazy" />
</div>
)}
{/* Content Connections - Removed MiniKnowledgeGraph from here */}
{/* <div class="content-connections">
<h3 class="connections-title">Post Connections</h3>
<MiniKnowledgeGraph currentPost={currentPost} relatedPosts={relatedPosts} />
</div> */}
{/* Main Content Area */}
<div class="blog-post-content prose prose-invert max-w-none">
<slot /> {/* Renders the actual markdown content */}
</div>
{/* Related Posts Section */}
{relatedPosts.length > 0 && (
<div class="related-posts-section">
<h3 class="related-title">Related Content</h3>
<div class="related-posts-grid">
{relatedPosts.map((post) => (
<a href={`/posts/${post.slug}/`} class="related-post-card">
<div class="related-post-content">
<h4>{post.data.title}</h4>
<p>{post.data.description ?
(post.data.description.length > 100 ?
post.data.description.substring(0, 100) + '...' :
post.data.description) :
'Read more about this related topic.'}</p>
</div>
</a>
))}
</div>
</div>
)}
</article>
{/* Sidebar */}
<aside class="blog-post-sidebar">
{/* Author Card */}
<div class="sidebar-card author-card">
<div class="author-avatar">
<div class="avatar-placeholder">DL</div>
</div>
<div class="author-info">
<h3>Daniel LaForce</h3>
<p>Infrastructure & DevOps Engineer</p>
</div>
<p class="author-bio">
Exploring enterprise-grade infrastructure, automation, Kubernetes, and self-hosted solutions for the modern home lab.
</p>
<div class="author-links">
<a href="https://github.com/keyargo" target="_blank" rel="noopener noreferrer" class="author-link github">
<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">
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
</svg>
GitHub
</a>
</div>
</div>
{/* MiniGraph Component - Placed after Author Card */}
<MiniGraph
slug={slug}
title={frontmatter.title}
tags={frontmatter.tags}
category={frontmatter.category}
/>
{/* Tags Section - Placed after MiniGraph */}
<div class="sidebar-card">
<h3 class="sidebar-title">Tags</h3>
<div class="tags">
{frontmatter.tags && frontmatter.tags.map(tag => (
<a href={`/tag/${tag}`} class="tag">{tag}</a>
))}
</div>
</div>
{/* Table of Contents Card */}
<div class="sidebar-card toc-card">
<h3>Table of Contents</h3>
<nav class="toc-container" id="toc">
<p class="text-sm text-gray-400">Loading Table of Contents...</p>
</nav>
</div>
</aside>
</div>
<Footer slot="footer" />
</BaseLayout>
<script>
// Table of Contents Generator
document.addEventListener('DOMContentLoaded', () => {
const tocContainer = document.getElementById('toc');
const contentArea = document.querySelector('.blog-post-content');
if (!tocContainer || !contentArea) return;
// Get all headings (h2, h3) from the content
const headings = contentArea.querySelectorAll('h2, h3');
if (headings.length === 0) {
tocContainer.innerHTML = '<p class="toc-empty">No sections found in this article.</p>';
return;
}
// Create the TOC list
const tocList = document.createElement('ul');
tocList.className = 'toc-list';
headings.forEach((heading, index) => {
// Add ID to heading if it doesn't have one
if (!heading.id) {
heading.id = `heading-${index}`;
}
// Create list item
const listItem = document.createElement('li');
listItem.className = `toc-item toc-${heading.tagName.toLowerCase()}`;
// Create link
const link = document.createElement('a');
link.href = `#${heading.id}`;
link.textContent = heading.textContent;
link.addEventListener('click', (e) => {
e.preventDefault();
document.getElementById(heading.id)?.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
});
// Add to list
listItem.appendChild(link);
tocList.appendChild(listItem);
});
// Replace loading message with the TOC
tocContainer.innerHTML = '';
tocContainer.appendChild(tocList);
// Add smooth scrolling for all links pointing to headings
document.querySelectorAll('a[href^="#heading-"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
document.querySelector(targetId)?.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
});
});
});
</script>
<style is:global>
/* Table of Contents Styles */
.toc-list {
list-style: none;
padding: 0;
margin: 0;
}
.toc-item {
margin-bottom: 0.75rem;
}
.toc-item a {
color: var(--text-secondary);
text-decoration: none;
transition: color 0.2s ease;
font-size: 0.9rem;
display: block;
}
.toc-item a:hover {
color: var(--accent-primary);
}
.toc-h3 {
padding-left: 1rem;
font-size: 0.85rem;
}
.toc-empty {
color: var(--text-tertiary);
font-style: italic;
font-size: 0.9rem;
}
/* Add styles for Tags in the sidebar */
.tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag {
color: var(--accent-secondary);
text-decoration: none;
font-size: 0.85rem;
transition: all 0.3s ease;
font-family: var(--font-mono);
background-color: rgba(59, 130, 246, 0.1);
padding: 0.3rem 0.6rem;
border-radius: 4px;
display: inline-block;
}
.tag:hover {
color: var(--accent-primary);
background-color: rgba(6, 182, 212, 0.15);
transform: translateY(-2px);
}
.sidebar-title {
font-size: 1.1rem;
margin-bottom: 1rem;
color: var(--text-primary);
}
</style>
<style>
.blog-post-container {
display: grid;
grid-template-columns: 7fr 3fr;
gap: 2rem;
max-width: 1200px;
margin: 2rem auto;
padding: 0 1.5rem;
}
.blog-post {
background: var(--card-bg);
border-radius: 12px;
border: 1px solid var(--card-border);
overflow: hidden;
padding: 2rem;
}
.blog-post-header {
margin-bottom: 2rem;
}
.draft-badge {
display: inline-block;
margin-bottom: 1rem;
padding: 0.25rem 0.75rem;
background-color: rgba(234, 179, 8, 0.2);
color: #ca8a04;
font-size: 0.8rem;
border-radius: 0.25rem;
font-weight: 600;
font-family: var(--font-mono);
}
.blog-post-title {
font-size: clamp(1.8rem, 4vw, 2.5rem);
line-height: 1.2;
margin-bottom: 0.75rem;
color: var(--text-primary);
}
.blog-post-description {
font-size: 1.1rem;
color: var(--text-secondary);
margin-bottom: 1.5rem;
max-width: 75ch;
}
.blog-post-meta {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1.5rem;
margin-bottom: 1.5rem;
font-size: 0.85rem;
color: var(--text-secondary);
}
.blog-post-category {
padding: 0.25rem 0.75rem;
background: rgba(6, 182, 212, 0.1);
border-radius: 2rem;
font-family: var(--font-mono);
}
.blog-post-tags {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
margin-bottom: 1.5rem;
}
.blog-post-tag {
color: var(--accent-secondary);
text-decoration: none;
font-size: 0.85rem;
transition: color 0.3s ease;
font-family: var(--font-mono);
background-color: rgba(59, 130, 246, 0.1);
padding: 0.2rem 0.6rem;
border-radius: 4px;
}
.blog-post-tag:hover {
color: var(--accent-primary);
background-color: rgba(6, 182, 212, 0.15);
transform: translateY(-2px);
}
.blog-post-hero {
width: 100%;
margin-bottom: 2rem;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--card-border);
background-color: var(--bg-secondary);
}
.blog-post-hero img {
width: 100%;
height: auto;
display: block;
}
/* Content Connections - Knowledge Graph */
.content-connections {
margin: 2rem 0;
padding: 1.5rem;
background: var(--bg-secondary);
border-radius: 8px;
border: 1px solid var(--card-border);
}
.connections-title {
font-size: 1.2rem;
margin-bottom: 1rem;
color: var(--text-primary);
}
/* Related Posts Section */
.related-posts-section {
margin-top: 3rem;
padding-top: 2rem;
border-top: 1px solid var(--card-border);
}
.related-title {
font-size: 1.5rem;
margin-bottom: 1.5rem;
color: var(--text-primary);
}
.related-posts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
}
.related-post-card {
background: var(--bg-secondary);
border-radius: 8px;
border: 1px solid var(--card-border);
padding: 1.5rem;
text-decoration: none;
transition: all 0.3s ease;
}
.related-post-card:hover {
transform: translateY(-3px);
border-color: var(--accent-primary);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.related-post-content h4 {
color: var(--text-primary);
font-size: 1.1rem;
margin-bottom: 0.5rem;
}
.related-post-content p {
color: var(--text-secondary);
font-size: 0.9rem;
}
/* Sidebar */
.blog-post-sidebar {
position: sticky;
top: 2rem;
align-self: start;
height: calc(100vh - 4rem);
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 2rem;
}
.sidebar-card {
background: var(--card-bg);
border-radius: 12px;
border: 1px solid var(--card-border);
padding: 1.5rem;
}
/* Author Card */
.author-card {
text-align: center;
}
.author-avatar {
width: 80px;
height: 80px;
border-radius: 50%;
overflow: hidden;
margin: 0 auto 1rem;
border: 2px solid var(--accent-primary);
background-color: var(--bg-secondary);
}
.avatar-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
font-weight: bold;
color: var(--accent-primary);
}
.author-info h3 {
margin-bottom: 0.25rem;
color: var(--text-primary);
font-size: 1.2rem;
}
.author-info p {
color: var(--text-secondary);
margin-bottom: 1rem;
font-size: 0.9rem;
}
.author-bio {
font-size: 0.9rem;
margin-bottom: 1.5rem;
color: var(--text-secondary);
text-align: left;
}
.author-links {
display: flex;
justify-content: center;
}
.author-link {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
background: rgba(226, 232, 240, 0.05);
border-radius: 8px;
color: var(--text-primary);
text-decoration: none;
font-size: 0.9rem;
transition: all 0.3s ease;
}
.author-link:hover {
background: rgba(226, 232, 240, 0.1);
transform: translateY(-2px);
}
/* Table of Contents */
.toc-card h3 {
margin-bottom: 1rem;
color: var(--text-primary);
}
.toc-container {
max-height: 500px;
overflow-y: auto;
}
@media (max-width: 1024px) {
.blog-post-container {
grid-template-columns: 1fr;
}
.blog-post-sidebar {
display: none;
}
}
@media (max-width: 768px) {
.blog-post-title {
font-size: 1.8rem;
}
.related-posts-grid {
grid-template-columns: 1fr;
}
.blog-post {
padding: 1.5rem;
}
}
</style>

View File

@ -4,7 +4,7 @@ import BaseLayout from '../layouts/BaseLayout.astro';
import Header from '../components/Header.astro'; import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro'; import Footer from '../components/Footer.astro';
const title = "Home Lab | Argobox - LaForceIT Tech Hub"; const title = "Home Lab | Argobox - ArgoBox Tech Hub";
const description = "ArgoBox - A production-grade Kubernetes homelab for DevOps experimentation, infrastructure automation, and containerized application deployment."; const description = "ArgoBox - A production-grade Kubernetes homelab for DevOps experimentation, infrastructure automation, and containerized application deployment.";
// Data for services (can be fetched or defined here) // Data for services (can be fetched or defined here)

View File

@ -132,7 +132,7 @@ const heroCommands = [
<div class="container"> <div class="container">
<h2 class="section-title">About ArgoBox</h2> <h2 class="section-title">About ArgoBox</h2>
<p class="intro-text"> <p class="intro-text">
ArgoBox is a community-driven platform sharing infrastructure patterns, automation techniques, and practical guides for building professional-grade technology environments at any scale. From home labs to enterprise deployments, we focus on Kubernetes, GitOps, Infrastructure as Code, and system optimization. Created by the LaForceIT team to help technologists build better systems through shared knowledge and proven configurations. ArgoBox is a community-driven platform sharing infrastructure patterns, automation techniques, and practical guides for building professional-grade technology environments at any scale. From home labs to enterprise deployments, we focus on Kubernetes, GitOps, Infrastructure as Code, and system optimization. Created by the ArgoBox team to help technologists build better systems through shared knowledge and proven configurations.
</p> </p>
</div> </div>
</section> </section>

View File

@ -5,8 +5,8 @@ import '../styles/card-animations.css';
import Header from '../components/Header.astro'; import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro'; import Footer from '../components/Footer.astro';
const title = "Projects | LaForceIT"; const title = "Projects | ArgoBox";
const description = "Explore Daniel LaForce's projects, including infrastructure solutions, automation tools, and home lab configurations."; const description = "Explore ArgoBox projects, including infrastructure solutions, automation tools, and home lab configurations.";
// Category icons // Category icons
const categoryIcons = { const categoryIcons = {

View File

@ -4,8 +4,8 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
import Header from '../../components/Header.astro'; import Header from '../../components/Header.astro';
import Footer from '../../components/Footer.astro'; import Footer from '../../components/Footer.astro';
const title = "GitHub Repositories | LaForceIT"; const title = "GitHub Repositories | ArgoBox";
const description = "Explore Daniel LaForce's GitHub projects, infrastructure code, automation scripts, and open-source contributions."; const description = "Explore ArgoBox GitHub projects, infrastructure code, automation scripts, and open-source contributions.";
--- ---
<BaseLayout title={title} description={description}> <BaseLayout title={title} description={description}>

View File

@ -4,7 +4,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
import Header from '../../components/Header.astro'; import Header from '../../components/Header.astro';
import Footer from '../../components/Footer.astro'; import Footer from '../../components/Footer.astro';
const title = "Obsidian Templates | LaForceIT"; const title = "Obsidian Templates | ArgoBox";
const description = "A collection of Obsidian templates for DevOps and IT professionals to better organize their technical knowledge."; const description = "A collection of Obsidian templates for DevOps and IT professionals to better organize their technical knowledge.";
--- ---

View File

@ -4,8 +4,8 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
import Header from '../../components/Header.astro'; import Header from '../../components/Header.astro';
import Footer from '../../components/Footer.astro'; import Footer from '../../components/Footer.astro';
const title = "Live Services | LaForceIT"; const title = "Live Services | ArgoBox";
const description = "Explore the live services running in Daniel LaForce's home lab infrastructure environment."; const description = "Explore the live services running in the ArgoBox home lab infrastructure environment.";
--- ---
<BaseLayout title={title} description={description}> <BaseLayout title={title} description={description}>

View File

@ -4,8 +4,8 @@ import BaseLayout from '../layouts/BaseLayout.astro';
import Header from '../components/Header.astro'; import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro'; import Footer from '../components/Footer.astro';
const title = "Tech Stack | LaForceIT"; const title = "Tech Stack | ArgoBox";
const description = "Explore the technology stack that powers LaForceIT projects, infrastructure, and home lab environment."; const description = "Explore the technology stack that powers ArgoBox projects, infrastructure, and home lab environment.";
// Define tech stack categories and items // Define tech stack categories and items
const techCategories = [ const techCategories = [
@ -170,7 +170,7 @@ const techCategories = [
<h1>Tech Stack</h1> <h1>Tech Stack</h1>
<div class="header-accent"></div> <div class="header-accent"></div>
<p class="intro-text"> <p class="intro-text">
Explore the technologies, tools, and platforms that power the LaForceIT infrastructure, projects, and home lab environment. This curated stack focuses on enterprise-grade solutions that balance performance, reliability, and maintainability. Explore the technologies, tools, and platforms that power the ArgoBox infrastructure, projects, and home lab environment. This curated stack focuses on enterprise-grade solutions that balance performance, reliability, and maintainability.
</p> </p>
</div> </div>

View File

@ -4,7 +4,7 @@ import Header from '../components/Header.astro';
import '../styles/card-animations.css'; import '../styles/card-animations.css';
import Footer from '../components/Footer.astro'; import Footer from '../components/Footer.astro';
--- ---
<BaseLayout title="Resources - LaForceIT"> <BaseLayout title="Resources - ArgoBox">
<Header slot="header" /> <Header slot="header" />
<!-- Main Content from public/resources.html --> <!-- Main Content from public/resources.html -->

View File

@ -4,7 +4,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
import Header from '../../components/Header.astro'; import Header from '../../components/Header.astro';
import Footer from '../../components/Footer.astro'; import Footer from '../../components/Footer.astro';
const title = "Configuration Files | LaForceIT"; const title = "Configuration Files | ArgoBox";
const description = "A curated collection of configuration files and templates for various DevOps tools and infrastructure components."; const description = "A curated collection of configuration files and templates for various DevOps tools and infrastructure components.";
--- ---

View File

@ -5,7 +5,7 @@ import Header from '../../components/Header.astro';
import Footer from '../../components/Footer.astro'; import Footer from '../../components/Footer.astro';
import '../../styles/card-animations.css'; // Assuming cards might be used import '../../styles/card-animations.css'; // Assuming cards might be used
const title = "Docker Compose Resources | LaForceIT"; const title = "Docker Compose Resources | ArgoBox";
const description = "A collection of Docker Compose files for various services and applications, optimized for home lab environments."; const description = "A collection of Docker Compose files for various services and applications, optimized for home lab environments.";
// Placeholder data - replace with actual data // Placeholder data - replace with actual data

View File

@ -4,7 +4,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
import Header from '../../components/Header.astro'; import Header from '../../components/Header.astro';
import Footer from '../../components/Footer.astro'; import Footer from '../../components/Footer.astro';
const title = "Infrastructure as Code | LaForceIT"; const title = "Infrastructure as Code | ArgoBox";
const description = "A collection of Terraform, Ansible, and other IaC templates and modules for efficient infrastructure management."; const description = "A collection of Terraform, Ansible, and other IaC templates and modules for efficient infrastructure management.";
// Define the Terraform example as a string to avoid parsing issues // Define the Terraform example as a string to avoid parsing issues

View File

@ -6,7 +6,7 @@ import Footer from '../../components/Footer.astro';
// Assuming card animations are needed if resource cards are used // Assuming card animations are needed if resource cards are used
import '../../styles/card-animations.css'; import '../../styles/card-animations.css';
const title = "Kubernetes Resources | LaForceIT"; const title = "Kubernetes Resources | ArgoBox";
const description = "A collection of Kubernetes manifests, deployment configurations, and best practices for container orchestration."; const description = "A collection of Kubernetes manifests, deployment configurations, and best practices for container orchestration.";
// Placeholder data - replace with actual data fetching or static data // Placeholder data - replace with actual data fetching or static data

View File

@ -4,7 +4,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
import Header from '../../components/Header.astro'; import Header from '../../components/Header.astro';
import Footer from '../../components/Footer.astro'; import Footer from '../../components/Footer.astro';
const title = "Tutorials | LaForceIT"; const title = "Tutorials | ArgoBox";
const description = "Step-by-step tutorials on DevOps, Kubernetes, home lab setup, infrastructure automation, and more."; const description = "Step-by-step tutorials on DevOps, Kubernetes, home lab setup, infrastructure automation, and more.";
--- ---

View File

@ -5,8 +5,8 @@ import '../styles/card-animations.css';
import Header from '../components/Header.astro'; import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro'; import Footer from '../components/Footer.astro';
const title = "Tech Stack | LaForceIT"; const title = "Tech Stack | ArgoBox";
const description = "Explore the technology stack that powers LaForceIT projects, infrastructure, and home lab environment."; const description = "Explore the technology stack that powers ArgoBox projects, infrastructure, and home lab environment.";
// Define tech categories // Define tech categories
const techCategories = [ const techCategories = [
@ -166,7 +166,7 @@ const filters = [
<div class="page-header"> <div class="page-header">
<h1 class="page-title">Tech Stack</h1> <h1 class="page-title">Tech Stack</h1>
<p class="page-description"> <p class="page-description">
Explore the technologies, tools, and platforms that power the LaForceIT infrastructure, projects, and home lab environment. This curated stack focuses on enterprise-grade solutions that balance performance, reliability, and maintainability. Explore the technologies, tools, and platforms that power the ArgoBox infrastructure, projects, and home lab environment. This curated stack focuses on enterprise-grade solutions that balance performance, reliability, and maintainability.
</p> </p>
</div> </div>