Skip to content

Commit 3c5ad53

Browse files
fix: new fumadocs stuff and md files for ai (#606)
1 parent b413702 commit 3c5ad53

File tree

25 files changed

+503
-177
lines changed

25 files changed

+503
-177
lines changed
Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,23 @@
1-
/* eslint-disable react/no-unstable-nested-components */
2-
import { Callout } from 'fumadocs-ui/components/callout';
3-
import { Pre, CodeBlock } from 'fumadocs-ui/components/codeblock';
4-
import { ImageZoom } from 'fumadocs-ui/components/image-zoom';
5-
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
6-
import defaultComponents from 'fumadocs-ui/mdx';
7-
import { DocsPage, DocsBody } from 'fumadocs-ui/page';
1+
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/page';
82
import { notFound } from 'next/navigation';
93

10-
import { source } from '@/app/source';
4+
import { LLMCopyButton, ViewOptions } from '@/components/page-actions';
5+
import { source } from '@/lib/source';
6+
import { getMDXComponents } from '@/mdx-components';
117

128
import { Edit } from './Edit';
139

14-
import type { MDXComponents, MDXContent } from 'mdx/types';
1510
import type { Metadata } from 'next';
16-
import type { ReactNode } from 'react';
1711

1812
export default async function Page(props: { readonly params: Promise<{ slugs?: string[] }> }) {
1913
const params = await props.params;
2014
const page = source.getPage(params.slugs);
2115

2216
if (!page) notFound();
2317

24-
const Mdx = page.data.body as MDXContent;
18+
const Mdx = page.data.body;
2519

26-
const path = `apps/website/content/docs/${page.file.path}`;
20+
const path = `apps/website/content/docs/${page.path}`;
2721
const footer = path.includes('/api/') ? null : (
2822
<a
2923
className="inline-flex items-center justify-center font-medium ring-offset-fd-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-fd-ring disabled:pointer-events-none disabled:opacity-50 border bg-fd-secondary text-fd-secondary-foreground hover:bg-fd-secondary/80 h-9 rounded-md px-3 text-xs gap-1.5"
@@ -44,27 +38,21 @@ export default async function Page(props: { readonly params: Promise<{ slugs?: s
4438
tableOfContentPopover={{ footer }}
4539
toc={page.data.toc}
4640
>
41+
<DocsTitle>{page.data.title}</DocsTitle>
42+
<DocsDescription>{page.data.description}</DocsDescription>
43+
<div className="flex flex-row gap-2 items-center border-b pb-6">
44+
<LLMCopyButton markdownUrl={`${page.url}.mdx`} />
45+
<ViewOptions githubUrl={`https://github.com/imranbarbhuiya/TagScript/tree/main/${path}`} markdownUrl={`${page.url}.mdx`} />
46+
</div>
4747
<DocsBody>
48-
<Mdx
49-
components={{
50-
...(defaultComponents as MDXComponents),
51-
pre: ({ ref: _ref, ...rest }) => (
52-
<CodeBlock {...rest}>
53-
<Pre>{rest.children}</Pre>
54-
</CodeBlock>
55-
),
56-
Tab,
57-
Tabs,
58-
InstallTabs: ({ items, children }: { readonly children: ReactNode; readonly items: string[] }) => (
59-
<Tabs id="package-manager" items={items}>
60-
{children}
61-
</Tabs>
62-
),
63-
blockquote: (props) => <Callout>{props.children}</Callout>,
64-
img: (props) => <ImageZoom {...props} />
65-
}}
66-
/>
48+
<Mdx components={getMDXComponents()} />
6749
</DocsBody>
50+
{/* <Rate
51+
onRateAction={async (url, feedback) => {
52+
'use server';
53+
console.log('Feedback received:', { url, feedback });
54+
}}
55+
/> */}
6856
</DocsPage>
6957
);
7058
}
@@ -73,7 +61,7 @@ export async function generateStaticParams() {
7361
return source.generateParams();
7462
}
7563

76-
export async function generateMetadata(props: { params: Promise<{ slugs?: string[] }> }) {
64+
export async function generateMetadata(props: { params: Promise<{ slugs?: string[] }> }): Promise<Metadata> {
7765
const params = await props.params;
7866
const page = source.getPage(params.slugs);
7967

@@ -94,11 +82,28 @@ export async function generateMetadata(props: { params: Promise<{ slugs?: string
9482
title: page.data.title,
9583
description: page.data.description,
9684
openGraph: {
85+
title: page.data.title,
86+
description: page.data.description,
9787
url: `/docs/${page.slugs.join('/')}`,
9888
images: image
9989
},
10090
twitter: {
101-
images: image
91+
card: 'summary_large_image',
92+
title: page.data.title,
93+
description: page.data.description,
94+
images: image,
95+
site: 'https://tagscript.js.org'
96+
},
97+
alternates: {
98+
canonical: `https://tagscript.js.org/${page.url}`,
99+
languages: {
100+
en: `https://tagscript.js.org/${page.url}`
101+
}
102+
},
103+
appleWebApp: {
104+
capable: true,
105+
title: 'Tagscript',
106+
statusBarStyle: 'default'
102107
}
103-
} satisfies Metadata;
108+
};
104109
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createFromSource } from 'fumadocs-core/search/server';
22

3-
import { source } from '@/app/source';
3+
import { source } from '@/lib/source';
44

55
export const { GET } = createFromSource(source);

apps/website/app/layout.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { RootProvider } from 'fumadocs-ui/provider';
44
import { GeistMono } from 'geist/font/mono';
55
import { GeistSans } from 'geist/font/sans';
66

7-
import { source } from '@/app/source';
7+
import { source } from '@/lib/source';
88

99
import type { Metadata, Viewport } from 'next';
1010
import type { ReactNode } from 'react';
@@ -73,5 +73,6 @@ export const viewport: Viewport = {
7373
themeColor: [
7474
{ media: '(prefers-color-scheme: dark)', color: '#0A0A0A' },
7575
{ media: '(prefers-color-scheme: light)', color: '#fff' }
76-
]
76+
],
77+
viewportFit: 'cover'
7778
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { notFound } from 'next/navigation';
2+
import { type NextRequest, NextResponse } from 'next/server';
3+
4+
import { getLLMText } from '@/lib/get-llm-text';
5+
import { source } from '@/lib/source';
6+
7+
export const revalidate = false;
8+
9+
export async function GET(_req: NextRequest, { params }: { params: Promise<{ slugs?: string[] }> }) {
10+
const { slugs } = await params;
11+
const page = source.getPage(slugs);
12+
if (!page) notFound();
13+
14+
return new NextResponse(await getLLMText(page));
15+
}
16+
17+
export function generateStaticParams() {
18+
return source.generateParams();
19+
}

apps/website/app/llms.txt/route.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { getLLMText } from '@/lib/get-llm-text';
2+
import { source } from '@/lib/source';
3+
4+
// cached forever
5+
export const revalidate = false;
6+
7+
export async function GET() {
8+
const scan = source.getPages().map(getLLMText);
9+
const scanned = await Promise.all(scan);
10+
11+
return new Response(scanned.join('\n\n'));
12+
}

apps/website/cli.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"aliases": {
3+
"uiDir": "./components/ui",
4+
"componentsDir": "./components",
5+
"blockDir": "./components",
6+
"cssDir": "./styles",
7+
"libDir": "./lib"
8+
},
9+
"baseDir": "",
10+
"commands": {}
11+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
'use client';
2+
3+
import { cva } from 'class-variance-authority';
4+
import { Popover, PopoverContent, PopoverTrigger } from 'fumadocs-ui/components/ui/popover';
5+
import { useCopyButton } from 'fumadocs-ui/utils/use-copy-button';
6+
import { Check, ChevronDown, Copy, ExternalLinkIcon, MessageCircleIcon } from 'lucide-react';
7+
import { useMemo, useState } from 'react';
8+
9+
import { buttonVariants } from './ui/button';
10+
11+
import { cn } from '../lib/cn';
12+
13+
const cache = new Map<string, string>();
14+
15+
export function LLMCopyButton({
16+
/**
17+
* A URL to fetch the raw Markdown/MDX content of page
18+
*/
19+
markdownUrl
20+
}: {
21+
readonly markdownUrl: string;
22+
}) {
23+
const [isLoading, setIsLoading] = useState(false);
24+
const [checked, onClick] = useCopyButton(async () => {
25+
const cached = cache.get(markdownUrl);
26+
if (cached) return navigator.clipboard.writeText(cached);
27+
28+
setIsLoading(true);
29+
30+
try {
31+
await navigator.clipboard.write([
32+
new ClipboardItem({
33+
'text/plain': fetch(markdownUrl).then(async (res) => {
34+
const content = await res.text();
35+
cache.set(markdownUrl, content);
36+
37+
return content;
38+
})
39+
})
40+
]);
41+
} finally {
42+
setIsLoading(false);
43+
}
44+
});
45+
46+
return (
47+
<button
48+
className={cn(
49+
buttonVariants({
50+
color: 'secondary',
51+
size: 'sm',
52+
className: 'gap-2 [&_svg]:size-3.5 [&_svg]:text-fd-muted-foreground'
53+
})
54+
)}
55+
disabled={isLoading}
56+
onClick={onClick}
57+
type="button"
58+
>
59+
{checked ? <Check /> : <Copy />}
60+
Copy Markdown
61+
</button>
62+
);
63+
}
64+
65+
const optionVariants = cva('text-sm p-2 rounded-lg inline-flex items-center gap-2 hover:text-fd-accent-foreground hover:bg-fd-accent [&_svg]:size-4');
66+
67+
export function ViewOptions({
68+
markdownUrl,
69+
githubUrl
70+
}: {
71+
/**
72+
* A URL to the raw Markdown/MDX content of page
73+
*/
74+
readonly markdownUrl: string;
75+
76+
/**
77+
* Source file URL on GitHub
78+
*/
79+
readonly githubUrl: string;
80+
}) {
81+
const items = useMemo(() => {
82+
const fullMarkdownUrl = typeof window === 'undefined' ? 'loading' : new URL(markdownUrl, window.location.origin);
83+
const q = `Read ${fullMarkdownUrl}, I want to ask questions about it.`;
84+
85+
return [
86+
{
87+
title: 'Open in GitHub',
88+
href: githubUrl,
89+
icon: (
90+
<svg fill="currentColor" role="img" viewBox="0 0 24 24">
91+
<title>GitHub</title>
92+
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
93+
</svg>
94+
)
95+
},
96+
{
97+
title: 'Open in ChatGPT',
98+
href: `https://chatgpt.com/?${new URLSearchParams({
99+
hints: 'search',
100+
q
101+
})}`,
102+
icon: (
103+
<svg fill="currentColor" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
104+
<title>OpenAI</title>
105+
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" />
106+
</svg>
107+
)
108+
},
109+
{
110+
title: 'Open in Claude',
111+
href: `https://claude.ai/new?${new URLSearchParams({
112+
q
113+
})}`,
114+
icon: (
115+
<svg fill="currentColor" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
116+
<title>Anthropic</title>
117+
<path d="M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z" />
118+
</svg>
119+
)
120+
},
121+
{
122+
title: 'Open in T3 Chat',
123+
href: `https://t3.chat/new?${new URLSearchParams({
124+
q
125+
})}`,
126+
icon: <MessageCircleIcon />
127+
}
128+
];
129+
}, [githubUrl, markdownUrl]);
130+
131+
return (
132+
<Popover>
133+
<PopoverTrigger
134+
className={cn(
135+
buttonVariants({
136+
color: 'secondary',
137+
size: 'sm',
138+
className: 'gap-2'
139+
})
140+
)}
141+
>
142+
Open
143+
<ChevronDown className="size-3.5 text-fd-muted-foreground" />
144+
</PopoverTrigger>
145+
<PopoverContent className="flex flex-col overflow-auto">
146+
{items.map((item) => (
147+
<a className={cn(optionVariants())} href={item.href} key={item.href} rel="noreferrer noopener" target="_blank">
148+
{item.icon}
149+
{item.title}
150+
<ExternalLinkIcon className="text-fd-muted-foreground size-3.5 ms-auto" />
151+
</a>
152+
))}
153+
</PopoverContent>
154+
</Popover>
155+
);
156+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { cva, type VariantProps } from 'class-variance-authority';
2+
3+
const variants = {
4+
primary: 'bg-fd-primary text-fd-primary-foreground hover:bg-fd-primary/80',
5+
outline: 'border hover:bg-fd-accent hover:text-fd-accent-foreground',
6+
ghost: 'hover:bg-fd-accent hover:text-fd-accent-foreground',
7+
secondary:
8+
'border bg-fd-secondary text-fd-secondary-foreground hover:bg-fd-accent hover:text-fd-accent-foreground',
9+
} as const;
10+
11+
export const buttonVariants = cva(
12+
'inline-flex items-center justify-center rounded-md p-2 text-sm font-medium transition-colors duration-100 disabled:pointer-events-none disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fd-ring',
13+
{
14+
variants: {
15+
variant: variants,
16+
// fumadocs use `color` instead of `variant`
17+
color: variants,
18+
size: {
19+
sm: 'gap-1 px-2 py-1.5 text-xs',
20+
icon: 'p-1.5 [&_svg]:size-5',
21+
'icon-sm': 'p-1.5 [&_svg]:size-4.5',
22+
'icon-xs': 'p-1 [&_svg]:size-4',
23+
},
24+
},
25+
},
26+
);
27+
28+
export type ButtonProps = VariantProps<typeof buttonVariants>;
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
---
22
title: EmbedParser
33
---
4-
5-
# EmbedParser

apps/website/content/docs/tagscript/parsers/break.mdx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
title: BreakParser
33
---
44

5-
# BreakParser
6-
75
import { Callout } from 'fumadocs-ui/components/callout';
86
import { Tabs } from 'fumadocs-ui/components/tabs';
97

0 commit comments

Comments
 (0)