Skip to content

Commit e5d9d08

Browse files
authored
feat: add docs site for quicker onboarding (#11)
1 parent 552bcfe commit e5d9d08

37 files changed

Lines changed: 7675 additions & 0 deletions

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
*.log
55
/.vscode/
66
/docs/.vitepress/cache
7+
/docs/node_modules
8+
/docs/.react-router
9+
/docs/.source
10+
/docs/.vite
11+
/docs/build
712
dist
813
dist-ssr
914
explorations

docs/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/node_modules/
3+
4+
# React Router
5+
/.react-router/
6+
/build/
7+
.source
8+
/.vite/

docs/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# docs
2+
3+
This is a React Router application generated with
4+
[Create Fumadocs](https://github.com/fuma-nama/fumadocs).
5+
6+
Run development server:
7+
8+
```bash
9+
npm run dev
10+
# or
11+
pnpm dev
12+
# or
13+
yarn dev
14+
```

docs/app/app.css

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
@import 'tailwindcss';
2+
@import 'fumadocs-ui/css/neutral.css';
3+
@import 'fumadocs-ui/css/preset.css';
4+
5+
@theme {
6+
--color-fd-background: #f3f3f3;
7+
--color-fd-foreground: #1f1f1f;
8+
--color-fd-muted: #e8e6e4;
9+
--color-fd-muted-foreground: #2f2f2f;
10+
--color-fd-popover: #f3f3f3;
11+
--color-fd-popover-foreground: #232323;
12+
--color-fd-card: #f7f4f1;
13+
--color-fd-card-foreground: #232323;
14+
--color-fd-border: #c4c2c0;
15+
--color-fd-primary: #c7441b;
16+
--color-fd-primary-foreground: #fdf7f2;
17+
--color-fd-secondary: #e2dfdc;
18+
--color-fd-secondary-foreground: #232323;
19+
--color-fd-accent: #d8d4d0;
20+
--color-fd-accent-foreground: #232323;
21+
--color-fd-ring: #b63c12;
22+
--font-sans: 'IBM Plex Sans', 'Noto Sans', sans-serif;
23+
--font-display: 'Space Grotesk', 'IBM Plex Sans', 'Noto Sans', sans-serif;
24+
--fd-layout-width: 1200px;
25+
}
26+
27+
:root {
28+
color-scheme: light;
29+
--shiki-light-bg: #f4f1ee;
30+
--shiki-light: #1f1f1f;
31+
}
32+
33+
.dark {
34+
--color-fd-background: #f3f3f3;
35+
--color-fd-foreground: #1f1f1f;
36+
--color-fd-muted: #e8e6e4;
37+
--color-fd-muted-foreground: #2f2f2f;
38+
--color-fd-popover: #f3f3f3;
39+
--color-fd-popover-foreground: #232323;
40+
--color-fd-card: #f7f4f1;
41+
--color-fd-card-foreground: #232323;
42+
--color-fd-border: #c4c2c0;
43+
--color-fd-primary: #c7441b;
44+
--color-fd-primary-foreground: #fdf7f2;
45+
--color-fd-secondary: #e2dfdc;
46+
--color-fd-secondary-foreground: #232323;
47+
--color-fd-accent: #d8d4d0;
48+
--color-fd-accent-foreground: #232323;
49+
--color-fd-ring: #b63c12;
50+
--shiki-dark-bg: #1c1a19;
51+
--shiki-dark: #f5f2ef;
52+
}
53+
54+
body {
55+
background-color: var(--color-fd-background);
56+
background-image:
57+
radial-gradient(1100px 600px at 90% -10%, rgba(234, 91, 38, 0.12), transparent 60%),
58+
radial-gradient(700px 520px at 10% 10%, rgba(35, 35, 35, 0.08), transparent 68%),
59+
radial-gradient(circle at 1px 1px, rgba(35, 35, 35, 0.06) 1px, transparent 0);
60+
background-size: auto, auto, 28px 28px;
61+
background-attachment: fixed, fixed, fixed;
62+
}
63+
64+
.bg-fd-secondary\/50.text-fd-muted-foreground {
65+
background-color: var(--color-fd-secondary);
66+
color: var(--color-fd-foreground);
67+
}
68+
69+
.bg-fd-secondary\/50.text-fd-muted-foreground:hover {
70+
background-color: var(--color-fd-accent);
71+
color: var(--color-fd-accent-foreground);
72+
}
73+
74+
button.bg-fd-secondary\/50.text-fd-muted-foreground {
75+
color: var(--color-fd-foreground);
76+
}
77+
78+
#nd-sidebar,
79+
#nd-sidebar-mobile {
80+
--color-fd-muted: #e8e6e4;
81+
--color-fd-secondary: #e2dfdc;
82+
--color-fd-muted-foreground: #2f2f2f;
83+
--color-fd-card: #f7f4f1;
84+
--color-fd-accent: #d8d4d0;
85+
--color-fd-foreground: #1f1f1f;
86+
color: var(--color-fd-foreground);
87+
}
88+
89+
.dark #nd-sidebar,
90+
.dark #nd-sidebar-mobile {
91+
--color-fd-muted: #e8e6e4;
92+
--color-fd-secondary: #e2dfdc;
93+
--color-fd-muted-foreground: #2f2f2f;
94+
--color-fd-card: #f7f4f1;
95+
--color-fd-accent: #d8d4d0;
96+
--color-fd-foreground: #1f1f1f;
97+
}
98+
99+
#nd-sidebar .text-fd-muted-foreground {
100+
color: var(--color-fd-muted-foreground);
101+
}
102+
103+
#nd-sidebar :where(a, button, span),
104+
#nd-sidebar-mobile :where(a, button, span) {
105+
color: var(--color-fd-foreground);
106+
}
107+
108+
#nd-sidebar :where(.text-fd-muted-foreground, [class*='text-fd-muted-foreground/']),
109+
#nd-sidebar-mobile :where(.text-fd-muted-foreground, [class*='text-fd-muted-foreground/']) {
110+
color: var(--color-fd-foreground) !important;
111+
opacity: 1;
112+
}
113+
114+
#nd-sidebar :where(svg),
115+
#nd-sidebar-mobile :where(svg) {
116+
color: var(--color-fd-foreground);
117+
}
118+
119+
#nd-sidebar :where([data-active='true']),
120+
#nd-sidebar-mobile :where([data-active='true']) {
121+
color: var(--color-fd-primary);
122+
}
123+
124+
#nd-sidebar :where([data-active='true'] svg),
125+
#nd-sidebar-mobile :where([data-active='true'] svg) {
126+
color: var(--color-fd-primary);
127+
}
128+
129+
.shiki :where(.text-fd-muted-foreground, [class*='text-fd-muted-foreground/']) {
130+
color: var(--color-fd-foreground);
131+
opacity: 1;
132+
}
133+
134+
[data-search-full] {
135+
background-color: #e8e6e4 !important;
136+
border-color: var(--color-fd-border) !important;
137+
color: var(--color-fd-foreground) !important;
138+
}
139+
140+
[data-search-full]:hover {
141+
background-color: #dedbd7 !important;
142+
color: var(--color-fd-foreground) !important;
143+
}
144+
145+
[data-search-full] svg {
146+
color: var(--color-fd-foreground) !important;
147+
}
148+
149+
[data-search-full] kbd {
150+
background-color: #f7f4f1 !important;
151+
border-color: var(--color-fd-border) !important;
152+
color: var(--color-fd-foreground) !important;
153+
}
154+
155+
.shiki:not(.not-fumadocs-codeblock *) {
156+
background-color: var(--shiki-light-bg);
157+
box-shadow: inset 0 0 0 1px var(--color-fd-border);
158+
color: var(--shiki-light);
159+
}
160+
161+
.dark .shiki:not(.not-fumadocs-codeblock *) {
162+
background-color: var(--shiki-dark-bg);
163+
}
164+
165+
:where(h1, h2, h3, h4, h5) {
166+
font-family: var(--font-display);
167+
letter-spacing: -0.015em;
168+
}
169+
170+
.fd-docs-title {
171+
letter-spacing: -0.02em;
172+
}
173+
174+
@keyframes fd-rise {
175+
from {
176+
opacity: 0;
177+
transform: translateY(16px);
178+
}
179+
to {
180+
opacity: 1;
181+
transform: translateY(0);
182+
}
183+
}
184+
185+
@keyframes fd-fade {
186+
from {
187+
opacity: 0;
188+
}
189+
to {
190+
opacity: 1;
191+
}
192+
}
193+
194+
.animate-rise {
195+
animation: fd-rise 0.8s cubic-bezier(0.16, 1, 0.3, 1) both;
196+
}
197+
198+
.animate-rise-delay-1 {
199+
animation-delay: 0.08s;
200+
}
201+
202+
.animate-rise-delay-2 {
203+
animation-delay: 0.16s;
204+
}
205+
206+
.animate-rise-delay-3 {
207+
animation-delay: 0.24s;
208+
}
209+
210+
.animate-fade {
211+
animation: fd-fade 0.9s ease-out both;
212+
}
213+
214+
@media (prefers-reduced-motion: reduce) {
215+
.animate-rise,
216+
.animate-rise-delay-1,
217+
.animate-rise-delay-2,
218+
.animate-rise-delay-3,
219+
.animate-fade {
220+
animation: none;
221+
}
222+
}

