159 lines
4.4 KiB
TypeScript
159 lines
4.4 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
|
|
} = {}): Promise<Article[]> {
|
|
const { limit = 12, offset = 0, categorySlug } = options
|
|
const filter: Record<string, unknown> = { status: { _eq: 'published' } }
|
|
if (categorySlug) {
|
|
filter['category'] = { slug: { _eq: categorySlug } }
|
|
}
|
|
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',
|
|
'nav_categories.id', 'nav_categories.name', 'nav_categories.slug',
|
|
],
|
|
})
|
|
) as Promise<SiteSettings>
|
|
}
|
|
|
|
export async function searchArticles(query: string): Promise<Article[]> {
|
|
return getClient().request(
|
|
readItems('articles', {
|
|
fields: ['id', 'title', 'slug', 'category.slug', 'category.name'],
|
|
search: query,
|
|
filter: { 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(`/assets/${fileId}`, process.env.DIRECTUS_URL!)
|
|
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.toString()
|
|
}
|