Files
kotobane/lib/directus.ts
T

169 lines
4.6 KiB
TypeScript

import {
createDirectus,
rest,
staticToken,
readItems,
readSingleton,
readItem,
} from '@directus/sdk'
import type { Article, Category, SiteSettings } from './types'
function createClient() {
return createDirectus(process.env.DIRECTUS_URL!)
.with(staticToken(process.env.DIRECTUS_TOKEN!))
.with(rest())
}
let _client: ReturnType<typeof createClient> | null = null
function getClient() {
if (!_client) {
_client = createClient()
}
return _client
}
export async function getAllCategories(): Promise<Category[]> {
return getClient().request(
readItems('categories', {
fields: ['id', 'name', 'slug', 'description'],
sort: ['name'],
})
) as Promise<Category[]>
}
export async function getCategoryBySlug(slug: string): Promise<Category | null> {
const results = await getClient().request(
readItems('categories', {
fields: ['id', 'name', 'slug', 'description'],
filter: { slug: { _eq: slug } },
limit: 1,
})
) as Category[]
return results[0] ?? null
}
export async function getArticles(options: {
limit?: number
offset?: number
categorySlug?: string
categoryId?: string
} = {}): Promise<Article[]> {
const { limit = 12, offset = 0, categorySlug, categoryId } = options
const filter: Record<string, unknown> = { status: { _eq: 'published' } }
if (categoryId) {
filter['category'] = { _eq: categoryId }
} else if (categorySlug) {
const cat = await getCategoryBySlug(categorySlug)
if (cat) {
filter['category'] = { _eq: cat.id }
}
}
return getClient().request(
readItems('articles', {
fields: [
'id', 'title', 'slug', 'status', 'excerpt', 'featured_image',
'published_at', 'is_featured',
'category.id', 'category.name', 'category.slug',
],
filter,
sort: ['-published_at'],
limit,
offset,
})
) as Promise<Article[]>
}
export async function getArticleBySlug(slug: string): Promise<Article | null> {
const results = await getClient().request(
readItems('articles', {
fields: [
'id', 'title', 'slug', 'status', 'content', 'excerpt',
'featured_image', 'published_at', 'is_featured',
'seo_title', 'seo_description',
'category.id', 'category.name', 'category.slug',
'tags.tags_id.id', 'tags.tags_id.name', 'tags.tags_id.slug',
],
filter: { slug: { _eq: slug }, status: { _eq: 'published' } },
limit: 1,
})
) as Article[]
return results[0] ?? null
}
export async function getArticlePathById(id: string): Promise<{
slug: string
category: { slug: string }
} | null> {
try {
return await getClient().request(
readItem('articles', id, {
fields: ['slug', 'category.slug'],
})
) as { slug: string; category: { slug: string } }
} catch {
return null
}
}
export async function getRelatedArticles(
categorySlug: string,
excludeSlug: string,
): Promise<Article[]> {
return getClient().request(
readItems('articles', {
fields: [
'id', 'title', 'slug', 'excerpt', 'featured_image',
'published_at', 'category.id', 'category.name', 'category.slug',
],
filter: {
status: { _eq: 'published' },
category: { slug: { _eq: categorySlug } },
slug: { _neq: excludeSlug },
},
sort: ['-published_at'],
limit: 4,
})
) as Promise<Article[]>
}
export async function getSiteSettings(): Promise<SiteSettings> {
return getClient().request(
readSingleton('site_settings', {
fields: [
'id', 'site_name',
'hero_article.id', 'hero_article.title', 'hero_article.slug',
'hero_article.excerpt', 'hero_article.featured_image',
'hero_article.category.slug', 'hero_article.category.name',
],
})
) as Promise<SiteSettings>
}
export async function searchArticles(query: string): Promise<Article[]> {
return getClient().request(
readItems('articles', {
fields: ['id', 'title', 'slug', 'category.slug', 'category.name'],
filter: {
_or: [
{ title: { _icontains: query } },
{ excerpt: { _icontains: query } },
],
status: { _eq: 'published' },
},
limit: 8,
})
) as Promise<Article[]>
}
export function getAssetUrl(
fileId: string,
params?: { width?: number; height?: number; quality?: number },
): string {
const url = new URL(`/api/image/${fileId}`, 'http://localhost')
if (params?.width) url.searchParams.set('width', String(params.width))
if (params?.height) url.searchParams.set('height', String(params.height))
if (params?.quality) url.searchParams.set('quality', String(params.quality))
return url.pathname + url.search
}