Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/app/[lang]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { RootProvider } from "fumadocs-ui/provider/next";
import { defineI18nUI } from "fumadocs-ui/i18n";
import { i18n } from "@/lib/i18n";
import Script from "next/script";
import englishTranslations from "@/../messages/en.json";
import { Geist, Geist_Mono } from "next/font/google";
import type { Metadata } from "next";
import { baseUrl } from "@/lib/config";
import { cn } from "@/lib/utils";

const geist = Geist({
Expand All @@ -17,9 +17,7 @@ const geistMono = Geist_Mono({
});

export const metadata: Metadata = {
metadataBase: new URL(
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000",
),
metadataBase: new URL(baseUrl),
keywords: [
"hytale modding",
"hytale",
Expand All @@ -33,6 +31,14 @@ export const metadata: Metadata = {
"how to start modding Hytale",
"how to make a mod",
],
alternates: {
types: {
"text/plain": [
{ url: "/llms.txt", title: "LLM-friendly site index" },
{ url: "/llms-full.txt", title: "LLM-friendly full documentation" },
],
},
},
};

const translations = Object.fromEntries(
Expand Down
14 changes: 10 additions & 4 deletions src/app/llms-full.txt/route.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { getLLMText, source } from "@/lib/source";
import { baseUrl } from "@/lib/config";
import { getLLMFullText } from "@/lib/source";

export const revalidate = false;

export async function GET() {
const scan = source.getPages().map(getLLMText);
const scanned = await Promise.all(scan);
const entries = await getLLMFullText(baseUrl);

return new Response(scanned.join("\n\n"));
const header = [
"# Hytale Modding Documentation",
"> The number one community resource for modding Hytale, featuring comprehensive guides, detailed documentation, and essential tools to kickstart your modding journey.",
"\n\n",
].join("\n");

return new Response(header + entries.join("\n\n"));
}
26 changes: 26 additions & 0 deletions src/app/llms.txt/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { baseUrl } from "@/lib/config";
import { getLLMIndex } from "@/lib/source";

export const revalidate = false;

export async function GET() {
const entries = getLLMIndex(baseUrl);

const header = [
"# Hytale Modding Documentation",
"> The number one community resource for modding Hytale, featuring comprehensive guides, detailed documentation, and essential tools to kickstart your modding journey.",
"",
"## Docs",
"",
].join("\n");

const footer = [
"\n",
"## Links",
`- [Full Documentation (LLM-optimized)](${baseUrl}/llms-full.txt)`,
`- [Wiki](https://wiki.hytalemodding.dev) - This is the official Wiki project from HytaleModding. It allows mod teams to create and manage documentation for their mods, making it easy for players and developers to find the information they need.`,
"",
].join("\n");

return new Response(header + entries.join("\n") + footer);
}
3 changes: 1 addition & 2 deletions src/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { baseUrl } from "@/lib/config";
import { source } from "@/lib/source";
import { i18n } from "@/lib/i18n";
import { readdir } from "fs/promises";
import { join } from "path";
import type { MetadataRoute } from "next";

const baseUrl = "https://hytalemodding.dev";

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const sitemap: MetadataRoute.Sitemap = [];

Expand Down
2 changes: 2 additions & 0 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const baseUrl =
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000";
58 changes: 54 additions & 4 deletions src/lib/source.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { docs } from "fumadocs-mdx:collections/server";
import { type InferPageType, loader } from "fumadocs-core/source";
import { lucideIconsPlugin } from "fumadocs-core/source/lucide-icons";
import type { Node } from "fumadocs-core/page-tree";
import { i18n } from "@/lib/i18n";
import { localizePageTree } from "@/lib/tree-localization";

// See https://fumadocs.dev/docs/headless/source-api for more info
export const source = loader({
Expand All @@ -18,10 +20,58 @@ export const source = loader({
// };
// }

export async function getLLMText(page: InferPageType<typeof source>) {
const processed = await page.data.getText("processed");
function getEnglishPages() {
return source.getPages().filter((page) => page.locale === "en");
}

export function getLLMIndex(baseUrl: string) {
const tree = localizePageTree(source.pageTree["en"], "en");
const lines: string[] = [];

function walk(nodes: Node[], depth: number) {
let inSeparator = false;

for (const node of nodes) {
if (node.type === "separator") {
if (node.name) {
const indent = " ".repeat(depth);
lines.push(`${indent}- ${node.name}`);
inSeparator = true;
}

return `# ${page.data.title}
continue;
}

const d = inSeparator ? depth + 1 : depth;
const indent = " ".repeat(d);

if (node.type === "page") {
const desc = node.description ? `: ${node.description}` : "";
lines.push(`${indent}- [${node.name}](${baseUrl}${node.url})${desc}`);
} else if (node.type === "folder") {
if (node.index) {
const desc = node.index.description
? `: ${node.index.description}`
: "";
lines.push(
`${indent}- [${node.name}](${baseUrl}${node.index.url})${desc}`,
);
} else {
lines.push(`${indent}- ${node.name}`);
}
walk(node.children, d + 1);
}
}
}

walk(tree.children, 0);
return lines;
}

${processed}`;
export async function getLLMFullText(baseUrl: string) {
const pages = getEnglishPages().map(async (page) => {
const processed = await page.data.getText("processed");
return `--- ${page.data.title}\nSource: ${baseUrl}${page.url}\n${processed}`;
});
return Promise.all(pages);
}