8.7 KiB
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
- Consistent Icons: Always use Lucide icons for consistency
- Active States: Pass
isActiveto sidebar items to highlight current page - Responsive: Grid and card components are responsive by default
- Accessibility: All components include proper ARIA attributes
- Performance: Use "use client" only when you need client-side interactivity
Migration Guide
To migrate an existing page:
- Import
PageTemplateand utility components - Wrap content in
<PageTemplate> - Move navigation to
sidebarprop - Move page header to
heroprop - Replace div sections with
<PageSection> - Replace card divs with
<PageCard> - 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>