refactor: separate blog content from code

### Changes:
1. **Create Blog Content Directory**
   - Created src/content/blog/ directory for content management
   - Added README.md with usage instructions
   - Added 3 sample blog posts

2. **Update Content Retrieval Function**
   - Modified getHomepagePosts() in homepage.ts
   - Now reads from src/content/blog/ instead of CMS config
   - Content and style are now separated

3. **Content Management**
   - Style: Keep existing components and styles
   - Content: Manage via markdown files in src/content/blog/
   - Metadata: YAML front matter (title, author, date, tags, excerpt)
   - Sorting: Sort by date (newest first)

### Benefits:
- Content separated from code
- Easy for non-technical users to add content
- Version control friendly
- Unified metadata management

To add new blog posts:
1. Create .md file in src/content/blog/
2. Use standard front matter format
3. Use kebab-case for filenames

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
Haitao Pan 2025-11-11 12:58:49 +08:00
parent 0ee41e774f
commit ebbe29afd1
5 changed files with 187 additions and 27 deletions

View File

@ -0,0 +1,44 @@
# Blog Content Directory
This directory contains all blog posts for the Cloud-Neutral platform.
## Directory Structure
```
src/content/blog/
├── README.md # This file
├── first-post.md # Example blog post
└── ...
```
## Adding a New Blog Post
1. Create a new markdown file in this directory
2. Use the following format:
```markdown
---
title: Your Post Title
author: Author Name
date: 2025-01-01
tags: [tag1, tag2, tag3]
excerpt: Brief description of the post
---
Your post content here in Markdown format.
```
## File Naming Convention
- Use kebab-case: `my-first-post.md`
- Avoid spaces and special characters
- Include the `.md` extension
## Metadata Fields
- **title**: The post title (required)
- **author**: Author name (optional)
- **date**: Publication date in YYYY-MM-DD format (required)
- **tags**: Array of tags (optional)
- **excerpt**: Brief description (optional, auto-generated if not provided)

View File

@ -0,0 +1,44 @@
---
title: GitOps Security & Compliance in 2025
author: Security Team
date: 2025-01-05
tags: [gitops, security, compliance, automation]
excerpt: How to implement robust security and compliance controls in your GitOps workflows.
---
GitOps has revolutionized how we manage infrastructure, but security and compliance remain critical concerns.
## Security Considerations
### Supply Chain Security
- Scan dependencies for vulnerabilities
- Use signed commits
- Implement code signing
- Verify container images
### Access Control
- Principle of least privilege
- Multi-factor authentication
- Role-based access control
- Audit all changes
## Compliance Framework
### Policy as Code
- Define policies in version control
- Automate compliance checks
- Block non-compliant changes
- Regular policy reviews
### Audit Trail
- Immutable Git history
- Signed commits
- Change tracking
- Compliance reporting
## Implementation Strategy
1. Start with high-level policies
2. Implement progressive enforcement
3. Automate validation
4. Monitor and alert

View File

@ -0,0 +1,36 @@
---
title: Kubernetes Observability Best Practices
author: SRE Team
date: 2025-01-10
tags: [kubernetes, observability, sre, monitoring]
excerpt: Learn the essential practices for building a robust observability strategy in Kubernetes environments.
---
Building effective observability in Kubernetes requires understanding the unique challenges of containerized environments.
## The Three Pillars
### Metrics
- Use Prometheus for metrics collection
- Monitor resource usage (CPU, memory, disk)
- Track application-specific metrics
- Set up alerting rules
### Logs
- Centralize logs with ELK or similar stack
- Structured logging for better searchability
- Log levels: DEBUG, INFO, WARN, ERROR
- Correlate logs with trace IDs
### Traces
- Use OpenTelemetry for distributed tracing
- Track request flows across services
- Identify performance bottlenecks
- Monitor service dependencies
## Best Practices
1. **Start with Golden Signals**: Latency, traffic, errors, saturation
2. **Use SLOs**: Define and track Service Level Objectives
3. **Alert Wisely**: Alert on symptoms, not causes
4. **Correlate Data**: Connect metrics, logs, and traces

View File

@ -0,0 +1,32 @@
---
title: Welcome to Cloud-Neutral
author: Cloud-Neutral Team
date: 2025-01-15
tags: [announcement, cloud-native, platform]
excerpt: Introducing Cloud-Neutral - your unified platform for managing complex multi-cloud operations.
---
Welcome to Cloud-Neutral, the platform that unifies governance, automation, and observability for modern cloud-native environments.
## What is Cloud-Neutral?
Cloud-Neutral is designed to help platform teams manage complex multi-cloud estates with clarity. We provide a unified interface for:
- **Unified multi-cloud governance** - Manage resources across AWS, Azure, GCP, and more
- **Automated security & compliance** - Policy-as-code guardrails with global acceleration
- **Observability with intelligent workflows** - Unified metrics, logs, and traces
## Key Features
### XCloudFlow
Multi-cloud automation & GitOps orchestration that connects Terraform, Pulumi, and GitOps pipelines.
### XScopeHub
Observability & intelligent collaboration that unifies metrics, logs, and traces with AI-guided incident response.
### XStream
Security & compliance automation with policy-as-code guardrails.
## Getting Started
Visit our [documentation](/docs) to learn more about how Cloud-Neutral can help your team.

View File

@ -198,35 +198,39 @@ export async function getHeroSolutions(): Promise<HeroSolution[]> {
}
export async function getHomepagePosts(): Promise<HomepagePost[]> {
if (!isCmsHomepageEnabled()) {
return []
const blogContentRoot = path.join(process.cwd(), 'src', 'content', 'blog')
let posts: HomepagePost[] = []
try {
const files = await readMarkdownDirectory('', { baseDir: blogContentRoot })
posts = files.map((file) => {
const title = ensureString(file.metadata.title) ?? file.slug
const author = ensureString(file.metadata.author)
const date = ensureString(file.metadata.date)
const readingTime = ensureString(file.metadata.readingTime)
const tags = ensureStringArray(file.metadata.tags)
const excerptMetadata = ensureString(file.metadata.excerpt)
const excerpt = excerptMetadata ?? extractExcerpt(file.content)
return {
slug: file.slug,
title,
author,
date,
readingTime,
tags,
excerpt,
contentHtml: file.html,
}
})
} catch (error) {
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
throw error
}
}
const postsDir = path.join('posts')
const posts = await readMarkdownDirectory(postsDir, { baseDir: HOMEPAGE_CONTENT_ROOT })
const enriched = posts.map((post) => {
const title = ensureString(post.metadata.title) ?? post.slug
const author = ensureString(post.metadata.author)
const date = ensureString(post.metadata.date)
const readingTime = ensureString(post.metadata.readingTime)
const tags = ensureStringArray(post.metadata.tags)
const excerptMetadata = ensureString(post.metadata.excerpt)
const excerpt = excerptMetadata ?? extractExcerpt(post.content)
return {
slug: post.slug,
title,
author,
date,
readingTime,
tags,
excerpt,
contentHtml: post.html,
}
})
const withParsedDates = enriched.map((post) => ({
const withParsedDates = posts.map((post) => ({
...post,
dateValue: post.date ? new Date(post.date) : undefined,
}))