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
7 changes: 7 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ function withMarkdocRscLayer(nextConfig = {}) {
/** @type {import('next').NextConfig} */
const nextConfig = {
pageExtensions: ['js', 'jsx', 'md', 'ts', 'tsx'],
// Serve a plain Markdown version of every page at `<path>.md` for agents
async rewrites() {
return [
{ source: '/index.md', destination: '/raw-md' },
{ source: '/:path+.md', destination: '/raw-md/:path+' },
]
},
}

export default withSearch(
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"typescript": "^5.9.3"
},
"devDependencies": {
"@types/js-yaml": "^4.0.9",
"@types/linkify-it": "^3.0.5",
"@types/node": "^24.12.2",
"@types/react": "19.2.14",
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 0 additions & 71 deletions public/llms.txt

This file was deleted.

9 changes: 9 additions & 0 deletions src/app/llms-full.txt/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getLlmsFullTxt } from '@/lib/markdown'

export const dynamic = 'force-static'

export async function GET() {
return new Response(await getLlmsFullTxt(), {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
})
}
9 changes: 9 additions & 0 deletions src/app/llms.txt/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getLlmsTxt } from '@/lib/markdown'

export const dynamic = 'force-static'

export async function GET() {
return new Response(await getLlmsTxt(), {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
})
}
23 changes: 23 additions & 0 deletions src/app/raw-md/[[...slug]]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getMarkdownSlugs, getPageMarkdown } from '@/lib/markdown'

// Serves each docs page as plain Markdown, e.g. `/start-guide/foo.md`.
// Requests are rewritten here from `*.md` URLs in next.config.mjs.
export const dynamic = 'force-static'
export const dynamicParams = false

export async function generateStaticParams() {
let slugs = await getMarkdownSlugs()
return slugs.map((slug) => ({ slug }))
}

export async function GET(
_request: Request,
{ params }: { params: Promise<{ slug?: Array<string> }> },
) {
let { slug = [] } = await params
let markdown = await getPageMarkdown(slug)

return new Response(markdown, {
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
})
}
14 changes: 13 additions & 1 deletion src/components/TableOfContents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@

import { useCallback, useEffect, useState } from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import clsx from 'clsx'

import { RobotHeadIcon } from '@/components/icons/RobotHeadIcon'
import { type Section, type Subsection } from '@/lib/sections'

export function TableOfContents({
tableOfContents,
}: {
tableOfContents: Array<Section>
}) {
let pathname = usePathname()
let markdownHref = pathname === '/' ? '/index.md' : `${pathname}.md`
let [currentSection, setCurrentSection] = useState(tableOfContents[0]?.id)

let getHeadings = useCallback((tableOfContents: Array<Section>) => {
Expand Down Expand Up @@ -64,11 +68,19 @@ export function TableOfContents({
return (
<div className="hidden xl:sticky xl:top-19 xl:-mr-6 xl:block xl:h-[calc(100vh-4.75rem)] xl:flex-none xl:overflow-y-auto xl:py-16 xl:pr-6">
<nav aria-labelledby="on-this-page-title" className="w-56">
<link rel="alternate" type="text/markdown" href={markdownHref} />
<a
href={markdownHref}
className="mb-8 inline-flex items-center gap-2 rounded-full border border-slate-200 px-3 py-1.5 text-sm font-medium text-slate-700 hover:border-slate-300 hover:bg-slate-50 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-300/50 active:bg-slate-100 dark:border-slate-700 dark:text-slate-300 dark:hover:border-slate-600 dark:hover:bg-slate-800 dark:active:bg-slate-700"
>
<RobotHeadIcon aria-hidden="true" className="h-4 w-4 flex-none" />
View as Markdown
</a>
{tableOfContents.length > 0 && (
<>
<h2
id="on-this-page-title"
className="font-proxyma text-md font-bold text-slate-900 dark:text-white"
className="text-md font-proxyma font-bold text-slate-900 dark:text-white"
>
On this page
</h2>
Expand Down
14 changes: 14 additions & 0 deletions src/components/icons/RobotHeadIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export function RobotHeadIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 24 24" {...props}>
<path
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
d="M5.25 9h13.5s2 0 2 2v10s0 2-2 2H5.25s-2 0-2-2V11s0-2 2-2M.75 14v4.5M23.25 14v4.5M6.5 16a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0-3 0M14.5 16a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0-3 0M12 9V6M9.5 3.5a2.5 2.5 0 1 0 5 0 2.5 2.5 0 1 0-5 0"
/>
</svg>
)
}
Loading
Loading