Initial commit
This commit is contained in:
583
lib/api.ts
Normal file
583
lib/api.ts
Normal file
@ -0,0 +1,583 @@
|
||||
"use client"
|
||||
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
import matter from "gray-matter"
|
||||
|
||||
const postsDirectory = path.join(process.cwd(), "posts")
|
||||
|
||||
export interface PostMetadata {
|
||||
title: string
|
||||
date: string
|
||||
excerpt: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface Post {
|
||||
slug: string
|
||||
content: string
|
||||
metadata: PostMetadata
|
||||
}
|
||||
|
||||
// Create posts directory if it doesn't exist
|
||||
try {
|
||||
if (!fs.existsSync(postsDirectory)) {
|
||||
fs.mkdirSync(postsDirectory, { recursive: true })
|
||||
createSamplePosts()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error checking or creating posts directory:", error)
|
||||
}
|
||||
|
||||
// Changed to synchronous to avoid suspense issues
|
||||
export function getAllPosts(): Post[] {
|
||||
try {
|
||||
const filenames = fs.readdirSync(postsDirectory)
|
||||
|
||||
const posts = filenames
|
||||
.filter((filename) => filename.endsWith(".md"))
|
||||
.map((filename) => {
|
||||
const slug = filename.replace(/\.md$/, "")
|
||||
const fullPath = path.join(postsDirectory, filename)
|
||||
const fileContents = fs.readFileSync(fullPath, "utf8")
|
||||
const { data, content } = matter(fileContents)
|
||||
|
||||
return {
|
||||
slug,
|
||||
content,
|
||||
metadata: data as PostMetadata,
|
||||
}
|
||||
})
|
||||
|
||||
return posts
|
||||
} catch (error) {
|
||||
console.error("Error getting all posts:", error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// Changed to synchronous to avoid suspense issues
|
||||
export function getPostBySlug(slug: string): Post | null {
|
||||
try {
|
||||
const fullPath = path.join(postsDirectory, `${slug}.md`)
|
||||
const fileContents = fs.readFileSync(fullPath, "utf8")
|
||||
const { data, content } = matter(fileContents)
|
||||
|
||||
return {
|
||||
slug,
|
||||
content,
|
||||
metadata: data as PostMetadata,
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error getting post by slug ${slug}:`, error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function createSamplePosts() {
|
||||
const samplePosts = [
|
||||
{
|
||||
filename: "getting-started-with-nextjs.md",
|
||||
content: `---
|
||||
title: "Getting Started with Next.js"
|
||||
date: "2023-05-15"
|
||||
excerpt: "Learn how to build modern web applications with Next.js"
|
||||
---
|
||||
|
||||
# Getting Started with Next.js
|
||||
|
||||
Next.js is a React framework that enables functionality such as server-side rendering and static site generation.
|
||||
|
||||
## Why Next.js?
|
||||
|
||||
- **Server-side Rendering**: Improves performance and SEO
|
||||
- **Static Site Generation**: Pre-renders pages at build time
|
||||
- **API Routes**: Build API endpoints as part of your Next.js app
|
||||
- **File-based Routing**: Create routes based on your file structure
|
||||
|
||||
## Getting Started
|
||||
|
||||
To create a new Next.js app, run:
|
||||
|
||||
\`\`\`bash
|
||||
npx create-next-app@latest my-app
|
||||
\`\`\`
|
||||
|
||||
This will set up everything automatically for you.`,
|
||||
},
|
||||
{
|
||||
filename: "markdown-styling-guide.md",
|
||||
content: `---
|
||||
title: "Markdown Styling Guide"
|
||||
date: "2023-06-22"
|
||||
excerpt: "Learn how to style your markdown content for better readability"
|
||||
---
|
||||
|
||||
# Markdown Styling Guide
|
||||
|
||||
Markdown is a lightweight markup language that you can use to add formatting elements to plaintext text documents.
|
||||
|
||||
## Basic Syntax
|
||||
|
||||
### Headers
|
||||
|
||||
# H1
|
||||
## H2
|
||||
### H3
|
||||
|
||||
### Emphasis
|
||||
|
||||
*This text will be italic*
|
||||
_This will also be italic_
|
||||
|
||||
**This text will be bold**
|
||||
__This will also be bold__
|
||||
|
||||
### Lists
|
||||
|
||||
Unordered:
|
||||
|
||||
- Item 1
|
||||
- Item 2
|
||||
- Item 2a
|
||||
- Item 2b
|
||||
|
||||
Ordered:
|
||||
|
||||
1. Item 1
|
||||
2. Item 2
|
||||
3. Item 3
|
||||
|
||||
### Links
|
||||
|
||||
[GitHub](http://github.com)
|
||||
|
||||
### Images
|
||||
|
||||

|
||||
|
||||
### Code
|
||||
|
||||
Inline \`code\` has \`back-ticks around\` it.
|
||||
|
||||
\`\`\`javascript
|
||||
var s = "JavaScript syntax highlighting";
|
||||
alert(s);
|
||||
\`\`\``,
|
||||
},
|
||||
{
|
||||
filename: "building-accessible-websites.md",
|
||||
content: `---
|
||||
title: "Building Accessible Websites"
|
||||
date: "2023-07-10"
|
||||
excerpt: "Learn how to make your websites accessible to everyone"
|
||||
---
|
||||
|
||||
# Building Accessible Websites
|
||||
|
||||
Web accessibility means that websites, tools, and technologies are designed and developed so that people with disabilities can use them.
|
||||
|
||||
## Why Accessibility Matters
|
||||
|
||||
- **Inclusivity**: Everyone should be able to access and use web content
|
||||
- **Legal Requirements**: Many countries have laws requiring web accessibility
|
||||
- **Better UX**: Accessible sites often provide better user experience for everyone
|
||||
- **SEO Benefits**: Many accessibility practices improve SEO
|
||||
|
||||
## Key Accessibility Practices
|
||||
|
||||
### Semantic HTML
|
||||
|
||||
Use the right HTML elements for their intended purpose:
|
||||
|
||||
\`\`\`html
|
||||
<!-- Bad -->
|
||||
<div class="button" onclick="submit()">Submit</div>
|
||||
|
||||
<!-- Good -->
|
||||
<button onclick="submit()">Submit</button>
|
||||
\`\`\`
|
||||
|
||||
### Keyboard Navigation
|
||||
|
||||
Ensure all interactive elements are keyboard accessible:
|
||||
|
||||
- Use proper focus states
|
||||
- Maintain a logical tab order
|
||||
- Provide skip links
|
||||
|
||||
### Alternative Text
|
||||
|
||||
Always provide alt text for images:
|
||||
|
||||
\`\`\`html
|
||||
<img src="chart.png" alt="Bar chart showing sales data for Q1 2023">
|
||||
\`\`\``,
|
||||
},
|
||||
// Adding 5 more dummy posts
|
||||
{
|
||||
filename: "modern-css-techniques.md",
|
||||
content: `---
|
||||
title: "Modern CSS Techniques for 2023"
|
||||
date: "2023-08-05"
|
||||
excerpt: "Explore the latest CSS features and techniques that are changing web development"
|
||||
---
|
||||
|
||||
# Modern CSS Techniques for 2023
|
||||
|
||||
CSS has evolved significantly in recent years, with powerful new features that make complex layouts and effects easier than ever.
|
||||
|
||||
## CSS Grid
|
||||
|
||||
CSS Grid has revolutionized web layouts:
|
||||
|
||||
\`\`\`css
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## CSS Custom Properties (Variables)
|
||||
|
||||
Variables make your CSS more maintainable:
|
||||
|
||||
\`\`\`css
|
||||
:root {
|
||||
--primary-color: #3490dc;
|
||||
--secondary-color: #ffed4a;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Container Queries
|
||||
|
||||
Container queries allow you to style elements based on their parent container's size:
|
||||
|
||||
\`\`\`css
|
||||
@container (min-width: 700px) {
|
||||
.card {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Logical Properties
|
||||
|
||||
Logical properties make internationalization easier:
|
||||
|
||||
\`\`\`css
|
||||
.element {
|
||||
margin-inline: 1rem;
|
||||
padding-block: 0.5rem;
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Conclusion
|
||||
|
||||
Modern CSS is more powerful than ever, enabling developers to create complex layouts and effects with less code and greater flexibility.`,
|
||||
},
|
||||
{
|
||||
filename: "typescript-best-practices.md",
|
||||
content: `---
|
||||
title: "TypeScript Best Practices for Large Projects"
|
||||
date: "2023-08-12"
|
||||
excerpt: "Learn how to effectively use TypeScript in large-scale applications"
|
||||
---
|
||||
|
||||
# TypeScript Best Practices for Large Projects
|
||||
|
||||
TypeScript has become the standard for large-scale JavaScript applications. Here are some best practices to keep your codebase maintainable.
|
||||
|
||||
## Type Everything
|
||||
|
||||
Always define types for your data structures:
|
||||
|
||||
\`\`\`typescript
|
||||
interface User {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
role: 'admin' | 'user' | 'guest';
|
||||
preferences?: UserPreferences;
|
||||
}
|
||||
|
||||
// Instead of:
|
||||
// const user = { id: '123', name: 'John' };
|
||||
\`\`\`
|
||||
|
||||
## Use Discriminated Unions
|
||||
|
||||
Discriminated unions make your code more type-safe:
|
||||
|
||||
\`\`\`typescript
|
||||
type Success = {
|
||||
status: 'success';
|
||||
data: User[];
|
||||
};
|
||||
|
||||
type Error = {
|
||||
status: 'error';
|
||||
message: string;
|
||||
};
|
||||
|
||||
type ApiResponse = Success | Error;
|
||||
|
||||
function handleResponse(response: ApiResponse) {
|
||||
if (response.status === 'success') {
|
||||
// TypeScript knows response.data exists
|
||||
return response.data;
|
||||
} else {
|
||||
// TypeScript knows response.message exists
|
||||
throw new Error(response.message);
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Avoid Any
|
||||
|
||||
The \`any\` type defeats the purpose of TypeScript. Use \`unknown\` instead when necessary:
|
||||
|
||||
\`\`\`typescript
|
||||
// Bad
|
||||
function parseData(data: any) {
|
||||
return data.items;
|
||||
}
|
||||
|
||||
// Good
|
||||
function parseData(data: unknown) {
|
||||
if (typeof data === 'object' && data !== null && 'items' in data) {
|
||||
return (data as { items: unknown[] }).items;
|
||||
}
|
||||
throw new Error('Invalid data format');
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Conclusion
|
||||
|
||||
Following these best practices will help you build more maintainable and robust TypeScript applications.`,
|
||||
},
|
||||
{
|
||||
filename: "serverless-architecture.md",
|
||||
content: `---
|
||||
title: "Introduction to Serverless Architecture"
|
||||
date: "2023-08-20"
|
||||
excerpt: "Understand the benefits and challenges of serverless computing"
|
||||
---
|
||||
|
||||
# Introduction to Serverless Architecture
|
||||
|
||||
Serverless computing allows developers to build and run applications without thinking about servers.
|
||||
|
||||
## What is Serverless?
|
||||
|
||||
Despite the name, serverless doesn't mean there are no servers. It means you don't have to manage them:
|
||||
|
||||
- No provisioning servers
|
||||
- No worrying about scaling
|
||||
- Pay only for what you use
|
||||
- Focus on code, not infrastructure
|
||||
|
||||
## Key Serverless Services
|
||||
|
||||
### AWS Lambda
|
||||
|
||||
\`\`\`javascript
|
||||
exports.handler = async (event) => {
|
||||
const result = await processData(event.data);
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: JSON.stringify(result)
|
||||
};
|
||||
};
|
||||
\`\`\`
|
||||
|
||||
### Azure Functions
|
||||
|
||||
\`\`\`javascript
|
||||
module.exports = async function (context, req) {
|
||||
const result = await processData(req.body);
|
||||
context.res = {
|
||||
status: 200,
|
||||
body: result
|
||||
};
|
||||
};
|
||||
\`\`\`
|
||||
|
||||
## Challenges
|
||||
|
||||
Serverless isn't perfect for every use case:
|
||||
|
||||
- Cold starts can impact performance
|
||||
- Long-running processes aren't ideal
|
||||
- Debugging can be more difficult
|
||||
- Vendor lock-in concerns
|
||||
|
||||
## Conclusion
|
||||
|
||||
Serverless architecture can significantly reduce operational complexity and cost for many applications, but it's important to understand its limitations and use cases.`,
|
||||
},
|
||||
{
|
||||
filename: "react-performance-optimization.md",
|
||||
content: `---
|
||||
title: "React Performance Optimization Techniques"
|
||||
date: "2023-08-25"
|
||||
excerpt: "Learn how to make your React applications faster and more efficient"
|
||||
---
|
||||
|
||||
# React Performance Optimization Techniques
|
||||
|
||||
Performance optimization is crucial for providing a good user experience in React applications.
|
||||
|
||||
## Use React.memo for Component Memoization
|
||||
|
||||
Prevent unnecessary re-renders with React.memo:
|
||||
|
||||
\`\`\`jsx
|
||||
const ExpensiveComponent = React.memo(({ data }) => {
|
||||
// Render using data
|
||||
return <div>{/* ... */}</div>;
|
||||
});
|
||||
\`\`\`
|
||||
|
||||
## Virtualize Long Lists
|
||||
|
||||
Use virtualization for long lists:
|
||||
|
||||
\`\`\`jsx
|
||||
import { FixedSizeList } from 'react-window';
|
||||
|
||||
function VirtualizedList({ items }) {
|
||||
const Row = ({ index, style }) => (
|
||||
<div style={style}>
|
||||
{items[index].name}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<FixedSizeList
|
||||
height={500}
|
||||
width={300}
|
||||
itemCount={items.length}
|
||||
itemSize={35}
|
||||
>
|
||||
{Row}
|
||||
</FixedSizeList>
|
||||
);
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Code Splitting
|
||||
|
||||
Split your code to load only what's needed:
|
||||
|
||||
\`\`\`jsx
|
||||
import React, { Suspense, lazy } from 'react';
|
||||
|
||||
const HeavyComponent = lazy(() => import('./HeavyComponent'));
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<HeavyComponent />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Avoid Inline Functions in Renders
|
||||
|
||||
Inline functions cause unnecessary re-renders:
|
||||
|
||||
\`\`\`jsx
|
||||
// Bad
|
||||
return <button onClick={() => handleClick(id)}>Click me</button>;
|
||||
|
||||
// Good
|
||||
const handleButtonClick = useCallback(() => {
|
||||
handleClick(id);
|
||||
}, [id, handleClick]);
|
||||
|
||||
return <button onClick={handleButtonClick}>Click me</button>;
|
||||
\`\`\`
|
||||
|
||||
## Conclusion
|
||||
|
||||
By implementing these optimization techniques, you can significantly improve the performance of your React applications.`,
|
||||
},
|
||||
{
|
||||
filename: "docker-for-developers.md",
|
||||
content: `---
|
||||
title: "Docker for Frontend Developers"
|
||||
date: "2023-09-01"
|
||||
excerpt: "A practical guide to using Docker in frontend development workflows"
|
||||
---
|
||||
|
||||
# Docker for Frontend Developers
|
||||
|
||||
Docker can streamline your frontend development workflow and ensure consistency across environments.
|
||||
|
||||
## Why Use Docker for Frontend?
|
||||
|
||||
- **Consistency**: Same environment for all developers
|
||||
- **Isolation**: Dependencies don't conflict with your system
|
||||
- **CI/CD Integration**: Easier testing and deployment
|
||||
- **Microservices**: Better for modern architecture
|
||||
|
||||
## Basic Dockerfile for a React App
|
||||
|
||||
\`\`\`dockerfile
|
||||
# Build stage
|
||||
FROM node:16-alpine as build
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM nginx:alpine
|
||||
COPY --from=build /app/build /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
\`\`\`
|
||||
|
||||
## Docker Compose for Development
|
||||
|
||||
\`\`\`yaml
|
||||
version: '3'
|
||||
services:
|
||||
frontend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.dev
|
||||
volumes:
|
||||
- ./src:/app/src
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
\`\`\`
|
||||
|
||||
## Tips for Frontend Docker Setups
|
||||
|
||||
1. Use multi-stage builds to keep images small
|
||||
2. Mount volumes for hot reloading in development
|
||||
3. Consider using Docker for your API during development
|
||||
4. Use environment variables for configuration
|
||||
|
||||
## Conclusion
|
||||
|
||||
Docker can significantly improve your frontend development workflow, especially for complex applications or teams with multiple developers.`,
|
||||
},
|
||||
]
|
||||
|
||||
samplePosts.forEach((post) => {
|
||||
fs.writeFileSync(path.join(postsDirectory, post.filename), post.content)
|
||||
})
|
||||
}
|
6
lib/utils.ts
Normal file
6
lib/utils.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
Reference in New Issue
Block a user