Skip to content

Commit 87aeec9

Browse files
committed
feat: implement individual blog post page with navigation
1 parent eb7946f commit 87aeec9

9 files changed

Lines changed: 686 additions & 0 deletions

File tree

src/app/blog/[slug]/page.tsx

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
import { BlogPostPage } from '@/components/blog/blog-post-page';
2+
import { BlogPost } from '@/types';
3+
import { notFound } from 'next/navigation';
4+
5+
// Mock data - in a real app, this would come from a CMS or markdown files
6+
const mockPosts: BlogPost[] = [
7+
{
8+
title: 'Building Offline-First Apps',
9+
slug: 'building-offline-first-apps',
10+
date: new Date('2025-01-15'),
11+
excerpt: 'Real-time synchronization strategies for mobile applications',
12+
tags: ['React Native', 'Offline', 'Sync'],
13+
category: 'Mobile Development',
14+
content: `
15+
# Building Offline-First Apps
16+
17+
This is a comprehensive guide to building offline-first applications that work seamlessly even when users have poor or no internet connectivity.
18+
19+
## Why Offline-First?
20+
21+
Offline-first applications provide a superior user experience by:
22+
23+
- Working immediately without waiting for network requests
24+
- Continuing to function in areas with poor connectivity
25+
- Reducing server load and bandwidth usage
26+
- Providing faster response times for common operations
27+
28+
## Key Components
29+
30+
### 1. Data Synchronization
31+
32+
\`\`\`javascript
33+
const syncData = async () => {
34+
const offlineData = await getOfflineData();
35+
const onlineData = await fetchOnlineData();
36+
return mergeData(offlineData, onlineData);
37+
};
38+
\`\`\`
39+
40+
### 2. Conflict Resolution
41+
42+
When data changes occur both offline and online, you need a strategy to resolve conflicts:
43+
44+
- **Last Write Wins**: Simple but can lose data
45+
- **Merge Strategies**: More complex but preserves all changes
46+
- **User Resolution**: Let users choose which version to keep
47+
48+
### 3. Storage Strategy
49+
50+
Choose the right storage mechanism for your needs:
51+
52+
- **IndexedDB**: For complex data structures
53+
- **LocalStorage**: For simple key-value pairs
54+
- **SQLite**: For relational data (in mobile apps)
55+
56+
## Implementation Example
57+
58+
Here's a basic implementation using React Native and AsyncStorage:
59+
60+
\`\`\`javascript
61+
import AsyncStorage from '@react-native-async-storage/async-storage';
62+
63+
class OfflineFirstApp {
64+
async saveData(key, data) {
65+
try {
66+
await AsyncStorage.setItem(key, JSON.stringify(data));
67+
await this.queueForSync(key, data);
68+
} catch (error) {
69+
console.error('Failed to save data:', error);
70+
}
71+
}
72+
73+
async loadData(key) {
74+
try {
75+
const offlineData = await AsyncStorage.getItem(key);
76+
return offlineData ? JSON.parse(offlineData) : null;
77+
} catch (error) {
78+
console.error('Failed to load data:', error);
79+
return null;
80+
}
81+
}
82+
83+
async queueForSync(key, data) {
84+
const syncQueue = await this.getSyncQueue();
85+
syncQueue.push({ key, data, timestamp: Date.now() });
86+
await AsyncStorage.setItem('syncQueue', JSON.stringify(syncQueue));
87+
}
88+
}
89+
\`\`\`
90+
91+
## Best Practices
92+
93+
1. **Always cache critical data locally**
94+
2. **Implement proper error handling for network failures**
95+
3. **Use optimistic updates for better UX**
96+
4. **Provide clear feedback about sync status**
97+
5. **Test thoroughly with poor network conditions**
98+
99+
## Conclusion
100+
101+
Building offline-first applications requires careful planning and implementation, but the benefits in user experience are significant. Start with a simple caching strategy and gradually add more sophisticated sync capabilities as your app grows.
102+
103+
Remember: the goal is to make your app feel like it works instantly, regardless of network conditions.
104+
`,
105+
readingTime: 8,
106+
published: true
107+
},
108+
{
109+
title: 'Microservices Architecture Patterns',
110+
slug: 'microservices-architecture-patterns',
111+
date: new Date('2025-01-10'),
112+
excerpt: 'Best practices for designing scalable microservices',
113+
tags: ['Microservices', 'Architecture', 'Scalability'],
114+
category: 'Backend Development',
115+
content: `
116+
# Microservices Architecture Patterns
117+
118+
A comprehensive guide to designing and implementing scalable microservices architectures.
119+
120+
## What are Microservices?
121+
122+
Microservices are an architectural style where an application is built as a collection of small, autonomous services that communicate over well-defined APIs.
123+
124+
## Key Patterns
125+
126+
### 1. API Gateway Pattern
127+
128+
The API Gateway acts as a single entry point for all client requests, handling cross-cutting concerns like authentication, rate limiting, and routing.
129+
130+
### 2. Circuit Breaker Pattern
131+
132+
Circuit breakers prevent cascading failures by monitoring for failures and stopping the flow of requests when a threshold is reached.
133+
134+
### 3. Event-Driven Architecture
135+
136+
Services communicate through events, enabling loose coupling and better scalability.
137+
138+
## Implementation Considerations
139+
140+
- **Service Discovery**: How services find each other
141+
- **Load Balancing**: Distributing traffic across instances
142+
- **Monitoring**: Observability and health checks
143+
- **Security**: Authentication and authorization
144+
`,
145+
readingTime: 12,
146+
published: true
147+
},
148+
{
149+
title: 'Modern CSS Techniques',
150+
slug: 'modern-css-techniques',
151+
date: new Date('2025-01-05'),
152+
excerpt: 'Advanced CSS features for modern web development',
153+
tags: ['CSS', 'Frontend', 'Web Development'],
154+
category: 'Frontend Development',
155+
content: `
156+
# Modern CSS Techniques
157+
158+
Exploring the latest CSS features and how to use them effectively in modern web development.
159+
160+
## CSS Grid Layout
161+
162+
CSS Grid provides a powerful two-dimensional layout system:
163+
164+
\`\`\`css
165+
.container {
166+
display: grid;
167+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
168+
gap: 1rem;
169+
}
170+
\`\`\`
171+
172+
## CSS Custom Properties
173+
174+
Custom properties (CSS variables) enable dynamic theming and better maintainability:
175+
176+
\`\`\`css
177+
:root {
178+
--primary-color: #0969da;
179+
--background-color: #ffffff;
180+
}
181+
182+
.button {
183+
background-color: var(--primary-color);
184+
color: var(--background-color);
185+
}
186+
\`\`\`
187+
188+
## Modern Selectors
189+
190+
New CSS selectors provide more powerful targeting capabilities:
191+
192+
\`\`\`css
193+
/* Select elements that are the first of their type */
194+
p:first-of-type {
195+
font-weight: bold;
196+
}
197+
198+
/* Select elements that match a pattern */
199+
[class*="btn-"] {
200+
border-radius: 4px;
201+
}
202+
\`\`\`
203+
`,
204+
readingTime: 6,
205+
published: true
206+
}
207+
];
208+
209+
// Generate static params for all blog posts
210+
export async function generateStaticParams() {
211+
return mockPosts.map((post) => ({
212+
slug: post.slug,
213+
}));
214+
}
215+
216+
interface BlogPostPageProps {
217+
params: {
218+
slug: string;
219+
};
220+
}
221+
222+
export default function BlogPostPageRoute({ params }: BlogPostPageProps) {
223+
const { slug } = params;
224+
225+
// Find the post by slug
226+
const post = mockPosts.find(p => p.slug === slug);
227+
228+
if (!post) {
229+
notFound();
230+
}
231+
232+
// Find previous and next posts for navigation
233+
const currentIndex = mockPosts.findIndex(p => p.slug === slug);
234+
const prev = currentIndex > 0 ? mockPosts[currentIndex - 1] : undefined;
235+
const next = currentIndex < mockPosts.length - 1 ? mockPosts[currentIndex + 1] : undefined;
236+
237+
return <BlogPostPage post={post} prev={prev} next={next} />;
238+
}

