Files
jarv.is/lib/posts.ts
T
jake d6bd6a4702 refactor: simplify comment form state, auth client exports, and feed builder
- Replace CommentFormContext/Provider with a plain `useCommentFormState` hook; the context abstraction was unused outside the file
- Narrow auth-client exports to only `signIn`; `authClient` and `useSession` are no longer exported
- Add `getPosts()` as a canonical sorted-posts helper and use it in `getFrontMatter` and `buildFeed`, removing the redundant sort in the latter
- Drop JSON feed support from `createFeedHandler` since no JSON feed route exists
- Rewrite `FrontMatter` as a `Pick` over the content-collections `Post` type to stay in sync automatically
2026-10-03 09:21:59 -04:00

80 lines
2.4 KiB
TypeScript

import { allPosts } from "content-collections";
export type Post = (typeof allPosts)[number];
/** The subset of a post's fields used for listings, metadata and the OG image (everything except the body). */
export type FrontMatter = Pick<
Post,
| "slug"
| "permalink"
| "date"
| "title"
| "htmlTitle"
| "description"
| "tags"
| "image"
| "noComments"
>;
/** Path to directory with .mdx files, relative to project root. */
export const POSTS_DIR = "notes" as const;
/** Use generated content collections data to get all post slugs. */
export const getSlugs = (): string[] => {
return allPosts.map((post) => post.slug);
};
/** Returns the post for a given slug, or undefined if the slug does not exist. */
export const getPost = (slug: string): Post | undefined => {
return allPosts.find((post) => post.slug === slug);
};
/**
* Returns the post for a page slug in the "notes/<slug>" format used by the `page` and `comment` tables
* (e.g. "notes/dark-mode"), or undefined if it isn't an existing post.
*/
export const getPostByPageSlug = (pageSlug: string): Post | undefined => {
const prefix = `${POSTS_DIR}/`;
if (!pageSlug.startsWith(prefix)) return undefined;
return getPost(pageSlug.slice(prefix.length));
};
/** Returns ALL posts, sorted reverse chronologically. */
export const getPosts = (): Post[] =>
allPosts.toSorted(
(post1, post2) => new Date(post2.date).getTime() - new Date(post1.date).getTime(),
);
/**
* Returns the front matter of ALL posts, sorted reverse chronologically.
*/
export function getFrontMatter(): FrontMatter[];
/**
* Returns the front matter of a given slug, or undefined if the slug does not exist.
*/
export function getFrontMatter(slug: string): FrontMatter | undefined;
export function getFrontMatter(slug?: string): FrontMatter[] | FrontMatter | undefined {
const toFrontMatter = (post: Post): FrontMatter => ({
slug: post.slug,
permalink: post.permalink,
date: post.date,
title: post.title,
htmlTitle: post.htmlTitle,
description: post.description,
tags: post.tags,
image: post.image,
noComments: post.noComments,
});
if (typeof slug === "string") {
const matchedPost = allPosts.find((candidate) => candidate.slug === slug);
return matchedPost ? toFrontMatter(matchedPost) : undefined;
}
if (!slug) {
return getPosts().map(toFrontMatter);
}
throw new Error("getFrontMatter() called with invalid argument.");
}