Chris Tate 5 mesi fa
parent
commit
f004caf95e

+ 41 - 59
apps/web/components/docs-mobile-nav.tsx

@@ -10,55 +10,15 @@ import {
   SheetContent,
   SheetTitle,
 } from "@/components/ui/sheet";
-
-const navigation = [
-  {
-    title: "Getting Started",
-    items: [
-      { title: "Introduction", href: "/docs" },
-      { title: "Installation", href: "/docs/installation" },
-      { title: "Quick Start", href: "/docs/quick-start" },
-    ],
-  },
-  {
-    title: "Core Concepts",
-    items: [
-      { title: "Catalog", href: "/docs/catalog" },
-      { title: "Registry", href: "/docs/registry" },
-      { title: "Data Binding", href: "/docs/data-binding" },
-      { title: "Actions", href: "/docs/actions" },
-      { title: "Visibility", href: "/docs/visibility" },
-      { title: "Validation", href: "/docs/validation" },
-    ],
-  },
-  {
-    title: "Guides",
-    items: [
-      { title: "AI SDK Integration", href: "/docs/ai-sdk" },
-      { title: "Streaming", href: "/docs/streaming" },
-      { title: "Code Export", href: "/docs/code-export" },
-    ],
-  },
-  {
-    title: "API Reference",
-    items: [
-      { title: "@json-render/core", href: "/docs/api/core" },
-      { title: "@json-render/react", href: "/docs/api/react" },
-      { title: "@json-render/codegen", href: "/docs/api/codegen" },
-    ],
-  },
-];
-
-// Flatten all pages for current page lookup
-const allPages = navigation.flatMap((section) => section.items);
+import { docsNavigation, allDocsPages } from "@/lib/docs-navigation";
 
 export function DocsMobileNav() {
   const [open, setOpen] = useState(false);
   const pathname = usePathname();
 
   const currentPage = useMemo(() => {
-    const page = allPages.find((page) => page.href === pathname);
-    return page ?? allPages[0];
+    const page = allDocsPages.find((page) => page.href === pathname);
+    return page ?? allDocsPages[0];
   }, [pathname]);
 
   return (
@@ -72,27 +32,49 @@ export function DocsMobileNav() {
       <SheetContent className="overflow-y-auto p-6">
         <SheetTitle className="mb-6">Table of Contents</SheetTitle>
         <nav className="space-y-6">
-          {navigation.map((section) => (
+          {docsNavigation.map((section) => (
             <div key={section.title}>
               <h4 className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-2">
                 {section.title}
               </h4>
               <ul className="space-y-1">
-                {section.items.map((item) => (
-                  <li key={item.href}>
-                    <Link
-                      href={item.href}
-                      onClick={() => setOpen(false)}
-                      className={`text-sm block py-2 transition-colors ${
-                        pathname === item.href
-                          ? "text-primary font-medium"
-                          : "text-muted-foreground hover:text-foreground"
-                      }`}
-                    >
-                      {item.title}
-                    </Link>
-                  </li>
-                ))}
+                {section.items.map((item) => {
+                  const isExternal = item.external;
+                  return (
+                    <li key={item.href}>
+                      <Link
+                        href={item.href}
+                        onClick={() => setOpen(false)}
+                        {...(isExternal && {
+                          target: "_blank",
+                          rel: "noopener noreferrer",
+                        })}
+                        className={`text-sm block py-2 transition-colors ${
+                          pathname === item.href
+                            ? "text-primary font-medium"
+                            : "text-muted-foreground hover:text-foreground"
+                        } ${isExternal ? "inline-flex items-center gap-1" : ""}`}
+                      >
+                        {item.title}
+                        {isExternal && (
+                          <svg
+                            className="w-3 h-3"
+                            fill="none"
+                            stroke="currentColor"
+                            viewBox="0 0 24 24"
+                          >
+                            <path
+                              strokeLinecap="round"
+                              strokeLinejoin="round"
+                              strokeWidth={2}
+                              d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
+                            />
+                          </svg>
+                        )}
+                      </Link>
+                    </li>
+                  );
+                })}
               </ul>
             </div>
           ))}

+ 3 - 68
apps/web/components/docs-sidebar.tsx

@@ -3,79 +3,14 @@
 import Link from "next/link";
 import { usePathname } from "next/navigation";
 import { cn } from "@/lib/utils";
-
-const navigation = [
-  {
-    title: "Getting Started",
-    items: [
-      { title: "Introduction", href: "/docs" },
-      { title: "Installation", href: "/docs/installation" },
-      { title: "Quick Start", href: "/docs/quick-start" },
-      { title: "Changelog", href: "/docs/changelog" },
-    ],
-  },
-  {
-    title: "Core Concepts",
-    items: [
-      { title: "Specs", href: "/docs/specs" },
-      { title: "Schemas", href: "/docs/schemas" },
-      { title: "Catalog", href: "/docs/catalog" },
-      { title: "Registry", href: "/docs/registry" },
-      { title: "Data Binding", href: "/docs/data-binding" },
-      { title: "Visibility", href: "/docs/visibility" },
-      { title: "Validation", href: "/docs/validation" },
-    ],
-  },
-  {
-    title: "Examples",
-    items: [
-      {
-        title: "Dashboard",
-        href: "https://github.com/vercel-labs/json-render/tree/main/examples/dashboard",
-        external: true,
-      },
-      {
-        title: "Remotion",
-        href: "https://github.com/vercel-labs/json-render/tree/main/examples/remotion",
-        external: true,
-      },
-    ],
-  },
-  {
-    title: "Guides",
-    items: [
-      { title: "Custom Schema", href: "/docs/custom-schema" },
-      { title: "Streaming", href: "/docs/streaming" },
-      { title: "Code Export", href: "/docs/code-export" },
-    ],
-  },
-  {
-    title: "Integrations",
-    items: [
-      { title: "AI SDK", href: "/docs/ai-sdk" },
-      { title: "A2UI", href: "/docs/a2ui" },
-      { title: "Adaptive Cards", href: "/docs/adaptive-cards" },
-      { title: "AG-UI", href: "/docs/ag-ui" },
-      { title: "OpenAPI", href: "/docs/openapi" },
-    ],
-  },
-  {
-    title: "API Reference",
-    items: [
-      { title: "@json-render/core", href: "/docs/api/core" },
-      { title: "@json-render/react", href: "/docs/api/react" },
-      { title: "@json-render/remotion", href: "/docs/api/remotion" },
-      { title: "@json-render/codegen", href: "/docs/api/codegen" },
-    ],
-  },
-];
+import { docsNavigation } from "@/lib/docs-navigation";
 
 export function DocsSidebar() {
   const pathname = usePathname();
 
   return (
     <nav className="space-y-6 pb-8">
-      {navigation.map((section) => (
+      {docsNavigation.map((section) => (
         <div key={section.title}>
           <h4 className="text-xs font-normal text-muted-foreground/50 uppercase tracking-wider mb-2">
             {section.title}
@@ -83,7 +18,7 @@ export function DocsSidebar() {
           <ul className="space-y-1">
             {section.items.map((item) => {
               const isActive = pathname === item.href;
-              const isExternal = "external" in item && item.external;
+              const isExternal = item.external;
               return (
                 <li key={item.href}>
                   <Link

+ 81 - 0
apps/web/lib/docs-navigation.ts

@@ -0,0 +1,81 @@
+export type NavItem = {
+  title: string;
+  href: string;
+  external?: boolean;
+};
+
+export type NavSection = {
+  title: string;
+  items: NavItem[];
+};
+
+export const docsNavigation: NavSection[] = [
+  {
+    title: "Getting Started",
+    items: [
+      { title: "Introduction", href: "/docs" },
+      { title: "Installation", href: "/docs/installation" },
+      { title: "Quick Start", href: "/docs/quick-start" },
+      { title: "Changelog", href: "/docs/changelog" },
+    ],
+  },
+  {
+    title: "Core Concepts",
+    items: [
+      { title: "Specs", href: "/docs/specs" },
+      { title: "Schemas", href: "/docs/schemas" },
+      { title: "Catalog", href: "/docs/catalog" },
+      { title: "Registry", href: "/docs/registry" },
+      { title: "Data Binding", href: "/docs/data-binding" },
+      { title: "Visibility", href: "/docs/visibility" },
+      { title: "Validation", href: "/docs/validation" },
+    ],
+  },
+  {
+    title: "Examples",
+    items: [
+      {
+        title: "Dashboard",
+        href: "https://github.com/vercel-labs/json-render/tree/main/examples/dashboard",
+        external: true,
+      },
+      {
+        title: "Remotion",
+        href: "https://github.com/vercel-labs/json-render/tree/main/examples/remotion",
+        external: true,
+      },
+    ],
+  },
+  {
+    title: "Guides",
+    items: [
+      { title: "Custom Schema", href: "/docs/custom-schema" },
+      { title: "Streaming", href: "/docs/streaming" },
+      { title: "Code Export", href: "/docs/code-export" },
+    ],
+  },
+  {
+    title: "Integrations",
+    items: [
+      { title: "AI SDK", href: "/docs/ai-sdk" },
+      { title: "A2UI", href: "/docs/a2ui" },
+      { title: "Adaptive Cards", href: "/docs/adaptive-cards" },
+      { title: "AG-UI", href: "/docs/ag-ui" },
+      { title: "OpenAPI", href: "/docs/openapi" },
+    ],
+  },
+  {
+    title: "API Reference",
+    items: [
+      { title: "@json-render/core", href: "/docs/api/core" },
+      { title: "@json-render/react", href: "/docs/api/react" },
+      { title: "@json-render/remotion", href: "/docs/api/remotion" },
+      { title: "@json-render/codegen", href: "/docs/api/codegen" },
+    ],
+  },
+];
+
+// Flatten all pages for current page lookup (excludes external links)
+export const allDocsPages = docsNavigation.flatMap((section) =>
+  section.items.filter((item) => !item.external),
+);