src/app/blog/page.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { BlogPostList } from '@/components/blog/blog-post-list';
2+
3+
// Mock data - in a real app, this would come from a CMS or markdown files
4+
const mockPosts = [
5+
{
6+
title: 'Building Offline-First Apps',
7+
slug: 'building-offline-first-apps',
8+
date: new Date('2025-01-15'),
9+
excerpt: 'Real-time synchronization strategies for mobile applications',
10+
tags: ['React Native', 'Offline', 'Sync'],
11+
category: 'Mobile Development',
12+
content: '',
13+
readingTime: 8,
14+
published: true
15+
},
16+
{
17+
title: 'Microservices Architecture Patterns',
18+
slug: 'microservices-architecture-patterns',
19+
date: new Date('2025-01-10'),
20+
excerpt: 'Best practices for designing scalable microservices',
21+
tags: ['Microservices', 'Architecture', 'Scalability'],
22+
category: 'Backend Development',
23+
content: '',
24+
readingTime: 12,
25+
published: true
26+
},
27+
{
28+
title: 'Modern CSS Techniques',
29+
slug: 'modern-css-techniques',
30+
date: new Date('2025-01-05'),
31+
excerpt: 'Advanced CSS features for modern web development',
32+
tags: ['CSS', 'Frontend', 'Web Development'],
33+
category: 'Frontend Development',
34+
content: '',
35+
readingTime: 6,
36+
published: true
37+
}
38+
];
39+
40+
export default function BlogPage() {
41+
return (
42+
<div className="max-w-6xl mx-auto px-4 py-8">
43+
<header className="mb-12">
44+
<h1 className="text-4xl font-bold font-mono mb-4 text-text">Blog</h1>
45+
<p className="text-lg text-muted">Thoughts on software development, architecture, and technology.</p>
46+
</header>
47+
48+
<BlogPostList posts={mockPosts} />
49+
</div>
50+
);
51+
}

0 commit comments

Comments
 (0)