feat: add Book type to schema and sidebar

- Add BookContentSchema with headline, subtitle, bookBody, reviewBody fields
- Add BookResource type and update GenericResourceSchema
- Add books to sidebar navigation with Bookmark Tabs icon
This commit is contained in:
2026-02-10 18:17:32 +01:00
parent e65938ecc2
commit c232794cc0
5 changed files with 211 additions and 1 deletions

View File

@@ -32,7 +32,7 @@ export const BaseFileSchema = z.object({
});
const makeContentSchema = <
TName extends "Article" | "Review" | "Recipe",
TName extends "Article" | "Review" | "Recipe" | "Book",
TShape extends z.ZodRawShape,
>(
name: TName,
@@ -55,6 +55,9 @@ export const ArticleContentSchema = makeContentSchema("Article", {
export const ReviewContentSchema = makeContentSchema("Review", {
tmdbId: z.number().optional(),
headline: z.string().optional(),
subtitle: z.string().optional(),
bookBody: z.string().optional(),
link: z.string().optional(),
reviewRating: ReviewRatingSchema.optional(),
reviewBody: z.string().optional(),
@@ -76,6 +79,17 @@ export const RecipeContentSchema = makeContentSchema("Recipe", {
url: z.string().optional(),
});
export const BookContentSchema = makeContentSchema("Book", {
headline: z.string().optional(),
subtitle: z.string().optional(),
bookBody: z.string().optional(),
reviewBody: z.string().optional(),
url: z.string().optional(),
reviewRating: ReviewRatingSchema.optional(),
isbn: z.string().optional(),
bookEdition: z.string().optional(),
});
export const articleMetadataSchema = z.object({
headline: z.union([z.null(), z.string()]).describe("Headline of the article"),
author: z.union([z.null(), z.string()]).describe("Author of the article"),
@@ -99,10 +113,15 @@ export const RecipeSchema = BaseFileSchema.extend({
content: RecipeContentSchema,
});
export const BookSchema = BaseFileSchema.extend({
content: BookContentSchema,
});
export const GenericResourceSchema = z.union([
ArticleSchema,
ReviewSchema,
RecipeSchema,
BookSchema,
]);
export type Person = z.infer<typeof PersonSchema>;
@@ -122,6 +141,10 @@ export type RecipeResource = z.infer<typeof RecipeSchema> & {
image?: typeof imageTable.$inferSelect;
};
export type BookResource = z.infer<typeof BookSchema> & {
image?: typeof imageTable.$inferSelect;
};
export type GenericResource = z.infer<typeof GenericResourceSchema> & {
image?: typeof imageTable.$inferSelect;
};
@@ -136,5 +159,8 @@ export function getNameOfResource(res: GenericResource): string {
if (res.content?._type === "Recipe" && res.content.name) {
return res.content.name;
}
if (res.content?._type === "Book" && res.content.headline) {
return res.content.headline;
}
return "Unnamed Resource";
}

View File

@@ -24,4 +24,9 @@ export const resources = {
name: "Series",
link: "/series",
},
"book": {
emoji: "Bookmark Tabs.png",
name: "Books",
link: "/books",
},
} as const;