Layouts and Pages

Create beautiful layouts and pages in VitNode plugins using Next.js App Router patterns.

Building layouts and pages in VitNode is just like Next.js - if you know Next.js, you're already a VitNode pro! Think of pages as rooms and layouts as the house structure that holds everything together.

VitNode automatically copies files from your plugin's app directory to the main application. No extra setup needed!

Creating Pages

Pages are React components that live in page.tsx files. Each page represents a unique URL route.

Basic Page

plugins/blog/src/app/page.tsx
export default function BlogHomePage() {
  return (
    <div className="py-12 text-center">
      <h1 className="mb-4 text-4xl font-bold">Welcome to Our Blog! 🚀</h1>
      <p className="text-gray-600">Where awesome content lives</p>
    </div>
  );
}

Nested Routes

Create folders to organize your routes:

plugins/blog/src/app/dashboard/page.tsx
export default function DashboardPage() {
  return (
    <div>
      <h1 className="text-3xl font-bold">Dashboard</h1>
      <p>Manage your blog content here</p>
    </div>
  );
}

This creates /dashboard route.

Dynamic Routes

Use [param] for dynamic URLs:

plugins/blog/src/app/posts/[slug]/page.tsx
interface PostPageProps {
  params: Promise<{ slug: string }>;
}

export default async function PostPage({ params }: PostPageProps) {
  const { slug } = await params;

  return (
    <div>
      <h1>Post: {slug}</h1>
      <p>Your post content goes here</p>
    </div>
  );
}

Creating Layouts

Layouts wrap your pages and provide shared UI elements like headers, navigation, and footers.

Basic Layout

plugins/blog/src/app/layout.tsx
import { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'My Blog Plugin',
  description: 'A fantastic blog plugin for VitNode',
};

export default function BlogLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="min-h-screen">
      <header className="border-b bg-white shadow-sm">
        <div className="container mx-auto px-4 py-4">
          <h1 className="text-2xl font-bold text-indigo-600">✨ My Blog</h1>
        </div>
      </header>

      <main className="container mx-auto px-4 py-8">{children}</main>

      <footer className="bg-gray-900 py-8 text-white">
        <div className="container mx-auto px-4 text-center">
          <p>Made with ❤️ using VitNode</p>
        </div>
      </footer>
    </div>
  );
}

Nested Layout for Specific Sections

plugins/blog/src/app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="flex">
      {/* Sidebar */}
      <aside className="min-h-screen w-64 border-r bg-gray-50">
        <nav className="p-6">
          <h2 className="mb-4 font-semibold">Dashboard</h2>
          <ul className="space-y-2">
            <li>
              <a
                href="/dashboard"
                className="text-gray-700 hover:text-indigo-600"
              >
                Overview
              </a>
            </li>
            <li>
              <a
                href="/dashboard/posts"
                className="text-gray-700 hover:text-indigo-600"
              >
                Posts
              </a>
            </li>
            <li>
              <a
                href="/dashboard/settings"
                className="text-gray-700 hover:text-indigo-600"
              >
                Settings
              </a>
            </li>
          </ul>
        </nav>
      </aside>

      {/* Main content */}
      <div className="flex-1 p-8">{children}</div>
    </div>
  );
}

Adding Metadata

Improve SEO and social sharing with metadata:

plugins/blog/src/app/posts/[slug]/page.tsx
import { Metadata } from 'next'; 

interface PostPageProps {
  params: Promise<{ slug: string }>;
}

export async function generateMetadata({
  params,
}: PostPageProps): Promise<Metadata> {
  const { slug } = await params;

  return {
    title: `Post: ${slug}`,
    description: `Read about ${slug} on our blog`,
  };
}

export default async function PostPage({ params }: PostPageProps) {
  const { slug } = await params;

  return (
    <article>
      <h1>Post: {slug}</h1>
      <p>Your post content here...</p>
    </article>
  );
}

Learn More