From 5c1b37cf0cdae3e3c798274624c97889fcbbb50e Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 14 Sep 2023 23:43:22 +0100 Subject: [PATCH] split up astro utils --- src/lib/astro.ts | 165 ----------------------- src/lib/{ => astro}/astro.test.ts | 3 +- src/lib/astro/getAllPosts.ts | 14 ++ src/lib/astro/getAllPostsForSearch.ts | 36 +++++ src/lib/astro/getAllTags.ts | 31 +++++ src/lib/astro/getPostsByTag.ts | 9 ++ src/lib/astro/index.ts | 6 + src/lib/astro/loadAndFormatCollection.ts | 77 +++++++++++ src/lib/astro/sortPosts.ts | 11 ++ src/pages/tags/index.astro | 3 + 10 files changed, 189 insertions(+), 166 deletions(-) delete mode 100644 src/lib/astro.ts rename src/lib/{ => astro}/astro.test.ts (94%) create mode 100644 src/lib/astro/getAllPosts.ts create mode 100644 src/lib/astro/getAllPostsForSearch.ts create mode 100644 src/lib/astro/getAllTags.ts create mode 100644 src/lib/astro/getPostsByTag.ts create mode 100644 src/lib/astro/index.ts create mode 100644 src/lib/astro/loadAndFormatCollection.ts create mode 100644 src/lib/astro/sortPosts.ts diff --git a/src/lib/astro.ts b/src/lib/astro.ts deleted file mode 100644 index a28ee5802..000000000 --- a/src/lib/astro.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { getCollection, type CollectionEntry } from 'astro:content' -import { slugifyAll } from './slugify' -import { readOutExif } from './exif' -import path from 'path' -import config from '@config/blog.config' - -export function sortPosts( - posts: CollectionEntry<'articles' | 'links' | 'photos'>[] -) { - return posts.sort( - (a, b) => - Math.floor(new Date(b.data.date as Date)?.getTime() / 1000) - - Math.floor(new Date(a.data.date as Date)?.getTime() / 1000) - ) -} - -export function getPostsByTag( - posts: CollectionEntry<'articles' | 'links' | 'photos'>[], - tag: string -) { - return posts.filter((post) => slugifyAll(post.data.tags || []).includes(tag)) -} - -// -// Main loader for all collections content. -// --- -// Astro's `getCollection()` is never called -// from components, but this helper method instead. -// -export async function loadAndFormatCollection( - name: 'articles' | 'links' | 'photos' -) { - let postsCollection = await getCollection(name) - - // filter out drafts, but only in production - if (import.meta.env.PROD) { - postsCollection = postsCollection.filter(({ data }) => data.draft !== true) - } - - for await (const post of postsCollection) { - // use date from frontmatter, or grab from folder path - const date = post.data.date - ? post.data.date - : new Date(post.id.split('/')[0].substring(0, 10)) - - // remove date from slug - let slug = post.id.split('/')[0].substring(11) as CollectionEntry< - 'articles' | 'photos' | 'links' - >['slug'] - - // links are not folders so remove .md from the end - if (post.collection === 'links') { - slug = slug.substring( - 0, - slug.length - 3 - ) as CollectionEntry<'links'>['slug'] - } - - const githubLink = `${config.repoContentPath}/${post.collection}/${post.id}` - - // extract exif & iptc data from photos - if (post.collection === 'photos') { - const isProd = import.meta.env.PROD - - // - // Get the absolute image path from post.data.image - // to read exif from - // - // production image.src: - // `/_astro/filename.hash.jpg` - // development image.src: - // `/@fs/absolute/system/path/project/src/content/photos/postSlug/filename.jpg?origWidth=3873&origHeight=2796&origFormat=jpg` - // - const imagePath = isProd - ? path.join( - 'content', - 'photos', - post.id.split('/')[0], - post.data.image.src.split('/')[2].split('.')[0].concat('.jpg') - ) - : post.data.image.src.split('?')[0].split('/@fs')[1] - const exif = await readOutExif(imagePath) - post.data.exif = exif - } - - post.slug = slug - post.data.date = date - post.data.githubLink = githubLink - } - - const posts = sortPosts(postsCollection) - return posts -} - -export async function getAllPosts() { - const articles = await loadAndFormatCollection('articles') - const links = await loadAndFormatCollection('links') - const photos = await loadAndFormatCollection('photos') - - const allPosts = sortPosts([...articles, ...links, ...photos]) - return allPosts -} - -export type AllTags = { - name: string - count: number -}[] - -export async function getAllTags( - posts: CollectionEntry<'articles' | 'links' | 'photos'>[] -): Promise { - const allTagsArray = posts - .filter((post) => post.data.tags) - .map((post) => post.data.tags) - .flat() as string[] - const allTagsArrayCleaned = slugifyAll(allTagsArray) - - // Explicitly define the type of tagCounts - const tagCounts: Record = {} - - for (const tag of allTagsArrayCleaned) { - tagCounts[tag] = (tagCounts[tag] || 0) + 1 - } - - const allUniqueTags = Object.keys(tagCounts).map((tag) => ({ - name: tag, - count: tagCounts[tag] - })) - - return allUniqueTags -} - -// helps to reduce DOM size -export async function getAllPostsForSearch() { - const allPosts = await getAllPosts() - - const cleaned = await Promise.all( - allPosts.map(async (post) => { - const imageSrc = ( - post.data as CollectionEntry<'articles' | 'photos'>['data'] - ).image - // const image = imageSrc - // ? await getImage({ - // src: imageSrc, - // width: 300, - // height: 100, - // format: 'png' - // }) - // : null - - return { - slug: post.slug, - data: { - title: post.data.title, - tags: post.data.tags, - collection: post.collection, - lead: post.body.substring(0, 200), - image: imageSrc - } - } - }) - ) - - return cleaned -} diff --git a/src/lib/astro.test.ts b/src/lib/astro/astro.test.ts similarity index 94% rename from src/lib/astro.test.ts rename to src/lib/astro/astro.test.ts index 34cff4a56..4d0d0ecdf 100644 --- a/src/lib/astro.test.ts +++ b/src/lib/astro/astro.test.ts @@ -1,5 +1,6 @@ import { test, expect } from 'vitest' -import { sortPosts, getPostsByTag, getAllTags } from './astro' +import { getPostsByTag, getAllTags } from '.' +import { sortPosts } from './sortPosts' test('sortPosts sorts posts by date in descending order', () => { const posts = [ diff --git a/src/lib/astro/getAllPosts.ts b/src/lib/astro/getAllPosts.ts new file mode 100644 index 000000000..a3be26171 --- /dev/null +++ b/src/lib/astro/getAllPosts.ts @@ -0,0 +1,14 @@ +import { sortPosts } from './sortPosts' +import { loadAndFormatCollection } from './loadAndFormatCollection' +import type { CollectionEntry } from 'astro:content' + +export async function getAllPosts(): Promise< + CollectionEntry<'articles' | 'links' | 'photos'>[] +> { + const articles = await loadAndFormatCollection('articles') + const links = await loadAndFormatCollection('links') + const photos = await loadAndFormatCollection('photos') + + const allPosts = sortPosts([...articles, ...links, ...photos]) + return allPosts +} diff --git a/src/lib/astro/getAllPostsForSearch.ts b/src/lib/astro/getAllPostsForSearch.ts new file mode 100644 index 000000000..f881cd8a0 --- /dev/null +++ b/src/lib/astro/getAllPostsForSearch.ts @@ -0,0 +1,36 @@ +import { type CollectionEntry } from 'astro:content' +import { getAllPosts } from '.' + +// helps to reduce DOM size + +export async function getAllPostsForSearch() { + const allPosts = await getAllPosts() + + const cleaned = await Promise.all( + allPosts.map(async (post) => { + const imageSrc = ( + post.data as CollectionEntry<'articles' | 'photos'>['data'] + ).image + // const image = imageSrc + // ? await getImage({ + // src: imageSrc, + // width: 300, + // height: 100, + // format: 'png' + // }) + // : null + return { + slug: post.slug, + data: { + title: post.data.title, + tags: post.data.tags, + collection: post.collection, + lead: post.body.substring(0, 200), + image: imageSrc + } + } + }) + ) + + return cleaned +} diff --git a/src/lib/astro/getAllTags.ts b/src/lib/astro/getAllTags.ts new file mode 100644 index 000000000..0c4374b52 --- /dev/null +++ b/src/lib/astro/getAllTags.ts @@ -0,0 +1,31 @@ +import { type CollectionEntry } from 'astro:content' +import { slugifyAll } from '../slugify' + +export type AllTags = { + name: string + count: number +}[] + +export async function getAllTags( + posts: CollectionEntry<'articles' | 'links' | 'photos'>[] +): Promise { + const allTagsArray = posts + .filter((post) => post.data.tags) + .map((post) => post.data.tags) + .flat() as string[] + const allTagsArrayCleaned = slugifyAll(allTagsArray) + + // Explicitly define the type of tagCounts + const tagCounts: Record = {} + + for (const tag of allTagsArrayCleaned) { + tagCounts[tag] = (tagCounts[tag] || 0) + 1 + } + + const allUniqueTags = Object.keys(tagCounts).map((tag) => ({ + name: tag, + count: tagCounts[tag] + })) + + return allUniqueTags +} diff --git a/src/lib/astro/getPostsByTag.ts b/src/lib/astro/getPostsByTag.ts new file mode 100644 index 000000000..ea9ce14d4 --- /dev/null +++ b/src/lib/astro/getPostsByTag.ts @@ -0,0 +1,9 @@ +import { type CollectionEntry } from 'astro:content' +import { slugifyAll } from '../slugify' + +export function getPostsByTag( + posts: CollectionEntry<'articles' | 'links' | 'photos'>[], + tag: string +) { + return posts.filter((post) => slugifyAll(post.data.tags || []).includes(tag)) +} diff --git a/src/lib/astro/index.ts b/src/lib/astro/index.ts new file mode 100644 index 000000000..c3ba9f5a1 --- /dev/null +++ b/src/lib/astro/index.ts @@ -0,0 +1,6 @@ +export { getAllPosts } from './getAllPosts' +export { getAllTags } from './getAllTags' +export { getPostsByTag } from './getPostsByTag' +export { loadAndFormatCollection } from './loadAndFormatCollection' +export { sortPosts } from './sortPosts' +export { getAllPostsForSearch } from './getAllPostsForSearch' diff --git a/src/lib/astro/loadAndFormatCollection.ts b/src/lib/astro/loadAndFormatCollection.ts new file mode 100644 index 000000000..206bb9e7b --- /dev/null +++ b/src/lib/astro/loadAndFormatCollection.ts @@ -0,0 +1,77 @@ +import { getCollection, type CollectionEntry } from 'astro:content' +import { readOutExif } from '../exif' +import path from 'path' +import config from '@config/blog.config' +import { sortPosts } from './sortPosts' + +// +// Main loader for all collections content. +// --- +// Astro's `getCollection()` is never called +// from components, but this helper method instead. +// + +export async function loadAndFormatCollection( + name: 'articles' | 'links' | 'photos' +) { + let postsCollection = await getCollection(name) + + // filter out drafts, but only in production + if (import.meta.env.PROD) { + postsCollection = postsCollection.filter(({ data }) => data.draft !== true) + } + + for await (const post of postsCollection) { + // use date from frontmatter, or grab from folder path + const date = post.data.date + ? post.data.date + : new Date(post.id.split('/')[0].substring(0, 10)) + + // remove date from slug + let slug = post.id.split('/')[0].substring(11) as CollectionEntry< + 'articles' | 'photos' | 'links' + >['slug'] + + // links are not folders so remove .md from the end + if (post.collection === 'links') { + slug = slug.substring( + 0, + slug.length - 3 + ) as CollectionEntry<'links'>['slug'] + } + + const githubLink = `${config.repoContentPath}/${post.collection}/${post.id}` + + // extract exif & iptc data from photos + if (post.collection === 'photos') { + const isProd = import.meta.env.PROD + + // + // Get the absolute image path from post.data.image + // to read exif from + // + // production image.src: + // `/_astro/filename.hash.jpg` + // development image.src: + // `/@fs/absolute/system/path/project/src/content/photos/postSlug/filename.jpg?origWidth=3873&origHeight=2796&origFormat=jpg` + // + const imagePath = isProd + ? path.join( + 'content', + 'photos', + post.id.split('/')[0], + post.data.image.src.split('/')[2].split('.')[0].concat('.jpg') + ) + : post.data.image.src.split('?')[0].split('/@fs')[1] + const exif = await readOutExif(imagePath) + post.data.exif = exif + } + + post.slug = slug + post.data.date = date + post.data.githubLink = githubLink + } + + const posts = sortPosts(postsCollection) + return posts +} diff --git a/src/lib/astro/sortPosts.ts b/src/lib/astro/sortPosts.ts new file mode 100644 index 000000000..547ecb6bf --- /dev/null +++ b/src/lib/astro/sortPosts.ts @@ -0,0 +1,11 @@ +import { type CollectionEntry } from 'astro:content' + +export function sortPosts( + posts: CollectionEntry<'articles' | 'links' | 'photos'>[] +): CollectionEntry<'articles' | 'links' | 'photos'>[] { + return posts.sort( + (a, b) => + Math.floor(new Date(b.data.date as Date)?.getTime() / 1000) - + Math.floor(new Date(a.data.date as Date)?.getTime() / 1000) + ) +} diff --git a/src/pages/tags/index.astro b/src/pages/tags/index.astro index 479292ebb..aae5d103e 100644 --- a/src/pages/tags/index.astro +++ b/src/pages/tags/index.astro @@ -47,3 +47,6 @@ const allTags = await getAllTags(allPosts) } + @lib/astro/astro import {getAllPosts} from '@lib/astro/getAllPosts' import { + getAllTags +} from '@lib/astro/AllTags'