Skip to content

Conversation

@eluce2
Copy link
Collaborator

@eluce2 eluce2 commented Sep 26, 2025

template docs

Update documentation for ProofKit CLI v2, highlighting new features such as shadcn integration, improved component addition, and deprecation of the FileMaker Add-on Auth. Enhance layout configuration for better navigation in the home layout.

Update CLI to version 2.0.0-beta.3, changing default UI to shadcn/ui for new projects and deprecating legacy Mantine templates. Enhance template documentation and layout configuration for improved navigation. Adjust template category handling in the UI for better organization and clarity.

Refactor template page and CLI command components for improved clarity and functionality. Update installation command to use dynamic CLI versioning and streamline template content display. Enhance error handling in tests for better resilience against undefined values.

Summary by CodeRabbit

  • New Features

    • ProofKit CLI v2 released: defaults to shadcn/ui, new templates flow, and installable via CLI/shadcn; CLI package bumped to v2.
    • New Templates browser in docs with search, category filters, install commands, and per-template pages.
  • Documentation

    • Major CLI docs overhaul (Introduction, v2, Registry, Adding Components); expanded Better-Auth installation guide and new Templates docs and sidebar.
  • Chores

    • Docs app: dependency updates, /docs → /docs/cli redirect, and updated home navigation link.

…uch as shadcn integration, improved component addition, and deprecation of the FileMaker Add-on Auth. Enhance layout configuration for better navigation in the home layout.
…for new projects and deprecating legacy Mantine templates. Enhance template documentation and layout configuration for improved navigation. Adjust template category handling in the UI for better organization and clarity.
…y and functionality. Update installation command to use dynamic CLI versioning and streamline template content display. Enhance error handling in tests for better resilience against undefined values.
@vercel
Copy link

vercel bot commented Sep 26, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
proofkit-docs Ready Ready Preview Sep 26, 2025 4:14pm

Copy link
Collaborator Author

eluce2 commented Sep 26, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

@eluce2 eluce2 marked this pull request as ready for review September 26, 2025 14:49
@cursor
Copy link

cursor bot commented Sep 26, 2025

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on October 11.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Sep 26, 2025

Open in StackBlitz

@proofkit/better-auth

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/better-auth@74

@proofkit/cli

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/cli@74

create-proofkit

pnpm add https://pkg.pr.new/proofgeist/proofkit/create-proofkit@74

@proofkit/fmdapi

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/fmdapi@74

@proofkit/typegen

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/typegen@74

@proofkit/webviewer

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/webviewer@74

commit: e86e9f5

@coderabbitai
Copy link

coderabbitai bot commented Sep 26, 2025

Walkthrough

Adds an in-repo DocsLayout and comprehensive docs UI (sidebar, TOC, page components), template registry pages and helpers, many CLI/v2 and Better-Auth docs updates, CLI version bump to 2.0.0-beta.3, docs CLI/templating wiring, and converts several InferZodPortals imports to type-only.

Changes

Cohort / File(s) Summary
Changesets
/.changeset/quick-ends-drop.md, /.changeset/ui-default-shadcn.md
Add patch changeset for typegen import; mark CLI changeset as major and update messaging to default to shadcn/ui (Mantine available via hidden flag).
Docs config & redirects
apps/docs/cli.json, apps/docs/next.config.ts, apps/docs/package.json
Add docs CLI scaffolding config, introduce /docs/docs/cli redirect, and add/update docs dependencies (Radix UI, next-themes, ts-morph, fumadocs/shiki bumps).
Docs content: CLI, v2, templates, guides
apps/docs/content/docs/cli/*.mdx, apps/docs/content/docs/cli/guides/*, apps/docs/content/docs/templates/*, apps/docs/content/docs/meta.json, apps/docs/content/docs/index.mdx, apps/docs/content/docs/cli/meta.json, apps/docs/content/docs/cli/guides/adding-components/*
Add expanded CLI intro, v2 page, templates/registry pages and meta, Better-Auth install/migration guide updates, adding-components guide and template redirect page.
Docs runtime: templates & registry helpers
apps/docs/src/lib/templates.ts, apps/docs/src/app/docs/templates/[...slug]/page.tsx, apps/docs/src/app/docs/templates/page.tsx, apps/docs/src/app/docs/templates/layout.tsx, apps/docs/src/app/docs/templates/category-config.ts
New template registry helpers, listing page, dynamic template routes with static params/metadata/404 handling, layout that injects templates into page tree, and category config.
Docs layout & navigation wiring
apps/docs/src/app/(home)/layout.tsx, apps/docs/src/app/docs/(docs)/layout.tsx, apps/docs/src/app/layout.config.tsx, apps/docs/src/app/layout.config.tsx
Inject Documentation link on home, switch to local DocsLayout import, change baseOptions typing to use satisfies and remove old Documentation link entry.
Docs UI: layout, page, sidebar, shared types
apps/docs/src/components/layout/docs/*, apps/docs/src/components/layout/page.tsx, apps/docs/src/components/layout/shared/*, apps/docs/src/components/sidebar.tsx
Implement in-repo DocsLayout, DocsPage APIs (breadcrumb, footer, TOC), full Sidebar/PageTree-driven components and shared navigation/link types and helpers.
Docs UI primitives & client components
apps/docs/src/components/ui/*, apps/docs/src/components/CliCommand.tsx, apps/docs/src/components/InitCommand.tsx, apps/docs/src/components/language-toggle.tsx, apps/docs/src/components/theme-toggle.tsx, apps/docs/src/components/search-toggle.tsx, apps/docs/src/components/root-toggle.tsx, apps/docs/src/components/redirect.tsx, apps/docs/src/components/layout/docs/client.tsx, apps/docs/src/components/layout/docs/page-client.tsx, apps/docs/src/components/layout/shared/client.tsx, apps/docs/src/components/templates/*
Add UI primitives (buttonVariants, Collapsible, Popover, ScrollArea, Skeleton, TOC helpers, TocThumb, ClerkTOCItems), CliCommand exec mode with manager execPrefix and bun support, InitCommand uses cliVersion, language/theme/search toggles, Redirect and root-toggle, and many client-side layout components (Navbar, LayoutBody, TOC/footer/breadcrumb pieces, templates client).
Docs lib utilities & constants
apps/docs/src/lib/constants.ts, apps/docs/src/lib/is-active.ts, apps/docs/src/lib/merge-refs.ts
Add cliVersion constant, isActive/isTabActive utilities, and mergeRefs helper.
Docs app config & package
apps/docs/next.config.ts, apps/docs/package.json
Add local lib import, redirect rule, and dependency additions/updates for docs app.
CLI package & template bump
packages/cli/package.json, packages/cli/template/nextjs-shadcn/package.json
Bump CLI package to 2.0.0-beta.3 and update nextjs-shadcn template dependency versions (next/react/react-dom, others) and remove packageManager field.
Typegen: type-only imports & snapshots
packages/typegen/src/buildSchema.ts, packages/typegen/tests/__snapshots__/*.snap.ts
Convert InferZodPortals imports to type-only (isTypeOnly true in buildSchema import config and import type in snapshots).
FMDAPI tests & config
packages/fmdapi/tests/client-methods.test.ts, packages/fmdapi/tests/tsconfig.json
Harden tests with optional chaining for nested response fields; add rootDir to tests tsconfig.
Tests & snapshots
packages/typegen/tests/__snapshots__/*, packages/fmdapi/tests/*
Update snapshots and tests to reflect type-only import changes and optional-chaining guards.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Browser
  participant Next as Next.js (server)
  participant TemplatesLib as apps/docs/src/lib/templates
  participant TemplatesPage
  participant DocsLayout

  Browser->>Next: GET /docs/templates
  Next->>TemplatesPage: render TemplatesPage()
  TemplatesPage->>TemplatesLib: getAllTemplates(), getTemplatesByCategory()
  TemplatesLib-->>TemplatesPage: templates[], byCategory
  TemplatesPage->>DocsLayout: render TemplatesLayout with templates
  DocsLayout-->>Browser: HTML for templates listing + sidebar
Loading
sequenceDiagram
  autonumber
  participant MDX as MDX page
  participant CliCmd as CliCommand component
  participant Managers as MANAGERS config

  MDX->>CliCmd: render <CliCommand command="add better-auth" exec=true />
  CliCmd->>Managers: read manager prefixes & execPrefix
  alt exec = true
    Managers-->>CliCmd: use execPrefix + execPackage
    CliCmd-->>MDX: render e.g. "npx @proofkit/cli@beta add better-auth"
  else
    Managers-->>CliCmd: use manager prefix
    CliCmd-->>MDX: render e.g. "npm add better-auth"
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • chriscors

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title Check ❓ Inconclusive The title “template docs” is a brief noun phrase rather than a descriptive sentence and fails to capture the scope of the changes. It is too generic to indicate that this PR updates ProofKit CLI v2 documentation, adds new template pages, and refactors layout components. As a result, it does not clearly communicate the primary purpose of the changeset. Please revise the title to a concise, descriptive sentence that highlights the main change. For example, “Update ProofKit CLI v2 template documentation and layout configuration” would make the purpose of this PR clear at a glance.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 09-19-template_docs

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7522e61 and e86e9f5.

📒 Files selected for processing (1)
  • apps/docs/src/lib/templates.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/docs/src/lib/templates.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 32

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/docs/content/docs/cli/meta.json (1)

7-20: Missing CLI docs pages
The following nav entries reference MDX files that don’t exist:

  • apps/docs/content/docs/cli/guides/adding-components.mdx
  • apps/docs/content/docs/cli/guides/auth.mdx
  • apps/docs/content/docs/cli/webviewer.mdx
    Add or correct these files to prevent broken navigation.
apps/docs/content/docs/better-auth/installation.mdx (1)

38-39: Grammar: clarify secrets wording.

Apply this diff:

-Configure your database connection in your `auth.ts` file. Be sure to set these value secrets in your environment variables.
+Configure your database connection in your `auth.ts` file. Be sure to set these values as secrets in your environment variables.
🧹 Nitpick comments (27)
apps/docs/src/app/docs/templates/category-config.ts (1)

7-11: Tighten icon typing to LucideIcon for better type safety.

Use lucide’s exported type instead of ComponentType<any>.

Apply this diff:

-import type { ComponentType } from "react";
+import type { ComponentType } from "react";
+import type { LucideIcon } from "lucide-react";
@@
 export interface CategoryConfig {
   category: Category;
   name: string;
-  icon: ComponentType<any>;
+  icon: LucideIcon;
 }
apps/docs/src/components/theme-toggle.tsx (2)

5-5: Prefer useEffect to avoid SSR warnings with useLayoutEffect.

This component runs on the client, but React/Next can still warn about useLayoutEffect during SSR. useEffect is sufficient here.

Apply this diff:

-import { type HTMLAttributes, useLayoutEffect, useState } from 'react';
+import { type HTMLAttributes, useEffect, useState } from 'react';
@@
-  useLayoutEffect(() => {
+  useEffect(() => {
     setMounted(true);
   }, []);

Also applies to: 36-39


49-55: Small a11y/UX tweaks: button type and pressed state.

  • Explicitly set type="button" to avoid accidental form submits.
  • Expose pressed state for the 3‑option toggle via aria-pressed.

Apply this diff:

       <button
         className={container}
         aria-label={`Toggle Theme`}
+        type="button"
         onClick={() => setTheme(value === 'light' ? 'dark' : 'light')}
         data-theme-toggle=""
         {...props}
       >
-      {full.map(([key, Icon]) => (
+      {full.map(([key, Icon]) => (
         <button
           key={key}
           aria-label={key}
           className={cn(itemVariants({ active: value === key }))}
+          type="button"
+          aria-pressed={value === key}
           onClick={() => setTheme(key)}
         >
           <Icon className="size-full" fill="currentColor" />
         </button>
       ))}

Also applies to: 74-85

apps/docs/src/components/layout/page.tsx (1)

79-82: Prop type/docs mismatch for disabling footer.

Docs say “disable by passing false”, but footer type does not allow false and the render path assumes an object. Support false and guard accordingly.

Apply this diff:

-export interface DocsPageProps {
+export interface DocsPageProps {
@@
-  /**
-   * Footer navigation, you can disable it by passing `false`
-   */
-  footer?: Partial<FooterOptions>;
+  /**
+   * Footer navigation, you can disable it by passing `false`
+   */
+  footer?: Partial<FooterOptions> | false;
-        {footer.enabled !== false &&
-          (footer.component ?? <PageFooter items={footer.items} />)}
+        {footer !== false &&
+          (footer.enabled !== false) &&
+          (footer.component ?? <PageFooter items={footer.items} />)}