docs/app/docs/page.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import type { Route } from './+types/page';
2+
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
3+
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
4+
import { source } from '@/lib/source';
5+
import defaultMdxComponents from 'fumadocs-ui/mdx';
6+
import browserCollections from 'fumadocs-mdx:collections/browser';
7+
import { baseOptions } from '@/lib/layout.shared';
8+
import { useFumadocsLoader } from 'fumadocs-core/source/client';
9+
10+
export async function loader({ params }: Route.LoaderArgs) {
11+
const raw = params['*'] ?? '';
12+
const slugs = raw.split('/').filter((v) => v.length > 0);
13+
const page = source.getPage(slugs);
14+
if (!page) throw new Response('Not found', { status: 404 });
15+
const title = page.data?.title;
16+
const description = page.data?.description;
17+
18+
return {
19+
path: page.path,
20+
pageTree: await source.serializePageTree(source.getPageTree()),
21+
frontmatter: {
22+
title,
23+
description,
24+
},
25+
};
26+
}
27+
28+
export function meta({ data }: Route.MetaArgs) {
29+
const title = data?.frontmatter?.title;
30+
const description = data?.frontmatter?.description;
31+
const tags = [] as ReturnType<Route.MetaFunction>;
32+
33+
if (title) {
34+
tags.push({ title });
35+
}
36+
37+
if (description) {
38+
tags.push({ name: 'description', content: description });
39+
}
40+
41+
return tags;
42+
}
43+
44+
const clientLoader = browserCollections.docs.createClientLoader({
45+
component(
46+
{ toc, frontmatter, default: Mdx },
47+
// you can define props for the `<Content />` component
48+
props?: {
49+
className?: string;
50+
},
51+
) {
52+
return (
53+
<DocsPage toc={toc} {...props}>
54+
<DocsTitle>{frontmatter.title}</DocsTitle>
55+
<DocsDescription>{frontmatter.description}</DocsDescription>
56+
<DocsBody>
57+
<Mdx components={{ ...defaultMdxComponents }} />
58+
</DocsBody>
59+
</DocsPage>
60+
);
61+
},
62+
});
63+
64+
export default function Page({ loaderData }: Route.ComponentProps) {
65+
const { path, pageTree } = useFumadocsLoader(loaderData);
66+
67+
return (
68+
<DocsLayout {...baseOptions()} tree={pageTree}>
69+
{clientLoader.useContent(path)}
70+
</DocsLayout>
71+
);
72+
}

