Skip to content
Open
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
49 changes: 34 additions & 15 deletions apps/registry/app/llms-full.txt/route.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import { readFile } from "node:fs/promises";
import path from "node:path";

import {
getTemplateGithubUrl,
getTemplatePath,
TEMPLATES,
} from "../../lib/templates";
import registry from "../../registry.json";

const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://ui.vllnt.ai";

type RegistryItem = {
readonly name: string;
readonly title: string;
readonly description: string;
readonly category: string;
readonly dependencies?: readonly string[];
readonly description: string;
readonly name: string;
readonly registryDependencies?: readonly string[];
readonly title: string;
};

const DOC_PAGES: ReadonlyArray<{ slug: string; title: string }> = [
const DOC_PAGES: readonly { slug: string; title: string }[] = [
{ slug: "home", title: "Get Started" },
{ slug: "docs", title: "Documentation" },
{ slug: "philosophy", title: "Philosophy" },
Expand All @@ -28,13 +33,8 @@ function stripFrontmatter(source: string): string {
return source.slice(end + 4).replace(/^\n+/, "");
}

async function readDocPage(slug: string): Promise<string> {
const file = path.join(
process.cwd(),
"content",
"pages",
`${slug}.mdx`,
);
async function readDocumentPage(slug: string): Promise<string> {
const file = path.join(process.cwd(), "content", "pages", `${slug}.mdx`);
try {
const raw = await readFile(file, "utf8");
return stripFrontmatter(raw).trim();
Expand All @@ -61,12 +61,11 @@ async function buildLlmsFullTxt(): Promise<string> {
lines.push("");
lines.push("```bash");
lines.push(`pnpm dlx shadcn@latest add ${SITE_URL}/r/<name>.json`);
lines.push(`# Or with npm: npx shadcn@latest add ${SITE_URL}/r/<name>.json`);
lines.push("```");
lines.push("");

for (const page of DOC_PAGES) {
const body = await readDocPage(page.slug);
const body = await readDocumentPage(page.slug);
if (!body) continue;
lines.push(`## ${page.title}`);
lines.push("");
Expand All @@ -76,6 +75,25 @@ async function buildLlmsFullTxt(): Promise<string> {
lines.push("");
}

lines.push("## Templates");
lines.push("");
lines.push(
"Starter kits pair complete app shapes with component lists and source paths that can be copied or adapted until a supported template CLI is available.",
);
lines.push("");

for (const template of TEMPLATES) {
lines.push(`### ${template.title}`);
lines.push("");
lines.push(`- Slug: \`${template.slug}\``);
lines.push(`- Page: ${SITE_URL}${getTemplatePath(template)}`);
lines.push(`- Demo: ${template.demoUrl}`);
lines.push(`- Source: ${getTemplateGithubUrl(template)}`);
lines.push(`- Audience: ${template.audience}`);
lines.push(`- Components: ${template.components.join(", ")}`);
lines.push("");
}

lines.push("## Components");
lines.push("");
lines.push(
Expand Down Expand Up @@ -107,14 +125,15 @@ async function buildLlmsFullTxt(): Promise<string> {
}

export const dynamic = "force-static";
export const revalidate = 86400;
export const revalidate = 86_400;

export async function GET(): Promise<Response> {
const body = await buildLlmsFullTxt();
return new Response(body, {
headers: {
"Cache-Control":
"public, max-age=0, s-maxage=86400, stale-while-revalidate=604800",
"Content-Type": "text/plain; charset=utf-8",
"Cache-Control": "public, max-age=0, s-maxage=86400, stale-while-revalidate=604800",
},
});
}
35 changes: 27 additions & 8 deletions apps/registry/app/llms.txt/route.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import {
getTemplateGithubUrl,
getTemplatePath,
TEMPLATES,
} from "../../lib/templates";
import registry from "../../registry.json";

const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://ui.vllnt.ai";

type RegistryItem = {
readonly category: string;
readonly description: string;
readonly name: string;
readonly title: string;
readonly description: string;
readonly category: string;
};

const CATEGORY_ORDER: readonly string[] = [
Expand Down Expand Up @@ -51,9 +56,7 @@ function buildLlmsTxt(): string {

const sortedCategories = [
...CATEGORY_ORDER.filter((c) => grouped.has(c)),
...[...grouped.keys()]
.filter((c) => !CATEGORY_ORDER.includes(c))
.sort(),
...[...grouped.keys()].filter((c) => !CATEGORY_ORDER.includes(c)).sort(),
];

const lines: string[] = [];
Expand All @@ -79,6 +82,19 @@ function buildLlmsTxt(): string {
lines.push(
`- [Components index](${SITE_URL}/components): browse all components by category`,
);
lines.push(
`- [Templates](${SITE_URL}/templates): starter kits for full VLLNT UI apps`,
);
lines.push("");

lines.push("## Templates");
lines.push("");
for (const template of TEMPLATES) {
lines.push(
`- [${template.title}](${SITE_URL}${getTemplatePath(template)}): ` +
`${template.description} Source: ${getTemplateGithubUrl(template)}`,
);
}
lines.push("");

lines.push("## Registry API");
Expand All @@ -102,7 +118,9 @@ function buildLlmsTxt(): string {
const label = CATEGORY_LABEL[category] ?? category;
lines.push(`## Components — ${label}`);
lines.push("");
for (const item of [...bucket].sort((a, b) => a.name.localeCompare(b.name))) {
for (const item of [...bucket].sort((a, b) =>
a.name.localeCompare(b.name),
)) {
lines.push(
`- [${item.title}](${SITE_URL}/components/${item.name}): ${item.description}`,
);
Expand All @@ -114,13 +132,14 @@ function buildLlmsTxt(): string {
}

export const dynamic = "force-static";
export const revalidate = 86400;
export const revalidate = 86_400;

export function GET(): Response {
return new Response(buildLlmsTxt(), {
headers: {
"Cache-Control":
"public, max-age=0, s-maxage=86400, stale-while-revalidate=604800",
"Content-Type": "text/plain; charset=utf-8",
"Cache-Control": "public, max-age=0, s-maxage=86400, stale-while-revalidate=604800",
},
});
}
21 changes: 20 additions & 1 deletion apps/registry/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { MetadataRoute } from "next";

import { getTemplatePath, TEMPLATES } from "../lib/templates";
import registry from "../registry.json";

const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://ui.vllnt.ai";
Expand Down Expand Up @@ -36,8 +37,21 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: "monthly",
priority: 0.6,
},
{
url: `${SITE_URL}/templates`,
lastModified,
changeFrequency: "weekly",
priority: 0.8,
},
];

const templateRoutes: MetadataRoute.Sitemap = TEMPLATES.map((template) => ({
url: `${SITE_URL}${getTemplatePath(template)}`,
lastModified,
changeFrequency: "weekly",
priority: 0.7,
}));

const items = (registry as { readonly items: readonly RegistryItem[] }).items;

const componentRoutes: MetadataRoute.Sitemap = items.map((item) => ({
Expand All @@ -62,5 +76,10 @@ export default function sitemap(): MetadataRoute.Sitemap {
})),
];

return [...staticRoutes, ...componentRoutes, ...registryEndpoints];
return [
...staticRoutes,
...templateRoutes,
...componentRoutes,
...registryEndpoints,
];
}
Loading
Loading