diff --git a/docs/app/(docs)/[...slug]/page.tsx b/docs/app/(docs)/[...slug]/page.tsx index 027beab0da5..5fb0df04401 100644 --- a/docs/app/(docs)/[...slug]/page.tsx +++ b/docs/app/(docs)/[...slug]/page.tsx @@ -4,7 +4,7 @@ import * as Twoslash from 'fumadocs-twoslash/ui'; import { Callout } from 'fumadocs-ui/components/callout'; import { TypeTable } from 'fumadocs-ui/components/type-table'; import * as Preview from '@/components/preview'; -import { createMetadata } from '@/lib/metadata'; +import { createMetadata, getPageImage } from '@/lib/metadata'; import { source } from '@/lib/source'; import { Wrapper } from '@/components/preview/wrapper'; import { Mermaid } from '@/components/mdx/mermaid'; @@ -16,21 +16,21 @@ import { HoverCardTrigger, } from '@/components/ui/hover-card'; import Link from 'fumadocs-core/link'; -import { AutoTypeTable } from 'fumadocs-typescript/ui'; -import { createGenerator } from 'fumadocs-typescript'; import { getPageTreePeers } from 'fumadocs-core/page-tree'; import { Card, Cards } from 'fumadocs-ui/components/card'; import { getMDXComponents } from '@/mdx-components'; -import { APIPage } from 'fumadocs-openapi/ui'; import { LLMCopyButton, ViewOptions } from '@/components/ai/page-actions'; -import * as path from 'node:path'; import { Banner } from 'fumadocs-ui/components/banner'; -import { openapi } from '@/lib/openapi'; import { Installation } from '@/components/preview/installation'; import { Customisation } from '@/components/preview/customisation'; -import { DocsPage } from 'fumadocs-ui/page'; +import { + DocsBody, + DocsPage, + PageLastUpdate, +} from 'fumadocs-ui/layouts/docs/page'; import { NotFound } from '@/components/not-found'; // import { getSuggestions } from '@/app/(docs)/[...slug]/suggestions'; +import { PathUtils } from 'fumadocs-core/source'; function PreviewRenderer({ preview }: { preview: string }): ReactNode { if (preview && preview in Preview) { @@ -41,8 +41,6 @@ function PreviewRenderer({ preview }: { preview: string }): ReactNode { return null; } -const generator = createGenerator(); - export const revalidate = false; export default async function Page(props: PageProps<'/[...slug]'>) { @@ -55,22 +53,33 @@ export default async function Page(props: PageProps<'/[...slug]'>) { Promise.resolve([])} /> ); - const preview = page.data.preview; - const { body: Mdx, toc, lastModified } = page.data; + if (page.data.type === 'openapi') { + const { APIPage } = await import('@/components/api-page'); + return ( + +

{page.data.title}

+ + + + +
+ ); + } + + const { body: Mdx, toc, lastModified } = await page.data.load(); return (

{page.data.title}

-

+

{page.data.description}

-
+
) { />
- {preview ? : null} + {page.data.preview && } { const found = source.getPageByHref(href ?? '', { - dir: path.dirname(page.path), + dir: PathUtils.dirname(page.path), }); if (!found) return ; return ( - - + + {props.children}

{found.page.data.title}

@@ -113,12 +122,8 @@ export default async function Page(props: PageProps<'/[...slug]'>) { Banner, Mermaid, TypeTable, - AutoTypeTable: (props) => ( - - ), Wrapper, blockquote: Callout as unknown as FC>, - APIPage: (props) => , DocsCategory: ({ url }) => { return ; }, @@ -129,6 +134,7 @@ export default async function Page(props: PageProps<'/[...slug]'>) { {page.data.index ? : null}
+ {lastModified && } ); } @@ -159,7 +165,7 @@ export async function generateMetadata( page.data.description ?? 'The platform for building ai-driven automations'; const image = { - url: ['/og', ...slug, 'image.webp'].join('/'), + url: getPageImage(page).url, width: 1200, height: 630, }; diff --git a/docs/app/(docs)/[...slug]/suggestions.ts b/docs/app/(docs)/[...slug]/suggestions.ts index c0e6ed7a8ef..5e331e5a702 100644 --- a/docs/app/(docs)/[...slug]/suggestions.ts +++ b/docs/app/(docs)/[...slug]/suggestions.ts @@ -1,18 +1,14 @@ -import { OramaClient } from '@oramacloud/client'; import type { Suggestion } from '@/components/not-found'; - -const client = new OramaClient({ - endpoint: 'https://cloud.orama.run/v1/indexes/docs-fk97oe', - api_key: '', -}); +import { DataSourceId, orama } from '@/lib/orama/client'; export async function getSuggestions(pathname: string): Promise { - const results = await client.search({ + const results = await orama.search({ term: pathname, mode: 'vector', + datasources: [DataSourceId], groupBy: { properties: ['url'], - maxResult: 1, + max_results: 1, }, }); @@ -23,8 +19,8 @@ export async function getSuggestions(pathname: string): Promise { return { id: doc.id, - href: doc.document.url, - title: doc.document.title, + href: doc.document.url as string, + title: doc.document.title as string, }; }); } diff --git a/docs/app/(docs)/layout.tsx b/docs/app/(docs)/layout.tsx index 13d2d8e2420..0e6cbd7e4b1 100644 --- a/docs/app/(docs)/layout.tsx +++ b/docs/app/(docs)/layout.tsx @@ -1,7 +1,11 @@ import { DocsLayout } from 'fumadocs-ui/layouts/docs'; import { baseOptions, linkItems, logo } from '@/lib/layout.shared'; import { source } from '@/lib/source'; -// import { AISearchTrigger } from '@/components/ai/search'; +import { + AISearch, + AISearchPanel, + AISearchTrigger, +} from '@/components/ai/search'; import 'katex/dist/katex.min.css'; export default function Layout({ children }: LayoutProps<'/'>) { @@ -11,7 +15,6 @@ export default function Layout({ children }: LayoutProps<'/'>) { item.type === 'icon')} nav={{ @@ -19,7 +22,7 @@ export default function Layout({ children }: LayoutProps<'/'>) { title: ( <> {logo} - + ByteChef @@ -54,7 +57,10 @@ export default function Layout({ children }: LayoutProps<'/'>) { > {children} - {/**/} + {/**/} + {/* */} + {/* */} + {/**/} ); } diff --git a/docs/app/api/search/route.ts b/docs/app/api/search/route.ts index df889626d76..7cce271e83b 100644 --- a/docs/app/api/search/route.ts +++ b/docs/app/api/search/route.ts @@ -1,4 +1,26 @@ import { source } from '@/lib/source'; -import { createFromSource } from 'fumadocs-core/search/server'; +import { createSearchAPI } from 'fumadocs-core/search/server'; -export const { GET } = createFromSource(source); +export const { GET } = createSearchAPI('advanced', { + language: 'english', + indexes: async () => { + const pages = source.getPages(); + const indexes = await Promise.all( + pages.map(async (page) => { + if (page.data.type === 'openapi') return undefined; + + const loaded = await page.data.load(); + + return { + title: page.data.title, + description: page.data.description, + url: page.url, + id: page.url, + structuredData: loaded.structuredData, + }; + }), + ); + + return indexes.filter((v): v is NonNullable => v !== undefined); + }, +}); diff --git a/docs/app/global.css b/docs/app/global.css index ec30a228f49..7cc42cae6f9 100644 --- a/docs/app/global.css +++ b/docs/app/global.css @@ -1,11 +1,33 @@ -@import 'tailwindcss' source(none); +@import 'tailwindcss'; @import 'fumadocs-ui/css/neutral.css'; @import 'fumadocs-ui/css/preset.css'; @import 'fumadocs-twoslash/twoslash.css'; @import 'fumadocs-openapi/css/preset.css'; - @plugin 'tailwindcss-animate'; +@theme { + --spacing-page: 1436px; + --color-brand: hsl(26, 73%, 51%); + --color-brand-foreground: white; + --color-brand-secondary: #c6bb58; + --color-brand-secondary-foreground: #97890c; + --color-brand-200: hsl(33, 100%, 50%); + + --color-landing-foreground: #59592a; + --color-landing-foreground-200: #a8a866; +} + +.dark { + --color-landing-foreground: #e4e2d0; + --color-landing-foreground-200: #b7af7e; + + --color-brand: #fff383; + --color-brand-secondary: #fc7744; + --color-brand-secondary-foreground: #521700; + --color-brand-foreground: black; + --color-brand-200: #fff7c8; +} + @theme inline { --default-mono-font-family: var(--font-mono); --animate-marquee: marquee var(--duration) infinite linear; @@ -62,17 +84,24 @@ :root { --headless-color: hsl(250, 80%, 54%); - --ui-color: hsl(220, 91%, 54%); + --ui-color: hsl(41, 100%, 40%); +} + +html { + scrollbar-gutter: stable; +} + +html:has(body[data-scroll-locked]) { + scrollbar-gutter: auto; } body { - overscroll-behavior-y: none; background-color: var(--color-fd-background); } .dark { --headless-color: hsl(250 100% 80%); - --ui-color: hsl(217 92% 76%); + --ui-color: #fff383; } @keyframes circuit_1 { diff --git a/docs/app/llms-full.txt/route.ts b/docs/app/llms-full.txt/route.ts index 73b525ffabd..ffdea45d5da 100644 --- a/docs/app/llms-full.txt/route.ts +++ b/docs/app/llms-full.txt/route.ts @@ -4,10 +4,7 @@ import { getLLMText } from '@/lib/get-llm-text'; export const revalidate = false; export async function GET() { - const scan = source - .getPages() - .filter((file) => file.slugs[0] !== 'openapi') - .map(getLLMText); + const scan = source.getPages().map(getLLMText); const scanned = await Promise.all(scan); return new Response(scanned.join('\n\n')); diff --git a/docs/app/og/[...slug]/generate.tsx b/docs/app/og/[...slug]/generate.tsx index 187e7039b6e..3fe445c6aa4 100644 --- a/docs/app/og/[...slug]/generate.tsx +++ b/docs/app/og/[...slug]/generate.tsx @@ -1,32 +1,29 @@ -import { type ImageResponseOptions } from '@takumi-rs/image-response'; import type { ReactNode } from 'react'; -import fs from 'node:fs/promises'; +import { readFile } from 'node:fs/promises'; +import type { ImageResponseOptions } from '@takumi-rs/image-response'; export interface GenerateProps { title: ReactNode; description?: ReactNode; } -const font = fs.readFile('./lib/og/JetBrainsMono-Regular.ttf'); -const fontBold = fs.readFile('./lib/og/JetBrainsMono-Bold.ttf'); +const font = readFile('./lib/og/JetBrainsMono-Regular.ttf').then((data) => ({ + name: 'Mono', + data, + weight: 400, +})); +const fontBold = readFile('./lib/og/JetBrainsMono-Bold.ttf').then((data) => ({ + name: 'Mono', + data, + weight: 600, +})); export async function getImageResponseOptions(): Promise { return { - format: 'webp', width: 1200, height: 630, - fonts: [ - { - name: 'Mono', - data: await font, - weight: 400, - }, - { - name: 'Mono', - data: await fontBold, - weight: 600, - }, - ], + format: 'webp', + fonts: await Promise.all([font, fontBold]), }; } diff --git a/docs/app/og/[...slug]/route.tsx b/docs/app/og/[...slug]/route.tsx index 7310802bb6e..61b1e5b3f04 100644 --- a/docs/app/og/[...slug]/route.tsx +++ b/docs/app/og/[...slug]/route.tsx @@ -2,6 +2,7 @@ import { source } from '@/lib/source'; import { notFound } from 'next/navigation'; import { generate as MetadataImage, getImageResponseOptions } from './generate'; import { ImageResponse } from '@takumi-rs/image-response'; +import { getPageImage } from '@/lib/metadata'; export const revalidate = false; @@ -14,12 +15,10 @@ export async function GET( if (!page) notFound(); return new ImageResponse( - ( - - ), + , await getImageResponseOptions(), ); } @@ -27,8 +26,7 @@ export async function GET( export function generateStaticParams(): { slug: string[]; }[] { - return source.generateParams().map((page) => ({ - ...page, - slug: [...page.slug, 'image.webp'], + return source.getPages().map((page) => ({ + slug: getPageImage(page).segments, })); } diff --git a/docs/app/provider.tsx b/docs/app/provider.tsx index 49676d2c262..33d4d152e9e 100644 --- a/docs/app/provider.tsx +++ b/docs/app/provider.tsx @@ -2,7 +2,7 @@ import { RootProvider } from 'fumadocs-ui/provider/base'; import dynamic from 'next/dynamic'; -import {ReactNode} from 'react'; +import type { ReactNode } from 'react'; import { TooltipProvider } from '@radix-ui/react-tooltip'; import {PostHogProvider} from "@/lib/posthog"; @@ -28,19 +28,19 @@ if (item === 'true') { export function Provider({ children }: { children: ReactNode }) { return ( - - -