init: project setup
This commit is contained in:
107
src/lib/data-utils.ts
Normal file
107
src/lib/data-utils.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { getCollection, type CollectionEntry } from 'astro:content'
|
||||
|
||||
export async function getAllPosts(): Promise<CollectionEntry<'blog'>[]> {
|
||||
const posts = await getCollection('blog')
|
||||
return posts
|
||||
.filter((post) => !post.data.draft)
|
||||
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
|
||||
}
|
||||
|
||||
export async function getRecentPosts(
|
||||
count: number,
|
||||
): Promise<CollectionEntry<'blog'>[]> {
|
||||
const posts = await getAllPosts()
|
||||
return posts.slice(0, count)
|
||||
}
|
||||
|
||||
export async function getAdjacentPosts(currentId: string): Promise<{
|
||||
prev: CollectionEntry<'blog'> | null
|
||||
next: CollectionEntry<'blog'> | null
|
||||
}> {
|
||||
const posts = await getAllPosts()
|
||||
const currentIndex = posts.findIndex((post) => post.id === currentId)
|
||||
|
||||
if (currentIndex === -1) {
|
||||
return { prev: null, next: null }
|
||||
}
|
||||
|
||||
return {
|
||||
next: currentIndex > 0 ? posts[currentIndex - 1] : null,
|
||||
prev: currentIndex < posts.length - 1 ? posts[currentIndex + 1] : null,
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAllTags(): Promise<Map<string, number>> {
|
||||
const posts = await getAllPosts()
|
||||
|
||||
return posts.reduce((acc, post) => {
|
||||
post.data.tags?.forEach((tag: string) => {
|
||||
acc.set(tag, (acc.get(tag) || 0) + 1)
|
||||
})
|
||||
return acc
|
||||
}, new Map<string, number>())
|
||||
}
|
||||
|
||||
export async function getSortedTags(): Promise<
|
||||
{ tag: string; count: number }[]
|
||||
> {
|
||||
const tagCounts = await getAllTags()
|
||||
|
||||
return [...tagCounts.entries()]
|
||||
.map(([tag, count]) => ({ tag, count }))
|
||||
.sort((a, b) => {
|
||||
const countDiff = b.count - a.count
|
||||
return countDiff !== 0 ? countDiff : a.tag.localeCompare(b.tag)
|
||||
})
|
||||
}
|
||||
|
||||
export function groupPostsByYear(
|
||||
posts: CollectionEntry<'blog'>[],
|
||||
): Record<string, CollectionEntry<'blog'>[]> {
|
||||
return posts.reduce(
|
||||
(acc: Record<string, CollectionEntry<'blog'>[]>, post) => {
|
||||
const year = post.data.date.getFullYear().toString()
|
||||
;(acc[year] ??= []).push(post)
|
||||
return acc
|
||||
},
|
||||
{},
|
||||
)
|
||||
}
|
||||
|
||||
export async function getPostsByAuthor(
|
||||
authorId: string,
|
||||
): Promise<CollectionEntry<'blog'>[]> {
|
||||
const posts = await getAllPosts()
|
||||
return posts.filter((post) => post.data.authors?.includes(authorId))
|
||||
}
|
||||
|
||||
export async function getPostsByTag(
|
||||
tag: string,
|
||||
): Promise<CollectionEntry<'blog'>[]> {
|
||||
const posts = await getAllPosts()
|
||||
return posts.filter((post) => post.data.tags?.includes(tag))
|
||||
}
|
||||
|
||||
export async function getAllProjects(): Promise<CollectionEntry<'projects'>[]> {
|
||||
const projects = await getCollection('projects')
|
||||
return projects
|
||||
.sort((a, b) => (b.data.startDate?.valueOf() ?? 0) - (a.data.startDate?.valueOf() ?? 0))
|
||||
}
|
||||
|
||||
export async function getProjectsFeaturedTags(maxCount: number): Promise<string[]> {
|
||||
const projects = await getAllProjects()
|
||||
const tags = new Set<string>()
|
||||
|
||||
for (const project of projects) {
|
||||
if (project.data.tags) {
|
||||
for (const tag of project.data.tags) {
|
||||
tags.add(tag)
|
||||
}
|
||||
}
|
||||
if (tags.size >= maxCount) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(tags).slice(0, maxCount)
|
||||
}
|
||||
21
src/lib/utils.ts
Normal file
21
src/lib/utils.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { type ClassValue, clsx } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
||||
export function formatDate(date: Date) {
|
||||
return Intl.DateTimeFormat('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
}).format(date)
|
||||
}
|
||||
|
||||
export function readingTime(html: string) {
|
||||
const textOnly = html.replace(/<[^>]+>/g, '')
|
||||
const wordCount = textOnly.split(/\s+/).length
|
||||
const readingTimeMinutes = (wordCount / 200 + 1).toFixed()
|
||||
return `${readingTimeMinutes} min read`
|
||||
}
|
||||
Reference in New Issue
Block a user