- Enable `ssr: true` in `nuxt.config.ts` for server-side rendering of meta tags. - Implement `useSeoMeta` in `events/.vue` with fallback logic for Open Graph and Twitter cards. - Update `content.config.ts` to use `asSeoCollection` for the news collection. - Migrate event markdown frontmatter to use standardized SEO fields.
78 lines
2.3 KiB
TypeScript
78 lines
2.3 KiB
TypeScript
import { defineContentConfig, defineCollection, z } from "@nuxt/content";
|
|
import { asSeoCollection } from "@nuxtjs/seo/content";
|
|
|
|
export default defineContentConfig({
|
|
collections: {
|
|
// 活动集合
|
|
events: defineCollection({
|
|
type: "page",
|
|
source: "events/*.md",
|
|
schema: z.object({
|
|
title: z.string(),
|
|
subtitle: z.string(),
|
|
date: z.coerce.date(),
|
|
location: z.string(),
|
|
cover: z.string().url(),
|
|
draft: z.boolean().optional().default(false),
|
|
}),
|
|
}),
|
|
// 新闻集合
|
|
news: defineCollection(
|
|
asSeoCollection({
|
|
type: "page",
|
|
source: "news/*.md",
|
|
schema: z.object({
|
|
title: z.string(),
|
|
date: z.coerce.date(),
|
|
updated: z.coerce.date().optional(),
|
|
author: z.string(),
|
|
description: z.string(),
|
|
cover: z.string().optional(),
|
|
tags: z.array(z.string()).optional(),
|
|
category: z.enum(["活动", "通知", "招聘", "博客"]).optional(),
|
|
highlight: z.boolean().optional(),
|
|
seoTitle: z.string().optional(),
|
|
seoDescription: z.string().optional(),
|
|
ogImage: z.string().optional(),
|
|
draft: z.boolean().optional().default(false),
|
|
}),
|
|
})
|
|
),
|
|
// 名人堂
|
|
hallOfFames: defineCollection({
|
|
type: "page",
|
|
source: "hall-of-fames/*.md",
|
|
schema: z.object({
|
|
name: z.string(),
|
|
photo: z.string().url(),
|
|
title: z.string(),
|
|
description: z.string(),
|
|
gallery: z.array(z.string()),
|
|
}),
|
|
}),
|
|
// 会员名册
|
|
members: defineCollection({
|
|
type: "data",
|
|
source: "members/members.csv",
|
|
schema: z.object({
|
|
// id: z.number(),
|
|
// chinese_name: z.string(),
|
|
// english_name: z.string(),
|
|
// ic: z.string(),
|
|
// mobile: z.string(),
|
|
// home: z.string(),
|
|
// email: z.string(),
|
|
// graduate_level: z.string(),
|
|
// graduate_year: z.string(),
|
|
// marriage_status: z.string(),
|
|
// living_country: z.string(),
|
|
// address_line_1: z.string(),
|
|
// address_line_2: z.string(),
|
|
// address_line_3: z.string(),
|
|
// joined_year: z.string(),
|
|
// receipt_number: z.string(),
|
|
}),
|
|
}),
|
|
},
|
|
});
|