159 lines
4.4 KiB
TypeScript
159 lines
4.4 KiB
TypeScript
import { imageMetadata } from '@/helpers/images';
|
|
import { defineCollection, z } from 'astro:content';
|
|
|
|
export const defaultCover = '/images/default-cover.jpg';
|
|
|
|
// Copied and modified from https://github.com/zce/velite/blob/main/src/schemas/slug.ts
|
|
// The slug is internally supported by Astro with 'content' type.
|
|
// We add the slug here for validating the YAML configuration.
|
|
const slug = () =>
|
|
z
|
|
.string()
|
|
.min(3)
|
|
.max(200)
|
|
.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/i, 'Invalid slug');
|
|
|
|
const image = (fallbackImage: string) =>
|
|
z
|
|
.string()
|
|
.optional()
|
|
.default(fallbackImage)
|
|
.transform(async (arg) => await imageMetadata(arg));
|
|
|
|
// Categories Collection
|
|
const categoriesCollection = defineCollection({
|
|
type: 'data',
|
|
schema: z.object({
|
|
name: z.string().max(20),
|
|
slug: slug(),
|
|
cover: image(defaultCover),
|
|
description: z.string().max(999).optional(),
|
|
}),
|
|
});
|
|
|
|
// Friends Collection
|
|
const friendsCollection = defineCollection({
|
|
type: 'data',
|
|
schema: z.array(
|
|
z
|
|
.object({
|
|
website: z.string().max(40),
|
|
description: z.string().optional(),
|
|
homepage: z.string().url(),
|
|
poster: z.string(),
|
|
favicon: z.string().optional(),
|
|
})
|
|
.transform((data) => {
|
|
if (data.favicon === undefined) {
|
|
data.favicon = `${data.homepage}/favicon.ico`;
|
|
}
|
|
return data;
|
|
}),
|
|
),
|
|
});
|
|
|
|
// Options Collection
|
|
const optionsCollection = defineCollection({
|
|
type: 'data',
|
|
schema: z.object({
|
|
title: z.string().max(40),
|
|
website: z.string().url(),
|
|
description: z.string().max(100),
|
|
keywords: z.array(z.string()),
|
|
author: z.object({ name: z.string(), email: z.string().email(), url: z.string().url() }),
|
|
navigation: z.array(z.object({ text: z.string(), link: z.string(), target: z.string().optional() })),
|
|
socials: z.array(
|
|
z.object({
|
|
name: z.string(),
|
|
icon: z.string(),
|
|
type: z.enum(['link', 'qrcode']),
|
|
title: z.string().optional(),
|
|
link: z.string().url(),
|
|
}),
|
|
),
|
|
settings: z.object({
|
|
initialYear: z.number().max(2024),
|
|
icpNo: z.string().optional(),
|
|
locale: z.string().optional().default('zh-CN'),
|
|
timeZone: z.string().optional().default('Asia/Shanghai'),
|
|
timeFormat: z.string().optional().default('yyyy-MM-dd HH:mm:ss'),
|
|
twitter: z.string(),
|
|
post: z.object({
|
|
sort: z.enum(['asc', 'desc']),
|
|
feature: z.array(z.string()).optional(),
|
|
category: z.array(z.string()).optional(),
|
|
}),
|
|
pagination: z.object({
|
|
posts: z.number().optional().default(5),
|
|
category: z.number().optional().default(7),
|
|
tags: z.number().optional().default(7),
|
|
search: z.number().optional().default(7),
|
|
}),
|
|
feed: z.object({
|
|
full: z.boolean().optional().default(true),
|
|
size: z.number().optional().default(20),
|
|
}),
|
|
sidebar: z.object({
|
|
search: z.boolean().default(false),
|
|
post: z.number().default(6),
|
|
comment: z.number().default(0),
|
|
tag: z.number().default(20),
|
|
}),
|
|
comments: z.object({
|
|
server: z.string().url().readonly(),
|
|
admins: z.array(z.number()),
|
|
}),
|
|
}),
|
|
}),
|
|
});
|
|
|
|
// Posts Collection
|
|
const postsCollection = defineCollection({
|
|
type: 'content',
|
|
schema: z.object({
|
|
title: z.string().max(99),
|
|
date: z.date(),
|
|
updated: z.date().optional(),
|
|
comments: z.boolean().optional().default(true),
|
|
tags: z.array(z.string()).optional().default([]),
|
|
category: z.string(),
|
|
summary: z.string().optional().default(''),
|
|
cover: image(defaultCover),
|
|
published: z.boolean().optional().default(true),
|
|
}),
|
|
});
|
|
|
|
// Pages Collection
|
|
const pagesCollection = defineCollection({
|
|
type: 'content',
|
|
schema: z.object({
|
|
title: z.string().max(99),
|
|
date: z.date(),
|
|
updated: z.date().optional(),
|
|
comments: z.boolean().optional().default(true),
|
|
cover: image(defaultCover),
|
|
published: z.boolean().optional().default(true),
|
|
friend: z.boolean().optional().default(false),
|
|
}),
|
|
});
|
|
|
|
// Tags Collection
|
|
const tagsCollection = defineCollection({
|
|
type: 'data',
|
|
schema: z.array(
|
|
z.object({
|
|
name: z.string().max(20),
|
|
slug: slug(),
|
|
}),
|
|
),
|
|
});
|
|
|
|
export const collections = {
|
|
categories: categoriesCollection,
|
|
friends: friendsCollection,
|
|
options: optionsCollection,
|
|
pages: pagesCollection,
|
|
posts: postsCollection,
|
|
tags: tagsCollection,
|
|
};
|