feat: add content system with MDX support, types, and meta files for 4 games
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
93
src/lib/content.ts
Normal file
93
src/lib/content.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import matter from "gray-matter";
|
||||
import { GameMeta, Chapter, GameWithChapters } from "@/types";
|
||||
|
||||
const contentDir = path.join(process.cwd(), "content");
|
||||
|
||||
export function getAllGames(): GameMeta[] {
|
||||
const gameDirs = fs.readdirSync(contentDir).filter((dir) => {
|
||||
const fullPath = path.join(contentDir, dir);
|
||||
return fs.statSync(fullPath).isDirectory();
|
||||
});
|
||||
|
||||
return gameDirs.map((slug) => {
|
||||
const metaPath = path.join(contentDir, slug, "meta.json");
|
||||
const meta = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
|
||||
return { slug, ...meta };
|
||||
});
|
||||
}
|
||||
|
||||
export function getGame(slug: string): GameWithChapters {
|
||||
const metaPath = path.join(contentDir, slug, "meta.json");
|
||||
const meta = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
|
||||
|
||||
const gameDir = path.join(contentDir, slug);
|
||||
const chapterFiles = fs
|
||||
.readdirSync(gameDir)
|
||||
.filter((f) => f.endsWith(".mdx"))
|
||||
.sort();
|
||||
|
||||
const chapters = chapterFiles.map((file, index) => {
|
||||
const filePath = path.join(gameDir, file);
|
||||
const raw = fs.readFileSync(filePath, "utf-8");
|
||||
const { data } = matter(raw);
|
||||
const chapterSlug = file.replace(".mdx", "");
|
||||
|
||||
return {
|
||||
slug: chapterSlug,
|
||||
number: index + 1,
|
||||
title: (data.title as string) || chapterSlug,
|
||||
};
|
||||
});
|
||||
|
||||
return { slug, ...meta, chapters };
|
||||
}
|
||||
|
||||
export function getChapter(gameSlug: string, chapterSlug: string): Chapter {
|
||||
const gameDir = path.join(contentDir, gameSlug);
|
||||
const chapterFiles = fs
|
||||
.readdirSync(gameDir)
|
||||
.filter((f) => f.endsWith(".mdx"))
|
||||
.sort();
|
||||
|
||||
const chapterIndex = chapterFiles.findIndex(
|
||||
(f) => f.replace(".mdx", "") === chapterSlug
|
||||
);
|
||||
const filePath = path.join(gameDir, `${chapterSlug}.mdx`);
|
||||
const raw = fs.readFileSync(filePath, "utf-8");
|
||||
const { data, content } = matter(raw);
|
||||
|
||||
return {
|
||||
slug: chapterSlug,
|
||||
number: chapterIndex + 1,
|
||||
title: (data.title as string) || chapterSlug,
|
||||
content,
|
||||
};
|
||||
}
|
||||
|
||||
export function getAdjacentChapters(
|
||||
gameSlug: string,
|
||||
chapterSlug: string
|
||||
): { prev: string | null; next: string | null } {
|
||||
const gameDir = path.join(contentDir, gameSlug);
|
||||
const chapterFiles = fs
|
||||
.readdirSync(gameDir)
|
||||
.filter((f) => f.endsWith(".mdx"))
|
||||
.sort();
|
||||
|
||||
const currentIndex = chapterFiles.findIndex(
|
||||
(f) => f.replace(".mdx", "") === chapterSlug
|
||||
);
|
||||
|
||||
return {
|
||||
prev:
|
||||
currentIndex > 0
|
||||
? chapterFiles[currentIndex - 1].replace(".mdx", "")
|
||||
: null,
|
||||
next:
|
||||
currentIndex < chapterFiles.length - 1
|
||||
? chapterFiles[currentIndex + 1].replace(".mdx", "")
|
||||
: null,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user