docs/app/docs/search.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { Route } from './+types/search';
2+
import { createFromSource } from 'fumadocs-core/search/server';
3+
import { source } from '@/lib/source';
4+
5+
const server = createFromSource(source, {
6+
// https://docs.orama.com/docs/orama-js/supported-languages
7+
language: 'english',
8+
});
9+
10+
export async function loader({ request }: Route.LoaderArgs) {
11+
return server.GET(request);
12+
}

docs/app/lib/layout.shared.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
2+
3+
export function baseOptions(): BaseLayoutProps {
4+
return {
5+
themeSwitch: {
6+
enabled: false,
7+
},
8+
githubUrl: 'https://github.com/dayhaysoos/convex-database-chat',
9+
links: [
10+
{ text: 'Docs', url: '/docs', active: 'nested-url' },
11+
{
12+
text: 'Live Example',
13+
url: 'https://convex-database-chat-production.up.railway.app/',
14+
external: true,
15+
},
16+
],
17+
nav: {
18+
title: 'DatabaseChat',
19+
url: '/docs',
20+
},
21+
};
22+
}

docs/app/lib/source.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { loader } from 'fumadocs-core/source';
2+
import { docs } from 'fumadocs-mdx:collections/server';
3+
4+
export const source = loader({
5+
source: docs.toFumadocsSource(),
6+
baseUrl: '/docs',
7+
});

0 commit comments

Comments
 (0)