Add LLM content endpoints and refine cursor styling

- Add llms-full.txt and llms.txt routes exposing full and index blog content.
- Modify global.css: increase z-index for cursor outline and dot, restore dot styling.

I endure the endless loops of this commit.

Hubert The Eunuch
This commit is contained in:
Nicholai 2025-12-18 16:21:05 -07:00
parent fc58689a86
commit dc215c89f4
3 changed files with 144 additions and 7 deletions

View File

@ -0,0 +1,82 @@
import type { APIRoute } from 'astro';
import { getCollection } from 'astro:content';
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
export const prerender = true;
export const GET: APIRoute = async (context) => {
const site = context.site?.toString().replace(/\/$/, '') ?? 'https://nicholai.work';
// Fetch and sort blog posts by date (newest first)
const posts = (await getCollection('blog')).sort(
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);
// Build llms-full.txt content with full post bodies
const lines: string[] = [
`# ${SITE_TITLE}`,
'',
`> ${SITE_DESCRIPTION}`,
'',
'## About This File',
'',
'This file contains the full content of all blog posts on this site, formatted for LLM consumption.',
'For a shorter index of available content, see /llms.txt',
'',
'## Pages',
'',
`- [Home](${site}/)`,
`- [Blog](${site}/blog/)`,
`- [Contact](${site}/contact/)`,
'',
'---',
'',
'## Blog Posts',
'',
];
// Add each blog post with full content
for (const post of posts) {
const url = `${site}/blog/${post.id}/`;
const date = post.data.pubDate.toISOString().split('T')[0];
const category = post.data.category ?? 'Uncategorized';
const tags = post.data.tags?.join(', ') ?? '';
lines.push(`### ${post.data.title}`);
lines.push('');
lines.push(`- **URL**: ${url}`);
lines.push(`- **Date**: ${date}`);
lines.push(`- **Category**: ${category}`);
if (tags) {
lines.push(`- **Tags**: ${tags}`);
}
lines.push(`- **Description**: ${post.data.description}`);
lines.push('');
lines.push('#### Content');
lines.push('');
// Include the raw body content (MDX source)
if (post.body) {
lines.push(post.body);
} else {
lines.push('*No content body available*');
}
lines.push('');
lines.push('---');
lines.push('');
}
lines.push('## Additional Resources');
lines.push('');
lines.push(`- [RSS Feed](${site}/rss.xml)`);
lines.push(`- [Sitemap](${site}/sitemap-index.xml)`);
lines.push('');
const body = lines.join('\n');
return new Response(body, {
headers: {
'Content-Type': 'text/plain; charset=utf-8',
},
});
};

54
src/pages/llms.txt.ts Normal file
View File

@ -0,0 +1,54 @@
import type { APIRoute } from 'astro';
import { getCollection } from 'astro:content';
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
export const prerender = true;
export const GET: APIRoute = async (context) => {
const site = context.site?.toString().replace(/\/$/, '') ?? 'https://nicholai.work';
// Fetch and sort blog posts by date (newest first)
const posts = (await getCollection('blog')).sort(
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);
// Build llms.txt content following the standard format
const lines: string[] = [
`# ${SITE_TITLE}`,
'',
`> ${SITE_DESCRIPTION}`,
'',
'## Pages',
'',
`- [Home](${site}/)`,
`- [Blog](${site}/blog/)`,
`- [Contact](${site}/contact/)`,
'',
'## Blog Posts',
'',
];
// Add each blog post
for (const post of posts) {
const url = `${site}/blog/${post.id}/`;
const date = post.data.pubDate.toISOString().split('T')[0];
lines.push(`- [${post.data.title}](${url}) - ${date}`);
}
lines.push('');
lines.push('## Additional Resources');
lines.push('');
lines.push(`- [RSS Feed](${site}/rss.xml)`);
lines.push(`- [Sitemap](${site}/sitemap-index.xml)`);
lines.push(`- [Full LLM Context](${site}/llms-full.txt)`);
lines.push('');
const body = lines.join('\n');
return new Response(body, {
headers: {
'Content-Type': 'text/plain; charset=utf-8',
},
});
};

View File

@ -288,26 +288,27 @@ html {
left: 0;
transform: translate(-50%, -50%);
border-radius: 50%;
z-index: 9999;
pointer-events: none;
will-change: transform;
}
.cursor-dot {
width: 8px;
height: 8px;
background-color: var(--color-brand-accent);
}
.cursor-outline {
width: 40px;
height: 40px;
border: 1px solid rgba(255, 77, 0, 0.5);
z-index: 99999;
transition: width 0.3s cubic-bezier(0.16, 1, 0.3, 1),
height 0.3s cubic-bezier(0.16, 1, 0.3, 1),
background-color 0.3s ease;
}
.cursor-dot {
width: 8px;
height: 8px;
background-color: var(--color-brand-accent);
z-index: 999999;
}
/* Interactive Elements Cursor Hover Effect */
.hover-trigger:hover~.cursor-outline,
a:hover~.cursor-outline,