| name | ui-patterns |
| description | Dashboard UI templates for page layouts, loading states, error states, and sheet scroll patterns. Use when creating admin dashboard pages or need consistent layout patterns. |
| allowed-tools | Read, Glob, Grep |
Dashboard UI Patterns
Reference templates for building and modifying dashboard pages. Use this when creating new pages, loading states, error states, or sheet/sidebar components.
Page Height Constants
Import from @/lib/utils/constants. These ensure consistent full-viewport layouts across all dashboard pages.
import { PAGE_HEIGHT_CLASS } from "@/lib/utils/constants";
| Constant | Value | Use When |
|---|
PAGE_HEIGHT_CLASS.WITH_FOOTER | "h-[calc(100dvh-176px)]" | Pages WITH footer (customers, FAQs, services, conversations) |
PAGE_HEIGHT_CLASS.WITHOUT_FOOTER | "h-[calc(100dvh-112px)]" | Pages WITHOUT footer (calendar, schedule, settings, pricing) |
PAGE_HEIGHT_CLASS.MAX_WITH_FOOTER | "max-h-[calc(100dvh-176px)]" | Scrollable cards/containers on pages with footer |
How to decide: If the page uses <PageFooter>, use WITH_FOOTER. Otherwise use WITHOUT_FOOTER.
Loading State Templates
Page WITH footer
<PageContent withFooter>
<Loader
className={PAGE_HEIGHT_CLASS.WITH_FOOTER}
message={t("loading")}
/>
</PageContent>
<PageFooter> </PageFooter>
Page WITHOUT footer
<PageContent>
<Loader
className={PAGE_HEIGHT_CLASS.WITHOUT_FOOTER}
message={t("loading")}
/>
</PageContent>
Error State Templates
Use InfoPanel centered with appropriate height class.
<PageContent
className={cn(
PAGE_HEIGHT_CLASS.WITHOUT_FOOTER,
"flex items-center justify-center"
)}
>
<InfoPanel
title={t("error.loadError")}
description={error.message || t("error.unexpectedError")}
icon={<WarningIcon size={40} />}
iconColor="text-destructive"
>
<Button onClick={reset}>{t("error.tryAgain")}</Button>
</InfoPanel>
</PageContent>
InfoPanel children layout: Children render inline with centered buttons. Multiple buttons appear side-by-side.
<InfoPanel title="..." description="...">
<Button>Action 1</Button>
<Button>Action 2</Button>
</InfoPanel>
Sheet / Sidebar Scroll Pattern
For sheets with scrollable content, use this flex layout recipe:
<SheetContent
side="right"
className="flex w-full max-h-[100dvh] flex-col gap-0 overflow-hidden sm:max-w-md"
>
<SheetHeader className="shrink-0 border-b border-border">
{/* Header content */}
</SheetHeader>
<div className="flex min-h-0 flex-1 flex-col overflow-hidden">
<div className="shrink-0 px-6 py-4 border-b">
{/* Fixed content (filters, tabs, etc.) */}
</div>
<div ref={scrollRef} className="flex-1 overflow-y-auto px-6 py-4">
{/* Scrollable content */}
</div>
</div>
</SheetContent>
Key principles:
max-h-[100dvh] and overflow-hidden on SheetContent
shrink-0 on fixed elements (headers, footers)
min-h-0 flex-1 overflow-hidden on the scrollable wrapper
flex-1 overflow-y-auto on the actual scrollable area
Workflow: Finding Real Examples
When applying these patterns, explore the codebase for existing implementations:
- Search for existing loading states:
Glob("src/app/**/loading.tsx")
- Search for existing error states:
Glob("src/app/**/error.tsx")
- Search for sheet patterns:
Grep("SheetContent", glob="src/components/**/*.tsx")
- Search for PAGE_HEIGHT_CLASS usage:
Grep("PAGE_HEIGHT_CLASS", glob="src/**/*.tsx")
Use these real implementations as reference alongside the templates above.
Icons
Always use Phosphor Icons. lucide-react is banned via linting.