diff --git a/app/academy/layout.tsx b/app/academy/layout.tsx index d31dd495164..d86f9be66ad 100644 --- a/app/academy/layout.tsx +++ b/app/academy/layout.tsx @@ -1,32 +1,20 @@ import { DocsLayout, type DocsLayoutProps } from 'fumadocs-ui/layouts/notebook'; +import { HomeLayout } from 'fumadocs-ui/layouts/home'; import type { ReactNode } from 'react'; -import { baseOptions, docsMenu, consoleMenu, integrationsMenu, userMenu } from '@/app/layout.config'; +import { baseOptions } from '@/app/layout.config'; import { academy } from '@/lib/source'; -import { AvalancheLogo } from '@/components/navigation/avalanche-logo'; +import './styles.css'; const academyOptions: DocsLayoutProps = { - ...baseOptions, + tree: academy.pageTree, nav: { - mode: "top" as const, - title: ( - <> - {} - Academy - - ), - url: '/academy', + enabled: false, }, - tree: academy.pageTree, - links: [ - consoleMenu, - docsMenu, - integrationsMenu, - userMenu - ], }; export default function Layout({ children }: { children: ReactNode }) { return ( + {children} + ); } \ No newline at end of file diff --git a/app/academy/styles.css b/app/academy/styles.css new file mode 100644 index 00000000000..bc66d8d5414 --- /dev/null +++ b/app/academy/styles.css @@ -0,0 +1,29 @@ +/* Increase spacing between the main navbar and the academy sidebar dropdown */ +@media (min-width: 768px) { + #nd-sidebar > div:first-child { + padding-top: calc(var(--spacing) * 7.5); + } +} + +/* Remove thin separator line from library defaults under navbar */ +body > div > nav[aria-label="Main"], +.nd-layout-home > nav:not([role="tablist"]):not(.nd-tabs-nav), +.nd-layout-home > header:not([role="tablist"]):not(.nd-tabs-nav) { + border-bottom: 0 !important; + box-shadow: none !important; +} + +/* Remove any top border drawn directly under the navbar */ +nav[aria-label="Main"] + *, +header + * { + border-top: 0 !important; + box-shadow: none !important; +} + +/* Fumadocs DocsNavbar adds border-b on internal containers; remove it */ +#nd-subnav .border-b { + border-bottom: 0 !important; + box-shadow: none !important; +} + + diff --git a/app/docs/layout.tsx b/app/docs/layout.tsx index 5a1d2c34cd4..24252a342db 100644 --- a/app/docs/layout.tsx +++ b/app/docs/layout.tsx @@ -1,34 +1,22 @@ import { DocsLayout, type DocsLayoutProps } from 'fumadocs-ui/layouts/notebook'; +import { HomeLayout } from 'fumadocs-ui/layouts/home'; import type { ReactNode } from 'react'; -import { baseOptions, academyMenu, consoleMenu, integrationsMenu } from '@/app/layout.config'; +import { baseOptions } from '@/app/layout.config'; import { documentation } from '@/lib/source'; import 'fumadocs-twoslash/twoslash.css'; -import { AvalancheLogo } from '@/components/navigation/avalanche-logo'; +import './styles.css'; const docsOptions: DocsLayoutProps = { -tree: documentation.pageTree, -tabMode: 'navbar', -nav: { - ...baseOptions.nav, - mode: 'top', - title: ( - <> - {} - Documentation - - ), - url: '/docs', + tree: documentation.pageTree, + nav: { + enabled: false, }, - links: [ - academyMenu, - consoleMenu, - integrationsMenu - ] }; export default function Layout({ children }: { children: ReactNode }) { return ( - + + {children} - + + ); } \ No newline at end of file diff --git a/app/docs/styles.css b/app/docs/styles.css new file mode 100644 index 00000000000..c41a6dce7cd --- /dev/null +++ b/app/docs/styles.css @@ -0,0 +1,59 @@ +/* Force ONLY main navbar to extend to left edge - DOCS PAGE ONLY */ +body { + padding-left: 0 !important; + margin-left: 0 !important; +} + +/* Target only the main navbar, NOT the tabs nav */ +body > div > nav[aria-label="Main"], +.nd-layout-home > nav:not([role="tablist"]):not(.nd-tabs-nav), +.nd-layout-home > header:not([role="tablist"]):not(.nd-tabs-nav) { + padding-left: 0 !important; + margin-left: 0 !important; + width: 100vw !important; + max-width: 100vw !important; + /* Remove thin separator line from library defaults */ + border-bottom: 0 !important; + box-shadow: none !important; +} + +/* Container gets the padding instead - only for main nav */ +nav[aria-label="Main"] > div, +.nd-layout-home > nav:not([role="tablist"]):not(.nd-tabs-nav) > div, +.nd-layout-home > header:not([role="tablist"]):not(.nd-tabs-nav) > div { + padding-left: 1rem !important; + padding-right: 1rem !important; +} + +/* Preserve normal styling for tabs nav */ +.nd-tabs-nav, +nav[role="tablist"], +[role="tablist"] { + width: auto !important; + max-width: none !important; + padding-left: 0 !important; +} + +/* Add padding at top of docs content area */ +.nd-layout-notebook { + padding-top: 2rem !important; +} + +/* Add padding to the main content container */ +main .nd-layout-notebook > div:first-child { + padding-top: 1rem !important; +} + +/* Remove any top border drawn directly under the navbar */ +nav[aria-label="Main"] + *, +header + * { + border-top: 0 !important; + box-shadow: none !important; +} + +/* Fumadocs DocsNavbar adds border-b on internal containers; remove it */ +#nd-subnav .border-b { + border-bottom: 0 !important; + box-shadow: none !important; +} + diff --git a/app/global.css b/app/global.css index 3d9e2340383..b0d9d66fde1 100644 --- a/app/global.css +++ b/app/global.css @@ -10,7 +10,7 @@ @media (min-width: 768px) { #nd-sidebar > div:first-child { - padding-top: calc(var(--spacing) * 3.5); + padding-top: calc(var(--spacing) * 7.5); } } /* @plugin "@tailwindcss/typography"; */ @@ -26,6 +26,49 @@ div.group\/accordion h3 { margin-top: 0 !important; } +/* Remove ALL left whitespace from navbar to fill screen edge */ +body > div > nav, +body > div > header, +nav[aria-label="Main"], +header nav, +.nd-nav, +.nd-layout-home > nav, +.nd-layout-home > header { + padding-left: 0 !important; + margin-left: 0 !important; + padding-right: 0 !important; + margin-right: 0 !important; + max-width: 100% !important; +} + +/* Remove container padding/margin */ +nav > div, +header > div, +nav[aria-label="Main"] > div, +.nd-nav > div { + padding-left: 1rem !important; + padding-right: 1rem !important; + margin-left: 0 !important; + margin-right: 0 !important; + max-width: 100% !important; +} + +/* Force the navbar to be full width */ +body > div:first-child, +body > div > main { + padding-left: 0 !important; + padding-right: 0 !important; +} + +/* Specifically target fumadocs nav container */ +.nd-layout-home, +.nd-layout-docs { + padding-left: 0 !important; + padding-right: 0 !important; + margin-left: 0 !important; + margin-right: 0 !important; +} + /* .light .prose :where(a:not([data-card])):not(:where([class~="not-prose"],[class~="not-prose"] *)) { color: #18181B; } diff --git a/app/layout.config.tsx b/app/layout.config.tsx index 3ad22b15dc0..e3df82b7106 100644 --- a/app/layout.config.tsx +++ b/app/layout.config.tsx @@ -140,7 +140,7 @@ export const stats: LinkItemType = { export const docsMenu: LinkItemType = { type: 'menu', - text: 'Docs', + text: 'Documentation', url: '/docs/quick-start', items: [ { diff --git a/middleware.ts b/middleware.ts index 3e1a2c89292..24bca07bd2a 100644 --- a/middleware.ts +++ b/middleware.ts @@ -4,6 +4,15 @@ import { NextMiddlewareResult } from "next/dist/server/web/types"; import { NextRequest, NextResponse } from "next/server"; export async function middleware(req: NextRequest) { + const pathname = req.nextUrl.pathname; + + // Proxy Mintlify-powered API Reference through our domain in production + if (pathname === '/docs/api-reference' || pathname.startsWith('/docs/api-reference/')) { + const suffix = pathname === '/docs/api-reference' ? '' : pathname.replace('/docs/api-reference', ''); + const target = new URL(`https://developers.avacloud.io${suffix}${req.nextUrl.search}`); + return NextResponse.rewrite(target); + } + const response = NextResponse.next(); response.headers.set("Access-Control-Allow-Origin", "*"); response.headers.set( @@ -18,17 +27,14 @@ export async function middleware(req: NextRequest) { if (req.method === "OPTIONS") { return new Response(null, { status: 204 }); } + const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET }); - const pathname = req.nextUrl.pathname; const isAuthenticated = !!token; const isLoginPage = pathname === "/login"; const isShowCase = pathname.startsWith("/showcase"); const custom_attributes = token?.custom_attributes as string[] ?? [] - // If not authenticated and trying to access protected routes, - // preserve the complete URL (including UTM) as callbackUrl if (!isAuthenticated && !isLoginPage) { - // Check if it's a protected path const protectedPaths = [ "/hackathons/registration-form", "/hackathons/project-submission", @@ -48,16 +54,13 @@ export async function middleware(req: NextRequest) { } if (isAuthenticated) { - if (isLoginPage) return NextResponse.redirect(new URL("/", req.url)); - //TODO Change this line to enable showcase to a different set of users if (isShowCase && !custom_attributes.includes('showcase')) return NextResponse.redirect(new URL("/hackathons", req.url)) - - } + return withAuth( (authReq: NextRequestWithAuth): NextMiddlewareResult => { return NextResponse.next(); @@ -68,7 +71,6 @@ export async function middleware(req: NextRequest) { }, callbacks: { authorized: ({ token }) => !!token, - } } )(req as NextRequestWithAuth, {} as any); @@ -76,6 +78,8 @@ export async function middleware(req: NextRequest) { export const config = { matcher: [ + "/docs/api-reference", + "/docs/api-reference/:path*", "/hackathons/registration-form/:path*", "/hackathons/project-submission/:path*", "/showcase/:path*", diff --git a/next.config.mjs b/next.config.mjs index 6eaaa1733a8..371d2f79ec6 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -40,10 +40,30 @@ const config = { protocol: 'https', hostname: 'cdn.prod.website-files.com', }, + { + protocol: 'https', + hostname: 'developers.avacloud.io', + }, ], }, async rewrites() { return [ + { + source: '/mintlify-assets/:path*', + destination: 'https://developers.avacloud.io/mintlify-assets/:path*', + }, + { + source: '/_mintlify/:path*', + destination: 'https://developers.avacloud.io/_mintlify/:path*', + }, + { + source: '/docs/api-reference', + destination: 'https://developers.avacloud.io', + }, + { + source: '/docs/api-reference/:path*', + destination: 'https://developers.avacloud.io/:path*', + }, { source: '/docs/:path*.mdx', destination: '/llms.mdx/docs/:path*', @@ -64,6 +84,41 @@ const config = { }, async redirects() { return [ + { + source: '/introduction', + destination: '/docs/api-reference/introduction', + permanent: false, + }, + { + source: '/data-api/:path*', + destination: '/docs/api-reference/data-api/:path*', + permanent: false, + }, + { + source: '/webhooks-api/:path*', + destination: '/docs/api-reference/webhooks-api/:path*', + permanent: false, + }, + { + source: '/metrics-api/:path*', + destination: '/docs/api-reference/metrics-api/:path*', + permanent: false, + }, + { + source: '/rpc-api/:path*', + destination: '/docs/api-reference/rpc-api/:path*', + permanent: false, + }, + { + source: '/avalanche-sdk/:path*', + destination: '/docs/api-reference/avalanche-sdk/:path*', + permanent: false, + }, + { + source: '/changelog/:path*', + destination: '/docs/api-reference/changelog/:path*', + permanent: false, + }, { source: '/codebase-entrepreneur', destination: '/codebase-entrepreneur-academy',