Also applies to: 189-191

apps/docs/cli.json (1)

1-11: Consider adding a JSON Schema for editor validation.

If your CLI provides a schema, add a $schema field so editors can validate keys/paths and provide intellisense. Example key (replace with your actual schema URL/path):

 {
+  "$schema": "<path-or-url-to-docs-cli.schema.json>",
   "aliases": {
     "uiDir": "./components/ui",
     "componentsDir": "./components",
     "blockDir": "./components",
     "cssDir": "./styles",
     "libDir": "./lib"
   },
   "baseDir": "src",
   "commands": {}
 }
apps/docs/src/components/redirect.tsx (1)

7-14: Client redirect is fine; add a small guard and a11y hint.

Avoid no‑op replaces and expose loading state for AT users.

-import { useRouter } from "next/navigation";
+import { usePathname, useRouter } from "next/navigation";
 import { Skeleton } from "./ui/skeleton";

 export default function Redirect({ href }: { href: string }) {
   const router = useRouter();
+  const pathname = usePathname();
   useEffect(() => {
-    router.replace(href);
-  }, [href, router]);
+    if (pathname !== href) router.replace(href);
+  }, [href, pathname, router]);
 
-  return <Skeleton className="h-8 w-full" />;
+  return (
+    <div role="status" aria-busy="true">
+      <Skeleton className="h-8 w-full" />
+    </div>
+  );
 }
apps/docs/content/docs/cli/guides/adding-components/templates.mdx (1)

1-10: Provide a no‑JS fallback link.

Helpful for crawlers and users with JS disabled.

 # ProofKit Templates
 <Redirect href="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/docs/templates" />
+<noscript>
+  <p>
+    <a href="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/docs/templates">Continue to Templates</a>
+  </p>
+</noscript>
apps/docs/src/app/docs/templates/page.tsx (1)

1-16: Avoid duplicate work: don’t fetch all templates twice.

getTemplatesByCategory already calls getAllTemplates; the Promise.all here doubles the IO. Compute categories from the single list instead.

