Skip to content

Commit 446c2c2

Browse files
Merge branch 'main' into migrate-react-19-4
2 parents 9c2c71b + 9d4cf92 commit 446c2c2

47 files changed

Lines changed: 4899 additions & 2668 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/www/next.config.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const config = {
2222
{
2323
source: '/docs/:path*.md',
2424
destination: '/llms.mdx/:path*'
25+
},
26+
{
27+
source: '/tokens/:path*.mdx',
28+
destination: '/tokens.mdx/:path*'
2529
}
2630
];
2731
},

apps/www/src/app/(llms)/llms-full.txt/route.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ export async function GET() {
1010
const header =
1111
'<SYSTEM>This is the full developer documentation for Apsara Design System.</SYSTEM>';
1212

13-
return new Response(header + '\n\n' + scanned.join('\n\n***\n\n'));
13+
return new Response(header + '\n\n' + scanned.join('\n\n***\n\n'), {
14+
headers: { 'Content-Type': 'text/markdown' }
15+
});
1416
}

apps/www/src/app/(llms)/llms.mdx/[[...slug]]/route.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { getLLMText } from '@/lib/ai';
2-
import { docs } from '@/lib/source';
31
import { notFound } from 'next/navigation';
42
import { type NextRequest, NextResponse } from 'next/server';
3+
import { getLLMText } from '@/lib/ai';
4+
import { docs } from '@/lib/source';
55

66
// cached forever
77
export const revalidate = false;
@@ -15,7 +15,9 @@ export async function GET(
1515

1616
if (!page) notFound();
1717

18-
return new NextResponse(await getLLMText(page));
18+
return new NextResponse(await getLLMText(page), {
19+
headers: { 'Content-Type': 'text/markdown' }
20+
});
1921
}
2022

2123
export function generateStaticParams() {

apps/www/src/app/(llms)/llms.txt/route.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,24 @@ export const revalidate = false;
66
export async function GET() {
77
const scanned: string[] = [];
88
scanned.push('# Apsara Design System Documentation for LLMs');
9+
scanned.push('## tokens');
10+
scanned.push(
11+
[
12+
'- [Color Tokens](/tokens/colors.mdx): CSS variables for foreground, background, border, and overlay colors',
13+
'- [Spacing Tokens](/tokens/spacing.mdx): CSS variables for spacing scale',
14+
'- [Typography Tokens](/tokens/typography.mdx): CSS variables for fonts, sizes, line heights, and letter spacing',
15+
'- [Effects Tokens](/tokens/effects.mdx): CSS variables for shadows and blurs',
16+
'- [Radius Tokens](/tokens/radius.mdx): CSS variables for border radius'
17+
].join('\n')
18+
);
919
const map = new Map<string, string[]>();
1020

1121
for (const page of docs.getPages()) {
1222
const dir = page.slugs[0] ?? 'root';
1323
const list = map.get(dir) ?? [];
14-
list.push(`- [${page.data.title}](${page.url}): ${page.data.description}`);
24+
list.push(
25+
`- [${page.data.title}](${page.url}.mdx): ${page.data.description}`
26+
);
1527
map.set(dir, list);
1628
}
1729

@@ -20,5 +32,7 @@ export async function GET() {
2032
scanned.push(value.join('\n'));
2133
}
2234

23-
return new Response(scanned.join('\n\n'));
35+
return new Response(scanned.join('\n\n'), {
36+
headers: { 'Content-Type': 'text/markdown' }
37+
});
2438
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { promises as fs } from 'fs';
2+
import { notFound } from 'next/navigation';
3+
import path from 'path';
4+
5+
const STYLES_DIR = path.resolve(
6+
process.cwd(),
7+
'../../packages/raystack/styles'
8+
);
9+
10+
export const revalidate = false;
11+
12+
function stripVar(value: string) {
13+
return value.replace(/var\((--[\w-]+)\)/g, '$1');
14+
}
15+
16+
function parseCSSFile(content: string) {
17+
const sections: {
18+
selector: string;
19+
comment: string | null;
20+
tokens: { name: string; value: string }[];
21+
}[] = [];
22+
let currentSelector: string | null = null;
23+
let currentComment: string | null = null;
24+
let tokens: { name: string; value: string }[] = [];
25+
26+
for (const line of content.split('\n')) {
27+
const trimmed = line.trim();
28+
29+
const selectorMatch = trimmed.match(/^(:root|\[[\w-]+="[\w-]+"\])\s*\{/);
30+
if (selectorMatch) {
31+
currentSelector = selectorMatch[1];
32+
continue;
33+
}
34+
35+
if (trimmed === '}') {
36+
if (currentSelector && tokens.length) {
37+
sections.push({
38+
selector: currentSelector,
39+
comment: currentComment,
40+
tokens: [...tokens]
41+
});
42+
}
43+
currentSelector = null;
44+
tokens = [];
45+
currentComment = null;
46+
continue;
47+
}
48+
49+
const commentMatch = trimmed.match(/^\/\*\s*(.+?)\s*\*\/$/);
50+
if (commentMatch && currentSelector) {
51+
if (tokens.length) {
52+
sections.push({
53+
selector: currentSelector,
54+
comment: currentComment,
55+
tokens: [...tokens]
56+
});
57+
tokens = [];
58+
}
59+
currentComment = commentMatch[1];
60+
if (currentComment.startsWith('Example usage:')) currentComment = null;
61+
continue;
62+
}
63+
64+
const varMatch = trimmed.match(
65+
/^(--[\w-]+)\s*:\s*(.+?)\s*;(?:\s*\/\*\s*(.+?)\s*\*\/)?$/
66+
);
67+
if (varMatch && currentSelector) {
68+
tokens.push({ name: varMatch[1], value: stripVar(varMatch[2]) });
69+
}
70+
}
71+
72+
return sections;
73+
}
74+
75+
function toMarkdown(
76+
category: string,
77+
sections: ReturnType<typeof parseCSSFile>
78+
) {
79+
const title = category.charAt(0).toUpperCase() + category.slice(1);
80+
let output = `# ${title} Tokens\n`;
81+
82+
for (const section of sections) {
83+
const prefix =
84+
section.selector === ':root' ? title : `${title} (${section.selector})`;
85+
const heading = section.comment ? `${prefix} - ${section.comment}` : prefix;
86+
87+
output += `\n## ${heading}\n`;
88+
for (const t of section.tokens) {
89+
output += `${t.name}: ${t.value}\n`;
90+
}
91+
}
92+
93+
return output;
94+
}
95+
96+
const CATEGORIES = ['colors', 'effects', 'radius', 'spacing', 'typography'];
97+
98+
export async function GET(
99+
_req: Request,
100+
{ params }: { params: Promise<{ category: string }> }
101+
) {
102+
const { category } = await params;
103+
104+
if (!CATEGORIES.includes(category)) notFound();
105+
106+
const filePath = path.join(STYLES_DIR, `${category}.css`);
107+
const exists = await fs.stat(filePath).then(
108+
() => true,
109+
() => false
110+
);
111+
if (!exists) notFound();
112+
113+
const content = await fs.readFile(filePath, 'utf-8');
114+
115+
const sections = parseCSSFile(content);
116+
return new Response(toMarkdown(category, sections), {
117+
headers: { 'Content-Type': 'text/markdown' }
118+
});
119+
}
120+
121+
export function generateStaticParams() {
122+
return CATEGORIES.map(category => ({ category }));
123+
}

0 commit comments

Comments
 (0)