diff --git a/site/app/docs/[[...slug]]/page.tsx b/site/app/docs/[[...slug]]/page.tsx index c6a0a2665..1b4ab8f97 100644 --- a/site/app/docs/[[...slug]]/page.tsx +++ b/site/app/docs/[[...slug]]/page.tsx @@ -1,4 +1,4 @@ -import { ArrowRight, ChevronRight } from "lucide-react"; +import { ArrowRight } from "lucide-react"; import type { Metadata } from "next"; import { MDXRemote } from "next-mdx-remote/rsc"; import Link from "next/link"; @@ -8,27 +8,18 @@ import rehypePrettyCode from "rehype-pretty-code"; import rehypeSlug from "rehype-slug"; import remarkGfm from "remark-gfm"; -import { DocsSearch } from "@/components/docs-search"; import { DocsToc } from "@/components/docs-toc"; -import { Wordmark } from "@/components/logo"; import { mdxComponents } from "@/components/mdx-components"; -import { ThemeToggle } from "@/components/theme-toggle"; -import { Button } from "@/components/ui/button"; import { auraCodeTheme } from "@/lib/aura-code-theme"; import { - type DocsNavItem, docsHref, - getDocsNav, getDocsPage, - getDocsSearchIndex, getDocsStaticParams, getHeadings, getPrevNext, } from "@/lib/docs"; import { cn } from "@/lib/utils"; -const githubUrl = "https://github.com/codegen-sh/graph-sitter"; - type DocsPageProps = { params: Promise<{ slug?: string[]; @@ -72,220 +63,98 @@ export default async function DocsPage({ params }: DocsPageProps) { const showToc = headings.length >= 2; return ( -
-
-
- - - - +
+
+
+

+ {page.title} +

+ {page.description ? ( +

+ {page.description} +

+ ) : null}
-
- -
- - -
-
- - Documentation menu - - -
- -
-
- -
-
-
-

- {page.title} -

- {page.description ? ( -

- {page.description} -

- ) : null} -
- {page.kind === "mdx" ? ( -
- + -
- ) : ( -
- {page.children.map((child) => ( - - - {child.title} - - {child.description ? ( - - {child.description} - - ) : null} - - ))} -
- )} - - {previous || next ? ( - - ) : null} -
- - {showToc ? ( - - ) : null} + ], + rehypeSlug, + [rehypeAutolinkHeadings, { behavior: "wrap" }], + ], + }, + }} + />
-
-
-
- ); -} - -function SidebarInner({ activeSlug }: { activeSlug: string }) { - return ( - <> - - - - ); -} - -function isActiveTree(item: DocsNavItem, slug: string): boolean { - if (item.slug === slug) { - return true; - } - return Boolean(item.children?.some((child) => isActiveTree(child, slug))); -} + )} -function DocsNavListItem({ - activeSlug, - item, -}: { - activeSlug: string; - item: DocsNavItem; -}) { - const isActive = item.slug === activeSlug; - const isOpen = isActiveTree(item, activeSlug); + {previous || next ? ( + + ) : null} + - return ( -
  • - - {item.title} - - {item.children && isOpen ? ( - + {showToc ? ( + ) : null} -
  • + ); } diff --git a/site/app/docs/layout.tsx b/site/app/docs/layout.tsx new file mode 100644 index 000000000..3aca08b71 --- /dev/null +++ b/site/app/docs/layout.tsx @@ -0,0 +1,71 @@ +import { ChevronRight } from "lucide-react"; +import Link from "next/link"; +import type { ReactNode } from "react"; + +import { DocsSidebar } from "@/components/docs-sidebar"; +import { Wordmark } from "@/components/logo"; +import { ThemeToggle } from "@/components/theme-toggle"; +import { Button } from "@/components/ui/button"; +import { getDocsNav, getDocsSearchIndex } from "@/lib/docs"; + +const githubUrl = "https://github.com/codegen-sh/graph-sitter"; + +export default function DocsLayout({ children }: { children: ReactNode }) { + const groups = getDocsNav(); + const searchEntries = getDocsSearchIndex(); + + return ( +
    +
    +
    + + + + +
    +
    + +
    + + +
    +
    + + Documentation menu + + +
    + +
    +
    + + {children} +
    +
    +
    + ); +} diff --git a/site/app/globals.css b/site/app/globals.css index c3cc0480b..7566cdc5b 100644 --- a/site/app/globals.css +++ b/site/app/globals.css @@ -141,8 +141,9 @@ } html { - scroll-behavior: smooth; + scroll-behavior: auto; scroll-padding-top: 5.5rem; + scrollbar-gutter: stable; } body { diff --git a/site/components/docs-sidebar.tsx b/site/components/docs-sidebar.tsx new file mode 100644 index 000000000..ba678eb8f --- /dev/null +++ b/site/components/docs-sidebar.tsx @@ -0,0 +1,99 @@ +"use client"; + +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +import { DocsSearch } from "@/components/docs-search"; +import type { DocsNavGroup, DocsNavItem, DocsSearchEntry } from "@/lib/docs"; +import { cn } from "@/lib/utils"; + +const DEFAULT_SLUG = "introduction/overview"; + +function pathnameToSlug(pathname: string | null) { + if (!pathname || pathname === "/docs" || pathname === "/docs/") { + return DEFAULT_SLUG; + } + + return decodeURIComponent(pathname) + .replace(/^\/docs\//u, "") + .replace(/\/+$/u, ""); +} + +export function DocsSidebar({ + groups, + searchEntries, +}: { + groups: DocsNavGroup[]; + searchEntries: DocsSearchEntry[]; +}) { + const activeSlug = pathnameToSlug(usePathname()); + + return ( + <> + + + + ); +} + +function isActiveTree(item: DocsNavItem, slug: string): boolean { + if (item.slug === slug) { + return true; + } + return Boolean(item.children?.some((child) => isActiveTree(child, slug))); +} + +function DocsNavListItem({ + activeSlug, + item, +}: { + activeSlug: string; + item: DocsNavItem; +}) { + const isActive = item.slug === activeSlug; + const isOpen = isActiveTree(item, activeSlug); + + return ( +
  • + + {item.title} + + {item.children && isOpen ? ( +
      + {item.children.map((child) => ( + + ))} +
    + ) : null} +
  • + ); +}