-import { getAllTemplates, getTemplatesByCategory } from "@/lib/templates";
+import { getAllTemplates } from "@/lib/templates";
@@
-export default async function TemplatesPage() {
-  const [templates, templatesByCategory] = await Promise.all([
-    getAllTemplates(),
-    getTemplatesByCategory(),
-  ]);
+export default async function TemplatesPage() {
+  const templates = await getAllTemplates();
+  const templatesByCategory = groupTemplatesByCategory(templates);

Add this helper in the same file (or export it from your templates lib):

function groupTemplatesByCategory<T extends { category: string; title: string }>(
  templates: T[],
): Record<string, T[]> {
  const grouped = templates.reduce((acc, t) => {
    (acc[t.category] ||= []).push(t);
    return acc;
  }, {} as Record<string, T[]>);
  Object.values(grouped).forEach((arr) => arr.sort((a, b) => a.title.localeCompare(b.title)));
  return grouped;
}
apps/docs/src/lib/is-active.ts (1)

19-23: Optional: guard against unnormalized tab.urls sources.

If upstream SidebarTab.urls isn’t guaranteed normalized, consider checking both normalized and raw pathname to be defensive.

Apply this diff:

 export function isTabActive(tab: SidebarTab, pathname: string) {
-  if (tab.urls) return tab.urls.has(normalize(pathname));
+  if (tab.urls) {
+    const p = normalize(pathname);
+    return tab.urls.has(p) || tab.urls.has(pathname);
+  }
 
   return isActive(tab.url, pathname, true);
 }
apps/docs/src/components/language-toggle.tsx (1)

37-54: UX: close popover after selecting a language.

Keeps the menu open after selection. Close it for a smoother experience.

Apply this diff:

-export function LanguageToggle(props: LanguageSelectProps): React.ReactElement {
+export function LanguageToggle(props: LanguageSelectProps): React.ReactElement {
   const context = useI18n();
   if (!context.locales) throw new Error('Missing `<I18nProvider />`');
 
-  return (
-    <Popover>
+  const [open, setOpen] = React.useState(false);
+  return (
+    <Popover open={open} onOpenChange={setOpen}>
 ...
-        {context.locales.map((item) => (
+        {context.locales.map((item) => (
           <button
             key={item.locale}
             type="button"
 ...
-            onClick={() => {
+            onClick={() => {
               context.onChange?.(item.locale);
+              setOpen(false);
             }}
           >
apps/docs/src/components/ui/button.tsx (1)

11-26: Optional: set defaultVariants for consistency.

Helps avoid missing size/variant when consumers forget to pass them.

Apply this diff:

 export const buttonVariants = cva(
   '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',
   {
     variants: {
       variant: variants,
       // fumadocs use `color` instead of `variant`
       color: variants,
       size: {
         sm: 'gap-1 px-2 py-1.5 text-xs',
         icon: 'p-1.5 [&_svg]:size-5',
-        'icon-sm': 'p-1.5 [&_svg]:size-4.5',
+        'icon-sm': 'p-1.5 [&_svg]:size-[18px]',
         'icon-xs': 'p-1 [&_svg]:size-4',
       },
     },
+    defaultVariants: {
+      size: 'sm',
+      color: 'ghost',
+    },
   },
 );
apps/docs/src/components/root-toggle.tsx (2)

28-31: Avoid findLast for broader browser support.

findLast is ES2023; replace with a backward-compatible loop to prevent unexpected client errors.

Apply this diff:

-  const selected = useMemo(() => {
-    return options.findLast((item) => isTabActive(item, pathname));
-  }, [options, pathname]);
+  const selected = useMemo(() => {
+    for (let i = options.length - 1; i >= 0; i--) {
+      if (isTabActive(options[i], pathname)) return options[i];
+    }
+    return undefined;
+  }, [options, pathname]);

68-70: Return null explicitly from map when skipping items.

Returning undefined is fine, but null is clearer and silences some linters.

Apply this diff:

-          if (!isActive && item.unlisted) return;
+          if (!isActive && item.unlisted) return null;
apps/docs/src/components/ui/toc-clerk.tsx (2)

83-93: Add WebKit mask fallback for Safari compatibility.

CSS mask-image lacks support in some Safari versions without the -webkit- prefixed property.

Apply this diff:

           style={{
             width: svg.width,
             height: svg.height,
-            maskImage: `url("data:image/svg+xml,${
+            maskImage: `url("data:image/svg+xml,${
               // Inline SVG
               encodeURIComponent(
                 `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${svg.width} ${svg.height}"><path d="${svg.path}" stroke="black" stroke-width="1" fill="none" /></svg>`,
               )
             }")`,
+            WebkitMaskImage: `url("data:image/svg+xml,${
+              encodeURIComponent(
+                `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${svg.width} ${svg.height}"><path d="${svg.path}" stroke="black" stroke-width="1" fill="none" /></svg>`,
+              )
+            }")`,
           }}

79-101: Avoid rendering overlay when the SVG path is empty.

If no anchors match yet, svg exists but svg.path may be empty, causing an unnecessary overlay render.

Apply this diff:

-      {svg ? (
+      {svg?.path ? (
         <div
apps/docs/src/components/search-toggle.tsx (2)

21-43: Disable the button when search is unavailable.

Render the control but set it disabled for better accessibility instead of only hiding it via hideIfDisabled.

Apply this diff:

-  if (hideIfDisabled && !enabled) return null;
+  if (hideIfDisabled && !enabled) return null;
@@
     <button
       type="button"
+      disabled={!enabled}
+      aria-disabled={!enabled || undefined}
       className={cn(

51-78: Add disabled state to LargeSearchToggle.

Improve semantics and UX when search isn’t enabled.

Apply this diff:

-  if (hideIfDisabled && !enabled) return null;
+  if (hideIfDisabled && !enabled) return null;
@@
     <button
       type="button"
       data-search-full=""
+      disabled={!enabled}
+      aria-disabled={!enabled || undefined}
       {...props}
apps/docs/src/lib/templates.ts (1)

4-10: Align category type with registry types to avoid drift.

Hard-coding the union risks breakage if categories expand. Reuse the registry’s type.

Apply this diff:

-import { getRegistryIndex } from "@proofkit/registry";
+import { getRegistryIndex } from "@proofkit/registry";
+import type { TemplateMetadata } from "@proofkit/registry";
@@
 export interface TemplateWithPath {
   name: string;
   title: string;
   description?: string;
-  category: "component" | "page" | "utility" | "hook" | "email";
+  category: TemplateMetadata["category"];
   path: string;
 }
apps/docs/src/app/docs/templates/templates-client.tsx (1)

58-66: Small a11y wins: label the search and mark toggle state.

  • Add an accessible label to the search input.
  • Use aria-pressed on category filter buttons to expose state.

Apply this diff:

             <input
               type="text"
               placeholder="Search templates..."
               value={searchQuery}
               onChange={(e) => setSearchQuery(e.target.value)}
+              aria-label="Search templates"
               className="w-full pl-10 pr-4 py-2 border border-border rounded-lg bg-background focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
             />

           <button
             onClick={() => setSelectedCategory(null)}
+            aria-pressed={selectedCategory === null}
             className={`px-3 py-1.5 rounded-full text-sm transition-colors ${
               selectedCategory === null
                 ? "bg-primary text-primary-foreground"
                 : "bg-secondary text-secondary-foreground hover:bg-secondary/80"
             }`}
           >

               <button
                 key={category}
                 onClick={() => setSelectedCategory(category)}
+                aria-pressed={selectedCategory === category}
                 className={`flex items-center gap-1.5 px-3 py-1.5 rounded-full text-sm transition-colors ${
                   selectedCategory === category
                     ? "bg-primary text-primary-foreground"
                     : "bg-secondary text-secondary-foreground hover:bg-secondary/80"
                 }`}
               >

Also applies to: 71-80, 85-96

apps/docs/src/app/docs/templates/[...slug]/page.tsx (1)

58-62: Remove any casts in category config usage.

template.category already matches the union; no any needed.

Apply this diff:

-              const CategoryIcon = getCategoryConfig(
-                template.category as any,
-              ).icon;
+              const CategoryIcon = getCategoryConfig(template.category).icon;
-            {getCategoryConfig(template.category as any).name}
+            {getCategoryConfig(template.category).name}

Also applies to: 75-77

apps/docs/src/components/ui/popover.tsx (1)

10-13: Optional: prefer ElementRef typing for forwardRef.

Use ElementRef/ComponentPropsWithoutRef for Radix refs for clarity and consistency.

Apply this diff:

-const PopoverContent = React.forwardRef<
-  React.ComponentRef<typeof PopoverPrimitive.Content>,
-  React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
+const PopoverContent = React.forwardRef<
+  React.ElementRef<typeof PopoverPrimitive.Content>,
+  React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
 >
apps/docs/src/components/layout/docs/index.tsx (1)

134-143: Use stable keys for mapped lists to reduce unnecessary re‑mounts.

Prefer semantic keys over array indexes for React lists.

Apply these diffs:

-        {links
-          .filter((v) => v.type !== "icon")
-          .map((item, i, list) => (
-            <SidebarLinkItem
-              key={i}
-              item={item}
-              className={cn(i === list.length - 1 && "mb-4")}
-            />
-          ))}
+        {links
+          .filter((v) => v.type !== "icon")
+          .map((item, i, list) => {
+            const key =
+              'url' in item && item.url ? item.url : `${item.type}-${i}`;
+            return (
+              <SidebarLinkItem
+                key={key}
+                item={item}
+                className={cn(i === list.length - 1 && "mb-4")}
+              />
+            );
+          })}
-              {iconLinks.map((item, i) => (
+              {iconLinks.map((item) => (
                 <BaseLinkItem
-                  key={i}
+                  key={item.url}
                   item={item}
                   className={cn(
                     buttonVariants({
                       size: "icon-sm",
                       color: "ghost",
                       className: "p-2",
                     }),
                   )}
                   aria-label={item.label}
                 >
                   {item.icon}
                 </BaseLinkItem>
               ))}
-            {iconLinks.map((item, i) => (
+            {iconLinks.map((item) => (
               <BaseLinkItem
-                key={i}
+                key={item.url}
                 item={item}
                 className={cn(
                   buttonVariants({ size: "icon-sm", color: "ghost" }),
                 )}
                 aria-label={item.label}
               >
                 {item.icon}
               </BaseLinkItem>
             ))}

Also applies to: 152-167, 240-251

apps/docs/src/components/layout/docs/page-client.tsx (2)

284-287: Only write to listCache when needed.

Small micro‑opt: avoid redundant Map writes when a cached list exists.

-    const cached = listCache.get(root.$id);
-    const list = cached ?? scanNavigationList(root.children);
-    listCache.set(root.$id, list);
+    let list = listCache.get(root.$id);
+    if (!list) {
+      list = scanNavigationList(root.children);
+      listCache.set(root.$id, list);
+    }

169-182: Outside‑click handler timing nit.

Consider listening on 'pointerdown' instead of 'click' for a snappier close on outside interaction, especially when interactive elements inside the popover can re-focus before the window click fires.

apps/docs/src/components/sidebar.tsx (3)

408-423: Expose toggle state via ARIA on SidebarTrigger.

Improve a11y by reflecting the open state.

 export function SidebarTrigger({
   children,
   ...props
 }: ComponentProps<'button'>) {
-  const { setOpen } = useSidebar();
+  const { open, setOpen } = useSidebar();
 
   return (
     <button
       {...props}
-      aria-label="Open Sidebar"
+      aria-label="Toggle Sidebar"
+      aria-expanded={open}
+      aria-pressed={open}
       onClick={() => setOpen((prev) => !prev)}
     >
       {children}
     </button>
   );
 }

425-441: Reflect collapsed state via ARIA on SidebarCollapseTrigger.

Expose toggle semantics to assistive tech.

 export function SidebarCollapseTrigger(props: ComponentProps<'button'>) {
   const { collapsed, setCollapsed } = useSidebar();
 
   return (
     <button
       type="button"
       aria-label="Collapse Sidebar"
+      aria-pressed={collapsed}
       data-collapsed={collapsed}
       {...props}
       onClick={() => {
         setCollapsed((prev) => !prev);
       }}
     >
       {props.children}
     </button>
   );
 }

474-522: Key stability for separators/folders (optional).

Using array indexes as keys can cause unnecessary re‑mounts on reordering. If feasible, derive stable keys (e.g., from item.name + level), keeping the current url key for pages.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b9f5be and 4d9d0e9.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (62)
  • .changeset/quick-ends-drop.md (1 hunks)
  • .changeset/ui-default-shadcn.md (1 hunks)
  • apps/docs/cli.json (1 hunks)
  • apps/docs/content/docs/better-auth/installation.mdx (2 hunks)
  • apps/docs/content/docs/cli/guides/adding-components/index.mdx (1 hunks)
  • apps/docs/content/docs/cli/guides/adding-components/meta.json (1 hunks)
  • apps/docs/content/docs/cli/guides/adding-components/templates.mdx (1 hunks)
  • apps/docs/content/docs/cli/guides/auth/add-on.mdx (1 hunks)
  • apps/docs/content/docs/cli/guides/motivation.mdx (3 hunks)
  • apps/docs/content/docs/cli/index.mdx (1 hunks)
  • apps/docs/content/docs/cli/meta.json (1 hunks)
  • apps/docs/content/docs/cli/registry/index.mdx (1 hunks)
  • apps/docs/content/docs/cli/v2.mdx (1 hunks)
  • apps/docs/content/docs/index.mdx (1 hunks)
  • apps/docs/content/docs/meta.json (1 hunks)
  • apps/docs/content/docs/templates/index.mdx (1 hunks)
  • apps/docs/content/docs/templates/meta.json (1 hunks)
  • apps/docs/next.config.ts (2 hunks)
  • apps/docs/package.json (1 hunks)
  • apps/docs/src/app/(home)/layout.tsx (1 hunks)
  • apps/docs/src/app/docs/(docs)/layout.tsx (1 hunks)
  • apps/docs/src/app/docs/templates/[...slug]/page.tsx (1 hunks)
  • apps/docs/src/app/docs/templates/category-config.ts (1 hunks)
  • apps/docs/src/app/docs/templates/layout.tsx (1 hunks)
  • apps/docs/src/app/docs/templates/page.tsx (1 hunks)
  • apps/docs/src/app/docs/templates/templates-client.tsx (1 hunks)
  • apps/docs/src/app/layout.config.tsx (2 hunks)
  • apps/docs/src/components/CliCommand.tsx (2 hunks)
  • apps/docs/src/components/InitCommand.tsx (1 hunks)
  • apps/docs/src/components/language-toggle.tsx (1 hunks)
  • apps/docs/src/components/layout/docs/client.tsx (1 hunks)
  • apps/docs/src/components/layout/docs/index.tsx (1 hunks)
  • apps/docs/src/components/layout/docs/page-client.tsx (1 hunks)
  • apps/docs/src/components/layout/docs/page.tsx (1 hunks)
  • apps/docs/src/components/layout/page.tsx (1 hunks)
  • apps/docs/src/components/layout/shared/client.tsx (1 hunks)
  • apps/docs/src/components/layout/shared/index.tsx (1 hunks)
  • apps/docs/src/components/redirect.tsx (1 hunks)
  • apps/docs/src/components/root-toggle.tsx (1 hunks)
  • apps/docs/src/components/search-toggle.tsx (1 hunks)
  • apps/docs/src/components/sidebar.tsx (1 hunks)
  • apps/docs/src/components/theme-toggle.tsx (1 hunks)
  • apps/docs/src/components/ui/button.tsx (1 hunks)
  • apps/docs/src/components/ui/collapsible.tsx (1 hunks)
  • apps/docs/src/components/ui/popover.tsx (1 hunks)
  • apps/docs/src/components/ui/scroll-area.tsx (1 hunks)
  • apps/docs/src/components/ui/skeleton.tsx (1 hunks)
  • apps/docs/src/components/ui/toc-clerk.tsx (1 hunks)
  • apps/docs/src/components/ui/toc-thumb.tsx (1 hunks)
  • apps/docs/src/components/ui/toc.tsx (1 hunks)
  • apps/docs/src/lib/constants.ts (1 hunks)
  • apps/docs/src/lib/is-active.ts (1 hunks)
  • apps/docs/src/lib/merge-refs.ts (1 hunks)
  • apps/docs/src/lib/templates.ts (1 hunks)
  • packages/cli/package.json (1 hunks)
  • packages/cli/template/nextjs-shadcn/package.json (1 hunks)
  • packages/fmdapi/tests/client-methods.test.ts (4 hunks)
  • packages/fmdapi/tests/tsconfig.json (1 hunks)
  • packages/typegen/src/buildSchema.ts (2 hunks)
  • packages/typegen/tests/__snapshots__/strict-numbers.snap.ts (1 hunks)
  • packages/typegen/tests/__snapshots__/zod-layout-client.snap.ts (1 hunks)
  • packages/typegen/tests/__snapshots__/zod-layout-overrides.snap.ts (1 hunks)
👮 Files not reviewed due to content moderation or server errors (4)
  • .changeset/quick-ends-drop.md
  • packages/typegen/tests/snapshots/zod-layout-overrides.snap.ts
  • packages/typegen/tests/snapshots/zod-layout-client.snap.ts
  • packages/typegen/tests/snapshots/strict-numbers.snap.ts
🧰 Additional context used
🧬 Code graph analysis (23)
apps/docs/src/components/InitCommand.tsx (1)
apps/docs/src/lib/constants.ts (1)
  • cliVersion (2-2)
apps/docs/src/app/docs/templates/templates-client.tsx (2)
apps/docs/src/lib/templates.ts (1)
  • TemplateWithPath (4-10)
apps/docs/src/app/docs/templates/category-config.ts (2)
  • categoryConfigs (13-39)
  • getCategoryConfig (51-53)
apps/docs/src/components/layout/shared/index.tsx (1)
apps/docs/src/components/layout/docs/index.tsx (1)
  • LinkItemType (368-368)
apps/docs/src/app/docs/templates/page.tsx (2)
apps/docs/src/lib/templates.ts (2)
  • getAllTemplates (28-41)
  • getTemplatesByCategory (46-69)
apps/docs/src/app/docs/templates/templates-client.tsx (1)
  • TemplatesPageClient (14-194)
apps/docs/src/components/layout/page.tsx (3)
apps/docs/src/components/layout/docs/page-client.tsx (9)
  • BreadcrumbProps (340-340)
  • FooterProps (244-252)
  • PageTOCPopover (163-219)
  • PageTOCPopoverTrigger (39-91)
  • PageTOCPopoverContent (151-161)
  • PageBreadcrumb (342-392)
  • PageLastUpdate (221-241)
  • PageFooter (277-310)
  • PageTOC (394-417)
apps/docs/src/components/layout/docs/page.tsx (14)
  • BreadcrumbProps (102-102)
  • FooterProps (101-101)
  • PageRoot (75-91)
  • PageTOCPopover (98-98)
  • PageTOCPopoverTrigger (99-99)
  • PageTOCPopoverContent (100-100)
  • PageTOCPopoverItems (46-55)
  • PageArticle (57-69)
  • PageBreadcrumb (94-94)
  • PageLastUpdate (96-96)
  • PageFooter (95-95)
  • PageTOC (97-97)
  • PageTOCTitle (20-33)
  • PageTOCItems (35-44)
apps/docs/src/components/ui/button.tsx (1)
  • buttonVariants (11-26)
apps/docs/src/components/layout/shared/client.tsx (2)
apps/docs/src/components/layout/shared/index.tsx (1)
  • BaseLinkType (72-81)
apps/docs/src/lib/is-active.ts (1)
  • isActive (8-17)
apps/docs/src/components/layout/docs/index.tsx (9)
apps/docs/src/components/layout/shared/index.tsx (5)
  • BaseLayoutProps (20-61)
  • getLinks (156-180)
  • IconItemType (90-102)
  • BaseLinkItem (182-182)
  • LinkItemType (146-151)
apps/docs/src/components/sidebar.tsx (15)
  • SidebarProps (37-62)
  • SidebarComponents (457-461)
  • SidebarViewport (237-254)
  • SidebarPageTree (466-523)
  • SidebarContentMobile (178-213)
  • SidebarHeader (215-224)
  • SidebarFooter (226-235)
  • SidebarContent (111-176)
  • SidebarCollapseTrigger (425-441)
  • Sidebar (89-109)
  • SidebarFolder (294-315)
  • SidebarFolderLink (337-370)
  • SidebarFolderTrigger (317-335)
  • SidebarFolderContent (372-406)
  • SidebarItem (270-292)
apps/docs/src/components/root-toggle.tsx (2)
  • Option (12-14)
  • RootToggle (16-103)
apps/docs/src/components/layout/shared/client.tsx (1)
  • BaseLinkItem (8-30)
apps/docs/src/components/ui/button.tsx (1)
  • buttonVariants (11-26)
apps/docs/src/components/language-toggle.tsx (2)
  • LanguageToggle (14-57)
  • LanguageToggleText (59-68)
apps/docs/src/components/theme-toggle.tsx (1)
  • ThemeToggle (26-87)
apps/docs/src/components/search-toggle.tsx (2)
  • LargeSearchToggle (45-79)
  • SearchToggle (15-43)
apps/docs/src/components/layout/docs/client.tsx (3)
  • CollapsibleControl (54-81)
  • Navbar (12-28)
  • LayoutBody (30-52)
apps/docs/src/app/(home)/layout.tsx (1)
apps/docs/src/app/layout.config.tsx (1)
  • baseOptions (10-41)
apps/docs/src/components/ui/toc-clerk.tsx (3)
apps/docs/src/components/ui/toc.tsx (1)
  • useTOCItems (12-14)
apps/docs/src/components/ui/toc-thumb.tsx (1)
  • TocThumb (38-73)
apps/docs/src/lib/merge-refs.ts (1)
  • mergeRefs (3-15)
apps/docs/src/components/layout/docs/client.tsx (3)
apps/docs/src/components/sidebar.tsx (1)
  • SidebarCollapseTrigger (425-441)
apps/docs/src/components/ui/button.tsx (1)
  • buttonVariants (11-26)
apps/docs/src/components/search-toggle.tsx (1)
  • SearchToggle (15-43)
apps/docs/src/components/sidebar.tsx (1)
apps/docs/src/lib/is-active.ts (1)
  • isActive (8-17)
apps/docs/src/components/layout/docs/page.tsx (2)
apps/docs/src/components/ui/toc.tsx (3)
  • TOCScrollArea (30-51)
  • TOCItems (53-85)
  • TOCProvider (16-28)
apps/docs/src/components/ui/toc-clerk.tsx (1)
  • ClerkTOCItems (11-117)
apps/docs/src/app/docs/templates/[...slug]/page.tsx (3)
apps/docs/src/lib/templates.ts (2)
  • getAllTemplates (28-41)
  • getTemplateByName (74-79)
apps/docs/src/app/docs/templates/category-config.ts (1)
  • getCategoryConfig (51-53)
apps/docs/src/components/CliCommand.tsx (1)
  • CliCommand (33-59)
apps/docs/src/components/search-toggle.tsx (1)
apps/docs/src/components/ui/button.tsx (2)
  • ButtonProps (28-28)
  • buttonVariants (11-26)
apps/docs/src/lib/templates.ts (1)
packages/registry/lib/utils.ts (1)
  • getRegistryIndex (72-87)
apps/docs/src/app/docs/templates/category-config.ts (1)
packages/registry/lib/types.ts (1)
  • TemplateMetadata (179-179)
apps/docs/src/components/root-toggle.tsx (1)
apps/docs/src/lib/is-active.ts (2)
  • isTabActive (19-23)
  • isActive (8-17)
apps/docs/src/app/layout.config.tsx (1)
apps/docs/src/components/layout/shared/index.tsx (1)
  • BaseLayoutProps (20-61)
apps/docs/src/components/language-toggle.tsx (1)
apps/docs/src/components/ui/button.tsx (1)
  • buttonVariants (11-26)
apps/docs/src/components/CliCommand.tsx (1)
apps/docs/src/lib/constants.ts (1)
  • cliVersion (2-2)
apps/docs/src/app/docs/templates/layout.tsx (4)
packages/registry/lib/types.ts (1)
  • TemplateMetadata (179-179)
apps/docs/src/lib/templates.ts (1)
  • getTemplatesByCategory (46-69)
apps/docs/src/app/docs/templates/category-config.ts (1)
  • categoryConfigs (13-39)
apps/docs/src/lib/source.ts (1)
  • source (9-49)
apps/docs/src/components/ui/toc.tsx (2)
apps/docs/src/lib/merge-refs.ts (1)
  • mergeRefs (3-15)
apps/docs/src/components/ui/toc-thumb.tsx (1)
  • TocThumb (38-73)
apps/docs/src/components/layout/docs/page-client.tsx (3)
apps/docs/src/components/ui/toc.tsx (1)
  • useTOCItems (12-14)
apps/docs/src/components/ui/collapsible.tsx (3)
  • CollapsibleTrigger (39-39)
  • CollapsibleContent (39-39)
  • Collapsible (39-39)
apps/docs/src/lib/is-active.ts (1)
  • isActive (8-17)
🪛 Biome (2.1.2)
apps/docs/src/app/docs/templates/layout.tsx

[error] 90-91: Avoid using target="_blank" without rel="noopener" or rel="noreferrer".

Opening external links in new tabs without rel="noopener" is a security risk. See the explanation for more details.
Safe fix: Add the rel="noopener" attribute.

(lint/security/noBlankTarget)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (34)
packages/typegen/src/buildSchema.ts (2)

35-39: Type-only import is the right fix

Marking InferZodPortals as type-only avoids pulling the runtime module into generated bundles and lines up with how the alias is used later. No further action needed.


350-354: Consistent type-only import here as well

Same as above—keeping this import type-only matches its usage and prevents unnecessary runtime dependencies. Looks good.

packages/fmdapi/tests/tsconfig.json (1)

6-8: Explicit rootDir avoids TS6059 when importing package sources

Pointing the tests’ config at the package root keeps TypeScript from flagging cross-folder imports and aligns with the parent config. Good addition.

.changeset/ui-default-shadcn.md (1)

5-9: Confirm docs URL and flag/setting availability.

  • Verify the docs domain (proofkit.com vs proofkit.dev) is correct and consistent across the repo.
  • Ensure init --ui mantine is actually implemented and that proofkit.json persists ui as documented.
apps/docs/cli.json (1)

2-10: Confirm alias paths resolve as intended with baseDir.

With baseDir set to "src", ensure the CLI combines these correctly (e.g., src/components vs ./components). If the CLI expects paths relative to baseDir, consider prefixing with "src/..." for clarity.

apps/docs/content/docs/meta.json (1)

2-3: LGTM: added Templates section to global docs nav.

No issues spotted.

apps/docs/src/lib/constants.ts (1)

1-2: Pin docs CLI version or clarify tracking the beta tag

  • Update to an explicit version and widen the type:
- // which version of the CLI to use in the docs
- export const cliVersion: "latest" | "beta" = "beta";
+ // Which version of the CLI to use in docs commands.
+ // Allow explicit versions in addition to dist-tags to avoid drift.
+ export type CliVersion = "latest" | "beta" | `${number}.${number}.${number}${string}`;
+ export const cliVersion: CliVersion = "2.0.0-beta.3";
  • Or keep "beta" and update the comment/tests to note that it tracks a moving dist-tag.

Confirm which approach you’d like.

apps/docs/src/lib/is-active.ts (1)

8-17: LGTM: robust active-path check with safe trailing-slash handling.

Equality plus prefix match with normalized paths is correct and avoids false positives like /docs vs /docsify.

apps/docs/src/components/ui/button.tsx (1)

19-23: Verify Tailwind class “size-4.5” exists.

Tailwind doesn’t ship size-4.5 by default; if you’re not extending theme or using arbitrary values, this won’t compile.

Consider switching to arbitrary values for consistency:

-        'icon-sm': 'p-1.5 [&_svg]:size-4.5',
+        'icon-sm': 'p-1.5 [&_svg]:size-[18px]',

If you’ve extended the theme to include 4.5, disregard. Please confirm.

apps/docs/src/components/ui/collapsible.tsx (1)

20-33: LGTM: SSR-safe mount gating for animation classes.

Delaying animation classes until after mount avoids hydration mismatches; re-exporting Radix parts keeps API familiar.

apps/docs/src/components/layout/docs/client.tsx (3)

12-28: Navbar structure LGTM.


30-52: Layout body spacing logic LGTM.


54-81: Collapsible control implementation LGTM.

apps/docs/src/components/layout/docs/page.tsx (3)

20-33: TOC title and i18n wiring LGTM.


35-44: TOC items composition LGTM (relies on TOC forwardRef fix).

After applying the TOC forwardRef fix, verify the TOC renders and the thumb updates on scroll.

Also applies to: 46-55


75-91: Conditional TOC provider in PageRoot LGTM.

apps/docs/src/components/CliCommand.tsx (1)

6-13: No action needed for npm prefix. All <CliCommand> invocations set exec, so prefix: "npm run" is never applied.

apps/docs/src/components/layout/docs/index.tsx (2)

169-174: Guard LanguageToggle against missing I18nProvider.

LanguageToggle throws if I18nProvider/locales are absent. Ensure the layout is wrapped in the provider whenever i18n is truthy, or gate rendering on provider presence.

Do you confirm the I18nProvider is always mounted in contexts where i18n is enabled?

Also applies to: 235-239


277-323: Well-structured layout composition.

Good separation of concerns (NavProvider, TreeContextProvider, sidebar assembly), sensible defaults, and safe conditional rendering.

apps/docs/src/components/layout/docs/page-client.tsx (1)

39-91: TOC trigger behavior looks solid.

Active section detection, progress indicator, and CollapsibleTrigger wiring are coherent.

apps/docs/src/components/sidebar.tsx (1)

111-176: Desktop sidebar hover/collapse behavior LGTM.

Good handling of hover timers, touch pointers, and CSS variables for smooth transitions.

packages/cli/package.json (1)

3-3: Align CLI version with docs

The bump to 2.0.0-beta.3 matches the documentation and init-command updates in this stack, keeping releases consistent.

apps/docs/src/app/(home)/layout.tsx (1)

6-15: Docs link restored in home navigation

Prepending the CLI docs link here cleanly restores that entry after slimming down baseOptions.links, without touching other layouts.

packages/cli/template/nextjs-shadcn/package.json (1)

18-34: Template dependencies updated coherently

Next/React patch bumps plus the tooling updates keep the generated project aligned with the CLI’s latest baseline.

apps/docs/package.json (1)

16-42: Docs dependencies track the new UI stack

Adding the Radix primitives, next-themes, and refreshed fumadocs versions lines up with the new layout and template browsing features.

apps/docs/content/docs/cli/guides/adding-components/meta.json (1)

1-6: Navigation metadata looks good

Title, icon, and default expansion all line up with the new guide, so it should slot straight into the sidebar.

apps/docs/src/components/ui/skeleton.tsx (1)

1-8: New skeleton utility looks solid

Lightweight component, reusable slot attribute, and shared cn helper keep loading placeholders consistent.

apps/docs/src/app/layout.config.tsx (1)

10-41: satisfies keeps typing without extra noise

Good call switching to satisfies; we retain compile-time coverage and stay flexible on the constant shape while trimming the docs link from the shared config.

apps/docs/content/docs/templates/meta.json (1)

4-4: Confirm icon casing

Other meta entries (e.g., the new “Adding Components” guide) use lowercase "puzzle". Please double-check whether the icon registry expects lowercase—if so, "Puzzle" may render a fallback.

Could you verify the expected casing for this icon in the docs UI before merging?

apps/docs/content/docs/cli/registry/index.mdx (1)

1-12: Registry overview addition looks solid

Content is concise and matches the new templates flow.

apps/docs/content/docs/index.mdx (1)

34-36: Nice to see Better Auth listed

Great to surface the new library alongside the existing core packages.

apps/docs/content/docs/templates/index.mdx (1)

1-3: Front matter stub lands cleanly

Looks ready for the templates client to slot content in.

apps/docs/src/app/docs/(docs)/layout.tsx (1)

1-31: Import swap to local DocsLayout looks good

Moving to the in-repo layout keeps everything consistent with the new components.

apps/docs/src/components/InitCommand.tsx (1)

6-8: Dist-tag “beta” exists for create-proofkitcreate-proofkit@beta resolves to v0.1.0-beta.1, so the docs commands are correct.

Comment on lines +40 to +51
#### [Shadcn/ui](https://ui.shadcn.com/) <Badge className="bg-blue-200 text-blue-700 dark:bg-blue-500 dark:text-blue-50 ">NEW</Badge>

A vast, themeable component library for React. We use their default components and styles to build apps very quickly, but with the option of adding custom styles or themes later if needed. Mantine also includes many helpful React hooks, and they provide a Modal and Notification system to ProofKit apps.
A themeable component library for React. We use their default components and styles to build apps very quickly, but with the option of adding custom styles or themes later if needed. Shadcn/ui also includes many helpful React hooks, and they provide a Modal and Notification system to ProofKit apps.

Why not tailwind css and/or shadcn/ui? We've chosen to focus on Mantine because it has allowed our team to work much faster for the kinds of web apps that we build for our clients. When you're working on multiple projects at once, it's actually a benefit to **not** own the component code within an individual codebase, so that it can be more easily upgraded when the time comes. However, we have not ruled out other components and style systems and may add support for them in the future.
Using the shadcn CLI, you can install any component or utility from any compatible library. This makes shadcn the best choice for the most flexible and customizable apps. Some of our favorite shadcn-compatible libraries are:
- [Kibu Ui](https://www.kibo-ui.com/)
- [reui](https://reui.io/)
- [Magic UI](https://magicui.design/)
- [tweakcn (easily theme your components)](https://tweakcn.com/)
- [A longer list of more...](https://github.com/birobirobiro/awesome-shadcn-ui)

#### [Tailwind CSS](https://tailwindcss.com/) <Badge className="bg-blue-200 text-blue-700 dark:bg-blue-500 dark:text-blue-50 ">NEW</Badge>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typos/brand casing and a factual correction for TanStack Query.

  • Use “shadcn/ui” casing; fix “Kibu Ui” → “Kibo UI”; “neccesary” → “necessary”.
  • TanStack Query manages server state/caching; it doesn’t ensure data “shape” — that’s Zod.

Apply this diff:

-#### [Shadcn/ui](https://ui.shadcn.com/) <Badge className="bg-blue-200 text-blue-700 dark:bg-blue-500 dark:text-blue-50 ">NEW</Badge>
+#### [shadcn/ui](https://ui.shadcn.com/) <Badge className="bg-blue-200 text-blue-700 dark:bg-blue-500 dark:text-blue-50 ">NEW</Badge>-Some of our favorite shadcn-compatible libraries are:
-- [Kibu Ui](https://www.kibo-ui.com/)
+Some of our favorite shadcn-compatible libraries are:
+- [Kibo UI](https://www.kibo-ui.com/)
 - [reui](https://reui.io/)
 - [Magic UI](https://magicui.design/)
 - [tweakcn (easily theme your components)](https://tweakcn.com/)
 - [A longer list of more...](https://github.com/birobirobiro/awesome-shadcn-ui)
…
-#### [Tanstack Query](https://tanstack.com/query)
+#### [TanStack Query](https://tanstack.com/query)-Sometimes also known as "React Query"; a library for managing server state in React. It's used by ProofKit to fetch data from external sources, such as REST APIs, so we can be certain that the "shape" of our data matches what we expected during development.
+Sometimes also known as "React Query"; a library for managing server state in React. It's used by ProofKit for fetching, caching, deduping, background updates, and invalidation of server data.-For when you need a bit more flexibility or if you want to self-host the authentication layer within your existing FileMaker solution. Better-auth is a great choice for this, and the [proofkit/better-auth](/docs/better-auth) adapter allows you to use FileMaker as your backend database, including automated schema migrations to easily add any neccesary tables and fields to your FileMaker file.
+For when you need a bit more flexibility or if you want to self-host the authentication layer within your existing FileMaker solution. Better-auth is a great choice for this, and the [proofkit/better-auth](/docs/better-auth) adapter allows you to use FileMaker as your backend database, including automated schema migrations to easily add any necessary tables and fields to your FileMaker file.

Also applies to: 55-62, 73-76

🤖 Prompt for AI Agents
In apps/docs/content/docs/cli/guides/motivation.mdx around lines 40-51 (and also
apply the same fixes to lines 55-62 and 73-76), fix branding/casing typos and
one factual statement: change “shadcn/ui” to lowercase exactly as "shadcn/ui",
rename “Kibu Ui” to “Kibo UI”, correct “neccesary” to “necessary” wherever
present, and update the TanStack Query sentence to state that TanStack Query
manages server state/caching (not data shape) and attribute validation/ensuring
data shape to Zod (reword the sentence to reflect that distinction).

Comment on lines +1 to +9
'use client';
import type { TOCItemType } from 'fumadocs-core/server';
import * as Primitive from 'fumadocs-core/toc';
import { type ComponentProps, createContext, useContext, useRef } from 'react';
import { cn } from '../../lib/cn';
import { useI18n } from 'fumadocs-ui/contexts/i18n';
import { TocThumb } from './toc-thumb';
import { mergeRefs } from '../../lib/merge-refs';

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Forward refs correctly; ref isn’t a normal prop.

Destructuring ref from props on function components drops refs and can cause runtime warnings. Convert to forwardRef and merge properly.

Apply this diff:

-'use client';
-import type { TOCItemType } from 'fumadocs-core/server';
-import * as Primitive from 'fumadocs-core/toc';
-import { type ComponentProps, createContext, useContext, useRef } from 'react';
-import { cn } from '../../lib/cn';
-import { useI18n } from 'fumadocs-ui/contexts/i18n';
-import { TocThumb } from './toc-thumb';
-import { mergeRefs } from '../../lib/merge-refs';
+'use client';
+import type { TOCItemType } from 'fumadocs-core/server';
+import * as Primitive from 'fumadocs-core/toc';
+import { type ComponentProps, createContext, useContext, useRef, forwardRef } from 'react';
+import { cn } from '../../lib/cn';
+import { useI18n } from 'fumadocs-ui/contexts/i18n';
+import { TocThumb } from './toc-thumb';
+import { mergeRefs } from '../../lib/merge-refs';
-export function TOCScrollArea({
-  ref,
-  className,
-  ...props
-}: ComponentProps<'div'>) {
-  const viewRef = useRef<HTMLDivElement>(null);
-
-  return (
-    <div
-      ref={mergeRefs(viewRef, ref)}
-      className={cn(
-        'relative min-h-0 text-sm ms-px overflow-auto [scrollbar-width:none] [mask-image:linear-gradient(to_bottom,transparent,white_16px,white_calc(100%-16px),transparent)] py-3',
-        className,
-      )}
-      {...props}
-    >
-      <Primitive.ScrollProvider containerRef={viewRef}>
-        {props.children}
-      </Primitive.ScrollProvider>
-    </div>
-  );
-}
+export const TOCScrollArea = forwardRef<HTMLDivElement, ComponentProps<'div'>>(
+  ({ className, ...props }, ref) => {
+    const viewRef = useRef<HTMLDivElement>(null);
+    return (
+      <div
+        ref={mergeRefs(viewRef, ref)}
+        className={cn(
+          'relative min-h-0 text-sm ms-px overflow-auto [scrollbar-width:none] [mask-image:linear-gradient(to_bottom,transparent,white_16px,white_calc(100%-16px),transparent)] py-3',
+          className,
+        )}
+        {...props}
+      >
+        <Primitive.ScrollProvider containerRef={viewRef}>
+          {props.children}
+        </Primitive.ScrollProvider>
+      </div>
+    );
+  },
+);
-export function TOCItems({ ref, className, ...props }: ComponentProps<'div'>) {
-  const containerRef = useRef<HTMLDivElement>(null);
-  const items = useTOCItems();
-  const { text } = useI18n();
+export const TOCItems = forwardRef<HTMLDivElement, ComponentProps<'div'>>(
+  ({ className, ...props }, ref) => {
+    const containerRef = useRef<HTMLDivElement>(null);
+    const items = useTOCItems();
+    const { text } = useI18n();
 
-  if (items.length === 0)
-    return (
-      <div className="rounded-lg border bg-fd-card p-3 text-xs text-fd-muted-foreground">
-        {text.tocNoHeadings}
-      </div>
-    );
+    if (items.length === 0)
+      return (
+        <div className="rounded-lg border bg-fd-card p-3 text-xs text-fd-muted-foreground">
+          {text.tocNoHeadings}
+        </div>
+      );
 
-  return (
-    <>
-      <TocThumb
-        containerRef={containerRef}
-        className="absolute top-(--fd-top) h-(--fd-height) w-px bg-fd-primary transition-all"
-      />
-      <div
-        ref={mergeRefs(ref, containerRef)}
-        className={cn(
-          'flex flex-col border-s border-fd-foreground/10',
-          className,
-        )}
-        {...props}
-      >
-        {items.map((item) => (
-          <TOCItem key={item.url} item={item} />
-        ))}
-      </div>
-    </>
-  );
-}
+    return (
+      <>
+        <TocThumb
+          containerRef={containerRef}
+          className="absolute top-(--fd-top) h-(--fd-height) w-px bg-fd-primary transition-all"
+        />
+        <div
+          ref={mergeRefs(ref, containerRef)}
+          className={cn(
+            'flex flex-col border-s border-fd-foreground/10',
+            className,
+          )}
+          {...props}
+        >
+          {items.map((item) => (
+            <TOCItem key={item.url} item={item} />
+          ))}
+        </div>
+      </>
+    );
+  },
+);

Also applies to: 30-51, 53-85


🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Follow-up: replicate the forwardRef fix in Clerk TOC.

ClerkTOCItems appears to destructure ref similarly. Please update it to use forwardRef too.

Run this to locate occurrences:


🏁 Script executed:

#!/bin/bash
rg -nP --type=tsx -C2 'function\s+\w+\s*\(\s*\{\s*ref\s*,' apps/docs/src/components | sed -n '1,200p'

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Locate the ClerkTOCItems component and its signature
rg -n 'ClerkTOCItems' -C3 -g '*.tsx'

Length of output: 2249


🏁 Script executed:

#!/bin/bash
# Show ClerkTOCItems implementation
sed -n '1,40p' apps/docs/src/components/ui/toc-clerk.tsx

# Find forwardRef usage in TOCItems
rg -n 'forwardRef' -C3 -g '*.tsx' apps/docs/src/components/ui/toc.tsx

Length of output: 1178


Wrap TOCItems and ClerkTOCItems in React.forwardRef
Destructuring ref in the props won’t attach it to the DOM—wrap both components in React.forwardRef and merge the forwarded ref with your internal useRef via mergeRefs.
Files:
• apps/docs/src/components/ui/toc.tsx
• apps/docs/src/components/ui/toc-clerk.tsx

🤖 Prompt for AI Agents
In apps/docs/src/components/ui/toc.tsx (lines 1-9) and
apps/docs/src/components/ui/toc-clerk.tsx, the TOCItem and ClerkTOCItem
components must be wrapped with React.forwardRef so the incoming ref is attached
to the DOM; change the components to accept (props, ref) in forwardRef, type the
ref appropriately, keep your internal useRef but merge it with the forwarded ref
using mergeRefs, and pass the merged ref to the root DOM element (e.g., the
container or list element); ensure props typing accommodates the forwarded ref
(use ComponentProps or appropriate HTML element ref type) and export the
forwardRef-wrapped component.

Comment on lines +21 to +27
return (
<TOCContext value={toc}>
<Primitive.AnchorProvider toc={toc} {...props}>
{children}
</Primitive.AnchorProvider>
</TOCContext>
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix context provider usage.

Use TOCContext.Provider; current code won’t provide context.

Apply this diff:

-    <TOCContext value={toc}>
+    <TOCContext.Provider value={toc}>
       <Primitive.AnchorProvider toc={toc} {...props}>
         {children}
       </Primitive.AnchorProvider>
-    </TOCContext>
+    </TOCContext.Provider>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (
<TOCContext value={toc}>
<Primitive.AnchorProvider toc={toc} {...props}>
{children}
</Primitive.AnchorProvider>
</TOCContext>
);
return (
<TOCContext.Provider value={toc}>
<Primitive.AnchorProvider toc={toc} {...props}>
{children}
</Primitive.AnchorProvider>
</TOCContext.Provider>
);
🤖 Prompt for AI Agents
In apps/docs/src/components/ui/toc.tsx around lines 21 to 27, the context
wrapper incorrectly uses TOCContext instead of TOCContext.Provider so the
context value is not actually provided; change the wrapper to use
TOCContext.Provider with the value={toc} prop (i.e., replace <TOCContext
value={toc}>…</TOCContext> with <TOCContext.Provider
value={toc}>…</TOCContext.Provider>) ensuring the children remain wrapped and
imports remain unchanged.

Comment on lines +7 to +12
refs.forEach((ref) => {
if (typeof ref === 'function') {
ref(value);
} else if (ref) {
ref.current = value;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix TypeScript readonly assignment on object refs

Assigning directly to ref.current fails type-checking because React.Ref<T> unions RefObject<T> (whose current is readonly) with MutableRefObject<T>. Under strict React typings this emits “Cannot assign to 'current' because it is a read-only property.” Wrap the assignment in a cast/narrowing to MutableRefObject<T | null> so the helper compiles.

-      } else if (ref) {
-        ref.current = value;
+      } else if (ref) {
+        (ref as React.MutableRefObject<T | null>).current = value;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
refs.forEach((ref) => {
if (typeof ref === 'function') {
ref(value);
} else if (ref) {
ref.current = value;
}
refs.forEach((ref) => {
if (typeof ref === 'function') {
ref(value);
} else if (ref) {
(ref as React.MutableRefObject<T | null>).current = value;
}
🤖 Prompt for AI Agents
In apps/docs/src/lib/merge-refs.ts around lines 7 to 12, assigning directly to
ref.current fails under strict React typings because React.Ref<T> can be a
readonly RefObject; cast or narrow the ref to MutableRefObject<T | null> before
assignment (e.g. const mutable = ref as MutableRefObject<typeof value | null>;
mutable.current = value) so the compiler accepts the write, keeping the function
branch for function refs unchanged.

Comment on lines +15 to +23
function getTemplatesPath(): string {
if (process.env.NODE_ENV === "production") {
// In production, templates are bundled in the public directory
return path.join(process.cwd(), "public/registry-templates");
} else {
// In development, read directly from registry package
return path.resolve(process.cwd(), "../../packages/registry/templates");
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify templates path resolution across environments.

The dev path assumes a specific monorepo layout; production assumes a public copy. Ensure both exist in CI/build and at runtime, or fall back to getRegistryIndex() default path when missing.

Run this script to check for expected paths and sample contents:

If either path is absent, consider falling back to getRegistryIndex() with no override.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "NODE_ENV=${NODE_ENV:-unset}"
echo "CWD=$(pwd)"
echo "--- Checking for production path (apps/docs/public/registry-templates) ---"
fd -t d -a 'registry-templates' 2>/dev/null || true
fd -t f -a 'meta.json' public/registry-templates 2>/dev/null || true

echo "--- Checking for registry templates in monorepo dev path ---"
fd -t d -a 'templates' 2>/dev/null | rg -n "/packages/registry/templates$" -n || true
fd -t f -a 'meta.json' packages/registry/templates 2>/dev/null || true

Length of output: 173


Ensure both production and development template paths exist or add a fallback
getTemplatesPath in apps/docs/src/lib/templates.ts references apps/docs/public/registry-templates and ../../packages/registry/templates, but neither directory (nor its meta.json) was found—add these assets or call getRegistryIndex() when the paths are missing.

🤖 Prompt for AI Agents
In apps/docs/src/lib/templates.ts around lines 15 to 23, getTemplatesPath()
returns hard-coded production and development directories but doesn’t verify
they exist or handle missing meta.json; update the function to check for the
presence of the resolved path and its meta.json and, if missing, either throw a
clear error or call getRegistryIndex() as a fallback to obtain templates
programmatically, ensuring any returned path is validated before use and logging
or propagating an explanatory error when neither disk path nor fallback is
available.

Comment on lines 113 to 117
const portalData =
data[0].portalData["long_and_strange.portalName#forTesting"];
data[0]?.portalData["long_and_strange.portalName#forTesting"];

expect(portalData.length).toBeGreaterThan(50);
expect(portalData?.length).toBeGreaterThan(50);
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Extend optional chaining through the bracket access

data[0]?.portalData["long_and_strange.portalName#forTesting"] still blows up when portalData is undefined because the optional chain stops before the bracket lookup. In the exact scenario this change is trying to guard against, the test will still throw a TypeError instead of failing the assertion. Please propagate the optional chaining to the bracket accessor.

-    const portalData =
-      data[0]?.portalData["long_and_strange.portalName#forTesting"];
+    const portalData =
+      data[0]?.portalData?.["long_and_strange.portalName#forTesting"];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const portalData =
data[0].portalData["long_and_strange.portalName#forTesting"];
data[0]?.portalData["long_and_strange.portalName#forTesting"];
expect(portalData.length).toBeGreaterThan(50);
expect(portalData?.length).toBeGreaterThan(50);
});
const portalData =
data[0]?.portalData?.["long_and_strange.portalName#forTesting"];
expect(portalData?.length).toBeGreaterThan(50);
});
🤖 Prompt for AI Agents
In packages/fmdapi/tests/client-methods.test.ts around lines 113 to 117, the
optional chaining stops before the bracket lookup so accessing portalData via
data[0]?.portalData["long_and_strange.portalName#forTesting"] will throw if
portalData is undefined; change the access to propagate optional chaining to the
bracket accessor (e.g.,
data[0]?.portalData?.["long_and_strange.portalName#forTesting"]) so portalData
can be undefined safely and the subsequent length check uses optional chaining
as currently written.

@proofgeist proofgeist deleted a comment from coderabbitai bot Sep 26, 2025
…ss various files. Update CLI command references and enhance error handling in template category management. Ensure consistent formatting in layout components and improve accessibility attributes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (11)
apps/docs/src/components/layout/docs/page-client.tsx (6)

93-101: Use ComponentProps to avoid React namespace dependency.

Be consistent with existing imports and avoid relying on ambient React namespace types.

-interface ProgressCircleProps
-  extends Omit<React.ComponentProps<"svg">, "strokeWidth"> {
+interface ProgressCircleProps
+  extends Omit<ComponentProps<"svg">, "strokeWidth"> {

116-121: Harden ProgressCircle math (avoid NaN/Infinity and negative radius).

Handle min/max span and radius safely; also update aria-valuenow variable.

-  const normalizedValue = clamp(value, min, max);
-  const radius = (size - strokeWidth) / 2;
-  const circumference = 2 * Math.PI * radius;
-  const progress = (normalizedValue / max) * circumference;
+  const clamped = clamp(value, min, max);
+  const radius = Math.max(0, (size - strokeWidth) / 2);
+  const circumference = 2 * Math.PI * radius;
+  const span = Math.max(1, max - min); // avoid divide-by-zero
+  const progress = ((clamped - min) / span) * circumference;
-      aria-valuenow={normalizedValue}
+      aria-valuenow={clamped}

Also applies to: 132-132


169-175: Type the click handler as MouseEvent for clarity.

Minor type cleanup to match the event you listen for.

-  const onClick = useEffectEvent((e: Event) => {
+  const onClick = useEffectEvent((e: MouseEvent) => {

176-183: Close the TOC popover on Escape as well.

Improves accessibility and expected behavior.

   useEffect(() => {
     window.addEventListener("click", onClick);
 
     return () => {
       window.removeEventListener("click", onClick);
     };
   }, [onClick]);
+
+  useEffect(() => {
+    const onKeyDown = (e: KeyboardEvent) => {
+      if (e.key === "Escape") setOpen(false);
+    };
+    window.addEventListener("keydown", onKeyDown);
+    return () => window.removeEventListener("keydown", onKeyDown);
+  }, [setOpen]);

293-296: Bound the listCache to prevent unbounded growth.

Small guard to avoid leaking entries across navigations.

     const list = cached ?? scanNavigationList(root.children);
     listCache.set(root.$id, list);
+    if (listCache.size > 20) {
+      const firstKey = listCache.keys().next().value as string | undefined;
+      if (firstKey) listCache.delete(firstKey);
+    }

377-399: Prefer stable keys for breadcrumb items.

Use url/name when available to help React reconcile.

-          <Fragment key={i}>
+          <Fragment key={item.url ?? item.name ?? i}>
apps/docs/src/components/layout/page.tsx (1)

187-187: Avoid double-parsing the date.

Let PageLastUpdate parse once; pass the original value through.

-          {lastUpdate && <PageLastUpdate date={new Date(lastUpdate)} />}
+          {lastUpdate && <PageLastUpdate date={lastUpdate} />}
apps/docs/src/components/layout/shared/index.tsx (1)

156-179: De-dupe and simplify getLinks; avoid redundant nullish coalescing.

Prevent duplicate GitHub entries and simplify logic; the default param already ensures links is an array.

-export function getLinks(
-  links: LinkItemType[] = [],
-  githubUrl?: string,
-): LinkItemType[] {
-  let result = links ?? [];
-
-  if (githubUrl)
-    result = [
-      ...result,
-      {
-        type: "icon",
-        url: githubUrl,
-        text: "GitHub",
-        label: "GitHub",
-        icon: (
-          <svg role="img" viewBox="0 0 24 24" fill="currentColor">
-            <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" />
-          </svg>
-        ),
-        external: true,
-      },
-    ];
-
-  return result;
-}
+export function getLinks(
+  links: LinkItemType[] = [],
+  githubUrl?: string,
+): LinkItemType[] {
+  const items = links;
+  if (!githubUrl) return items;
+
+  // Avoid duplicate GitHub entries (by exact URL match)
+  const hasGitHub = items.some((l) => "url" in l && l.url === githubUrl);
+  if (hasGitHub) return items;
+
+  return [
+    ...items,
+    {
+      type: "icon",
+      url: githubUrl,
+      text: "GitHub",
+      label: "GitHub",
+      icon: (
+        <svg role="img" viewBox="0 0 24 24" fill="currentColor">
+          <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" />
+        </svg>
+      ),
+      external: true,
+    },
+  ];
+}
apps/docs/src/components/root-toggle.tsx (2)

67-68: Use clearer boolean for isActive.

Avoid boolean | undefined from selected && .... Use optional chaining for a strict boolean.

-          const isActive = selected && item.url === selected.url;
+          const isActive = selected?.url === item.url;

68-69: Return null explicitly for skipped items.

Returning null is clearer than undefined in React lists.

-          if (!isActive && item.unlisted) return;
+          if (!isActive && item.unlisted) return null;
apps/docs/content/docs/cli/guides/auth/add-on.mdx (1)

9-11: Unify Callout variant: use "warn" (matches elsewhere in this page).

The rest of this doc uses type="warn". Keep variants consistent to avoid styling drift.

Apply this diff:

-<Callout type="warning" title="Deprecated">
+<Callout type="warn" title="Deprecated">
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d9d0e9 and 7522e61.

📒 Files selected for processing (16)
  • apps/docs/content/docs/better-auth/installation.mdx (2 hunks)
  • apps/docs/content/docs/cli/guides/adding-components/index.mdx (1 hunks)
  • apps/docs/content/docs/cli/guides/auth/add-on.mdx (1 hunks)
  • apps/docs/content/docs/cli/guides/motivation.mdx (3 hunks)
  • apps/docs/content/docs/cli/index.mdx (1 hunks)
  • apps/docs/content/docs/cli/v2.mdx (1 hunks)
  • apps/docs/src/app/docs/templates/category-config.ts (1 hunks)
  • apps/docs/src/app/docs/templates/layout.tsx (1 hunks)
  • apps/docs/src/app/docs/templates/templates-client.tsx (1 hunks)
  • apps/docs/src/components/CliCommand.tsx (2 hunks)
  • apps/docs/src/components/layout/docs/page-client.tsx (1 hunks)
  • apps/docs/src/components/layout/page.tsx (1 hunks)
  • apps/docs/src/components/layout/shared/index.tsx (1 hunks)
  • apps/docs/src/components/root-toggle.tsx (1 hunks)
  • apps/docs/src/components/ui/scroll-area.tsx (1 hunks)
  • apps/docs/src/lib/templates.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/docs/content/docs/cli/v2.mdx
  • apps/docs/content/docs/cli/index.mdx
  • apps/docs/src/app/docs/templates/category-config.ts
  • apps/docs/content/docs/cli/guides/adding-components/index.mdx
  • apps/docs/src/app/docs/templates/templates-client.tsx
  • apps/docs/src/app/docs/templates/layout.tsx
  • apps/docs/src/lib/templates.ts
🧰 Additional context used
🧬 Code graph analysis (5)
apps/docs/src/components/layout/shared/index.tsx (1)
apps/docs/src/components/layout/docs/index.tsx (1)
  • LinkItemType (368-368)
apps/docs/src/components/layout/page.tsx (3)
apps/docs/src/components/layout/docs/page-client.tsx (8)
  • BreadcrumbProps (349-349)
  • FooterProps (253-261)
  • PageTOCPopover (163-219)
  • PageTOCPopoverTrigger (39-91)
  • PageTOCPopoverContent (151-161)
  • PageBreadcrumb (351-401)
  • PageLastUpdate (221-250)
  • PageTOC (403-426)
apps/docs/src/components/layout/docs/page.tsx (12)
  • BreadcrumbProps (102-102)
  • FooterProps (101-101)
  • PageRoot (75-91)
  • PageTOCPopover (98-98)
  • PageTOCPopoverTrigger (99-99)
  • PageTOCPopoverContent (100-100)
  • PageArticle (57-69)
  • PageBreadcrumb (94-94)
  • PageLastUpdate (96-96)
  • PageTOC (97-97)
  • PageTOCTitle (20-33)
  • PageTOCItems (35-44)
apps/docs/src/components/ui/button.tsx (1)
  • buttonVariants (11-26)
apps/docs/src/components/layout/docs/page-client.tsx (3)
apps/docs/src/components/ui/toc.tsx (1)
  • useTOCItems (12-14)
apps/docs/src/components/ui/collapsible.tsx (3)
  • CollapsibleTrigger (39-39)
  • CollapsibleContent (39-39)
  • Collapsible (39-39)
apps/docs/src/lib/is-active.ts (1)
  • isActive (8-17)
apps/docs/src/components/CliCommand.tsx (1)
apps/docs/src/lib/constants.ts (1)
  • cliVersion (2-2)
apps/docs/src/components/root-toggle.tsx (1)
apps/docs/src/lib/is-active.ts (2)
  • isTabActive (19-23)
  • isActive (8-17)
🔇 Additional comments (13)
apps/docs/src/components/ui/scroll-area.tsx (1)

53-54: Incorrect Radix thumb component still in place

We still render ScrollAreaPrimitive.ScrollAreaThumb, which is not a Radix export; the thumb never mounts, so the scrollbar is invisible. Please swap it for ScrollAreaPrimitive.Thumb.

-    <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-fd-border" />
+    <ScrollAreaPrimitive.Thumb className="relative flex-1 rounded-full bg-fd-border" />
apps/docs/src/components/layout/docs/page-client.tsx (1)

242-249: Don’t render the label when the date is invalid/empty.

Avoids showing a dangling “Last update ” with no date. This was raised previously.

-  return (
-    <p
-      {...props}
-      className={cn("text-sm text-fd-muted-foreground", props.className)}
-    >
-      {text.lastUpdate} {date || ""}
-    </p>
-  );
+  if (!date) return null;
+  return (
+    <p
+      {...props}
+      className={cn("text-sm text-fd-muted-foreground", props.className)}
+    >
+      {text.lastUpdate} {date}
+    </p>
+  );
apps/docs/src/components/layout/page.tsx (1)

182-185: Good fix: default GitHub ref to ‘main’.

Prevents “undefined” in blob URLs and matches prior review feedback.

apps/docs/src/components/layout/shared/index.tsx (3)

162-169: Brand casing fixed; keep it consistent site-wide.

"GitHub" is correct; previous "Github" issue is resolved.


146-152: Public union type looks solid.

Clear, extensible LinkItemType union and separation of concerns via BaseLinkType.


52-54: Ensure external links use rel="noopener noreferrer" and target="_blank
BaseLinkItem forwards external to Link; verify that Link from fumadocs-core/link sets target="_blank" and rel="noopener noreferrer" when external=true. If it doesn’t, add these attributes in BaseLinkItem.

apps/docs/src/components/root-toggle.tsx (3)

65-66: Tailwind arbitrary value syntax is now correct.

w-[--radix-popover-trigger-width] fixes the prior issue.


51-63: Good controlled Popover and trigger composition.

Accessible trigger with icon and responsive copy looks good.


28-31: Confirm Array.prototype.findLast support

  • apps/docs/tsconfig.json already targets ESNext and includes "esnext" in lib, so TypeScript provides findLast typings.
  • No explicit browserslist entry found—verify your browsers targets support findLast or include a runtime polyfill.
apps/docs/src/components/CliCommand.tsx (2)

20-24: Good fix: yarn execPrefix -> ‘yarn dlx’.

This corrects prior guidance.


33-41: Clarify pinned CLI version
cliVersion is currently typed "latest" | "beta" and defaults to "beta". If you intend to pin @proofkit/[email protected], update the cliVersion constant in apps/docs/src/lib/constants.ts (type and default) or pass execPackage explicitly where needed.

apps/docs/content/docs/cli/guides/motivation.mdx (1)

40-49: Fix brand casing/names and clarify TanStack Query role.

  • Use “shadcn/ui” (lowercase).
  • “Kibu Ui” → “Kibo UI”.
  • “Tanstack” → “TanStack”.
  • TanStack Query manages server state (fetching/caching/etc.); Zod handles shape/validation.

Apply this diff:

-#### [Shadcn/ui](https://ui.shadcn.com/) <Badge className="bg-blue-200 text-blue-700 dark:bg-blue-500 dark:text-blue-50 ">NEW</Badge>
+#### [shadcn/ui](https://ui.shadcn.com/) <Badge className="bg-blue-200 text-blue-700 dark:bg-blue-500 dark:text-blue-50 ">NEW</Badge>
 
-A themeable component library for React. We use their default components and styles to build apps very quickly, but with the option of adding custom styles or themes later if needed. Shadcn/ui also includes many helpful React hooks, and they provide a Modal and Notification system to ProofKit apps.
+A themeable component library for React. We use their default components and styles to build apps very quickly, but with the option of adding custom styles or themes later if needed. shadcn/ui also includes many helpful React hooks, and they provide a Modal and Notification system to ProofKit apps.
 
 Using the shadcn CLI, you can install any component or utility from any compatible library. This makes shadcn the best choice for the most flexible and customizable apps. Some of our favorite shadcn-compatible libraries are:
-- [Kibu Ui](https://www.kibo-ui.com/)
+- [Kibo UI](https://www.kibo-ui.com/)
 - [reui](https://reui.io/)
 - [Magic UI](https://magicui.design/)
 - [tweakcn (easily theme your components)](https://tweakcn.com/)
 - [A longer list of more...](https://github.com/birobirobiro/awesome-shadcn-ui)
 
-#### [Tanstack Query](https://tanstack.com/query)
+#### [TanStack Query](https://tanstack.com/query)
 
-Sometimes also known as "React Query"; a library for managing server state in React. It's used by ProofKit to fetch data from external sources, such as REST APIs, so we can be certain that the "shape" of our data matches what we expected during development.
+Sometimes also known as "React Query"; a library for managing server state in React. It's used by ProofKit for fetching, caching, deduping, background updates, and invalidation of server data.
 
 #### [Zod](https://zod.dev/)
 
 A type-safe validation library for JavaScript and TypeScript. It's used by ProofKit to validate all inputs from external sources, such as REST APIs, so we can be certain that the "shape" of our data matches what we expected during development. It's also used in form validation.
 
 #### [Better-Auth](https://better-auth.com/) (self-hosted)
 
 For when you need a bit more flexibility or if you want to self-host the authentication layer within your existing FileMaker solution. Better-auth is a great choice for this, and the [proofkit/better-auth](/docs/better-auth) adapter allows you to use FileMaker as your backend database, including automated schema migrations to easily add any necessary tables and fields to your FileMaker file.

Also applies to: 55-58, 73-76

apps/docs/content/docs/better-auth/installation.mdx (1)

19-26: Typos/wording: set up vs setup; Tailwind CSS; brand casing.

  • “setup” (verb) → “set up”.
  • “tailwindcss” → “Tailwind CSS”.
  • Prefer “Better Auth” in the note.

Apply this diff:

 <Callout type="warning">
-This automated setup expects you to have Next.js and shadcn/ui set up in your project. It will also setup various auth pages for you, but these may not work if you have a prefix configured for tailwindcss. You can use this opinionated setup to get you started, or if you need more control you should refer to the manual setup.
+This automated setup expects you to have Next.js and shadcn/ui set up in your project. It will also set up various auth pages for you, but these may not work if you have a prefix configured for Tailwind CSS. You can use this opinionated setup to get you started, or if you need more control you should refer to the manual setup.
 </Callout>
@@
-Run the following command to add the necessary packages and config files to your project. You will not need to follow the better-auth installation guide.
+Run the following command to add the necessary packages and config files to your project. You won't need to follow the Better Auth installation guide.

Comment on lines +72 to 73
The tables/fields that are created will be dependent on how your `auth.ts` file is setup. If you want to use any of your existing tables, just set [custom table names](https://www.better-auth.com/docs/concepts/database#custom-table-names) in the `auth.ts` file before running the migration command.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typos/wording: “is setup” → “is set up”.

Also simplify phrasing.

Apply this diff:

-The tables/fields that are created will be dependent on how your `auth.ts` file is setup. If you want to use any of your existing tables, just set [custom table names](https://www.better-auth.com/docs/concepts/database#custom-table-names) in the `auth.ts` file before running the migration command.
+The tables/fields that are created will depend on how your `auth.ts` file is set up. If you want to use any of your existing tables, set [custom table names](https://www.better-auth.com/docs/concepts/database#custom-table-names) in the `auth.ts` file before running the migration command.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
The tables/fields that are created will be dependent on how your `auth.ts` file is setup. If you want to use any of your existing tables, just set [custom table names](https://www.better-auth.com/docs/concepts/database#custom-table-names) in the `auth.ts` file before running the migration command.
The tables/fields that are created will depend on how your `auth.ts` file is set up. If you want to use any of your existing tables, set [custom table names](https://www.better-auth.com/docs/concepts/database#custom-table-names) in the `auth.ts` file before running the migration command.
🤖 Prompt for AI Agents
In apps/docs/content/docs/better-auth/installation.mdx around lines 72-73, fix
the wording "is setup" to "is set up" and simplify the sentence for clarity;
reword the two sentences into a single concise sentence that advises the reader
that created tables/fields depend on their auth.ts configuration and that
existing tables can be used by setting custom table names in auth.ts before
running the migration command.

Comment on lines +10 to +11
prefix: "npm run",
execPrefix: "npx",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix npm/bun non-exec prefixes.

  • npm: “npm run” assumes a package.json script; use npx for binaries.
  • bun: “bun” won’t run package binaries; use bunx.

Apply this diff:

-    prefix: "npm run",
+    prefix: "npx",
@@
-    prefix: "bun",
+    prefix: "bunx",

Also applies to: 26-29

🤖 Prompt for AI Agents
In apps/docs/src/components/CliCommand.tsx around lines 10-11 and 26-29, the
non-exec prefixes for npm and bun are incorrect; update the npm non-exec prefix
from "npm run" to "npx" (so binaries use npx instead of assuming a package
script) and update the bun non-exec prefix from "bun" to "bunx" (so bun package
binaries run correctly).

Comment on lines +33 to +41
export function CliCommand({
command,
exec,
execPackage = `@proofkit/cli@${cliVersion}`,
}: {
command: string;
exec?: boolean;
execPackage?: string;
}) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Preserve DynamicCodeBlock props (e.g., frame).

CliCommand drops props like frame used across MDX. Accept and forward rest props to avoid breaking existing pages.

Apply this diff:

+import type { ComponentProps } from "react";
@@
-export function CliCommand({
-  command,
-  exec,
-  execPackage = `@proofkit/cli@${cliVersion}`,
-}: {
-  command: string;
-  exec?: boolean;
-  execPackage?: string;
-}) {
+export function CliCommand({
+  command,
+  exec,
+  execPackage = `@proofkit/cli@${cliVersion}`,
+  ...rest
+}: {
+  command: string;
+  exec?: boolean;
+  execPackage?: string;
+} & Partial<ComponentProps<typeof DynamicCodeBlock>>) {
@@
-          <DynamicCodeBlock
+          <DynamicCodeBlock
             lang="bash"
             code={`${exec ? manager.execPrefix + " " + execPackage : manager.prefix} ${command}`}
-          />
+            {...rest}
+          />

Verification script to find usages passing frame:

Also applies to: 51-54


🏁 Script executed:

#!/bin/bash
rg -n -C2 '<CliCommand[^>]*\bframe=' --glob '!**/node_modules/**'

Length of output: 148


🏁 Script executed:

#!/bin/bash
echo "Searching for all <CliCommand> usages in MDX and TSX files:"
rg -n '<CliCommand' -g '*.mdx' -g '*.tsx' --color always || true

echo ""
echo "Searching for <CliCommand> usages with a frame= attribute:"
rg -n '<CliCommand[^>]*frame=' -g '*.mdx' -g '*.tsx' --color always || true

Length of output: 4346


#!/bin/bash
echo "Import of DynamicCodeBlock:"
rg -n "import .*DynamicCodeBlock" -g "apps/docs/src/components/CliCommand.tsx" -C2

echo ""
echo "CliCommand component signature and usage of DynamicCodeBlock:"
rg -n -C3 "export function CliCommand" -g "apps/docs/src/components/CliCommand.tsx"
rg -n -C3 "DynamicCodeBlock" -g "apps/docs/src/components/CliCommand.tsx"

🏁 Script executed:

#!/bin/bash
# Verify import of DynamicCodeBlock
rg -nP "import.*DynamicCodeBlock" -g "apps/docs/src/components/CliCommand.tsx"

echo ""
# Show component signature
rg -n -C3 "export function CliCommand" -g "apps/docs/src/components/CliCommand.tsx"

echo ""
# Show usage of DynamicCodeBlock inside CliCommand
rg -n -C3 "DynamicCodeBlock" -g "apps/docs/src/components/CliCommand.tsx"

Length of output: 1492


Forward DynamicCodeBlock props in CliCommand

Extend CliCommand to accept ...rest of ComponentProps<typeof DynamicCodeBlock> and spread them into <DynamicCodeBlock> so MDX pages passing frame (and other props) don’t break.

File apps/docs/src/components/CliCommand.tsx

+import type { ComponentProps } from "react";
@@
-export function CliCommand({
+export function CliCommand({
   command,
   exec,
   execPackage = `@proofkit/cli@${cliVersion}`,
+  ...rest
-}: {
+}: { command: string; exec?: boolean; execPackage?: string } & Partial<ComponentProps<typeof DynamicCodeBlock>>) {
@@
-          <DynamicCodeBlock
+          <DynamicCodeBlock
             lang="bash"
             code={`${exec ? manager.execPrefix + " " + execPackage : manager.prefix} ${command}`}
-          />
+            {...rest}
+          />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function CliCommand({
command,
exec,
execPackage = `@proofkit/cli@${cliVersion}`,
}: {
command: string;
exec?: boolean;
execPackage?: string;
}) {
import type { ComponentProps } from "react";
// … other imports …
import { DynamicCodeBlock } from "./DynamicCodeBlock";
export function CliCommand({
command,
exec,
execPackage = `@proofkit/cli@${cliVersion}`,
...rest
}: { command: string; exec?: boolean; execPackage?: string }
& Partial<ComponentProps<typeof DynamicCodeBlock>>
) {
const manager = getPackageManager(); // assuming this is defined elsewhere
return (
<DynamicCodeBlock
lang="bash"
code={`${exec ? manager.execPrefix + " " + execPackage : manager.prefix} ${command}`}
{...rest}
/>
);
}

Comment on lines +71 to +79
<Link
key={item.url}
href={item.url}
onClick={onClick}
{...item.props}
className={cn(
"flex items-center gap-2 rounded-lg p-1.5 hover:bg-fd-accent hover:text-fd-accent-foreground",
item.props?.className,
)}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Compose onClick handlers; current spread can override closing logic.

{...item.props} after onClick={onClick} can replace the handler and leave the popover open. Compose both.

-            <Link
+            <Link
               key={item.url}
               href={item.url}
-              onClick={onClick}
+              onClick={(e) => {
+                item.props?.onClick?.(e);
+                onClick();
+              }}
               {...item.props}
               className={cn(
                 "flex items-center gap-2 rounded-lg p-1.5 hover:bg-fd-accent hover:text-fd-accent-foreground",
                 item.props?.className,
               )}
             >

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/docs/src/components/root-toggle.tsx around lines 71 to 79, the current
JSX spreads {...item.props} after onClick={onClick} which allows
item.props.onClick to overwrite the popover-closing onClick; fix by composing
the handlers instead of letting the spread override: create a combinedOnClick
that invokes item.props.onClick (if present) and then the local onClick (or vice
versa depending on desired order), pass combinedOnClick as the onClick prop, and
spread the rest of item.props excluding its onClick and className (merge
className values instead of letting the spread replace them).

- Cast Object.keys(grouped) to Category[] to fix type error
- Ensures proper type safety when accessing grouped[category]
- Resolves build failure in docs app
@eluce2 eluce2 merged commit 7a263a1 into main Sep 26, 2025
7 checks passed
@eluce2 eluce2 deleted the 09-19-template_docs branch September 26, 2025 16:49
@coderabbitai coderabbitai bot mentioned this pull request Dec 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants