Utility Functions
Utility functions for blog management, date formatting, filtering, and CSS class manipulation.
Blog Utilities
Functions for working with blog posts and content.
Formats an ISO date string into a human-readable format.
import { formatDate } from '../lib/blogUtils';
ISO date string (e.g., “2024-01-15”)
Returns: string - Formatted date (e.g., “January 15, 2024”)
Usage
const publishedDate = "2024-01-15";
const formatted = formatDate(publishedDate);
// Output: "January 15, 2024"
Implementation
export function formatDate(dateString: string): string {
const date = new Date(dateString);
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
}
Source: src/lib/blogUtils.ts:4
estimateReadingTime
Calculates estimated reading time based on word count.
import { estimateReadingTime } from '../lib/blogUtils';
The full text content to analyze
Returns: number - Reading time in minutes (minimum 1)
Usage
const blogContent = "Lorem ipsum dolor sit amet...";
const readingTime = estimateReadingTime(blogContent);
// Output: 5 (minutes)
Implementation
export function estimateReadingTime(content: string): number {
const wordsPerMinute = 200;
const wordCount = content.split(/\s+/).length;
return Math.max(1, Math.ceil(wordCount / wordsPerMinute));
}
Source: src/lib/blogUtils.ts:14
searchPosts
Searches blog posts by title, excerpt, category, or tags.
import { searchPosts } from '../lib/blogUtils';
import type { BlogPostMetadata } from '../types/blog';
posts
BlogPostMetadata[]
required
Array of blog post metadata to search
Search query string (case-insensitive)
Returns: BlogPostMetadata[] - Filtered posts matching the query
Usage
const allPosts = getAllBlogPosts();
const results = searchPosts(allPosts, "React");
// Returns posts containing "React" in title, excerpt, category, or tags
Implementation
export function searchPosts(
posts: BlogPostMetadata[],
query: string
): BlogPostMetadata[] {
if (!query.trim()) return posts;
const lowerQuery = query.toLowerCase();
return posts.filter(post =>
post.title.toLowerCase().includes(lowerQuery) ||
post.excerpt.toLowerCase().includes(lowerQuery) ||
(post.category && post.category.toLowerCase().includes(lowerQuery)) ||
(post.tags && post.tags.some(tag => tag.toLowerCase().includes(lowerQuery)))
);
}
Source: src/lib/blogUtils.ts:21
filterByCategory
Filters blog posts by category.
import { filterByCategory } from '../lib/blogUtils';
posts
BlogPostMetadata[]
required
Array of blog posts to filter
Category name to filter by (use “All” to return all posts)
Returns: BlogPostMetadata[] - Posts in the specified category
Usage
const allPosts = getAllBlogPosts();
const techPosts = filterByCategory(allPosts, "Technology");
Source: src/lib/blogUtils.ts:34
filterByTag
Filters blog posts by tag.
import { filterByTag } from '../lib/blogUtils';
posts
BlogPostMetadata[]
required
Array of blog posts to filter
Tag name to filter by (use “All” to return all posts)
Returns: BlogPostMetadata[] - Posts containing the specified tag
Usage
const allPosts = getAllBlogPosts();
const reactPosts = filterByTag(allPosts, "React");
Source: src/lib/blogUtils.ts:40
getAllCategories
Extracts all unique categories from blog posts.
import { getAllCategories } from '../lib/blogUtils';
posts
BlogPostMetadata[]
required
Array of blog posts
Returns: string[] - Sorted array of unique category names
Usage
const allPosts = getAllBlogPosts();
const categories = getAllCategories(allPosts);
// Output: ["AI", "Finance", "Technology"]
Source: src/lib/blogUtils.ts:48
Extracts all unique tags from blog posts.
import { getAllTags } from '../lib/blogUtils';
posts
BlogPostMetadata[]
required
Array of blog posts
Returns: string[] - Sorted array of unique tag names
Usage
const allPosts = getAllBlogPosts();
const tags = getAllTags(allPosts);
// Output: ["AI", "Machine Learning", "React", "TypeScript"]
Source: src/lib/blogUtils.ts:59
Blog Data Functions
Functions for loading blog content from markdown files.
getAllBlogPosts
Retrieves all blog post metadata from markdown files.
import { getAllBlogPosts } from '../lib/blog';
Parameters: None
Returns: BlogPostMetadata[] - Array of all blog posts sorted by date (newest first)
Usage
const posts = getAllBlogPosts();
console.log(posts.length); // Number of blog posts
How It Works
- Imports all
.md files from ../blog/ directory using Vite’s glob import
- Parses frontmatter from each markdown file
- Validates required fields (slug, title, date, excerpt)
- Calculates reading time automatically
- Sorts posts by date (newest first)
Source: src/lib/blog.ts:51
getBlogPost
Retrieves a single blog post with full content by slug.
import { getBlogPost } from '../lib/blog';
URL slug of the blog post (e.g., “welcome-to-my-blog”)
Returns: BlogPost | null - Blog post with full content, or null if not found
Usage
const post = getBlogPost("my-first-post");
if (post) {
console.log(post.title);
console.log(post.content); // Full markdown content
}
Source: src/lib/blog.ts:89
parseFrontmatter
Internal function that extracts frontmatter and content from markdown.
function parseFrontmatter(content: string): {
frontmatter: Record<string, any>;
body: string
}
Raw markdown content with YAML frontmatter
Returns: Object with parsed frontmatter and body content
Supported Frontmatter Types
- Strings:
title: "My Post"
- Booleans:
featured: true
- Arrays:
tags: [React, TypeScript]
- Dates:
date: 2024-01-15
Example Markdown
---
slug: my-first-post
title: My First Post
date: 2024-01-15
excerpt: This is my first blog post
category: Technology
tags: [React, TypeScript]
featured: true
---
# Post Content
This is the body of the post...
Source: src/lib/blog.ts:12
Styling Utilities
cn (ClassNames)
Combines and merges Tailwind CSS class names intelligently.
import { cn } from '../lib/utils';
Variable number of class values to merge (strings, objects, arrays)
Returns: string - Merged class names with conflicts resolved
Usage
// Basic usage
const classes = cn("px-4 py-2", "bg-blue-500");
// Output: "px-4 py-2 bg-blue-500"
// Conditional classes
const buttonClass = cn(
"px-4 py-2 rounded",
isActive && "bg-blue-500",
!isActive && "bg-gray-300"
);
// Merging with conflicts (Tailwind merge)
const merged = cn("p-4", "p-2"); // p-2 wins
// Output: "p-2"
Implementation
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Source: src/lib/utils.ts:4
Usage Patterns
Blog List with Filtering
import {
getAllBlogPosts,
searchPosts,
filterByCategory,
getAllCategories
} from '../lib/blog';
function BlogList() {
const allPosts = getAllBlogPosts();
const [query, setQuery] = useState('');
const [category, setCategory] = useState('All');
const categories = ['All', ...getAllCategories(allPosts)];
let filteredPosts = allPosts;
if (query) {
filteredPosts = searchPosts(filteredPosts, query);
}
if (category !== 'All') {
filteredPosts = filterByCategory(filteredPosts, category);
}
return (
<div>
{filteredPosts.map(post => (
<BlogCard key={post.id} post={post} />
))}
</div>
);
}
import { formatDate, estimateReadingTime } from '../lib/blogUtils';
function BlogMeta({ post }) {
return (
<div>
<span>{formatDate(post.date)}</span>
<span>{estimateReadingTime(post.content)} min read</span>
</div>
);
}
Dependencies
clsx - Class name construction
tailwind-merge - Tailwind CSS class merging
- Vite’s
import.meta.glob - Dynamic markdown imports