Files
vibn-frontend/components/layout/PAGE_TEMPLATE_GUIDE.md

8.7 KiB

Page Template Guide

A consistent, reusable page layout system for all pages in the application.

Features

  • Consistent Layout: Left rail + sidebar + main content area
  • Responsive Design: Works on all screen sizes
  • Sidebar Navigation: Built-in support for left sidebar with active states
  • Hero Section: Optional hero banner with icon, title, description, and actions
  • Utility Components: Pre-built sections, cards, grids, and empty states
  • Type-safe: Full TypeScript support

Basic Usage

import { PageTemplate } from "@/components/layout/page-template";
import { Home } from "lucide-react";

export default function MyPage() {
  return (
    <PageTemplate
      hero={{
        icon: Home,
        title: "My Page Title",
        description: "A brief description of what this page does",
      }}
    >
      <div>Your page content here</div>
    </PageTemplate>
  );
}

With Sidebar Navigation

import { PageTemplate } from "@/components/layout/page-template";
import { Home, Settings, Users } from "lucide-react";

export default function MyPage() {
  return (
    <PageTemplate
      sidebar={{
        title: "My Section",
        description: "Navigate through options",
        items: [
          { title: "Home", icon: Home, href: "/home", isActive: true },
          { title: "Settings", icon: Settings, href: "/settings" },
          { title: "Users", icon: Users, href: "/users", badge: "3" },
        ],
        footer: <p className="text-xs">Footer content</p>,
      }}
      hero={{
        icon: Home,
        title: "My Page",
        description: "Page description",
        actions: [
          {
            label: "Create New",
            onClick: () => console.log("Create"),
            icon: Plus,
          },
        ],
      }}
    >
      <div>Your content</div>
    </PageTemplate>
  );
}

Using Utility Components

PageSection

Organized content sections with optional titles and actions:

import { PageSection } from "@/components/layout/page-template";
import { Button } from "@/components/ui/button";

<PageSection
  title="Recent Activity"
  description="Your latest updates"
  headerAction={<Button size="sm">View All</Button>}
>
  <div>Section content</div>
</PageSection>

PageCard

Styled cards with consistent padding and hover effects:

import { PageCard } from "@/components/layout/page-template";

<PageCard padding="lg" hover>
  <h3>Card Title</h3>
  <p>Card content</p>
</PageCard>

PageGrid

Responsive grid layouts:

import { PageGrid } from "@/components/layout/page-template";

<PageGrid cols={3}>
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</PageGrid>

PageEmptyState

Empty states with icon, title, description, and action:

import { PageEmptyState } from "@/components/layout/page-template";
import { Inbox } from "lucide-react";

<PageEmptyState
  icon={Inbox}
  title="No messages yet"
  description="Start a conversation to see messages here"
  action={{
    label: "New Message",
    onClick: () => console.log("Create message"),
    icon: Plus,
  }}
/>

Complete Example

Here's a full example combining all components:

"use client";

import { useParams } from "next/navigation";
import { Home, Settings, Users, Plus, Mail } from "lucide-react";
import {
  PageTemplate,
  PageSection,
  PageCard,
  PageGrid,
  PageEmptyState,
} from "@/components/layout/page-template";

export default function DashboardPage() {
  const params = useParams();
  const workspace = params.workspace as string;
  const projectId = params.projectId as string;

  return (
    <PageTemplate
      sidebar={{
        title: "Dashboard",
        description: "Overview and insights",
        items: [
          {
            title: "Overview",
            icon: Home,
            href: `/${workspace}/project/${projectId}/overview`,
            isActive: true,
          },
          {
            title: "Settings",
            icon: Settings,
            href: `/${workspace}/project/${projectId}/settings`,
          },
          {
            title: "Users",
            icon: Users,
            href: `/${workspace}/project/${projectId}/users`,
            badge: "12",
          },
        ],
        footer: (
          <p className="text-xs text-muted-foreground">
            Last updated 5 minutes ago
          </p>
        ),
      }}
      hero={{
        icon: Home,
        title: "Dashboard",
        description: "Welcome back! Here's what's happening.",
        actions: [
          {
            label: "Create Report",
            onClick: () => console.log("Create report"),
            icon: Plus,
          },
        ],
      }}
    >
      {/* Stats Grid */}
      <PageSection title="Quick Stats">
        <PageGrid cols={4}>
          <PageCard>
            <h3 className="text-sm font-medium text-muted-foreground">
              Total Users
            </h3>
            <p className="text-3xl font-bold mt-2">1,234</p>
          </PageCard>
          <PageCard>
            <h3 className="text-sm font-medium text-muted-foreground">
              Active Sessions
            </h3>
            <p className="text-3xl font-bold mt-2">89</p>
          </PageCard>
          <PageCard>
            <h3 className="text-sm font-medium text-muted-foreground">
              Revenue
            </h3>
            <p className="text-3xl font-bold mt-2">$12,345</p>
          </PageCard>
          <PageCard>
            <h3 className="text-sm font-medium text-muted-foreground">
              Conversion
            </h3>
            <p className="text-3xl font-bold mt-2">3.2%</p>
          </PageCard>
        </PageGrid>
      </PageSection>

      {/* Recent Activity */}
      <PageSection
        title="Recent Activity"
        description="Latest updates from your team"
      >
        <PageCard>
          <div className="space-y-4">
            <div className="flex items-center gap-3">
              <div className="h-8 w-8 rounded-full bg-primary/10" />
              <div>
                <p className="text-sm font-medium">User signed up</p>
                <p className="text-xs text-muted-foreground">2 minutes ago</p>
              </div>
            </div>
          </div>
        </PageCard>
      </PageSection>

      {/* Empty State Example */}
      <PageSection title="Messages">
        <PageCard>
          <PageEmptyState
            icon={Mail}
            title="No messages yet"
            description="When you receive messages, they'll appear here"
            action={{
              label: "Send Message",
              onClick: () => console.log("Send"),
              icon: Plus,
            }}
          />
        </PageCard>
      </PageSection>
    </PageTemplate>
  );
}

Props Reference

PageTemplate

Prop Type Description
children ReactNode Main content
sidebar object Optional sidebar configuration
hero object Optional hero section configuration
containerWidth "default" | "wide" | "full" Content container width (default: "default")
className string Custom wrapper class
contentClassName string Custom content class

Sidebar Config

Prop Type Description
title string Sidebar title
description string Optional subtitle
items array Navigation items
footer ReactNode Optional footer content

Hero Config

Prop Type Description
icon LucideIcon Optional icon
title string Page title
description string Optional description
actions array Optional action buttons

Tips

  1. Consistent Icons: Always use Lucide icons for consistency
  2. Active States: Pass isActive to sidebar items to highlight current page
  3. Responsive: Grid and card components are responsive by default
  4. Accessibility: All components include proper ARIA attributes
  5. Performance: Use "use client" only when you need client-side interactivity

Migration Guide

To migrate an existing page:

  1. Import PageTemplate and utility components
  2. Wrap content in <PageTemplate>
  3. Move navigation to sidebar prop
  4. Move page header to hero prop
  5. Replace div sections with <PageSection>
  6. Replace card divs with <PageCard>
  7. Use <PageGrid> for responsive grids

Before:

<div className="flex h-full">
  <div className="w-64 border-r">
    {/* sidebar */}
  </div>
  <div className="flex-1">
    {/* content */}
  </div>
</div>

After:

<PageTemplate sidebar={{...}} hero={{...}}>
  {/* content */}
</PageTemplate>