Skip to content

# Adding Pages

How to create new pages in the Zenith Dashboard and integrate them into the sidebar navigation.

## Overview

Adding a new page to the dashboard takes three steps: create the page file, add it to the navigation configuration, and optionally customize it. The page automatically inherits the dashboard layout (sidebar, header, and content shell) because it lives inside the `(dashboard)` route group.

## Step 1: Create the Page File

Create a new directory and `page.tsx` file inside `src/app/(dashboard)/`:

    // src/app/(dashboard)/reports/page.tsx

    export default function ReportsPage() {
      return (
        <div className="space-y-6">
          <div>
            <h1 className="text-2xl font-bold tracking-tight">Reports</h1>
            <p className="text-sm text-muted-foreground">
              View and generate reports for your business.
            </p>
          </div>

          {/* Your page content goes here */}
        </div>
      );
    }

This page will be accessible at `/reports`. The `(dashboard)` route group does not appear in the URL.

## Step 2: Add to Navigation

Open `src/lib/navigation.ts` and add a new entry to the `navigationItems` array:

    import {
      // ... existing imports
      FileBarChart,
    } from "lucide-react";

    export const navigationItems: NavItem[] = [
      // ... existing items
      {
        label: "Reports",
        href: "/reports",
        icon: FileBarChart,
        keywords: ["reports", "analytics", "export"],
        group: "main",
      },
    ];

The sidebar will automatically render the new link. You can add an optional `badge` property (e.g., `badge: "New"`) to show a count or label next to the link.

## Step 3: Customize (Optional)

The page inherits the full dashboard layout automatically. You can enhance it with any of the available components:

    // src/app/(dashboard)/reports/page.tsx
    import { Card, CardContent, CardHeader, CardTitle } from "@dashboardpack/core/components/ui/card";
    import { Button } from "@dashboardpack/core/components/ui/button";
    import { Download } from "lucide-react";

    export default function ReportsPage() {
      return (
        <div className="space-y-6">
          <div className="flex items-center justify-between">
            <div>
              <h1 className="text-2xl font-bold tracking-tight">Reports</h1>
              <p className="text-sm text-muted-foreground">
                View and generate reports for your business.
              </p>
            </div>
            <Button>
              <Download className="size-4" />
              Export
            </Button>
          </div>

          <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
            <Card>
              <CardHeader>
                <CardTitle>Monthly Revenue</CardTitle>
              </CardHeader>
              <CardContent>
                <p className="text-sm text-muted-foreground">
                  Revenue breakdown for the current month.
                </p>
              </CardContent>
            </Card>
            {/* More cards... */}
          </div>
        </div>
      );
    }

## Client vs. Server Components

By default, Next.js pages are server components. If your page needs interactivity (state, effects, event handlers), add the `"use client"` directive at the top of the file:

    "use client";

    import { useState } from "react";

    export default function InteractivePage() {
      const [count, setCount] = useState(0);

      return (
        <button onClick={() => setCount(count + 1)}>
          Clicked {count} times
        </button>
      );
    }

For better performance, keep pages as server components when possible and extract interactive parts into smaller client components.

## Nested Routes

To create nested pages (e.g., a detail view), add subdirectories:

    src/app/(dashboard)/reports/
    ├── page.tsx                # /reports (list view)
    ├── [id]/
    │   └── page.tsx            # /reports/123 (detail view)
    └── create/
        └── page.tsx            # /reports/create (form)

Square brackets denote a dynamic segment. The `params.id` value is available as a prop in the page component.

## Adding Translations (i18n)

If you want your page title and labels to support multiple languages, add translation keys to the JSON message files in `src/lib/i18n/messages/`. Each locale (en, de, fr) has its own file.

    // src/lib/i18n/messages/en.json
    {
      "reports": {
        "title": "Reports",
        "description": "View and generate reports."
      }
    }

    // src/lib/i18n/messages/de.json
    {
      "reports": {
        "title": "Berichte",
        "description": "Berichte anzeigen und erstellen."
      }
    }

Then use the `useTranslations` hook in your component:

    "use client";

    import { useTranslations } from "@dashboardpack/core/lib/i18n/locale-context";
    import type { Metadata } from "next";

    export const metadata: Metadata = {
      title: "Adding Pages",
      description:
        "Add a new route, wire it into navigation, and reuse the page layout patterns.",
    };

    export default function ReportsPage() {
      const t = useTranslations();

      return (
        <div className="space-y-6">
          <h1 className="text-2xl font-bold">{t("reports.title")}</h1>
          <p className="text-sm text-muted-foreground">
            {t("reports.description")}
          </p>
        </div>
      );
    }

To add the page to the sidebar with translation support, include a `tKey` property in the navigation config pointing to the translation key. The sidebar will use `t(tKey)` when available and fall back to the `label` string otherwise.

## Next Steps

Browse the Components page for a full list of available UI primitives, or learn about Theming to customize the dashboard's appearance.